GPIGuide - Character String Primitives
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
Character String Primitives
Character string primitives are printed or displayed text limited to a length of 256 characters by the PM.
The following topics are related to information in this chapter:
- Presentation spaces and device contextf
- Color and mix attributes
- Fonts
- Coordinate spaces and transformations
About Character String Primitives
A PM application must make certain choices about fonts in preparation for text display or printing. Often these choices are driven by selections from a user. After the selections are made, as discussed in Fonts, the application can make additional decisions about the appearance of the individual characters within the font by setting attributes in the CHARBUNDLE data structure. CHARBUNDLE is the lowest of three levels of data structures that define the appearance of displayed or printed text. The other two, FONTMETRICS and FATTRS, are described in Fonts.
A font family—for instance, Helvetica or Courier—is a collection of fonts. Fonts within the same family share certain attributes such as stroke width and serif characteristics. Stroke width refers to the width of lines used to draw characters and symbols from a font. A serif is a short crossline drawn at the ends of the main strokes that form a character or symbol.
Individual fonts within a family differ from each other in the following ways:
- Height
- Line weight
- Appearance
Height refers to the point size of a font. A common example of line weight is boldface. A common example of appearance is italic.
The most important factor that affects the CHARBUNDLE attributes is whether the current font is an image or an outline font. The following figure shows an example of the difference.
Outline fonts are composed of characters drawn with straight and curved lines. Image fonts, also called bit map fonts, are composed of pels arranged in certain shapes.
Attributes of Character String Primitives
Attributes of the character string primitives contained in CHARBUNDLE are as follows:
- Character set
- Character mode
- Character cell
- Character angle
- Character shear
- Character direction
- Character text alignment
- Character extra
- Character break extra
- Foreground color
- Background color
- Foreground mix
- Background mix
When an application creates a presentation space, the character string attributes are set to the default values shown in the following table.
Character String Attribute Default Values
Attribute | Default Value | Function that Redefines Attribute |
---|---|---|
Set | LCID_DEFAULT | GpiSetCharSet |
Mode | CM_MODE1 | GpiSetCharMode |
Cell | Outline font - Defined by device Image font - Defined by font |
GpiSetCharBox |
Angle | (1,0) | GpiSetCharAngle |
Shear | (0,1) | GpiSetCharShear |
Direction | Left to right | GpiSetCharDirection |
Text alignment | Left | GpiSetTextAlignment |
Extra | 0 | GpiSetCharExtra |
Break extra | 0 | GpiSetCharBreakExtra |
Foreground color | Black | GpiSetAttrs(CBB_COLOR) |
Background color | Clear | GpiSetAttrs(CBB_BACK_COLOR) |
Foreground mix | Overpaint | GpiSetAttrs(CBB_MIX_MODE) |
Background mix | Leave alone | GpiSetAttrs(CBB_BACK_MIX_MODE) |
Current character attributes take effect when you send graphics characters to an output device. They have no effect at the time you define a logical font.
Character Set
Character set defines the local identifier, lcid, of the current font. The font lcid is set using GpiSetCharSet. GpiCreateLogFont associates the font with an lcid.
The value of the current lcid is determined using GpiQueryCharSet.
Character Mode
Every presentation space has a current character mode, which determines the extent to which a font can be affected by the attributes defined in CHARBUNDLE. The mode affects compatibility issues that are invisible to both the user and the programmer. The following table describes the character modes and their influences on the current font.
An application selects a character mode using GpiSetCharMode. When a mode is selected, it applies to any font (including the system font) used while the mode is current. The character mode takes effect when you draw character strings; it has no effect at the time you define a logical font.
Character Mode Effects on Character Attributes
Character Mode | If Image Font... | If Outline Font... |
---|---|---|
CM_MODE1 | Ignores all current character attributes, except character direction. | Affected by all current character attributes. |
CM_MODE2 | Uses the character shear, box, angle, and direction attributes to position the character cell, but the characters themselves are not sheared, rotated, scaled, or reversed. | Affected by all current character attributes. |
CM_MODE3 | Raises an error if you try to draw a character string. Note: Any font used when the current character mode is CM_MODE3 must be an outline font. |
Affected by all current character attributes. |
The default character mode (CM_DEFAULT) is identical to CM_MODE1.
Character Cell
A character cell is an imaginary rectangular boundary that defines the horizontal and vertical space occupied by a single character from an outline character set.
The PM calculates character cell width and height from the point size. The width value for the character cell is the nominal width of the lowercase characters in the character set. In a monospace font, the width of all character cells is identical. In a proportional font, the width of the character cells depends on the character.
In an image font, the height of the character cell is the number of pels in the font. In an outline font, the height of the character cell is the point size of the font.
The characters in a character string are positioned one character per cell. The spacing between adjacent characters in a string is affected by the character cell attribute, except for image characters in CM_MODE1.
Cell width determines the spacing of consecutive characters along the baseline, as illustrated in the following figure.
Current cell size is specified using GpiSetCharBox. As input, this function accepts the desired height and width of the character cell in world coordinates. These values are related to certain dimensions in the FONTMETRICS structure that controls font attributes. Heights or widths of 0 are valid input and cause the outline character to be drawn as a point or straight line. Heights or widths of negative values cause certain special effects, for example, reversed lettering.
The character cell value affects both the size and position of characters drawn from an outline font, regardless of the current character mode. Each character is scaled up or down to fit the cell size, as shown in the following figure.
The character cell value is ignored if the current font is an image font and the current character mode is CM_MODE1, as shown in the following figure.
Note: It is essential to code the character cell correctly, even if you anticipate using image fonts. In case of a font match failure, an outline font can be substituted for an image font.
Effect of the Character Cell on an Image Font in CM_MODE1
Although the character cell has been both increased and decreased, the character string is unaltered.
The character cell value controls the positioning of image-font characters when the current character mode is CM_MODE2; but it cannot cause the characters to be scaled to fit the cell. This effect is shown in the following figure.
Effect of the Character Cell on an Image Font in CM_MODE2
If you increase the character cell size for an image font in CM_MODE2, the characters are more widely spaced, but their size is not changed. If you decrease character cell size, the space between the characters is reduced, and because the characters themselves cannot be scaled, they can overlap.
Default Character Cell
The default character-cell size is a device-dependent value. You do not need to know this value unless you want to switch back to the initial default value after having specified another value. It is recommended that you save initial default values using GpiSavePS.
The default character cell, like other default attributes, can be set using GpiSetDefAttrs(CBB_BOX). If necessary, you can query the current default value using GpiQueryDefAttrs.
Coding a Character Cell
The dimensions that an application passes to GpiSetCharBox and that GpiQueryCharBox returns are fixed-point values. A fixed value is a 32-bit value whose high-order 16 bits contain the integral part of the floating-point number and whose low-order 16 bits contain the fractional part. The fractional part is the numerator of a fraction whose denominator is fixed at 65536. The MAKEFIXED macro provides a method for producing fixed values. If, for example, one of the character cell dimensions were 7.635 world units, an application could obtain the corresponding fixed value by using the MAKEFIXED macro, passing 7 as the first argument and 41615 as the second.
The purpose of the character cell is to assist other font metrics to define text lines. For example, if you planned to have an average text line of 60 characters, dividing your output width by 60 would provide your character cell width.
DevQueryCaps can be used to provide information about suitable character cell values. DevQueryCaps returns two sets of values that can influence the character cell:
- Default cell values
* CAPS_GRAPHICS_CHAR_WIDTH * CAPS_GRAPHICS_CHAR_HEIGHT
- Device resolution
* CAPS_HORIZONTAL_FONT_RES * CAPS_VERTICAL_FONT_RES
The default cell values return the size of the default character cell in pels. Convert the device resolution into character cell values by multiplying it by the desired point size, then dividing by 72 (72.2818).
Character Angle
The character angle is defined by the x-axis and a vector drawn through the origin to a specified point in a Cartesian coordinate system. Neither (0,0) nor the specified point need have any relation to the current position. The operating system then aligns the baseline with this vector.
An application can retrieve the point that defines the character angle vector using GpiQueryCharAngle. An application can set the character angle using GpiSetCharAngle. This function accepts as input the x- and y-coordinates of a point that defines the new vector. When you specify an angle, it becomes the current setting. To reset the character angle vector to its default value (parallel to the x-axis), call GpiSetCharAngle with both x and y equal to 0.
The effects of the current character angle vary depending on the current character mode and the current font type. When the current font is an outline font, the current character angle determines the angle of both the whole string and the individual characters in the string, regardless of the current character mode. The baseline of each character cell is drawn parallel to the new baseline, as shown in the following figure.
Effect of the Character Angle on an Outline Font
The character string is drawn parallel to the vector drawn from the origin to (10,7). The baseline of each of the character cells also is drawn parallel to this vector.
The character angle value is ignored if the current font is an image font and the current character mode is CM_MODE1, as shown in the following figure.
Effect of the Character Angle on an Image Font in CM_MODE1
The angle of the character string is unaltered by GpiSetCharAngle.
When the current font is an image font and the current character mode is CM_MODE2, the current character angle determines the angle of the whole string but does not affect the individual characters in the string. The character reference point, which is the point at which the character baseline intersects the left edge of the character cell, is placed on a line parallel to the new baseline. The baseline of each character cell remains parallel to the x-axis, as shown in the following figure.
The character string is drawn parallel to the vector from (0,0) to (10,7). Each of the characters in the string is drawn with the vertical sides of its character cell parallel to the y-axis, and with the horizontal sides of its character box parallel to the x-axis.
Character Shear
Character shear is the angle defined by the x-axis and a vector drawn through the origin to a specified point in a Cartesian coordinate system. Neither (0,0) nor the specified point need have any relation to the current position. The operating system then aligns the vertical sides of the character cell. If the font is an outline font, the operating system also aligns the vertical strokes of the characters with the vector, regardless of the current character mode, as shown in the following figure.
An application can retrieve the point that defines the character shear vector using GpiQueryCharShear. An application can set the character shear using GpiSetCharShear, which accepts as input the x- and y-coordinates of a point that defines the new vector in a POINTL structure.
The shear of a character is the angle formed by the vertical lines of the character cell, and it can affect both the positioning and shape of characters in the character string. By default, the vertical lines of a character cell are parallel to the y-axis of the presentation page. As input to GpiSetCharShear supply the coordinates of the end point of a vector drawn from the origin (0,0). The effects of the current character shear value vary, depending on the current character mode and font type.
Effect of Character Shear on an Outline Font
The character cell is drawn with its vertical lines parallel to the vector from the origin to (5,6). The character is sheared to the same degree.
The character-shear value is ignored if the current font is an image font and the current character mode is CM_MODE1, as shown in the following figure.
Effect of Character Shear on an Image Font in CM_MODE1
The character string is unaffected by the character-shear value.
The character-shear value affects the positioning of the characters from an image font in CM_MODE2 only if character direction is CHDIRN_TOPBOTTOM or CHDIRN_BOTTOMTOP. That is, characters drawn vertically do not appear in a vertical line for nonzero shear angle from the vertical. The characters themselves cannot be sheared, as shown in the following figure.
Effect of Character Shear on an Image Font in CM_MODE2
The character cell is sheared, and it controls the positioning of the characters; the characters themselves are unchanged.
If the x- and y-coordinate values you specify in GpiSetCharShear are both positive and negative, the characters slant from lower left to upper right. If you supply one negative and one positive value, the characters slant from upper left to lower right, as illustrated in the following figure.
Effect of X- and Y-Values on Character Shear
Character shear, like other attributes, has a default value that can be changed using GpiSetDefAttrs (CBB_SHEAR). To reset the character shear to its default effect of drawing the vertical lines of the character cell parallel to the y-axis, supply a coordinate value of (0,1) on GpiSetCharShear.
Character Direction
Character direction is the direction in which the characters in a string are drawn in relation to the baseline. By default, the characters are drawn from left to right. An application can change the direction using GpiSetCharDirection. GpiSetCharDirection accepts as input one of the four values illustrated in the following figure. The value CHDIRN_DEFAULT is identical to CHDIRN_LEFTRIGHT.
┌───┬───┬───┐ ┌───┬───┬───┐ │ A │ B │ C │ │ C │ B │ A │ └───┴───┴───┘ └───┴───┴───┘ start end end start CHDIRN_LEFTRIGHT CHDIRN_RIGHTLEFT start end ┌───┐ ┌───┐ │ A │ │ C │ ├───┤ ├───┤ │ B │ │ B │ ├───┤ ├───┤ │ C │ │ A │ └───┘ └───┘ end start CHDIRN_TOPBOTTOM CHDIRN_BOTTOMTOP
An application can determine the current character direction using GpiQueryCharDirection.
Character Text Alignment
Character text alignment describes how character strings are drawn relative to the output boundary, either at the current position or the starting position of the string when using a `GpiCharString...At` function. Alignment is configured using GpiSetTextAlignment, which takes a long value specifying horizontal and vertical alignment.
The acceptable values for GpiSetTextAlignment depend on the current coordinate system’s direction, as follows:
- Left: The lowest x-coordinate value
- Right: The highest x-coordinate value
- Top: The highest y-coordinate value
- Bottom: The lowest y-coordinate value
Internally, the Presentation Manager (PM) determines a reference point within a character string to position it over the specified starting point. For strings drawn with GpiCharString or GpiCharStringPos, the starting point is the current position. For GpiCharStringAt or GpiCharStringPosAt, the starting point is provided as input to the function.
Horizontal Alignment of a Character String
When a horizontal character string does not fill the width of the output area, it can be positioned in one of the three ways shown in the following figure. All of these options can be set directly with the lHorizontal option of GpiSetTextAlignment.
Horizontal Positioning of Text Strings
Text justification requires applications to perform queries and coordinate calculations. The following flags specify horizontal alignment types:
Horizontal Alignment Values
Identifier | Alignment |
---|---|
TA_LEFT | On the left edge of the leftmost character in the string |
TA_RIGHT | On the right edge of the rightmost character in the string |
TA_CENTER | On the arithmetic mean of the leftmost and rightmost characters in the string |
Two sets of default values for the `lHorizontal` option are provided for compatibility, mapping to the above alignment values. Functions like GpiQueryGraphicsField, GpiQueryPageViewport, and GpiQueryViewingLimits help determine the output area’s width for proper coordinate specification.
Vertical Alignment of a Character String
When displaying a character string vertically, it can be positioned in one of four ways, as shown in the referenced figure.
These options are set using the `lVertical` parameter of GpiSetTextAlignment.
Vertical Positioning of Text Strings
The following flags specify vertical alignment types:
Vertical Alignment Values
Identifier | Alignment |
---|---|
TA_TOP | On the top edge of the topmost character in the string |
TA_HALF | On the arithmetic mean of the topmost and bottommost characters in the string |
TA_BASE | On the baseline of the bottommost character in the string |
TA_BOTTOM | On the bottom edge of the bottommost character in the string |
Two sets of default values for the `lVertical` option are provided for compatibility, mapping to the above vertical alignment values.
Character Extra and Break Extra
Certain output devices allow specifying extra space between character cells using the character extra attribute. The space between words can also be expanded by adjusting the break character (typically the space character) using the break extra attribute. These adjustments add to spacing effects from:
- Font kerning
- Font proportional spacing
- Width vectors
The break values create different effects, as follows:
Break Values and Their Effects
Value | Effect |
---|---|
Positive | Forces characters apart. |
0 | Resumes default spacing created by other parameters. |
Negative | Forces characters together, even overlapped characters. |
These effects are illustrated in the referenced figure.
The Cumulative Effect of Break Values
Both character extra and break extra attributes default to 0 and can be modified using GpiSetDefAttrs (CBB_EXTRA and CBB_BREAK_EXTRA), GpiSetCharExtra, or GpiSetCharBreakExtra. Values can be queried using GpiQueryCharExtra and GpiQueryCharBreakExtra.
Character Color and Mix
The color attribute defines the color used to draw a primitive or object, while the mix attribute determines how this color combines with the drawing surface or other objects. For character strings, the color defines the output color for draw-character-string functions. The default character-string color in a new presentation space is black.
Character strings have both foreground and background colors. For image characters, colors are set by pels. For outline characters, the foreground consists of arcs and lines, with the background color appearing between them unless the character is solid or filled. The character cell surrounding the character uses the background color.
The foreground mix attribute controls the combination of character-string color and drawing-surface color, while the background mix attribute controls the character-cell color combination, as shown in the referenced figure.
Character String Primitives
In a new presentation space, the character string mix attribute defaults to FM_OVERPAINT, meaning the character-string color is not modified by the drawing surface. Changing the mix attribute blends the character-string color with existing surface colors. The background color defaults to CLR_BACKGROUND (typically the drawing surface color), with a background mix of BM_LEAVEALONE, meaning the background is not drawn unless attributes are changed.
Use GpiSetAttrs to specify new color or mix attributes, providing:
- Primitive type (e.g., PRIM_CHAR)
- Attributes to change
- Attributes to reset to defaults
- Values for changed attributes
GpiSetAttrs can target specific data structures (e.g., CHARBUNDLE) and protects against invalid colors. Query current attributes with GpiQueryAttrs, which returns an array of values for specified attributes. Reset defaults with GpiSetDefAttrs, specifying the primitive type, attributes, and new default values. Changing defaults during drawing operations is not recommended.
Character color and mix attributes can also be set using:
Query individual attributes with:
These may return values inconsistent with current character attributes if set individually.
Using Character String Primitives
Character string primitive functions support:
- Drawing character strings with the selected font
- Modifying strings via:
* Scaling * Shearing * Rotating * Transforming * Changing the baseline angle
- Aligning text
Drawing Text
The following example demonstrates selecting a Helvetica outline font, setting the character box size, changing the foreground color to red, setting the character angle, moving the cursor to a specified location, and using GpiCharString to draw a string with the specified attributes.
#define INCL_GPIPRIMITIVES #define INCL_GPILCIDS #include <os2.h> void fncFONT09(void) { POINTL ptl = { 100, 50 }; GRADIENTL grad = { 4, 1 }; SIZEF sizfx; FATTRS fat; CHARBUNDLE cbnd; FONTMETRICS afm[80]; HPS hps; HDC hdc; LONG cHelvFonts, i; LONG cFonts = 0; LONG lcid = 1; LONG devRes[2]; /* Horizontal, vertical font resolutions */ cHelvFonts = GpiQueryFonts(hps, QF_PUBLIC, "Helv", &cFonts, sizeof(FONTMETRICS), NULL); GpiQueryFonts(hps, QF_PUBLIC, "Helv", &cHelvFonts, sizeof(FONTMETRICS), afm); /* Find an outline Helvetica font. */ for (i = 0; (!(afm[i].fsDefn & FM_DEFN_OUTLINE)) && i < cHelvFonts; i++); fat.usRecordLength = sizeof(FATTRS); fat.fsSelection = 0; fat.lMatch = afm[i].lMatch; StringCopy(fat.szFacename, afm[i].szFacename); fat.idRegistry = 0; fat.usCodePage = 0; fat.lMaxBaselineExt = 0; fat.lAveCharWidth = 0; fat.fsType = 0; fat.fsFontUse = FATTR_FONTUSE_OUTLINE; GpiCreateLogFont(hps, (PSTR8) NULL, lcid, &fat); GpiSetCharSet(hps, lcid); DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 2L, devRes); sizfx.cx = MAKEFIXED((afm[i].sNominalPointSize * devRes[0]) / 720, 0); sizfx.cy = MAKEFIXED((afm[i].sNominalPointSize * devRes[1]) / 720, 0); GpiSetCharBox(hps, &sizfx); cbnd.lColor = CLR_RED; GpiSetAttrs(hps, PRIM_CHAR, CBB_COLOR, NULLHANDLE, &cbnd); GpiSetCharAngle(hps, &grad); GpiMove(hps, &ptl); GpiCharString(hps, 11, "Vector Text"); } /* fncFONT09 */
Parameters are further explained in Fonts.
Formatting Text
Graphics text must be positioned correctly in the output area, which may be:
- The entire client area of a PM window
- Part of a PM window
- The addressable area of a printer
Unlike other graphics objects, text follows readability and usability rules, including:
- Larger font sizes require wider line spacing for readability.
- Longer text lines need greater inter-line spacing to avoid merging.
- Very small text should be split into multiple columns.
Some considerations are handled by font designers, but PM allows control over horizontal and vertical text positioning.
Positioning Text in World Coordinates
Text alignment depends on the coordinate system, with the following definitions:
World Coordinate Values
Value | Corresponds to the direction of... |
---|---|
Left | The lowest x-coordinate value |
Right | The highest x-coordinate value |
Top | The highest y-coordinate value |
Bottom | The lowest y-coordinate value |
To position a character string horizontally, you need the output area’s width and the string’s length. PM provides functions to determine the output width:
Function Name | Description |
---|---|
GpiQueryGraphicsField | Returns the bottom-left and top-right corners of the graphics field in presentation page units. |
GpiQueryViewingLimits | Returns the viewing limit. |
GpiQueryPageViewport | Returns the page viewport in device units. |
GpiConvert converts coordinates to world coordinates. To calculate the output area’s width, subtract the `left` from the `right`. For example, if `left` is 30 and `right` is 600, the width is 570 world coordinates.
PM provides three functions to determine the character string’s length:
GpiQueryTextBox returns the parallelogram’s relative coordinates around the string. Subtracting TXTBOX_BOTTOMRIGHT’s x-coordinate from TXTBOX_BOTTOMLEFT’s gives the string’s length.
GpiQueryCharStringPos returns an array of world coordinate positions for each character. The last value is the new current position if drawn with GpiCharStringPos. Subtracting this from the current position (via GpiQueryCurrentPosition) determines the string’s length.
GpiQueryCharStringPosAt also returns an array of character positions, with the last value as the new current position if drawn with GpiCharStringPosAt. Using a starting position like (0,0) allows length calculation without subtraction.
Neither GpiQueryCharStringPos nor GpiQueryCharStringPosAt updates the current position.
When a string doesn’t fill the output area’s width, it can be positioned in four ways, as shown in the referenced figure (img33.bmp).
Horizontal Positioning of Text Strings
To left-align text, set the x-coordinate of the current position to the output area’s `left` before drawing. Use GpiSetCurrentPosition for GpiCharString or GpiCharStringPos. GpiCharStringAt and GpiCharStringPosAt accept a starting position as input.
To right-align, subtract the string’s length from the output area’s width, then add the difference to the current position’s x-coordinate. For example, if the output area is 570 units wide and the string is 436 units, add 134 to the x-coordinate.
To center, subtract the string’s length from the output area’s width, divide the difference by 2, and add it to the x-coordinate. For a difference of 134, add 67.
To justify text to fill the output area, distribute surplus space throughout the string, either at break characters or equally among all characters. Use:
- GpiCharStringPos: Draws at the current position, allowing positioning of all characters after the first.
- GpiCharStringPosAt: Allows positioning of all characters, including the first.
Both functions allow specifying per-character increments, measured from one character’s reference point to the next. These values are temporary and do not affect current attributes.
For text blocks wider than the output area or exceeding 256 characters, split the string into smaller groups. Estimate characters per line by dividing the output width by the character cell width. Scan for spaces, comparing the string length to the output area’s width. When the string exceeds the width, backtrack to the previous space and display that portion. Repeat to format the entire block.
For vertical placement in text blocks, ensure consistent line separation. Image fonts have uniform character heights, but outline fonts or mixed fonts do not. Avoid complex font metrics; instead, multiply the desired point size or em-height by 1.2 for line spacing.