2007-12-07

Font-Be-Gone

Last change of the day. I’ve conflated the text font and glyph font into the same bitmap, saving about 30K off the final ROM size. Initially tried putting the glyphs at the start of the file, but ran into problems with this - char(10) and char(13) are line feed and carriage return, and there are a few other non-printing characters that appear regularly in text. I’ve shifted the glyphs to char(128) onwards - the extended ASCII set isn’t used very often.

In order to achieve this, I’ve made a few changes:

  • TextWriter has another function for printing chars
  • GraphicsPort has another function for printing chars
  • The base Gadget class contains a Font pointer
  • All gadgets accept a Font pointer in their constructors
  • Removed all references to _glyphFont

Just need to have a setFont(Font* font) method on there now.

EDIT:

Gadget::setFont() and Gadget::getFont() are now done. Woopsi creates its own font and deletes it in its destructor if no font is specified in its constructor. Also, passing in NULL as the font parameter is possible on some of the gadgets (I need to work out which ones don’t need a font for initialisation and make it an optional parameter). Any gadgets with a NULL font are automatically sent a pointer to their parent’s font when they are added to the parent’s child vector.

Comments

Jeff on 2007-12-07 at 01:05 said:

Speechless! Thanks for this.

ant on 2007-12-07 at 01:10 said:

Heh, no prob. It’s all done at speed at 1AM, so don’t be too surprised if you find that something doesn’t make sense or doesn’t quite work properly.

Jeff on 2007-12-07 at 07:59 said:

I’ve added a bug report on SourceForge - Button() allows you to pass a NULL font in, but expects it to be populated prior to addGadget() time because it calls calculateTextPosition() (Obviously, its not just button, its all the TextBox derived classes which include the screen decorations, the window decorations, etc…

I’m not quite sure how to protect against that, to be honest - you can probably safely defer the calculation of the position till the first time you draw, but that makes draws slower every time.

I suspect the cheapest answer is to have the Gadget constructor to read a ‘default font’ that the Woopsi constructor populates. ie, in Gadget::Gadget(), you check font for null and substitute in Woopsi::defaultFont()

Jeff on 2007-12-07 at 09:03 said:

As it stands, I can now build my Woopsi app with virtually none of the all_gfx stuff that the standard sources include, with only a few minor changes which I think would be a good idea - there’s a lot of pollution in there from the demo application.

main.cpp: //#include “bitmap/all_gfx.c”

include “bitmap/font.h”

include “bitmap/font.c

bitmap/font.h:

ifndef ALL_GFX_H

define ALL_GFX_H

extern const unsigned short font_Bitmap[12800] attribute ((aligned (4))) ; #endif

woopsi.cpp:

include “woopsi.h”

include “bitmap/font.h”

debug.h: //#include “textwriter.h” //#include “font.h” //#include “bitmap/all_gfx.h

debug.cpp:

include “debug.h”

include “textwriter.h”

include “font.h”

include “bitmap/font.h”

I’d be inclined to rename bitmap/font.c as sysfont.c and I’d move it into the woopsi source directory - ie, remove it from the bitmap directory altogether. That way, it becomes “strongly supported”. Its a bit tedious at PAgfx time, but thats infrequent compared to regular application builds.

ant on 2007-12-07 at 10:16 said:

Yeah, this is what I was alluding to when I mentioned that some gadgets expect to receive a valid Font pointer. My solution was to make the font parameter optional on any gadgets that don’t need to have it instantiated immediately. Any gadgets that don’t make their font optional, therefore, must be sent a valid font. This solution depends on the programmer understanding the difference between the two different font requirements, so it’s not the best solution.

Adding a static method to Woopsi that served up the default font would work, but that would need to create at least one more instance of the font class - the Woopsi class would need a static variable that stored a pointer to a font, and that would have to be created when the static method was accessed (if the static font didn’t already exist). Waste of memory. Plus, there would be no way to delete the font automatically, as we’d never know when it wasn’t needed any more.

A third solution would be to change the lifecycle of a gadget. All initialisation code could be moved out of the constructor and into a Gadget::initialise() function. That function would be called when the gadget is added to a parent, like this:

Gadget::addGadget(Gadget* gadget) { _gadgets.push_back(gadget); gadget->initialise(); }

Not sure of the greater impact of this change, though. It probably wouldn’t work for something like the MultiLineTextBox and the TextViewer, which don’t store a pointer to the text that they show but create a duplicate and store it internally. They can’t store a pointer because the original value could go out of scope, and they can’t duplicate the text without having a valid font because the font’s dimensions determine how the text is copied (wrapping, etc).

ant on 2007-12-07 at 10:56 said:

Oh, the spam filter has made the comments out of sync. If I didn’t have it turned on, though, I’d have about 20 comments a day telling me what a fantastic job I’ve done talking about “Downtime” on this glorious Thursday.

Anyhoo - yep, I do need to switch the font around, and I need to get rid of all_gfx. I was tempted to do this yesterday, actually - now that I’m only building one font, it’s less effort to copy things around.

Let’s see if I’ve got this right. Moving the includes from “debug.h” into “debug.cpp” means that those things are only included if “debug.h” is included. Makes sense. “main.cpp” includes the font instead of “all_gfx.h” - can’t really do this because the demo needs the other graphics. The “main.cpp” file isn’t part of the Woopsi folder anyway, so that shouldn’t be a problem. “woopsi.cpp” and “debug.cpp” include the font instead of “all_gfx.h” - makes sense. I don’t quite understand the “#define ALL_GFX_H” in the font file - are you suggesting this for Woopsi as a whole, or just for your project?

In fact, let’s just do it - I’ll rename the font next time I get chance to work on Woopsi and extract it from “all_gfx.h”.

Jeff on 2007-12-07 at 11:46 said:

I just hacked on the existing all_gfx.h file and left the duplicate protection in. Nothing deliberate.

In fact, I don’t use that stuff at all - I’m a “#pragma once” kind of guy these days.

I would move the inclusion of the font into woopsi.cpp rather than main.cpp - but I was originally trying to modify your sources as little as possible…

ant on 2007-12-07 at 15:18 said:

Oh! Duh, here’s a solution for the static font problem. If Woopsi requests its font from Woopsi::getSystemFont() (the static font retrieval function), there will only be one instance of the default font in the system.

When Woopsi gets deleted, it could probably delete the font at the same time. I could even implement some sort of reference counting thing. Woopsi::getSystemFont() would increase the static reference count by one. Gadget::~Gadget() could call Woopsi::freeSystemFont(), another static method that decreases the reference count. When Woopsi gets deleted, if the reference count is 0, it can delete the font.

getSystemFont() would look like this:

Font* getSystemFont() if static font = null create new font end refcount++ end

freeSystemFont() would look like this:

void freeSystemFont() if --refcount = 0 delete font font = null end end

Jeff on 2007-12-07 at 20:35 said:

I think you’re being over-complicated. When the Woopsi is deleted, the whole application is toast so its no problem deleting the font object - no-one can possibly continue to use it.

ant on 2007-12-08 at 10:47 said:

Heh, good point!