home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / books / progem / menus.7 < prev    next >
Text File  |  1986-11-01  |  24KB  |  532 lines

  1.     Permission to reprint or excerpt is granted only if the following line
  2.     appears at the top of the article:
  3.  
  4.       ANTIC PUBLISHING INC., COPYRIGHT 1986. REPRINTED BY PERMISSION.
  5.  
  6.  
  7.  
  8.     Professional GEM  by Tim Oren
  9.     Column #7 - Menu Structures
  10.  
  11.  
  12.     HAPPY NEW YEAR!
  13.  
  14.         This  is  article  number  seven in the ST PRO GEM series, and the
  15.     first  for  1986.   In this installment, I will be discussing GEM menu
  16.     structures  and  how to use them in your application.  There is also a
  17.     short  Feedback  response  section.   You  will find the download file
  18.     containing the code for this column in the file GEMCL7.C in DL3 of the
  19.     ATARI16 SIG (PCS-58).
  20.  
  21.  
  22.     MENU BASICS
  23.  
  24.         In ST GEM, the menu consists of a bar across the top of the screen
  25.     which  displays  several  sub-menu titles.  Touching one of the titles
  26.     causes  it  to  highlight,  and  an associated "drop-down" to be drawn
  27.     directly  below  on  the  screen.   This drop-down may be dismissed by
  28.     moving  to  another  title,  or  by  clicking  the  mouse  off  of the
  29.     drop-down.
  30.  
  31.         To  make a selection, the mouse is moved over the drop-down.  Each
  32.     valid  selection  is  highlighted when the mouse touches it.  Clicking
  33.     the  mouse  while  over  one of these selections picks that item.  GEM
  34.     then  undraws  the  drop-down, and sends a message to your application
  35.     giving the object number of the title bar entry, and the object number
  36.     of  the  drop-down item which were selected by the user.  The selected
  37.     title  entry  is  left  highlighted  while  your  code  processes  the
  38.     request.
  39.  
  40.  
  41.     MENU STRUCTURES
  42.  
  43.         The  data  structure  which  defines  a GEM menu is (surprise!) an
  44.     object  tree, just like the dialogs and panels which we have discussed
  45.     before.   However,  the  operations  of the GEM menu manager are quite
  46.     different  from  those  of the form manager, so the internal design of
  47.     the menu tree has some curious constraints.
  48.  
  49.         The  best  way  to  understand  these constraints is to look at an
  50.     example.   The  first  item  in  the  download is the object structure
  51.     (only) of the menu tree from the GEM Doodle/Demo sample application.
  52.  
  53.         The  ROOT  of  a  menu tree is sized to fit the entire screen.  To
  54.     satisfy the visual hierarchy principle (see article #5), the screen is
  55.     divided  into  two parts: THE BAR, containing the menu titles, and THE
  56.     SCREEN,  while  contains  the drop-downs when they are drawn.  Each of
  57.     these  areas  is  defined by an object of the same name, which are the
  58.     only  two  objects linked directly below the ROOT of a menu tree.  You
  59.     will  notice  an  important  implication  of  this structure: the menu
  60.     titles   and  their  associated  drop-downs  are  stored  in  entirely
  61.     different subtrees of the menu!
  62.  
  63.         While  examining  THE  BAR  in the example listing, you may notice
  64.     that  its  OB_HEIGHT  is  very  large  (513).   In hexadecimal this is
  65.     0x0201.   This  defines a height for THE BAR of one character plus two
  66.     pixels used for spacing.  THE BAR and its subtree are the only objects
  67.     which are drawn on the screen in the menu's quiescent state.
  68.  
  69.         The  only  offspring object of THE BAR is THE ACTIVE.  This object
  70.     defines  the  part  of  THE  BAR which is covered by menu titles.  The
  71.     screen  rectangle  belonging  to  THE ACTIVE is used by the GEM screen
  72.     manager  when  it  waits for the mouse to enter an active menu title.
  73.     Notice  that  THE  ACTIVE  and its offspring also have OB_HEIGHTs with
  74.     pixel residues.
  75.  
  76.         The actual menu titles are linked left to right in order below THE
  77.     ACTIVE.    Their  OB_Xs  and  OB_WIDTHs  are  arranged  so  that  they
  78.     completely  cover  THE  ACTIVE.  Normally, the title objects are typed
  79.     G_TITLE,  a  special type which assures that the title bar margins are
  80.     correctly drawn.
  81.  
  82.         THE SCREEN is the parent object of the drop-down boxes themselves.
  83.     They are linked left to right in an order identical with their titles,
  84.     so  that  the  menu  manager  can  make  the correct correspondence at
  85.     run-time.   The OB_X of each drop-down is set so that it is positioned
  86.     below its title on the screen.
  87.  
  88.         Notice  that  it  is safe to overlap the drop-downs within a menu,
  89.     since  only  one  of them will be displayed at any time.  There is one
  90.     constraint  on  the  boxes  however:  they  must  be no greater than a
  91.     quarter screen in total size.  This is the size of the off-screen blit
  92.     buffer  which  is  used  by  GEM to store the screen contents when the
  93.     drop-down is drawn.  If you exceed this size, not all the screen under
  94.     the drop-down will be restored, or the ST may crash!
  95.  
  96.         The  entries  within  a drop-down are usually G_STRINGs, which are
  97.     optimized  for  drawing  speed.   The rectangles of these entries must
  98.     completely  cover  the  drop-down,  or  the  entire  drop-down will be
  99.     inverted  when  the  mouse  touches an uncovered area!  Techniques for
  100.     using objects other than G_STRINGs are discussed later in this column.
  101.  
  102.         The  first title and its corresponding drop-down are special.  The
  103.     title  name,  by  custom,  is set to DESK.  The drop-down must contain
  104.     exactly  eight  G_STRING  objects.  The first (again by custom) is the
  105.     INFO  entry,  which  usually  leads  to a dialog displaying author and
  106.     copyright  information  for your application.  The next is a separator
  107.     string  of  dashes  with  the  DISABLED  flag  set.  The following six
  108.     objects  are  dummy  strings which GEM fills in with the names of desk
  109.     accessories when your menu is loaded.
  110.  
  111.         The  purpose  of  this description of menu trees is to give you an
  112.     understanding  of  what  lies "behind the scenes" in the next section,
  113.     which  describes  the  run-time  menu library calls.  In practice, the
  114.     Resource  Construction Set provides "blank menus" which include all of
  115.     the  required  elements,  and  it  also  enforces  the  constraints on
  116.     internal  structure.  You only need to worry about these if you modify
  117.     the menu tree "on-the-fly".
  118.  
  119.  
  120.     USING THE MENU
  121.  
  122.         Once  you  have loaded the application's resource, you can ask the
  123.     AES  to install your menu.  You must first get the address of the menu
  124.     tree within the resource using:
  125.  
  126.         rsrc_gaddr(R_TREE, MENUTREE, &ad_menu);
  127.  
  128.     assuming  that  MENUTREE is the name you gave the menu in the RCS, and
  129.     that  ad_menu is a LONG which will receive the address.  Then you call
  130.     the AES to establish the menu:
  131.  
  132.         menu_bar(ad_menu, TRUE);
  133.  
  134.     At  this point, the AES draws your menu bar on the screen and animates
  135.     it when the user moves the mouse into the title area.
  136.  
  137.         The  AES  indicates  that  the  user  has made a menu selection by
  138.     sending  your application a message.  The message type is MN_SELECTED,
  139.     which  will  be  stored  in  msg[0], the first location in the message
  140.     returned by evnt_multi().
  141.  
  142.         The AES also stores the object number of the selected menu's title
  143.     in  msg[3], and the object number of the selected menu item in msg[4].
  144.     Generally,  your  application will process menu messages with nested C
  145.     switch  statements.  The outer switch will have one case for each menu
  146.     title, and the inner switch statements will have a case for each entry
  147.     within  the selected menu.  (This implies that you must give a name to
  148.     each  title  and  to  each  menu entry when you create the menu in the
  149.     RCS.)
  150.  
  151.         After the user has made a menu selection, the AES leaves the title
  152.     of  the chosen menu in reverse video to indicate that your application
  153.     is  busy  processing  the  message.   When  you are done with whatever
  154.     action  is  indicated, you need to return the title to a normal state.
  155.     This is done with
  156.  
  157.         menu_tnormal(ad_menu, msg[3], TRUE);
  158.  
  159.     (Remember that msg[3] is the title's object number.)
  160.  
  161.         When  your application is ready to terminate, it should delete its
  162.     menu bar.  Do this with the call:
  163.  
  164.         menu_bar(ad_menu, FALSE);
  165.  
  166.  
  167.     GETTING FANCY
  168.  
  169.         The  techniques  above represent the bare minimum to handle menus.
  170.     In  most  cases,  however,  you  will  want  your  menus  to  be  more
  171.     "intelligent" in displaying the user's options.  For instance, you can
  172.     prevent  many  user  errors by disabling inappropriate choices, or you
  173.     can save space on drop-downs by showing only one line for a toggle and
  174.     altering  its text or placing and removing a check mark when the state
  175.     is   changed.    This  section  discusses  these  and  other  advanced
  176.     techniques.
  177.  
  178.         It  is a truism of user interface design that the best way to deal
  179.     with  an  error  is  not to let it happen in the first place.  It many
  180.     cases,  you can apply this principle to GEM menus by disabling choices
  181.     which  should  not  be  used.   If  your application uses a "selection
  182.     precedes  action"  type  of interface, the type of object selected may
  183.     give the information needed to do this.  Alternately, the state of the
  184.     underlying program may render certain menu choices illegal.
  185.  
  186.         GEM  provides  a  call to disable and re-enable menu options.  The
  187.     call is:
  188.  
  189.         menu_ienable(ad_menu, ENTRY, FALSE);
  190.  
  191.     to  disable  a  selection.   The  entry  will be grayed out when it is
  192.     drawn, and will not invert under the mouse and will not be selected by
  193.     the user. Substituting TRUE for FALSE re-enables the option.  ENTRY is
  194.     the  name  of  the  object which is being affected, as assigned in the
  195.     RCS.
  196.  
  197.         Note  that  menu_ienable() will not normally affect the appearance
  198.     or operation of menu TITLE entries.  However, there is an undocumented
  199.     feature  which allows this.  If ENTRY is replaced by the object number
  200.     of  a title bar entry with its top bit set, then the entire associated
  201.     drop-down will be disabled or re-enabled as requested, and the title's
  202.     appearance  will be changed.  But, be warned that this feature did not
  203.     work  reliably in some early versions of GEM.  Test it on your copy of
  204.     ST  GEM,  and  use it with caution when you cannot control the version
  205.     under which your application may run.
  206.  
  207.         It  is  also possible to disable menu entries by directly altering
  208.     the  DISABLED  attribute  within  the  OB_STATE  word.   The  routines
  209.     enab_obj()  and  disab_obj()  in  the download show how this is done.
  210.     They are also used in set_menu(), which follows them immediately.
  211.  
  212.         Set_menu()  is  a  utility  which  is  useful  when  you  wish  to
  213.     simultaneously  enable  or  disable  many entries in the menu when the
  214.     program's  state  changes or a new object is selected by the user.  It
  215.     is called with
  216.  
  217.         set_menu(ad_menu, vector);
  218.  
  219.     where vector is a pointer to an array of WORDs.  The first word of the
  220.     array  determines  the  default state of menu entries.  If it is TRUE,
  221.     then  set_menu()  enables  all  entries in every drop-down of the menu
  222.     tree,  except  that the DESK drop-down is unaffected.  If it is FALSE,
  223.     then every menu entry is disabled.
  224.  
  225.         The following entries in the array are the numbers of menu entries
  226.     which are to be toggled to the reverse of the default state. This list
  227.     is terminated by a zero entry.
  228.  
  229.         The  advantage  of  set_menu()  is  that  it allows you to build a
  230.     collection  of  menu state arrays, and associate one with each type of
  231.     user-selected  object,  program state, and so on.  Changing the status
  232.     of the menu tree may then be accomplished with a single call.
  233.  
  234.  
  235.     CHECK, PLEASE?
  236.  
  237.         One type of state indicator which may appear within a drop-down is
  238.     a  checkmark  next  to  an  entry.  You can add the checkmark with the
  239.     call:
  240.  
  241.         menu_icheck(ad_menu, ENTRY, TRUE);
  242.  
  243.     and  remove  it  by replacing the TRUE with FALSE.  As above, ENTRY is
  244.     the  name of the menu entry of interest.  The checkmark appears inside
  245.     the left boundary of the entry object, so leave some space for it.
  246.  
  247.         The  menu_icheck()  call  is  actually  changing  the state of the
  248.     CHECKED  flag  within the entry object's OB_STATE word.  If necessary,
  249.     you may alter the flag directly using do_obj() and undo_obj() from the
  250.     download.
  251.  
  252.  
  253.     NOW YOU SEE IT, NOW YOU DON'T
  254.  
  255.         You  can  also  alter  the text which appears in a particular menu
  256.     entry (assuming that the entry is a G_STRING object).  The call
  257.  
  258.         menu_text(ad_menu, ENTRY, ADDR(text));
  259.  
  260.     will  substitute  the  null-terminated  string  pointed to by text for
  261.     whatever  is  currently in ENTRY.  Remember to make the drop-down wide
  262.     enough to handle the largest text string which you may substitute.  In
  263.     the  interests  of  speed,  G_STRINGs  drawn within drop-downs are not
  264.     clipped,  so  you  may get garbage characters on the desktop if you do
  265.     not size the drop-down properly!
  266.  
  267.         The menu_text() call actually alters the OB_SPEC field of the menu
  268.     entry object to point to the string which you specify.  Since the menu
  269.     tree  is a static data structure which may be directly accessed by the
  270.     AES  at any time, be sure that the string is also statically allocated
  271.     and that it is not modified without first being delinked from the menu
  272.     tree.   Failure  to do this may result in random crashes when the user
  273.     accesses the drop-down!
  274.  
  275.  
  276.     LUNCH AND DINNER MENUS
  277.  
  278.         Some  applications  may  have such a wide range of operations that
  279.     they  need  more  than  one  menu bar at different times.  There is no
  280.     problem with having more than one menu tree in a resource, but the AES
  281.     can  only keep track of one at a time.  Therefore, to switch menus you
  282.     need to use menu_bar(ad_menu1, FALSE); to release the first menu, then
  283.     use menu_bar(ad_menu2, TRUE); to load the second menu tree.
  284.  
  285.         Changing   the   entire   menu   is  a  drastic  action.   Out  of
  286.     consideration for your user, it should be associated with some equally
  287.     obvious  change  in  the  application  which  has  just  been manually
  288.     requested.   An  example  might  be  changing from spreadsheet to data
  289.     graphing mode in a multi-function program.
  290.  
  291.  
  292.     DO IT YOURSELF
  293.  
  294.         In  a  future  column,  I  will discuss how to set up user-defined
  295.     drawing objects.  If you have already discovered them on your own, you
  296.     can use them within a drop-down or as a title entry.
  297.  
  298.         If  the  user-defined object is within a drop-down, its associated
  299.     drawing  code  will be called once when the drop-down is first drawn.
  300.     It  will  then  be  called  in  "state-change"  mode when the entry is
  301.     highlighted  (inverted).   This allows you to use non-standard methods
  302.     to show selection, such as outlines.
  303.  
  304.         If  you  try to insert a user-defined object within the menu title
  305.     area,  remember  that  the  G_TITLE  object  which  you  are replacing
  306.     includes  part  of  the  dark  margin  of  the  bar.  You will need to
  307.     experiment with your object drawing code to replicate this effect.
  308.  
  309.  
  310.     MAKE PRETTY
  311.  
  312.         There  are  a  number  of  menu  formatting conventions which have
  313.     become  standard  practice.   Using  these  gives  your  application a
  314.     recognizable  "look-and-feel" and helps users learn it.  The following
  315.     section reviews these conventions, and supplies a few hints and tricks
  316.     to obtain a better appearance for you menus.
  317.  
  318.         The  second  drop-down  is  customarily used as the FILE menu.  It
  319.     contains  options  related to loading and saving the files used by the
  320.     application,  as  well  as  entries  for  clearing  the  workspace and
  321.     terminating the program.
  322.  
  323.         You  should avoid crowding the menu bar.  Leave a couple of spaces
  324.     between  each entry, and try not to use more than 70% of the bar.  Not
  325.     only  does  this look better, but you will have space for longer words
  326.     if you translate your application to a foreign language.
  327.  
  328.         Similarly,  avoid  cluttering  menu  drop-downs.   Try to keep the
  329.     number of options to no more than ten unless they are clearly related,
  330.     such  as  colors.   Separate  off dissimilar entries with the standard
  331.     disabled  dashes  line.   (If  you  are  using set_menu(), remember to
  332.     consider the separators when setting up the state vectors.)
  333.  
  334.         If  the  number of options grows beyond this bound, it may be time
  335.     to  move them to a dialog box.  If so, it is a convention to put three
  336.     dots  following each menu entry which leads to a dialog. Also, allow a
  337.     margin  on  the menu entries.  Two leading blanks and a minimum of one
  338.     trailing blank is standard, and allows room for checkmarks if they are
  339.     used.
  340.  
  341.         Dangerous  menu  options  should  be  far  away  from  common used
  342.     entries,  and  are  best  separated  with  dashed lines.  Such options
  343.     should  either  lead  to  a  confirming go/no-go alert, or should have
  344.     associated "undo" options.
  345.  
  346.         After you have finished defining a menu drop-down with the RCS, be
  347.     sure  that  its  entries cover the entire box.  Then use ctrl-click to
  348.     select the drop-down itself, and SORT the entries top to bottom.  This
  349.     way the drop-down draws in smoothly top to bottom.
  350.  
  351.         Finally,  it  is possible to put entries other than G_STRINGs into
  352.     drop-downs.   In  the  RCS,  you  will  need  to  import  them via the
  353.     clipboard from the Dialog mode.
  354.  
  355.         Some  non-string  object,  such as icons and images, will look odd
  356.     when they are inverted under the mouse.  There is a standard trick for
  357.     dealing  with  this  problem.   Insert  the  icon  or  whatever in the
  358.     drop-down first.  Then get a G_IBOX object and position and size it so
  359.     that  it  covers  the first object as well as the extra area you would
  360.     like to be inverted.
  361.  
  362.         Edit the G_IBOX to remove its border, and assign the entry name to
  363.     it.   Since  the  menu  manager  uses  objc_find(), it will detect and
  364.     invert  this  second  object when the mouse moves into the drop-down.
  365.     (To  see  why, refer to article #5.)  Finally, DO NOT SORT a drop-down
  366.     which has been set up this way!
  367.  
  368.  
  369.     THAT'S IT FOR NOW!
  370.  
  371.         The  next  column will discuss some of the principles of designing
  372.     GEM  interfaces for applications.  This topic is irreverantly known as
  373.     GEM  mythology  or  interface religion.  The subject for the following
  374.     column  is  undecided.   I am considering mouse and keyboard messages,
  375.     VDI  drawing primitives, and the file selector as topics.  Let me know
  376.     your preferences in the Feedback!
  377.  
  378.  
  379.  
  380.  
  381. >>>>>>>>>>>>>>>>>>>>>>>>>>>> Sample Menu Tree <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  382.  
  383. -1, 1, 6, G_IBOX, NONE, NORMAL, 0x0L, 0,0, 80,25,       /* ROOT             */
  384. 6, 2, 2, G_BOX, NONE, NORMAL, 0x1100L, 0,0, 80,513,     /* THE BAR          */
  385. 1, 3, 5, G_IBOX, NONE, NORMAL, 0x0L, 2,0, 20,769,       /* THE ACTIVE       */
  386. 4, -1, -1, G_TITLE, NONE, NORMAL, 0x0L, 0,0, 6,769,     /* Title #1         */
  387. 5, -1, -1, G_TITLE, NONE, NORMAL, 0x1L, 6,0, 6,769,     /* Title #2         */
  388. 2, -1, -1, G_TITLE, NONE, NORMAL, 0x2L, 12,0, 8,769,    /* Title #3         */
  389. 0, 7, 22, G_IBOX, NONE, NORMAL, 0x0L, 0,769, 80,19,     /* THE SCREEN       */
  390. 16, 8, 15, G_BOX, NONE, NORMAL, 0xFF1100L, 2,0, 20,8,   /* Drop-down #1     */
  391. 9, -1, -1, G_STRING, NONE, NORMAL, 0x3L, 0,0, 19,1,     /* About... entry   */
  392. 10, -1, -1, G_STRING, NONE, DISABLED, 0x4L, 0,1, 20,1,
  393. 11, -1, -1, G_STRING, NONE, NORMAL, 0x5L, 0,2, 20,1,    /* Desk acc entries */
  394. 12, -1, -1, G_STRING, NONE, NORMAL, 0x6L, 0,3, 20,1,
  395. 13, -1, -1, G_STRING, NONE, NORMAL, 0x7L, 0,4, 20,1,
  396. 14, -1, -1, G_STRING, NONE, NORMAL, 0x8L, 0,5, 20,1,
  397. 15, -1, -1, G_STRING, NONE, NORMAL, 0x9L, 0,6, 20,1,
  398. 7, -1, -1, G_STRING, NONE, NORMAL, 0xAL, 0,7, 20,1,
  399. 22, 17, 21, G_BOX, NONE, NORMAL, 0xFF1100L, 8,0, 13,5,  /* Drop-down #2     */
  400. 18, -1, -1, G_STRING, NONE, NORMAL, 0xBL, 0,0, 13,1,
  401. 19, -1, -1, G_STRING, NONE, DISABLED, 0xCL, 0,1, 13,1,
  402. 20, -1, -1, G_STRING, NONE, NORMAL, 0xDL, 0,4, 13,1,
  403. 21, -1, -1, G_STRING, NONE, NORMAL, 0xEL, 0,2, 13,1,
  404. 16, -1, -1, G_STRING, NONE, DISABLED, 0xFL, 0,3, 13,1,
  405. 6, 23, 25, G_BOX, NONE, NORMAL, 0xFF1100L, 14,0, 26,3,  /* Drop down #3     */
  406. 24, -1, -1, G_STRING, NONE, NORMAL, 0x10L, 0,2, 26,1,
  407. 25, -1, -1, G_STRING, NONE, NORMAL, 0x11L, 0,0, 26,1,
  408. 22, -1, -1, G_STRING, LASTOB, DISABLED, 0x12L, 0,1, 26,1
  409.  
  410.  
  411. >>>>>>>>>>>>>>>>>>>>>>>> Menu enable/disable utility <<<<<<<<<<<<<<<<<<<<<<
  412.  
  413. /*------------------------------*/
  414. /*         undo_obj             */
  415. /*------------------------------*/
  416.      VOID
  417. undo_obj(tree, which, bit)
  418.      LONG     tree;
  419.      WORD     which;
  420.      UWORD     bit;
  421.      {
  422.      WORD     state;
  423.  
  424.      state = LWGET(OB_STATE(which));
  425.      LWSET(OB_STATE(which), state & ~bit);
  426.      }
  427.  
  428.  
  429. /*------------------------------*/
  430. /*         enab_obj             */
  431. /*------------------------------*/
  432.      WORD
  433. enab_obj(tree, which)
  434.      LONG     tree;
  435.      WORD     which;
  436.      {
  437.      undo_obj(tree, which, (UWORD) DISABLED);
  438.      return (TRUE);
  439.      }
  440.  
  441.  
  442. /*------------------------------*/
  443. /*         do_obj               */
  444. /*------------------------------*/
  445.      VOID
  446. do_obj(tree, which, bit)
  447.      LONG     tree;
  448.      WORD     which;
  449.      UWORD     bit;
  450.      {
  451.      WORD     state;
  452.  
  453.      state = LWGET(OB_STATE(which));
  454.      LWSET(OB_STATE(which), state | bit);
  455.      }
  456.  
  457.  
  458. /*------------------------------*/
  459. /*          disab_obj           */
  460. /*------------------------------*/
  461.      WORD
  462. disab_obj(tree, which)
  463.      LONG     tree;
  464.      WORD     which;
  465.      {
  466.      do_obj(tree, which, (UWORD) DISABLED);
  467.      return (TRUE);
  468.      }
  469.  
  470.  
  471. /*------------------------------*/
  472. /*         set_menu             */
  473. /*------------------------------*/
  474.      VOID
  475. set_menu(tree, change)               /* change[0] TRUE selects all entries*/
  476.      LONG     tree;                  /* FALSE deselects all.  Change list */
  477.      WORD     *change;               /* of items is then toggled.         */
  478.      {
  479.      WORD     dflt, screen, drop, obj;
  480.  
  481.      dflt = *change++;                       /* What is default?          */
  482.      screen = LWGET(OB_TAIL(ROOT));          /* Get SCREEN                */
  483.      drop = LWGET(OB_HEAD(screen));          /* Get DESK drop-down        */
  484.                                              /* and skip it               */
  485.      for (; (drop = LWGET(OB_NEXT(drop))) != screen; )
  486.           {
  487.           obj = LWGET(OB_HEAD(drop));
  488.           if (obj != NIL)
  489.           if (dflt)
  490.                map_tree(tree, obj, drop, enab_obj);
  491.           else
  492.                map_tree(tree, obj, drop, disab_obj);
  493.           }
  494.  
  495.      for (; *change; change++)
  496.           if (dflt)
  497.                disab_obj(tree, *change);
  498.           else
  499.                enab_obj(tree, *change);
  500.      }
  501.  
  502.  
  503. >>>>>>>>>>>>>>>>>>>>> Definitions used in this article <<<<<<<<<<<<<<<<<<<<<<
  504.  
  505. #define ROOT 0
  506.  
  507. #define G_IBOX    25
  508. #define G_STRING  28
  509. #define G_TITLE   32
  510.  
  511. #define R_TREE     0
  512.  
  513. #define MN_SELECTED 10
  514.  
  515. #define CHECKED   0x4
  516. #define DISABLED  0x8
  517.  
  518. #define OB_NEXT(x)   (tree + (x) * sizeof(OBJECT) + 0)
  519. #define OB_HEAD(x)   (tree + (x) * sizeof(OBJECT) + 2)
  520. #define OB_TAIL(x)   (tree + (x) * sizeof(OBJECT) + 4)
  521. #define OB_TYPE(x)   (tree + (x) * sizeof(OBJECT) + 6)
  522. #define OB_FLAGS(x)  (tree + (x) * sizeof(OBJECT) + 8)
  523. #define OB_STATE(x)  (tree + (x) * sizeof(OBJECT) + 10)
  524. #define OB_SPEC(x)   (tree + (x) * sizeof(OBJECT) + 12)
  525. #define OB_X(x)      (tree + (x) * sizeof(OBJECT) + 16)
  526. #define OB_Y(x)      (tree + (x) * sizeof(OBJECT) + 18)
  527. #define OB_WIDTH(x)  (tree + (x) * sizeof(OBJECT) + 20)
  528. #define OB_HEIGHT(x) (tree + (x) * sizeof(OBJECT) + 22)
  529.  
  530. #define M_OFF     256
  531. #define M_ON      257
  532.