int _mouse_trafo(lua_State* const state) { int y, x; y = lua::get<int>(state, 1); x = lua::get<int>(state, 2); lua::push(state, mouse_trafo(&y, &x, lua::get<bool>(state, 3))); lua::push(state, y); lua::push(state, x); return 3; }
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); }
/* * this function will get the input from the user. * CAUTION: this is an hack, since it uses wgetch() * it will takeover the main dispatching loop !!! */ void wdg_input_get_input(wdg_t *wo) { int key, ret; struct wdg_mouse_event mouse; WDG_DEBUG_MSG("wdg_input_get_input"); /* dispatch keys to self */ WDG_LOOP { key = wgetch(stdscr); switch (key) { /* don't switch focus... */ case KEY_TAB: break; case KEY_CTRL_L: /* redrawing the screen is equivalent to resizing it */ case KEY_RESIZE: /* the screen has been resized */ wdg_redraw_all(); /* update the screen */ doupdate(); break; case ERR: /* non-blocking input reached the timeout */ /* sleep for milliseconds */ napms(WDG_INPUT_TIMEOUT * 10); refresh(); doupdate(); break; default: #ifdef NCURSES_MOUSE_VERSION /* handle mouse events */ if (key == KEY_MOUSE) { MEVENT event; getmouse(&event); mouse_trafo(&event.y, &event.x, TRUE); mouse.x = event.x; mouse.y = event.y; mouse.event = event.bstate; } #else /* we don't support mouse events */ memset(&mouse, 0, sizeof(mouse)); #endif /* dispatch the user input */ ret = wdg_input_get_msg(wo, key, &mouse); /* update the screen */ doupdate(); /* * if the object is destroyed or the input finished, * then return to the main loop */ if (ret == WDG_EFINISHED) { WDG_DEBUG_MSG("wdg_input_get_input: return to main loop"); return; } break; } } }