This chapter describes how to work with fonts in a Photon application.
It's possible - and common - to hard-code all references to fonts in a Photon application. But there's a more flexible approach where applications can choose the best match from whatever fonts are available. That way, there isn't a problem if a particular font is eventually renamed, removed, or replaced.
To specify a font in the Photon API, you always use a stem name. For example, the following call to PtAskQuestion() uses the stem name helv14 to specify 14-point Helvetica:
PtAskQuestion (base_wgt, NULL, "File has not been saved. Save it?", "helv14", "&Save", "&Discard", "&Cancel", 1);
If you're using QNX 4.25, you'll find the available stem names listed in /qnx4/photon/font/fontdir. If you're using QNX Neutrino 2, look in /nto/photon/font/fontdir.
Alternately, if you have a $HOME/.photon directory, check in $HOME/.photon/font/fontdir. Photon creates this local file only when needed, such as when you run the fontcfg utility to create your own personal font configuration. Until the local file is created, Photon uses the global file.
The above example takes a shortcut by using a hard-coded stem name (helv14).And, like any shortcut, this approach has tradeoffs. First, stem names are subject to change. More importantly, all versions of Photon up to and including 1.13 have only 16 characters available for the stem name. This isn't always enough to give each font a unique stem. Photon 1.14 for QNX Neutrino has 80 characters
To get around these problems, use PfQueryFonts() to provide the information needed to build your stem name. This function queries the Photon Font Server, and protects you from future changes.
Let's start with the parameters to PfQueryFonts() - then we'll look at a code sample that extracts the stem name from the data returned by the function.
The function itself looks like this:
PfQueryFonts (long symbol, unsigned flags, FontDetails list[], int n );
The arguments are:
For instance, a Unicode space symbol (0x0020) is available in almost any font. Specifying an é symbol (Unicode 0x00c9), on the other hand, narrows down the font choices considerably. And, of course, specifying a Japanese character selects only Japanese fonts.
To include all available fonts, use PHFONT_ALL_SYMBOLS.
If PfQueryFonts() is successful, it returns the number of fonts available that matched your selection criteria. Otherwise, it returns -1.
If n is 0 and list is NULL, PfQueryFonts() returns the number of matching fonts but doesn't try to fill in the list. You can use this feature to determine the number of items to allocate for the list. |
Once you've got the list of fonts, you'll need to tear apart the FontDetails structure for each. That way, you can find both the font you need and the string to use as a stem name.
The FontDetails structure is defined in <photon/Pf.h>, and is defined as:
typedef struct { FontDescription desc; FontName stem; short losize; short hisize; unsigned short flags; } FontDetails;
For our purposes, the desc and stem elements the most useful, but let's review them all.
Now that we've looked at the pieces involved, it's fairly simple to follow the steps needed to build up the correct stem name for a given font.
Keep these things in mind:
You'll probably want to do this work in the initialization function for your application, or perhaps in the base window setup function. Once you've constructed the stem name, keep the string in a global variable. You can then use it as needed.
Here's a sample application-initialization function:
/*************************** *** global variables *** ***************************/ char GcaCharter14Bold [MAX_FONT_TAG + 1]; /* Remember: there's no point in having a larger buffer than the stem name's size (plus 1 to allow for a NULL-terminated string */ int fcnAppInit( int argc, char *argv[] ) { /* Local variables */ FontDetails tsFontList [nFONTLIST_SIZE]; short sCurrFont = 0; char caBuff[20]; /* Get a description of the available fonts */ if (PfQueryFonts (PHFONT_ALL_SYMBOLS, PHFONT_ALL_FONTS, tsFontList, nFONTLIST_SIZE) == -1) { perror ("PfQueryFonts() failed: "); return (Pt_CONTINUE); } /* Search among them for the font that matches our specifications */ for (sCurrFont = 0; sCurrFont < nFONTLIST_SIZE; sCurrFont++) { if ( !strcmp (tsFontList[sCurrFont].desc, "Charter") ) break; /* we've found it */ } /* Overrun check */ if (sCurrFont == nFONTLIST_SIZE) { /* check for a partial match */ for (sCurrFont = 0; sCurrFont < nFONTLIST_SIZE; sCurrFont++) { if ( !strncmp (tsFontList[sCurrFont].desc, "Charter", strlen ("Charter") ) ) break; /* found a partial match */ } if (sCurrFont == nFONTLIST_SIZE) { printf ("Charter not in %d fonts checked.\n", sCurrFont); return (Pt_CONTINUE); } else printf ("Using partial match -- 'Charter'.\n"); } /* Does it have bold? */ if (!(tsFontList[sCurrFont].flags & PHFONT_INFO_BOLD)) { printf ("Charter not available in bold font.\n"); return (Pt_CONTINUE); } /* Is 14-point available? */ if ( !( (tsFontList[sCurrFont].losize == tsFontList[sCurrFont].hisize == 0) /* proportional font -- it can be shown in 14-point*/ || ( (tsFontList[sCurrFont].losize <= 14 ) && (tsFontList[sCurrFont].hisize >= 14 ) ) ) ) /* 14-point fits between smallest and largest available size */ { printf ("Charter not available in 14-point.\n"); return (Pt_CONTINUE); } /* Build up the stem name */ strncpy (GcaCharter14Bold, tsFontList[sCurrFont].stem, MAX_FONT_TAG); if (GcaCharter14Bold[0] == '\x0') { printf ("Charter font stem name was blank.\n"); return (Pt_CONTINUE); } strcat (GcaCharter14Bold, itoa (14, caBuff, 10) ); strcat (GcaCharter14Bold, "b"); strcat (GcaCharter14Bold, ""); /* note the NULL termination */ /* You can now use GcaCharter14Bold as an argument to PtAskQuestion(), etc. */ /* Eliminate 'unreferenced' warnings */ argc = argc, argv = argv; return( Pt_CONTINUE ); }
For the above code to work, you must declare the following information in the application's global header file. To do this, use PhAB's Startup Info/Modules dialog (accessed from the Application menu).
/********************************* *** user-defined constants *** *********************************/ #define nFONTLIST_SIZE 100 /* an arbitrary choice of size */ /*************************** *** global variables *** ***************************/ extern char GcaCharter14Bold [];
Remember to define this header before you start adding callbacks and setup functions -- that way, it will be automatically included as a #define. If you forget, you'll have to go back and add the statement manually.
And last of all, here's a sample callback that uses our stem name string:
int fcnbase_btn_showdlg_ActivateCB( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) /* This callback is used to launch a dialog box with the intent of exercising the global variable GcaCharter14Bold */ { PtAskQuestion (ABW_base, "Font Demonstration", "This sentence is in 14-pt. Charter bold", GcaCharter14Bold, "OK", NULL, NULL, 1); /* Eliminate 'unreferenced' warnings */ widget = widget, apinfo = apinfo, cbinfo = cbinfo; return( Pt_CONTINUE ); }