[Previous] [Contents] [Index] [Next]

Fonts

Although the Photon libraries provide many functions that deal with fonts (see the Pf -- Font Server chapter of the Photon Library Reference), most of them are low-level routines that you probably don't need to use. This chapter describes the basics of using fonts.

This chapter includes:

Symbol metrics

Let's start with some definitions:


Symbol metrics


Symbol metrics


Advance
The amount by which the pen x position advances after drawing the symbol. This might not be the full width of the character (especially in an italic font) to implement kerning.
Ascender
The height from the baseline to the top of the character.
Bearing x or left bearing
The amount of the character to the left of where the character is deemed to start.
Descender
The height from the bottom of the character to the baseline.
Extent
The width of the symbol. Depending on the font, this might include some white space.
Origin
The lower left corner of the character
X Max
The width of the symbol, not including the bearing x.

Note: To save time and memory, kerning isn't supported.

Font names

A font is identified by its name, which can be in one of these forms:

foundry name
The name assigned by the font foundry to identify the font family, such as Helvetica, Comic Sans MS, and PrimaSans BT. Note the use of capitals.

The foundry name doesn't include information about the style (e.g. bold, italic) or the size. This name is universal across operating environments (e.g. X, Photon).

stem name
A unique identifier that includes an abbreviation of the foundry name, as well as the style (e.g. b, i) and the size. For example, helv12 is the stem name for 12-point Helvetica, and helv12b is the stem name for 12-point bold Helvetica.

To specify a font in the Photon API, you always use a stem name. You should consider stem names to be constant identifiers, not modifiable strings.

You can hard-code all references to fonts in a Photon application. But your application can be more flexible if it uses the foundry name to 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.

For example, the following call to PtAlert() uses the hard-coded stem name helv14 to specify 14-point Helvetica:

answer = PtAlert(
            base_wgt, NULL, "File Not Saved", NULL,
            "File has not been saved.\nSave it?",
            "helv14", 3, btns, NULL, 1, 3, Pt_MODAL );

You can get the available stem names from the names of the files in ${PHOTON_PATH}/font -- just remove any file extension (e.g. .phf).

Alternately, if you have a $HOME/.ph directory, check in $HOME/.ph/font/. The Photon microGUI creates this local file only when needed, such as when you run the fontadmin utility (see the QNX 6 Utilities Reference) to create your own personal font configuration. Until the local file is created, the microGUI uses the global file.

Querying available fonts

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 the Photon microGUI 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. The current version of the Photon microGUI allows 80 characters.

To get around these problems, you can use PfQueryFonts() to determine which fonts are available and provide the information needed to build a 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:

symbol
A key for searching the Photon Font Manager. The function looks for fonts that include this symbol and discards those that don't have it.

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. For a list of symbols, see PkKeyDef.h or ISO/EIC 10646-1.

To include all available fonts, use PHFONT_ALL_SYMBOLS.

flags
Provides another way to narrow down your search. Available values:
list[]
An array that the Photon Font Manager fills in for you. You need to declare a FontDetails structure, which is described below.
n
The number of elements available in the list array.

If PfQueryFonts() is successful, it returns the number of fonts available that matched your selection criteria. Otherwise, it returns -1.


Note: 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.

FontDetails structure

Once you've got the list of fonts, you need to examine each FontDetails structure in it to find the font you need and determine the string to use as the 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:

desc
The foundry name or full descriptive name of the font, such as Helvetica or Charter.
stem
The short form. This provides a part of the stem name used by the Photon API calls. For example, helv and char correspond to Helvetica and Charter.
losize
The minimum available point size for the font, say 4.
hisize
The largest size the font has available. If both losize and hisize are 0, the font is scalable.
flags
Available values:

Generating font names

As described earlier, the Photon API requires a stem name to identify a font, but if you want to be flexible, you should use a font foundry name.

