The Menu Display Classes
                            

1. The Choice Display Class

2. The Hmenu and Vmenu Display Classes

---------------------------------------------------


1. The Choice Display Class


The choice class, like the radio class, is for boolean-valued slotfiller
variables whose value part contains one and only one 1.  The radio display may
perhaps be more appropriate when the choices are few or choosing is done
often, the choice display when there are many choices or choosing is seldom
done.

The choice representation has three parts, a title area on the left, a button
in the middle invoking a pulldown menu, and a value area on the right.  The
pulldown menu consists of label areas, which hold either the value of the
label attribute or, if that is null, the symbolic indices of the slotfiller.
The value area holds the label or symbolic index for the only slotfiller value
that is 1.

In the following example, notice that:
   when the label attribute is null, the symbolic index is used;
   when the label attribute is given a non-null value, neither the size of the
window nor the display in the value area changes;
   when the value part of c is respecified, the display in the value area is
changed but the size of the window remains unchanged;
   when naturalsize is specified, the value area is enlarged and all of the
label is shown.

     $load s
     scrs.SCREEN-34 12
     br{w;m}:{w has (`yx;scr-m+`yxs of w);}
     c(`fut `opt `ind;(1;0;0))
     `c has (`class;`choice; `shelltitle;'QList Products'; `title;'Type');
     show `c; br{`c;100}
     `label of `c
     `c has (`label;(`Future;`Option;`Index));
     (1c)(1;0;0)
     `c has `naturalsize; br{`c;100}

If instead of respecifying the value part of c you had made a choice from the
menu, the effect would have been the same.  The instant you pressed the left
mouse button with the pointer on the choice button, the display in the value
area, but not its size, would have changed.

Starting fresh and reversing the order of the last two statements, you see
that specifying naturalsize increases the window size but does not change the
display in the value area; that display is changed by a respecification of the
underlying variable (and could have been done by a choice from the menu):

     _ex free `c;
     c(`fut `opt `ind;(1;0;0))
     `c has (`class;`choice; `shelltitle;'QList Products'; `title;'Type');
     show `c; br{`c;100}
     `c has (`label;(`Future;`Option;`Index));
     `c has `naturalsize; br{`c;100}
     (1c)(1;0;0)

What these two examples really demonstrate, of course, is that you want to set
the label attribute before realizing or showing the object.

Now make a selection in two different ways.  For the first selection, place
the pointer on the choice button, press the left mouse button, move the
pointer down the menu that appears, and release the button when the pointer is
on Option or Index.  For the second, again place the pointer on the choice
button, then click the left mouse button, use the up and down arrow keys to
move around the menu, stop at Future, and press Enter.

So far we have been dealing only with appearances.  To provide a response to
any menu selection, you must set a callback function.

Selecting an item in the menu amounts to selecting a symbolic index of the
slotfiller and causes a value change in the underlying variable.  When an item
is selected, if the value at that symbolic index is 0, then it becomes 1 and
the value that was 1 becomes 0.  In addition, the menu disappears and the
selected symbolic index or label is displayed in the value area.

Because of this value change, any callback function defined for the variable
is called whenever a new item is selected; the path argument p is the symbolic
index to the changed value.  Although there are actually two value changes,
the callback function is called only once, and its path argument refers to the
value that changed from 0 to 1.

Set a callback function that just displays the arguments that are passed
to it:

     f{s;d;i;p;c;v}:{'-----------';(s;d;i;p;c;v)}
     `c has (`set;(f;'choice'));

Make some choices and watch the responses that appear in the A+ session log.

If you choose a menu item that already has the value 1, no callback occurs.
On the other hand, a callback always occurs for a change made by an A+
statement, and all respecified values are included in it.  Furthermore, the
index and path arguments reflect the statement executed, so they are different
for the third and fourth statements below although the actions called for by
these statements are identical:

     c(`fut `opt `ind;(0;1;0))
     (1c)[0 1](0;1)
     (1c)[1]<1
     (`optc)1
     _ex free `c;


2. The Hmenu and Vmenu Display Classes


The hmenu and vmenu display classes are designed to represent nested
slotfillers as cascaded menus.  A nested slotfiller is a slotfiller some of
whose values are also slotfillers, perhaps nested slotfillers.  There is no
limit to the level of nesting.

In contrast to a choice display, the top-level menu is continuously shown,
laid out horizontally in hmenu and vertically in vmenu, but without any
indication of the last selection.  All submenus are pulldown and are arranged
vertically in both classes.  The items shown in the top-level menu are the
symbolic indices of the slotfiller.  If a value is also a slotfiller, then its
symbolic indices are shown in the corresponding submenu.

If a callback function is set on the nested slotfiller, a callback occurs
whenever a menu or submenu item is selected.  When the function is called,
only pd is given in the second argument (data), where d is the underlying
slotfiller.

Incidentally, these classes can be used with non-nested slotfillers to provide
buttons that have no outlines unless pressed:

     c(`fut `opt `ind;(0;1;0))
     `c has (`set;(f;'hmenu'));
     show `c is `hmenu; br{`c;100}

Click on the symbolic indices in the hmenu window.  Shadowed outlines will
appear around them and callback output will appear in the session log.  Do the
same for this vmenu:

     `c has (`set;(f;'vmenu'));
     show `c is `vmenu; br{`c;100}

Here is a more complicated example, with irregular levels of nesting:

     _ex free `c;
     c(`file`edit`charformat;(
          (`new`open`close`save;(;;;
               (`save`save_as`save_all;(;;))));
          (`copy`cut`paste`undo;(;;;));
          (`font`size`style;(
               (`kaplgallant`courier`times`palatino`helvetica;(;;;;));
               (`10`12`14`17`24;(;;;;));
               (`regular`italic`bold;(;;))))))
     show `c is `hmenu; br{`c;150 100}

When you click on an item that has an arrowhead, its submenu appears.  When
you click on an item without an arrowhead, a selection takes place and any
displayed submenus vanish.  You can also drag the pointer, holding the mouse
button down.  In a horizontal menu, a submenu appears whenever you are in an
item that has one; in a vertical menu, a submenu appears whenever the pointer
is on an arrowhead.

If you place the pointer in the hmenu window, the left and right arrow keys
move you from item to item in the top-level menu and the down arrow key moves
you to a submenu when you are on an item that has one.  In the submenus, the
up and down arrow keys move you among items, the left arrow key moves you back
to the parent menu, and the right arrow key moves you to a submenu when you
are on an item that has one.  The Escape key aborts the operation.  The Enter
key makes a selection if you are on an item with no submenu, and otherwise
aborts the operation.

Try these keys.  Then set the callback function and see the results of your
selections.

     `c has (`set;(f;'hmenu'));

A vmenu is handled in the same way, except that the keys act the same for the
top-level menu as for the submenus, since it is also vertical.  Execute the
next two statements and then try some selections.

     show `c is `vmenu; br{`c;150 100}
     `c has (`set;(f;'vmenu'));

     _ex free `c;