home *** CD-ROM | disk | FTP | other *** search
- /**
- *
- * Name MNREAD - Read from any menu using a highlight
- * bar, given a starting row and column.
- *
- * Synopsis ret = mnread (pmenu, srow, scol, prow, pcol,
- * pch, pscan, option);
- *
- * int ret WN_NO_ERROR (0) if selection was
- * without error, otherwise ret is
- * the MN/WN error code.
- * BMENU *pmenu Pointer to menu to read from.
- * int srow, Starting row and column of item to
- * scol highlight first.
- * int *prow, Pointers to returned row and column
- * *pcol of highlight bar when a transmit
- * key is pressed.
- * int *pch, Pointers to returned character code
- * *pscan, and scan code of key pressed that
- * terminated MNREAD.
- * int option A bitwise OR-ing of the following
- * values:
- *
- * MN_USE_DESCRIPTION
- * Display Lotus-style descriptions, if any,
- * for highlighted items.
- * MN_ALL_TRANSMIT
- * Transmit on any key pressed,
- * whether it is a transmit key
- * or not.
- * MN_DESTROY
- * Both remove the menu from
- * the screen and destroy the
- * menu's data structures upon
- * termination of MNREAD.
- * MN_HOLD_BEEP
- * Don't beep if the key pressed
- * is a transmit key, even if
- * the key's action specifies a
- * beep.
- * MN_KEEP_DESCRIPTION
- * Leave the "Lotus" description
- * on the menu on termination.
- * MN_KEEP_HIGHLIGHT
- * Leave the highlight bar on
- * the menu on termination.
- * MN_REMOVE
- * Remove the menu from the
- * display screen when MNREAD
- * terminates.
- * MN_UNKNOWN_BEEP
- * Beep when the user types an
- * unknown key.
- * MN_UNKNOWN_TRANSMIT
- * Transmit when user types an
- * unknown key.
- * MN_PREV_BAR
- * Use previous highlight bar. This effect
- * may be modified by MN_SHOW_BAR.
- * MN_SHOW_BAR
- * If MN_PREV_BAR is used, force display of
- * highlight bar even if it was not shown
- * formerly. (Error WN_NONE_SELECT if no
- * selectable item can be found.)
- * MN_HIDE_BAR
- * Highlight no item at first. Overrides
- * MN_SHOW_BAR.
- *
- * Description MNREAD accepts keystrokes from the user and moves
- * a highlight bar on the specified menu.
- *
- * An error code is returned if:
- * There are no selectable items on the menu.
- * The menu is not displayed (via MNDSPLAY).
- * WNREMOVE fails (option includes MN_REMOVE
- * or MN_DESTROY).
- * MNDSTROY fails (option includes MN_DESTROY).
- * The key pressed is unknown (and option includes
- * MN_UNKNOWN_TRANSMIT).
- *
- * Returns ret WN_NO_ERROR (if no error), or a MN/WN error
- * code if failure.
- * *prow The row and column where the highlight bar was
- * *pcol when a transmit key was pressed, or the
- * item most recently highlighted if no item
- * is currently highlighted.
- * *pch The character code and scan code of the
- * *pscan last key pressed, or 0xff if mouse event
- * caused transmission.
- * b_mnmoevent
- * Most recent mouse event, or OL if none.
- * b_mnmovert, b_mnmohoriz
- * Row and column where most recent mouse event
- * took place, or 0xffff if none.
- *
- * Version 6.00 (C)Copyright Blaise Computing Inc. 1987-1989
- *
- **/
-
- #include <bkeybrd.h>
- #include <bmenu.h>
- #include <bmouse.h>
-
- /* Most recent mouse menu event. */
- unsigned long b_mnmoevent; /* Event, or OL if none. */
- unsigned b_mnmovert; /* Row and column where event took*/
- unsigned b_mnmohoriz; /* place, or 0xffff if none. */
-
-
- typedef struct /* CLEANUP_ITEMS: Items to */
- { /* restore on exit. */
- /* */
- int MOCATCH_was_off; /* Must remove MOCATCH. */
- unsigned delayed_flag; /* Window was previously delayed. */
- } CLEANUP_ITEMS;
-
- typedef struct /* USER_RESPONSE: Mouse or */
- { /* keyboard event. */
-
- enum {MOUSE, KEYSTROKE, INTERNAL_ERROR} mouse_or_key;
- union
- {
- struct /* Details of mouse event: */
- { /* */
- unsigned long event; /* Actual mouse event. */
- unsigned vert,horiz; /* Mouse cursor location */
- /* (in characters). */
- const BMNMOUSE *pmouse; /* Mouse event node. */
- BITEM *pitem; /* Menu item where mouse */
- } mouse; /* event took place. */
- struct
- { /* Details of keystroke: */
- KEY_SEQUENCE kseq; /* Character and key codes*/
- const BKEYMAP *pkey; /* Key map entry. */
- } keystroke;
- } data;
- } USER_RESPONSE;
-
- #define TRUE 1
- #define FALSE 0
-
- /* Internal functions. */
-
- static void clean_up(const BMENU *,const CLEANUP_ITEMS *);
- static int mnchkxit(const BKEYMAP *,const BMNMOUSE *,int);
- static int in_window(const BWINDOW *,unsigned,unsigned);
- static BITEM *pfind_item(const BMENU *,unsigned,unsigned);
- static const BMNMOUSE *pfind_mouse_event(const BMNMOUSE *,unsigned long,int *);
- static int wait_operator(const BMENU *,USER_RESPONSE *,
- const BKEYMAP *,int);
- static int interp_resp(BMENU *,const USER_RESPONSE *,int *,BITEM **,
- int *,int *);
- static int jump(BWINDOW *,int);
-
- int mnread (pmenu, srow, scol, prow, pcol, pch, pscan, option)
- BMENU *pmenu;
- int srow, scol;
- int *prow, *pcol;
- int *pch, *pscan;
- int option;
- {
- int code, /* Returned error code from MNFINDSL*/
- done = FALSE, /* Becomes true when MNREAD should */
- /* exit at next opportunity. */
- result, /* Return code from interp_resp(). */
- shouldbeep = FALSE;/* Whether we should beep or not. */
- BITEM *pitem; /* Pointer to current menu item. */
- const BKEYMAP *pkey; /* Pointer to current key found. */
- USER_RESPONSE resp;
- CLEANUP_ITEMS dirt;
-
- /* Validate menu data structures. */
- if (mnvalmnu (pmenu) == NIL)
- wnretern (MN_BAD_MENU);
-
- /* Exit if menu not displayed. */
- if ( pmenu->pwin->where_shown.dev != SC_MONO
- && pmenu->pwin->where_shown.dev != SC_COLOR)
- wnretern (WN_NOT_SHOWN);
-
- /* Exit if window is covered or frozen. */
- if (pmenu->pwin->internals.frozen)
- wnretern (WN_COVERED);
-
- /* Disable keys which do not point either at items */
- /* or at (-1,-1). */
- if (mndisabl (pmenu) == NIL)
- return (b_wnerr);
-
- /* Check to make sure there is an exit route. */
- if (mnchkxit(pmenu->pkeys,pmenu->pmouse,option))
- return (b_wnerr);
-
- /* Set pitem to highlight bar location (and set */
- /* previous location if no bar shown). */
-
- if (option & MN_PREV_BAR)
- {
- pitem = pmenu->pbar_item; /* Use former location */
- /* or none if no bar shown. */
- if ( (pitem == NIL)
- && (option & MN_SHOW_BAR)) /* We require a bar, */
- pitem = pmenu->pbar_prev; /* so try harder. */
- }
- else
- { /* If not using previous, */
- option |= MN_SHOW_BAR; /* then we must show a bar. */
- pitem = NIL;
- }
-
- if ( (pitem == NIL)
- && (option & MN_SHOW_BAR)) /* We still need a bar. */
- {
- /* Find the first selectable menu item. */
- pitem = mnfindsl(pmenu,NIL,srow,scol,&code);
- if (pitem == NIL)
- {
- if ( code == WN_NO_ERROR /* Error if none selectable */
- && !(option & MN_HIDE_BAR)) /* unless none wanted. */
- wnretern (MN_NONE_SELECT);
- else
- return (b_wnerr); /* Internal error. */
- }
- }
-
- if ( (option & MN_HIDE_BAR) /* Must hide the bar and */
- && (pitem != NIL)) /* there is a bar to hide. */
- {
- pmenu->pbar_prev = pitem; /* Save previous bar site. */
- pitem = NIL; /* Show no bar. */
- }
-
- /* Point pkey at menu's keylist. */
- pkey = pmenu->pkeys;
-
- /* Save the starting row and column coordinates. */
- if (pitem)
- {
- *prow = pitem->row;
- *pcol = pitem->col;
- }
-
- /* Save items that may need restoration on exit. */
- dirt.MOCATCH_was_off = !b_mocatch;
- dirt.delayed_flag = pmenu->pwin->options.delayed;
-
- /* Miscellaneous setup. */
- pmenu->pwin->options.delayed = 0; /* Allow immediate output. */
-
- /* Check whether we should always transmit. */
- if (option & MN_ALL_TRANSMIT)
- done = TRUE;
-
- do
- {
- /* Show highlight bar and (perhaps) description. */
- if (NIL == mnhilit0(pmenu,pitem,
- (option & MN_USE_DESCRIPTION) | WN_UPDATE | MN_HIGHLIGHT))
- {
- clean_up(pmenu,&dirt);
- return b_wnerr;
- }
-
- /* Do a beep if the last keycode told us to do so.... */
- if (shouldbeep)
- {
- scttywrt ('\a', 0);
- shouldbeep = FALSE;
- }
-
- /* Get a keystroke or mouse event from the user. */
-
- if (WN_NO_ERROR != wait_operator(pmenu,&resp,pkey,option))
- {
- clean_up(pmenu,&dirt);
- return b_wnerr;
- }
- switch (resp.mouse_or_key)
- {
- case KEYSTROKE:
- *pch = resp.data.keystroke.kseq.character_code;
- *pscan = resp.data.keystroke.kseq.key_code;
- if (resp.data.keystroke.pkey != NIL)
- pkey = resp.data.keystroke.pkey;
- b_mnmoevent = 0L;
- b_mnmovert = 0xffff;
- b_mnmohoriz = 0xffff;
- break;
-
- case MOUSE:
- *pch = 0xff;
- *pscan = 0xff;
- b_mnmoevent = resp.data.mouse.event;
- b_mnmovert = resp.data.mouse.vert;
- b_mnmohoriz = resp.data.mouse.horiz;
- break;
- }
-
- /* Interpret user response in terms of menu results. */
-
- switch (result = interp_resp(pmenu,&resp,&option,&pitem,
- &shouldbeep,&done))
- {
- case WN_NO_ERROR:
- case MN_READ_AB:
- case MN_XMIT_NOBAR:
- case MN_UNKNOWN_AB:
- break;
-
- default:
- clean_up(pmenu,&dirt);
- return result; /* Internal error. */
- }
-
- } while (!done);
-
- clean_up(pmenu,&dirt);
-
- /* Show highlight bar and (perhaps) description. */
- if (NIL == mnhilit0(pmenu,pitem,
- (option & MN_USE_DESCRIPTION) | WN_UPDATE | MN_HIGHLIGHT))
- return b_wnerr;
-
- /* Check whether we should beep. */
- if (shouldbeep && ( !(option & MN_HOLD_BEEP)))
- scttywrt ('\a', 0);
-
- /* Perhaps remove highlight bar and description. */
- if (NIL == mnhilit0(pmenu,pitem,
- WN_UPDATE
- | ((option & MN_KEEP_HIGHLIGHT) ? MN_HIGHLIGHT : MN_UNHIGHLIGHT)
- | ((option & MN_KEEP_DESCRIPTION) ? MN_USE_DESCRIPTION : 0)))
- return b_wnerr;
-
- /* Return the final row and column of the highlight */
- /* bar. */
- if (pitem == NIL)
- pitem = pmenu->pbar_prev;
- if (pitem == NIL)
- {
- *pcol = -1;
- *prow = -1;
- }
- else
- {
- *pcol = pitem->col;
- *prow = pitem->row;
- }
-
- /* Remove menu's window from display if told to. */
- if (option & MN_REMOVE)
- if (wnremove (pmenu->pwin) == NIL)
- return (b_wnerr);
-
- /* Destroy menu's data structures if told to do so. */
- if ((option & MN_DESTROY) == MN_DESTROY)
- if (mndstroy (pmenu) != WN_NO_ERROR)
- return (b_wnerr);
-
- return (result);
- }
-
- /**
- *
- * Name clean_up -- Restore miscellaneous aspects of
- * environment.
- *
- * Synopsis clean_up(pmenu,pdirt);
- *
- * const CLEANUP_ITEMS *pmenu
- * Address of the menu structure.
- * const CLEANUP_ITEMS *pdirt
- * Address of record structure listing
- * items to restore on exit from
- * MNREAD.
- *
- * Description This function restores miscellaneous items:
- * specifically, if MOCATCH was not installed before MNREAD
- * was invoked, this function removes it; also restores the
- * menu's window's "delayed" state.
- *
- * Returns b_mocatch Restored to value before MNREAD was
- * called.
- *
- **/
-
- static void clean_up(pmenu,pdirt)
- const BMENU *pmenu;
- const CLEANUP_ITEMS *pdirt;
- {
- if (pdirt->MOCATCH_was_off)
- mopreclk(MO_REMOVE);
- pmenu->pwin->options.delayed = pdirt->delayed_flag;
- }
-
-
- /**
- *
- * Name mnchkxit -- Check whether there is any way to
- * exit the menu.
- *
- * Synopsis ret = mnchkxit(pkey,pmouse,option);
- *
- * int ret Zero if there is an exit route (i.e. no
- * error);
- * MN_BAD_KEY if a bad keymap
- * entry encountered;
- * MN_BAD_MOUSE if a bad mouse
- * entry encountered;
- * MN_NO_EXIT if there is no exit key.
- * const BKEYMAP *pkey
- * Pointer to the start of the menu's
- * key list.
- * const BMNMOUSE *pmouse
- * Address of first item in list of menu's
- * mouse actions.
- * int option MNREAD options including the following
- * bits:
- *
- * MN_KBIGNORE
- * MN_ALL_TRANSMIT
- * MN_UNKNOWN_TRANSMIT
- *
- * Description MNCHKXIT checks the option value and the menu's key and
- * mouse lists to see if there is any way for the menu to
- * be exited.
- *
- * Returns ret Zero if there is an exit route (i.e. no
- * error);
- * MN_BAD_KEY if a bad keymap
- * entry encountered;
- * MN_BAD_MOUSE if a bad mouse
- * entry encountered;
- * MN_NO_EXIT if there is no exit key.
- *
- * b_wnerr Possible values:
- * (No change) Success.
- * MN_NO_EXIT No way to exit the
- * menu.
- * MN_BAD_KEY Bad keymap entry
- * encountered.
- * MN_BAD_MOUSE Bad mouse entry
- * encountered.
- **/
-
- static int mnchkxit(pkey,pmouse,option)
- const BKEYMAP *pkey;
- const BMNMOUSE *pmouse;
- int option;
- {
- if (option & (MN_ALL_TRANSMIT | MN_UNKNOWN_TRANSMIT))
- return 0;
-
- if (! (option & MN_KBIGNORE))
- {
- for (; pkey != NIL; pkey = pkey->next)
- {
- /* Check key signature. */
- if (pkey->signature != MN_KEY_SIGN)
- wnretern (MN_BAD_KEY);
-
- if ( !(pkey->action & (MN_DISABLE | MN_TEMP_DISABLE))
- && (pkey->action & (MN_TRANSMIT | MN_ABORT)))
- return (0);
- }
- }
-
- for (; pmouse != NIL; pmouse = pmouse->pnext)
- {
- /* Check mouse signature. */
- if (pmouse->signature != MN_MOU_SIGN)
- wnretern (MN_BAD_MOUSE);
-
- if ( !(pmouse->action & (MN_DISABLE | MN_TEMP_DISABLE))
- && (pmouse->action & (MN_TRANSMIT | MN_ABORT)))
- return (0);
- }
-
- wnretern (MN_NO_EXIT);
- }
-
- /**
- *
- * Name pfind_item -- Find menu item that covers a given
- * screen location.
- *
- * Synopsis pitem = pfind_item(pmenu,row,col)
- *
- * BITEM *pitem Address of resulting menu item node,
- * or NIL if error or if none found.
- * const BMENU *pmenu
- * Address of menu control structure.
- * int row,col Display location (relative to (0,0) at
- * upper left corner of display).
- *
- * Description This function finds a menu item (if any) that covers a
- * given display location.
- *
- * The result is meaningless if the menu is not displayed
- * or (row,col) is outside the viewport.
- *
- * Returns *pitem Address of resulting menu item node,
- * or NIL if error or if none found.
- * b_wnerr Unchanged if no error or if none found;
- * MN_BAD_ITEM if corrupted item list.
- *
- **/
-
- static BITEM *pfind_item(pmenu,row,col)
- const BMENU *pmenu;
- unsigned row,col;
- {
- BITEM *pitem;
-
- int target_row = row
- - pmenu->pwin->where_shown.corner.row
- + pmenu->pwin->data_origin.row;
- int target_col = col
- - pmenu->pwin->where_shown.corner.col
- + pmenu->pwin->data_origin.col;
-
- for (pitem = pmenu->pitems;
- pitem != NIL;
- pitem = pitem->next)
- {
- if (pitem->signature != MN_ITEM_SIGN)
- {
- wnreterr(MN_BAD_ITEM);
- }
- if ( pitem->row == target_row
- && pitem->col <= target_col
- && target_col < pitem->col + pitem->len)
- {
- return pitem;
- }
- }
-
- return NIL;
- }
-
- /**
- *
- * Name in_window -- Report whether window data area contains
- * a given display location.
- *
- * Synopsis contains = in_window(pwin,row,col);
- *
- * int contains Nonzero if window contains the
- * given location,
- * zero if not.
- * const BWINDOW *pwin
- * Address of window control structure.
- * int row,col Display location (relative to (0,0) at
- * upper left corner of display).
- *
- * Description This function tells whether a given display location
- * lies within a window's data area. The window must be
- * displayed.
- *
- * Returns contains Nonzero if window contains the
- * given location,
- * zero if not.
- *
- **/
-
- static int in_window(pwin,row,col)
- const BWINDOW *pwin;
- unsigned row,col;
- {
-
- /* Macros to return edge of data area (plus 1). */
-
- #define BOT_ROW_P1 (pwin->where_shown.corner.row + wnview_h(pwin))
- #define RT_COL_P1 (pwin->where_shown.corner.col + wnview_w(pwin))
-
- return ( pwin->where_shown.corner.row <= row
- && row < BOT_ROW_P1
- && pwin->where_shown.corner.col <= col
- && col < RT_COL_P1);
-
- #undef BOT_ROW_P1
- #undef RT_COL_P1
- }
-
- /**
- *
- * Name pfind_mouse_event -- Find mouse event in list.
- *
- * Synopsis pfound = pfind_mouse_event(pmouse,event,perror)
- *
- * const BMNMOUSE *pfound
- * Returned address of found mouse event
- * record.
- * const BMNMOUSE *pmouse
- * Address of first mouse node to check.
- * unsigned long event
- * Actual mouse event to search for.
- * int *perror Address into which to return success
- * code.
- *
- * Description This function searches for a matching mouse event
- * in a list of mouse events, taking into account
- * what aspects should be ignored.
- *
- * Returns pfound Address of found mouse event record,
- * or NIL if error or if none found.
- * *perror WN_NO_ERROR or MN_BAD_MOUSE.
- *
- **/
-
- static const BMNMOUSE *pfind_mouse_event(pmouse,event,perror)
- const BMNMOUSE *pmouse;
- unsigned long event;
- int *perror;
- {
- for ( ;
- pmouse != NIL;
- pmouse = pmouse->pnext)
- {
- if (pmouse->signature != MN_MOU_SIGN)
- {
- wnreterr(*perror = MN_BAD_MOUSE);
- }
- if ( 0 == (pmouse->action & (MN_DISABLE | MN_TEMP_DISABLE))
- && (pmouse->ignore | event) == (pmouse->ignore | pmouse->event))
- {
- *perror = WN_NO_ERROR;
- return pmouse;
- }
- }
- *perror = WN_NO_ERROR;
- return NIL;
- }
-
- /**
- *
- * Name wait_operator -- Wait for mouse or keyboard command
- * from operator.
- *
- * Synopsis ercode = wait_operator(pmenu,presp,pkey,option);
- *
- * int ercode Error code:
- * WN_NO_ERROR if okay;
- * other if internal error.
- * const BMENU *pmenu
- * Address of menu structure.
- * USER_RESPONSE *presp
- * Address of structure containing the
- * returned user response.
- * const BKEYMAP *pkey
- * Address of keymap entry for most
- * recent keystroke.
- * int option Option flag. Relevant bits:
- * MN_KBIGNORE
- * MN_KBDISCARD (both have same effect).
- *
- * Description This function polls the mouse and keyboard for a response
- * from the user.
- *
- * Mouse events are reported only if they are listed
- * in the menu's list of mouse events.
- *
- * Returns ercode Error code:
- * WN_NO_ERROR if okay;
- * other if internal error.
- * b_wnerr Unchanged if no error;
- * same as "ercode" if error detected.
- * *presp User response.
- *
- **/
-
- static int wait_operator(pmenu,presp,pkey,option)
- const BMENU *pmenu;
- USER_RESPONSE *presp;
- const BKEYMAP *pkey;
- int option;
- {
- unsigned long event;
- BITEM *pitem;
- unsigned vert,horiz;
- int ercode;
-
- const BMNMOUSE *pmouse;
-
- for (;;) /* Infinite loop: First poll mouse, then */
- { /* keyboard. Exit when anything happens. */
-
- /* Poll mouse history separately for each */
- /* listed mouse event. */
- for (pmouse = pmenu->pmouse;
- pmouse != NIL;
- pmouse = pmouse->pnext)
- {
- if (pmouse->signature != MN_MOU_SIGN)
- {
- wnretern(MN_BAD_MOUSE);
- }
-
- if ( 0 == (pmouse->action & (MN_DISABLE | MN_TEMP_DISABLE))
- && MO_OK == mocheck(pmouse->event,pmouse->ignore,
- MO_CLEAR,&event,&vert,&horiz)
- && event)
- {
- /* Analyze location of mouse event: whether on a */
- /* menu item and whether outside the menu. */
-
- vert >>= 3; /* Convert from pixels to characters. */
- horiz >>= 3;
-
- if (in_window(pmenu->pwin,vert,horiz))
- {
- if (NIL == (pitem = pfind_item(pmenu,vert,horiz)))
- event = (event | MN_OFF_ITEMS)
- & ~(unsigned long) (MN_ITEMS | MN_OUT_MENU);
- else
- event = (event | MN_ITEMS)
- & ~(unsigned long) (MN_OFF_ITEMS | MN_OUT_MENU);
- }
- else
- event = (event | MN_OUT_MENU)
- & ~(unsigned long) (MN_OFF_ITEMS | MN_ITEMS);
-
- /* Mouse event is now completely characterized, so */
- /* scan list of menu events for this menu. Ignore */
- /* event if not found in list. */
-
- if (NIL != (presp->data.mouse.pmouse
- = pfind_mouse_event(pmenu->pmouse,event,&ercode)))
- { /* Found mouse event. */
- presp->mouse_or_key = MOUSE;
- presp->data.mouse.event = event;
- presp->data.mouse.vert = vert;
- presp->data.mouse.horiz = horiz;
- presp->data.mouse.pitem = pitem;
- return ercode;
- }
- }
- }
-
- /* No relevant mouse event, so poll keyboard. */
-
- if (kbpoll(b_key_ctrl,pmenu,
- &presp->data.keystroke.kseq,
- KB_REMOVE_KEY))
- if (0 == (option & (MN_KBIGNORE | MN_KBDISCARD)))
- {
- presp->mouse_or_key = KEYSTROKE;
- presp->data.keystroke.pkey =
- mnmchkey(pmenu,pkey,
- presp->data.keystroke.kseq.character_code,
- presp->data.keystroke.kseq.key_code,
- &ercode);
- return ercode;
- }
- }
- }
-
- /**
- *
- * Name interp_resp -- Interpret user response and decide
- * actions to take.
- *
- * Synopsis ercode = interp_resp(pmenu,presp,poption,ppitem,
- * pshouldbeep,pdone);
- *
- * int ercode Error code:
- *
- * WN_NO_ERROR if okay;
- * MN_READ_AB if user requested abort;
- * MN_XMIT_NOBAR if user requested transmit while
- * no bar shown;
- * MN_UNKNOWN_AB if user pressed an unknown key
- * the MN_UNKNOWN_TRANSMIT option in *poption
- * was set;
- * other if internal error.
- *
- * BMENU *pmenu Address of menu structure.
- * const USER_RESPONSE *presp
- * Address of structure containing the
- * actual user response.
- * int *poption Address of option flag.
- * BITEM **ppitem Address of pointer to highlighted menu
- * item (*pitem == NIL if none).
- * int *pshouldbeep
- * Address of flag indicating whether
- * a beep was requested.
- * int *pdone Address of flag indicating whether
- * calling function should return without
- * further user input.
- *
- * Description This function interprets the user's response (in *presp)
- * and determines what action to take.
- *
- * Returns ercode Error code:
- *
- * WN_NO_ERROR if okay;
- * MN_READ_AB if user requested abort;
- * MN_XMIT_NOBAR if user requested transmit while
- * no bar shown;
- * MN_UNKNOWN_AB if user pressed an unknown key
- * the MN_UNKNOWN_TRANSMIT option in *poption
- * was set;
- * other if internal error.
- *
- * b_wnerr Unchanged if no error;
- * same as "ercode" if error detected.
- * *poption The MN_KB_DISCARD bit may be set or
- * cleared.
- * *ppitem Menu item to highlight (NIL if no
- * highlight bar).
- * *pshouldbeep TRUE if beep requested;
- * unchanged if no beep requested.
- * *pdone TRUE if caller should return;
- * unchanged if further input okay.
- *
- **/
-
- /* Macro to do a for loop which makes the variable */
- /* qitem take on all of the pointer values from */
- /* pitem to the end of the item list in the menu's */
- /* item list. ritem is initialized to be pitem. */
-
- #define FORALL(pitem) \
- for (qitem = pmenu->pitems, ritem = (pitem); \
- qitem != NIL; \
- qitem = qitem->next) \
- { \
- if (qitem->signature != MN_ITEM_SIGN) \
- wnretern (MN_BAD_ITEM);
-
- #define FOREND() }
-
- /* Macro which maximizes a "rangefunc". This is */
- /* used by MN_UP, DOWN, RIGHT, and LEFT to determine*/
- /* the correct place to move the highlight bar. */
- /* Arguments: */
- /* matchrc -- Either "row" or "col"; the */
- /* component of the item's */
- /* position which is supposed to */
- /* match that of the other item. */
- /* diffrc -- Either "row" or "col"; the */
- /* opposite of "matchrc". */
- /* size -- Either height (if matchrc is */
- /* "col") or width (if matchrc is*/
- /* "row) of menu's window data */
- /* area. */
- /* rangefunc- Either ULRANGE or DRRANGE. */
-
- #define IFMATCH(matchrc, diffrc, size, rangefunc, pitem) \
- if (( !(qitem->option & MN_PROTECT)) && \
- (qitem->matchrc == (pitem)->matchrc) && \
- (rangefunc ((pitem), qitem, diffrc, size) > \
- rangefunc ((pitem), ritem, diffrc, size)))
-
-
-
- #define DRRANGE(pitem, qitem, rowcol, size) \
- ((qitem->rowcol <= (pitem)->rowcol) \
- ? ((pitem)->rowcol - qitem->rowcol) & wrap_mask \
- : ((size - qitem->rowcol) + (pitem)->rowcol))
-
- #define ULRANGE(pitem, qitem, rowcol, size) \
- ((qitem->rowcol >= (pitem)->rowcol) \
- ? (qitem->rowcol - (pitem)->rowcol) & wrap_mask \
- : ((size - (pitem)->rowcol) + qitem->rowcol))
-
- /* BEYOND: Macro that maximizes a "beyondfunc": returns */
- /* nonzero value if *qitem is a better candidate than *ritem. */
- /* Use is similar to IFMATCH. */
- /* size - height or width of data area. */
- /* floor - preferred amount of motion (negative for upward */
- /* or leftward. */
-
- #define BEYOND(matchrc,diffrc,size,beyondfunc,pitem,floor) \
- ( (!(qitem->option & MN_PROTECT)) \
- && (qitem->matchrc == (pitem)->matchrc) \
- && (beyondfunc((pitem),qitem,diffrc,size,floor) > \
- beyondfunc((pitem),ritem,diffrc,size,floor)))
-
- #define DRBEYOND(pitem,qitem,rowcol,size,floor) \
- ( (qitem->rowcol >= (pitem)->rowcol + (floor)) \
- ? size - qitem->rowcol \
- : qitem->rowcol - size)
-
- #define ULBEYOND(pitem,qitem,rowcol,size,ceiling) \
- ( (qitem->rowcol <= (pitem)->rowcol + (ceiling)) \
- ? qitem->rowcol \
- : -1 - qitem->rowcol)
-
- /* Height of menu's data area. */
- #define H (pmenu->pwin->img.dim.h)
-
- /* Width of menu's data area. */
- #define W (pmenu->pwin->img.dim.w)
-
-
- static int interp_resp(pmenu,presp,poption,ppitem,
- pshouldbeep,pdone)
- BMENU *pmenu;
- const USER_RESPONSE *presp;
- int *poption;
- BITEM **ppitem;
- int *pshouldbeep,*pdone;
- {
- int code;
- BITEM *pitem,*qitem,*ritem;
- int result = WN_NO_ERROR;
- int action;
- int disp;
- int wrap_mask;
-
- pitem = *ppitem;
-
- /* Do operations that are different for mouse and */
- /* keystroke events: in particular, get action code*/
- switch (presp->mouse_or_key)
- {
- case KEYSTROKE:
- if (presp->data.keystroke.pkey != NIL)
- {
- action = presp->data.keystroke.pkey->action;
-
- if (MNMOVE(action) == MN_SELECT)
- {
- const BKEYMAP *pkey;
-
- /* Move highlight bar to specified row/column of a */
- /* menu item. */
- pkey = presp->data.keystroke.pkey;
- if ((qitem =
- mnmchitm (pmenu, pitem, pkey->row,
- pkey->col, 0, &code)) != NIL)
- pitem = qitem;
-
- else if (code != WN_NO_ERROR)
- {
- *pdone = TRUE;
- return (b_wnerr);
- }
- }
- }
- else /* Unknown (or disabled) key pressed. */
- {
- action = 0;
-
- /* Check whether we should beep when unknown key */
- /* pressed. */
- if (*poption & MN_UNKNOWN_BEEP)
- *pshouldbeep = TRUE;
-
- /* Check whether we should transmit when unknown */
- /* key pressed. */
- if (*poption & MN_UNKNOWN_TRANSMIT)
- {
- result = wnerror(MN_UNKNOWN_AB);
- *pdone = TRUE;
- }
- }
- break;
-
- case MOUSE:
- action = presp->data.mouse.pmouse->action;
- if (MNMOVE(action) == MN_SELECT)
- pitem = presp->data.mouse.pitem;
- break;
- }
-
- switch (MNMOVE(action))
- {
- case MN_UP:
- case MN_DOWN:
- case MN_RIGHT:
- case MN_LEFT:
- case MN_NEXT:
- case MN_PREVIOUS:
- case MN_PGDN:
- case MN_PGUP:
- case MN_PGRIGHT:
- case MN_PGLEFT:
- /* Handle relative movements specially: if bar */
- /* not shown, use previously highlighted item. */
- /* This has the effect of showing the bar unless */
- /* MN_HIDE_BAR is also specified in the action code.*/
- if (pitem == NIL)
- pitem = pmenu->pbar_prev;
- if (pitem != NIL)
- {
- /* wrap_mask is used by the DRRANGE and ULRANGE */
- /* macros for the MN_UP, MN_DOWN, MN_RIGHT, and */
- /* MN_LEFT motions. When MN_NOWRAP is specified, */
- /* then wrap_mask is 0, thus causing DRRANGE and */
- /* ULRANGE to return 0 for coordinates in the */
- /* opposite direction. */
- wrap_mask = ((action & MN_NOWRAP) ? 0 : ~0);
-
- switch (MNMOVE(action))
- {
- /* Move highlight bar up. Wrap to bottom if at top.*/
- case MN_UP:
- FORALL(pitem)
- IFMATCH (col, row, H, ULRANGE, pitem)
- ritem = qitem;
- FOREND ()
-
- pitem = ritem;
- break;
-
-
- case MN_DOWN:
- /* Move highlight bar down. Wrap to top if at */
- /* bottom. */
- FORALL(pitem)
- IFMATCH (col, row, H, DRRANGE, pitem)
- ritem = qitem;
- FOREND ()
-
- pitem = ritem;
- break;
-
-
- case MN_RIGHT:
- /* Move highlight bar right. Wrap to left if at */
- /* rightmost item. */
- FORALL(pitem)
- IFMATCH (row, col, W, DRRANGE, pitem)
- ritem = qitem;
- FOREND ()
-
- pitem = ritem;
- break;
-
-
- case MN_LEFT:
- /* Move highlight bar left. Wrap to right if at */
- /* leftmost item. */
- FORALL(pitem)
- IFMATCH (row, col, W, ULRANGE, pitem)
- ritem = qitem;
- FOREND ()
-
- pitem = ritem;
- break;
-
-
- case MN_NEXT:
- /* Move highlight bar to "logical-next" menu */
- /* position. This is the next item in the order */
- /* that items were entered by MNITEM and/or */
- /* MNITMKEY. Wrap to beginning if at end unless */
- /* MN_NOWRAP specified. */
- if (action & MN_NOWRAP)
- {
- for (qitem = pitem->next;
- qitem != NIL;
- qitem = qitem->next)
- {
- if (!(qitem->option & MN_PROTECT))
- {
- pitem = qitem;
- break;
- }
- }
- }
- else
- { /* MNMCHITM automatically wraps. */
- pitem = mnmchitm (pmenu, (*ppitem)->next,
- -1, -1, 0, &code);
- if (code != WN_NO_ERROR)
- {
- *pdone = TRUE;
- return (b_wnerr);
- }
- }
- break;
-
-
- case MN_PREVIOUS:
- /* Move highlight bar to "logical-previous" menu */
- /* position. This is the previous item in the */
- /* order that items were entered by MNITEM and/or */
- /* MNITMKEY. Wrap to end if at beginning. */
- if (pitem == mnmchitm (pmenu, pmenu->pitems,
- -1, -1, 0, &code))
- { /* pitem is first in list. */
- if (action & MN_NOWRAP)
- ritem = pitem;
- else
- { /* Find last in list. */
- FORALL(pitem)
- if (! (qitem->option & MN_PROTECT))
- ritem = qitem;
- FOREND ()
- }
- }
- else
- {
- if (code != WN_NO_ERROR)
- {
- *pdone = TRUE;
- return (b_wnerr);
- }
-
- for (ritem = pitem, qitem = pmenu->pitems;
- qitem != pitem;
- qitem = qitem->next)
-
- if ( !(qitem->option & MN_PROTECT))
- ritem = qitem;
- }
- pitem = ritem;
- break;
-
- case MN_PGDN:
- disp = jump(pmenu->pwin,MN_PGDN);
- FORALL(pitem)
- if (BEYOND(col,row,H,DRBEYOND,pitem,disp))
- ritem = qitem;
- FOREND()
- pitem = ritem;
- break;
-
- case MN_PGUP:
- disp = jump(pmenu->pwin,MN_PGUP);
- FORALL(pitem)
- if (BEYOND(col,row,H,ULBEYOND,pitem,disp))
- ritem = qitem;
- FOREND()
- pitem = ritem;
- break;
-
- case MN_PGRIGHT:
- disp = jump(pmenu->pwin,MN_PGRIGHT);
- FORALL(pitem)
- if (BEYOND(row,col,W,DRBEYOND,pitem,disp))
- ritem = qitem;
- FOREND()
- pitem = ritem;
- break;
-
- case MN_PGLEFT:
- disp = jump(pmenu->pwin,MN_PGLEFT);
- FORALL(pitem)
- if (BEYOND(row,col,W,ULBEYOND,pitem,disp))
- ritem = qitem;
- FOREND()
- pitem = ritem;
- break;
- }
- }
- break;
-
-
- case MN_FIRST:
- /* Move highlight bar to first item entered by */
- /* MNITEM and/or MNITMKEY. */
- pitem = mnmchitm (pmenu, pmenu->pitems, -1, -1, 0, &code);
- if (code != WN_NO_ERROR)
- {
- *pdone = TRUE;
- return (b_wnerr);
- }
- break;
-
-
- case MN_LAST:
- /* Move highlight bar to last item entered by */
- /* MNITEM and/or MNITMKEY. */
- FORALL(pitem)
- if ( !(qitem->option & MN_PROTECT))
- ritem = qitem;
- FOREND ()
-
- pitem = ritem;
- break;
- }
-
- if (action & MN_SHOW_BAR)
- {
- if (pitem == NIL) /* If no menu item lit, */
- pitem = pmenu->pbar_prev; /* find an item to highlight*/
- }
- else if (action & MN_HIDE_BAR)
- {
- if (pitem != NIL) /* If an item is lit, */
- {
- pmenu->pbar_prev = pitem; /* save location */
- pitem = NIL; /* and unlight the bar. */
- }
- }
-
- if (action & MN_BEEP)
- *pshouldbeep = TRUE; /* Forward beep request. */
-
- if (action & MN_KBIGNORE)
- *poption |= MN_KBDISCARD; /* Ignore keystrokes. */
- else
- *poption &= ~MN_KBDISCARD; /* Begin watching keys. */
-
- if (action & MN_ABORT)
- { /* User requested abort. */
- result = wnerror(MN_READ_AB);
- *pdone = TRUE;
- }
- else if (action & MN_TRANSMIT)
- { /* User requested transmit. */
- if (pitem == NIL)
- result = wnerror(MN_XMIT_NOBAR); /* Error if transmit */
- /* while no item lit.*/
- *pdone = TRUE;
- }
-
- *ppitem = pitem;
- return result;
- }
-
- /**
- *
- * Name jump -- Adjust window origin for MN_PGUP, MN_PGDN,
- * MN_PGRIGHT, or MN_PGLEFT motion.
- *
- * Synopsis displacement = jump(pwin,dir);
- *
- * int displacement Preferred amount of motion by
- * highlight bar (negative for
- * upward or toward left edge).
- * BWINDOW *pwin Address of menu's window.
- * int dir MN_PGUP, MN_PGDN, MN_PGRIGHT, or
- * MN_PGLEFT.
- *
- * Description This function moves the window's origin and
- * computes the distance the highlight bar should move.
- *
- * Returns displacement Preferred amount of motion by
- * highlight bar (negative for
- * upward or toward left edge).
- * b_wnerr Window error if any.
- *
- **/
-
- static int jump(pwin,dir)
- BWINDOW *pwin;
- int dir;
- {
- int new_origin_row,old_origin_row,new_origin_col,old_origin_col;
- int displacement;
-
- new_origin_row = old_origin_row = pwin->data_origin.row;
- new_origin_col = old_origin_col = pwin->data_origin.col;
-
- switch (dir)
- {
- case MN_PGDN:
- new_origin_row = utmin(old_origin_row + wnview_h(pwin) - 1,
- wndata_h(pwin) - wnview_h(pwin));
- if (new_origin_row == old_origin_row)
- displacement = wnview_h(pwin) - 1;
- else
- displacement = new_origin_row - old_origin_row;
- break;
-
- case MN_PGUP:
- new_origin_row = utmax(old_origin_row - (wnview_h(pwin) - 1),
- 0);
- if (new_origin_row == old_origin_row)
- displacement = 1 - wnview_h(pwin);
- else
- displacement = new_origin_row - old_origin_row;
- break;
-
- case MN_PGRIGHT:
- new_origin_col = utmin(old_origin_col + wnview_w(pwin) - 1,
- wndata_w(pwin) - wnview_w(pwin));
- if (new_origin_col == old_origin_col)
- displacement = wnview_w(pwin) - 1;
- else
- displacement = new_origin_col - old_origin_col;
- break;
-
- case MN_PGLEFT:
- new_origin_col = utmax(old_origin_col - (wnview_w(pwin) - 1),
- 0);
- if (new_origin_col == old_origin_col)
- displacement = 1 - wnview_w(pwin);
- else
- displacement = new_origin_col - old_origin_col;
- break;
- }
-
- wnorigin(pwin,new_origin_row,new_origin_col,WN_NO_UPDATE);
- return displacement;
- }