The easiest way to get a stem name, given the font foundry name, desired point size, and style, is to call PfGenerateFontName(). It creates, in a buffer that you supply, a unique stem name for the font. (You can use this approach even if you don't use PfQueryFonts() to find all the available fonts.) The prototype is:

uchar_t * PfGenerateFontName(
             uchar_t const *pkucDescription,
             uint32_t const kuiFlags,
             uint32_t const kuiSize,
             uchar_t *pucBuff );

If PfGenerateFontName() succeeds, it returns a pointer to the buffer; if it fails, it returns NULL.

We've defined the FontName data type for you to use for the buffer you pass to PfGenerateFontName(). It's an array of size MAX_FONT_TAG. For successful font programming, don't use a font identifier storage buffer that's smaller than FontName.

Here's the same call to PtAlert() as shown earlier, but this time it calls PfGenerateFontName():

char Helvetica14[MAX_FONT_TAG];

if ( PfGenerateFontName("Helvetica", 0, 14,
                         Helvetica14) == NULL )
{
  /* Couldn't find the font! */
  ...
}

answer = PtAlert(
            base_wgt, NULL, "File Not Saved", NULL,
            "File has not been saved.\nSave it?",
            Helvetica14, 3, btns, NULL, 1, 3,
            Pt_MODAL );

Example

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. Define the FontName buffer as a global variable; you can then use it as needed throughout your application.

Here's a sample application-initialization function:

/***************************
***   global variables   ***
***************************/

FontName GcaCharter14Bold;

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);
    }

    /* Generate the stem name */
    if (PfGenerateFontName( tsFontList[sCurrFont].desc,
                            PF_STYLE_BOLD, 14,
                            GcaCharter14Bol) == NULL)
    {
       perror ("PfGenerateFontName() failed:  ");
       return (Pt_CONTINUE);
    }
         
    /* You can now use GcaCharter14Bold as an argument to
       PtAlert(), 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 FontName GcaCharter14Bold;

You can avoid using a specific size for the list by calling PfQueryFonts() with n set to 0 and list set to NULL. If you do this, 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.

Remember to define this header before you start adding callbacks and setup functions -- that way, it's automatically included as a #define. If you forget, you'll have to go back and add the statement manually. For more information, see "Specifying a global header file" in the Working with Applications chapter.

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 */

{
   PtNotice (ABW_base, NULL, "Font Demonstration", NULL,
             "This sentence is in 14-pt. Charter bold",
             GcaCharter14Bold, "OK", NULL, 0);

   /* Eliminate 'unreferenced' warnings */
   widget = widget, apinfo = apinfo, cbinfo = cbinfo;

   return( Pt_CONTINUE );
}

Writing text in a rectangular area

Writing text in a rectangle of a specific size can be tricky if the string size is unknown.

Consider a rectangle of fixed dimensions, for example a cell in a spreadsheet. How do you determine how many characters can successfully be displayed in this cell without clipping? Call PfExtentTextToRect(). Give it a clipping rectangle, a font identifier, a string, and the maximum number of bytes within the string, and it tells you the number and extent of the characters that fit within the clipping rectangle.

This is useful for placing an ellipsis (...) after a truncated string and avoiding partially clipped characters. Currently this routine supports clipping only along the horizontal axis.

Here's an example:

/* PfExtentTextToRect */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Ap.h>
#include <Ph.h>
#include <Pt.h>
#include <errno.h>

PtWidget_t * pwndMain = NULL, * pbtn = NULL, * pobjRaw = NULL;
char * pcText = "pAfaBfbfffffffffffffffCfcXfxYfyZfzf";
char * pcGB = "\323\316\317\267";
char ** ppcData = NULL;

int fnDrawCanvas( PtWidget_t * ptsWidget, PhTile_t * ptsDamage );

#define FALSE 0

FontName szFont;

char * pmbGB = NULL;
struct PxTransCtrl * ptsTrans = NULL;
int iTemp1 = 0, iTemp2 = 0;

#define BUFFER_SIZE 256

int main (int argc, char *argv[])
{   PtArg_t args[4];
    PhPoint_t win_size, pntPOS, pntDIM;
    short nArgs = 0;

    if((pmbGB = calloc(BUFFER_SIZE, sizeof(char))) == NULL)
      return(EXIT_FAILURE);

    PtInit (NULL);

    if(argc > 1)
    {  if(PfGenerateFontName(argv[1], 0, 9, szFont) == NULL)
         PfGenerateFontName("TextFont", 0, 9, szFont);
    }
    else
      PfGenerateFontName("TextFont", 0, 9, szFont);

    if((ptsTrans = PxTranslateSet(NULL, "GB2312-80")) == NULL)
      return(EXIT_FAILURE);

    if(PxTranslateToUTF(ptsTrans, pcGB, 4, &iTemp1, pmbGB,
                        BUFFER_SIZE, &iTemp2) == -1)
      printf("Could not translate from GB to UTF.\n");

    if(argc > 2)
      pcText = pmbGB;

    /* Set the base pwndMain parameters. */
    win_size.x = 450;
    win_size.y = 450;

    PtSetArg(&args[0],Pt_ARG_DIM, &win_size, 0);
    PtSetArg(&args[1],Pt_ARG_WINDOW_TITLE,
             "PfExtentTextToRect", 0);

    pwndMain = PtCreateWidget (PtWindow, Pt_NO_PARENT, 2, args);

    nArgs = 0;
    pntPOS.x = 100;
    pntPOS.y = 10;
    PtSetArg(&args[nArgs], Pt_ARG_POS, &pntPOS, 0);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_TEXT_STRING, pcText, NULL);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_TEXT_FONT, szFont, NULL);
    nArgs++;
    pbtn = PtCreateWidget(PtButton, pwndMain, nArgs, args);
    PtRealizeWidget(pbtn);

    pntPOS.y = 100;
    pntPOS.x = 75;
    pntDIM.x = 300;
    pntDIM.y = 300;
    PtSetArg(&args[0], Pt_ARG_POS, &pntPOS, 0); 
    PtSetArg(&args[1], Pt_ARG_DIM, &pntDIM, 0);
    PtSetArg(&args[2], Pt_ARG_RAW_DRAW_F, fnDrawCanvas, 0L);
    pobjRaw = PtCreateWidget(PtRaw, pwndMain, 3, args);

    PtRealizeWidget(pwndMain);

    PtMainLoop ();

    return(0);
}

