xref: /openbsd-src/lib/libmenu/m_driver.c (revision c7ef0cfc17afcba97172c25e1e3a943e893bc632)
1*c7ef0cfcSnicm /* $OpenBSD: m_driver.c,v 1.9 2023/10/17 09:52:10 nicm Exp $ */
29f1aa62bSmillert 
3457960bfSmillert /****************************************************************************
4*c7ef0cfcSnicm  * Copyright 2020,2021 Thomas E. Dickey                                     *
5*c7ef0cfcSnicm  * Copyright 1998-2012,2016 Free Software Foundation, Inc.                  *
6457960bfSmillert  *                                                                          *
7457960bfSmillert  * Permission is hereby granted, free of charge, to any person obtaining a  *
8457960bfSmillert  * copy of this software and associated documentation files (the            *
9457960bfSmillert  * "Software"), to deal in the Software without restriction, including      *
10457960bfSmillert  * without limitation the rights to use, copy, modify, merge, publish,      *
11457960bfSmillert  * distribute, distribute with modifications, sublicense, and/or sell       *
12457960bfSmillert  * copies of the Software, and to permit persons to whom the Software is    *
13457960bfSmillert  * furnished to do so, subject to the following conditions:                 *
14457960bfSmillert  *                                                                          *
15457960bfSmillert  * The above copyright notice and this permission notice shall be included  *
16457960bfSmillert  * in all copies or substantial portions of the Software.                   *
17457960bfSmillert  *                                                                          *
18457960bfSmillert  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
19457960bfSmillert  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
20457960bfSmillert  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
21457960bfSmillert  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
22457960bfSmillert  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
23457960bfSmillert  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
24457960bfSmillert  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
25457960bfSmillert  *                                                                          *
26457960bfSmillert  * Except as contained in this notice, the name(s) of the above copyright   *
27457960bfSmillert  * holders shall not be used in advertising or otherwise to promote the     *
28457960bfSmillert  * sale, use or other dealings in this Software without prior written       *
29457960bfSmillert  * authorization.                                                           *
30457960bfSmillert  ****************************************************************************/
31457960bfSmillert 
32457960bfSmillert /****************************************************************************
3381d8c4e1Snicm  *   Author:  Juergen Pfeifer, 1995,1997                                    *
34457960bfSmillert  ****************************************************************************/
35c166cd22Stholo 
36c166cd22Stholo /***************************************************************************
379f1aa62bSmillert * Module m_driver                                                          *
389f1aa62bSmillert * Central dispatching routine                                              *
39c166cd22Stholo ***************************************************************************/
40c166cd22Stholo 
41c166cd22Stholo #include "menu.priv.h"
42c166cd22Stholo 
43*c7ef0cfcSnicm MODULE_ID("$Id: m_driver.c,v 1.9 2023/10/17 09:52:10 nicm Exp $")
440107aba4Smillert 
45c166cd22Stholo /* Macros */
46c166cd22Stholo 
47c166cd22Stholo /* Remove the last character from the match pattern buffer */
48c166cd22Stholo #define Remove_Character_From_Pattern(menu) \
49c166cd22Stholo   (menu)->pattern[--((menu)->pindex)] = '\0'
50c166cd22Stholo 
51c166cd22Stholo /* Add a new character to the match pattern buffer */
52c166cd22Stholo #define Add_Character_To_Pattern(menu,ch) \
53*c7ef0cfcSnicm   { (menu)->pattern[((menu)->pindex)++] = (char) (ch);\
54c166cd22Stholo     (menu)->pattern[(menu)->pindex] = '\0'; }
55c166cd22Stholo 
56c166cd22Stholo /*---------------------------------------------------------------------------
57c166cd22Stholo |   Facility      :  libnmenu
58c166cd22Stholo |   Function      :  static bool Is_Sub_String(
59c166cd22Stholo |                           bool IgnoreCaseFlag,
60c166cd22Stholo |                           const char *part,
61c166cd22Stholo |                           const char *string)
62c166cd22Stholo |
63c166cd22Stholo |   Description   :  Checks whether or not part is a substring of string.
64c166cd22Stholo |
65c166cd22Stholo |   Return Values :  TRUE   - if it is a substring
66c166cd22Stholo |                    FALSE  - if it is not a substring
67c166cd22Stholo +--------------------------------------------------------------------------*/
6881d8c4e1Snicm static bool
Is_Sub_String(bool IgnoreCaseFlag,const char * part,const char * string)6981d8c4e1Snicm Is_Sub_String(
70c166cd22Stholo 	       bool IgnoreCaseFlag,
71c166cd22Stholo 	       const char *part,
72c166cd22Stholo 	       const char *string
73c166cd22Stholo )
74c166cd22Stholo {
75c166cd22Stholo   assert(part && string);
76c166cd22Stholo   if (IgnoreCaseFlag)
77c166cd22Stholo     {
78c166cd22Stholo       while (*string && *part)
79c166cd22Stholo 	{
8081d8c4e1Snicm 	  if (toupper(UChar(*string++)) != toupper(UChar(*part)))
8181d8c4e1Snicm 	    break;
82c166cd22Stholo 	  part++;
83c166cd22Stholo 	}
84c166cd22Stholo     }
85c166cd22Stholo   else
86c166cd22Stholo     {
87c166cd22Stholo       while (*string && *part)
8881d8c4e1Snicm 	if (*part != *string++)
8981d8c4e1Snicm 	  break;
90c166cd22Stholo       part++;
91c166cd22Stholo     }
92c166cd22Stholo   return ((*part) ? FALSE : TRUE);
93c166cd22Stholo }
94c166cd22Stholo 
95c166cd22Stholo /*---------------------------------------------------------------------------
96c166cd22Stholo |   Facility      :  libnmenu
979f1aa62bSmillert |   Function      :  int _nc_Match_Next_Character_In_Item_Name(
98c166cd22Stholo |                           MENU *menu,
99c166cd22Stholo |                           int  ch,
100c166cd22Stholo |                           ITEM **item)
101c166cd22Stholo |
102c166cd22Stholo |   Description   :  This internal routine is called for a menu positioned
103c166cd22Stholo |                    at an item with three different classes of characters:
104c166cd22Stholo |                       - a printable character; the character is added to
105c166cd22Stholo |                         the current pattern and the next item matching
106c166cd22Stholo |                         this pattern is searched.
107c166cd22Stholo |                       - NUL; the pattern stays as it is and the next item
108c166cd22Stholo |                         matching the pattern is searched
109c166cd22Stholo |                       - BS; the pattern stays as it is and the previous
110c166cd22Stholo |                         item matching the pattern is searched
111c166cd22Stholo |
112c166cd22Stholo |                       The item parameter contains on call a pointer to
113c166cd22Stholo |                       the item where the search starts. On return - if
114c166cd22Stholo |                       a match was found - it contains a pointer to the
115c166cd22Stholo |                       matching item.
116c166cd22Stholo |
117c166cd22Stholo |   Return Values :  E_OK        - an item matching the pattern was found
118c166cd22Stholo |                    E_NO_MATCH  - nothing found
119c166cd22Stholo +--------------------------------------------------------------------------*/
120*c7ef0cfcSnicm MENU_EXPORT(int)
_nc_Match_Next_Character_In_Item_Name(MENU * menu,int ch,ITEM ** item)12184af20ceSmillert _nc_Match_Next_Character_In_Item_Name
12284af20ceSmillert (MENU *menu, int ch, ITEM **item)
123c166cd22Stholo {
124c166cd22Stholo   bool found = FALSE, passed = FALSE;
125c166cd22Stholo   int idx, last;
126c166cd22Stholo 
127*c7ef0cfcSnicm   T((T_CALLED("_nc_Match_Next_Character(%p,%d,%p)"),
128*c7ef0cfcSnicm      (void *)menu, ch, (void *)item));
12981d8c4e1Snicm 
130c166cd22Stholo   assert(menu && item && *item);
131c166cd22Stholo   idx = (*item)->index;
132c166cd22Stholo 
133c166cd22Stholo   if (ch && ch != BS)
134c166cd22Stholo     {
135c166cd22Stholo       /* if we become to long, we need no further checking : there can't be
136c166cd22Stholo          a match ! */
137c166cd22Stholo       if ((menu->pindex + 1) > menu->namelen)
138c166cd22Stholo 	RETURN(E_NO_MATCH);
139c166cd22Stholo 
140c166cd22Stholo       Add_Character_To_Pattern(menu, ch);
141c166cd22Stholo       /* we artificially position one item back, because in the do...while
142c166cd22Stholo          loop we start with the next item. This means, that with a new
143c166cd22Stholo          pattern search we always start the scan with the actual item. If
144*c7ef0cfcSnicm          we do a NEXT_PATTERN or PREV_PATTERN search, we start with the
145c166cd22Stholo          one after or before the actual item. */
146c166cd22Stholo       if (--idx < 0)
147c166cd22Stholo 	idx = menu->nitems - 1;
148c166cd22Stholo     }
149c166cd22Stholo 
150c166cd22Stholo   last = idx;			/* this closes the cycle */
151c166cd22Stholo 
15281d8c4e1Snicm   do
15381d8c4e1Snicm     {
154c166cd22Stholo       if (ch == BS)
155c166cd22Stholo 	{			/* we have to go backward */
156c166cd22Stholo 	  if (--idx < 0)
157c166cd22Stholo 	    idx = menu->nitems - 1;
158c166cd22Stholo 	}
159c166cd22Stholo       else
160c166cd22Stholo 	{			/* otherwise we always go forward */
161c166cd22Stholo 	  if (++idx >= menu->nitems)
162c166cd22Stholo 	    idx = 0;
163c166cd22Stholo 	}
16481d8c4e1Snicm       if (Is_Sub_String((bool)((menu->opt & O_IGNORECASE) != 0),
165c166cd22Stholo 			menu->pattern,
166c166cd22Stholo 			menu->items[idx]->name.str)
167c166cd22Stholo 	)
168c166cd22Stholo 	found = TRUE;
169c166cd22Stholo       else
170c166cd22Stholo 	passed = TRUE;
17181d8c4e1Snicm     }
17281d8c4e1Snicm   while (!found && (idx != last));
173c166cd22Stholo 
174c166cd22Stholo   if (found)
175c166cd22Stholo     {
176c166cd22Stholo       if (!((idx == (*item)->index) && passed))
177c166cd22Stholo 	{
178c166cd22Stholo 	  *item = menu->items[idx];
179c166cd22Stholo 	  RETURN(E_OK);
180c166cd22Stholo 	}
181c166cd22Stholo       /* This point is reached, if we fully cycled through the item list
182c166cd22Stholo          and the only match we found is the starting item. With a NEXT_PATTERN
183c166cd22Stholo          or PREV_PATTERN scan this means, that there was no additional match.
184c166cd22Stholo          If we searched with an expanded new pattern, we should never reach
185c166cd22Stholo          this point, because if the expanded pattern matches also the actual
186c166cd22Stholo          item we will find it in the first attempt (passed==FALSE) and we
187c166cd22Stholo          will never cycle through the whole item array.
188c166cd22Stholo        */
189c166cd22Stholo       assert(ch == 0 || ch == BS);
190c166cd22Stholo     }
191c166cd22Stholo   else
192c166cd22Stholo     {
193c166cd22Stholo       if (ch && ch != BS && menu->pindex > 0)
194c166cd22Stholo 	{
195c166cd22Stholo 	  /* if we had no match with a new pattern, we have to restore it */
196c166cd22Stholo 	  Remove_Character_From_Pattern(menu);
197c166cd22Stholo 	}
198c166cd22Stholo     }
199c166cd22Stholo   RETURN(E_NO_MATCH);
200c166cd22Stholo }
201c166cd22Stholo 
202c166cd22Stholo /*---------------------------------------------------------------------------
203c166cd22Stholo |   Facility      :  libnmenu
204c166cd22Stholo |   Function      :  int menu_driver(MENU* menu, int c)
205c166cd22Stholo |
206c166cd22Stholo |   Description   :  Central dispatcher for the menu. Translates the logical
207c166cd22Stholo |                    request 'c' into a menu action.
208c166cd22Stholo |
209c166cd22Stholo |   Return Values :  E_OK            - success
210c166cd22Stholo |                    E_BAD_ARGUMENT  - invalid menu pointer
211c166cd22Stholo |                    E_BAD_STATE     - menu is in user hook routine
212c166cd22Stholo |                    E_NOT_POSTED    - menu is not posted
213c166cd22Stholo +--------------------------------------------------------------------------*/
214*c7ef0cfcSnicm MENU_EXPORT(int)
menu_driver(MENU * menu,int c)21584af20ceSmillert menu_driver(MENU *menu, int c)
216c166cd22Stholo {
217c166cd22Stholo #define NAVIGATE(dir) \
218c166cd22Stholo   if (!item->dir)\
219c166cd22Stholo      result = E_REQUEST_DENIED;\
220c166cd22Stholo   else\
221c166cd22Stholo      item = item->dir
222c166cd22Stholo 
223c166cd22Stholo   int result = E_OK;
224c166cd22Stholo   ITEM *item;
225*c7ef0cfcSnicm   int my_top_row;
226c166cd22Stholo 
227*c7ef0cfcSnicm   T((T_CALLED("menu_driver(%p,%d)"), (void *)menu, c));
22881d8c4e1Snicm 
229c166cd22Stholo   if (!menu)
230c166cd22Stholo     RETURN(E_BAD_ARGUMENT);
231c166cd22Stholo 
232c166cd22Stholo   if (menu->status & _IN_DRIVER)
233c166cd22Stholo     RETURN(E_BAD_STATE);
234c166cd22Stholo   if (!(menu->status & _POSTED))
235c166cd22Stholo     RETURN(E_NOT_POSTED);
236c166cd22Stholo 
237c166cd22Stholo   item = menu->curitem;
2385be68eb8Smillert 
2395be68eb8Smillert   my_top_row = menu->toprow;
240c166cd22Stholo   assert(item);
241c166cd22Stholo 
242c166cd22Stholo   if ((c > KEY_MAX) && (c <= MAX_MENU_COMMAND))
243c166cd22Stholo     {
244*c7ef0cfcSnicm       int rdiff;
245*c7ef0cfcSnicm 
246c166cd22Stholo       if (!((c == REQ_BACK_PATTERN)
247c166cd22Stholo 	    || (c == REQ_NEXT_MATCH) || (c == REQ_PREV_MATCH)))
248c166cd22Stholo 	{
249c166cd22Stholo 	  assert(menu->pattern);
250c166cd22Stholo 	  Reset_Pattern(menu);
251c166cd22Stholo 	}
252c166cd22Stholo 
253c166cd22Stholo       switch (c)
254c166cd22Stholo 	{
255c166cd22Stholo 	case REQ_LEFT_ITEM:
256c166cd22Stholo 	    /*=================*/
257c166cd22Stholo 	  NAVIGATE(left);
258c166cd22Stholo 	  break;
259c166cd22Stholo 
260c166cd22Stholo 	case REQ_RIGHT_ITEM:
261c166cd22Stholo 	    /*==================*/
262c166cd22Stholo 	  NAVIGATE(right);
263c166cd22Stholo 	  break;
264c166cd22Stholo 
265c166cd22Stholo 	case REQ_UP_ITEM:
266c166cd22Stholo 	    /*===============*/
267c166cd22Stholo 	  NAVIGATE(up);
268c166cd22Stholo 	  break;
269c166cd22Stholo 
270c166cd22Stholo 	case REQ_DOWN_ITEM:
271c166cd22Stholo 	    /*=================*/
272c166cd22Stholo 	  NAVIGATE(down);
273c166cd22Stholo 	  break;
274c166cd22Stholo 
275c166cd22Stholo 	case REQ_SCR_ULINE:
276c166cd22Stholo 	    /*=================*/
2775be68eb8Smillert 	  if (my_top_row == 0 || !(item->up))
278c166cd22Stholo 	    result = E_REQUEST_DENIED;
279c166cd22Stholo 	  else
280c166cd22Stholo 	    {
281c166cd22Stholo 	      --my_top_row;
282c166cd22Stholo 	      item = item->up;
283c166cd22Stholo 	    }
284c166cd22Stholo 	  break;
285c166cd22Stholo 
286c166cd22Stholo 	case REQ_SCR_DLINE:
287c166cd22Stholo 	    /*=================*/
2885be68eb8Smillert 	  if ((my_top_row + menu->arows >= menu->rows) || !(item->down))
289c166cd22Stholo 	    {
290c166cd22Stholo 	      /* only if the menu has less items than rows, we can deny the
291c166cd22Stholo 	         request. Otherwise the epilogue of this routine adjusts the
292c166cd22Stholo 	         top row if necessary */
293c166cd22Stholo 	      result = E_REQUEST_DENIED;
294c166cd22Stholo 	    }
29581d8c4e1Snicm 	  else
29681d8c4e1Snicm 	    {
2975be68eb8Smillert 	      my_top_row++;
298c166cd22Stholo 	      item = item->down;
2995be68eb8Smillert 	    }
300c166cd22Stholo 	  break;
301c166cd22Stholo 
302c166cd22Stholo 	case REQ_SCR_DPAGE:
303c166cd22Stholo 	    /*=================*/
3045be68eb8Smillert 	  rdiff = menu->rows - (menu->arows + my_top_row);
3050107aba4Smillert 	  if (rdiff > menu->arows)
3060107aba4Smillert 	    rdiff = menu->arows;
3075be68eb8Smillert 	  if (rdiff <= 0)
308c166cd22Stholo 	    result = E_REQUEST_DENIED;
309c166cd22Stholo 	  else
310c166cd22Stholo 	    {
311c166cd22Stholo 	      my_top_row += rdiff;
31281d8c4e1Snicm 	      while (rdiff-- > 0 && item != 0 && item->down != 0)
313c166cd22Stholo 		item = item->down;
314c166cd22Stholo 	    }
315c166cd22Stholo 	  break;
316c166cd22Stholo 
317c166cd22Stholo 	case REQ_SCR_UPAGE:
318c166cd22Stholo 	    /*=================*/
3195be68eb8Smillert 	  rdiff = (menu->arows < my_top_row) ? menu->arows : my_top_row;
3205be68eb8Smillert 	  if (rdiff <= 0)
321c166cd22Stholo 	    result = E_REQUEST_DENIED;
322c166cd22Stholo 	  else
323c166cd22Stholo 	    {
324c166cd22Stholo 	      my_top_row -= rdiff;
32581d8c4e1Snicm 	      while (rdiff-- > 0 && item != 0 && item->up != 0)
326c166cd22Stholo 		item = item->up;
327c166cd22Stholo 	    }
328c166cd22Stholo 	  break;
329c166cd22Stholo 
330c166cd22Stholo 	case REQ_FIRST_ITEM:
331c166cd22Stholo 	    /*==================*/
332c166cd22Stholo 	  item = menu->items[0];
333c166cd22Stholo 	  break;
334c166cd22Stholo 
335c166cd22Stholo 	case REQ_LAST_ITEM:
336c166cd22Stholo 	    /*=================*/
337c166cd22Stholo 	  item = menu->items[menu->nitems - 1];
338c166cd22Stholo 	  break;
339c166cd22Stholo 
340c166cd22Stholo 	case REQ_NEXT_ITEM:
341c166cd22Stholo 	    /*=================*/
342c166cd22Stholo 	  if ((item->index + 1) >= menu->nitems)
343c166cd22Stholo 	    {
344c166cd22Stholo 	      if (menu->opt & O_NONCYCLIC)
345c166cd22Stholo 		result = E_REQUEST_DENIED;
346c166cd22Stholo 	      else
347c166cd22Stholo 		item = menu->items[0];
348c166cd22Stholo 	    }
349c166cd22Stholo 	  else
350c166cd22Stholo 	    item = menu->items[item->index + 1];
351c166cd22Stholo 	  break;
352c166cd22Stholo 
353c166cd22Stholo 	case REQ_PREV_ITEM:
354c166cd22Stholo 	    /*=================*/
355c166cd22Stholo 	  if (item->index <= 0)
356c166cd22Stholo 	    {
357c166cd22Stholo 	      if (menu->opt & O_NONCYCLIC)
358c166cd22Stholo 		result = E_REQUEST_DENIED;
359c166cd22Stholo 	      else
360c166cd22Stholo 		item = menu->items[menu->nitems - 1];
361c166cd22Stholo 	    }
362c166cd22Stholo 	  else
363c166cd22Stholo 	    item = menu->items[item->index - 1];
364c166cd22Stholo 	  break;
365c166cd22Stholo 
366c166cd22Stholo 	case REQ_TOGGLE_ITEM:
367c166cd22Stholo 	    /*===================*/
368c166cd22Stholo 	  if (menu->opt & O_ONEVALUE)
369c166cd22Stholo 	    {
370c166cd22Stholo 	      result = E_REQUEST_DENIED;
371c166cd22Stholo 	    }
372c166cd22Stholo 	  else
373c166cd22Stholo 	    {
374c166cd22Stholo 	      if (menu->curitem->opt & O_SELECTABLE)
375c166cd22Stholo 		{
3760107aba4Smillert 		  menu->curitem->value = !menu->curitem->value;
377c166cd22Stholo 		  Move_And_Post_Item(menu, menu->curitem);
378c166cd22Stholo 		  _nc_Show_Menu(menu);
379c166cd22Stholo 		}
380c166cd22Stholo 	      else
381c166cd22Stholo 		result = E_NOT_SELECTABLE;
382c166cd22Stholo 	    }
383c166cd22Stholo 	  break;
384c166cd22Stholo 
385c166cd22Stholo 	case REQ_CLEAR_PATTERN:
386c166cd22Stholo 	    /*=====================*/
387c166cd22Stholo 	  /* already cleared in prologue */
388c166cd22Stholo 	  break;
389c166cd22Stholo 
390c166cd22Stholo 	case REQ_BACK_PATTERN:
391c166cd22Stholo 	    /*====================*/
392c166cd22Stholo 	  if (menu->pindex > 0)
393c166cd22Stholo 	    {
394c166cd22Stholo 	      assert(menu->pattern);
395c166cd22Stholo 	      Remove_Character_From_Pattern(menu);
396c166cd22Stholo 	      pos_menu_cursor(menu);
397c166cd22Stholo 	    }
398c166cd22Stholo 	  else
399c166cd22Stholo 	    result = E_REQUEST_DENIED;
400c166cd22Stholo 	  break;
401c166cd22Stholo 
402c166cd22Stholo 	case REQ_NEXT_MATCH:
403c166cd22Stholo 	    /*==================*/
404c166cd22Stholo 	  assert(menu->pattern);
405c166cd22Stholo 	  if (menu->pattern[0])
4069f1aa62bSmillert 	    result = _nc_Match_Next_Character_In_Item_Name(menu, 0, &item);
407c166cd22Stholo 	  else
408c166cd22Stholo 	    {
409c166cd22Stholo 	      if ((item->index + 1) < menu->nitems)
410c166cd22Stholo 		item = menu->items[item->index + 1];
411c166cd22Stholo 	      else
412c166cd22Stholo 		{
413c166cd22Stholo 		  if (menu->opt & O_NONCYCLIC)
414c166cd22Stholo 		    result = E_REQUEST_DENIED;
415c166cd22Stholo 		  else
416c166cd22Stholo 		    item = menu->items[0];
417c166cd22Stholo 		}
418c166cd22Stholo 	    }
419c166cd22Stholo 	  break;
420c166cd22Stholo 
421c166cd22Stholo 	case REQ_PREV_MATCH:
422c166cd22Stholo 	    /*==================*/
423c166cd22Stholo 	  assert(menu->pattern);
424c166cd22Stholo 	  if (menu->pattern[0])
4259f1aa62bSmillert 	    result = _nc_Match_Next_Character_In_Item_Name(menu, BS, &item);
426c166cd22Stholo 	  else
427c166cd22Stholo 	    {
428c166cd22Stholo 	      if (item->index)
429c166cd22Stholo 		item = menu->items[item->index - 1];
430c166cd22Stholo 	      else
431c166cd22Stholo 		{
432c166cd22Stholo 		  if (menu->opt & O_NONCYCLIC)
433c166cd22Stholo 		    result = E_REQUEST_DENIED;
434c166cd22Stholo 		  else
435c166cd22Stholo 		    item = menu->items[menu->nitems - 1];
436c166cd22Stholo 		}
437c166cd22Stholo 	    }
438c166cd22Stholo 	  break;
439c166cd22Stholo 
440c166cd22Stholo 	default:
441c166cd22Stholo 	    /*======*/
442c166cd22Stholo 	  result = E_UNKNOWN_COMMAND;
443c166cd22Stholo 	  break;
444c166cd22Stholo 	}
445c166cd22Stholo     }
446c166cd22Stholo   else
447c166cd22Stholo     {				/* not a command */
44881d8c4e1Snicm       if (!(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(UChar(c)))
4499f1aa62bSmillert 	result = _nc_Match_Next_Character_In_Item_Name(menu, c, &item);
4505be68eb8Smillert #ifdef NCURSES_MOUSE_VERSION
4515be68eb8Smillert       else if (KEY_MOUSE == c)
4525be68eb8Smillert 	{
4535be68eb8Smillert 	  MEVENT event;
4545be68eb8Smillert 	  WINDOW *uwin = Get_Menu_UserWin(menu);
4555be68eb8Smillert 
4565be68eb8Smillert 	  getmouse(&event);
4575be68eb8Smillert 	  if ((event.bstate & (BUTTON1_CLICKED |
4585be68eb8Smillert 			       BUTTON1_DOUBLE_CLICKED |
4595be68eb8Smillert 			       BUTTON1_TRIPLE_CLICKED))
4605be68eb8Smillert 	      && wenclose(uwin, event.y, event.x))
4615be68eb8Smillert 	    {			/* we react only if the click was in the userwin, that means
4625be68eb8Smillert 				 * inside the menu display area or at the decoration window.
4635be68eb8Smillert 				 */
4645be68eb8Smillert 	      WINDOW *sub = Get_Menu_Window(menu);
4655be68eb8Smillert 	      int ry = event.y, rx = event.x;	/* screen coordinates */
4665be68eb8Smillert 
4675be68eb8Smillert 	      result = E_REQUEST_DENIED;
4685be68eb8Smillert 	      if (mouse_trafo(&ry, &rx, FALSE))
4695be68eb8Smillert 		{		/* rx, ry are now "curses" coordinates */
4705be68eb8Smillert 		  if (ry < sub->_begy)
4715be68eb8Smillert 		    {		/* we clicked above the display region; this is
4725be68eb8Smillert 				 * interpreted as "scroll up" request
4735be68eb8Smillert 				 */
4745be68eb8Smillert 		      if (event.bstate & BUTTON1_CLICKED)
4755be68eb8Smillert 			result = menu_driver(menu, REQ_SCR_ULINE);
4765be68eb8Smillert 		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4775be68eb8Smillert 			result = menu_driver(menu, REQ_SCR_UPAGE);
4785be68eb8Smillert 		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4795be68eb8Smillert 			result = menu_driver(menu, REQ_FIRST_ITEM);
4805be68eb8Smillert 		      RETURN(result);
4815be68eb8Smillert 		    }
48281d8c4e1Snicm 		  else if (ry > sub->_begy + sub->_maxy)
4835be68eb8Smillert 		    {		/* we clicked below the display region; this is
4845be68eb8Smillert 				 * interpreted as "scroll down" request
4855be68eb8Smillert 				 */
4865be68eb8Smillert 		      if (event.bstate & BUTTON1_CLICKED)
4875be68eb8Smillert 			result = menu_driver(menu, REQ_SCR_DLINE);
4885be68eb8Smillert 		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4895be68eb8Smillert 			result = menu_driver(menu, REQ_SCR_DPAGE);
4905be68eb8Smillert 		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4915be68eb8Smillert 			result = menu_driver(menu, REQ_LAST_ITEM);
4925be68eb8Smillert 		      RETURN(result);
4935be68eb8Smillert 		    }
4945be68eb8Smillert 		  else if (wenclose(sub, event.y, event.x))
4955be68eb8Smillert 		    {		/* Inside the area we try to find the hit item */
496*c7ef0cfcSnicm 		      int x, y;
49781d8c4e1Snicm 
49881d8c4e1Snicm 		      ry = event.y;
49981d8c4e1Snicm 		      rx = event.x;
5005be68eb8Smillert 		      if (wmouse_trafo(sub, &ry, &rx, FALSE))
5015be68eb8Smillert 			{
502*c7ef0cfcSnicm 			  int i;
503*c7ef0cfcSnicm 
5045be68eb8Smillert 			  for (i = 0; i < menu->nitems; i++)
5055be68eb8Smillert 			    {
506*c7ef0cfcSnicm 			      int err = _nc_menu_cursor_pos(menu,
507*c7ef0cfcSnicm 							    menu->items[i],
5085be68eb8Smillert 							    &y, &x);
509*c7ef0cfcSnicm 
5105be68eb8Smillert 			      if (E_OK == err)
5115be68eb8Smillert 				{
5125be68eb8Smillert 				  if ((ry == y) &&
5135be68eb8Smillert 				      (rx >= x) &&
5145be68eb8Smillert 				      (rx < x + menu->itemlen))
5155be68eb8Smillert 				    {
5165be68eb8Smillert 				      item = menu->items[i];
5175be68eb8Smillert 				      result = E_OK;
5185be68eb8Smillert 				      break;
5195be68eb8Smillert 				    }
5205be68eb8Smillert 				}
5215be68eb8Smillert 			    }
5225be68eb8Smillert 			  if (E_OK == result)
5235be68eb8Smillert 			    {	/* We found an item, now we can handle the click.
5245be68eb8Smillert 				 * A single click just positions the menu cursor
5255be68eb8Smillert 				 * to the clicked item. A double click toggles
5265be68eb8Smillert 				 * the item.
5275be68eb8Smillert 				 */
5285be68eb8Smillert 			      if (event.bstate & BUTTON1_DOUBLE_CLICKED)
5295be68eb8Smillert 				{
5305be68eb8Smillert 				  _nc_New_TopRow_and_CurrentItem(menu,
5315be68eb8Smillert 								 my_top_row,
5325be68eb8Smillert 								 item);
5335be68eb8Smillert 				  menu_driver(menu, REQ_TOGGLE_ITEM);
5345be68eb8Smillert 				  result = E_UNKNOWN_COMMAND;
5355be68eb8Smillert 				}
5365be68eb8Smillert 			    }
5375be68eb8Smillert 			}
5385be68eb8Smillert 		    }
5395be68eb8Smillert 		}
5405be68eb8Smillert 	    }
5415be68eb8Smillert 	  else
542*c7ef0cfcSnicm 	    {
543*c7ef0cfcSnicm 	      if (menu->opt & O_MOUSE_MENU)
544*c7ef0cfcSnicm 		ungetmouse(&event);	/* let someone else handle this */
5455be68eb8Smillert 	      result = E_REQUEST_DENIED;
5465be68eb8Smillert 	    }
547*c7ef0cfcSnicm 	}
5485be68eb8Smillert #endif /* NCURSES_MOUSE_VERSION */
549c166cd22Stholo       else
550c166cd22Stholo 	result = E_UNKNOWN_COMMAND;
551c166cd22Stholo     }
552c166cd22Stholo 
553*c7ef0cfcSnicm   if (item == 0)
554*c7ef0cfcSnicm     {
555*c7ef0cfcSnicm       result = E_BAD_STATE;
556*c7ef0cfcSnicm     }
557*c7ef0cfcSnicm   else if (E_OK == result)
5585be68eb8Smillert     {
559c166cd22Stholo       /* Adjust the top row if it turns out that the current item unfortunately
560c166cd22Stholo          doesn't appear in the menu window */
561c166cd22Stholo       if (item->y < my_top_row)
562c166cd22Stholo 	my_top_row = item->y;
5630107aba4Smillert       else if (item->y >= (my_top_row + menu->arows))
5640107aba4Smillert 	my_top_row = item->y - menu->arows + 1;
565c166cd22Stholo 
566c166cd22Stholo       _nc_New_TopRow_and_CurrentItem(menu, my_top_row, item);
567c166cd22Stholo 
5685be68eb8Smillert     }
5695be68eb8Smillert 
570c166cd22Stholo   RETURN(result);
571c166cd22Stholo }
572c166cd22Stholo 
573c166cd22Stholo /* m_driver.c ends here */
574