10SN/A/****************************************************************************
29330SN/A * Copyright (c) 1998-2005,2008 Free Software Foundation, Inc.              *
30SN/A *                                                                          *
40SN/A * Permission is hereby granted, free of charge, to any person obtaining a  *
50SN/A * copy of this software and associated documentation files (the            *
60SN/A * "Software"), to deal in the Software without restriction, including      *
72362SN/A * without limitation the rights to use, copy, modify, merge, publish,      *
80SN/A * distribute, distribute with modifications, sublicense, and/or sell       *
92362SN/A * copies of the Software, and to permit persons to whom the Software is    *
100SN/A * furnished to do so, subject to the following conditions:                 *
110SN/A *                                                                          *
120SN/A * The above copyright notice and this permission notice shall be included  *
130SN/A * in all copies or substantial portions of the Software.                   *
140SN/A *                                                                          *
150SN/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
160SN/A * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
170SN/A * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
180SN/A * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
190SN/A * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
200SN/A * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
212362SN/A * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
222362SN/A *                                                                          *
232362SN/A * Except as contained in this notice, the name(s) of the above copyright   *
240SN/A * holders shall not be used in advertising or otherwise to promote the     *
250SN/A * sale, use or other dealings in this Software without prior written       *
260SN/A * authorization.                                                           *
270SN/A ****************************************************************************/
280SN/A
290SN/A/****************************************************************************
300SN/A *   Author:  Juergen Pfeifer, 1995,1997                                    *
310SN/A ****************************************************************************/
320SN/A
330SN/A/***************************************************************************
340SN/A* Module m_driver                                                          *
350SN/A* Central dispatching routine                                              *
360SN/A***************************************************************************/
370SN/A
380SN/A#include "menu.priv.h"
390SN/A
400SN/AMODULE_ID("$Id: m_driver.c,v 1.27 2008/08/03 22:08:22 tom Exp $")
410SN/A
420SN/A/* Macros */
430SN/A
440SN/A/* Remove the last character from the match pattern buffer */
450SN/A#define Remove_Character_From_Pattern(menu) \
460SN/A  (menu)->pattern[--((menu)->pindex)] = '\0'
470SN/A
480SN/A/* Add a new character to the match pattern buffer */
490SN/A#define Add_Character_To_Pattern(menu,ch) \
500SN/A  { (menu)->pattern[((menu)->pindex)++] = (ch);\
510SN/A    (menu)->pattern[(menu)->pindex] = '\0'; }
520SN/A
530SN/A/*---------------------------------------------------------------------------
540SN/A|   Facility      :  libnmenu
550SN/A|   Function      :  static bool Is_Sub_String(
560SN/A|                           bool IgnoreCaseFlag,
570SN/A|                           const char *part,
580SN/A|                           const char *string)
590SN/A|
600SN/A|   Description   :  Checks whether or not part is a substring of string.
610SN/A|
620SN/A|   Return Values :  TRUE   - if it is a substring
630SN/A|                    FALSE  - if it is not a substring
640SN/A+--------------------------------------------------------------------------*/
650SN/Astatic bool
660SN/AIs_Sub_String(
670SN/A	       bool IgnoreCaseFlag,
680SN/A	       const char *part,
690SN/A	       const char *string
700SN/A)
710SN/A{
720SN/A  assert(part && string);
730SN/A  if (IgnoreCaseFlag)
740SN/A    {
750SN/A      while (*string && *part)
760SN/A	{
770SN/A	  if (toupper(UChar(*string++)) != toupper(UChar(*part)))
780SN/A	    break;
790SN/A	  part++;
800SN/A	}
810SN/A    }
820SN/A  else
830SN/A    {
840SN/A      while (*string && *part)
850SN/A	if (*part != *string++)
860SN/A	  break;
870SN/A      part++;
880SN/A    }
890SN/A  return ((*part) ? FALSE : TRUE);
900SN/A}
910SN/A
920SN/A/*---------------------------------------------------------------------------
930SN/A|   Facility      :  libnmenu
940SN/A|   Function      :  int _nc_Match_Next_Character_In_Item_Name(
950SN/A|                           MENU *menu,
960SN/A|                           int  ch,
970SN/A|                           ITEM **item)
980SN/A|
990SN/A|   Description   :  This internal routine is called for a menu positioned
1000SN/A|                    at an item with three different classes of characters:
1010SN/A|                       - a printable character; the character is added to
1020SN/A|                         the current pattern and the next item matching
1030SN/A|                         this pattern is searched.
1040SN/A|                       - NUL; the pattern stays as it is and the next item
1050SN/A|                         matching the pattern is searched
1060SN/A|                       - BS; the pattern stays as it is and the previous
1070SN/A|                         item matching the pattern is searched
1080SN/A|
1090SN/A|                       The item parameter contains on call a pointer to
1100SN/A|                       the item where the search starts. On return - if
1110SN/A|                       a match was found - it contains a pointer to the
1120SN/A|                       matching item.
1130SN/A|
1140SN/A|   Return Values :  E_OK        - an item matching the pattern was found
1150SN/A|                    E_NO_MATCH  - nothing found
1160SN/A+--------------------------------------------------------------------------*/
1170SN/ANCURSES_EXPORT(int)
1180SN/A_nc_Match_Next_Character_In_Item_Name
1190SN/A(MENU * menu, int ch, ITEM ** item)
1200SN/A{
1210SN/A  bool found = FALSE, passed = FALSE;
1220SN/A  int idx, last;
1230SN/A
1240SN/A  T((T_CALLED("_nc_Match_Next_Character(%p,%d,%p)"), menu, ch, item));
1250SN/A
1260SN/A  assert(menu && item && *item);
1270SN/A  idx = (*item)->index;
1280SN/A
1290SN/A  if (ch && ch != BS)
1300SN/A    {
1310SN/A      /* if we become to long, we need no further checking : there can't be
1320SN/A         a match ! */
1330SN/A      if ((menu->pindex + 1) > menu->namelen)
1340SN/A	RETURN(E_NO_MATCH);
1350SN/A
1360SN/A      Add_Character_To_Pattern(menu, ch);
1370SN/A      /* we artificially position one item back, because in the do...while
1380SN/A         loop we start with the next item. This means, that with a new
1390SN/A         pattern search we always start the scan with the actual item. If
1400SN/A         we do a NEXT_PATTERN oder PREV_PATTERN search, we start with the
1410SN/A         one after or before the actual item. */
1420SN/A      if (--idx < 0)
1430SN/A	idx = menu->nitems - 1;
1440SN/A    }
1450SN/A
1460SN/A  last = idx;			/* this closes the cycle */
1470SN/A
1480SN/A  do
1490SN/A    {
1500SN/A      if (ch == BS)
1510SN/A	{			/* we have to go backward */
1520SN/A	  if (--idx < 0)
1530SN/A	    idx = menu->nitems - 1;
1540SN/A	}
1550SN/A      else
1560SN/A	{			/* otherwise we always go forward */
1570SN/A	  if (++idx >= menu->nitems)
1580SN/A	    idx = 0;
1590SN/A	}
1600SN/A      if (Is_Sub_String((bool)((menu->opt & O_IGNORECASE) != 0),
1610SN/A			menu->pattern,
1620SN/A			menu->items[idx]->name.str)
1630SN/A	)
16412745Smartin	found = TRUE;
1650SN/A      else
1660SN/A	passed = TRUE;
1670SN/A    }
1680SN/A  while (!found && (idx != last));
1690SN/A
1700SN/A  if (found)
1710SN/A    {
1720SN/A      if (!((idx == (*item)->index) && passed))
1730SN/A	{
1740SN/A	  *item = menu->items[idx];
1750SN/A	  RETURN(E_OK);
1760SN/A	}
1770SN/A      /* This point is reached, if we fully cycled through the item list
1780SN/A         and the only match we found is the starting item. With a NEXT_PATTERN
1790SN/A         or PREV_PATTERN scan this means, that there was no additional match.
1800SN/A         If we searched with an expanded new pattern, we should never reach
1810SN/A         this point, because if the expanded pattern matches also the actual
1820SN/A         item we will find it in the first attempt (passed==FALSE) and we
1830SN/A         will never cycle through the whole item array.
1840SN/A       */
1850SN/A      assert(ch == 0 || ch == BS);
1860SN/A    }
1870SN/A  else
1880SN/A    {
1890SN/A      if (ch && ch != BS && menu->pindex > 0)
1900SN/A	{
1910SN/A	  /* if we had no match with a new pattern, we have to restore it */
1920SN/A	  Remove_Character_From_Pattern(menu);
1930SN/A	}
1940SN/A    }
1950SN/A  RETURN(E_NO_MATCH);
1960SN/A}
1970SN/A
1980SN/A/*---------------------------------------------------------------------------
1990SN/A|   Facility      :  libnmenu
2000SN/A|   Function      :  int menu_driver(MENU *menu, int c)
2010SN/A|
2020SN/A|   Description   :  Central dispatcher for the menu. Translates the logical
2030SN/A|                    request 'c' into a menu action.
2040SN/A|
2050SN/A|   Return Values :  E_OK            - success
2060SN/A|                    E_BAD_ARGUMENT  - invalid menu pointer
2070SN/A|                    E_BAD_STATE     - menu is in user hook routine
2080SN/A|                    E_NOT_POSTED    - menu is not posted
2090SN/A+--------------------------------------------------------------------------*/
2100SN/ANCURSES_EXPORT(int)
2110SN/Amenu_driver(MENU * menu, int c)
2120SN/A{
2130SN/A#define NAVIGATE(dir) \
2140SN/A  if (!item->dir)\
2150SN/A     result = E_REQUEST_DENIED;\
2160SN/A  else\
2170SN/A     item = item->dir
2180SN/A
2190SN/A  int result = E_OK;
2200SN/A  ITEM *item;
2210SN/A  int my_top_row, rdiff;
2220SN/A
2230SN/A  T((T_CALLED("menu_driver(%p,%d)"), menu, c));
2240SN/A
2250SN/A  if (!menu)
2260SN/A    RETURN(E_BAD_ARGUMENT);
2270SN/A
2280SN/A  if (menu->status & _IN_DRIVER)
2290SN/A    RETURN(E_BAD_STATE);
2300SN/A  if (!(menu->status & _POSTED))
2310SN/A    RETURN(E_NOT_POSTED);
2320SN/A
2330SN/A  item = menu->curitem;
2340SN/A
2350SN/A  my_top_row = menu->toprow;
2360SN/A  assert(item);
2370SN/A
2380SN/A  if ((c > KEY_MAX) && (c <= MAX_MENU_COMMAND))
2390SN/A    {
2400SN/A      if (!((c == REQ_BACK_PATTERN)
2410SN/A	    || (c == REQ_NEXT_MATCH) || (c == REQ_PREV_MATCH)))
2420SN/A	{
2430SN/A	  assert(menu->pattern);
2440SN/A	  Reset_Pattern(menu);
2450SN/A	}
2460SN/A
2470SN/A      switch (c)
2480SN/A	{
2490SN/A	case REQ_LEFT_ITEM:
2500SN/A	    /*=================*/
2510SN/A	  NAVIGATE(left);
2520SN/A	  break;
2533625SN/A
2540SN/A	case REQ_RIGHT_ITEM:
2550SN/A	    /*==================*/
2560SN/A	  NAVIGATE(right);
2570SN/A	  break;
2580SN/A
2590SN/A	case REQ_UP_ITEM:
2600SN/A	    /*===============*/
2610SN/A	  NAVIGATE(up);
2620SN/A	  break;
2630SN/A
2640SN/A	case REQ_DOWN_ITEM:
2650SN/A	    /*=================*/
2660SN/A	  NAVIGATE(down);
2670SN/A	  break;
2680SN/A
2690SN/A	case REQ_SCR_ULINE:
2700SN/A	    /*=================*/
2710SN/A	  if (my_top_row == 0 || !(item->up))
2720SN/A	    result = E_REQUEST_DENIED;
2730SN/A	  else
2740SN/A	    {
2750SN/A	      --my_top_row;
2760SN/A	      item = item->up;
2770SN/A	    }
2780SN/A	  break;
2790SN/A
2800SN/A	case REQ_SCR_DLINE:
2810SN/A	    /*=================*/
2820SN/A	  if ((my_top_row + menu->arows >= menu->rows) || !(item->down))
2830SN/A	    {
2843626SN/A	      /* only if the menu has less items than rows, we can deny the
2853626SN/A	         request. Otherwise the epilogue of this routine adjusts the
2863626SN/A	         top row if necessary */
2873626SN/A	      result = E_REQUEST_DENIED;
2883626SN/A	    }
2893626SN/A	  else
2903626SN/A	    {
2910SN/A	      my_top_row++;
2920SN/A	      item = item->down;
2930SN/A	    }
2940SN/A	  break;
2950SN/A
2960SN/A	case REQ_SCR_DPAGE:
2970SN/A	    /*=================*/
2980SN/A	  rdiff = menu->rows - (menu->arows + my_top_row);
2990SN/A	  if (rdiff > menu->arows)
3000SN/A	    rdiff = menu->arows;
3010SN/A	  if (rdiff <= 0)
3020SN/A	    result = E_REQUEST_DENIED;
3030SN/A	  else
3040SN/A	    {
3054818SN/A	      my_top_row += rdiff;
3060SN/A	      while (rdiff-- > 0 && item != 0 && item->down != 0)
3070SN/A		item = item->down;
3080SN/A	    }
3090SN/A	  break;
3100SN/A
3110SN/A	case REQ_SCR_UPAGE:
3120SN/A	    /*=================*/
3130SN/A	  rdiff = (menu->arows < my_top_row) ? menu->arows : my_top_row;
3140SN/A	  if (rdiff <= 0)
3150SN/A	    result = E_REQUEST_DENIED;
3160SN/A	  else
3170SN/A	    {
3180SN/A	      my_top_row -= rdiff;
3190SN/A	      while (rdiff-- > 0 && item != 0 && item->up != 0)
3200SN/A		item = item->up;
3210SN/A	    }
3220SN/A	  break;
3230SN/A
3240SN/A	case REQ_FIRST_ITEM:
3250SN/A	    /*==================*/
3260SN/A	  item = menu->items[0];
3270SN/A	  break;
3280SN/A
3290SN/A	case REQ_LAST_ITEM:
3300SN/A	    /*=================*/
3310SN/A	  item = menu->items[menu->nitems - 1];
3320SN/A	  break;
3330SN/A
3340SN/A	case REQ_NEXT_ITEM:
3350SN/A	    /*=================*/
3360SN/A	  if ((item->index + 1) >= menu->nitems)
3370SN/A	    {
3380SN/A	      if (menu->opt & O_NONCYCLIC)
3390SN/A		result = E_REQUEST_DENIED;
3400SN/A	      else
3410SN/A		item = menu->items[0];
3420SN/A	    }
3430SN/A	  else
3440SN/A	    item = menu->items[item->index + 1];
3450SN/A	  break;
3460SN/A
3470SN/A	case REQ_PREV_ITEM:
3480SN/A	    /*=================*/
3490SN/A	  if (item->index <= 0)
3500SN/A	    {
3510SN/A	      if (menu->opt & O_NONCYCLIC)
3520SN/A		result = E_REQUEST_DENIED;
3530SN/A	      else
3540SN/A		item = menu->items[menu->nitems - 1];
3550SN/A	    }
3560SN/A	  else
3570SN/A	    item = menu->items[item->index - 1];
35812143Savstepan	  break;
3590SN/A
3600SN/A	case REQ_TOGGLE_ITEM:
3610SN/A	    /*===================*/
3620SN/A	  if (menu->opt & O_ONEVALUE)
3630SN/A	    {
3640SN/A	      result = E_REQUEST_DENIED;
3650SN/A	    }
3660SN/A	  else
3670SN/A	    {
3680SN/A	      if (menu->curitem->opt & O_SELECTABLE)
3690SN/A		{
3700SN/A		  menu->curitem->value = !menu->curitem->value;
3710SN/A		  Move_And_Post_Item(menu, menu->curitem);
3720SN/A		  _nc_Show_Menu(menu);
37315451Sredestad		}
3740SN/A	      else
3750SN/A		result = E_NOT_SELECTABLE;
3760SN/A	    }
3770SN/A	  break;
3780SN/A
3790SN/A	case REQ_CLEAR_PATTERN:
3800SN/A	    /*=====================*/
3810SN/A	  /* already cleared in prologue */
3820SN/A	  break;
3830SN/A
3840SN/A	case REQ_BACK_PATTERN:
3850SN/A	    /*====================*/
3860SN/A	  if (menu->pindex > 0)
3870SN/A	    {
3880SN/A	      assert(menu->pattern);
3890SN/A	      Remove_Character_From_Pattern(menu);
3900SN/A	      pos_menu_cursor(menu);
3910SN/A	    }
3920SN/A	  else
3930SN/A	    result = E_REQUEST_DENIED;
3940SN/A	  break;
3950SN/A
3960SN/A	case REQ_NEXT_MATCH:
3970SN/A	    /*==================*/
3980SN/A	  assert(menu->pattern);
3990SN/A	  if (menu->pattern[0])
4000SN/A	    result = _nc_Match_Next_Character_In_Item_Name(menu, 0, &item);
4010SN/A	  else
4020SN/A	    {
4030SN/A	      if ((item->index + 1) < menu->nitems)
4040SN/A		item = menu->items[item->index + 1];
4050SN/A	      else
4060SN/A		{
4070SN/A		  if (menu->opt & O_NONCYCLIC)
4080SN/A		    result = E_REQUEST_DENIED;
4090SN/A		  else
4100SN/A		    item = menu->items[0];
4110SN/A		}
4120SN/A	    }
4130SN/A	  break;
4140SN/A
4150SN/A	case REQ_PREV_MATCH:
4160SN/A	    /*==================*/
4170SN/A	  assert(menu->pattern);
4180SN/A	  if (menu->pattern[0])
4190SN/A	    result = _nc_Match_Next_Character_In_Item_Name(menu, BS, &item);
4200SN/A	  else
4210SN/A	    {
4220SN/A	      if (item->index)
4230SN/A		item = menu->items[item->index - 1];
4240SN/A	      else
4250SN/A		{
4260SN/A		  if (menu->opt & O_NONCYCLIC)
4270SN/A		    result = E_REQUEST_DENIED;
4280SN/A		  else
4290SN/A		    item = menu->items[menu->nitems - 1];
4300SN/A		}
4310SN/A	    }
4320SN/A	  break;
4330SN/A
4340SN/A	default:
4350SN/A	    /*======*/
4360SN/A	  result = E_UNKNOWN_COMMAND;
4370SN/A	  break;
4380SN/A	}
4390SN/A    }
4400SN/A  else
4410SN/A    {				/* not a command */
4420SN/A      if (!(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(UChar(c)))
4430SN/A	result = _nc_Match_Next_Character_In_Item_Name(menu, c, &item);
4440SN/A#ifdef NCURSES_MOUSE_VERSION
4450SN/A      else if (KEY_MOUSE == c)
4463625SN/A	{
4473625SN/A	  MEVENT event;
4483625SN/A	  WINDOW *uwin = Get_Menu_UserWin(menu);
4493625SN/A
4503625SN/A	  getmouse(&event);
4513625SN/A	  if ((event.bstate & (BUTTON1_CLICKED |
4523625SN/A			       BUTTON1_DOUBLE_CLICKED |
4533625SN/A			       BUTTON1_TRIPLE_CLICKED))
4543625SN/A	      && wenclose(uwin, event.y, event.x))
4553625SN/A	    {			/* we react only if the click was in the userwin, that means
4563625SN/A				 * inside the menu display area or at the decoration window.
4573625SN/A				 */
4583625SN/A	      WINDOW *sub = Get_Menu_Window(menu);
4593625SN/A	      int ry = event.y, rx = event.x;	/* screen coordinates */
4603625SN/A
4613625SN/A	      result = E_REQUEST_DENIED;
4623625SN/A	      if (mouse_trafo(&ry, &rx, FALSE))
4633625SN/A		{		/* rx, ry are now "curses" coordinates */
4643625SN/A		  if (ry < sub->_begy)
4653625SN/A		    {		/* we clicked above the display region; this is
4663625SN/A				 * interpreted as "scroll up" request
4673625SN/A				 */
4683625SN/A		      if (event.bstate & BUTTON1_CLICKED)
4693625SN/A			result = menu_driver(menu, REQ_SCR_ULINE);
4703625SN/A		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4713625SN/A			result = menu_driver(menu, REQ_SCR_UPAGE);
4723625SN/A		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4733625SN/A			result = menu_driver(menu, REQ_FIRST_ITEM);
4743625SN/A		      RETURN(result);
4753625SN/A		    }
4760SN/A		  else if (ry > sub->_begy + sub->_maxy)
4770SN/A		    {		/* we clicked below the display region; this is
4780SN/A				 * interpreted as "scroll down" request
4790SN/A				 */
4800SN/A		      if (event.bstate & BUTTON1_CLICKED)
4810SN/A			result = menu_driver(menu, REQ_SCR_DLINE);
4820SN/A		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4830SN/A			result = menu_driver(menu, REQ_SCR_DPAGE);
4840SN/A		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4850SN/A			result = menu_driver(menu, REQ_LAST_ITEM);
4860SN/A		      RETURN(result);
4870SN/A		    }
4880SN/A		  else if (wenclose(sub, event.y, event.x))
4890SN/A		    {		/* Inside the area we try to find the hit item */
4900SN/A		      int i, x, y, err;
4910SN/A
4920SN/A		      ry = event.y;
4930SN/A		      rx = event.x;
4940SN/A		      if (wmouse_trafo(sub, &ry, &rx, FALSE))
4950SN/A			{
4960SN/A			  for (i = 0; i < menu->nitems; i++)
4970SN/A			    {
4980SN/A			      err = _nc_menu_cursor_pos(menu, menu->items[i],
4990SN/A							&y, &x);
5000SN/A			      if (E_OK == err)
5010SN/A				{
5020SN/A				  if ((ry == y) &&
5030SN/A				      (rx >= x) &&
5040SN/A				      (rx < x + menu->itemlen))
5056548SN/A				    {
5060SN/A				      item = menu->items[i];
5070SN/A				      result = E_OK;
5080SN/A				      break;
5090SN/A				    }
5100SN/A				}
5110SN/A			    }
5120SN/A			  if (E_OK == result)
5130SN/A			    {	/* We found an item, now we can handle the click.
5140SN/A				 * A single click just positions the menu cursor
5150SN/A				 * to the clicked item. A double click toggles
5160SN/A				 * the item.
5170SN/A				 */
5180SN/A			      if (event.bstate & BUTTON1_DOUBLE_CLICKED)
5190SN/A				{
5200SN/A				  _nc_New_TopRow_and_CurrentItem(menu,
5210SN/A								 my_top_row,
5220SN/A								 item);
5230SN/A				  menu_driver(menu, REQ_TOGGLE_ITEM);
5240SN/A				  result = E_UNKNOWN_COMMAND;
5250SN/A				}
5260SN/A			    }
5270SN/A			}
5280SN/A		    }
5290SN/A		}
5300SN/A	    }
5310SN/A	  else
5320SN/A	    result = E_REQUEST_DENIED;
5330SN/A	}
5340SN/A#endif /* NCURSES_MOUSE_VERSION */
5350SN/A      else
5360SN/A	result = E_UNKNOWN_COMMAND;
5370SN/A    }
5380SN/A
5390SN/A  if (E_OK == result)
5400SN/A    {
5410SN/A      /* Adjust the top row if it turns out that the current item unfortunately
5420SN/A         doesn't appear in the menu window */
5430SN/A      if (item->y < my_top_row)
5440SN/A	my_top_row = item->y;
5450SN/A      else if (item->y >= (my_top_row + menu->arows))
5460SN/A	my_top_row = item->y - menu->arows + 1;
5470SN/A
5480SN/A      _nc_New_TopRow_and_CurrentItem(menu, my_top_row, item);
5490SN/A
5500SN/A    }
5510SN/A
5520SN/A  RETURN(result);
5530SN/A}
5540SN/A
5550SN/A/* m_driver.c ends here */
5566897SN/A