#define ASCENDER tsExtent.ul.y
#define DESCENDER tsExtent.lr.y

int fnDrawCanvas( PtWidget_t * ptsWidget, PhTile_t * ptsDamage )
{   PhRect_t tsExtentClip;
    PhRect_t rect;
    PhPoint_t pnt;
    PhRect_t tsExtent;
    PgColor_t old;
    PhPoint_t pnt2;
    PhPoint_t tsPos = {0, 0};
    int iRet = 0;
    int iBytes = 0;

    /* Find our canvas. */
    PtBasicWidgetCanvas(pobjRaw, &rect);

    old = PgSetStrokeColor(Pg_BLACK);

    PfExtentText(&tsExtent, &tsPos, szFont, pcText,
                 strlen(pcText));

    /* Draw the text. */
    pnt.x = 10 + rect.ul.x;
    pnt.y = 100 + rect.ul.y;

    PgSetFont(szFont);
    PgSetTextColor(Pg_BLACK);
    PgDrawText(pcText, strlen(pcText), &pnt, 0);

    pnt.x -= 10;
    pnt2.x = pnt.x + tsExtent.lr.x + 20;
    pnt2.y = pnt.y;

    PgSetStrokeColor(Pg_BLUE);

    PgDrawLine(&pnt, &pnt2);

    pnt.x = 10 + rect.ul.x;
    pnt.y = 100 + rect.ul.y;

    PgSetStrokeColor(Pg_RED);

    PgDrawIRect(tsExtent.ul.x + pnt.x,
                tsExtent.ul.y + pnt.y,
                (tsExtent.lr.x - min(tsExtent.ul.x, 0)
                + 1) + pnt.x, tsExtent.lr.y + pnt.y,
                Pg_DRAW_STROKE);

    if((iRet = PfExtentTextToRect(&tsExtentClip, szFont,
                  &tsExtent, pcText, strlen(pcText))) == -1)
      printf("PfExtentTextToRect failed 1.\n");
    else
    {  printf("lrx == %d, %d characters in string.\n",
              tsExtent.lr.x, mbstrlen(pcText, 0, &iBytes));
       printf("PfExtentTextToRect lrx == %d, %d characters will\
 fit in clip of %d.\n", tsExtentClip.lr.x, iRet, tsExtent.lr.x);
    }

    tsExtent.lr.x /= 2;

    if((iRet = PfExtentTextToRect(&tsExtentClip, szFont,
                  &tsExtent, pcText, strlen(pcText))) == -1)
      printf("PfExtentTextToRect failed 2.\n");
    else
    {  printf("lrx == %d, %d characters in string.\n",
              tsExtent.lr.x, mbstrlen(pcText, 0, &iBytes));
       printf("PfExtentTextToRect lrx == %d, %d characters will\
 fit in clip of %d.\n", tsExtentClip.lr.x, iRet, tsExtent.lr.x);
    }

    pnt.x = 10 + rect.ul.x;
    pnt.y = 150 + rect.ul.y;

    PgDrawText(pcText, iRet, &pnt, 0);
    PgDrawIRect(tsExtentClip.ul.x + pnt.x,
                tsExtentClip.ul.y + pnt.y,
                (tsExtentClip.lr.x - min(tsExtentClip.ul.x, 0)
                + 1) + pnt.x, tsExtentClip.lr.y + pnt.y,
                Pg_DRAW_STROKE);

    tsExtent.lr.x /= 2;

    if((iRet = PfExtentTextToRect(&tsExtentClip, szFont,
                  &tsExtent, pcText, strlen(pcText))) == -1)
      printf("PfExtentTextToRect failed 3.\n");
    else
    {  printf("lrx == %d, %d characters in string.\n",
              tsExtent.lr.x, mbstrlen(pcText, 0, &iBytes));
       printf("PfExtentTextToRect lrx == %d, %d characters will\
 fit in clip of %d.\n", tsExtentClip.lr.x, iRet, tsExtent.lr.x);
    }

    pnt.x = 10 + rect.ul.x;
    pnt.y = 200 + rect.ul.y;

    PgDrawText(pcText, iRet, &pnt, 0);
    PgDrawIRect(tsExtentClip.ul.x + pnt.x,
                tsExtentClip.ul.y + pnt.y,
                (tsExtentClip.lr.x - min(tsExtentClip.ul.x, 0)
                + 1) + pnt.x, tsExtentClip.lr.y + pnt.y,
                Pg_DRAW_STROKE);

    PgSetStrokeColor(old);

    return( Pt_CONTINUE );
}

