一、改进:按钮文字
按钮文字大小不一,没有严格居中,太小看不清
根据配置文件的各项确定最长的名字,确定字符大小:每个按钮中文字大小都一样
修改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;Car.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这个脚本