{Begin SubSec Menus} {Title Menus} {Text {index *PRIMARY* Menus} A menu is basically a means of selecting from a list of items. The system provides common layout and interactive user selection mechanisms, then calls a user-supplied function when a selection has been confirmed. The two major constituents of a menu are a list of items and a "when selected function." The label that appears for each item is the item itself for non-lists, or its {lisp CAR} if the item is a list. In addition, there are a multitude of different formatting parameters for specifying font, size, and layout. When a menu is created, its unspecified fields are filled with defaults and its screen image is computed and saved. Menus can be either pop up or fixed. If fixed menus are used, the menu must be included in a window. {FnDef {Name MENU} {Args MENU POSITION RELEASECONTROLFLG {anonarg}} {Text This function provides menus that pop up when they are used. It displays {arg MENU} at {arg POSITION} (in screen coordinates) and waits for the user to select an item with a mouse key. Before any mouse key is pressed, the item the mouse is over is boxed. After any key is down, the selected menu item is video reversed. When all keys are released, {arg MENU}'s {lisp WHENSELECTEDFN} field is called with four arguments: (1) the item selected, (2) the menu, (3) the last mouse key released ({lisp LEFT}, {lisp MIDDLE}, or {lisp RIGHT}), and (4) the reverse list of superitems rolled through when selecting the item and {fn MENU} returns its value. If no item is selected, {fn MENU} returns {lisp NIL}. If {arg POSITION} is {lisp NIL}, the menu is brought up at the value from {arg MENU}'s {lisp MENUPOSITION} field, if it is a {lisp POSITION}, or at the current cursor position. The orientation of {arg MENU} with respect to the specified position is determined by its {lisp MENUOFFSET} field. If {arg RELEASECONTROLFLG} is {lisp NIL}, this process will retain control of the mouse. In this case, if the user lets the mouse key up outside of the menu, {lisp MENU} return {lisp NIL}. (Note: this is the standard way of allowing the user to indicate that they do not want to make the offered choice.) If {arg RELEASECONTROLFLG} is non-{lisp NIL}, this process will give up control of the mouse when it is outside of the menu so that other processes can be run. In this case, clicking outside the menu has no effect on the call to {lisp MENU}. If the menu is closed (for example, by right buttoning in it and selecting "{lisp Close}" from the window menu), {lisp MENU} returns {lisp NIL}. Programmers are encouraged to provide a menu item such as "cancel" or "abort" which gives users a positive way of indicating "no choice". Note: A "released" menu will stay visible (on top of the window stack) until it is closed or an item is selected. }} {FnDef {Name ADDMENU} {Args MENU WINDOW POSITION DONTOPENFLG} {Text This function provides menus that remain active in windows. {fn ADDMENU} displays {arg MENU} at {arg POSITION} (in window coordinates) in {arg WINDOW}. If the window is too small to display the entire menu, the window is made scrollable. When an item is selected, the value of the {lisp WHENSELECTEDFN} field of {arg MENU} is called with three arguments: (1) the item selected, (2) the menu, and (3) the mouse key that the item was selected with ({lisp LEFT}, {lisp MIDDLE}, or {lisp RIGHT}). More than one menu can be put in a window, but a menu can only be added to one window at a time. {fn ADDMENU} returns the window into which {arg MENU} is placed. If {arg WINDOW} is {lisp NIL}, a window is created at the position specified by {arg POSITION} (in screen coordinates) that is the size of {arg MENU}. If a window is created, it will be opened unless {arg DONTOPENFLG} is non-{lisp NIL}. If {arg POSITION} is {lisp NIL}, the menu is brought up at the value of {arg MENU}'s {lisp MENUPOSITION} field (in window coordinates), if it is a position, or else in the lower left corner of {arg WINDOW}. If both {arg WINDOW} and {arg POSITION} are {lisp NIL}, a window is created at the current cursor position. {index CURSORINFN (Window Property)} {index CURSORMOVEDFN (Window Property)} {index BUTTONEVENTFN (Window Property)} {index REPAINTFN (Window Property)} {index SCROLLFN (Window Property)} Warning: {fn ADDMENU} resets several of the window properties of {arg WINDOW}. The {lisp CURSORINFN}, {lisp CURSORMOVEDFN}, and {lisp BUTTONEVENTFN} window properties are replaced with {fn MENUBUTTONFN},{index MENUBUTTONFN Fn} so that {arg MENU} will be active. {fn MENUREPAINTFN} is added to the {lisp REPAINTFN} window property to update the menu image if the window is redisplayed. The {lisp SCROLLFN} window property is changed to {fn SCROLLBYREPAINTFN} if the window is too small for the menu, to make the window scroll. }} {FnDef {Name DELETEMENU} {Args MENU CLOSEFLG FROMWINDOW} {Text This function removes {arg MENU} from the window {arg FROMWINDOW}. If {arg MENU} is the only menu in the window and {arg CLOSEFLG} is non-{lisp NIL}, its window will be closed (by {fn CLOSEW}). If {arg FROMWINDOW} is {lisp NIL}, the list of currently open windows is searched for one that contains {arg MENU}. If none is found, {fn DELETEMENU} does nothing. }} {note examples!! (with figures if possible)} {Begin SubSec Menu Fields} {Title Menu Fields} {Text A menu is a datatype with the following fields: {Def {Type (Menu Field)} {Name ITEMS} {Text The list of items to appear in the menu. If an item is a list, its {lisp CAR} will appear in the menu. If the item (or its {lisp CAR}) is a bitmap, the bitmap will be displayed in the menu. The default selection functions interpret each item as a list of three elements: a label, a form whose value is returned upon selection, and a help string that is printed in the prompt window when the user presses a mouse key with the cursor pointing to this item. The default subitem function interprets the fourth element of the list. If it is a list whose {lisp CAR} is the litatom {lisp SUBITEMS} {index SUBITEMS atom}, the {lisp CDR} is taken as a list of subitems. }} {Def {Type (Menu Field)} {Name SUBITEMFN} {Text A function to be called to determine if an item has any subitems. If an item has subitems and the user rolls the cursor out the right of that item, a submenu with that item's subitems in it pops up. If the user selects one of the items from the submenu, the selected subitem is handled as if it were selected from the main menu. If the user rolls out of the submenu to the left, the submenu is taken down and selection resumes from the main menu. An item with subitems is marked in the menu by a grey, right pointing triangle following the label. The function is called with two arguments: (1) the menu and (2) the item. It should return a list of the subitems of this item if any. (Note: it is called twice to compute the menu image and each time the user rolls out of the item box so it should be moderately efficient. The default {lisp SUBITEMFN}, {fn DEFAULTSUBITEMFN},{index DEFAULTSUBITEMFN Fn} checks to see if the item is a list whose fourth element is a list whose {fn CAR} is the litatom {index SUBITEMS Litatom}{lisp SUBITEMS} and if so, returns the {fn CDR} of it. For example: {lispcode (create MENU ITEMS _ '(AAAA (BBBB 'BBBB "help string for BBBB" (SUBITEMS BBBB1 BBBB2 BBBB3))))} will create a menu with items {lisp A} and {lisp B} in which {lisp B} will have subitems {lisp B1}, {lisp B2} and {lisp B3}. The following picture below shows this menu as it first appears: .@@@@B!H$H$H$ DH$TH$H$ DH$ The following picture shows the submenu, with the item {lisp BBBB3} selected by the cursor ( ): [2  ~? A A ~? A A A ~? @ @ @ @ B! ~? A H$ A H$ ~? A A A ~? p8x _p8^}n~}~p8}~}~}n`` }} {Def {Type (Menu Field)} {Name WHENSELECTEDFN} {Text A function to be called when an item is selected. The function is called with three arguments: (1) the item selected, (2) the menu, and (3) the mouse key that the item was selected with ({lisp LEFT}, {lisp MIDDLE}, or {lisp RIGHT}). The default function {fn DEFAULTWHENSELECTEDFN}{index DEFAULTWHENSELECTEDFN Fn} evaluates and returns the value of the second element of the item if the item is a list of at least length 2. If the item is not a list of at least length 2, {fn DEFAULTWHENSELECTEDFN} returns the item. Note: If the menu is added to a window with {fn ADDMENU}, the default {lisp WHENSELECTEDFN} is {fn BACKGROUNDWHENSELECTEDFN},{index BACKGROUNDWHENSELECTEDFN Fn} which is the same as {fn DEFAULTWHENSELECTEDFN} except that {fn EVAL.AS.PROCESS} ({PageRef Fn EVAL.AS.PROCESS}) is used to evaluate the second element of the item, instead of tying up the mouse process. }} {Def {Type (Menu Field)} {Name WHENHELDFN} {Text The function which is called when the user has held a mouse key on an item for {var MENUHELDWAIT}{index MENUHELDWAIT Var} milliseconds (initially 1200). The function is called with three arguments: (1) the item selected, (2) the menu, and (3) the mouse key that the item was selected with ({lisp LEFT}, {lisp MIDDLE}, or {lisp RIGHT}). {lisp WHENHELDFN} is intended for prompting users. The default is {fn DEFAULTMENUHELDFN}{index DEFAULTMENUHELDFN Fn} which prints (in the prompt window) the third element of the item or, if there is not a third element, the string "This item will be selected when the button is released." }} {Def {Type (Menu Field)} {Name WHENUNHELDFN} {Text If {lisp WHENHELDFN} was called, {lisp WHENUNHELDFN} will be called: (1) when the cursor leaves the item, (2) when a mouse key is released, or (3) when another key is pressed. The function is called with the same three argument values used to call {lisp WHENHELDFN}. The default {lisp WHENUNHELDFN} is the function {fn CLRPROMPT} ({PageRef Fn CLRPROMPT}), which just clears the prompt window. }} {Def {Type (Menu Field)} {Name MENUPOSITION} {Text The position of the menu to be used if the call to {fn MENU} or {fn ADDMENU} does not specify a position. For popup menus, this is in screen coordinates. For fixed menus, it is in the coordinates of the window the menu is in. The point within the menu image that is placed at this position is determined by {lisp MENUOFFSET}. If {lisp MENUPOSITION} is {lisp NIL}, the menu will be brought up at the cursor position.{note awk.} }} {Def {Type (Menu Field)} {Name MENUOFFSET} {Text The position in the menu image that is to be located at {lisp MENUPOSITION}. The default offset is (0,0). For example, to bring up a menu with the cursor over a particular menu item, set its {lisp MENUOFFSET} to a position within that item and set its {lisp MENUPOSITION} to {lisp NIL}.{note awk.} }} {Def {Type (Menu Field)} {Name MENUFONT} {Text The font in which the items will be appear in the menu. Default is the value of {var MENUFONT}.{index MENUFONT Var} }} {Def {Type (Menu Field)} {Name TITLE} {Text If non-{lisp NIL}, the value of this field will appear as a title in a line above the menu. }} {Def {Type (Menu Field)} {Name MENUTITLEFONT} {Text The font in which the title of the menu will be appear. If this is {lisp NIL}, the title will be in the same font as window titles. If it is {lisp T}, it will be in the same font as the menu items. }} {Def {Type (Menu Field)} {Name CENTERFLG} {Text If non-{lisp NIL}, the menu items are centered; otherwise they are left-justified. }} {Def {Type (Menu Field)} {Name MENUROWS}} {Def {Type (Menu Field)} {Name MENUCOLUMNS} {Text These fields control the shape of the menu in terms of rows and columns. If {lisp MENUROWS} is given, the menu will have that number of rows. If {lisp MENUCOLUMNS} is given, the menu will have that number of columns. If only one is given, the other one will be calculated to generate the minimal rectangular menu. (Normally only one of {lisp MENUROWS} or {lisp MENUCOLUMNS} is given.) If neither is given, the items will be in one column. }} {Def {Type (Menu Field)} {Name ITEMHEIGHT} {Text The height of each item box in the menu. If not specified, it will be the maximum of the height of the {lisp MENUFONT} and the heights of any bitmaps appearing as labels. }} {Def {Type (Menu Field)} {Name ITEMWIDTH} {Text The width of each item box in the menu. If not specified, it will be the width of the largest item in the menu. }} {Def {Type (Menu Field)} {Name MENUBORDERSIZE} {Text The size of the border around each item box. If not specified, 0 (no border) is used. }} {Def {Type (Menu Field)} {Name MENUOUTLINESIZE} {Text The size of the outline around the entire menu. If not specified, a maximum of 1 and the {lisp MENUBORDERSIZE} is used. }} {Def {Type (Menu Field)} {Name CHANGEOFFSETFLG} {Text (popup menus only) If {lisp CHANGEOFFSETFLG} is non-{lisp NIL}, the position of the menu offset is set each time a selection is confirmed so that the menu will come up next time in the same position relative to the cursor. This will cause the menu to reappear in the same place on the screen if the cursor has not moved since the last selection. This is implemented by changing the {lisp MENUOFFSET} field on each use. If {lisp CHANGEOFFSETFLG} is the atom {lisp X} or the atom {lisp Y}, only the X or the Y coordinate of the {lisp MENUOFFSET} field will be changed. For example, by setting the {lisp MENUOFFSET} position to (-1,0) and setting {lisp CHANGEOFFSETFLG} to {lisp Y}, the menu will pop up so that the cursor is just to the left of the last item selected. This is the setting of the window command menus. }} The following fields are read only. {Def {Type (Menu Field)} {Name IMAGEHEIGHT} {Text Returns the height of the entire menu. }} {Def {Type (Menu Field)} {Name IMAGEWIDTH} {Text Returns the width of the entire menu. }} }{End SubSec Menu Fields} {Begin SubSec Miscellaneous Menu Functions} {Title Miscellaneous Menu Functions} {Text {FnDef {Name MAXMENUITEMWIDTH} {Args MENU} {Text Returns the width of the largest menu item label in the menu {arg MENU}. }} {FnDef {Name MAXMENUITEMHEIGHT} {Args MENU} {Text Returns the height of the largest menu item label in the menu {arg MENU}. }} {FnDef {Name MENUREGION} {Args MENU} {Text Returns the region covered by the image of {arg MENU} in its window. }} {FnDef {Name WFROMMENU} {Args MENU} {Text Returns the window {arg MENU} is located in, if it is in one; {lisp NIL} otherwise. }} {FnDef {Name DOSELECTEDITEM} {Args MENU ITEM BUTTON} {Text Calls {arg MENU}'s {lisp WHENSELECTEDFN} on {arg ITEM} and {arg BUTTON}. It provides a programmatic way of making a selection. It does not change the display. }} {FnDef {Name MENUITEMREGION} {Args ITEM MENU} {Text Returns the region occupied by {arg ITEM} in {arg MENU}. }} {FnDef {Name SHADEITEM} {Args ITEM MENU SHADE DS/W} {Text Shades the region occupied by {arg ITEM} in {arg MENU}. If {arg DS/W} is a display stream or a window, it is assumed to be where {arg MENU} is displayed. Otherwise, {fn WFROMMENU} is called to locate the window {arg MENU} is in. Shading is persistent, and is reapplied when the window the menu is in gets redisplayed. To unshade an item, call with a {arg SHADE} of 0. }} {FnDef {Name PUTMENUPROP} {Args MENU PROPERTY VALUE} {Text Stores the property {arg PROPERTY} with the value {arg VALUE} on a property list in the menu {arg MENU}. The user can use this property list for associating arbitrary data with a menu object. }} {FnDef {Name GETMENUPROP} {Args MENU PROPERTY} {Text Returns the value of the {arg PROPERTY} property of the menu {arg MENU}. }} }{End SubSec Miscellaneous Menu Functions} {Begin SubSec Examples of Menu Use} {Title Examples of Menu Use} {Text {Begin labeledlist Examples of Menu Use} {Label Example:} {Text A simple menu: {lispcode (MENU (create MENU ITEMS _ '((YES T) (NO (QUOTE NIL))) ))} Creates a menu with items {lisp YES} and {lisp NO} in a single vertical column: O∈‚"CD HHHH C If {lisp YES} is selected, {lisp T} will be returned. Otherwise, {lisp NIL} will be returned. } {Label Example:} {Text A simple menu, with centering: {lispcode (MENU (create MENU TITLE _ "Foo?" ITEMS _ '((YES T "Adds the Foo feature.") (NO 'NO "Removes the Foo feature.")) CENTERFLG _ T))} Creates a menu with a title {lisp Foo?} and items {lisp YES} and {lisp NO} centered in a single vertical column: #n6۾۾O∈‚"<BD$$ B< The strings following the {lisp YES} and {lisp NO} are help strings and will be printed if the cursor remains over one of the items for a period of time. This menu differs from the one above in that it distinquishes the {lisp NO} case from the case where the user clicked outside of the menu. If the user clicks outside of the menu, {lisp NIL} is returned. } {Label Example:} {Text A multi-column menu: {LispCode (create MENU ITEMS _ '(1 2 3 4 5 6 7 8 9 * 0 #) CENTERFLG _ T MENUCOLUMNS _ 3 MENUFONT _ (FONTCREATE 'MODERN 10 'BOLD) ITEMHEIGHT _ 15 ITEMWIDTH _ 15 CHANGEOFFSETFLG _ T)} Creates a touch-tone-phone number pad with the items in 15 by 15 boxes printed in Modern 10 bold font: />```€``€`€`p€`€0`€00`€``€`€`€`@b`b`⁰`€``   If used in pop up mode, its first use will have the cursor in the middle. Subsequent use will have the cursor in the same relative location as the previous selection. } {Label Example:} {Text A program using a previously-saved menu: {LispCode (SELECTQ [MENU (COND ((type? MENU FOOMENU) {it (* use previously computed menu.)} FOOMENU) (T {it (* create and save the menu)} (SETQ FOOMENU (create MENU ITEMS _ '((A 'A-SELECTED "prompt string for A") (B 'B-SELECTED "prompt string for B"] (A-SELECTED {it (* if A is selected)} (DOATHING)) (B-SELECTED {it (* if B is selected)} (DOBTHING)) (PROGN {it (* user selected outside the menu)} NIL)))} This expression displays a pop up menu with two items, {lisp A} and {lisp B}, and waits for the user to select one. If {lisp A} is selected, {lisp DOATHING} is called. If {lisp B} is selected, {lisp DOBTHING} is called. If neither of these is selected, the form returns {lisp NIL}. The purpose of this example is to show some good practices to follow when using menus. First, the menu is only created once, and saved in the variable {lisp FOOMENU}. This is more efficient if the menu is used more than once. Second, all of the information about the menu is kept in one place, which makes it easy to understand and edit. Third, the forms evaluated as a result of selecting something from the menu are part of the code and hence will be known to masterscope (as opposed to the situation if the forms were stored as part of the items). Fourth, the items in the menu have help strings for the user. Finally, the code is commented (always worth the trouble). } {End labeledlist Examples of Menu Use} }{End SubSec Examples of Menu Use} }{End SubSec Menus} ?1(DEFAULTFONT 1 (GACHA 10) (GACHA 8) (TERMINAL 8))  BMOBJ.GETFN2^* BMOBJ.GETFN2b BMOBJ.GETFN2r BMOBJ.GETFN2 BMOBJ.GETFN2~ BMOBJ.GETFN2rP z