跳到主要内容位置

改进

1.改进字体#

  • 找出最长的name
  • 确定font size
    • 先设置一个字体大小,算出文字外框
    • 放大或者缩小,以适配Button
    • 再算出合适的字体大小

page/mainpage.c中GenerateButtons函数中添加,计算字体大小的函数GetFontSizeForAllButton

static void GenerateButtons(void)
{
/* 算出单个按钮的width,height */
/* 居中:计算每个按钮的region */
for (row = 0; (row < rows) && (i < n); row++) //计算region
{
cur_start_y = start_y + row * height;
// pre_start_x = start_x - width;
for (col = 0; (col < n_per_line) && (i < n); col++)
{
...
/* InitButton */
InitButton(GetItemCfgByIndex(i)->name, pButton, NULL, NULL, MainPageOnPressed);
}
}
前面代码保持不变,省略
iFontSize = GetFontSizeForAllButton();
// SetFontSize(iFontSize);
/* 显示:OnDraw */
for (i = 0; i < n; i++)
{
g_atButtons[i].iFontSize = iFontSize;
g_atButtons[i].OnDraw(&g_atButtons[i], pDispBuff);
}
}
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_iButtonCnt; i++)
{
if ((len = strlen(g_atButtons[i].name)) > max_len)
{
max_len = len;
max_index = i;
}
}
/* 2.以font_size = 100,算出它的外框 */
SetFontSize(100);
GetStringRegionCar(g_atButtons[max_index].name, &tRegionCar);
/* 3.把文字的外框缩放为Button的外框 */
kx = (float)g_atButtons[max_index].tRegion.iWidth / tRegionCar.iWidth;
ky = (float)g_atButtons[max_index].tRegion.iHight / tRegionCar.iHight;
if (kx < ky)
{
k = kx;
}
else
{
k = ky;
}
/* 4.反算出font size, 只取0.8大小,避免文字过于接近边界 */
return k * 100 * 0.8;
}
  • 计算外框函数GetStringRegionCar:参考"01_all_series_quickstart\04_嵌入式Linux应用开发基础知识\source\10_freetype\04_show_line\show_line.c" 获取字符串的外框的左上角坐标与宽和高,保存到定义在common.h中的笛卡尔坐标区域的结构体 common.h

    typedef struct RegionCartesian
    {
    int iLeftUpX;
    int iLeftUpY;
    int iWidth;
    int iHight;
    } RegionCartesian, *PRegionCartesian;

    freetype.c的FreetypeGetStringRegionCar函数获取字符串的外框的左上角坐标与宽和高,将函数放入Fontopr结构体

    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 */
    ptRegionCar->iLeftUpX = bbox.xMin;
    ptRegionCar->iLeftUpY = bbox.yMax;
    ptRegionCar->iWidth = bbox.xMax - bbox.xMin + 1;
    ptRegionCar->iHight = bbox.yMax - bbox.yMin + 1;
    return 0;
    }
    static FontOpr g_tFreetypeOpr = {
    .name = "freetype",
    .FontInit = FreetypeFontInit,
    .SetFontSize = FreetypeSetFontSize,
    .GetFontBitMap = FreetypeGetFontBitMap,
    .GetStringRegionCar = FreetypeGetStringRegionCar,
    };

    font_manager上层字体管理系统中,提供接口函数

    int GetStringRegionCar(char *str, PRegionCartesian ptRegionCar)
    {
    return g_ptDefaultFontOpr->GetStringRegionCar(str, ptRegionCar);
    }

tips:将framebuffer转换为图片

开发板:把fb0的数据拷贝处理

[root@imx6ull:/mnt]# cat /dev/fb0 > 1.raw

在虚拟机里:转换为bmp文件

./fb2bmp

2.规范函数API命名#

主要是将管理系统相关的初始化函数改名为系统注册函数,与下层具体部件初始化区分

int main(int argc, char **argv)
{
// PDispBuff ptBuffer;
int err;
if (argc != 2)
{
printf("Usage: %s <font_file>\n", argv[0]);
return -1;
}
/* 初始化显示系统 */
DisplaySystemRegister();
SelectDefaultDisplay("fb");
InitDefaultDisplay();
// ptBuffer = GetDisplayBuffer(); //获得显存buffer
/* 初始化输入系统 */
IntputSystemRegister();
IntputDeviceInit();
/* 初始化文字系统 */
FontSystemRegister();
err = SelectAndInitFont("freetype", argv[1]);
if (err)
{
printf("SelectAndInitFont err\n");
return -1;
}
/* 初始化页面系统 */ // UI系统不需要初始化,直接获取按键即可
PageSystemRegister();
/* 运行业务系统的主页面 */
Page("main")->Run(NULL);
return 0;
}

3.支持配置文件的command#

修改MainPageOnPressed函数,在按钮被按下时能够调用配置文件的command:

调用command文件,传入当前状态。

static int MainPageOnPressed(struct Button *ptButton, PDispBuff ptDispBuff, PInputEvent ptInputEvent)
{
unsigned int dwColor = BUTTON_DEFAULT_COLOR;
char name[100];
char status[100];
char *strButton = ptButton->name;
char *command_status[3] = {"err",
"ok",
"percent"};
int command_status_index = 0;
char command[1000];
PItemCfg ptItemCfg;
/* 1. 对于触摸屏事件 */
if (ptInputEvent->iType == INPUT_TYPE_TOUCH && ptInputEvent->iPressure == 0) // 松开的时候响应
{
/* 1.1 分辨能否被点击 */
if (0 == GetItemCfgByName(ptButton->name)->bCanBeTouched)
{
return -1;
}
/* 1.2 修改颜色 */
ptButton->status = !ptButton->status;
if (1 == ptButton->status)
{
dwColor = BUTTON_PRESSED_COLOR;
command_status_index = 1;
}
}
/* 2. 对于网络事件 */
else if (ptInputEvent->iType == INPUT_TYPE_NET)
{
/* 2.1 根据传入字符串修改颜色 */
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);
//居中写文字
DrawTextInRegionCentrl(strButton, &ptButton->tRegion, BUTTON_TEXT_COLOR);
// flush to lcd or web
FlushDisplayRegion(&ptButton->tRegion, ptDispBuff);
/* 执行command */
ptItemCfg = GetItemCfgByName(ptButton->name);
if (ptItemCfg->command[0] != '\0')
{
//把命令和按钮状态拷贝到command数组
sprintf(command, "%s %s", ptItemCfg->command, command_status[command_status_index]);
system(command);
}
return 0;
}

上机:

编写一个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 err"
fi

拷贝到bin目录,修改执行权限

[root@imx6ull:/mnt/31_improve_command]# ls
Makefile built-in.o config etc include led.sh simsun.ttc ui ??????.txt
Makefile.build business display font input page test unittest
[root@imx6ull:/mnt/31_improve_command]# cp led.sh /bin/
[root@imx6ull:/mnt/31_improve_command]# chmod +x /bin/led.sh

如果无法执行,需要在虚拟机转换:

dos2unix led.sh

请点击左侧菜单(移动端为右下角)选择要查看的所有笔记吧。