X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=menu%2Fm_driver.c;h=8e72999b64c1d3a549cbd8cc1759ffeb26240f97;hp=5e47beac1e08b519e11de7a6501378e46a26976a;hb=c3b21f65a2687f3894a0d3217006c23f162c893a;hpb=661078ddbde3ce0f3b06e95642fbb9b5fef7dca1 diff --git a/menu/m_driver.c b/menu/m_driver.c index 5e47beac..8e72999b 100644 --- a/menu/m_driver.c +++ b/menu/m_driver.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998 Free Software Foundation, Inc. * + * Copyright (c) 1998-2012,2016 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -27,7 +27,7 @@ ****************************************************************************/ /**************************************************************************** - * Author: Juergen Pfeifer 1995,1997 * + * Author: Juergen Pfeifer, 1995,1997 * ****************************************************************************/ /*************************************************************************** @@ -37,7 +37,7 @@ #include "menu.priv.h" -MODULE_ID("$Id: m_driver.c,v 1.10 1998/02/11 12:13:49 tom Exp $") +MODULE_ID("$Id: m_driver.c,v 1.32 2016/03/26 21:51:52 tom Exp $") /* Macros */ @@ -47,52 +47,55 @@ MODULE_ID("$Id: m_driver.c,v 1.10 1998/02/11 12:13:49 tom Exp $") /* Add a new character to the match pattern buffer */ #define Add_Character_To_Pattern(menu,ch) \ - { (menu)->pattern[((menu)->pindex)++] = (ch);\ + { (menu)->pattern[((menu)->pindex)++] = (char) (ch);\ (menu)->pattern[(menu)->pindex] = '\0'; } /*--------------------------------------------------------------------------- -| Facility : libnmenu -| Function : static bool Is_Sub_String( +| Facility : libnmenu +| Function : static bool Is_Sub_String( | bool IgnoreCaseFlag, | const char *part, | const char *string) -| +| | Description : Checks whether or not part is a substring of string. | | Return Values : TRUE - if it is a substring | FALSE - if it is not a substring +--------------------------------------------------------------------------*/ -static bool Is_Sub_String( - bool IgnoreCaseFlag, - const char *part, - const char *string - ) +static bool +Is_Sub_String( + bool IgnoreCaseFlag, + const char *part, + const char *string +) { - assert( part && string ); - if ( IgnoreCaseFlag ) + assert(part && string); + if (IgnoreCaseFlag) { - while(*string && *part) + while (*string && *part) { - if (toupper(*string++)!=toupper(*part)) break; + if (toupper(UChar(*string++)) != toupper(UChar(*part))) + break; part++; } } else { - while( *string && *part ) - if (*part != *string++) break; + while (*string && *part) + if (*part != *string++) + break; part++; } - return ( (*part) ? FALSE : TRUE ); + return ((*part) ? FALSE : TRUE); } /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu | Function : int _nc_Match_Next_Character_In_Item_Name( | MENU *menu, | int ch, | ITEM **item) -| +| | Description : This internal routine is called for a menu positioned | at an item with three different classes of characters: | - a printable character; the character is added to @@ -107,89 +110,96 @@ static bool Is_Sub_String( | the item where the search starts. On return - if | a match was found - it contains a pointer to the | matching item. -| +| | Return Values : E_OK - an item matching the pattern was found | E_NO_MATCH - nothing found +--------------------------------------------------------------------------*/ -int _nc_Match_Next_Character_In_Item_Name(MENU *menu, int ch, ITEM **item) +NCURSES_EXPORT(int) +_nc_Match_Next_Character_In_Item_Name +(MENU * menu, int ch, ITEM ** item) { bool found = FALSE, passed = FALSE; - int idx, last; - - assert( menu && item && *item); + int idx, last; + + T((T_CALLED("_nc_Match_Next_Character(%p,%d,%p)"), + (void *)menu, ch, (void *)item)); + + assert(menu && item && *item); idx = (*item)->index; - - if (ch && ch!=BS) + + if (ch && ch != BS) { /* if we become to long, we need no further checking : there can't be - a match ! */ - if ((menu->pindex+1) > menu->namelen) + a match ! */ + if ((menu->pindex + 1) > menu->namelen) RETURN(E_NO_MATCH); - - Add_Character_To_Pattern(menu,ch); + + Add_Character_To_Pattern(menu, ch); /* we artificially position one item back, because in the do...while - loop we start with the next item. This means, that with a new - pattern search we always start the scan with the actual item. If - we do a NEXT_PATTERN oder PREV_PATTERN search, we start with the - one after or before the actual item. */ - if (--idx < 0) - idx = menu->nitems-1; + loop we start with the next item. This means, that with a new + pattern search we always start the scan with the actual item. If + we do a NEXT_PATTERN oder PREV_PATTERN search, we start with the + one after or before the actual item. */ + if (--idx < 0) + idx = menu->nitems - 1; } - + last = idx; /* this closes the cycle */ - - do{ - if (ch==BS) - { /* we have to go backward */ - if (--idx < 0) - idx = menu->nitems-1; - } - else - { /* otherwise we always go forward */ - if (++idx >= menu->nitems) - idx = 0; - } - if (Is_Sub_String((menu->opt & O_IGNORECASE) != 0, - menu->pattern, - menu->items[idx]->name.str) + + do + { + if (ch == BS) + { /* we have to go backward */ + if (--idx < 0) + idx = menu->nitems - 1; + } + else + { /* otherwise we always go forward */ + if (++idx >= menu->nitems) + idx = 0; + } + if (Is_Sub_String((bool)((menu->opt & O_IGNORECASE) != 0), + menu->pattern, + menu->items[idx]->name.str) ) - found = TRUE; - else - passed = TRUE; - } while (!found && (idx != last)); - + found = TRUE; + else + passed = TRUE; + } + while (!found && (idx != last)); + if (found) { - if (!((idx==(*item)->index) && passed)) + if (!((idx == (*item)->index) && passed)) { *item = menu->items[idx]; RETURN(E_OK); } /* This point is reached, if we fully cycled through the item list - and the only match we found is the starting item. With a NEXT_PATTERN - or PREV_PATTERN scan this means, that there was no additional match. - If we searched with an expanded new pattern, we should never reach - this point, because if the expanded pattern matches also the actual - item we will find it in the first attempt (passed==FALSE) and we - will never cycle through the whole item array. - */ - assert( ch==0 || ch==BS ); + and the only match we found is the starting item. With a NEXT_PATTERN + or PREV_PATTERN scan this means, that there was no additional match. + If we searched with an expanded new pattern, we should never reach + this point, because if the expanded pattern matches also the actual + item we will find it in the first attempt (passed==FALSE) and we + will never cycle through the whole item array. + */ + assert(ch == 0 || ch == BS); } else { - if (ch && ch!=BS && menu->pindex>0) + if (ch && ch != BS && menu->pindex > 0) { /* if we had no match with a new pattern, we have to restore it */ Remove_Character_From_Pattern(menu); } - } + } RETURN(E_NO_MATCH); -} +} /*--------------------------------------------------------------------------- -| Facility : libnmenu -| Function : int menu_driver(MENU *menu, int c) -| +| Facility : libnmenu +| Function : int menu_driver(MENU* menu, int c) +| | Description : Central dispatcher for the menu. Translates the logical | request 'c' into a menu action. | @@ -198,7 +208,8 @@ int _nc_Match_Next_Character_In_Item_Name(MENU *menu, int ch, ITEM **item) | E_BAD_STATE - menu is in user hook routine | E_NOT_POSTED - menu is not posted +--------------------------------------------------------------------------*/ -int menu_driver(MENU * menu, int c) +NCURSES_EXPORT(int) +menu_driver(MENU * menu, int c) { #define NAVIGATE(dir) \ if (!item->dir)\ @@ -209,118 +220,121 @@ int menu_driver(MENU * menu, int c) int result = E_OK; ITEM *item; int my_top_row, rdiff; - + + T((T_CALLED("menu_driver(%p,%d)"), (void *)menu, c)); + if (!menu) RETURN(E_BAD_ARGUMENT); - - if ( menu->status & _IN_DRIVER ) + + if (menu->status & _IN_DRIVER) RETURN(E_BAD_STATE); - if ( !( menu->status & _POSTED ) ) + if (!(menu->status & _POSTED)) RETURN(E_NOT_POSTED); - + + item = menu->curitem; + my_top_row = menu->toprow; - item = menu->curitem; assert(item); - - if ((c > KEY_MAX) && (c<=MAX_MENU_COMMAND)) - { - if (!((c==REQ_BACK_PATTERN) - || (c==REQ_NEXT_MATCH) || (c==REQ_PREV_MATCH))) + + if ((c > KEY_MAX) && (c <= MAX_MENU_COMMAND)) + { + if (!((c == REQ_BACK_PATTERN) + || (c == REQ_NEXT_MATCH) || (c == REQ_PREV_MATCH))) { - assert( menu->pattern ); + assert(menu->pattern); Reset_Pattern(menu); } - - switch(c) + + switch (c) { case REQ_LEFT_ITEM: - /*=================*/ + /*=================*/ NAVIGATE(left); break; - + case REQ_RIGHT_ITEM: - /*==================*/ + /*==================*/ NAVIGATE(right); break; - + case REQ_UP_ITEM: - /*===============*/ + /*===============*/ NAVIGATE(up); break; - + case REQ_DOWN_ITEM: - /*=================*/ + /*=================*/ NAVIGATE(down); break; - + case REQ_SCR_ULINE: - /*=================*/ - if (my_top_row == 0) + /*=================*/ + if (my_top_row == 0 || !(item->up)) result = E_REQUEST_DENIED; else { --my_top_row; item = item->up; - } + } break; - + case REQ_SCR_DLINE: - /*=================*/ - my_top_row++; - if ((menu->rows - menu->arows)>0) + /*=================*/ + if ((my_top_row + menu->arows >= menu->rows) || !(item->down)) { /* only if the menu has less items than rows, we can deny the - request. Otherwise the epilogue of this routine adjusts the - top row if necessary */ - my_top_row--; + request. Otherwise the epilogue of this routine adjusts the + top row if necessary */ result = E_REQUEST_DENIED; } else - item = item->down; + { + my_top_row++; + item = item->down; + } break; - + case REQ_SCR_DPAGE: - /*=================*/ - rdiff = menu->rows - menu->arows - my_top_row; - if (rdiff > menu->arows) + /*=================*/ + rdiff = menu->rows - (menu->arows + my_top_row); + if (rdiff > menu->arows) rdiff = menu->arows; - if (rdiff==0) + if (rdiff <= 0) result = E_REQUEST_DENIED; else { my_top_row += rdiff; - while(rdiff-- > 0) + while (rdiff-- > 0 && item != 0 && item->down != 0) item = item->down; } break; - + case REQ_SCR_UPAGE: - /*=================*/ - rdiff = (menu->arows < my_top_row) ? - menu->arows : my_top_row; - if (rdiff==0) + /*=================*/ + rdiff = (menu->arows < my_top_row) ? menu->arows : my_top_row; + if (rdiff <= 0) result = E_REQUEST_DENIED; else { my_top_row -= rdiff; - while(rdiff--) + while (rdiff-- > 0 && item != 0 && item->up != 0) item = item->up; } break; - + case REQ_FIRST_ITEM: - /*==================*/ + /*==================*/ item = menu->items[0]; break; - + case REQ_LAST_ITEM: - /*=================*/ - item = menu->items[menu->nitems-1]; + /*=================*/ + item = menu->items[menu->nitems - 1]; break; case REQ_NEXT_ITEM: - /*=================*/ - if ((item->index+1)>=menu->nitems) + /*=================*/ + if ((item->index + 1) >= menu->nitems) { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; @@ -330,22 +344,22 @@ int menu_driver(MENU * menu, int c) else item = menu->items[item->index + 1]; break; - + case REQ_PREV_ITEM: - /*=================*/ - if (item->index<=0) + /*=================*/ + if (item->index <= 0) { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else - item = menu->items[menu->nitems-1]; + item = menu->items[menu->nitems - 1]; } else item = menu->items[item->index - 1]; break; - + case REQ_TOGGLE_ITEM: - /*===================*/ + /*===================*/ if (menu->opt & O_ONEVALUE) { result = E_REQUEST_DENIED; @@ -355,40 +369,40 @@ int menu_driver(MENU * menu, int c) if (menu->curitem->opt & O_SELECTABLE) { menu->curitem->value = !menu->curitem->value; - Move_And_Post_Item(menu,menu->curitem); + Move_And_Post_Item(menu, menu->curitem); _nc_Show_Menu(menu); } else result = E_NOT_SELECTABLE; } break; - + case REQ_CLEAR_PATTERN: - /*=====================*/ + /*=====================*/ /* already cleared in prologue */ break; - + case REQ_BACK_PATTERN: - /*====================*/ - if (menu->pindex>0) + /*====================*/ + if (menu->pindex > 0) { assert(menu->pattern); Remove_Character_From_Pattern(menu); - pos_menu_cursor( menu ); + pos_menu_cursor(menu); } else result = E_REQUEST_DENIED; break; - + case REQ_NEXT_MATCH: - /*==================*/ + /*==================*/ assert(menu->pattern); if (menu->pattern[0]) - result = _nc_Match_Next_Character_In_Item_Name(menu,0,&item); + result = _nc_Match_Next_Character_In_Item_Name(menu, 0, &item); else { - if ((item->index+1)nitems) - item=menu->items[item->index+1]; + if ((item->index + 1) < menu->nitems) + item = menu->items[item->index + 1]; else { if (menu->opt & O_NONCYCLIC) @@ -397,50 +411,153 @@ int menu_driver(MENU * menu, int c) item = menu->items[0]; } } - break; - + break; + case REQ_PREV_MATCH: - /*==================*/ + /*==================*/ assert(menu->pattern); if (menu->pattern[0]) - result = _nc_Match_Next_Character_In_Item_Name(menu,BS,&item); + result = _nc_Match_Next_Character_In_Item_Name(menu, BS, &item); else { if (item->index) - item = menu->items[item->index-1]; + item = menu->items[item->index - 1]; else { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else - item = menu->items[menu->nitems-1]; + item = menu->items[menu->nitems - 1]; } } break; - + default: - /*======*/ + /*======*/ result = E_UNKNOWN_COMMAND; break; } } else { /* not a command */ - if ( !(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(c) ) - result = _nc_Match_Next_Character_In_Item_Name( menu, c, &item ); + if (!(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(UChar(c))) + result = _nc_Match_Next_Character_In_Item_Name(menu, c, &item); +#ifdef NCURSES_MOUSE_VERSION + else if (KEY_MOUSE == c) + { + MEVENT event; + WINDOW *uwin = Get_Menu_UserWin(menu); + + getmouse(&event); + if ((event.bstate & (BUTTON1_CLICKED | + BUTTON1_DOUBLE_CLICKED | + BUTTON1_TRIPLE_CLICKED)) + && wenclose(uwin, event.y, event.x)) + { /* we react only if the click was in the userwin, that means + * inside the menu display area or at the decoration window. + */ + WINDOW *sub = Get_Menu_Window(menu); + int ry = event.y, rx = event.x; /* screen coordinates */ + + result = E_REQUEST_DENIED; + if (mouse_trafo(&ry, &rx, FALSE)) + { /* rx, ry are now "curses" coordinates */ + if (ry < sub->_begy) + { /* we clicked above the display region; this is + * interpreted as "scroll up" request + */ + if (event.bstate & BUTTON1_CLICKED) + result = menu_driver(menu, REQ_SCR_ULINE); + else if (event.bstate & BUTTON1_DOUBLE_CLICKED) + result = menu_driver(menu, REQ_SCR_UPAGE); + else if (event.bstate & BUTTON1_TRIPLE_CLICKED) + result = menu_driver(menu, REQ_FIRST_ITEM); + RETURN(result); + } + else if (ry > sub->_begy + sub->_maxy) + { /* we clicked below the display region; this is + * interpreted as "scroll down" request + */ + if (event.bstate & BUTTON1_CLICKED) + result = menu_driver(menu, REQ_SCR_DLINE); + else if (event.bstate & BUTTON1_DOUBLE_CLICKED) + result = menu_driver(menu, REQ_SCR_DPAGE); + else if (event.bstate & BUTTON1_TRIPLE_CLICKED) + result = menu_driver(menu, REQ_LAST_ITEM); + RETURN(result); + } + else if (wenclose(sub, event.y, event.x)) + { /* Inside the area we try to find the hit item */ + int i, x, y, err; + + ry = event.y; + rx = event.x; + if (wmouse_trafo(sub, &ry, &rx, FALSE)) + { + for (i = 0; i < menu->nitems; i++) + { + err = _nc_menu_cursor_pos(menu, menu->items[i], + &y, &x); + if (E_OK == err) + { + if ((ry == y) && + (rx >= x) && + (rx < x + menu->itemlen)) + { + item = menu->items[i]; + result = E_OK; + break; + } + } + } + if (E_OK == result) + { /* We found an item, now we can handle the click. + * A single click just positions the menu cursor + * to the clicked item. A double click toggles + * the item. + */ + if (event.bstate & BUTTON1_DOUBLE_CLICKED) + { + _nc_New_TopRow_and_CurrentItem(menu, + my_top_row, + item); + menu_driver(menu, REQ_TOGGLE_ITEM); + result = E_UNKNOWN_COMMAND; + } + } + } + } + } + } + else + { + if (menu->opt & O_MOUSE_MENU) + ungetmouse(&event); /* let someone else handle this */ + result = E_REQUEST_DENIED; + } + } +#endif /* NCURSES_MOUSE_VERSION */ else result = E_UNKNOWN_COMMAND; } - - /* Adjust the top row if it turns out that the current item unfortunately - doesn't appear in the menu window */ - if ( item->y < my_top_row ) - my_top_row = item->y; - else if ( item->y >= (my_top_row + menu->arows) ) - my_top_row = item->y - menu->arows + 1; - - _nc_New_TopRow_and_CurrentItem( menu, my_top_row, item ); - + + if (item == 0) + { + result = E_BAD_STATE; + } + else if (E_OK == result) + { + /* Adjust the top row if it turns out that the current item unfortunately + doesn't appear in the menu window */ + if (item->y < my_top_row) + my_top_row = item->y; + else if (item->y >= (my_top_row + menu->arows)) + my_top_row = item->y - menu->arows + 1; + + _nc_New_TopRow_and_CurrentItem(menu, my_top_row, item); + + } + RETURN(result); }