Repairing damage to proportional text

When dealing with proportional fonts, sometimes the vectors of one glyph run into the vectors of another. This is especially evident when using a font such as Nuptial BT. You need to take special care when repairing damage to such fonts.

PfExtentTextCharPositions() addresses this issue. You can use this routine to obtain the position after each character, incorporating the bearing x of the following character. This position is where you should draw the next character.

If you use the PF_CHAR_DRAW_POSITIONS flag, the bearing x of the following character isn't applied to the position, which is useful when you're placing cursors.

For example:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Ap.h>
#include <Ph.h>
#include <Pt.h>
#include <errno.h>

PtWidget_t * pwndMain = NULL,
           * pbtn = NULL,
           * pobjRaw = NULL,
           * pobjLabel = NULL;
char ** ppcData = NULL;

int fnDrawCanvas( PtWidget_t * ptsWidget,
                  PhTile_t * ptsDamage );

#define FALSE 0

#define __WIN_SIZE_X_ 1000

FontName szFont;

int main (int argc, char *argv[])
{   PtArg_t args[8];
    PhPoint_t win_size, pntPOS, pntDIM;
    short nArgs = 0;
    char caTitle[50];

    if(argc < 2)
    {  printf("Usage:  pen text_string\n");
       exit(EXIT_FAILURE);
    }

    PtInit (NULL);

    ppcData = argv;

    PfGenerateFontName("TextFont", 0, 9, szFont);

    /* Set the base pwndMain parms. */
    win_size.x = 800;
    win_size.y = 600;

    sprintf(caTitle, "Get the pen position");
    PtSetArg(&args[0],Pt_ARG_DIM, &win_size, 0);
    PtSetArg(&args[1],Pt_ARG_WINDOW_TITLE, caTitle, 0);

    pwndMain = PtCreateWidget (PtWindow, Pt_NO_PARENT, 2, args);

    nArgs = 0;
    pntDIM.x = 80;
    pntDIM.y = 20;
    PtSetArg(&args[nArgs], Pt_ARG_DIM, &pntDIM, 0);
    nArgs++;
    pntPOS.x = 100;
    pntPOS.y = 10;
    PtSetArg(&args[nArgs], Pt_ARG_POS, &pntPOS, 0);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_TEXT_STRING, argv[1], NULL);
    nArgs++;
    pbtn = PtCreateWidget(PtButton, pwndMain, nArgs, args);
    PtRealizeWidget(pbtn);

    nArgs = 0;
    pntDIM.x = 80;
    pntDIM.y = 20;
    PtSetArg(&args[nArgs], Pt_ARG_DIM, &pntDIM, 0);
    nArgs++;
    pntPOS.x = 100;
    pntPOS.y = 600;
    PtSetArg(&args[nArgs], Pt_ARG_POS, &pntPOS, 0);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_TEXT_STRING, argv[1], NULL);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_RESIZE_FLAGS,
             Pt_RESIZE_XY_ALWAYS, Pt_RESIZE_XY_ALWAYS);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_BORDER_WIDTH, 0L, 0L);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_MARGIN_LEFT, 0L, 0L);
    nArgs++;
    PtSetArg(&args[nArgs], Pt_ARG_MARGIN_RIGHT, 0L, 0L);
    nArgs++;
    pobjLabel = PtCreateWidget(PtLabel, pwndMain, nArgs, args);
    PtRealizeWidget(pobjLabel);

    pntPOS.y = 100;
    pntPOS.x = 75;
    pntDIM.x = __WIN_SIZE_X_ - 75 - 10;
    pntDIM.y = 300;
    PtSetArg(&args[0], Pt_ARG_POS, &pntPOS, 0); 
    PtSetArg(&args[1], Pt_ARG_DIM, &pntDIM, 0);
    PtSetArg(&args[2], Pt_ARG_RAW_DRAW_F, fnDrawCanvas, 0L);
    pobjRaw = PtCreateWidget(PtRaw, pwndMain, 3, args);

    (void) PtRealizeWidget(pwndMain);

    PtMainLoop ();

    return(0);
}

