home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c070 / 4.ddi / TOOLS.4 / TCTSRC1.EXE / MNKEY.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-31  |  7.2 KB  |  271 lines

  1. /**
  2. *
  3. * Name        MNKEY -- Add, change, or delete a key binding in a
  4. *             menu.
  5. *
  6. * Synopsis    presult = mnkey (pmenu, row, col, ch, scan,
  7. *                 action, howchange);
  8. *
  9. *        BMENU *presult    Pointer to menu in which key binding
  10. *                was just changed, or NIL for failure.
  11. *        BMENU *pmenu    Pointer to menu in which to change key
  12. *                binding.
  13. *        int    row,    Row and column (relative to menu's
  14. *               col    window data area) at which to bind
  15. *                the key.  If MN_SELECT is not the
  16. *                key movement, the key binding
  17. *                can have only a global action (motion),
  18. *                and is not associated with a
  19. *                specific menu item/location.
  20. *        int    ch,    Character and scan code of key to
  21. *               scan    add to key bindings list.
  22. *        int    action    The action(s) which should be taken
  23. *                when (ch,scan) is received by
  24. *                MNREAD:
  25. *                   The bitwise OR-ing of any of the
  26. *                   following:
  27. *                       MN_TRANSMIT, MN_BEEP,
  28. *                       MN_DISABLE, and
  29. *                       MN_ABORT,
  30. *
  31. *                     OR-ed with exactly one of:
  32. *
  33. *                       MN_UP, MN_DOWN, MN_RIGHT,
  34. *                       MN_LEFT, MN_NEXT,
  35. *                       MN_PREVIOUS, MN_FIRST,
  36. *                       MN_LAST, MN_SELECT, or
  37. *                       MN_NOMOVE.
  38. *
  39. *        int    howchange
  40. *                How the specified key binding should
  41. *                be changed -- Use MN_ADD, MN_CHANGE,
  42. *                or MN_DELETE.
  43. *
  44. * Description    This function adds a key binding to a menu.  An example
  45. *        is probably best here:
  46. *
  47. *        The call:
  48. *            presult = mnkey (pmenu, 5, 2, 'O', KB_S_S_O,
  49. *                     MN_SELECT, MN_ADD);
  50. *
  51. *        Will make MNREAD recognize "O" (KB_S_S_O means scan code
  52. *        of shift-o) as being bound to whatever menu item is at
  53. *        location (5,2), with MN_SELECT being its movement.  That
  54. *        is, when the user presses "O", the highlight bar will
  55. *        move to the item at (5,2).  If there is no menu item at
  56. *        (5,2), or the item is protected, pressing "O" will be
  57. *        ignored or beeped at, (unless MN_ALL_TRANSMIT is an
  58. *        option to MNREAD/MNLREAD, in which case a transmit will
  59. *        occur after each key in any case).
  60. *
  61. *        If howchange is MN_CHANGE, only the key's action may
  62. *        be changed (the bitwise OR-ing of one or more of MN_TRANSMIT,
  63. *        MN_BEEP, MN_DISABLE, or MN_ABORT); its location and motion
  64. *        remain the same.
  65. *
  66. *        An error occurs if the specified motion is MN_SELECT and
  67. *        row or col exceeds the menu's window dimensions.
  68. *
  69. * Returns    presult         Pointer to changed menu, or
  70. *                    NIL if failure.
  71. *        b_wnerr         Possible values:
  72. *                (No change)     Success.
  73. *                MN_BAD_MENU     Pmenu is invalid.
  74. *                MN_BAD_KEY     A member of pmenu's
  75. *                         key list is bad.
  76. *                WN_ILL_DIM     Row or col out of range.
  77. *                WN_ILL_VALUE     Howchange is not MN_ADD
  78. *                         MN_DELETE or MN_CHANGE.
  79. *                WN_NO_MEMORY     Insufficient memory.
  80. *
  81. * Version    6.00 (C)Copyright Blaise Computing Inc.  1987-1989
  82. *
  83. **/
  84.  
  85.  
  86. #include <bmenu.h>
  87.  
  88. #define TRUE   1
  89. #define FALSE  0
  90.  
  91.  
  92. BMENU *mnkey (pmenu, row, col, ch, scan, action, howchange)
  93. BMENU *pmenu;
  94. int    row, col;
  95. int    ch;
  96. int    scan, action, howchange;
  97. {
  98.     int      done    = FALSE;
  99.     int      touched = FALSE;
  100.     int      code;
  101.     BKEYMAP *pkey, *qkey, *rkey;
  102.  
  103.         /* Validate the menu data structure.            */
  104.     mnvalidm (pmenu)
  105.  
  106.     qkey = NIL;
  107.  
  108.     switch (howchange)
  109.     {
  110.     case MN_ADD:
  111.     case MN_CHANGE:
  112.         /* If movement is MN_SELECT, (row,col) must be        */
  113.         /* valid window coordinates, and must have an item. */
  114.         if (MNMOVE (action) == MN_SELECT)
  115.         {
  116.         if (utrange (row, 0, pmenu->pwin->img.dim.h - 1) ||
  117.             utrange (col, 0, pmenu->pwin->img.dim.w - 1))
  118.             wnreterr (WN_ILL_DIM);
  119.  
  120.         if (NIL == mnmchitm (pmenu, NIL, row, col, 1, &code))
  121.         {
  122.             if (code == WN_NO_ERROR)
  123.             wnreterr (MN_NO_ITEM);
  124.             else
  125.             return (NIL);
  126.         }
  127.         }
  128.  
  129.         pkey = pmenu->pkeys;
  130.  
  131.         /* Go check for a change of action code for old key */
  132.         /* definition, or for a key conflict.            */
  133.         while ((pkey != NIL) && (!done))
  134.         {
  135.         /* Check key signature byte.                */
  136.         if (pkey->signature != MN_KEY_SIGN)
  137.             wnreterr (MN_BAD_KEY);
  138.  
  139.         if ((pkey->scan == scan)   &&
  140.             (pkey->ch    == ch)       &&
  141.             (((pkey->row  == row)  &&
  142.               (pkey->col  == col)) ||
  143.               (MNMOVE (pkey->action) != MN_SELECT)))
  144.         /* What we really want to do is change the action   */
  145.         /* associated with this key.                */
  146.         {
  147.             /* Check for possible key conflict.        */
  148.             if ((MNMOVE (pkey->action) == MN_SELECT) &&
  149.             (MNMOVE (action) != MN_SELECT))
  150.  
  151.             for (rkey = pmenu->pkeys;
  152.                  rkey != NIL;
  153.                  rkey = rkey->next)
  154.             {
  155.                 if (rkey->signature != MN_KEY_SIGN)
  156.                 wnreterr (MN_BAD_KEY);
  157.  
  158.                 if ((rkey != pkey)         &&
  159.                 (rkey->ch   == ch)   &&
  160.                 (rkey->scan == scan))
  161.                 wnreterr (MN_KEY_CONFLICT);
  162.             }
  163.  
  164.             done     = TRUE;
  165.             /* Change the key's action, but preserve    */
  166.             /* its motion.                    */
  167.             pkey->action = MNMOVE(pkey->action) |
  168.                    (action & ~MN_MOVE_MASK);
  169.         }
  170.         else
  171.         /* Check for a key conflict.  A conflict is defined */
  172.         /* as when two keys have the same character and key */
  173.         /* codes, and are not both bound to menu items (i.e.*/
  174.         /* do not have MN_SELECT as their movment).        */
  175.             if ((pkey->ch   == ch)   &&
  176.             (pkey->scan == scan) &&
  177.             (MNMOVE (pkey->action) != MN_SELECT))
  178.             wnreterr (MN_KEY_CONFLICT);
  179.  
  180.         qkey = pkey;
  181.         pkey = pkey->next;
  182.         }
  183.  
  184.         if (!done)
  185.         {
  186.         /* Now we know we really want to *add* a key binding*/
  187.  
  188.         /* Qkey is pointing to the last item in the keymap, */
  189.         /* or is NIL if there is no keymap defined.        */
  190.  
  191.         /* Allocate memory for new key binding.         */
  192.         if ((pkey = utalloc (BKEYMAP)) == NIL)
  193.             wnreterr (WN_NO_MEMORY);
  194.  
  195.         pkey->action = action;
  196.         pkey->row    = row;
  197.         pkey->col    = col;
  198.         pkey->ch     = ch;
  199.         pkey->scan   = scan;
  200.         pkey->next   = NIL;
  201.  
  202.         /* Create key signature.                */
  203.         pkey->signature = MN_KEY_SIGN;
  204.  
  205.         /* Insert it at the end of the list, or as the        */
  206.         /* first list item if there is no list yet.        */
  207.         if (qkey == NIL)
  208.             pmenu->pkeys = pkey;
  209.         else
  210.             qkey->next = pkey;
  211.         }
  212.         break;
  213.  
  214.  
  215.     case MN_DELETE:
  216.  
  217.         for (pkey = pmenu->pkeys;  pkey != NIL;  )
  218.         {
  219.         /* Check key signature.                 */
  220.         if (pkey->signature != MN_KEY_SIGN)
  221.             wnreterr (MN_BAD_KEY);
  222.  
  223.         /* Make sure to remove every definition of the key. */
  224.         if ((pkey->ch    == ch)     &&
  225.             (pkey->scan == scan))
  226.         {
  227.             if (((MNMOVE (pkey->action) == MN_SELECT) &&
  228.              (pkey->row == row)              &&
  229.              (pkey->col == col))              ||
  230.             (MNMOVE (pkey->action) != MN_SELECT))
  231.             {
  232.             if (MNMOVE (pkey->action) != MN_SELECT)
  233.                 done = TRUE;
  234.  
  235.                 /* Point previous key to next key.    */
  236.             if (qkey == NIL)
  237.                 pmenu->pkeys = pkey->next;
  238.             else
  239.                 qkey->next = pkey->next;
  240.  
  241.                 /* Delete key signature.        */
  242.             pkey->signature = MN_DEAD_KEY;
  243.  
  244.                 /* Free memory used by deleted key    */
  245.                 /* binding.             */
  246.             free (pkey);
  247.  
  248.                 /* Set up pointers to mean something*/
  249.             touched = TRUE;
  250.             pkey    = pmenu->pkeys;
  251.             qkey    = NIL;
  252.             }
  253.         }
  254.  
  255.         if (!touched)
  256.         {
  257.             qkey = pkey;
  258.             pkey = pkey->next;
  259.         }
  260.         else
  261.             touched = FALSE;
  262.         }
  263.         break;
  264.  
  265.  
  266.     default:
  267.         wnreterr (WN_ILL_VALUE);
  268.     }
  269.     return (pmenu);
  270. }
  271.