home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 10: Diskmags / nf_archive_10.iso / MAGS / ON_DISC / ONDISC03.MSA / F1.MAG < prev    next >
Text File  |  1985-11-19  |  16KB  |  353 lines

  1.  
  2.  
  3.                 ** Professional GEM ** by Tim Oren
  4.  
  5.                     THE DIALOG HANDLER   11/7/85
  6.  
  7.  
  8.  
  9.    A MEANINGFUL DIALOG
  10.  
  11.    This issue of ST PRO GEM begins an exploration of ST GEM's dialog
  12. handler.  I will discuss basic system calls for presenting the
  13. dialog, and then continue with techniques for initializing and
  14. reading on/off button and "radio" button objects.  We  will also take
  15. some short side-trips into the operation of the GEM Resource
  16. Construction Set to assist you in building these dialogs.
  17.  
  18.    There are a number of short C routines which accompany this column.
  19. These are stored as file GMCL03.C in the download section of the
  20. ANTIC SIG. Before reading this column, you should download this
  21. file.
  22.  
  23.    DEFINING TERMS
  24.  
  25.    A dialog box is an "interactive form" in which the user may enter
  26. text and indicate selections by pointing with the mouse. Dialogs in
  27. GEM are "modal", that is, when a dialog is activated other screen
  28. functions such as menus and  window controls are suspended until the
  29. dialog is completed.
  30.  
  31.    In most cases, the visual structure of a GEM dialog is specified
  32. within your application's resource file.  The GEM Resource
  33. Construction Set (RCS) is used to build a picture of the dialog.
  34.  
  35.    When the RCS writes out a resource, it converts that picture into a
  36. tree of GEM drawing objects and stores this data structure within the
  37. resource.  Before your application can  display the dialog, it must
  38. load this resource file and find the  address of the tree which
  39. defines the dialog.
  40.  
  41.    To load a resource, the AES checks its size and allocates memory for
  42. the load.  It then reads in the resource, adjusting internal pointers
  43. to reflect the load address.  Finally, the object sizes stored in the
  44. resource are converted from characters to pixels using the system
  45. font size.
  46.  
  47.    (A note for those with Macintosh experience:  Although Mac and GEM
  48. resources share a name, there are fundamental differences which can
  49. be misleading.  A Mac resource is a fork within a file; a GEM
  50. resource is a TOS file by itself.  Mac resources may be paged in and
  51. out of memory; GEM resources are monolithic.  GEM resources are
  52. internally tree structured; Mac resources are not.  Finally, Mac
  53. resources include font information, while ST GEM does this with font
  54. loading at the VDI level.)
  55.  
  56.    The resource load is done with the GEM AES call:
  57.  
  58.    ok = rsrc_load(ADDR("MYAPP.RSC"));
  59.  
  60.    "MYAPP" should be replaced with the name of your program. Resources
  61. conventionally have the same primary name as their application, with
  62. the RSC extent name instead of PRG.  The ok flag returned by
  63. rsrc_load will be FALSE is anything went wrong during the load.
  64.  
  65.    The most common causes of failure are the resource not being in the
  66. application's subdirectory, or lack of sufficient memory for GEM to
  67. allocate space for the resource.  If this happens, you must terminate
  68. the program immediately.
  69.  
  70.    Once you have loaded the resource, you find the address of a dialog's
  71. object tree with:
  72.  
  73.    rsrc_gaddr(R_TREE, MYDIALOG, &tree);
  74.  
  75. Tree is a 32-bit variable which will receive the address of the root
  76. node of the tree.
  77.  
  78.    The mnemonic MYDIALOG should be replaced with the name you gave your
  79. dialog when defining it in the RCS.  At the same time that it writes
  80. the resource, RCS generates a corresponding .H file containing tree
  81. and object names.  In order to use these mnemonics within your
  82. program, you must include the name file in your compile:  #include
  83. "MYAPP.H"
  84.  
  85.    BUG ALERT!
  86.  
  87. When using the DRI/Alcyon C compiler, .H files must be in the
  88. compiler's home directory or they will not be found.  This is
  89. especially annoying using a two floppy drive ST development system.
  90. The only way around this is to explicitly  reference an alternate
  91. disk in the #include, for instance:  "B:MYAPP.H"
  92.  
  93.    Now that the address of the dialog tree has been found, you are ready
  94. to display it.  The standard (and minimal) sequence for doing so is
  95. given in routine hndl_dial() in the download.  We will now walk
  96. through each step in this procedure.
  97.  
  98.    The form_center call establishes the location of the dialog on the
  99. screen.  Dialog trees generated by the RCS have an undefined origin
  100. (upper-left corner).
  101.  
  102.    Form_center computes the upper-left location necessary to center the
  103. dialog on the screen, and inserts it into the OB_X and OB_Y fields of
  104. the ROOT object of the tree.  It also computes the screen rectangle
  105. which the dialog will occupy on screen and writes its pixel
  106. coordinates into variables xdial, ydial, wdial, and hdial.
  107.  
  108.    There is one peculiarity of form_center which occasionally causes
  109. trouble.  Normally the rectangle returned in xdial, etc., is exactly
  110. the same size as the basic dialog box.
  111.  
  112.    However, when the OUTLINED enhancement has been specified for the
  113. box, form_center adds a three pixel margin to the rectangle returned.
  114. This causes the screen area under the outline to be correctly redrawn
  115. later (see below).  Note that OUTLINED is part of the standard dialog
  116. box in the RCS.  Other enhancements, such as SHADOWED or "outside"
  117. borders are NOT handled in this fashion, and you must compensate  for
  118. them in your code.
  119.  
  120.    The next part of the sequence is a form_dial call with a zero
  121. parameter.  This reserves the screen for the dialog action about to
  122. occur. Note that the C binding given for form_dial in the DRI
  123. documents is in error: there are nine parameters, not five.  The
  124. first set of xywh arguments is actually used with form_dial calls 1
  125. and 2 only, but place holders must be supplied in all cases.
  126.  
  127.    The succeeding form_dial call (parameter one) animates a "zoom box"
  128. on the screen which moves and grows from the first screen rectangle
  129. given to the second rectangle, where the dialog will be displayed.
  130.  
  131.    The use of this call is entirely optional.  In choosing whether to
  132. use it or not, you should consider whether the origin of the "zoom"
  133. is relevant to the  operation.  For instance, a zoom from the menu
  134. bar is relatively meaningless, while a zoom from an object about to
  135. be edited in the dialog provides visual feedback to the user, showing
  136. whether the correct object was chosen.
  137.  
  138.    If the origin is not relevant, then the zoom is just a time-waster.
  139. If  you decide to include these effects, consider a "preferences"
  140. option in  your app which will allow the experienced and jaded user
  141. to turn them off in the interests of speed.
  142.  
  143.    The objc_draw call actually displays the dialog on the screen. Note
  144. that the address of the tree, the beginning drawing object, and the
  145. drawing depth are passed as arguments, as well as the rectangle
  146. allotted for the dialog.
  147.  
  148.    In general, dialogs (and parts of dialogs) are  ALWAYS drawn
  149. beginning at the ROOT (object zero).  When you want to draw  only a
  150. portion of the dialog, adjust the clipping rectangle, but not the
  151. object number.  This ensures that the background of the dialog is
  152. always  drawn correctly.
  153.  
  154.    The objc_xywh() utility in the download can be used to find the
  155. clipping rectangle for any object within a dialog, though you may
  156. have to allow an extra margin is you have used shadows, outlines, or
  157. outside borders with the object.
  158.  
  159.    Calling form_do transfers control to the AES, which animates the
  160. dialog for user interaction.  The address of the dialog tree is
  161. passed as a parameter.  The second paramter is the number of the
  162. editable object at which the text cursor will first be positioned.
  163. If you have no text fields, pass a zero.  Note that again the DRI
  164. documents are in error: passing a -1 default may crash the system.
  165. Also be careful that the default which you specify is actually a text
  166. field; no error checking is performed.
  167.  
  168.    The form_do call returns the number of the object on which the
  169. clicked to terminate the dialog.  Usually this is a button type
  170. object with the EXIT and SELECTABLE attributes set.  Setting the
  171. DEFAULT attribute as well will cause an exit on that object is a
  172. carriage return is struck while in the dialog.
  173.  
  174.    If the top bit of the return is set, it indicates that  the exit
  175. object had the TOUCHEXIT attribute and was selected with a
  176. double-click.  Since very few dialogs use this combination, the
  177. sample code simply masks off the top bit.
  178.  
  179.    The next form_dial call reverses the "zoom box", moving it from the
  180. dialog's location back to the given x,y,w,h.  The same cautions apply
  181. here as above.
  182.  
  183.    The final form_dial call tells GEM that the dialog is complete, and
  184. that the screen area occupied by the dialog is now considered "dirty"
  185. and needs to be redrawn.  Using the methods described in our last
  186. column, GEM then sends redraws to all windows which were overlaid,
  187. and does any necessary redrawing of the menu or desktop itself.
  188.  
  189.    There is one notable "feature" of form_dial(3):  It always redraws an
  190. area which is two pixels wider and higher than your request!  This
  191. was probably included to make sure that drop-shadows were cleaned up,
  192. and is usually innocuous.
  193.  
  194.    A HANDY TRICK
  195.  
  196. Use of the form_dial(3) call is not limited to dialogs.  You can use
  197. it to force the system to redraw any part of the screen.  The
  198. advantage of this method is that the redraw area need not lie
  199. entirely within a window, as was necessary with the send_redraw
  200. method detailed in the last column.  A disadvantage is that this
  201. method is  somewhat slower, since the AES has to decide who gets the
  202. redraws.
  203.  
  204.    CLEAN UP
  205.  
  206. As a last step, you need to clear the SELECTED flag in the object
  207. which was clicked.  If you do not do this, the object will  be drawn
  208. inverted the next time you call the dialog.  You could clear the flag
  209. with the GEM objc_change call, but it is inefficient since you do
  210. not need to redraw the object.
  211.  
  212.    Instead, use the desel_obj() code in the  download, which modifies
  213. the object's OB_STATE field directly.  Assuming  that ret_obj
  214. contains the exit object returned by hndl_dial, the call:
  215.  
  216.    desel_obj(tree, ret_obj);
  217.  
  218.  will do the trick.
  219.  
  220.    RECAP
  221.  
  222. The basic dialog handling method I have described contains three
  223. steps: initialization (rsrc_gaddr), dialog presentation (hndl_dial),
  224. and cleanup (desel_obj).
  225.  
  226.    As we build more advanced dialogs, these same basic steps will be
  227. performed, but they will grow more complex. The initialization will
  228. include setting up proper object text and states, and the cleanup
  229. phase will also interrogate the final states of objects to find out
  230. what the user did.
  231.  
  232.    BUTTON, BUTTON
  233.  
  234. The simple dialogs described above contain only exit buttons as
  235. active objects.  As such, they are little more than glorified alert
  236. boxes.
  237.  
  238.    We will now increase the complexity a little by considering non-exit
  239. buttons.  These are constructed by setting the SELECTABLE attribute
  240. on a button object.  At run-time, such an object will toggle its
  241. state between selected (highlighted) and non-selected  whenever the
  242. user clicks on it.  (You can set the SELECTABLE attribute  of other
  243. types of objects and use them instead of actual buttons, but  be sure
  244. that the user will be able to figure out what you intend!)
  245.  
  246.    Having non-exit buttons forces us to consider the problem of
  247. initializing them before the dialog, and interrogating and resetting
  248. them afterward.
  249.  
  250.    Since a button is a toggle, it is usually associated with a flag
  251. variable in the program.  As part of the initialization, you should
  252. test the flag variable, and if true call:
  253.  
  254.    sel_obj(tree, BTNOBJ);
  255.  
  256. which will cause the button to appear highlighted when the dialog is
  257. first drawn.  Sel_obj() is in the download.  BTNOBJ is replaced with
  258. the  name you gave your button when you defined it in the RCS.  Since
  259. the button starts out deselected, you don't have to do anything if
  260. your flag variable is false.
  261.  
  262.    After the dialog has completed, you need to check the object's state.
  263. The selectp() utility does so by masking the OB_STATE field.  You can
  264. simply assign the result of this test to your flag variable, but be
  265. sure that the dialog was exited with an OK button, not with a CANCEL!
  266. Again, remember to clean up the button with desel_obj(). (It's often
  267. easiest to deselect all buttons just before you leave the dialog
  268. routine, regardless of the final dialog state.)
  269.  
  270.    WHO'S GOT THE BUTTON?
  271.  
  272. Another common use of buttons in a  dialog is to select one of a set
  273. of possible options.  In GEM, such objects are called radio buttons.
  274. This term recalls automobile radio tuners where pushing in one button
  275. pops out any others.  In like fashion, selecting any one of a set of
  276. radio buttons automatically deselects all of the others.
  277.  
  278.    To use the radio button feature, you must do some careful work with
  279. the Resource Construction Set.
  280.  
  281.    First, each member of a set of  radio buttons must be children of the
  282. same parent object within the  object tree. To create this structure,
  283. put a hollow box type object in the  dialog, make it big enough to
  284. hold all of the buttons, and then put the buttons into the box one at
  285. a time.
  286.  
  287.    By nesting the buttons within the  box object, you force them to be
  288. its children.  Each of the buttons must have both the SELECTABLE and
  289. RADIO BUTTON attributes set.  When you are done, you may make the
  290. containing box invisible by setting its border to zero, but do not
  291. FLATTEN it!
  292.  
  293.    Since each radio button represents a different option, you must
  294. usually assign a name to each object.  When initializing the dialog,
  295. you must check which option is currently set, and turn on the
  296. corresponding button only.  A chain of if-then-else structures
  297. assures that only one button will be selected.
  298.  
  299.    At the conclusion of the dialog, you must check each button with
  300. selectp() and make the appropriate adjustments to internal variables.
  301. Again, an if-then-else chain is appropriate since only one button may
  302. be selected.  Either deselect the chosen button within this chain or
  303. do them all at the end.
  304.  
  305.    There is one common use of radio buttons in which you may short-cut
  306. this procedure.  If the buttons each represent one possible value of
  307. a numeric variable, for instance, a set of selector buttons
  308. representing  colors from zero to seven, then you can compute the
  309. initial object directly.
  310.  
  311.    In order for this technique to work, you must use a special
  312. capability of the RCS.  Insert the object corresponding to a zero
  313. value at the top (or left) of your array of buttons, then put the
  314. "one" button below (or right) of it, and so on.
  315.  
  316.    When the buttons are complete,  the SORT operation is used to
  317. guarantee that the top/left object is in fact the first child of the
  318. parent box with the others following in order.  Due to the details of
  319. object tree structure (to be discussed in the next column), this will
  320. guarantee that these objects are contiguous in the resource.
  321.  
  322.    If you assign a name (say BUTTON1) to the first button,  then you can
  323. initialize the correct button with the call:
  324.  
  325.    sel_obj(tree, BUTTON1 + field);
  326.  
  327.  where field is the variable of interest.
  328.  
  329.    When the dialog is complete, you can scan the radio buttons to
  330. compute the new value for the underlying variable.  The encode()
  331. procedure in the download will do this.  As always, remember to
  332. deselect the buttons at the end.
  333.  
  334.    You can use offsets or multipliers if your variable's values don't
  335. start with zero or increment by one.  If the values are irregular you
  336. may be able to use a lookup table, at the cost of additional code.
  337.  
  338.    COMING UP NEXT
  339.  
  340. In the next column, I will discuss the internal structure of object
  341. trees.  Then we'll use that knowledge to build a piece of code which
  342. will "walk" an entire tree and apply a function to each object.
  343. We'll apply this code to do all of the button deselects  with a
  344. single call!  I'll also look at handling editable text fields and
  345. discuss some ways to alter a dialog's appearance at run-time.
  346.  
  347.    DISPELL GREMLINS
  348.  
  349. An editing error caused an omission in the first installment of ST
  350. PRO GEM.  The window components RTARROW and DNARROW should have been
  351. listed along with HSLIDE as the horizontal equivalents of the
  352. vertical slider components which were discussed.
  353.