A Window On GEM Special Effects
by Corey Cole
How to manipulate text in GEM. A thorough investigation of sophisticated text handling. Technical tips-and pitfalls to avoid. Including a full-featured C program that lets you test all possible GEM text capabilities. Related files may be found within the GEMTEXT folder on your START disk.
Before the advent of Apple's Macintosh, microcomputer programmers had an easier time using text in their programs. Computer screens generally could only display a single font. As computers became more sophisticated, users began to expect more from them: the Macintosh delivered reasonably priced proportional spacing and multiple type fonts.
Thanks to GEM, the Atari 520ST has many of the advanced text display features previously found only in expensive, dedicated publishing systems. Let's explore the use of some of these.
USING GEM TEXT
GEM helps programmers by doing much of the hard work needed for sophisticated text display. You can ignore most of GEM's overwhelming set of operations for displaying and dealing with graphics text. If you are just trying to display plain text in a window, you only have to worry about where to put it. Beyond that, you can use as many of the more advanced features as you need.
Think of GEM's VDI calls as a toolkit; the basic set of tools for text consists of only seven VDI calls. The calls v_gtext and v_justified actually display the text. You can set text size in pixels with vst_height, or in points (a typographer's unit measuring 1/72 of an inch) with vst_point. The vst_effects call specifies characteristics such as boldface, italics, underlining, outlining, shadowing, and "light" (grey shading); vst_alignment positions and aligns the text. You can check the width of a string or of a single character with vqt_extent and vqt_width.
Depending on your application, you may need vst_rotation and vst_color (which set baseline rotation and foreground/background colors), and vqt_attributes (which returns the characteristics of the current typestyle). Once the final GDOS becomes available (see "GDOS & Metafiles" by Tim Oren, this issue), you may have use for vst_load _fonts, vst_unload_fonts, and vst_font-which allow you to deal with proportionally spaced and alternative typestyles. Finally, you may need vswr_mode and v_bar to deal with "reversed" (white on black) text or italic characters, and vs_clip to keep your text in the window.
Unfortunately, there is a darker side to the ST's GEM. Several of the above features were omitted from the Atari version of GEM; others have bugs. A few features crucial to some applications never found their way into GEM at all. This makes developing text applications on the ST a real challenge-and tends to turn your life with GEM into a love! hate relationship.
At this point, let me recommend Tim Oren's article on GEM text-column #10-which may be found in the Professional GEM section in ANTIC OnLine on Compuserve. (Many Atari user groups have reprints of this article as well.) As Tim mentions, it is a good idea to start your text display on a byte boundary in memory (X-coordinate that is a multiple of eight). You should use the "Replace" writing mode and, whenever possible, try to do your own clipping (rather than relying on the vs_clip function). Each of these techniques improves text display speed.
PUTTING IT TOGETHER
TEXTDEMO.PRG, on the START disk, demonstrates the use of most of GEM's text display features. It opens a window and displays lines of text according to your specifications. With TEXTDEMO, you can easily display several lines of text with different attributes, since TEXTDEMO will not erase the window until you give it an explicit "Erase Window" command.
To use TEXTDEMO, pull down the "Display" menu, and select "Char Attributes." The Character Attributes dialogue is shown in figure 1. The first field is the "Font i.d." (as in the vst_font VDI call). Changing the Font i.d. has no effect currently; this option is included for use after GDOS is released (see the "Bug Box" sidebar).
Character Height may be specified in either pixels or points. Note that the number of pixels applies only to the part of the character above its baseline.
The Special Effects value is the sum (in decimal) of the special effects bits you wish to be set. These bit values are: 1 = bold, 2 = light, 4 = italic, 8 = underline, 16 = outline, and 32 = shadowed. Try various combinations. The effects of the Foreground and Background Color values depend on your current resolution and color map, but 0 is generally white, while 1 is generally black. You can get some very interesting effects on a color monitor!
After clicking on the OK button, select "Display Line" from the Display menu. (For convenience, pressing any key on the keyboard is equivalent to selecting "Display Line".)
The Line Attributes dialogue (figure 2) allows you to specify a line of text to display (up to 30 characters), and its positioning and alignment. Position is in pixels relative to the display window's top left corner, and is the line's left baseline position.
A single letter specifies Justification. Character justification adds space between characters, while word justification adds space only between words.
Horizontal Alignment is also specified with a single letter, which determines the horizontal "anchor point" for text display (left edge, centered, or right edge). There is no visible difference between the various horizontal alignments when justification is in effect.
Vertical Alignment determines the position of each character relative to the specified Y-coordinate. That coordinate will fall on the top line, ascent line, half line, base line, descent line, or bottom line of the character cell. Since "Bottom" and "Base" begin with the same letter, we use "F" (Floor) for bottom alignment. The results of changing vertical alignment value will probably surprise you; specifying "Floor" moves text up with respect to the drawn "Baseline," while specifying "Top" moves the text down.
Finally, the Baseline Rotation value specifies a vector along which to display the text's baseline. Even though this is specified in tenths of a degree (0 is normal, 900 is straight up, etc.), there are only four meaningful ranges on the ST screen-normal, backward, up, and down.
Accepting the line attribute dialogue (pressing [Return] or clicking on "OK") displays the text line. If you are just changing character attributes, and want an immediate display, an easy trick is to press any keyboard key, then press [Return]; this brings up the line attribute dialogue, then accepts it without changing any line attribute values.
TEXTDEMO draws a rectangle around your nominal text line in color 2, and draws a dotted line along the baseline in color 3 (both are black on the monochrome monitor). If you are using baseline alignment, the text will be vertically centered in the line rectangle.
If your text window becomes too cluttered, you can use "Erase Window" at any time. "Quit" in the Exit menu returns you to the GEM desktop (or your shell). There are several ways to crash the system by specifying unusual combinations of the dialogue parameters. This is intentional-it allows you to find out in advance where GEM is most likely to choke on your own text applications.
HOW IT WORKS
You should be able to learn quite a bit about how the various GEM text functions interact by first trying several minor variations of character and line attributes and then displaying the resulting strings above or next to each other. Start by experimenting with the program in this fashion, before spending significant time with the code and "how it's done." The source code for TEXTDEMO. PRG is in several files- TEXTDEMO.C and TEXTDEMO.H contain the main code, while DEBUG. C contains procedures for formatting numeric strings (used in TEXTDEMO's dialogue-handling routines). In addition, TXDEMO.RSC, TXDEMO.DEF, and TXDEMO.H contain TEXTDEMO's resources (the menu and dialogue boxes). DEBUG.C is generic-you can use it to debug your own GEM applications.
The general flow of control in TEXTDEMO is similar to that of Digital Research's "doodle/demo" application, from which several pieces were borrowed. TEXTDEMO begins (in gemInit) by initializing the desktop and opening a single window which completely fills the desktop's work area. The initial text line is set to fill most of the window's width, and to be vertically centered in it. The initialization routine also allocates and clears a buffer large enough to cover the entire screen. This is the "save buffer," and lets TEXTDEMO easily redraw the text window after it has been covered (as by the attribute dialogues).
After initialization, control passes to mainLoop, which consists entirely of an evnt_multi in a loop. The evnt_multi looks only for messages and keyboard events (treating any of the latter as equivalent to selecting the "Display Line" menu item). The only messages considered are menu item selected" and "redraw" (the latter happens on beginning the program, and whenever a window leaves the desktop, as after a dialogue is displayed). Redraw is accomplished by copying the save buffer back into the text window.
Selecting the "Char Attributes" menu item invokes charDial. This procedure initializes the fields of the Character Attribute dialogue, then calls GEM's form handler, and finally (if the dialogue was not cancelled) stores the user-entered values back into the global textLine structure. The initialization and saves are performed by initChDial and saveChDial. Four general-purpose procedure set and retrieve values from the dialogue fields: getName, getNum, setName, and setNum. You may find this approach useful for editing complex dialogues in other applications. The save routine also uses a simple "character decoder" (decode()) to convert an entered character into the corresponding numeric value-this is easy, since GEM's attributes are all set with consecutive low numbers.
lineDial, invoked when a key is pressed, or when the "Display Line" menu item is chosen, is only slightly more complicated. lineDial uses the same approach as charDial to initialize and read the dialogue. When the dialogue is OK'd, lineDial restores the window-this is unnecessary for the other dialogues, since dismissing them causes GEM to issue a Redraw message to the application. Here, however, we want to display another line, then save the modified work area, which means we need to clean out the window first.
As is typical in GEM (and in other graphics-oriented environments), something like 90 percent of our code is devoted to handling the user interface. We finally come to the application's heart in drawLine. This routine looks up the values stored in the global textLine structure, and attempts to display a line of text based on them.
As mentioned, it is faster for an application to do its own clipping when displaying text. This is only significant if the text will in fact be clipped, and drawing off the screen without clipping is likely to crash the system (or at least GEM), so we ignore that advice and clip to the text window
We then call textStyle, which calls GEM's attribute functions with the specified character and line attributes. This "environment" approach for defining display attributes may seem odd if you have used systems in which the attributes are specified in the display call. That approach is unusable in GEM, since there are so many different attributes. GEM's technique also lets you set the attributes once, then use them several times (as in displaying several lines of text with common attributes).
Pay close attention to the verbose comment about vst_height, in the textStyle procedure-the correct values for the default system font sizes are probably not what you expect them to be: size is specified in height above baseline, not total character cell height.
Displaying justified text under GEM is trivial-you simply call v_justified instead of v_gtext. It wasn't all that long ago that displaying or printing justified text was one of programmer's more cumbersome tasks. Of course, you still need to put reasonable amounts of text on each line, so that the spaces aren't too large or too small (line-breaking is a subject deserving its own article).
You will find the problems with GEM's justification feature (and with any display involving proportionally spaced characters) when you try to mix character styles in a line, or if your text is user-editable. Since you must specify X and Y coordinates for each text display operation, you need to determine where to start each "piece" of the text line (when mixing styles).
When using a monospace font and not justifying, this is easy: determine the character width in each style, and multiply by the number of characters displayed. To get the width of each sub-string, increment the X-coordinate by this amount each time.
The task is just a little harder with non-justified proportional type. GEM provides the vqt_extent call, which returns a box describing the exact size of a string in a given style. Use this to find the width of each sub-string, and increment as above (but see the Bug Box if your string is italic).
Justifying text makes things much tougher-where the substrings will go depends on how many spaces there are in each of them, as well as on the nominal string widths. Your best bet is to avoid the situation. If you can't, you have to pre-scan the string, counting spaces and characters-of-width, etc.
Much of GEM is based on the Small-Talk model for user interface. SmallTalk recommends a single procedure, "scanLine." With several functions- depending on a flag, it will display a string, measure the string's width (including the effects of justification on it), find the X-offset corresponding to a given index within the string, or return the index of the character closest to a specified X-offset.
Why put all that utility in a single routine? There are many ways to justify text or to display certain sequences- kerning, ligatures, and so on. (Editor's note: for a better treatment of these advanced topics, see resources listed at end of article.) The same algorithms must be used for any of the four operations mentioned, since inconsistent sizes or positions could otherwise result. Unfortunately, GEM does not provide such a scanning routine.
This means there is no straightforward way to accomplish mouse-oriented editing in justified or proportional text. You can try to second-guess GEM's justification algorithm (and hope that it will be consistent on other GEM systems to which you later port your application), and "scan" accordingly, or you will have to do your own justification. Once again, your best bet is to not allow direct editing of justified or proportional text-if you can survive without it.
Using italic characters under GEM also appears to be quite simple-initially Simply call vst_effects, specifying the "Skewed" special effect, then do either a vq_text or a v_justified call to display the text. If your entire string is italic, this will work fine, as long as you leave a little extra room on the string's right.
The bad news comes when you mix italic and non-italic characters. It seems that skewed characters in GEM really are skewed-GEM displays them approximately half a character position to the right of where they should go! This means that, if you are using Replace Mode (recommended for smooth display), the next non-skewed character you display will erase the right edge of the last skewed character. (If you have 1ST Word, you will be able to demonstrate this phenomenon. Type "GEM" in italics, followed immediately by a non-italic space.) In addition, unless you take special precautions (as 1ST Word does), you may end up with "mouse droppings" (extra displayed pixels) at the beginning of the italic string.
If this isn't enough, GEM also returns incorrect values if you do a vqt_extent (VDI #116) on an italic string. You have to get the width of a string of italic characters the hard way-call vqt_width (opcode 117) for each character, ignoring the left and right "alignment delta" values returned.
There is no such easy work-around for the position problem; how well you solve it depends on how much work you're willing to do. The simplest "solution" is not to mix italic and non-italic text at all. If you can get away with this, you probably don't even have to worry about the half-character positioning error-no one will notice.
GEM has given us an excellent set of tools for displaying clear and "interesting" text. Although these tools contain a number of bugs and "blind spots," with a little care they can be used to greatly enhance the appearance of ST screen text. Using GEM for leverage, you can write text-oriented programs with much more sophistication, and in significantly less time, than on non-GEM systems. Use GEM's text features-your application and its users will benefit!
Phototypography: A Guide to Typesetting and Design, by Allan Haley, Charles
Scribner's Sons, New York, NY
Publication Design. Second Edition, by Roy Paul Nelson, Win. Brown Company
Publishers, Dubuque, IA
- Smalltalk-80: The Language and its Implementation, by Adele Goldberg and David Robsen, Addison-Wesley Publishing Company, Menlo Park, CA
A GEMTEXT GLOSSARY
Alignment: The relative positioning of text, compared to the coordinates specified in a vq_text or v_justified VDI call. The most commonly used vertical alignments are "baseline" (recommended if you plan to mix fonts, since the baselines of all text on a given line must be the same) and "top". You are familiar with top alignment from non-graphics text; it simplifies the issue of determining clipping and erasure boundaries. Horizontal alignment determines whether the text will be displayed to the right of, centered on, or to the left of, your specified position. Both horizontal and vertical alignment are set using the vst_alignment call (VDI opcode #39).
Alpha Text: A GEM term for the text normally used by a computer system (what non-GEM applications would display, the system font).
Baseline: An imaginary line on which the capital letters in a line of text rest. When mixing type fonts on a line, the rule is to use the same baseline for all of the fonts.
BitBlt: Bit Block Transfer, a term borrowed from SmallTalk, refers to the copying of a rectangular block of pixels (screen bit locations) from one place to another, possibly performing a transformation on the way In GEM, characters are displayed by copying a bit image of the character from memory to the screen, a process made possible by the the speed of the 68000 chip.
Cell Width and Height: In GEM, the size of a rectangle of sufficient size to display a given character with an appropriate amount of white space on all sides. In a monospace font, all characters have identical cell width and height.
Font (or Typefont): A set of characters having the same general appearance, style, and size. The 8x8 screen font on the color ST monitor is an example; the italic version of this screen font is another "font."
GDOS: The "Graphics Device Operating System." GDOS is a portion of GEM which allows GEM to deal with certain device-dependent features, such as multiple "workstations" (screen and printer, for instance), and multiple type fonts. GDOS was not released with the initial RAM or ROM versions of TOS, but should be available shortly It is an overlay to the main part of GEM, and so can be provided after the fact (i.e. GDOS would not have been part of the ROM code in any case). Until GDOS is released, many functions of GEM are unavailable (see the "Bug Box" sidebar).
Graphics Text: A GEM term for text displayed within GEM by plotting individual characters as graphics images (see BitBIt).
Justification: Adjusting character and/or word spacing in a line to make the string fit a specified width. The term is also used ("Left-Justified," "Center-Justified," etc.) to refer to horizontal alignment (see Alignment).
Leading: Amount of space between lines (distance from the baseline of one line to the baseline of the next). A good rule of thumb is to use approximately 20 percent extra lead with proportional space type; 10 Point type looks best with 12 Points total line leading. TEXTDEMO. PRG refers to it as "Line Height" to avoid confusion.
Monospace Typefont: A typefont in which all characters have the same width. All of the standard ST screen fonts are monospaced. Monospaced characters are easily manipulated from a computer program, since no special width calculations need be made.
Pitch: The normal way of measuring monospace fonts. Pitch is the number of characters which fit in an inch, horizontally (Elite type is 12 Pitch, or 12 characters per inch, while Pica type is 10 characters per inch). Note that GEM never deals with pitch-monospace character sizes are instead set by character height above the baseline, in pixels!
Point Size: The most common way of specifying the size of proportional space fonts. A point is 0.0138 inch. All characters in a font are nominally guaranteed to fit in an area with a height equal to the point size. Thus, consecutive lines will not overlap if the leading is at least equal to the point size. GEM allows programs to specify Point Size in full points (half-points would be better), and will display with the font most closely matching the specified point size.
Proportionally Spaced Typefont: A typefont in which different characters may have different widths (for instance, the letter "i" will probably be significantly narrower than the "W"). Nearly all books, magazines, and newspapers use proportionally spaced type-it uses much less (30 percent-50 percent) space, reads quickly and is visually more pleasing. GEM provides support for proportional fonts, but these features ore incomplete on the ST at this time.
Raster vs. NDC Coordinates: GEM allows positions to be specified either in terms of absolute screen locations (Raster Coordinates) or relative locations in terms of an idealized screen (Normalized Device Coordinates, or NDC). Since typefonts are available only in certain pre-specified sizes, any program that needs to use text is well advised to stick with Raster Coordinates, which are significantly faster than Normalized Coordinates.
Style: A generic term for the attributes of a text character. These include the character's type family, and "special effects" such as bold, italics, underlining, etc. Modest use of special effects enhances text readability and appearance.
Typeface: Collection of all supported sizes of a given font, but staying with a single style.
Type Family: A collection of related typefaces. Popular type families include Helvetica and Times Roman. The entire collection of mono-spaced screen fonts for the various ST resolutions could also be said to comprise a "family" of type.
THE BUG BOX
Yes, GEM does have afew bugs. Here are several specifically related
to text handling. START welcomes comments, additions, and-especially-fixes.
1 Italic characters are offset from their ideal "cell" location, so the right halves of characters are clipped when italic characters abut non-italic characters.
2 The vq_extent VDI call (opcode 116) returns an incorrect value (much too large) for italic text.
3 GDOS is not included with TOS. There ore, only the monos paced system fonts are available. (VDI opcode #119, vst_load_fonts, will crash the system. So will attempting to open a workstation other than the screen, such as a printer.) Application packages using GDOS are beginning to appear on the market, and Atari is evaluating a version of GDOS for release.
4 There is no "scan" function corresponding to justified graphics text display, making v_justified (opcode #11-10) useless for text editing applications (see article).
5 The v_justified call produces strange (and apparently unpredictable) results when both the word-spacing and character-spacing flags are False (no justification desired). This case should be the same as using v_gtext, but is not. Use v_gtext for non-justified text.
6 The rightmost pixel of bold characters (when using any of the system fonts) is clipped. This is not, strictly speaking, a bug-it is a "feature" which ensures that the width of characters in the system font remains constant even if bold characters are used.
7 Text display slows down significantly under some conditions. In particular characters which do not fall on an even eight-pixel boundary take much longer to display than those which do, and text display becomes much slower if clipping is needed. Also, display of proportionally-spaced characters using version 1.2 of GEM on the IBM PC is incredibly slow; we can hope that the GDOS Atari releases will be faster (the "Blitter" chip can also be expected to improve all of the speed problems significantly).
8 GEM allows text to be rotated in tenths of a degree, but does not support fractional point sizes! (Rotations other than at 45 degree angles are rare, whereas certain half-point sizes, such as 5.5 Point type, are quite common.)