已经有很多移植例子了,为什么还要写一个?
因为看了很多例子,基本都是按照uCGUI的处理方式,需要一个GUI_UC_EncodeNone.c文件处理非unicode中文字体编码,原子提供的例子也是这样的方式,,但在我这里,显示有很多问题,可以说不能工作,至少STemWinV5.26和V5.28都有问题。这个移植例子是基于以往例子的改进版本。不知道之前的版本会不会如此。
GUI_Type.h和GUI.h定义了多个结构体,基于这些结构体,实现了各种字体的框架。
结构体GUI_FONT定义了整个字体的信息以及接口函数指针,如字体高度、宽度、显示该字体的接口函数、计算该字体字符串长度宽度的函数、判断某个字符是否属于该字体等等。当YDist>YSize时,相当于上下行字符之间插入间隔。
struct GUI_FONT {
GUI_DISPCHAR* pfDispChar;//显示该字体单个字符的接口函数
GUI_GETCHARDISTX*pfGetCharDistX;//计算该字体单个字符的像素宽度
GUI_GETFONTINFO* pfGetFontInfo;//获取该字体的信息
GUI_ISINFONT* pfIsInFont;//判断某个字符是否属于该字体
GUI_GETCHARINFO * pfGetCharInfo; //获取该字体单个字符信息
const tGUI_ENC_APIList* pafEncode;//该字体字符串操作接口
U8 YSize; //该字体的Y轴高度,指的是显示信息高度
U8 YDist; //该字体的Y轴距离,指的是字体占用高度,YDist>=YSize
char XMag; //该字体的X轴放大
char YMag; //该字体的Y轴放大
union {
constvoid GUI_UNI_PTR * pFontData;
constGUI_FONT_MONO GUI_UNI_PTR * pMono;
constGUI_FONT_PROP GUI_UNI_PTR * pProp;
} p; //多功能指针
U8 Baseline; //该字体Y轴行数?
U8 LHeight; /* height of a small lower case character(a,x) */
U8 CHeight; /* height of a small upper case character(A,X) */
};
下面定义了GUI_FONT结构体里面的函数指针类型。
typedefvoid GUI_DISPCHAR (U16 c);
typedefint GUI_GETCHARDISTX(U16P c, int * pSizeX);
typedefvoid GUI_GETFONTINFO (const GUI_FONT * pFont, GUI_FONTINFO * pfi);
typedefchar GUI_ISINFONT (const GUI_FONT *pFont, U16 c);
typedefint GUI_GETCHARINFO (U16P c,GUI_CHARINFO_EXT * pInfo);
结构体GUI_FONTINFO定义了字体信息,其中Baseline,LHeight,CHeight在GUI_FONT结构体里面也有对应的成员。
typedefstruct {
U16Flags;
U8Baseline; //字体高度
U8LHeight; /* height of a small lowercase character (a,x) */
U8CHeight; /* height of a small uppercase character (A,X) */
} GUI_FONTINFO;
结构体GUI_CHARINFO定义了字符信息,当XDist>XSize时,相当于相邻字符之间插入间隔。
typedefstruct {
U8XSize; //字体X轴宽度,指的是显示信息宽度
U8XDist; //字体X轴距离,指的是字体占用宽度,XDist>=XSize
U8BytesPerLine; //字体X轴字节数
constunsigned char * pData;
} GUI_CHARINFO;
结构体GUI_CHARINFO_EXT定义了字符扩展信息,作为GUI_GETCHARINFO函数指针所指向的函数参数。
typedefstruct {
U8XSize;
U8YSize;
I8XPos;
I8YPos;
U8XDist;
constunsigned char * pData;
} GUI_CHARINFO_EXT;
结构体tGUI_ENC_APIList定义了该字体字符串操作函数指针。
typedefint tGUI_GetLineDistX(const char * s,int Len);
typedefint tGUI_GetLineLen (const char * s, int MaxLen);
typedefvoid tGL_DispLine (const char * s,int Len);
typedefstruct {
tGUI_GetLineDistX* pfGetLineDistX; //获取该字体字符串X轴占用的像素点数
tGUI_GetLineLen * pfGetLineLen; //获取该字体字符串的长度
tGL_DispLine * pfDispLine; //显示该字体字符串
} tGUI_ENC_APIList;
结构体GUI_FONT_PROP定义了字体多个编码区域的地址和信息,因为一个字体可能存在多个编码区域,每个区域都有各自的信息,字体高度宽区可能都不一样。
typedefstruct GUI_FONT_PROP {
U16PFirst; //区域第一个字符的编码
U16PLast; //区域最好一个字符的编码
constGUI_CHARINFO * paCharInfo; //属于该区域字符的字体信息
conststruct GUI_FONT_PROP * pNext; //指向字体下一个编码区域
} GUI_FONT_PROP;
基于上述这些结构体,我们开始实现中文汉字支持功能,字体名字为CNHZK。由于没有emWin源代码,这里参照了uCGUI的核心源码,如参照GUIEncSJ.C文件的GetLineDistX、_GetLineLen_SJIS、_DispLine_SJIS函数实现。此外还参照了GUI_SIF_Prop.c、GUI_GetFontInfo.C、GUIAAChar4.c、F16_HK.C等文件。
需要注意:网上大多数中文支持都是参照uCGUI支持中文的移植方式,需要用到GUI_UC_EncodeNone.c文件处理非unicode中文字体编码,这里需要删掉,否则中文显示会抖动窜动。实际上,如果实现了GUICNHZK_DispLine函数,则每次显示HZK字体字符串,都会调用该函数,而这个函数是我们自己实现的,这样我们就可以自己处理中文字体编码细节了,如果没有实现GUICNHZK_DispLine,则GUI核心会直接调用GUICNHZK_DispChar函数,这时候GUI核心要被告知如何处理字体编码,但怎么告知呢?emWin不开源,不好解决。按照uCGUI那种方式实现GUI_UC_EncodeNone.c,工作的有问题,至少在STemWinV5.26和V5.28上面都有问题。
目前支持12、16、24三种大小,将HZK12,HZK16, HZK24字库文件放置在SDCard或者外置SpiFlash等存储介质。按照类似的方法,可以扩展支持其他各种各样的字体。
首先在GUIType.h增加下列声明和宏定义。
externconst tGUI_ENC_APIList GUI_ENC_APIList_CNHZK;//
/*HZK12, HZK16, HZK24 : chinese 16x12, 16x16, 24x24 fonts */
#defineGUI_FONTTYPE_CNHZK \
GUICNHZK_DispChar, \
GUICNHZK_GetCharDistX, \
GUICNHZK_GetFontInfo, \
GUICNHZK_IsInFont, \
GUICNHZK_GetCharInfo, \
&GUI_ENC_APIList_CNHZK
其次在GUI.h添加下列字体声明和宏定义。
externGUI_CONST_STORAGE GUI_FONT GUI_Font16x12_CNHZK;//
externGUI_CONST_STORAGE GUI_FONT GUI_Font16x16_CNHZK;//
externGUI_CONST_STORAGE GUI_FONT GUI_Font24x24_CNHZK;//
#defineGUI_FONT_16x12_CNHZK &GUI_Font16x12_CNHZK//
#defineGUI_FONT_16x16_CNHZK &GUI_Font16x16_CNHZK//
#defineGUI_FONT_24x24_CNHZK &GUI_Font24x24_CNHZK//
定义GUI_Font16x12_CNHZK字体的相关信息。
///Chinese_Font_16x12Define Start///
GUI_CONST_STORAGE GUI_CHARINFO GUI_Font16x12_CNHZK_CharInfo[2] = {
{8, 8, 1, (void*)0},//ASCII8x12,X轴宽度为8,1字节,Y轴高度为12
{16, 16, 2, (void*)0},//CHINESE16x12,X轴宽度为16,2字节,Y轴高度为12
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_Font16x12_CNHZK_PropHZK = {
0xA1A1, //HZK12字库第一个字符的编码
0xFFFF, //HZK12字库最后一个字符的编码
&GUI_Font16x12_CNHZK_CharInfo[1], //HZK12字库字体信息
(void *)0,
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_Font16x12_CNHZK_PropASC = {
0x0000, //ASCII12字库第一个字符的编码
0x007F, //ASCII12字库最后一个字符的编码
&GUI_Font16x12_CNHZK_CharInfo[0], //ASCII12字库字体信息
(void GUI_CONST_STORAGE*)&GUI_Font16x12_CNHZK_PropHZK, //指向HZK12字库
};
GUI_CONST_STORAGE GUI_FONT GUI_Font16x12_CNHZK = {
GUI_FONTTYPE_CNHZK,//接口函数指针列表
12, //字体Y轴高度
12, //字体Y轴距离
1, //字体X轴放大
1, //字体Y轴放大
(void GUI_CONST_STORAGE*)&GUI_Font16x12_CNHZK_PropASC //指向Prop列表
};
Chinese_Font_16x12Define End
定义GUI_Font16x16_CNHZK字体的相关信息。
///Chinese_Font_16x16Define Start///
GUI_CONST_STORAGE GUI_CHARINFO GUI_Font16x16_CNHZK_CharInfo[2] = {
{16, 16, 2, (void*)0},//ASCII 16x16,X轴宽度为16,2字节,Y轴高度为16
{16, 16, 2, (void*)0},//CHINESE 16x16,X轴宽度为16,2字节,Y轴高度为16
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_Font16x16_CNHZK_PropHZK = {
0xA1A1, //HZK16字库第一个字符的编码
0xFFFF, //HZK16字库最后一个字符的编码
&GUI_Font16x16_CNHZK_CharInfo[1], //HZK16字库字体信息
(void *)0,
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_Font16x16_CNHZK_PropASC = {
0x0000, //ASCII16字库第一个字符的编码
0x007F, //ASCII16字库最后一个字符的编码
&GUI_Font16x16_CNHZK_CharInfo[0], //ASCII16字库字体信息
(void GUI_CONST_STORAGE*)&GUI_Font16x16_CNHZK_PropHZK, //指向HZK16字库
};
GUI_CONST_STORAGE GUI_FONT GUI_Font16x16_CNHZK = {
GUI_FONTTYPE_CNHZK,//接口函数指针列表
16, //字体Y轴高度
16, //字体Y轴距离
1, //字体X轴放大
1, //字体Y轴放大
(void GUI_CONST_STORAGE*)&GUI_Font16x16_CNHZK_PropASC //指向Prop列表
};
//Chinese_Font_16x16Define End//
定义GUI_Font24x24_CNHZK字体的相关信息。
/Chinese_Font_24x24Define Start/
GUI_CONST_STORAGE GUI_CHARINFO GUI_Font24x24_CNHZK_CharInfo[2] = {
{24, 24, 3, (void*)0},//ASCII 24x24,X轴宽度为24,3字节,Y轴高度为24
{24, 24, 3, (void*)0},//CHINESE 24x24,X轴宽度为24,3字节,Y轴高度为24
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_Font24x24_CNHZK_PropHZK = {
0xA1A1, //HZK24字库第一个字符的编码
0xFFFF, //HZK24字库最后一个字符的编码
&GUI_Font24x24_CNHZK_CharInfo[1], //HZK24字库字体信息
(void *)0,
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_Font24x24_CNHZK_PropASC = {
0x0000, //ASCII24字库第一个字符的编码
0x007F, //ASCII24字库最后一个字符的编码
&GUI_Font24x24_CNHZK_CharInfo[0], //ASCII24字库字体信息
(void GUI_CONST_STORAGE*)&GUI_Font24x24_CNHZK_PropHZK, //指向HZK24字库
};
GUI_CONST_STORAGE GUI_FONT GUI_Font24x24_CNHZK = {
GUI_FONTTYPE_CNHZK,//接口函数指针列表
24, //字体Y轴高度
24, //字体Y轴距离
1, //字体X轴放大
1, //字体Y轴放大
(void GUI_CONST_STORAGE*)&GUI_Font24x24_CNHZK_PropASC //指向Prop列表
};
//Chinese_Font_24x24Define End//
从存储介质获取字体数据的接口函数,如果是ASCII字符(小于等于127),则从Font12.c、Font16.c、Font24.c三个文件获取字体数字,如果是汉字,则从外部存储介质读取字体数据。
//getdata from file named of HZK12, HZK16, HZK24
staticvoid GUI_GetChineseFontData(const GUI_FONT_PROP GUI_UNI_PTR *pProp, U16P c)
显示中文字体单个字符的接口函数。
voidGUICNHZK_DispChar(U16 c)
获取中文字体单个字符的X轴宽度,还有乘以放大系数(一般为1)。
intGUICNHZK_GetCharDistX(U16P c, int *pSizeX)
*pSizeX = (pProp->paCharInfo)->XSize *GUI_pContext->pAFont->XMag;
获取中文字体信息,
voidGUICNHZK_GetFontInfo(const GUI_FONT * pFont, GUI_FONTINFO * pfi)
判断字符c是否属于中文字体,根据GUI_FONT_PROP结构体的First和Last判断。
charGUICNHZK_IsInFont(const GUI_FONT * pFont, U16 c)
if((c >= pProp->First) && (c <= pProp->Last) )
这个函数暂时没有实现。
intGUICNHZK_GetCharInfo(U16P c, GUI_CHARINFO_EXT * pInfo)
获取中文字体字符串的像素总长度,其内部进一步调用GUICNHZK_GetCharDistX获取每一个字符的像素宽度,需要注意的是ASCII字符占用1个字节,中文占用2个字节。
intGUICNHZK_GetLineDistX(const char * s, int Len)
获取中文字体字符串的长度,需要注意,ASCII字符占用1字节,中文占用2字节。
intGUICNHZK_GetLineLen(const char * s, int MaxLen)
显示中文字体字符串。
voidGUICNHZK_DispLine(const char * s, int Len)
中文字体字符串操作函数指针结构体。
consttGUI_ENC_APIList GUI_ENC_APIList_CNHZK ={
GUICNHZK_GetLineDistX,
GUICNHZK_GetLineLen,
GUICNHZK_DispLine,
};
底层函数的实现。
/*********************************************************************
*
* GUICNHZK_DispChar
*
* Purpose:
* This is the routine that displays a character. It is used by all
* other routines which display characters as a subroutine.
*/
//void GUI##Type##_DispChar(U16P c);
void GUICNHZK_DispChar(U16 c)
{
GUI_DRAWMODE OldDrawMode, DrawMode;
const GUI_FONT_PROP GUI_UNI_PTR *pProp;
const GUI_CHARINFO GUI_UNI_PTR *pCharInfo;
//see if c is belong to the font scope
pProp = GUI_pContext->pAFont->p.pProp;
for (; pProp; pProp = pProp->pNext) {
if( (c >= pProp->First) && (c <= pProp->Last) ) break;
}
if(0 == pProp) return;
//save and set DrawMode
DrawMode = GUI_pContext->TextMode;
OldDrawMode = LCD_SetDrawMode(DrawMode);
//Get font data from HZK12, HZK16, HZK24
GUI_GetChineseFontData(pProp, c);
//write font data
pCharInfo = pProp->paCharInfo;
LCD_DrawBitmap(GUI_pContext->DispPosX, GUI_pContext->DispPosY,
pCharInfo->XSize, GUI_pContext->pAFont->YSize,
GUI_pContext->pAFont->XMag, GUI_pContext->pAFont->YMag,
1, /* Bits per Pixel */
pCharInfo->BytesPerLine,
&GUI_FontDataBuf[0],
&LCD_BKCOLORINDEX
);
//Fill empty pixel lines
if (GUI_pContext->pAFont->YDist > GUI_pContext->pAFont->YSize) {
int YMag = GUI_pContext->pAFont->YMag;
int YDist = GUI_pContext->pAFont->YDist * YMag;
int YSize = GUI_pContext->pAFont->YSize * YMag;
if (DrawMode != LCD_DRAWMODE_TRANS) {
LCD_COLOR OldColor = GUI_GetColor();
GUI_SetColor(GUI_GetBkColor());
LCD_FillRect(GUI_pContext->DispPosX, GUI_pContext->DispPosY + YSize,
GUI_pContext->DispPosX + pCharInfo->XSize,
GUI_pContext->DispPosY + YDist);
GUI_SetColor(OldColor);
}
}
//Restore draw mode
LCD_SetDrawMode(OldDrawMode);
GUI_pContext->DispPosX += pCharInfo->XDist * GUI_pContext->pAFont->XMag;
}
/*********************************************************************
*
* GUICNHZK_GetCharDistX
*/
//int GUI##Type##_GetCharDistX(U16P c, int * pSizeX);
int GUICNHZK_GetCharDistX(U16P c, int *pSizeX)
{
const GUI_FONT_PROP GUI_UNI_PTR *pProp = GUI_pContext->pAFont->p.pProp;
for(; pProp; pProp = pProp->pNext) {
if( (c >= pProp->First) && (c <= pProp->Last) ) break;
}
if(pProp){
*pSizeX = (pProp->paCharInfo)->XSize * GUI_pContext->pAFont->XMag;
}else{
*pSizeX = 0;
}
return *pSizeX;
}
/*********************************************************************
*
* GUICNHZK_GetFontInfo
*/
//void GUI##Type##_GetFontInfo (const GUI_FONT * pFont, GUI_FONTINFO * pfi);
void GUICNHZK_GetFontInfo(const GUI_FONT * pFont, GUI_FONTINFO * pfi)
{
uint32_t FontCode;
GUI_USE_PARA(pFont);
//ysize - 12, 16, 24
FontCode = GUI_pContext->pAFont->YSize;
if(12 == FontCode){
pfi->Baseline = 12;
pfi->LHeight = 12;
pfi->CHeight = 12;
pfi->Flags = GUI_FONTINFO_FLAG_PROP;
}else if(16 == FontCode){
pfi->Baseline = 16;
pfi->LHeight = 16;
pfi->CHeight = 16;
pfi->Flags = GUI_FONTINFO_FLAG_PROP;
}else if(24 == FontCode){
pfi->Baseline = 24;
pfi->LHeight = 24;
pfi->CHeight = 24;
pfi->Flags = GUI_FONTINFO_FLAG_PROP;
}else{
return;
}
}
/*********************************************************************
*
* GUICNHZK_IsInFont
*/
//char GUI##Type##_IsInFont (const GUI_FONT * pFont, U16 c);
char GUICNHZK_IsInFont(const GUI_FONT * pFont, U16 c)
{
const GUI_FONT_PROP GUI_UNI_PTR *pProp = GUI_pContext->pAFont->p.pProp;
GUI_USE_PARA(pFont);
for(; pProp; pProp = pProp->pNext) {
if( (c >= pProp->First) && (c <= pProp->Last) ) break;
}
if(pProp){
return 1;
}else{
return 0;
}
}
/*********************************************************************
*
* GUICNHZK_GetCharInfo
*/
//int GUI##Type##_GetCharInfo (U16P c, GUI_CHARINFO_EXT * pInfo)
int GUICNHZK_GetCharInfo(U16P c, GUI_CHARINFO_EXT * pInfo)
{
return 0;
}
/*********************************************************************
*
* GUICNHZK_GetLineDistX
*/
int GUICNHZK_GetLineDistX(const char * s, int Len)
{
int Dist =0, SizeX;
U16 c0, c1;
if(0 == s) return 0;
while( ((c0=*(const U8*)s) !=0) && Len >=0 ) {
s++; Len--;
if (c0 > 127) {
c1 = *(const U8*)s++;
Len--;
Dist += GUICNHZK_GetCharDistX((c1<<8)|c0, &SizeX);
} else {
Dist += GUICNHZK_GetCharDistX(c0, &SizeX);
}
}
return Dist;
}
/*********************************************************************
*
* GUICNHZK_GetLineLen
* Purpose:
* Returns the number of characters in a string.
*/
int GUICNHZK_GetLineLen(const char * s, int MaxLen)
{
int Len =0;
U16 c0;
while( ((c0=*(const U8*)s) !=0) && Len < MaxLen ) {
s++;
if (c0 > 127) {
Len++; s++;
} else {
switch (c0) {
case '\n': return Len;
}
}
Len++;
}
return Len;
}
/*********************************************************************
*
* GUICNHZK_DispLine
*/
void GUICNHZK_DispLine(const char * s, int Len)
{
U16 c0, c1;
while (--Len >=0) {
c0 = *(const U8*)s++;
if (c0 > 127) {
c1 = *(const U8*)s++;
Len--;
GUICNHZK_DispChar((c1<<8) | c0);
} else {
GUICNHZK_DispChar(c0);
}
}
}
/*********************************************************************
*
* GUI_ENC_APIList_CNHZK
*/
const tGUI_ENC_APIList GUI_ENC_APIList_CNHZK = {
GUICNHZK_GetLineDistX,
GUICNHZK_GetLineLen,
GUICNHZK_DispLine,
};