typedef struct { BYTE bFontType; BYTE bFirstChar; BYTE bLastChar; BYTE bCharHeight; BYTE bCharUnderlineRow; BYTE bCharWidth; BYTE *bCharDefinitions; WORD *wCharOffsets; } FontDefinition;bFontType: bit 0 set to 1 specifies this font is proportional; otherwise it is fixed-width. Bit 7 set to 1 specifies a blank will be added after each character.
bFirstChar: the first character that this font defines.
bLastChar: the last character that this font defines.
bCharHeight: height of font. This will help you to determine how many bytes are necessary for each vertical line.
bCharUnderlineRow: which row of the fonts will be used for underlining. bCharWidth: specifies the width of the fixed-width font.
bCharDefinitions: pointer to a memory area that contains font definitions.
This area needs the help of the next field wCharOffsets to determine where
each char definition begins and ends.
One or more definition bytes define a vertical
line of the font. If font has font height smaller or equal to 8, then only one byte
is necessary for the vertical line. If font has font height bigger then 8 and smaller
than 16 then 2 bytes are used for the vertical lines, and so on.
This memory
area contains two parts: the data part and the name part. The data part has all the bytes
for drawing all the characters. Following the data part is the font name part, a string
containing the font name, ended by zero.
wCharOffsets: pointer to an array having the members equal to number of characters defined by the font plus 1. Member[N+1] determines the offset into bCharDefinitions that begins the byte definitions for N+1 th character, and that ends the byte definitions of the N-th character, N >= 0. One of the interesting thing is if we want to omit M-th character, we just need to set Member[M] = Member[M+1]. This means M-th character has zero width.
With the above information, if we need to define a character of proportional font , height of 14, width of 8, then we need to have 16 bytes for this character. Perhaps that's enough for this font theory ( and that's all that I know about RimOS font ). Let's start some programming.
My application needs two different sets of fonts with different heights of 8 and 10, one
at a time, each set requires to have normal, reversed ( black background, white
foreground ) and underlined fonts. I am not sure if the Lcd API calls could help me to solve
this or not, but I hate to deal with pixels, areas, lines, so I ignore these APIs.
For the normal fonts, it is easy to use the built-in fonts of the RimOS, using
Font::GetDefault(int,int). For the other fonts, I clone the original ones then process them.
In the following code, there is RIMStrCpy function, that is from http://resources.rimdev.com/codesnippet.htm. Also for the sake of simplicity, codes for checking memory allocation have been got out of here.
The following function will create a set of three fonts for a given height, 8 or 10.
1. Create the normal font : line 17 - 20
2. Create the reversed font out of the normal font. This step will first create the new font definition ( line 23 - 24 ). Then the number of characters is calculated ( line 25 ). Recall the meaning of the wCharOffsets, we know that the last member of this array lets us know the offset of the last byte of the last character. This also is the size of the data part of bCharDefinitions. Knowing the size of the data part, knowing the name of the font ( line 10 ) we now can allocate memory for this memory area ( line 27 ). Line 28-30 finishes the work of creating a font definition out of the normal one.
3. Manually process the font definition as we want. We need a reversed font, so all we need to do is to XOR each byte of the data part ( line 31- 32 ).
4. Create the reversed font from the font definition ( line 33 ).
5. For the underlined font, we repeat step 2 to 4, except there is a little different for step 3.
To have the underline, we need to put a dot at the lower part of each vertical line of the font. This requires us know how many byte a vertical line requires. That's why in the codes ( line 42 and 53 ) we check if this font requires one or two bytes for one vertical line : font 8 requires 1 byte, font 10 requires 2 bytes. For font 8, we just simply OR each byte with 0x80, the lowest dot of the vertical line. For font 10, there are two bytes for each vertical line, so we need to add a dot to the 2nd byte only ( line 50 ).
1. Font *gpfont1 = NULL; 2. Font *gpfont2 = NULL; 3. Font *gpfont3 = NULL; 4. Font *gpselectedfont = NULL; 5. FontDefinition gfontdef2, gfontdef3; 6. 7.void InitializeFonts( int fontsize) 8.{ 9. const FontDefinition *pfontdef; 10. const char *customedfontname="Custom Font"; 11. Font *font; 12. int i; 13. 14. // support size 10 and size 8 only at this time 15. if( fontsize != 10 && fontsize != 8 ) fontsize = 10; 16. 17. font = (Font*)Font::GetDefault(fontsize); 18. 19. // font 1 is the default font 20. gpfont1 = new Font(font->GetDefinition()); 21. 22. // font 2 is the reversed font of font 1 23. pfontdef = gpfont1->GetDefinition(); 24. memcpy( &gfontdef2, pfontdef, sizeof(gfontdef2)); 25. int charnum = pfontdef->bLastChar - pfontdef->bFirstChar ; 26. int size = pfontdef->wCharOffsets[charnum+1]; 27. unsigned char *pnewdata2 = new unsigned char[size + RIMStrLen(customedfontname)+1]; 28. memcpy( pnewdata2, pfontdef->bCharDefinitions, size ); 29. RIMStrCpy( (char*)pnewdata2+size, customedfontname ); 30. gfontdef2.bCharDefinitions = pnewdata2; 31. for( i = 0; i < size; i++ ) 32. *(pnewdata2+i) = (*(pnewdata2+i))^0xFF; 33. gpfont2 = new Font(&gfontdef2); 34. 35. // font 3 is the underlined font 1 36. memcpy( &gfontdef3, pfontdef, sizeof(gfontdef3)); 37. unsigned char *pnewdata3 = new unsigned char[size + RIMStrLen(customedfontname)+1]; 38. memcpy( pnewdata3, pfontdef->bCharDefinitions, size ); 39. RIMStrCpy( (char*)pnewdata3+size, customedfontname ); 40. gfontdef3.bCharDefinitions = pnewdata3; 41. int height = gfontdef3.bCharHeight; 42. if( fontsize == 10 ) 43. { 44. for( i = 1; i < charnum; i++ ) 45. { 46. int index1 = gfontdef3.wCharOffsets[i-1]; 47. int index2 = gfontdef3.wCharOffsets[i]; 48. int j; 49. for( j = index1; j < index2; j++ ) 50. *(pnewdata3 + ++j) |= 0x2; 51. } 52. } 53. else // fontsize = 8; 54. { 55. for( i = 1; i < charnum; i++ ) 56. { 57. int index1 = gfontdef3.wCharOffsets[i-1]; 58. int index2 = gfontdef3.wCharOffsets[i]; 59. int j; 60. for( j = index1; j < index2; j++ ) 61. *(pnewdata3 + j) |= 0x80; 62. } 63. } 64. gpfont3 = new Font(&gfontdef3); 65.}Note: Even if we just need the reversed ( or any customed ) font, not the normal one, we still need to allocate memory for bCharDefinitions. The memory pointed to by original font definition 's bCharDefinitions is "constant". For RimOS, it means the flash memory. Writing to this will cause a memory fault.
... #includeThere are a lot of useful fonts that we can find at http://resources.rimdev.com/codesnippet.htm// include the font definition file ... Font * font = new Font( &EightFontB );
Edit m_edit_name; m_edit_name.SetBuffer(11,11); m_edit_name.Append("Hello world"); m_edit_name.SetFont( &font1 );
In this case, all the characrers in the field will be applied the same font format.
If you need to have an edit field that can have multiple fonts, then use class RichText. In order to specify which fonts that it will need, use void SetFonts(Font const * const * fonts, int nFonts). This function will let ReciText knows of the font definitions and their corresponding data. To know which part of RichText will apply which font, use void SetAttributes(TextRangeAttribute const * AttributeArray, int NumberOfAttributes). TextRangeAttribute is declared privately in class RichText as follows ( copied from RichText.h):
struct TextRangeAttribute { int Offset; int Length; unsigned char Attribute; //current implementation supports only font index (0..4) };where offset is the starting position in the text that will apply the font specified by Attribute as an index into the array of Fonts that specified in SetFonts, and length is the number of characters starting from Offset will apply this font. Note: although there is a comment of index from 0 to 4, but I 've tried to use SetFonts with 7 fonts, and SetAttributes with index of 5 and 6, it still works.
An example for using RichText with Font:
RichText m_richtext; RichText::TextRangeAttribute arAttb[3]; Font const * arFonts[3]; const char * pSentence = "This is font 0.This is font 1.This is font 3."; arFont[0] = new Font( &font0definition ); arFont[1] = new Font( &font1definition ); arFont[2] = new Font( &font2definition ); m_richtext.SetFonts( arFonts, 3 ); arAttb[0].Offset = 0; // beginning of pSentence : "This is font 0" arAttb[0].Length = 15; arAttb[0].Attribute = 0; // index into arFonts arAttb[0].Offset = 15; // "this is font 1" arAttb[0].Length = 15; arAttb[0].Attribute = 1; // index into arFonts arAttb[0].Offset = 30; // "this is font 2" arAttb[0].Length = 15; arAttb[0].Attribute = 2; // index into arFonts m_richtext.SetAttributes( arAttb, 3 );All the above are much more than what I need for my apps, and that's all I know about fonts on RIMOS.