bammi@cwruecmp.UUCP (Jwahar R. Bammi) (03/22/86)
#!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # wind4.prf # wind5.prf # wind6.prf # This archive created: Fri Mar 21 22:40:50 1986 # By: Jwahar R. Bammi () export PATH; PATH=/bin:$PATH echo shar: extracting "'wind4.prf'" '(18602 characters)' if test -f 'wind4.prf' then echo shar: over-writing existing file "'wind4.prf'" fi sed 's/^X//' << \SHAR_EOF > 'wind4.prf' X.!**************************************************************************** X.! X.! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION. X.! X.! ** Professional GEM ** by Tim Oren X.! X.! Proff File by ST enthusiasts at X.! Case Western Reserve University X.! Cleveland, Ohio X.! uucp : decvax!cwruecmp!bammi X.! csnet: bammi@case X.! arpa : bammi%case@csnet-relay X.! compuserve: 71515,155 X.! X.!**************************************************************************** X.! X.! X.!**************************************************************************** X.! X.! Begin Part 4 X.! X.!**************************************************************************** X.! X.PART IV Resource Structure X.PP XWelcome to the fourth installment of ST PRO GEM. We are about to delve into Xthe mysteries of GEM resource structure, and then use this knowledge to create Xsome useful utilities for handling dialogs. As with the past columns, there is Xonce again a download file. You will find it under the name GEMCL4.C in the XATARI 16-bit Forum (GO PCS-58). X.PP XThe first and largest part of the download contains a C image of a sample Xresource file. To create this listing, I used the GEM Resource Construction XSet to create a dummy resource with three dialogs including examples of all Xobject types, then enabled the C output option and saved the resource. If you Xhave access to a copy of RCS, I suggest that you create your own listing in Xorder to get a feel for the results. Then, using either listing as a roadmap Xto the resource, you can follow along as we enter... X.SH A MAZE OF TWISTY LITTLE PASSAGES. XWhile a GEM resource is loaded as a block of binary information, it Xis actually composed of a number of different data structures. These Xstructures are linked together in a rather tangled hierarchy. Our Xfirst job is to map this linkage system. X.PP XThe topmost structure in a resource file is the resource header. This is an Xarray of words containing the size and offset within the resource of the other Xstructures which follow. This information is used by GEM during the resource Xload process, and you should never need to access it. (The resource header does Xnot appear in the C output file; it is generated by the RSCREATE utility if the XC file is used to recreate the resource.) X.PP XThe next structure of interest is the tree index. This is an array of long Xpointers, each of which addresses the beginning of an object tree. Again, you Xwouldn't normally access this structure directly. The GEM rsrc_gaddr call uses Xit when finding trees' addresses. This structure is called "rs_trindex" in the XC output. X.PP XIf you look at the contents of rs_trindex you will notice that the values are Xintegers, instead of the pointers I described. What has happened is that RCS Xhas converted the pointers to indices into the object array. (If you actually Xused the C file to recreate the resource file, then the pointers would be Xregenerated by RSCREATE.) X.PP XNow you can follow the link from rs_trindex to the objects stored in Xrs_object. Take (for instance) the second entry in rs_trindex and count down Xthat many lines in rs_object. The following line (object) should start with a X-1. This indicates that it is the root object of a tree. The following objects Xdown to the next root belong to that tree. We'll pass over the details of Xinter-object linkage for now, leaving it for a later column. X.PP XThere are a number of different fields in an object, but right now we'll Xconcentrate on two of them: OB_TYPE and OB_SPEC. The OB_TYPE is the field which Xcontains mnemonics like G_STRING and G_BOX indicating the type of the object. XThe OB_SPEC is the only field in each object which is a LONG - you can tell it Xby the L after the number. X.PP XWhat's in OB_SPEC depends on the object type, so we need to talk about what Xkinds of objects are available, what you might use them for, and finally how Xthey use the OB_SPEC field. X.PP XThe box type objects are G_BOX, G_IBOX, and G_BOXCHAR. A G_BOX is an opaque Xrectangle, with an optional border. It's used to create a solid patch of color Xor pattern on which to place other objects. For instance, the background of a Xdialog is a G_BOX. X.PP XA G_IBOX is a hollow box which has only a border. (If the border has no Xthickness, then the box is "invisible", hence the name.) The favorite use for XIBOXes is to hold radio buttons. There is also one neat trick you can play with Xan IBOX. If you have more than one object (say an image and a string) which you Xwould like to have selected all at once, you can insert them in a dialog, then Xcover them with an IBOX. Since the box is transparent, they will show through. XIf you now make the box selectable, clicking on it will highlight the whole area Xat once! X.PP XThe G_BOXCHAR is just like a G_BOX, except that a single character is drawn Xin its center. They are mostly used as "control points": the FULLER, CLOSER, XSIZER, and arrows in GEM windows are BOXCHARs, as are the components of the Xcolor selection gadgets in the RCS. X.PP XThe OB_SPEC for box type objects is a packed bit array. Its various fields Xcontain the background color and pattern, the border thickness and color, and Xthe optional character and its color. X.PP XThe string type objects are G_STRING, G_BUTTON, and G_TITLE. G_STRINGs (in Xaddition to being a bad pun) are for setting up static explanatory text within Xdialogs. The characters are always written in the "system font": full size, Xblack, with no special effects. X.PP XWe have already discussed many of the uses of G_BUTTONs. They add a border Xaround the text. The thickness of a G_BUTTON's border is determined by what Xflags are set for the object. All buttons start out with a border thickness of Xone pixel. One pixel is added if the EXIT attribute is set, and one more is Xadded if the DEFAULT attribute is set. X.PP XThe G_TITLE type is a specially formatted text string used only in the title Xbar of menus. This type is needed to make sure that the menus redraw correctly. XThe Resource Construction Set automatically handles inserting G_TITLEs, so you Xwill seldom use them directly. X.PP XIn a resource, the OB_SPEC for all string objects is a long pointer to a null Xterminated ASCII string. The string data in the C file is shown in the BYTE Xarray rs_strings. Again you will notice that the OB_SPECs in the C file have Xbeen converted to indices into rs_string. To find the string which matches the Xobject, take the value of OB_SPEC and count down that many lines in rs_strings. XThe next line is the correct string. X.PP XThe formatted text object types are G_TEXT, G_BOXTEXT, G_FTEXT, and XG_FBOXTEXT. G_TEXTs are a lot like strings, except that you can specify a Xcolor, different sizes, and a positioning rule for the text. Since they Xrequire more memory than G_STRINGs, G_TEXTs should be used sparingly to draw Xattention to important information within a dialog. G_TEXTs are also useful Xfor automatic centering of dialog text which is changed at run-time. I will Xdescribe this technique in detail later on. X.PP XThe G_BOXTEXT type adds a solid background and border to the G_TEXT type. XThese objects are occasionally used in place of G_BUTTONs when their color will Xdraw attention to an important object. X.PP XThe G_FTEXT object is an editable text field. You are able to specify a Xconstant "template" of characters, a validation field for those characters which Xare to be typed in, and an initial value for the input characters. You may also Xselect color, size, and positioning rule for G_FTEXTs. We'll discuss text Xediting at length below. X.PP XThe G_FBOXTEXT object, as you might suspect, is the same as G_FTEXT with the Xaddition of background and border. This type is seldom used: the extra Xappearance details distract attention from the text being edited. X.PP XThe OB_SPEC for a formatted text object is a pointer to yet another type of Xstructure: a TEDINFO. In the C file, you will find these in rs_tedinfo. Take Xthe OB_SPEC value from each text type object and count down that many entries in Xrs_tedinfo, finding the matching TEDINFO on the next line. Each contains Xpointers to ASCII strings for the template, validation, and initialization. You Xcan find these strings in rs_strings, just as above. X.PP XThere are also fields for the optional background and border details, and for Xthe length of the template and text. As we will see when discussing editing, Xthe most important TEDINFO fields are the TE_PTEXT pointer to initialized text Xand the TE_TXTLEN field which gives its length. X.PP XThe G_IMAGE object type is the only one of its kind. A G_IMAGE is a Xmonochrome bit image. For examples, see the images within the various GEM alert Xboxes. Note that monochrome does not necessarily mean black. The image may be Xany color, but all parts of it are the SAME color. G_IMAGEs are used as visual Xcues in dialogs. They are seldom used as selectable items because their entire Xrectangle is inverted when they are clicked. This effect is seldom visually Xpleasing, particularly if the image is colored. X.PP XG_IMAGE objects have an OB_SPEC which is a pointer to a further structure Xtype: the BITBLK. By now, you should guess that you will find it in the C file Xin the array rs_bitblk. The BITBLK contains fields describing the height and Xwidth of the image in pixels, its color,nd it also contains a long pointer to Xthe actual bits which make up the image. In the C file, the images are encoded Xas hexadecimal words and stored in arrays named IMAG0, IMAG1, and so on. X.PP XThe last type of object is the G_ICON. Like the G_IMAGE, the G_ICON is a bit Ximage, but it adds a mask array which selects what portions of the image will be Xdrawn, as well as an explanatory text field. A G_ICON may also specify Xdifferent colors for its "foreground" pixels (the ones that are normally black), Xand its "background" pixels (which are normally white). X.PP XThe pictures which you see in Desktop windows are G_ICONs, and so are the Xdisks and trashcan on the desktop surface. With the latter you will notice the Xeffects of the mask. The desktop shows through right up to the edge of the XG_ICON, and only the icon itself (not a rectangle) is inverted when a disk is Xselected. X.PP XThe OB_SPEC of an icon points to another structure called an ICONBLK. It is Xshown in the C file as rs_iconblk. The ICONBLK contains long pointers to its Xforeground bit array, to the mask bit array, and to the ASCII string of Xexplanatory text. It also has the foreground and background colors as well as Xthe location of the text area from the upper left of the icon. The most common Xuse of G_ICONs and ICONBLKs is not in dialogs, instead they are used frequently Xin trees which are build at run-time, such as Desktop windows. In a future Xarticle, we will return to a discussion of building such "on-the-fly" trees with XG_ICONs. X.PP XNow, let's recap the hierarchy of resource structures: The highest level Xstructures are the resource header, and then the tree index. The tree index Xpoints to the beginning of each object tree. The objects making up the tree are Xof several types, and depending on that type, they may contain pointers to ASCII Xstrings, or to TEDINFO, ICONBLK, or BITBLK structures. TEDINFOs contain further Xpointers to strings; BITBLKs have pointers to bit images; and ICONBLKs have Xboth. X.SH PUTTING IT TO WORK XThe most common situations requiring you to understand Xresource structures involve the use of text and editable text objects in Xdialogs. We'll look at two such techniques. X.PP XOften an application requires two or more dialogs which are very similar Xexcept for one or two title lines. In this circumstance, you can save a good Xdeal of resource space by building only one dialog, and changing the title at Xrun time. X.PP XIt is easy to go wrong with this practice, however, because the obvious Xtactic of using a G_STRING and writing over its text at run time can go wrong. XThe first problem is that you must know in advance the longest title to be used, Xand put a string that long into the resource. If you don't you will damage other Xobjects in the resource as you copy in characters. The other problem is that a XG_STRING is always drawn at the same place in a dialog. If the length of the Xtitle changes from time to time, the dialog will have an unbalanced and sloppy Xappearance. X.PP XA better way to do this is to exploit the G_TEXT object type, and the TEDINFO Xstructure. The set_text() routine in the download shows how. The parameters Xprovided are the tree address, the object number, and the 32-bit address of the Xstring to be substituted. For this to work, the object referenced should be Xdefined as a G_TEXT type object. Additionally, the Centered text type should Xbe chosen, and the object should have been "stretched" so that it fills the Xdialog box from side to side. X.PP XIn the code, the first action is to get the OB_SPEC from the object which was Xreferenced. Since we know that the object is a G_TEXT, the OB_SPEC must point Xto a TEDINFO. We need to change two fields in the TEDINFO. The TE_PTEXT field Xis the pointer to the actual string to be displayed; we replace it with the Xaddress of our new string. The TE_TXTLEN field is loaded with the new string's Xlength. Since the Centered attribute was specified for the object, changing the XTE_TXTLEN will cause the string to be correctly positioned in the middle of the Xdialog! X.PP XEditing text also requires working with the TEDINFO structure. One way of Xdoing this is shown in the download. The object to be used (EDITOBJ) is assumed Xto be a G_FTEXT or G_FBOXTEXT. Since we will replace the initialized text at Xrun time, that field may be left empty when building the object in the RCS. X.PP XThe basic trick of this code is to point the TEDINFO's TE_PTEXT at a string Xwhich is defined in your code's local stack. The advantages of this technique Xare that you save resource space, save static data by putting the string in Xreusable stack memory, and automatically create a scratch string which may be Xdiscarded if the dialog is cancelled. X.PP XThe text string shown is arbitrarily 41 characters long. You should give Xyours a length equal to the number of blanks in the object's template field plus Xone. Note that the code is shown as a segment, rather than a subroutine. This Xis required because the text string must be allocated within the context of Xdialog handling routine itself, rather than a routine which it calls! X.PP XAfter the tree address is found, the code proceeds to find the TEDINFO and Xmodify its TE_PTEXT as described above. However, the length which is inserted Xinto TE_TXTLEN must be the maximum string length, including the null! X.PP XThe final line of code inserts a null into the first character of the Xuninitialized string. This will produce an empty editing field when the dialog Xis displayed. If there is an existing value for the object, you Xshould instead use strcpy() to move it into text[]. Once the dialog is Xcomplete, you should check its final status as described in the last Xarticle. If an "OK" button was clicked, you will then use strcpy() to Xmove the value in text[] back to its static location. X.PP XAlthough I prefer this method of handling editable text, another method Xdeserves mention also. This procedure allocates a full length text string of Xblanks when creating the editable object in the RCS. At run-time, the TE_PTEXT Xlink is followed to find this string's location in the resource, and any Xpre-existing value is copied in. After the dialog is run, the resulting value is Xcopied back out if the dialog completed successfully. X.PP XNote that in both editing techniques a copy of the current string value is Xkept within the application's data area. Threading the resource whenever you Xneed to check a string's value is extremely wasteful. X.PP XOne final note on editable text objects: GEM's editor uses the commercial at Xsign '@' as a "meta-character". If it is the first byte of the initialized Xtext, then the field is displayed blank no matter what follows. This can be Xuseful, but is sometimes confusing when a user in all innocence enters an @ and Xhas his text disappear the next time the dialog is drawn! X.SH LETTERS, WE GET LETTERS XThe Feedback section on ANTIC ST ONLINE is now Xfunctional and is producing a gratifying volume of response. A number of Xrequests were made for topics such as ST hardware and ST BASIC which are beyond Xthe intended scope of this column. These have been referred to ANTIC's Xeditorial staff for action. X.PP XSo many good GEM questions were received that I will devote part of the next Xcolumn to answering several of general interest. Also, your requests have Xresulting in scheduling future columns on VDI text output and on the principles X(or mythology) of designing GEM application interfaces. Finally, a tip of the Xhat to the anonymous reader who suggested including the actual definitions of Xall macro symbols, so that those without the appropriate H files can follow Xalong. As a result of this suggestion, the definitions for this column and the Xprevious three are included at the end of the download. Future articles will Xcontinue this practice. X.SH STRAW POLL! XI'd like to make a practice of using the Feedback to get your Xopinions on the column's format. As a first trial, I'd like to know your Xfeelings about my use of "portability macros" in the sample code. These macros, XLLGET for example, are used for compatibility between 68K GEM systems like the XST, and Intel based systems like the IBM PC. This may be important to many Xdevelopers. On the other hand, omitting them results in more natural looking C Xcode. For instance, in the download you will find a second version of Xset_text() as described above, but without the portability macros. So, I would Xlike to know if you think we should (A) Keep the macros - portability is Ximportant to serious developers, (B) Get rid of them - who cares about Intel Xchips anyway, or (C) Who cares? I'll tally the votes in two weeks and announce Xthe results here. X.SH STAY TUNED! XAs well as answers to feedback questions, the next column will Xdiscuss how GEM objects are linked to form trees, and how to use AES calls and Xyour own code to manipulate them for fun and profit. In the following Xinstallment, we'll look at the VDI raster operations (also known as "blit" Xfunctions). X.! X.! X.!***************************************************************************** X.!* * X.!* End Part 4 * X.!* * X.!***************************************************************************** SHAR_EOF if test 18602 -ne "`wc -c 'wind4.prf'`" then echo shar: error transmitting "'wind4.prf'" '(should have been 18602 characters)' fi echo shar: extracting "'wind5.prf'" '(17957 characters)' if test -f 'wind5.prf' then echo shar: over-writing existing file "'wind5.prf'" fi sed 's/^X//' << \SHAR_EOF > 'wind5.prf' X.!**************************************************************************** X.! X.! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION. X.! X.! ** Professional GEM ** by Tim Oren X.! X.! Proff File by ST enthusiasts at X.! Case Western Reserve University X.! Cleveland, Ohio X.! uucp : decvax!cwruecmp!bammi X.! csnet: bammi@case X.! arpa : bammi%case@csnet-relay X.! compuserve: 71515,155 X.! X.!**************************************************************************** X.! X.! X.!**************************************************************************** X.! X.! Begin Part 5 X.! X.!**************************************************************************** X.! X.PART V Resource Tree Structures X.PP XThis is the fifth issue of ST PROFESSIONAL GEM, concluding our Xtrek through GEM dialogs and resources with a look at the internal Xstructure of object trees. Also, I'll answer a number of questions Xof general interest which have been received via the ANTIC ONLINE XFEEDBACK. As always, there is a download file associated with this Xcolumn: GEMCL5.C, which you will find in DL3 of the new Atari 16-bit XSIG (type GO PCS-58 or GO ATARI16). X.PP XEven if you have no immediate use for this issue's code, be sure Xto take the download anyway; some of the routines will be used in Xlater articles. X.PP XIn the last installment, we established that resources trees are Xpointed to by the tree index, and that they are composed of objects Xwhich contain pointers onward to other structures. However, we Xpassed over the issue of linkage among the objects within a tree. It Xis now time to go back and cure this omission. X.PP XThe technical term for the linkage scheme of an object tree is a X"right-threaded binary tree". If you already know what this is, you Xcan skim over the next few paragraphs. If you happen to have access Xto a copy of the book "FUNDAMENTAL ALGORITHMS", which is part of the Xseries THE ART OF COMPUTER PROGRAMMING by Donald E. Knuth, you might Xwant to read his excellent discussion of binary trees beginning on Xpage 332. X.PP XFor the following discussion, you should have a listing of the C Ximage of a resource tree in front of you. For those who do not have Xthe listing from the last column, I have included a fragment at the Xbeginning of the download. Before we begin, I should warn you of one Xpeculiarity of "computer trees": They grow upside-down! That is, Xwhen they are diagrammed or described, their root is at the top, and Xthe "leaves" grow downward. You will see this both in the listing, Xand in the way the following discussion talks about moving through Xtrees. X.PP XEach GEM object tree begins at its ROOT object, numbered zero, Xwhich is the object pointed at by the tree index. There are three Xlink fields at the beginning of each object. They are called XOB_NEXT, OB_HEAD, and OB_TAIL, which is the order in which they Xappear. X.PP XEach of the links is shown as an index relative to the root of Xthe current tree. This means that the link '0' would refer to the Xroot of the tree, while '2' would indicate the object two lines below Xit. The special link -1 is called NIL, and means that there is no Xlink in the given direction. X.PP XEach object, or node, in a tree may have "offspring" or nodes Xwhich are nested below it. If it does, then its OB_HEAD will point Xto its first (or "leftmost") "child", while the OB_TAIL will point to Xthe last ("rightmost") of its offspring. The OB_NEXT pointer links Xthe children together, with the OB_NEXT of the first pointing to the Xsecond, and so on, until the OB_NEXT of the last finally points back Xto its parent, the object at which we started. X.PP XRemember that each of these children may in turn have offspring Xof their own, so that the original "parent" may have a large and Xcomplex collection of "descendents". X.PP XLet's look at the first tree in the download to see an example Xof this structure. The very first object is the ROOT. Note that its XOB_NEXT is NIL, meaning that there are no more objects in the tree: Xthe ROOT is both the beginning and the end of the tree. In this Xcase, the OB_HEAD is 1 and the OB_TAIL is 3, showing that there are Xat least two different children. X.PP XFollowing OB_HEAD down to the next line, we can trace through Xthe OB_NEXT links (2, 3, 0) as they lead through a total of three Xchildren and back to the ROOT. You will notice that the first two Xchildren have NIL for the OB_HEAD and OB_TAILs, indicating that they Xhave no further offspring. X.PP XHowever, node three, the last child of the ROOT, does have the Xvalue 4 for both its OB_HEAD and OB_TAIL. By this we can tell that Xit has one, and only one, offspring. Sure enough, when we look at Xnode four, we see that its OB_NEXT leads immediately back to node Xthree. Additionally, it has no further offspring because its OB_HEAD Xand OB_TAIL are NIL. X.PP XYou will find that object trees are always written out by the XResource Construction Set in "pre-order". (Again, see Knuth if you Xhave a copy.) This means that the ROOT is always written first, then Xits offspring left to right. This rule is applied recursively, that Xis, we go down to the next level and write out each of these nodes, Xthen THEIR children left to right, and so on. X.PP XFor a further example, look at the next tree in rs_object in the Xdownload. You will see that the ROOT has an OB_HEAD of 1 and an XOB_TAIL of 6, but that it actually has only three offspring (nodes 1, X2 and 6). We see that node 2 itself had children, and applying the Xrule given above, they were written out before continuing with the Xnext child of the ROOT. X.PP XWhy was this seemingly complex structure chosen for GEM? The Xreason has do with the tasks of drawing objects in their proper Xlocations on the screen, and determining which object was "hit" when Xa mouse click is detected. X.PP XTo find out how this works, we must look at four more fields Xfound in each object: OB_X, OB_Y, OB_WIDTH, and OB_HEIGHT. These Xfields are the last four on each line in the sample trees. X.PP XEach object in a tree "owns" a rectangle on the screen. These Xfields define that rectangle. When a resource is stored "outside" Xthe program the fields are in character units, so that an object Xwith OB_WIDTH of 10 and OB_HEIGHT of 2 (for instance) would define a Xscreen area 10 characters wide and 2 high. X.PP XWhen the resource is read into memory with an rsrc_load call, XGEM multiplies the appropriate character dimension in pixels into Xeach of these fields. In this way portability is achieved: the same Xresource file works for any of the ST's three resolutions. Knowing Xhow rsrc_load works, your code should treat these fields as pixel Xcoordinates. X.PP XI have committed one oversimplification above. If an object is Xnot created on a character boundary in the RCS, then the external Xstorage method described will not work. In this case, the lower byte Xof each rectangle field is used to store the nearest character Xposition, while the upper byte stores the pixel remainder to be added Xafter the character size is multiplied in. XNon-character-boundary objects may only be created in the "FREE" Xtree mode of the Resource Construction Set (also called "PANEL" in XRCS 2.0). You should use them only in programs which will run in a Xsingle ST screen mode, because pixel coordinates are not portable Xbetween resolutions. X.PP XThe first real secret of object rectangles is that each OB_X and XOB_Y is specified RELATIVE to the X and Y coordinate of its parent Xobject within the tree. This is the first property we have seen Xthat is actually "inherited" from level to level within the tree. X.PP XThe second secret is more subtle: Every object's rectangle must Xbe entirely contained within the rectangle of its parent. This Xprinciple goes by the names "bounding rectangles" or "visual Xhierarchy". We'll see in a moment how useful it is when detecting Xmouse/object collisions. X.SH HOW GEM DOES IT. XKnowing these secrets, and the linkage structure of object Xtrees, we can deduce how a number of the GEM operations must work. XFor instance, consider objc_offset, which returns the actual screen XX and Y of an object. We can see now that simply loading the OB_X Xand OB_Y fields of the object does not suffice: they only give the Xoffset relative to the parent object. So, objc_offset must BEGIN Xwith these values, and then work its way back up to the ROOT of the Xtree, adding in the offsets found at each level. X.PP XThis can be done by following the OB_NEXT links from the chosen Xobject. Whenever OB_NEXT points to an object whose OB_TAIL points Xright back to the same location, then the new node is another level, Xor "parent" in the tree, and objc_offset adds its OB_X and OB_Y into Xthe running totals. When OB_NEXT becomes NIL, then the ROOT has been Xreached and the totals are the values to return. (By the way, Xremember that the OB_X and OB_Y of the ROOT are undefined until Xform_center has been called for the tree. They are shown as zeroes Xin the sample trees.) X.PP XWe can also figure out objc_draw. It works its way DOWN the Xtree, drawing each object as it comes to it. It, too, must keep a Xrunning X and Y variable, adding in object offsets as it descends Xtree levels (using OB_HEAD), and subtracting them again as it returns Xfrom each level. Since the larger objects are nearer the ROOT, we Xcan now see why they are drawn first, with smaller objects drawn Xlater or "on top of" them. X.PP XIf you write an application which needs to move portions of a Xdialog or screen with respect to each other, you can take advantage Xof inheritance of screen position in objc_draw. Simply by changing Xthe OB_X and/or OB_Y of an object, you can move it and its entire Xsub-tree to a new location in the dialog. For instance, changing the Xcoordinates of the parent box of a set of radio buttons will cause Xall of the buttons to move along with it. X.PP XObjc_draw also gives us an example of the uses of visual Xhierarchy. Recall that a clipping rectangle is specified when calling Xobjc_draw. At each level of the tree we know that all objects below Xare contained in the screen rectangle of the current object. If the Xcurrent rectangle falls completely outside the specified clipping Xrectangle, we know immediately that we need not draw the object, or Xany of its descendents! This ability to ignore an entire subtree is Xcalled "trivial rejection". X.PP XNow it's rather easy to figure out objc_find. It starts out by Xsetting its "object found" variable to NIL. It begins a "walk" Xthrough the entire object tree, following OB_HEAD and OB_NEXT links, Xand keeping a current X and Y, just like objc_draw. X.PP XAt each node visited, it simply checks to see if the "mouse" X,Y Xspecified in the call are inside the current object's rectangle. If Xthey are, that object becomes the found object, and the tree walk Xcontinues with the object's offspring, and then siblings. Notice how Xthis checking of offspring makes sure that a smaller object nested Xwithin, i.e., below, a larger object is found correctly. X.PP XIf the mouse X,Y position is not within the object being Xchecked, then by visual hierarchy it cannot be within any of its Xoffspring, either. Trivial rejection wins again, and the entire Xsub-tree is skipped! Objc_find moves on to the OB_NEXT of the Xrejected object. X.SH THOUGHT EXPERIMENTS XThinking about the objc_find algorithm reveals some information Xabout its performance, and a few tricks we may use in improving the Xappearance of dialogs and other object trees. X.PP XFirst consider the problem of a dialog which contains many Xobjects. If we lay them all out "side-by-side", then they will all be Ximmediate offspring of the ROOT object. In this situation, the Xtrivial rejection method will gain nothing. The time objc_find takes Xto complete will vary linearly with the total number of objects. XThis is called an "Order N" process. X.PP XSuppose that instead we broke up the dialog into two areas with Xinvisible boxes, then broke up each of these areas in a like fashion, Xand so on until we got down to the size of the individual selectable Xobjects. The number of bottom level objects in this scheme is a Xpower of two equal to the depth of the tree. Trivial rejection is Xused to its fullest in this case. It is called an "Order Log N" Xprocess, and is much more efficient for large numbers of objects. X.PP XIn practice, the speed of the ST will allow you to ignore this Xdistinction for most dialogs and other trees. But if you get into a Xsituation when speed is critical in searching a large tree, remember Xthat nesting objects can improve performance dramatically. X.PP XIf you have been following closely, you may have also noticed a Xhole in the visual hierarchy rule. It says that all of a node's Xchildren must lie within its rectangle, but it does NOT guarantee Xthat the children's rectangles will be disjoint, that is, not Xoverlap one another. This peculiarity is the basis of several useful Xtricks. X.PP XFirst, remember that objc_find always tries to scan the entire Xtree. That is, it doesn't quit when it finds the first object on the Xgiven coordinates. As mentioned above, this normally guarantees that Xnested objects will be found. Consider, however, what happens when Xthe mouse coordinates are on a point where two or more objects AT XTHE SAME LEVEL overlap: they will replace one another as the "found Xobject" until objc_find returns with the one which is "last", that Xis, rightmost in the tree. X.PP XThis quirk can be used to advantage in a number of cases. XSuppose that you have in a dialog an image and a string which you Xwould like to be selected together when either is clicked. Nesting Xwithin a common parent achieves nothing in this case. Instead, Xknowing that form_do must use objc_find, you could use our trick. X.PP XYou have to know that the Resource Construction Set normally Xadds objects in a tree left to right, in the order in which you Xinserted them. You proceed to build the dialog in the following Xorder: insert the image first, the string next, then carefully add Xan invisible box which is not nested within either, and size it to Xcover them both. Set the SELECTABLE attribute for the box, and the Xdialog manager will find it, and invert the whole area, when either Xthe image or string is clicked. X.PP XBy the way, remember that the SORT option in the RCS will change Xthe order of an object's offspring. If you are going to try this Xtrick, don't use SORT! It will undo all of your careful work. X.SH A TREEWALKER OF OUR OWN XSince the GEM system gets so much mileage out of walking object Xtrees, it seems reasonable that the same method should be useful in Xapplication programs. In the download you will find map_tree(). As Xmany LISP veterans might guess from the name, this code will traverse Xall or part of an object tree, applying a function to each node. It Xalso allows the function to return a true/false value specifying Xwhether the sub-tree below a particular node should be ignored. XLet's examine map_tree() in more detail as a final review of object Xtree structure. X.PP XFirst, look at the parameters. "tree" is the long address of Xthe object tree of interest, as retrieved by rsrc_gaddr. "this" is Xthe node at which to begin the traverse, and "last" is the node at Xwhich to terminate. X.PP XIn most cases, the beginning node will be ROOT, and the final Xvalue will be NIL. This will result in the entire tree being Xtraversed. You may use other values, but be sure that you CAN get to X"last" from "this" by following tree links! Although map_tree() Xincludes a safety check to prevent "running off" the tree, you could Xget some very strange results from incorrect parameters. X.PP XThe declaration for the final parameter, "routine", makes use of XC construct which may be new to some. It is a pointer to a Xsubroutine which returns a WORD as a result. X.PP XMap_tree() begins by initializing a temporary variable, tmp1, Xwhich is used to store the number of the last node visited. Since no Xnode will follow itself, setting tmp1 to the starting node is safe. X.PP XThe main loop of the routine simply repeats visiting a new node Xuntil the last value is reached, or the safety check for end of tree Xis satisfied. X.PP XAt any node visited, we can be in one of two conditions. Either Xwe are at a node which is "new", that is, not previously visited, or Xelse we are returning to a parent node which has already been Xprocessed. We can detect the latter condition by comparing the last Xnode visited (tmp1) with the OB_TAIL pointer of the current node. If Xthe node is "old", it is not processed a second time, we simply Xupdate tmp1 and continue. X.PP XIf the node is new, we call "routine" to process it, sending the Xtree address and object number as parameters. If a FALSE is Xreturned, we will ignore any subtree below this node. On a TRUE Xreturn, we load up the OB_HEAD pointer and follow it if a subtree Xexists. (If you don't care about rejecting subtrees, simply remove Xthe if condition.) Finally, if the new node had no subtree, or was Xrejected by "routine", we follow along its OB_NEXT link to the next Xnode. X.PP XA simple application of our new tool shows its power. From a Xprevious column you may recall the tedium of deselecting every button Xinside a dialog after it was completed. Using map_tree(), you can Xdeselect EVERY OBJECT in the tree by using map_tree(tree, ROOT, NIL, Xdesel_obj); You must use a slightly modified version of desel_obj() X(included in the download) which always returns TRUE. Be sure to Xdefine or declare desel_obj() in your code BEFORE making the map_tree Xcall! X.PP XIn future columns, I will return to map_tree() and show how it Xcan be used for advanced techniques such as animated dialogs. In the Xmeantime, experiment and enjoy! X.! X.! X.!***************************************************************************** X.!* * X.!* End Part 5 * X.!* * X.!***************************************************************************** SHAR_EOF if test 17957 -ne "`wc -c 'wind5.prf'`" then echo shar: error transmitting "'wind5.prf'" '(should have been 17957 characters)' fi echo shar: extracting "'wind6.prf'" '(20611 characters)' if test -f 'wind6.prf' then echo shar: over-writing existing file "'wind6.prf'" fi sed 's/^X//' << \SHAR_EOF > 'wind6.prf' X.!**************************************************************************** X.! X.! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION. X.! X.! ** Professional GEM ** by Tim Oren X.! X.! Proff File by ST enthusiasts at X.! Case Western Reserve University X.! Cleveland, Ohio X.! uucp : decvax!cwruecmp!bammi X.! csnet: bammi@case X.! arpa : bammi%case@csnet-relay X.! compuserve: 71515,155 X.! X.!**************************************************************************** X.! X.! X.!**************************************************************************** X.! X.! Begin Part 6 X.! X.!**************************************************************************** X.! X.PART VI Raster operations X.SH SEASONS GREETINGS XThis is the Yuletide installment of ST PRO GEM, devoted to Xexplaining the raster, or "bit-blit" portion of the Atari ST's VDI Xfunctions. X.PP XPlease note that this is NOT an attempt to show how to write Xdirectly to the video memory, although you will be able to deduce a Xgreat deal from the discussion. X.PP XAs usual, there is a download with this column. You will find Xit in ATARI16 (PCS-58) in DL3 under the name of GEMCL6.C. X.SH DEFINING TERMS XTo understand VDI raster operations, you need to understand the Xjargon used to describe them. (Many programmers will be tempted to Xskip this section and go directly to the code. Please don't do it Xthis time: Learning the jargon is the larger half of understanding Xthe raster operations!) X.PP XIn VDI terms a raster area is simply a chunk of contiguous words Xof memory, defining a bit image. This chunk is called a "form". A Xform may reside in the ST's video map area or it may be in the data Xarea of your application. Forms are roughly analogous to "blits" or X"sprites" on other systems. (Note, however, that there is no sprite Xhardware on the ST.) X.PP XUnlike other systems, there is NO predefined organization of the Xraster form. Instead, you determine the internal layout of the form Xwith an auxiliary data structure called the MFDB, or Memory Form XDefinition Block. Before going into the details of the MFDB, we need Xto look at the various format options. Their distinguishing features Xare monochrome vs. color, standard vs. device-specific and even-word Xvs. fringed. X.SH MONOCHROME VS. COLOR XAlthough these terms are standard, it might be better to say X"single-color vs. multi-color". What we are actually defining is the Xnumber of bits which correspond to each dot, or pixel, on the screen. XIn the ST, there are three possible answers. The high-resolution mode Xhas one bit per pixel, because there is only one "color": white. X.PP XIn the medium resolution color mode, there are four possible Xcolors for each pixel. Therefore, it takes two bits to represent Xeach dot on the screen. (The actual colors which appear are Xdetermined by the settings of the ST's pallette registers.) X.PP XIn the low resolution color mode, sixteen colors are generated Xrequiring four bits per pixel. Notice that as the number of bits per Xpixel has been doubled for each mode, so the number of pixels on the Xscreen has been halved: 640 by 400 for monochrome, 640 by 200 for Xmedium-res, and 320 by 200 by low-res. In this way the ST always Xuses the same amount of video RAM: 32K. X.PP XNow we have determined how many bits are needed for each pixel, Xbut not how they are laid out within the form. To find this out, we Xhave to see whether the form is device-dependent or not. X.SH STANDARD VS. DEVICE-SPECIFIC FORMAT XThe standard raster form format is a constant layout which is Xthe same for all GEM systems. A device-specific form is one which is Xstored in the internal format of a particular GEM system. Just as Xthe ST has three different screen modes, so it has three different Xdevice-specific form formats. We will look at standard form first, Xthen the ST-specific forms. X.PP XFirst, it's reasonable to ask why a standard format is used. Its Xmain function is to establish a portability method between various XGEM systems. For instance, an icon created in standard format on an XIBM PC GEM setup can be moved to the ST, or a GEM Paint picture from Xan AT&T 6300 could be loaded into the ST version of Paint. X.PP XThe standard format has some uses even if you only work with the XST, because it gives a method of moving your application's icons and Ximages amongst the three different screen modes. To be sure, there Xare limits to this. Since there are different numbers of pixels in Xthe different modes, an icon built in the high-resolution mode will Xappear twice as large in low-res mode, and would appear oblong in Xmedium-res. (You can see this effect in the ST Desktop's icons.) XAlso, colors defined in the lower resolutions will be useless in Xmonochrome. X.PP XThe standard monochrome format uses a one-bit to represent Xblack, and uses a zero for white. It is assumed that the form begins Xat the upper left of the raster area, and is written a word at a Xtime left to right on each row, with the rows being output top to Xbottom. Within each word, the most significant bit is the left-most Xon the screen. X.PP XThe standard color form uses a storage method called "color Xplanes". The high-order bits for all of the pixels are stored just as Xfor monochrome, followed by the next-lowest bit in another contiguous Xblock, and so on until all of the necessary color bits have been Xstored. X.PP XFor example, on a 16-color system, there would be four different Xplanes. The color of the upper-leftmost bit in the form would be Xdetermined by concatenating the high-order bit in the first word of Xeach plane of the form. X.PP XThe system dependent form for the ST's monochrome mode is very Xsimple: it is identical to the standard form! This occurs because Xthe ST uses a "reverse-video" setup in monochrome mode, with the Xbackground set to white. X.PP XThe video organization of the ST's color modes is more Xcomplicated. It uses an "interleaved plane" system to store the bits Xwhich make up a pixel. In the low-resolution mode, every four words Xdefine the values of 16 pixels. The high-order bits of the four Xwords are merged to form the left-most pixel, followed by the next Xlower bit of each word, and so on. This method is called Xinterleaving because the usually separate color planes described Xabove have been shuffled together in memory. X.PP XThe organization of the ST's medium-resolution mode is similar Xto low-res, except the only two words are taken at a time. These are Xmerged to create the two bits needed to address four colors. X.PP XYou should note that the actual color produced by a particular Xpixel value is NOT fixed. The ST uses a color remapping system Xcalled a palette. The pixel value in memory is used to address a Xhardware register in the palette which contains the actual RGB Xlevels to be sent to the display. Programs may set the palette Xregisters with BIOS calls, or the user may alter its settings with Xthe Control Panel desk accessory. Generally, palette zero X(background) is left as white, and the highest numbered palette is Xblack. X.SH EVEN-WORD VS. FRINGES XA form always begins on a word boundary, and is always stored Xwith an integral number of words per row. However, it is possible Xto use only a portion of the final word. This partial word is called Xa "fringe". If, for instance, you had a form 40 pixels wide, it Xwould be stored with four words per row: three whole words, and one Xword with the eight pixel fringe in its upper byte. X.SH MFDB's XNow we can intelligently define the elements of the MFDB. Its Xexact C structure definition will be found in the download. The Xfd_nplanes entry determines the color scheme: a value of one is Xmonochrome, more than one denotes a color form. If fd_stand is zero, Xthen the form is device-specific, otherwise it is in standard format. X.PP XThe fd_w and fd_h fields contain the pixel width and height of Xthe form respectively. Fd_wdwidth is the width of a row in words. XIf fd_w is not exactly equal to sixteen times fd_wdwidth, then the Xform has a fringe. X.PP XFinally, fd_addr is the 32-bit memory address of the form Xitself. Zero is a special value for fd_addr. It denotes that this XMFDB is for the video memory itself. In this case, the VDI Xsubstitutes the actual address of the screen, and it ignores ALL of Xthe other parameters. They are replaced with the size of the whole Xscreen and number of planes in the current mode, and the form is (of Xcourse) in device-specific format. X.PP XThis implies that any MFDB which points at the screen can only Xaddress the entire screen. This is not a problem, however, since the Xthe VDI raster calls allow you to select a rectangular region within Xthe form. (A note to advanced programmers: If this situation is Xannoying, you can retrieve the address of the ST's video area from Xlow memory, add an appropriate offset, and substitute it into the XMFDB yourself to address a portion of the screen.) X.SH LET'S OPERATE XNow we can look at the VDI raster operations themselves. There Xare actually three: transform form, copy raster opaque, and copy Xraster transparent. Both copy raster functions can perform a variety Xof logic operatoins during the copy. X.SH TRANSFORM FORM XThe purpose of this operation is to change the format of a form: Xfrom standard to device-specific, or vice-versa. The calling Xsequence is: X.FB vr_trnfm() Xvr_trnfm(vdi_handle, source, dest); X.FE Xwhere source and dest are each pointers to MFDBs. They ARE allowed Xto be the same. Transform form checks the fd_stand flag in the Xsource MFDB, toggles it and writes it into the destination MFDB after Xrewriting the form itself. Note that transform form CANNOT change Xthe number of color planes in a form: fd_nplanes must be identical in Xthe two MFDBs. X.PP XIf you are writing an application to run on the ST only, you Xwill probably be able to avoid transform form entirely. Images and Xicons are stored within resources as standard forms, but since they Xare monochrome, they will work "as is" with the ST. X.PP XIf you may want to move your program or picture files to another XGEM system, then you will need transform form. Screen images can be Xtransformed to standard format and stored to disk. Another system Xwith the same number of color planes could the read the files, and Xtransform the image to ITS internal format with transform form. X.PP XA GEM application which will be moved to other systems needs to Xcontain code to transform the images and icons within its resource, Xsince standard and device-specific formats will not always coincide. X.PP XIf you are in this situation, you will find several utilities in Xthe download which you can use to transform G_ICON and G_IMAGE Xobjects. There is also a routine which may be used with map_tree() Xfrom the last column in order to transform all of the images and Xicons in a resource tree at once. X.SH COPY RASTER OPAQUE XThis operation copies all or part of the source form into the Xdestination form. Both the source and destination forms must be in Xdevice-specific form. Copy raster opaque is for moving information Xbetween "like" forms, that is, it can copy from monochrome to Xmonochrome, or between color forms with the same number of planes. XThe calling format is: X.FB vro_cpyfm() Xvro_cpyfm(vdi_handle, mode, pxy, source, dest); X.FE XAs above, the source and dest parameters are pointers to MFDBs X(which in turn point to the actual forms). The two MFDBs may point Xto memory areas which overlap. In this case, the VDI will perform Xthe move in a non-destructive order. Mode determines how the pixel Xvalues in the source and destination areas will be combined. I will Xdiscuss it separately later on. X.PP XThe pxy parameter is a pointer to an eight-word integer array. XThis array defines the area within each form which will be affected. XPxy[0] and pxy[1] contain, respectively, the X and Y coordinates of Xthe upper left corner of the source rectangle. These are given as Xpositive pixel displacements from the upper left of the form. XPxy[2] and pxy[3] contain the X and Y displacements for the lower Xright of the source rectangle. X.PP XPxy[4] through pxy[7] contain the destination rectangle in the Xsame format. Normally, the destination and source should be the same Xsize. If not, the size given for the source rules, and the whole are Xis transferred beginning at the upper left given for the destination. X.PP XThis all sounds complex, but is quite simple in many cases. XConsider an example where you want to move a 32 by 32 pixel area Xfrom one part of the display to another. You would need to allocate Xonly one MFDB, with a zero in the fd_addr field. The VDI will take Xcare of counting color planes and so on. The upper left raster Xcoordinates of the source and destination rectangles go into pxy[0], Xpxy[1] and pxy[4], pxy[5] respectively. You add 32 to each of these Xvalues and insert the results in the corresponding lower right Xentries, then make the copy call using the same MFDB for both source Xand destination. The VDI takes care of any overlaps. X.SH COPY RASTER TRANSPARENT XThis operation is used for copying from a monochrome form to a Xcolor form. It is called transparent because it "writes through" to Xall of the color planes. Again, the forms need to be in Xdevice-specific form. The calling format is: X.FB vrt_cpyfm() Xvrt_cpyfm(vdi_handle, mode, pxy, source, dest, color); X.FE XAll of the parameters are the same as copy opaque, except that Xcolor has been added. Color is a pointer to a two word integer Xarray. Color[0] contains the color index which will be used when a Xone appears in the source form, and color[1] contains the index for Xuse when a zero occurs. X.PP XIncidentally, copy transparent is used by the AES to draw XG_ICONs and G_IMAGEs onto the screen. This explains why you do not Xneed to convert them to color forms yourself. X.PP XA note for advanced VDI programmers: The pxy parameter in both Xcopy opaque and transparent may be given in normalized device Xcoordinates (NDC) if the workstation associated with vdi_handle was Xopened for NDC work. X.SH THE MODE PARAMETER XThe mode variable used in both of the copy functions is an Xinteger with a value between zero and fifteen. It is used to select Xhow the copy function will merge the pixel values of the source and Xdestination forms. The complete table of functions is given in the Xdownload. Since a number of these are of obscure or questionable Xusefulness, I will only discuss the most commonly used modes. X.SH REPLACE MODE XA mode of 3 results in a straight-forward copy: every Xdestination pixel is replaced with the corresponding source form Xvalue. X.SH ERASE MODE XA mode value of 4 will erase every destination pixel which Xcorresponds to a one in the source form. (This mode corresponds to Xthe "eraser" in a Paint program.) A mode value of 1 will erase every Xdestination pixel which DOES NOT correspond to a one in the source. X.SH XOR MODE XA mode value of 6 will cause the destination pixel to be toggled Xif the corresponding source bit is a one. This operation is Xinvertable, that is, executing it again will reverse the effects. XFor this reason it is often used for "software sprites" which must be Xshown and then removed from the screens. There are some problems Xwith this in color operations, though - see below. X.SH TRANSPARENT MODE XDon't confuse this term with the copy transparent function Xitself. In this case it simply means that ONLY those destination Xpixels corresponding with ones in the source form will be modified Xby the operation. If a copy transparent is being performed, the Xvalue of color[0] is substituted for each one bit in the source form. XA mode value of 7 selects transparent mode. X.SH REVERSE TRANSPARENT MODE XThis is like transparent mode except that only those destination Xpixels corresponding to source ZEROS are modified. In a copy Xtransparent, the value of color[1] is substituted for each zero bit. XMode 13 selects reverse transparent. X.SH THE PROBLEM OF COLOR XI have discussed the various modes as if they deal with one and Xzero pixel values only. This is exactly true when both forms are Xmonochrome, but is more complex when one or both are color forms. X.PP XWhen both forms are color, indicating that a copy opaque is Xbeing performed, then the color planes are combined bit-by-bit using Xthe rule for that mode. That is, for each corresponding source and Xdestination pixel, the VDI extracts the top order bits and processes Xthem, then operates on the next lower bit, and so on, stuffing each Xbit back into the destination form as the copy progresses. For Xexample, an XOR operation on pixels valued 7 and 10 would result in a Xpixel value of 13. X.PP XIn the case of a copy transparent, the situation is more Xcomplex. The source form consists of one plane, and the destination Xform has two or more. In order to match these up, the color[] array Xis used. Whenever a one pixel is found, the value of color[0] is Xextracted and used in the bit-by-bit merge process described in the Xlast paragraph. When a zero is found, the value of color[1] is Xmerged into the destination form. X.PP XAs you can probably see, a raster copy using a mode which Xcombines the source and destination can be quite complex when color Xplanes are used! The situation is compounded on the ST, since the Xactual color values may be remapped by the palette at any time. In Xmany cases, just using black and white in color[] may achieve the Xeffects you desire. If need to use full color, experimentation is Xthe best guide to what looks good on the screen and what is garish Xor illegible. X.SH OPTIMIZING RASTER OPERATIONS XBecause the VDI raster functions are extremely generalized, they Xare also slower than hand-coded screen drivers which you might write Xfor your own special cases. If you want to speed up your Xapplication's raster operations without writing assembl language Xdrivers, the following hints will help you increase the VDI's Xperformance. X.SH AVOID MERGED COPIES XThese are copy modes, such as XOR, which require that words be Xread from the destination form. This extra memory access increases Xthe running time by up to fifty percent. X.SH MOVE TO CORRESPONDING PIXELS XThe bit position within a word of the destination rectangle Xshould correspond with the bit position of the source rectangle's Xleft edge. For instance, if the source's left edge is one pixel in, Xthen the destination's edge could be at one, seventeen, thirty-three, Xand so. Copies which do not obey this rule force the VDI to shift Xeach word of the form as it is moved. X.SH AVOID FRINGES XPut the left edge of the source and destination rectangles on Xan even word boundary, and make their widths even multiples of Xsixteen. The VDI then does not have to load and modify partial words Xwithin the destination forms. X.SH USE ANOTHER METHOD XSometimes a raster operation is not the fastest way to Xaccomplish your task. For instance, filling a rectangle with zeros Xor ones may be accomplished by using raster copy modes zero and Xfifteen, but it is faster to use the VDI v_bar function instead. XLikewise, inverting an area on the screen may be done more quickly Xwith v_bar by using BLACK in XOR mode. Unfortunately, v_bar cannot Xaffect memory which is not in the video map, so these alternatives Xdo not always work. X.SH FEEDBACK RESULTS XThe results of the poll on keeping or dropping the use of Xportability macros are in. By a slim margin, you have voted to keep Xthem. The vote was close enough that in future columns I will try to Xinclude ST-only versions of routines which make heavy use of the Xmacros. C purists and dedicated Atarians may then use the alternate Xcode. X.SH THE NEXT QUESTION XThis time I'd like to ask you to drop by the Feedback Section Xand tell me whether the technical level of the columns has been: X.br X.sp 1 X.in +4 XA) Too hard! Who do you think we are, anyway? X.br XB) Too easy! Don't underestimate Atarians. X.br XC) About right, on the average. X.in -4 X.PP XIf you have the time, it would also help to know a little about Xyour background, for instance, whether you are a professional Xprogrammer, how long you have been computing, if you owned an 8-bit XAtari, and so on. X.SH COMING UP SOON XThe next column will deal with GEM menus: How they are Xconstructed, how to decipher menu messages, and how to change menu Xentries at run-time. The following issue will contain more feedback Xresponse, and a discussion on designing user interfaces for GEM Xprograms. X.! X.! X.!***************************************************************************** X.!* * X.!* End Part 6 * X.!* * X.!***************************************************************************** SHAR_EOF if test 20611 -ne "`wc -c 'wind6.prf'`" then echo shar: error transmitting "'wind6.prf'" '(should have been 20611 characters)' fi # End of shell archive exit 0 -- Jwahar R. Bammi Usenet: .....!decvax!cwruecmp!bammi CSnet: bammi@case Arpa: bammi%case@csnet-relay CompuServe: 71515,155