I have been considering to replace the OLED with a TFT screen and use a variable width font to allow more characters on the screen. This meant obtaining the width of each font character.
I cannot do this with the inbuilt fonts so have will be requesting an addition feature as I post this.
The Freefonts which can be added to font slots 10-> were more accessible so I present a pair of programs and some sample pictures using variable width font FreeSans9pt7b.bin.
First a comparison of word-wrapped and normal text on a 2.8" 320x240 TFT. And a sample screen from the web radio prototype on a 1.69" 280x240 TFT.
The first program extracts the character spaces (usually about 126 of them) from the font file and creates a much smaller binary file for use in the main program(s)
Code: [Local Link Removed for Guests]
CODE: xxxx.bas
--------------------------------------------------------------------------------
'Program to get character widths (x-advance) from a binary font file
'and create a binary file (usually only 128 bytes) for use in other programs
'/rdfontwidths.bas
fontfile$ = "/FreeSans9pt7b.bin"
Ret = FILE.EXISTS(fontfile$)
if ret = 0 then wlog "no file" : end
fl$ = word$(fontfile$, 1, ".")&".wid"
siz = file.size(fontfile$)
iobuff.dim(0, siz)
'load the basic info from beginning of font file
FILE.READ_IOBUFF(0), fontfile$ , 0, 16
segsizelo = iobuff.read(0, 0)
segsizehi = iobuff.read(0, 1)
charfirst = iobuff.read(0, 8)
charlast = iobuff.read(0, 10)
yadvance = iobuff.read(0, 12) 'not used here
segsize = (segsizehi*256) + segsizelo
offset = 16
glyphaddr = segsize + offset
'Now load the individual character x-advance (width) information
FILE.READ_IOBUFF(0), fontfile$ , glyphaddr, siz
iobuff.dim(1, charlast+1)
for j = 0 to charlast-charfirst
wlog chr$(j + charfirst),
ptr = j*12 + 6 'there are 12 bytes per character and x-advance is the 6th byte
v1 = iobuff.read(0, ptr)
wlog v1
iobuff.write(1, j + charfirst, v1)
next j
FILE.WRITE_IOBUFF(1), fl$
'==============================================================
' just test the binary file looks ok
IOBUFF.DESTROY(0)
iobuff.dim(0, 128)
FILE.READ_IOBUFF(0), fl$, 0, 127
wlog "______________________________"
for i = 32 to 126
wlog chr$(i), iobuff.read(0, i)
next i
Code: [Local Link Removed for Guests]
CODE: xxxx.bas
--------------------------------------------------------------------------------
'program to get character widths (x-advance) from a previously created binary file (rdfont.bas)
'/wordwrap.bas
fontfile$ = "/FreeSans9pt7b.bin"
'set size of tft screen ( OR TEXT AREA )
maxwid = 320 ' number of tft pixels (width)
maxht = 240 ' number of tft pixels (height)
fontsize = 1 'mutiplier for text size
fl$ = word$(fontfile$, 1, ".")
fl$ = fl$ & ".wid"
'initialise with 128 byte file previously created from Freesans9pt7b font
Ret = FILE.EXISTS(fl$)
if ret = 0 then wlog "No file":end
'read character info from the font file
iobuff.dim(0, 16)
FILE.READ_IOBUFF(0), fontfile$ , 0, 16
charfirst = iobuff.read(0, 8)
charlast = iobuff.read(0, 10)
yadvance = iobuff.read(0, 12) * fontsize
' now load the individual character widths to a buffer
loadwidths fl$
Ret = FILE.EXISTS(fl$) : if ret = 0 then wlog "No file" : end
xadv = 0 : py = 0
'
'get width of space character
ch = asc(" ") : getcharwid ch, xadv
spwid = xadv
'get width of widest characte = "W"
ch = asc("W") : getcharwid ch, xadv
maxcharwid = xadv
'initialise the tft
tft.init 1
TFT.LOADFONT fontfile$, 2
tft.text.font 11
tft.text.size fontsize
tft.fill tft.color(black)
tft.text.color white
'set some dummy text string
Aa$ = "The quick brown fox jumps over the lazy dog. "
bb$= "Now is the time for all good men to come to the aid of the party."
cc$ = aa$ + " " + bb$ + " " + aa$ + " " + bb$ + " " + aa$ + " " + bb$ + " " + aa$ + " " + bb$
'write the text to screen with word wrap
wraptft cc$
end
'=============================================================
'--------------------------- the wrap routine --------------
sub wraptft(a$)
p$ = "" : st = millis
py = yadvance - 6 ' account for the font character offset
tft.text.pos 0, py
'check total string width in case it would fit
strlen = len(a$) : totwid = strlen * maxcharwid
if totwid< = maxwid then
wlog "It fits!" : tft.print a$
else
totwid = 0 : wordwid=0 : wordcount = word.count(a$)
for j = 1 to wordcount
w$ = word$(a$, j) : getwordwid w$ ,wordwid
totwid = totwid + spwid + wordwid
if totwid>maxwid then 'have printed the current words so continue
totwid = wordwid + spwid
tft.print p$ : p$ = w$
py = py + yadvance: tft.text.pos 0, py
if py> = maxht then
p$ = "" : exit for
endif
else 'just continue adding to the string to print
p$ = p$ & " " & w$
endif
next j
tft.print p$
endif
wlog millis-st
end sub
'________________________________________________
'------------- subroutines for character widths-------------------
sub getwordwid(w$,wordwid) 'get the width of a single word
wordwid = 0
for i = 1 to len(w$)
ch = asc(mid$(w$, i, 1))
getcharwid ch, xadv
wordwid = wordwid + xadv
next i
end sub
sub getcharwid(ch, xadv) ' get the pixel width of a single character
xadv = IOBUFF.READ(1, ch)
xadv = xadv * fontsize
end sub
sub loadwidths(f$) 'load buffer from 128 byte width file
iobuff.dim(1, charlast)
FILE.READ_IOBUFF(1), f$, 0, charlast
end sub
Note that although the simple program fits the text to the screen boundaries, it is possible to constrain the text to a smaller area.
Feature request going in now...