home *** CD-ROM | disk | FTP | other *** search
- /**
- *
- * Name MNKEY -- Add, change, or delete a key binding in a
- * menu.
- *
- * Synopsis presult = mnkey (pmenu, row, col, ch, scan,
- * action, howchange);
- *
- * BMENU *presult Pointer to menu in which key binding
- * was just changed, or NIL for failure.
- * BMENU *pmenu Pointer to menu in which to change key
- * binding.
- * int row, Row and column (relative to menu's
- * col window data area) at which to bind
- * the key. If MN_SELECT is not the
- * key movement, the key binding
- * can have only a global action (motion),
- * and is not associated with a
- * specific menu item/location.
- * int ch, Character and scan code of key to
- * scan add to key bindings list.
- * int action The action(s) which should be taken
- * when (ch,scan) is received by
- * MNREAD:
- * The bitwise OR-ing of any of the
- * following:
- * MN_TRANSMIT, MN_BEEP,
- * MN_DISABLE, and
- * MN_ABORT,
- *
- * OR-ed with exactly one of:
- *
- * MN_UP, MN_DOWN, MN_RIGHT,
- * MN_LEFT, MN_NEXT,
- * MN_PREVIOUS, MN_FIRST,
- * MN_LAST, MN_SELECT, or
- * MN_NOMOVE.
- *
- * int howchange
- * How the specified key binding should
- * be changed -- Use MN_ADD, MN_CHANGE,
- * or MN_DELETE.
- *
- * Description This function adds a key binding to a menu. An example
- * is probably best here:
- *
- * The call:
- * presult = mnkey (pmenu, 5, 2, 'O', KB_S_S_O,
- * MN_SELECT, MN_ADD);
- *
- * Will make MNREAD recognize "O" (KB_S_S_O means scan code
- * of shift-o) as being bound to whatever menu item is at
- * location (5,2), with MN_SELECT being its movement. That
- * is, when the user presses "O", the highlight bar will
- * move to the item at (5,2). If there is no menu item at
- * (5,2), or the item is protected, pressing "O" will be
- * ignored or beeped at, (unless MN_ALL_TRANSMIT is an
- * option to MNREAD/MNLREAD, in which case a transmit will
- * occur after each key in any case).
- *
- * If howchange is MN_CHANGE, only the key's action may
- * be changed (the bitwise OR-ing of one or more of MN_TRANSMIT,
- * MN_BEEP, MN_DISABLE, or MN_ABORT); its location and motion
- * remain the same.
- *
- * An error occurs if the specified motion is MN_SELECT and
- * row or col exceeds the menu's window dimensions.
- *
- * Returns presult Pointer to changed menu, or
- * NIL if failure.
- * b_wnerr Possible values:
- * (No change) Success.
- * MN_BAD_MENU Pmenu is invalid.
- * MN_BAD_KEY A member of pmenu's
- * key list is bad.
- * WN_ILL_DIM Row or col out of range.
- * WN_ILL_VALUE Howchange is not MN_ADD
- * MN_DELETE or MN_CHANGE.
- * WN_NO_MEMORY Insufficient memory.
- *
- * Version 6.00 (C)Copyright Blaise Computing Inc. 1987-1989
- *
- **/
-
-
- #include <bmenu.h>
-
- #define TRUE 1
- #define FALSE 0
-
-
- BMENU *mnkey (pmenu, row, col, ch, scan, action, howchange)
- BMENU *pmenu;
- int row, col;
- int ch;
- int scan, action, howchange;
- {
- int done = FALSE;
- int touched = FALSE;
- int code;
- BKEYMAP *pkey, *qkey, *rkey;
-
- /* Validate the menu data structure. */
- mnvalidm (pmenu)
-
- qkey = NIL;
-
- switch (howchange)
- {
- case MN_ADD:
- case MN_CHANGE:
- /* If movement is MN_SELECT, (row,col) must be */
- /* valid window coordinates, and must have an item. */
- if (MNMOVE (action) == MN_SELECT)
- {
- if (utrange (row, 0, pmenu->pwin->img.dim.h - 1) ||
- utrange (col, 0, pmenu->pwin->img.dim.w - 1))
- wnreterr (WN_ILL_DIM);
-
- if (NIL == mnmchitm (pmenu, NIL, row, col, 1, &code))
- {
- if (code == WN_NO_ERROR)
- wnreterr (MN_NO_ITEM);
- else
- return (NIL);
- }
- }
-
- pkey = pmenu->pkeys;
-
- /* Go check for a change of action code for old key */
- /* definition, or for a key conflict. */
- while ((pkey != NIL) && (!done))
- {
- /* Check key signature byte. */
- if (pkey->signature != MN_KEY_SIGN)
- wnreterr (MN_BAD_KEY);
-
- if ((pkey->scan == scan) &&
- (pkey->ch == ch) &&
- (((pkey->row == row) &&
- (pkey->col == col)) ||
- (MNMOVE (pkey->action) != MN_SELECT)))
- /* What we really want to do is change the action */
- /* associated with this key. */
- {
- /* Check for possible key conflict. */
- if ((MNMOVE (pkey->action) == MN_SELECT) &&
- (MNMOVE (action) != MN_SELECT))
-
- for (rkey = pmenu->pkeys;
- rkey != NIL;
- rkey = rkey->next)
- {
- if (rkey->signature != MN_KEY_SIGN)
- wnreterr (MN_BAD_KEY);
-
- if ((rkey != pkey) &&
- (rkey->ch == ch) &&
- (rkey->scan == scan))
- wnreterr (MN_KEY_CONFLICT);
- }
-
- done = TRUE;
- /* Change the key's action, but preserve */
- /* its motion. */
- pkey->action = MNMOVE(pkey->action) |
- (action & ~MN_MOVE_MASK);
- }
- else
- /* Check for a key conflict. A conflict is defined */
- /* as when two keys have the same character and key */
- /* codes, and are not both bound to menu items (i.e.*/
- /* do not have MN_SELECT as their movment). */
- if ((pkey->ch == ch) &&
- (pkey->scan == scan) &&
- (MNMOVE (pkey->action) != MN_SELECT))
- wnreterr (MN_KEY_CONFLICT);
-
- qkey = pkey;
- pkey = pkey->next;
- }
-
- if (!done)
- {
- /* Now we know we really want to *add* a key binding*/
-
- /* Qkey is pointing to the last item in the keymap, */
- /* or is NIL if there is no keymap defined. */
-
- /* Allocate memory for new key binding. */
- if ((pkey = utalloc (BKEYMAP)) == NIL)
- wnreterr (WN_NO_MEMORY);
-
- pkey->action = action;
- pkey->row = row;
- pkey->col = col;
- pkey->ch = ch;
- pkey->scan = scan;
- pkey->next = NIL;
-
- /* Create key signature. */
- pkey->signature = MN_KEY_SIGN;
-
- /* Insert it at the end of the list, or as the */
- /* first list item if there is no list yet. */
- if (qkey == NIL)
- pmenu->pkeys = pkey;
- else
- qkey->next = pkey;
- }
- break;
-
-
- case MN_DELETE:
-
- for (pkey = pmenu->pkeys; pkey != NIL; )
- {
- /* Check key signature. */
- if (pkey->signature != MN_KEY_SIGN)
- wnreterr (MN_BAD_KEY);
-
- /* Make sure to remove every definition of the key. */
- if ((pkey->ch == ch) &&
- (pkey->scan == scan))
- {
- if (((MNMOVE (pkey->action) == MN_SELECT) &&
- (pkey->row == row) &&
- (pkey->col == col)) ||
- (MNMOVE (pkey->action) != MN_SELECT))
- {
- if (MNMOVE (pkey->action) != MN_SELECT)
- done = TRUE;
-
- /* Point previous key to next key. */
- if (qkey == NIL)
- pmenu->pkeys = pkey->next;
- else
- qkey->next = pkey->next;
-
- /* Delete key signature. */
- pkey->signature = MN_DEAD_KEY;
-
- /* Free memory used by deleted key */
- /* binding. */
- free (pkey);
-
- /* Set up pointers to mean something*/
- touched = TRUE;
- pkey = pmenu->pkeys;
- qkey = NIL;
- }
- }
-
- if (!touched)
- {
- qkey = pkey;
- pkey = pkey->next;
- }
- else
- touched = FALSE;
- }
- break;
-
-
- default:
- wnreterr (WN_ILL_VALUE);
- }
- return (pmenu);
- }