Professional GEM - Part IV - Resource structure
Professional GEM 24
P�PA�AR�RT�T -�- I�IV�V
R�Re�es�so�ou�ur�rc�ce�e S�St�tr�ru�uc�ct�tu�ur�re�e
Welcome to the fourth installment of ST PRO GEM. We are
about to delve into the mysteries of GEM resource structure, and
then use this knowledge to create some useful utilities for
handling dialogs. As with the past columns, there is once again
a download file. You will find it under the name GEMCL4.C in
the ATARI 16-bit Forum (GO PCS-58).
The first and largest part of the download contains a C
image of a sample resource file. To create this listing, I used
the GEM Resource Construction Set to create a dummy resource
with three dialogs including examples of all object types, then
enabled the C output option and saved the resource. If you
have access to a copy of RCS, I suggest that you create your
own listing in order to get a feel for the results. Then,
using either listing as a roadmap to the resource, you can
follow along as we enter...
A�A M�MA�AZ�ZE�E O�OF�F T�TW�WI�IS�ST�TY�Y L�LI�IT�TT�TL�LE�E P�PA�AS�SS�SA�AG�GE�ES�S.�.
While a GEM resource is loaded as a block of binary
information, it is actually composed of a number of different
data structures. These structures are linked together in a
rather tangled hierarchy. Our first job is to map this linkage
system.
The topmost structure in a resource file is the resource
header. This is an array of words containing the size and offset
within the resource of the other structures which follow. This
information is used by GEM during the resource load process,
and you should never need to access it. (The resource header
does not appear in the C output file; it is generated by the
RSCREATE utility if the C file is used to recreate the
resource.)
The next structure of interest is the tree index. This is
an array of long pointers, each of which addresses the beginning
of an object tree. Again, you wouldn't normally access this
structure directly. The GEM rsrcgaddr call uses it when
finding trees' addresses. This structure is called "rstrindex"
in the C output.
If you look at the contents of rstrindex you will notice
that the values are integers, instead of the pointers I
described. What has happened is that RCS has converted the
pointers to indices into the object array. (If you actually used
the C file to recreate the resource file, then the pointers
Professional GEM Part IV 25
would be regenerated by RSCREATE.)
Now you can follow the link from rstrindex to the objects
stored in rsobject. Take (for instance) the second entry in
rstrindex and count down that many lines in rsobject. The
following line (object) should start with a -1. This indicates
that it is the root object of a tree. The following objects
down to the next root belong to that tree. We'll pass over the
details of inter-object linkage for now, leaving it for a later
column.
There are a number of different fields in an object, but
right now we'll concentrate on two of them: OBTYPE and OBSPEC.
The OBTYPE is the field which contains mnemonics like GSTRING
and GBOX indicating the type of the object. The OBSPEC is the
only field in each object which is a LONG - you can tell it by
the L after the number.
What's in OBSPEC depends on the object type, so we need to
talk about what kinds of objects are available, what you might
use them for, and finally how they use the OBSPEC field.
The box type objects are GBOX, GIBOX, and GBOXCHAR. A GBOX
is an opaque rectangle, with an optional border. It's used to
create a solid patch of color or pattern on which to place other
objects. For instance, the background of a dialog is a GBOX.
A GIBOX is a hollow box which has only a border. (If the
border has no thickness, then the box is "invisible", hence the
name.) The favorite use for IBOXes is to hold radio buttons.
There is also one neat trick you can play with an IBOX. If you
have more than one object (say an image and a string) which you
would like to have selected all at once, you can insert them in
a dialog, then cover them with an IBOX. Since the box is
transparent, they will show through. If you now make the box
selectable, clicking on it will highlight the whole area at
once!
The GBOXCHAR is just like a GBOX, except that a single
character is drawn in its center. They are mostly used as
"control points": the FULLER, CLOSER, SIZER, and arrows in GEM
windows are BOXCHARs, as are the components of the color
selection gadgets in the RCS.
The OBSPEC for box type objects is a packed bit array. Its
various fields contain the background color and pattern, the
border thickness and color, and the optional character and its
color.
The string type objects are GSTRING, GBUTTON, and GTITLE.
GSTRINGs (in addition to being a bad pun) are for setting up
static explanatory text within dialogs. The characters are
Professional GEM Part IV 26
always written in the "system font": full size, black, with no
special effects.
We have already discussed many of the uses of GBUTTONs.
They add a border around the text. The thickness of a GBUTTON's
border is determined by what flags are set for the object. All
buttons start out with a border thickness of one pixel. One
pixel is added if the EXIT attribute is set, and one more is
added if the DEFAULT attribute is set.
The GTITLE type is a specially formatted text string used
only in the title bar of menus. This type is needed to make
sure that the menus redraw correctly. The Resource Construction
Set automatically handles inserting GTITLEs, so you will seldom
use them directly.
In a resource, the OBSPEC for all string objects is a long
pointer to a null terminated ASCII string. The string data in
the C file is shown in the BYTE array rsstrings. Again you will
notice that the OBSPECs in the C file have been converted to
indices into rsstring. To find the string which matches the
object, take the value of OBSPEC and count down that many lines
in rsstrings. The next line is the correct string.
The formatted text object types are GTEXT, GBOXTEXT,
GFTEXT, and GFBOXTEXT. GTEXTs are a lot like strings, except
that you can specify a color, different sizes, and a positioning
rule for the text. Since they require more memory than
GSTRINGs, GTEXTs should be used sparingly to draw attention to
important information within a dialog. GTEXTs are also useful
for automatic centering of dialog text which is changed at
run-time. I will describe this technique in detail later on.
The GBOXTEXT type adds a solid background and border to the
GTEXT type. These objects are occasionally used in place of
GBUTTONs when their color will draw attention to an important
object.
The GFTEXT object is an editable text field. You are able
to specify a constant "template" of characters, a validation
field for those characters which are to be typed in, and an
initial value for the input characters. You may also select
color, size, and positioning rule for GFTEXTs. We'll discuss
text editing at length below.
The GFBOXTEXT object, as you might suspect, is the same as
GFTEXT with the addition of background and border. This type is
seldom used: the extra appearance details distract attention
from the text being edited.
The OBSPEC for a formatted text object is a pointer to yet
another type of structure: a TEDINFO. In the C file, you will
Professional GEM Part IV 27
find these in rstedinfo. Take the OBSPEC value from each text
type object and count down that many entries in rstedinfo,
finding the matching TEDINFO on the next line. Each contains
pointers to ASCII strings for the template, validation, and
initialization. You can find these strings in rsstrings, just
as above.
There are also fields for the optional background and
border details, and for the length of the template and text. As
we will see when discussing editing, the most important TEDINFO
fields are the TEPTEXT pointer to initialized text and the
TETXTLEN field which gives its length.
The GIMAGE object type is the only one of its kind. A
GIMAGE is a monochrome bit image. For examples, see the images
within the various GEM alert boxes. Note that monochrome does
not necessarily mean black. The image may be any color, but all
parts of it are the SAME color. GIMAGEs are used as visual cues
in dialogs. They are seldom used as selectable items because
their entire rectangle is inverted when they are clicked. This
effect is seldom visually pleasing, particularly if the image is
colored.
GIMAGE objects have an OBSPEC which is a pointer to a
further structure type: the BITBLK. By now, you should guess
that you will find it in the C file in the array rsbitblk. The
BITBLK contains fields describing the height and width of the
image in pixels, its color,nd it also contains a long pointer to
the actual bits which make up the image. In the C file, the
images are encoded as hexadecimal words and stored in arrays
named IMAG0, IMAG1, and so on.
The last type of object is the GICON. Like the GIMAGE, the
GICON is a bit image, but it adds a mask array which selects
what portions of the image will be drawn, as well as an
explanatory text field. A GICON may also specify different
colors for its "foreground" pixels (the ones that are normally
black), and its "background" pixels (which are normally white).
The pictures which you see in Desktop windows are GICONs,
and so are the disks and trashcan on the desktop surface. With
the latter you will notice the effects of the mask. The desktop
shows through right up to the edge of the GICON, and only the
icon itself (not a rectangle) is inverted when a disk is
selected.
The OBSPEC of an icon points to another structure called an
ICONBLK. It is shown in the C file as rsiconblk. The ICONBLK
contains long pointers to its foreground bit array, to the mask
bit array, and to the ASCII string of explanatory text. It also
has the foreground and background colors as well as the location
of the text area from the upper left of the icon. The most
Professional GEM Part IV 28
common use of GICONs and ICONBLKs is not in dialogs, instead
they are used frequently in trees which are build at run-time,
such as Desktop windows. In a future article, we will return to
a discussion of building such "on-the-fly" trees with GICONs.
Now, let's recap the hierarchy of resource structures: The
highest level structures are the resource header, and then the
tree index. The tree index points to the beginning of each
object tree. The objects making up the tree are of several
types, and depending on that type, they may contain pointers to
ASCII strings, or to TEDINFO, ICONBLK, or BITBLK structures.
TEDINFOs contain further pointers to strings; BITBLKs have
pointers to bit images; and ICONBLKs have both.
P�PU�UT�TT�TI�IN�NG�G I�IT�T T�TO�O W�WO�OR�RK�K
The most common situations requiring you to understand
resource structures involve the use of text and editable text
objects in dialogs. We'll look at two such techniques.
Often an application requires two or more dialogs which are
very similar except for one or two title lines. In this
circumstance, you can save a good deal of resource space by
building only one dialog, and changing the title at run time.
It is easy to go wrong with this practice, however, because
the obvious tactic of using a GSTRING and writing over its text
at run time can go wrong. The first problem is that you must
know in advance the longest title to be used, and put a string
that long into the resource. If you don't you will damage other
objects in the resource as you copy in characters. The other
problem is that a GSTRING is always drawn at the same place in a
dialog. If the length of the title changes from time to time,
the dialog will have an unbalanced and sloppy appearance.
A better way to do this is to exploit the GTEXT object
type, and the TEDINFO structure. The settext() routine in the
download shows how. The parameters provided are the tree
address, the object number, and the 32-bit address of the string
to be substituted. For this to work, the object referenced
should be defined as a GTEXT type object. Additionally, the
Centered text type should be chosen, and the object should have
been "stretched" so that it fills the dialog box from side to
side.
In the code, the first action is to get the OBSPEC from the
object which was referenced. Since we know that the object is a
GTEXT, the OBSPEC must point to a TEDINFO. We need to change
two fields in the TEDINFO. The TEPTEXT field is the pointer to
the actual string to be displayed; we replace it with the
address of our new string. The TETXTLEN field is loaded with the
Professional GEM Part IV 29
new string's length. Since the Centered attribute was specified
for the object, changing the TETXTLEN will cause the string to
be correctly positioned in the middle of the dialog!
Editing text also requires working with the TEDINFO
structure. One way of doing this is shown in the download. The
object to be used (EDITOBJ) is assumed to be a GFTEXT or
GFBOXTEXT. Since we will replace the initialized text at run
time, that field may be left empty when building the object in
the RCS.
The basic trick of this code is to point the TEDINFO's
TEPTEXT at a string which is defined in your code's local
stack. The advantages of this technique are that you save
resource space, save static data by putting the string in
reusable stack memory, and automatically create a scratch string
which may be discarded if the dialog is cancelled.
The text string shown is arbitrarily 41 characters long.
You should give yours a length equal to the number of blanks in
the object's template field plus one. Note that the code is
shown as a segment, rather than a subroutine. This is required
because the text string must be allocated within the context of
dialog handling routine itself, rather than a routine which it
calls!
After the tree address is found, the code proceeds to find
the TEDINFO and modify its TEPTEXT as described above. However,
the length which is inserted into TETXTLEN must be the maximum
string length, including the null!
The final line of code inserts a null into the first
character of the uninitialized string. This will produce an
empty editing field when the dialog is displayed. If there is
an existing value for the object, you should instead use
strcpy() to move it into text[]. Once the dialog is complete,
you should check its final status as described in the last
article. If an "OK" button was clicked, you will then use
strcpy() to move the value in text[] back to its static
location.
Although I prefer this method of handling editable text,
another method deserves mention also. This procedure allocates
a full length text string of blanks when creating the editable
object in the RCS. At run-time, the TEPTEXT link is followed to
find this string's location in the resource, and any
pre-existing value is copied in. After the dialog is run, the
resulting value is copied back out if the dialog completed
successfully.
Note that in both editing techniques a copy of the current
string value is kept within the application's data area.
Professional GEM Part IV 30
Threading the resource whenever you need to check a string's
value is extremely wasteful.
One final note on editable text objects: GEM's editor uses
the commercial at sign '@' as a "meta-character". If it is the
first byte of the initialized text, then the field is displayed
blank no matter what follows. This can be useful, but is
sometimes confusing when a user in all innocence enters an @ and
has his text disappear the next time the dialog is drawn!
L�LE�ET�TT�TE�ER�RS�S W�WE�E G�GE�ET�T L�LE�ET�TT�TE�ER�RS�S
The Feedback section on ANTIC ST ONLINE is now functional
and is producing a gratifying volume of response. A number of
requests were made for topics such as ST hardware and ST BASIC
which are beyond the intended scope of this column. These have
been referred to ANTIC's editorial staff for action.
So many good GEM questions were received that I will devote
part of the next column to answering several of general
interest. Also, your requests have resulting in scheduling
future columns on VDI text output and on the principles (or
mythology) of designing GEM application interfaces. Finally, a
tip of the hat to the anonymous reader who suggested including
the actual definitions of all macro symbols, so that those
without the appropriate H files can follow along. As a result
of this suggestion, the definitions for this column and the
previous three are included at the end of the download. Future
articles will continue this practice.
S�ST�TR�RA�AW�W P�PO�OL�LL�L!�!
I'd like to make a practice of using the Feedback to get
your opinions on the column's format. As a first trial, I'd
like to know your feelings about my use of "portability macros"
in the sample code. These macros, LLGET for example, are used
for compatibility between 68K GEM systems like the ST, and Intel
based systems like the IBM PC. This may be important to many
developers. On the other hand, omitting them results in more
natural looking C code. For instance, in the download you will
find a second version of settext() as described above, but
without the portability macros. So, I would like to know if you
think we should (A) Keep the macros - portability is important
to serious developers, (B) Get rid of them - who cares about
Intel chips anyway, or (C) Who cares? I'll tally the votes in
two weeks and announce the results here.
Back to Professional_GEM