int fnDrawCanvas( PtWidget_t * ptsWidget, PhTile_t * ptsDamage )
{   unsigned char const * pucFont = NULL;
    int * piIndx = NULL;
    int * piPos = NULL;
    char ** argv = (char **)ppcData;
    PhRect_t rect;
    PhPoint_t pnt;
    PhPoint_t tsPos = {0, 0};
    PhRect_t tsExtent;
    short n = 0;
    char * pc = NULL;
    PgColor_t old;

    pucFont = szFont;
    pc = argv[1];
    piIndx = (int *)calloc(50, sizeof(int));
    piPos = (int *)calloc(50, sizeof(int));

    if(strlen(pc) < 4)
    {  printf("Pick a longer string, must be at least\
 4 characters.\n");
       exit(EXIT_SUCCESS);
    }

    for(n = 0; n < strlen(pc); n++)
      piIndx[n] = n + 1;

    /* Find our canvas. */
    PtBasicWidgetCanvas(pobjRaw, &rect);

    old = PgSetStrokeColor(Pg_BLACK);

    PfExtentText(&tsExtent, &tsPos, pucFont, pc, strlen(pc));

    PgSetFont(pucFont);
    PgSetTextColor(Pg_BLACK);

    for(n = 0; n < strlen(pc); n++)
      piIndx[n] = n + 1;

    /* Draw the string, one character at a time. */
    PfExtentTextCharPositions(&tsExtent, &tsPos, pc,
                              pucFont, piIndx, piPos,
                              strlen(pc), 0L, 0, 0, NULL);
    pnt.x = 10 + rect.ul.x;
    pnt.y = 200 + rect.ul.y;

    PgDrawIRect(tsExtent.ul.x + pnt.x,
                tsExtent.ul.y + pnt.y,
                (tsExtent.lr.x - min(tsExtent.ul.x, 0) + 1) +
                pnt.x, tsExtent.lr.y + pnt.y, Pg_DRAW_STROKE);

    for(n = 0; n < strlen(pc); n++)
    {  PgDrawText(pc + n, 1, &pnt, 0);
       pnt.x = 10 + rect.ul.x + piPos[n];
       printf("Single[%d]:  %d\n", n, piPos[n]);
    }
    /* End draw one character at a time. */

    /* Draw the string, then overlay individual characters on
       top from right to left. */
    printf("Overlay test.\n");

    PfExtentText(&tsExtent, &tsPos, pucFont, pc, strlen(pc));   
    pnt.x = 10 + rect.ul.x;
    pnt.y = 400 + rect.ul.y;

    PgDrawIRect(tsExtent.ul.x + pnt.x,
                tsExtent.ul.y + pnt.y,
                (tsExtent.lr.x - min(tsExtent.ul.x, 0) + 1) +
                 pnt.x, tsExtent.lr.y + pnt.y, Pg_DRAW_STROKE);

    PgSetFont(pucFont);
    PgSetTextColor(Pg_BLACK);
    PgDrawText(pc, strlen(pc), &pnt, 0);

    for(n = strlen(pc) - 1; n >= 0; n--)
    {  switch(n)
       {  case 0:  pnt.x = 10 + rect.ul.x;
                   PgDrawText(pc + 0, strlen(pc), &pnt, 0);
                   break;

          default: piIndx[0] = n;
                   PfExtentTextCharPositions(&tsExtent,
                      &tsPos, pc, pucFont, piIndx, piPos,
                      1, 0L, 0, 0, NULL);
                   printf("Position:  %d\n", piPos[0]);
                   pnt.x = 10 + rect.ul.x + piPos[0];
                   PgDrawText(pc + n, strlen(pc) - n, &pnt, 0);
                   PgFlush();
                   sleep(1);
                   break;
       } 
    }
    /* End draw string, then overlay individual characters
       on top from right to left. */

   PgSetStrokeColor(old);
   free(piPos);
   free(piIndx);

   return( Pt_CONTINUE );
}

[Previous] [Contents] [Index] [Next]