xref: /freebsd/contrib/ncurses/menu/m_driver.c (revision 21817992b3314c908ab50f0bb88d2ee750b9c4ac)
10e3d5408SPeter Wemm /****************************************************************************
2*21817992SBaptiste Daroussin  * Copyright 2020,2021 Thomas E. Dickey                                     *
3e1865124SBaptiste Daroussin  * Copyright 1998-2012,2016 Free Software Foundation, Inc.                  *
40e3d5408SPeter Wemm  *                                                                          *
50e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
60e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
70e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
80e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
90e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
100e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
110e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
120e3d5408SPeter Wemm  *                                                                          *
130e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
140e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
150e3d5408SPeter Wemm  *                                                                          *
160e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
170e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
180e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
190e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
200e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
210e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
220e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
230e3d5408SPeter Wemm  *                                                                          *
240e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
250e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
260e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
270e3d5408SPeter Wemm  * authorization.                                                           *
280e3d5408SPeter Wemm  ****************************************************************************/
290e3d5408SPeter Wemm 
300e3d5408SPeter Wemm /****************************************************************************
314a1a9510SRong-En Fan  *   Author:  Juergen Pfeifer, 1995,1997                                    *
320e3d5408SPeter Wemm  ****************************************************************************/
330e3d5408SPeter Wemm 
340e3d5408SPeter Wemm /***************************************************************************
350e3d5408SPeter Wemm * Module m_driver                                                          *
360e3d5408SPeter Wemm * Central dispatching routine                                              *
370e3d5408SPeter Wemm ***************************************************************************/
380e3d5408SPeter Wemm 
390e3d5408SPeter Wemm #include "menu.priv.h"
400e3d5408SPeter Wemm 
41*21817992SBaptiste Daroussin MODULE_ID("$Id: m_driver.c,v 1.37 2021/03/27 23:46:29 tom Exp $")
420e3d5408SPeter Wemm 
430e3d5408SPeter Wemm /* Macros */
440e3d5408SPeter Wemm 
450e3d5408SPeter Wemm /* Remove the last character from the match pattern buffer */
460e3d5408SPeter Wemm #define Remove_Character_From_Pattern(menu) \
470e3d5408SPeter Wemm   (menu)->pattern[--((menu)->pindex)] = '\0'
480e3d5408SPeter Wemm 
490e3d5408SPeter Wemm /* Add a new character to the match pattern buffer */
500e3d5408SPeter Wemm #define Add_Character_To_Pattern(menu,ch) \
5173f0a83dSXin LI   { (menu)->pattern[((menu)->pindex)++] = (char) (ch);\
520e3d5408SPeter Wemm     (menu)->pattern[(menu)->pindex] = '\0'; }
530e3d5408SPeter Wemm 
540e3d5408SPeter Wemm /*---------------------------------------------------------------------------
550e3d5408SPeter Wemm |   Facility      :  libnmenu
560e3d5408SPeter Wemm |   Function      :  static bool Is_Sub_String(
570e3d5408SPeter Wemm |                           bool IgnoreCaseFlag,
580e3d5408SPeter Wemm |                           const char *part,
590e3d5408SPeter Wemm |                           const char *string)
600e3d5408SPeter Wemm |
610e3d5408SPeter Wemm |   Description   :  Checks whether or not part is a substring of string.
620e3d5408SPeter Wemm |
630e3d5408SPeter Wemm |   Return Values :  TRUE   - if it is a substring
640e3d5408SPeter Wemm |                    FALSE  - if it is not a substring
650e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
664a1a9510SRong-En Fan static bool
Is_Sub_String(bool IgnoreCaseFlag,const char * part,const char * string)674a1a9510SRong-En Fan Is_Sub_String(
680e3d5408SPeter Wemm 	       bool IgnoreCaseFlag,
690e3d5408SPeter Wemm 	       const char *part,
700e3d5408SPeter Wemm 	       const char *string
710e3d5408SPeter Wemm )
720e3d5408SPeter Wemm {
730e3d5408SPeter Wemm   assert(part && string);
740e3d5408SPeter Wemm   if (IgnoreCaseFlag)
750e3d5408SPeter Wemm     {
760e3d5408SPeter Wemm       while (*string && *part)
770e3d5408SPeter Wemm 	{
785d08fb1fSRong-En Fan 	  if (toupper(UChar(*string++)) != toupper(UChar(*part)))
794a1a9510SRong-En Fan 	    break;
800e3d5408SPeter Wemm 	  part++;
810e3d5408SPeter Wemm 	}
820e3d5408SPeter Wemm     }
830e3d5408SPeter Wemm   else
840e3d5408SPeter Wemm     {
850e3d5408SPeter Wemm       while (*string && *part)
864a1a9510SRong-En Fan 	if (*part != *string++)
874a1a9510SRong-En Fan 	  break;
880e3d5408SPeter Wemm       part++;
890e3d5408SPeter Wemm     }
900e3d5408SPeter Wemm   return ((*part) ? FALSE : TRUE);
910e3d5408SPeter Wemm }
920e3d5408SPeter Wemm 
930e3d5408SPeter Wemm /*---------------------------------------------------------------------------
940e3d5408SPeter Wemm |   Facility      :  libnmenu
950e3d5408SPeter Wemm |   Function      :  int _nc_Match_Next_Character_In_Item_Name(
960e3d5408SPeter Wemm |                           MENU *menu,
970e3d5408SPeter Wemm |                           int  ch,
980e3d5408SPeter Wemm |                           ITEM **item)
990e3d5408SPeter Wemm |
1000e3d5408SPeter Wemm |   Description   :  This internal routine is called for a menu positioned
1010e3d5408SPeter Wemm |                    at an item with three different classes of characters:
1020e3d5408SPeter Wemm |                       - a printable character; the character is added to
1030e3d5408SPeter Wemm |                         the current pattern and the next item matching
1040e3d5408SPeter Wemm |                         this pattern is searched.
1050e3d5408SPeter Wemm |                       - NUL; the pattern stays as it is and the next item
1060e3d5408SPeter Wemm |                         matching the pattern is searched
1070e3d5408SPeter Wemm |                       - BS; the pattern stays as it is and the previous
1080e3d5408SPeter Wemm |                         item matching the pattern is searched
1090e3d5408SPeter Wemm |
1100e3d5408SPeter Wemm |                       The item parameter contains on call a pointer to
1110e3d5408SPeter Wemm |                       the item where the search starts. On return - if
1120e3d5408SPeter Wemm |                       a match was found - it contains a pointer to the
1130e3d5408SPeter Wemm |                       matching item.
1140e3d5408SPeter Wemm |
1150e3d5408SPeter Wemm |   Return Values :  E_OK        - an item matching the pattern was found
1160e3d5408SPeter Wemm |                    E_NO_MATCH  - nothing found
1170e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
1187a656419SBaptiste Daroussin MENU_EXPORT(int)
_nc_Match_Next_Character_In_Item_Name(MENU * menu,int ch,ITEM ** item)1197a69bbfbSPeter Wemm _nc_Match_Next_Character_In_Item_Name
1207a69bbfbSPeter Wemm (MENU *menu, int ch, ITEM **item)
1210e3d5408SPeter Wemm {
1220e3d5408SPeter Wemm   bool found = FALSE, passed = FALSE;
1230e3d5408SPeter Wemm   int idx, last;
1240e3d5408SPeter Wemm 
12506bfebdeSXin LI   T((T_CALLED("_nc_Match_Next_Character(%p,%d,%p)"),
12606bfebdeSXin LI      (void *)menu, ch, (void *)item));
1274a1a9510SRong-En Fan 
1280e3d5408SPeter Wemm   assert(menu && item && *item);
1290e3d5408SPeter Wemm   idx = (*item)->index;
1300e3d5408SPeter Wemm 
1310e3d5408SPeter Wemm   if (ch && ch != BS)
1320e3d5408SPeter Wemm     {
1330e3d5408SPeter Wemm       /* if we become to long, we need no further checking : there can't be
1340e3d5408SPeter Wemm          a match ! */
1350e3d5408SPeter Wemm       if ((menu->pindex + 1) > menu->namelen)
1360e3d5408SPeter Wemm 	RETURN(E_NO_MATCH);
1370e3d5408SPeter Wemm 
1380e3d5408SPeter Wemm       Add_Character_To_Pattern(menu, ch);
1390e3d5408SPeter Wemm       /* we artificially position one item back, because in the do...while
1400e3d5408SPeter Wemm          loop we start with the next item. This means, that with a new
1410e3d5408SPeter Wemm          pattern search we always start the scan with the actual item. If
142aae38d10SBaptiste Daroussin          we do a NEXT_PATTERN or PREV_PATTERN search, we start with the
1430e3d5408SPeter Wemm          one after or before the actual item. */
1440e3d5408SPeter Wemm       if (--idx < 0)
1450e3d5408SPeter Wemm 	idx = menu->nitems - 1;
1460e3d5408SPeter Wemm     }
1470e3d5408SPeter Wemm 
1480e3d5408SPeter Wemm   last = idx;			/* this closes the cycle */
1490e3d5408SPeter Wemm 
1504a1a9510SRong-En Fan   do
1514a1a9510SRong-En Fan     {
1520e3d5408SPeter Wemm       if (ch == BS)
1530e3d5408SPeter Wemm 	{			/* we have to go backward */
1540e3d5408SPeter Wemm 	  if (--idx < 0)
1550e3d5408SPeter Wemm 	    idx = menu->nitems - 1;
1560e3d5408SPeter Wemm 	}
1570e3d5408SPeter Wemm       else
1580e3d5408SPeter Wemm 	{			/* otherwise we always go forward */
1590e3d5408SPeter Wemm 	  if (++idx >= menu->nitems)
1600e3d5408SPeter Wemm 	    idx = 0;
1610e3d5408SPeter Wemm 	}
1624a1a9510SRong-En Fan       if (Is_Sub_String((bool)((menu->opt & O_IGNORECASE) != 0),
1630e3d5408SPeter Wemm 			menu->pattern,
1640e3d5408SPeter Wemm 			menu->items[idx]->name.str)
1650e3d5408SPeter Wemm 	)
1660e3d5408SPeter Wemm 	found = TRUE;
1670e3d5408SPeter Wemm       else
1680e3d5408SPeter Wemm 	passed = TRUE;
1694a1a9510SRong-En Fan     }
1704a1a9510SRong-En Fan   while (!found && (idx != last));
1710e3d5408SPeter Wemm 
1720e3d5408SPeter Wemm   if (found)
1730e3d5408SPeter Wemm     {
1740e3d5408SPeter Wemm       if (!((idx == (*item)->index) && passed))
1750e3d5408SPeter Wemm 	{
1760e3d5408SPeter Wemm 	  *item = menu->items[idx];
1770e3d5408SPeter Wemm 	  RETURN(E_OK);
1780e3d5408SPeter Wemm 	}
1790e3d5408SPeter Wemm       /* This point is reached, if we fully cycled through the item list
1800e3d5408SPeter Wemm          and the only match we found is the starting item. With a NEXT_PATTERN
1810e3d5408SPeter Wemm          or PREV_PATTERN scan this means, that there was no additional match.
1820e3d5408SPeter Wemm          If we searched with an expanded new pattern, we should never reach
1830e3d5408SPeter Wemm          this point, because if the expanded pattern matches also the actual
1840e3d5408SPeter Wemm          item we will find it in the first attempt (passed==FALSE) and we
1850e3d5408SPeter Wemm          will never cycle through the whole item array.
1860e3d5408SPeter Wemm        */
1870e3d5408SPeter Wemm       assert(ch == 0 || ch == BS);
1880e3d5408SPeter Wemm     }
1890e3d5408SPeter Wemm   else
1900e3d5408SPeter Wemm     {
1910e3d5408SPeter Wemm       if (ch && ch != BS && menu->pindex > 0)
1920e3d5408SPeter Wemm 	{
1930e3d5408SPeter Wemm 	  /* if we had no match with a new pattern, we have to restore it */
1940e3d5408SPeter Wemm 	  Remove_Character_From_Pattern(menu);
1950e3d5408SPeter Wemm 	}
1960e3d5408SPeter Wemm     }
1970e3d5408SPeter Wemm   RETURN(E_NO_MATCH);
1980e3d5408SPeter Wemm }
1990e3d5408SPeter Wemm 
2000e3d5408SPeter Wemm /*---------------------------------------------------------------------------
2010e3d5408SPeter Wemm |   Facility      :  libnmenu
2020e3d5408SPeter Wemm |   Function      :  int menu_driver(MENU* menu, int c)
2030e3d5408SPeter Wemm |
2040e3d5408SPeter Wemm |   Description   :  Central dispatcher for the menu. Translates the logical
2050e3d5408SPeter Wemm |                    request 'c' into a menu action.
2060e3d5408SPeter Wemm |
2070e3d5408SPeter Wemm |   Return Values :  E_OK            - success
2080e3d5408SPeter Wemm |                    E_BAD_ARGUMENT  - invalid menu pointer
2090e3d5408SPeter Wemm |                    E_BAD_STATE     - menu is in user hook routine
2100e3d5408SPeter Wemm |                    E_NOT_POSTED    - menu is not posted
2110e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
2127a656419SBaptiste Daroussin MENU_EXPORT(int)
menu_driver(MENU * menu,int c)2137a69bbfbSPeter Wemm menu_driver(MENU *menu, int c)
2140e3d5408SPeter Wemm {
2150e3d5408SPeter Wemm #define NAVIGATE(dir) \
2160e3d5408SPeter Wemm   if (!item->dir)\
2170e3d5408SPeter Wemm      result = E_REQUEST_DENIED;\
2180e3d5408SPeter Wemm   else\
2190e3d5408SPeter Wemm      item = item->dir
2200e3d5408SPeter Wemm 
2210e3d5408SPeter Wemm   int result = E_OK;
2220e3d5408SPeter Wemm   ITEM *item;
223*21817992SBaptiste Daroussin   int my_top_row;
2240e3d5408SPeter Wemm 
22506bfebdeSXin LI   T((T_CALLED("menu_driver(%p,%d)"), (void *)menu, c));
2264a1a9510SRong-En Fan 
2270e3d5408SPeter Wemm   if (!menu)
2280e3d5408SPeter Wemm     RETURN(E_BAD_ARGUMENT);
2290e3d5408SPeter Wemm 
2300e3d5408SPeter Wemm   if (menu->status & _IN_DRIVER)
2310e3d5408SPeter Wemm     RETURN(E_BAD_STATE);
2320e3d5408SPeter Wemm   if (!(menu->status & _POSTED))
2330e3d5408SPeter Wemm     RETURN(E_NOT_POSTED);
2340e3d5408SPeter Wemm 
2350e3d5408SPeter Wemm   item = menu->curitem;
2360e3d5408SPeter Wemm 
2370e3d5408SPeter Wemm   my_top_row = menu->toprow;
2380e3d5408SPeter Wemm   assert(item);
2390e3d5408SPeter Wemm 
2400e3d5408SPeter Wemm   if ((c > KEY_MAX) && (c <= MAX_MENU_COMMAND))
2410e3d5408SPeter Wemm     {
242*21817992SBaptiste Daroussin       int rdiff;
243*21817992SBaptiste Daroussin 
2440e3d5408SPeter Wemm       if (!((c == REQ_BACK_PATTERN)
2450e3d5408SPeter Wemm 	    || (c == REQ_NEXT_MATCH) || (c == REQ_PREV_MATCH)))
2460e3d5408SPeter Wemm 	{
2470e3d5408SPeter Wemm 	  assert(menu->pattern);
2480e3d5408SPeter Wemm 	  Reset_Pattern(menu);
2490e3d5408SPeter Wemm 	}
2500e3d5408SPeter Wemm 
2510e3d5408SPeter Wemm       switch (c)
2520e3d5408SPeter Wemm 	{
2530e3d5408SPeter Wemm 	case REQ_LEFT_ITEM:
2540e3d5408SPeter Wemm 	    /*=================*/
2550e3d5408SPeter Wemm 	  NAVIGATE(left);
2560e3d5408SPeter Wemm 	  break;
2570e3d5408SPeter Wemm 
2580e3d5408SPeter Wemm 	case REQ_RIGHT_ITEM:
2590e3d5408SPeter Wemm 	    /*==================*/
2600e3d5408SPeter Wemm 	  NAVIGATE(right);
2610e3d5408SPeter Wemm 	  break;
2620e3d5408SPeter Wemm 
2630e3d5408SPeter Wemm 	case REQ_UP_ITEM:
2640e3d5408SPeter Wemm 	    /*===============*/
2650e3d5408SPeter Wemm 	  NAVIGATE(up);
2660e3d5408SPeter Wemm 	  break;
2670e3d5408SPeter Wemm 
2680e3d5408SPeter Wemm 	case REQ_DOWN_ITEM:
2690e3d5408SPeter Wemm 	    /*=================*/
2700e3d5408SPeter Wemm 	  NAVIGATE(down);
2710e3d5408SPeter Wemm 	  break;
2720e3d5408SPeter Wemm 
2730e3d5408SPeter Wemm 	case REQ_SCR_ULINE:
2740e3d5408SPeter Wemm 	    /*=================*/
2750e3d5408SPeter Wemm 	  if (my_top_row == 0 || !(item->up))
2760e3d5408SPeter Wemm 	    result = E_REQUEST_DENIED;
2770e3d5408SPeter Wemm 	  else
2780e3d5408SPeter Wemm 	    {
2790e3d5408SPeter Wemm 	      --my_top_row;
2800e3d5408SPeter Wemm 	      item = item->up;
2810e3d5408SPeter Wemm 	    }
2820e3d5408SPeter Wemm 	  break;
2830e3d5408SPeter Wemm 
2840e3d5408SPeter Wemm 	case REQ_SCR_DLINE:
2850e3d5408SPeter Wemm 	    /*=================*/
2860e3d5408SPeter Wemm 	  if ((my_top_row + menu->arows >= menu->rows) || !(item->down))
2870e3d5408SPeter Wemm 	    {
2880e3d5408SPeter Wemm 	      /* only if the menu has less items than rows, we can deny the
2890e3d5408SPeter Wemm 	         request. Otherwise the epilogue of this routine adjusts the
2900e3d5408SPeter Wemm 	         top row if necessary */
2910e3d5408SPeter Wemm 	      result = E_REQUEST_DENIED;
2920e3d5408SPeter Wemm 	    }
2934a1a9510SRong-En Fan 	  else
2944a1a9510SRong-En Fan 	    {
2950e3d5408SPeter Wemm 	      my_top_row++;
2960e3d5408SPeter Wemm 	      item = item->down;
2970e3d5408SPeter Wemm 	    }
2980e3d5408SPeter Wemm 	  break;
2990e3d5408SPeter Wemm 
3000e3d5408SPeter Wemm 	case REQ_SCR_DPAGE:
3010e3d5408SPeter Wemm 	    /*=================*/
3020e3d5408SPeter Wemm 	  rdiff = menu->rows - (menu->arows + my_top_row);
3030e3d5408SPeter Wemm 	  if (rdiff > menu->arows)
3040e3d5408SPeter Wemm 	    rdiff = menu->arows;
3050e3d5408SPeter Wemm 	  if (rdiff <= 0)
3060e3d5408SPeter Wemm 	    result = E_REQUEST_DENIED;
3070e3d5408SPeter Wemm 	  else
3080e3d5408SPeter Wemm 	    {
3090e3d5408SPeter Wemm 	      my_top_row += rdiff;
3105d08fb1fSRong-En Fan 	      while (rdiff-- > 0 && item != 0 && item->down != 0)
3110e3d5408SPeter Wemm 		item = item->down;
3120e3d5408SPeter Wemm 	    }
3130e3d5408SPeter Wemm 	  break;
3140e3d5408SPeter Wemm 
3150e3d5408SPeter Wemm 	case REQ_SCR_UPAGE:
3160e3d5408SPeter Wemm 	    /*=================*/
3170e3d5408SPeter Wemm 	  rdiff = (menu->arows < my_top_row) ? menu->arows : my_top_row;
3180e3d5408SPeter Wemm 	  if (rdiff <= 0)
3190e3d5408SPeter Wemm 	    result = E_REQUEST_DENIED;
3200e3d5408SPeter Wemm 	  else
3210e3d5408SPeter Wemm 	    {
3220e3d5408SPeter Wemm 	      my_top_row -= rdiff;
3235d08fb1fSRong-En Fan 	      while (rdiff-- > 0 && item != 0 && item->up != 0)
3240e3d5408SPeter Wemm 		item = item->up;
3250e3d5408SPeter Wemm 	    }
3260e3d5408SPeter Wemm 	  break;
3270e3d5408SPeter Wemm 
3280e3d5408SPeter Wemm 	case REQ_FIRST_ITEM:
3290e3d5408SPeter Wemm 	    /*==================*/
3300e3d5408SPeter Wemm 	  item = menu->items[0];
3310e3d5408SPeter Wemm 	  break;
3320e3d5408SPeter Wemm 
3330e3d5408SPeter Wemm 	case REQ_LAST_ITEM:
3340e3d5408SPeter Wemm 	    /*=================*/
3350e3d5408SPeter Wemm 	  item = menu->items[menu->nitems - 1];
3360e3d5408SPeter Wemm 	  break;
3370e3d5408SPeter Wemm 
3380e3d5408SPeter Wemm 	case REQ_NEXT_ITEM:
3390e3d5408SPeter Wemm 	    /*=================*/
3400e3d5408SPeter Wemm 	  if ((item->index + 1) >= menu->nitems)
3410e3d5408SPeter Wemm 	    {
3420e3d5408SPeter Wemm 	      if (menu->opt & O_NONCYCLIC)
3430e3d5408SPeter Wemm 		result = E_REQUEST_DENIED;
3440e3d5408SPeter Wemm 	      else
3450e3d5408SPeter Wemm 		item = menu->items[0];
3460e3d5408SPeter Wemm 	    }
3470e3d5408SPeter Wemm 	  else
3480e3d5408SPeter Wemm 	    item = menu->items[item->index + 1];
3490e3d5408SPeter Wemm 	  break;
3500e3d5408SPeter Wemm 
3510e3d5408SPeter Wemm 	case REQ_PREV_ITEM:
3520e3d5408SPeter Wemm 	    /*=================*/
3530e3d5408SPeter Wemm 	  if (item->index <= 0)
3540e3d5408SPeter Wemm 	    {
3550e3d5408SPeter Wemm 	      if (menu->opt & O_NONCYCLIC)
3560e3d5408SPeter Wemm 		result = E_REQUEST_DENIED;
3570e3d5408SPeter Wemm 	      else
3580e3d5408SPeter Wemm 		item = menu->items[menu->nitems - 1];
3590e3d5408SPeter Wemm 	    }
3600e3d5408SPeter Wemm 	  else
3610e3d5408SPeter Wemm 	    item = menu->items[item->index - 1];
3620e3d5408SPeter Wemm 	  break;
3630e3d5408SPeter Wemm 
3640e3d5408SPeter Wemm 	case REQ_TOGGLE_ITEM:
3650e3d5408SPeter Wemm 	    /*===================*/
3660e3d5408SPeter Wemm 	  if (menu->opt & O_ONEVALUE)
3670e3d5408SPeter Wemm 	    {
3680e3d5408SPeter Wemm 	      result = E_REQUEST_DENIED;
3690e3d5408SPeter Wemm 	    }
3700e3d5408SPeter Wemm 	  else
3710e3d5408SPeter Wemm 	    {
3720e3d5408SPeter Wemm 	      if (menu->curitem->opt & O_SELECTABLE)
3730e3d5408SPeter Wemm 		{
3740e3d5408SPeter Wemm 		  menu->curitem->value = !menu->curitem->value;
3750e3d5408SPeter Wemm 		  Move_And_Post_Item(menu, menu->curitem);
3760e3d5408SPeter Wemm 		  _nc_Show_Menu(menu);
3770e3d5408SPeter Wemm 		}
3780e3d5408SPeter Wemm 	      else
3790e3d5408SPeter Wemm 		result = E_NOT_SELECTABLE;
3800e3d5408SPeter Wemm 	    }
3810e3d5408SPeter Wemm 	  break;
3820e3d5408SPeter Wemm 
3830e3d5408SPeter Wemm 	case REQ_CLEAR_PATTERN:
3840e3d5408SPeter Wemm 	    /*=====================*/
3850e3d5408SPeter Wemm 	  /* already cleared in prologue */
3860e3d5408SPeter Wemm 	  break;
3870e3d5408SPeter Wemm 
3880e3d5408SPeter Wemm 	case REQ_BACK_PATTERN:
3890e3d5408SPeter Wemm 	    /*====================*/
3900e3d5408SPeter Wemm 	  if (menu->pindex > 0)
3910e3d5408SPeter Wemm 	    {
3920e3d5408SPeter Wemm 	      assert(menu->pattern);
3930e3d5408SPeter Wemm 	      Remove_Character_From_Pattern(menu);
3940e3d5408SPeter Wemm 	      pos_menu_cursor(menu);
3950e3d5408SPeter Wemm 	    }
3960e3d5408SPeter Wemm 	  else
3970e3d5408SPeter Wemm 	    result = E_REQUEST_DENIED;
3980e3d5408SPeter Wemm 	  break;
3990e3d5408SPeter Wemm 
4000e3d5408SPeter Wemm 	case REQ_NEXT_MATCH:
4010e3d5408SPeter Wemm 	    /*==================*/
4020e3d5408SPeter Wemm 	  assert(menu->pattern);
4030e3d5408SPeter Wemm 	  if (menu->pattern[0])
4040e3d5408SPeter Wemm 	    result = _nc_Match_Next_Character_In_Item_Name(menu, 0, &item);
4050e3d5408SPeter Wemm 	  else
4060e3d5408SPeter Wemm 	    {
4070e3d5408SPeter Wemm 	      if ((item->index + 1) < menu->nitems)
4080e3d5408SPeter Wemm 		item = menu->items[item->index + 1];
4090e3d5408SPeter Wemm 	      else
4100e3d5408SPeter Wemm 		{
4110e3d5408SPeter Wemm 		  if (menu->opt & O_NONCYCLIC)
4120e3d5408SPeter Wemm 		    result = E_REQUEST_DENIED;
4130e3d5408SPeter Wemm 		  else
4140e3d5408SPeter Wemm 		    item = menu->items[0];
4150e3d5408SPeter Wemm 		}
4160e3d5408SPeter Wemm 	    }
4170e3d5408SPeter Wemm 	  break;
4180e3d5408SPeter Wemm 
4190e3d5408SPeter Wemm 	case REQ_PREV_MATCH:
4200e3d5408SPeter Wemm 	    /*==================*/
4210e3d5408SPeter Wemm 	  assert(menu->pattern);
4220e3d5408SPeter Wemm 	  if (menu->pattern[0])
4230e3d5408SPeter Wemm 	    result = _nc_Match_Next_Character_In_Item_Name(menu, BS, &item);
4240e3d5408SPeter Wemm 	  else
4250e3d5408SPeter Wemm 	    {
4260e3d5408SPeter Wemm 	      if (item->index)
4270e3d5408SPeter Wemm 		item = menu->items[item->index - 1];
4280e3d5408SPeter Wemm 	      else
4290e3d5408SPeter Wemm 		{
4300e3d5408SPeter Wemm 		  if (menu->opt & O_NONCYCLIC)
4310e3d5408SPeter Wemm 		    result = E_REQUEST_DENIED;
4320e3d5408SPeter Wemm 		  else
4330e3d5408SPeter Wemm 		    item = menu->items[menu->nitems - 1];
4340e3d5408SPeter Wemm 		}
4350e3d5408SPeter Wemm 	    }
4360e3d5408SPeter Wemm 	  break;
4370e3d5408SPeter Wemm 
4380e3d5408SPeter Wemm 	default:
4390e3d5408SPeter Wemm 	    /*======*/
4400e3d5408SPeter Wemm 	  result = E_UNKNOWN_COMMAND;
4410e3d5408SPeter Wemm 	  break;
4420e3d5408SPeter Wemm 	}
4430e3d5408SPeter Wemm     }
4440e3d5408SPeter Wemm   else
4450e3d5408SPeter Wemm     {				/* not a command */
4464a1a9510SRong-En Fan       if (!(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(UChar(c)))
4470e3d5408SPeter Wemm 	result = _nc_Match_Next_Character_In_Item_Name(menu, c, &item);
4480e3d5408SPeter Wemm #ifdef NCURSES_MOUSE_VERSION
4490e3d5408SPeter Wemm       else if (KEY_MOUSE == c)
4500e3d5408SPeter Wemm 	{
4510e3d5408SPeter Wemm 	  MEVENT event;
4520e3d5408SPeter Wemm 	  WINDOW *uwin = Get_Menu_UserWin(menu);
4530e3d5408SPeter Wemm 
4540e3d5408SPeter Wemm 	  getmouse(&event);
4550e3d5408SPeter Wemm 	  if ((event.bstate & (BUTTON1_CLICKED |
4560e3d5408SPeter Wemm 			       BUTTON1_DOUBLE_CLICKED |
4570e3d5408SPeter Wemm 			       BUTTON1_TRIPLE_CLICKED))
4580e3d5408SPeter Wemm 	      && wenclose(uwin, event.y, event.x))
4590e3d5408SPeter Wemm 	    {			/* we react only if the click was in the userwin, that means
4600e3d5408SPeter Wemm 				 * inside the menu display area or at the decoration window.
4610e3d5408SPeter Wemm 				 */
4620e3d5408SPeter Wemm 	      WINDOW *sub = Get_Menu_Window(menu);
4630e3d5408SPeter Wemm 	      int ry = event.y, rx = event.x;	/* screen coordinates */
4640e3d5408SPeter Wemm 
4650e3d5408SPeter Wemm 	      result = E_REQUEST_DENIED;
4660e3d5408SPeter Wemm 	      if (mouse_trafo(&ry, &rx, FALSE))
4670e3d5408SPeter Wemm 		{		/* rx, ry are now "curses" coordinates */
4680e3d5408SPeter Wemm 		  if (ry < sub->_begy)
4690e3d5408SPeter Wemm 		    {		/* we clicked above the display region; this is
4700e3d5408SPeter Wemm 				 * interpreted as "scroll up" request
4710e3d5408SPeter Wemm 				 */
4720e3d5408SPeter Wemm 		      if (event.bstate & BUTTON1_CLICKED)
4730e3d5408SPeter Wemm 			result = menu_driver(menu, REQ_SCR_ULINE);
4740e3d5408SPeter Wemm 		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4750e3d5408SPeter Wemm 			result = menu_driver(menu, REQ_SCR_UPAGE);
4760e3d5408SPeter Wemm 		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4770e3d5408SPeter Wemm 			result = menu_driver(menu, REQ_FIRST_ITEM);
4780e3d5408SPeter Wemm 		      RETURN(result);
4790e3d5408SPeter Wemm 		    }
4804a1a9510SRong-En Fan 		  else if (ry > sub->_begy + sub->_maxy)
4810e3d5408SPeter Wemm 		    {		/* we clicked below the display region; this is
4820e3d5408SPeter Wemm 				 * interpreted as "scroll down" request
4830e3d5408SPeter Wemm 				 */
4840e3d5408SPeter Wemm 		      if (event.bstate & BUTTON1_CLICKED)
4850e3d5408SPeter Wemm 			result = menu_driver(menu, REQ_SCR_DLINE);
4860e3d5408SPeter Wemm 		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4870e3d5408SPeter Wemm 			result = menu_driver(menu, REQ_SCR_DPAGE);
4880e3d5408SPeter Wemm 		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4890e3d5408SPeter Wemm 			result = menu_driver(menu, REQ_LAST_ITEM);
4900e3d5408SPeter Wemm 		      RETURN(result);
4910e3d5408SPeter Wemm 		    }
4920e3d5408SPeter Wemm 		  else if (wenclose(sub, event.y, event.x))
4930e3d5408SPeter Wemm 		    {		/* Inside the area we try to find the hit item */
494*21817992SBaptiste Daroussin 		      int x, y;
4954a1a9510SRong-En Fan 
4964a1a9510SRong-En Fan 		      ry = event.y;
4974a1a9510SRong-En Fan 		      rx = event.x;
4980e3d5408SPeter Wemm 		      if (wmouse_trafo(sub, &ry, &rx, FALSE))
4990e3d5408SPeter Wemm 			{
500*21817992SBaptiste Daroussin 			  int i;
501*21817992SBaptiste Daroussin 
5020e3d5408SPeter Wemm 			  for (i = 0; i < menu->nitems; i++)
5030e3d5408SPeter Wemm 			    {
504*21817992SBaptiste Daroussin 			      int err = _nc_menu_cursor_pos(menu,
505*21817992SBaptiste Daroussin 							    menu->items[i],
5060e3d5408SPeter Wemm 							    &y, &x);
507*21817992SBaptiste Daroussin 
5080e3d5408SPeter Wemm 			      if (E_OK == err)
5090e3d5408SPeter Wemm 				{
5100e3d5408SPeter Wemm 				  if ((ry == y) &&
5110e3d5408SPeter Wemm 				      (rx >= x) &&
5120e3d5408SPeter Wemm 				      (rx < x + menu->itemlen))
5130e3d5408SPeter Wemm 				    {
5140e3d5408SPeter Wemm 				      item = menu->items[i];
5150e3d5408SPeter Wemm 				      result = E_OK;
5160e3d5408SPeter Wemm 				      break;
5170e3d5408SPeter Wemm 				    }
5180e3d5408SPeter Wemm 				}
5190e3d5408SPeter Wemm 			    }
5200e3d5408SPeter Wemm 			  if (E_OK == result)
5210e3d5408SPeter Wemm 			    {	/* We found an item, now we can handle the click.
5220e3d5408SPeter Wemm 				 * A single click just positions the menu cursor
5230e3d5408SPeter Wemm 				 * to the clicked item. A double click toggles
5240e3d5408SPeter Wemm 				 * the item.
5250e3d5408SPeter Wemm 				 */
5260e3d5408SPeter Wemm 			      if (event.bstate & BUTTON1_DOUBLE_CLICKED)
5270e3d5408SPeter Wemm 				{
5280e3d5408SPeter Wemm 				  _nc_New_TopRow_and_CurrentItem(menu,
5290e3d5408SPeter Wemm 								 my_top_row,
5300e3d5408SPeter Wemm 								 item);
5310e3d5408SPeter Wemm 				  menu_driver(menu, REQ_TOGGLE_ITEM);
5320e3d5408SPeter Wemm 				  result = E_UNKNOWN_COMMAND;
5330e3d5408SPeter Wemm 				}
5340e3d5408SPeter Wemm 			    }
5350e3d5408SPeter Wemm 			}
5360e3d5408SPeter Wemm 		    }
5370e3d5408SPeter Wemm 		}
5380e3d5408SPeter Wemm 	    }
5390e3d5408SPeter Wemm 	  else
540aae38d10SBaptiste Daroussin 	    {
541aae38d10SBaptiste Daroussin 	      if (menu->opt & O_MOUSE_MENU)
542aae38d10SBaptiste Daroussin 		ungetmouse(&event);	/* let someone else handle this */
5430e3d5408SPeter Wemm 	      result = E_REQUEST_DENIED;
5440e3d5408SPeter Wemm 	    }
545aae38d10SBaptiste Daroussin 	}
5460e3d5408SPeter Wemm #endif /* NCURSES_MOUSE_VERSION */
5470e3d5408SPeter Wemm       else
5480e3d5408SPeter Wemm 	result = E_UNKNOWN_COMMAND;
5490e3d5408SPeter Wemm     }
5500e3d5408SPeter Wemm 
55173f0a83dSXin LI   if (item == 0)
55273f0a83dSXin LI     {
55373f0a83dSXin LI       result = E_BAD_STATE;
55473f0a83dSXin LI     }
55573f0a83dSXin LI   else if (E_OK == result)
5560e3d5408SPeter Wemm     {
5570e3d5408SPeter Wemm       /* Adjust the top row if it turns out that the current item unfortunately
5580e3d5408SPeter Wemm          doesn't appear in the menu window */
5590e3d5408SPeter Wemm       if (item->y < my_top_row)
5600e3d5408SPeter Wemm 	my_top_row = item->y;
5610e3d5408SPeter Wemm       else if (item->y >= (my_top_row + menu->arows))
5620e3d5408SPeter Wemm 	my_top_row = item->y - menu->arows + 1;
5630e3d5408SPeter Wemm 
5640e3d5408SPeter Wemm       _nc_New_TopRow_and_CurrentItem(menu, my_top_row, item);
5650e3d5408SPeter Wemm 
5660e3d5408SPeter Wemm     }
5670e3d5408SPeter Wemm 
5680e3d5408SPeter Wemm   RETURN(result);
5690e3d5408SPeter Wemm }
5700e3d5408SPeter Wemm 
5710e3d5408SPeter Wemm /* m_driver.c ends here */
572