set_current_item(MENU * menu, ITEM * item) { T((T_CALLED("set_current_item(%p,%p)"), menu, item)); if (menu && item && (item->imenu == menu)) { if (menu->status & _IN_DRIVER) RETURN(E_BAD_STATE); assert(menu->curitem); if (item != menu->curitem) { if (menu->status & _LINK_NEEDED) { /* * Items are available, but they are not linked together. * So we have to link here. */ _nc_Link_Items(menu); } assert(menu->pattern); Reset_Pattern(menu); /* adjust the window to make item visible and update the menu */ Adjust_Current_Item(menu, menu->toprow, item); } } else RETURN(E_BAD_ARGUMENT); RETURN(E_OK); }
set_top_row(MENU * menu, int row) { ITEM *item; T((T_CALLED("set_top_row(%p,%d)"), menu, row)); if (menu) { if (menu->status & _IN_DRIVER) RETURN(E_BAD_STATE); if (menu->items == (ITEM **) 0) RETURN(E_NOT_CONNECTED); if ((row < 0) || (row > (menu->rows - menu->arows))) RETURN(E_BAD_ARGUMENT); } else RETURN(E_BAD_ARGUMENT); if (row != menu->toprow) { if (menu->status & _LINK_NEEDED) _nc_Link_Items(menu); item = menu->items[(menu->opt & O_ROWMAJOR) ? (row * menu->cols) : row]; assert(menu->pattern); Reset_Pattern(menu); _nc_New_TopRow_and_CurrentItem(menu, row, item); } RETURN(E_OK); }
set_menu_pattern(MENU * menu, const char *p) { ITEM *matchitem; int matchpos; T((T_CALLED("set_menu_pattern(%p,%s)"), menu, _nc_visbuf(p))); if (!menu || !p) RETURN(E_BAD_ARGUMENT); if (!(menu->items)) RETURN(E_NOT_CONNECTED); if (menu->status & _IN_DRIVER) RETURN(E_BAD_STATE); Reset_Pattern(menu); if (!(*p)) { pos_menu_cursor(menu); RETURN(E_OK); } if (menu->status & _LINK_NEEDED) _nc_Link_Items(menu); matchpos = menu->toprow; matchitem = menu->curitem; assert(matchitem); while (*p) { if (!isprint(UChar(*p)) || (_nc_Match_Next_Character_In_Item_Name(menu, *p, &matchitem) != E_OK)) { Reset_Pattern(menu); pos_menu_cursor(menu); RETURN(E_NO_MATCH); } p++; } /* This is reached if there was a match. So we position to the new item */ Adjust_Current_Item(menu, matchpos, matchitem); RETURN(E_OK); }
set_menu_format(MENU * menu, int rows, int cols) { int total_rows, total_cols; T((T_CALLED("set_menu_format(%p,%d,%d)"), menu, rows, cols)); if (rows < 0 || cols < 0) RETURN(E_BAD_ARGUMENT); if (menu) { if (menu->status & _POSTED) RETURN(E_POSTED); if (!(menu->items)) RETURN(E_NOT_CONNECTED); if (rows == 0) rows = menu->frows; if (cols == 0) cols = menu->fcols; if (menu->pattern) Reset_Pattern(menu); menu->frows = rows; menu->fcols = cols; assert(rows > 0 && cols > 0); total_rows = (menu->nitems - 1) / cols + 1; total_cols = (menu->opt & O_ROWMAJOR) ? minimum(menu->nitems, cols) : (menu->nitems - 1) / total_rows + 1; menu->rows = total_rows; menu->cols = total_cols; menu->arows = minimum(total_rows, rows); menu->toprow = 0; menu->curitem = *(menu->items); assert(menu->curitem); menu->status |= _LINK_NEEDED; _nc_Calculate_Item_Length_and_Width(menu); } else { if (rows > 0) _nc_Default_Menu.frows = rows; if (cols > 0) _nc_Default_Menu.fcols = cols; } RETURN(E_OK); }
/*--------------------------------------------------------------------------- | Facility : libnmenu | Function : bool _nc_Connect_Items(MENU *menu, ITEM **items) | | Description : Connect the items in the item array to the menu. | Decorate all the items with a number and a backward | pointer to the menu. | | Return Values : TRUE - successfull connection | FALSE - connection failed +--------------------------------------------------------------------------*/ bool _nc_Connect_Items(MENU *menu, ITEM **items) { ITEM **item; unsigned int ItemCount = 0; if ( menu && items ) { for(item=items; *item ; item++) { if ( (*item)->imenu ) { /* if a item is already connected, reject connection */ break; } } if (! (*item) ) /* we reached the end, so there was no connected item */ { for(item=items; *item ; item++) { if (menu->opt & O_ONEVALUE) { (*item)->value = FALSE; } (*item)->index = ItemCount++; (*item)->imenu = menu; } } } else return(FALSE); if (ItemCount != 0) { menu->items = items; menu->nitems = ItemCount; ComputeMaximum_NameDesc_Lengths(menu); if ( (menu->pattern = (char *)malloc( (unsigned)(1 + menu->namelen))) ) { Reset_Pattern(menu); set_menu_format(menu,menu->frows,menu->fcols); menu->curitem = *items; menu->toprow = 0; return(TRUE); } } /* If we fall through to this point, we have to reset all items connection and inform about a reject connection */ ResetConnectionInfo( menu, items ); return(FALSE); }
menu_driver(MENU * menu, int c) { #define NAVIGATE(dir) \ if (!item->dir)\ result = E_REQUEST_DENIED;\ else\ item = item->dir 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) RETURN(E_BAD_STATE); if (!(menu->status & _POSTED)) RETURN(E_NOT_POSTED); item = menu->curitem; my_top_row = menu->toprow; assert(item); if ((c > KEY_MAX) && (c <= MAX_MENU_COMMAND)) { if (!((c == REQ_BACK_PATTERN) || (c == REQ_NEXT_MATCH) || (c == REQ_PREV_MATCH))) { assert(menu->pattern); Reset_Pattern(menu); } 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 || !(item->up)) result = E_REQUEST_DENIED; else { --my_top_row; item = item->up; } break; case REQ_SCR_DLINE: /*=================*/ 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 */ result = E_REQUEST_DENIED; } else { 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->arows; if (rdiff <= 0) result = E_REQUEST_DENIED; else { my_top_row += rdiff; 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) result = E_REQUEST_DENIED; else { my_top_row -= 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]; break; case REQ_NEXT_ITEM: /*=================*/ if ((item->index + 1) >= menu->nitems) { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else item = menu->items[0]; } else item = menu->items[item->index + 1]; break; case REQ_PREV_ITEM: /*=================*/ if (item->index <= 0) { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else 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; } else { if (menu->curitem->opt & O_SELECTABLE) { menu->curitem->value = !menu->curitem->value; 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) { assert(menu->pattern); Remove_Character_From_Pattern(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); else { if ((item->index + 1) < menu->nitems) item = menu->items[item->index + 1]; else { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else item = menu->items[0]; } } break; case REQ_PREV_MATCH: /*==================*/ assert(menu->pattern); if (menu->pattern[0]) result = _nc_Match_Next_Character_In_Item_Name(menu, BS, &item); else { if (item->index) item = menu->items[item->index - 1]; else { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else item = menu->items[menu->nitems - 1]; } } break; default: /*======*/ result = E_UNKNOWN_COMMAND; break; } } else { /* not a command */ 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 result = E_REQUEST_DENIED; } #endif /* NCURSES_MOUSE_VERSION */ else result = E_UNKNOWN_COMMAND; } 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); }
/*--------------------------------------------------------------------------- | 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. | | Return Values : E_OK - success | E_BAD_ARGUMENT - invalid menu pointer | E_BAD_STATE - menu is in user hook routine | E_NOT_POSTED - menu is not posted +--------------------------------------------------------------------------*/ int menu_driver(MENU * menu, int c) { #define NAVIGATE(dir) \ if (!item->dir)\ result = E_REQUEST_DENIED;\ else\ item = item->dir int result = E_OK; ITEM *item; int my_top_row, rdiff; if (!menu) RETURN(E_BAD_ARGUMENT); if ( menu->status & _IN_DRIVER ) RETURN(E_BAD_STATE); if ( !( menu->status & _POSTED ) ) RETURN(E_NOT_POSTED); 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))) { assert( menu->pattern ); Reset_Pattern(menu); } 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) 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) { /* 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--; result = E_REQUEST_DENIED; } else item = item->down; break; case REQ_SCR_DPAGE: /*=================*/ rdiff = menu->rows - menu->arows - my_top_row; if (rdiff > menu->arows) rdiff = menu->arows; if (rdiff==0) result = E_REQUEST_DENIED; else { my_top_row += rdiff; while(rdiff-- > 0) item = item->down; } break; case REQ_SCR_UPAGE: /*=================*/ 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--) item = item->up; } break; case REQ_FIRST_ITEM: /*==================*/ item = menu->items[0]; break; case REQ_LAST_ITEM: /*=================*/ item = menu->items[menu->nitems-1]; break; case REQ_NEXT_ITEM: /*=================*/ if ((item->index+1)>=menu->nitems) { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else item = menu->items[0]; } else item = menu->items[item->index + 1]; break; case REQ_PREV_ITEM: /*=================*/ if (item->index<=0) { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else 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; } else { if (menu->curitem->opt & O_SELECTABLE) { menu->curitem->value = !menu->curitem->value; 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) { assert(menu->pattern); Remove_Character_From_Pattern(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); else { if ((item->index+1)<menu->nitems) item=menu->items[item->index+1]; else { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else item = menu->items[0]; } } break; case REQ_PREV_MATCH: /*==================*/ assert(menu->pattern); if (menu->pattern[0]) result = _nc_Match_Next_Character_In_Item_Name(menu,BS,&item); else { if (item->index) item = menu->items[item->index-1]; else { if (menu->opt & O_NONCYCLIC) result = E_REQUEST_DENIED; else 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 ); 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 ); RETURN(result); }