前言:
前面我们已经构造出来显示系统、输入系统、文字系统、UI系统、页面系统,业务系统,这个小项目该完成的功能我们已经都完成了,但是还是有很多地方可以优化改进的,现在让我们对这个系统不足的地方进行相应的和改进与优化吧。
目录
一、改进:按钮文字
按钮文字大小不一,没有严格居中,太小看不清
根据配置文件的各项确定最长的名字,确定字符大小:每个按钮中文字大小都一样
修改disp_manager.c中的DrawTextInRegionCentral
1.freetype.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <font_manager.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
static FT_Face g_tFace;
static int g_iDefaultFontSize = 12;
static int FreetypeGetStringRegionCar(char *str, PRegionCartesian ptRegionCar)
{
int i;
int error;
FT_BBox bbox;
FT_BBox glyph_bbox;
FT_Vector pen;
FT_Glyph glyph;
FT_GlyphSlot slot = g_tFace->glyph;
/* 初始化 */
bbox.xMin = bbox.yMin = 32000;
bbox.xMax = bbox.yMax = -32000;
/* 指定原点为(0, 0) */
pen.x = 0;
pen.y = 0;
/* 计算每个字符的bounding box */
/* 先translate, 再load char, 就可以得到它的外框了 */
for (i = 0; i < strlen(str); i++)
{
/* 转换:transformation */
FT_Set_Transform(g_tFace, 0, &pen);
/* 加载位图: load glyph image into the slot (erase previous one) */
error = FT_Load_Char(g_tFace, str[i], FT_LOAD_RENDER);
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
/* 取出glyph */
error = FT_Get_Glyph(g_tFace->glyph, &glyph);
if (error)
{
printf("FT_Get_Glyph error!\n");
return -1;
}
/* 从glyph得到外框: bbox */
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
/* 更新外框 */
if ( glyph_bbox.xMin < bbox.xMin )
bbox.xMin = glyph_bbox.xMin;
if ( glyph_bbox.yMin < bbox.yMin )
bbox.yMin = glyph_bbox.yMin;
if ( glyph_bbox.xMax > bbox.xMax )
bbox.xMax = glyph_bbox.xMax;
if ( glyph_bbox.yMax > bbox.yMax )
bbox.yMax = glyph_bbox.yMax;
/* 计算下一个字符的原点: increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
/* return string bbox */
//*abbox = bbox;
ptRegionCar->iLeftUpX = bbox.xMin;
ptRegionCar->iLeftUpY = bbox.yMax;
ptRegionCar->iWidth = bbox.xMax - bbox.xMin + 1;
ptRegionCar->iHeigh = bbox.yMax - bbox.yMin + 1;
return 0;
}
static int FreeTypeFontInit(char *aFineName)
{
FT_Library library;
int error;
error = FT_Init_FreeType( &library ); /* initialize library */
if (error)
{
printf("FT_Init_FreeType err\n");
return -1;
}
error = FT_New_Face(library, aFineName, 0, &g_tFace ); /* create face object */
if (error)
{
printf("FT_New_Face err\n");
return -1;
}
FT_Set_Pixel_Sizes(g_tFace, g_iDefaultFontSize, 0);
return 0;
}
static int FreeTypeSetFontSize(int iFontSize)
{
FT_Set_Pixel_Sizes(g_tFace, iFontSize, 0);
return 0;
}
static int FreeTypeGetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{
int error;
FT_Vector pen;
FT_GlyphSlot slot = g_tFace->glyph;
pen.x = ptFontBitMap->iCurOriginX * 64; /* 单位: 1/64像素 */
pen.y = ptFontBitMap->iCurOriginY * 64; /* 单位: 1/64像素 */
/* 转换:transformation */
FT_Set_Transform(g_tFace, 0, &pen);
/* 加载位图: load glyph image into the slot (erase previous one) */
error = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER);
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
ptFontBitMap->pucBuffer = slot->bitmap.buffer;
ptFontBitMap->tRegion.iLeftUpX = slot->bitmap_left;
ptFontBitMap->tRegion.iLeftUpY = ptFontBitMap->iCurOriginY*2 - slot->bitmap_top;
ptFontBitMap->tRegion.iWidth = slot->bitmap.width;
ptFontBitMap->tRegion.iHeigh = slot->bitmap.rows;
ptFontBitMap->iNextOriginX = ptFontBitMap->iCurOriginX + slot->advance.x / 64;
ptFontBitMap->iNextOriginY = ptFontBitMap->iCurOriginY;
return 0;
}
static FontOpr g_tFreetypeOpr = {
.name = "freetype",
.FontInit = FreeTypeFontInit,
.SetFontSize = FreeTypeSetFontSize,
.GetFontBitMap = FreeTypeGetFontBitMap,
.GetStringRegionCar = FreetypeGetStringRegionCar,
};
void FreetypeRegister(void)
{
RegisterFont(&g_tFreetypeOpr);
}
static int FreetypeGetStringRegionCar(char *str, PRegionCartesian ptRegionCar)
第23行:将外框保存在笛卡坐标系里面
2.font_manager.h
#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H
#include <common.h>
typedef struct FontBitMap {
Region tRegion;
int iCurOriginX;
int iCurOriginY;
int iNextOriginX;
int iNextOriginY;
unsigned char *pucBuffer;
}FontBitMap, *PFontBitMap;
typedef struct FontOpr {
char *name;
int (*FontInit)(char *aFineName);
int (*SetFontSize)(int iFontSize);
int (*GetFontBitMap)(unsigned int dwCode, PFontBitMap ptFontBitMap);
int (*GetStringRegionCar)(char *str, PRegionCartesian ptRegionCar);
struct FontOpr *ptNext;
}FontOpr, *PFontOpr;
void RegisterFont(PFontOpr ptFontOpr);
void FontsRegister(void);
int SelectAndInitFont(char *aFontOprName, char *aFontFileName);
int SetFontSize(int iFontSize);
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap);
int GetStringRegionCar(char *str, PRegionCartesian ptRegionCar);
#endif
第20行:添加 GetStringRegionCar 函数指针
第31行:在头文件里将这个函数声明出来
3.font_manager.c
调用你所选择的字库操作函数里面对应的函数
int GetStringRegionCar(char *str, PRegionCartesian ptRegionCar)
{
return g_ptDefaulFontOpr->GetStringRegionCar(str, ptRegionCar);
}
4.common.h
构建笛卡坐标系计算外框
#ifndef _COMMON_H
#define _COMMON_H
#ifndef NULL
#define NULL (void *)0
#endif
typedef struct Region {
int iLeftUpX;
int iLeftUpY;
int iWidth;
int iHeigh;
}Region, *PRegion;
typedef struct RegionCartesian {
int iLeftUpX;
int iLeftUpY;
int iWidth;
int iHeigh;
}RegionCartesian, *PRegionCartesian;
#endif
5.main_page.c
对边框进行计算得出文字大小
static int GetFontSizeForAllButton(void)
{
int i;
int max_len = -1;
int max_index = 0;
int len;
RegionCartesian tRegionCar;
float k, kx, ky;
/* 1. 找出name最长的Button */
for (i = 0; i < g_tButtonCnt; i++)
{
len = strlen(g_tButtons[i].name);
if (len > max_len)
{
max_len = len;
max_index = i;
}
}
/* 2. 以font_size =100, 算出它的外框 */
SetFontSize(100);
GetStringRegionCar(g_tButtons[max_index].name, &tRegionCar);
/* 3. 把文字的外框缩放为Button的外框 */
kx = (float)g_tButtons[max_index].tRegion.iWidth / tRegionCar.iWidth;
ky = (float)g_tButtons[max_index].tRegion.iHeigh / tRegionCar.iHeigh;
if (kx < ky)
k = kx;
else
k = ky;
//printf("font size = %d\n", (int)(k*100));
/* 4. 反算出font size, 只取0.80, 避免文字过于接近边界 */
return k * 100 * 0.8;
}
6.disp_manager.c
在DrawTextInRegionCentral绘制函数中
/* 计算字符串的外框 */
GetStringRegionCar(name, &tRegionCar);
/* 算出第一个字符的origin */
iOriginX = ptRegion->iLeftUpX + (ptRegion->iWidth - tRegionCar.iWidth)/2 - tRegionCar.iLeftUpX;
iOriginY = ptRegion->iLeftUpY + (ptRegion->iHeigh - tRegionCar.iHeigh)/2 + tRegionCar.iLeftUpY;
7.上板效果:
二、改进:接口函数名优化
显示系统、输入系统中,有多个init函数,让人难以分辨。
如下图修改:
main.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <disp_manager.h>
#include <font_manager.h>
#include <input_manager.h>
#include <page_manager.h>
int main(int argc, char **argv)
{
int error;
if (argc != 2)
{
printf("Usage: %s <font_file>\n", argv[0]);
return -1;
}
/* 初始化显示系统 */
DisplaySystemRegister(); /* 以前是: DisplayInit(); */
SelectDefaultDisplay("fb");
InitDefaultDisplay();
/* 初始化输入系统 */
InputSystemRegister(); /* 以前是: InputInit(); */
IntpuDeviceInit();
/* 初始化文字系统 */
FontSystemRegister(); /* 以前是: FontsRegister(); */
error = SelectAndInitFont("freetype", argv[1]);
if (error)
{
printf("SelectAndInitFont err\n");
return -1;
}
/* 初始化页面系统 */
PageSystemRegister(); /* 以前是: PagesRegister(); */
/* 运行业务系统的主页面 */
Page("main")->Run(NULL);
return 0;
}
三、改进:支持配置文件中的command
1.main_page.c:
在按钮的OnPressed函数中,用system函数运行command:
#include <config.h>
#include <stdio.h>
#include <ui.h>
#include <page_manager.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#define X_GAP 5
#define Y_GAP 5
static Button g_tButtons[ITEMCFG_MAX_NUM];
static int g_tButtonCnt;
static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{
unsigned int dwColor = BUTTON_DEFAULT_COLOR;
char name[100];
char status[100];
char *strButton;
char *command_status[3] = {"err", "ok", "percent"};
int command_status_index = 0;
char command[1000];
PItemCfg ptItemCfg;
strButton = ptButton->name;
/* 1. 对于触摸屏事件 */
if (ptInputEvent->iType == INPUT_TYPE_TOUCH)
{
/* 1.1 分辨能否被点击 */
if (GetItemCfgByName(ptButton->name)->bCanBeTouched == 0)
return -1;
/* 1.2 修改颜色 */
ptButton->status = !ptButton->status;
if (ptButton->status)
{
dwColor = BUTTON_PRESSED_COLOR;
command_status_index = 1;
}
}
else if (ptInputEvent->iType == INPUT_TYPE_NET)
{
/* 2. 对于网络事件 */
/* 根据传入的字符串修改颜色 : wifi ok, wifi err, burn 70 */
sscanf(ptInputEvent->str, "%s %s", name, status);
if (strcmp(status, "ok") == 0)
{
command_status_index = 1;
dwColor = BUTTON_PRESSED_COLOR;
}
else if (strcmp(status, "err") == 0)
{
command_status_index = 0;
dwColor = BUTTON_DEFAULT_COLOR;
}
else if (status[0] >= '0' && status[0] <= '9')
{
command_status_index = 2;
dwColor = BUTTON_PERCENT_COLOR;
strButton = status;
}
else
return -1;
}
else
{
return -1;
}
/* 绘制底色 */
DrawRegion(&ptButton->tRegion, dwColor);
/* 居中写文字 */
DrawTextInRegionCentral(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);
/* flush to lcd/web */
FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);
/* 执行command */
ptItemCfg = GetItemCfgByName(ptButton->name);
if (ptItemCfg->command[0] != '\0')
{
sprintf(command, "%s %s", ptItemCfg->command, command_status[command_status_index]);
system(command);
}
return 0;
}
static int GetFontSizeForAllButton(void)
{
int i;
int max_len = -1;
int max_index = 0;
int len;
RegionCartesian tRegionCar;
float k, kx, ky;
/* 1. 找出name最长的Button */
for (i = 0; i < g_tButtonCnt; i++)
{
len = strlen(g_tButtons[i].name);
if (len > max_len)
{
max_len = len;
max_index = i;
}
}
/* 2. 以font_size =100, 算出它的外框 */
SetFontSize(100);
GetStringRegionCar(g_tButtons[max_index].name, &tRegionCar);
/* 3. 把文字的外框缩放为Button的外框 */
kx = (float)g_tButtons[max_index].tRegion.iWidth / tRegionCar.iWidth;
ky = (float)g_tButtons[max_index].tRegion.iHeigh / tRegionCar.iHeigh;
//printf("button width / str width = %d/%d = %f\n", g_tButtons[max_index].tRegion.iWidth, tRegionCar.iWidth, kx);
//printf("button height / str height = %d/%d = %f\n", g_tButtons[max_index].tRegion.iHeigh, tRegionCar.iHeigh, ky);
if (kx < ky)
k = kx;
else
k = ky;
//printf("font size = %d\n", (int)(k*100));
/* 4. 反算出font size, 只取0.80, 避免文字过于接近边界 */
return k * 100 * 0.8;
}
static void GenerateButtons(void)
{
int width, height;
int n_per_line;
int row, rows;
int col;
int n;
PDispBuff pDispBuff;
int xres, yres;
int start_x, start_y;
int pre_start_x, pre_start_y;
PButton pButton;
int i = 0;
int iFontSize;
/* 算出单个按钮的width/height */
g_tButtonCnt = n = GetItemCfgCount();
pDispBuff = GetDisplayBuffer();
xres = pDispBuff->iXres;
yres = pDispBuff->iYres;
width = sqrt(1.0/0.618 *xres * yres / n);
n_per_line = xres / width + 1;
width = xres / n_per_line;
height = 0.618 * width;
/* 居中显示: 计算每个按钮的region */
start_x = (xres - width * n_per_line) / 2;
rows = n / n_per_line;
if (rows * n_per_line < n)
rows++;
start_y = (yres - rows*height)/2;
/* 计算每个按钮的region */
for (row = 0; (row < rows) && (i < n); row++)
{
pre_start_y = start_y + row * height;
pre_start_x = start_x - width;
for (col = 0; (col < n_per_line) && (i < n); col++)
{
pButton = &g_tButtons[i];
pButton->tRegion.iLeftUpX = pre_start_x + width;
pButton->tRegion.iLeftUpY = pre_start_y;
pButton->tRegion.iWidth = width - X_GAP;
pButton->tRegion.iHeigh = height - Y_GAP;
pre_start_x = pButton->tRegion.iLeftUpX;
/* InitButton */
InitButton(pButton, GetItemCfgByIndex(i)->name, NULL, NULL, MainPageOnPressed);
i++;
}
}
iFontSize = GetFontSizeForAllButton();
//SetFontSize(iFontSize);
/* OnDraw */
for (i = 0; i < n; i++)
{
g_tButtons[i].iFontSize = iFontSize;
g_tButtons[i].OnDraw(&g_tButtons[i], pDispBuff);
}
}
static int isTouchPointInRegion(int iX, int iY, PRegion ptRegion)
{
if (iX < ptRegion->iLeftUpX || iX >= ptRegion->iLeftUpX + ptRegion->iWidth)
return 0;
if (iY < ptRegion->iLeftUpY || iY >= ptRegion->iLeftUpY + ptRegion->iHeigh)
return 0;
return 1;
}
static PButton GetButtonByName(char *name)
{
int i;
for (i = 0; i < g_tButtonCnt; i++)
{
if (strcmp(name, g_tButtons[i].name) == 0)
return &g_tButtons[i];
}
return NULL;
}
static PButton GetButtonByInputEvent(PInputEvent ptInputEvent)
{
int i;
char name[100];
if (ptInputEvent->iType == INPUT_TYPE_TOUCH)
{
for (i = 0; i < g_tButtonCnt; i++)
{
if (isTouchPointInRegion(ptInputEvent->iX, ptInputEvent->iY, &g_tButtons[i].tRegion))
return &g_tButtons[i];
}
}
else if (ptInputEvent->iType == INPUT_TYPE_NET)
{
sscanf(ptInputEvent->str, "%s", name);
return GetButtonByName(name);
}
else
{
return NULL;
}
return NULL;
}
static void MainPageRun(void *pParams)
{
int error;
InputEvent tInputEvent;
PButton ptButton;
PDispBuff ptDispBuff = GetDisplayBuffer();
/* 读取配置文件 */
error = ParseConfigFile();
if (error)
return ;
/* 根据配置文件生成按钮、界面 */
GenerateButtons();
while (1)
{
/* 读取输入事件 */
error = GetInputEvent(&tInputEvent);
if (error)
continue;
/* 根据输入事件找到按钮 */
ptButton = GetButtonByInputEvent(&tInputEvent);
if (!ptButton)
continue;
/* 调用按钮的OnPressed函数 */
ptButton->OnPressed(ptButton, ptDispBuff, &tInputEvent);
}
}
static PageAction g_tMainPage = {
.name = "main",
.Run = MainPageRun,
};
void MainPageRegister(void)
{
PageRegister(&g_tMainPage);
}
第22行:状态存储
第23行:默认状态为err,并且用command_status_index标记状态
第84~89行:执行command
第84行:根据名字找到配置项
第85行:查看是否查找到配置项
第86行:打印出命令和命令的状态
第87行:执行命令
2.执行命令后所执行的脚本
led.sh
#!/bin/sh
status=$1
if [ "$status" = "ok" ]
then
echo "led has been tested, it is ok"
fi
if [ "$status" = "err" ]
then
echo "led has been tested, it is fail"
fi
test_sleep_key.sh
#!/bin/sh
status=$1
if [ "$status" = "processing" ]
then
wakeup_count=$(cat /sys/power/wakeup_count)
echo standby > /sys/power/state
wakeup_count_new=$(cat /sys/power/wakeup_count)
while [ $wakeup_count_new -eq $wakeup_count ]
do
wakeup_count_new=$(cat /sys/power/wakeup_count)
done
count=0
while [ $count -le 1 ]
do
detect_dev 127.0.0.1 "ALL ok" > /dev/null 2>&1
sleep 1
let count++
done
fi
3.ubuntu上:
book@100ask:~/31_improve_command$ dos2unix led.sh
dos2unix: converting file led.sh to Unix format...
4.开发板上:
[root@100ask:/mnt/31_improve_command]# cp led.sh /bin/
[root@100ask:/mnt/31_improve_command]# chmod +x /bin/led.sh
[root@100ask:/mnt/31_improve_command]# led.sh ok
led has been tested, it is ok
[root@100ask:/mnt/31_improve_command]# led.sh err
led has been tested, it is fail
[root@100ask:/mnt/31_improve_command]#
当点击开发板上的LED时会运行led.sh这个脚本