📄 fl_menu.cxx
字号:
if (!itemheight) { // menubar int x = 3; int i = 0; const Fl_Menu_Item *m = menu; for (;; m = m->next(), i++) { if (!m->text) return -1; x += m->measure(0, button) + 16; if (x > mx) break; } return i; } if (mx < Fl::box_dx(box()) || mx >= w()) return -1; int i = (my - Fl::box_dx(box()) - 1) / itemheight; if (i < 0 || i >= numitems) return -1; return i;}// return horizontal position for item i in a menubar:intmenuwindow::titlex(int i){ const Fl_Menu_Item *m; int x = 3; for (m = menu; i--; m = m->next()) x += m->measure(0, button) + 16; return x;}// match shortcuts & label shortcuts, don't search submenus:// returns menu item and indexconst Fl_Menu_Item *Fl_Menu_Item::find_shortcut(int *ip) const{ const Fl_Menu_Item *m1 = this; for (int ii = 0; m1 && m1->text; m1 = m1->next(1), ii++) { if (m1->activevisible() && (Fl::test_shortcut(m1->shortcut_) || Fl_Widget::test_shortcut(m1->text))) { if (ip) *ip = ii; return m1; } } return 0;}////////////////////////////////////////////////////////////////// Fl_Menu_Item::popup(...)// Because Fl::grab() is done, all events go to one of the menu windows.// But the handle method needs to look at all of them to find out// what item the user is pointing at. And it needs a whole lot// of other state variables to determine what is going on with// the currently displayed menus.// So the main loop (handlemenu()) puts all the state in a structure// and puts a pointer to it in a static location, so the handle()// on menus can refer to it and alter it. The handle() method// changes variables in this state to indicate what item is// picked, but does not actually alter the display, instead the// main loop does that. This is because the X mapping and unmapping// of windows is slow, and we don't want to fall behind the events.// values for menustate.state:#define INITIAL_STATE 0 // no mouse up or down since popup() called#define PUSH_STATE 1 // mouse has been pushed on a normal item#define DONE_STATE 2 // exit the popup, the current item was picked#define MENU_PUSH_STATE 3 // mouse has been pushed on a menu titlestruct menustate{ const Fl_Menu_Item *current_item; // what mouse is pointing at int menu_number; // which menu it is in int item_number; // which item in that menu, -1 if none menuwindow *p[20]; // pointers to menus int nummenus; int menubar; // if true p[0] is a menubar int state;};static menustate *p;static inline voidsetitem(const Fl_Menu_Item * i, int m, int n){ p->current_item = i; p->menu_number = m; p->item_number = n;}static voidsetitem(int m, int n){ menustate & p = *(::p); p.current_item = (n >= 0) ? p.p[m]->menu->next(n) : 0; p.menu_number = m; p.item_number = n;}static intforward(int menu){ // go to next item in menu menu if possible menustate & p = *(::p); menuwindow & m = *(p.p[menu]); int item = (menu == p.menu_number) ? p.item_number : m.selected; while (++item < m.numitems) { const Fl_Menu_Item *m1 = m.menu->next(item); if (m1->activevisible()) { setitem(m1, menu, item); return 1; } } return 0;}static intbackward(int menu){ // previous item in menu menu if possible menustate & p = *(::p); menuwindow & m = *(p.p[menu]); int item = (menu == p.menu_number) ? p.item_number : m.selected; if (item < 0) item = m.numitems; while (--item >= 0) { const Fl_Menu_Item *m1 = m.menu->next(item); if (m1->activevisible()) { setitem(m1, menu, item); return 1; } } return 0;}intmenuwindow::handle(int e){ menustate & p = *(::p); switch (e) { case FL_KEYBOARD: switch (Fl::event_key()) { case FL_Tab: if (Fl::event_shift() & FL_SHIFT) goto BACKTAB; case ' ': if (!forward(p.menu_number)) { p.item_number = -1; forward(p.menu_number); } return 1; case FL_BackSpace: case 0xFE20: // backtab BACKTAB: if (!backward(p.menu_number)) { p.item_number = -1; backward(p.menu_number); } return 1; case FL_Up: if (p.menubar && p.menu_number == 0); else if (backward(p.menu_number)); else if (p.menubar && p.menu_number == 1) setitem(0, p.p[0]->selected); return 1; case FL_Down: if (p.menu_number || !p.menubar) forward(p.menu_number); else if (p.menu_number < p.nummenus - 1) forward(p.menu_number + 1); return 1; case FL_Right: if (p.menubar && (p.menu_number <= 0 || p.menu_number == 1 && p.nummenus == 2)) forward(0); else if (p.menu_number < p.nummenus - 1) forward(p.menu_number + 1); return 1; case FL_Left: if (p.menubar && p.menu_number <= 1) backward(0); else if (p.menu_number > 0) setitem(p.menu_number - 1, p.p[p.menu_number - 1]->selected); return 1; case FL_Enter: p.state = DONE_STATE; return 1; case FL_Escape: setitem(0, -1, 0); p.state = DONE_STATE; return 1; } break; case FL_SHORTCUT:{ for (int menu = p.nummenus; menu--;) { menuwindow & mw = *(p.p[menu]); int item; const Fl_Menu_Item *m = mw.menu->find_shortcut(&item); if (m) { setitem(m, menu, item); if (!m->submenu()) p.state = DONE_STATE; return 1; } } } break; case FL_PUSH: //case FL_MOVE: case FL_DRAG:{ int mx = Fl::event_x() + x(); int my = Fl::event_y() + y(); int item = 0; int menu; for (menu = p.nummenus - 1;; menu--) { item = p.p[menu]->find_selected(mx, my); if (item >= 0) break; if (menu <= 0) break; } setitem(menu, item); if (e == FL_PUSH) { if (p.current_item && p.current_item->submenu() // this is a menu title && item != p.p[menu]->selected // and it is not already on && !p.current_item->callback_) // and it does not have a callback p.state = MENU_PUSH_STATE; else p.state = PUSH_STATE; } } return 1; case FL_RELEASE: // do nothing if they try to pick inactive items if (p.current_item && !p.current_item->activevisible()) return 1; // Mouse must either be held down/dragged some, or this must be // the second click (not the one that popped up the menu): if (!Fl::event_is_click() || p.state == PUSH_STATE || p.menubar && p.current_item && !p.current_item->submenu() // button ) {#if 0 // makes the check/radio items leave the menu up const Fl_Menu_Item *m = p.current_item; if (m && button && (m->flags & (FL_MENU_TOGGLE | FL_MENU_RADIO))) { ((Fl_Menu_ *) button)->picked(m); p.p[p.menu_number]->redraw(); } else#endif p.state = DONE_STATE; } return 1; } return Fl_Window::handle(e);}const Fl_Menu_Item *Fl_Menu_Item::pulldown(int X, int Y, int W, int H, const Fl_Menu_Item * initial_item, const Fl_Menu_ * pbutton, const Fl_Menu_Item * t, int menubar) const{ Fl_Group::current(0); // fix possible user error... button = pbutton; if (pbutton) { for (Fl_Window * w = pbutton->window(); w; w = w->window()) { X += w->x(); Y += w->y(); } } else { X += Fl::event_x_root() - Fl::event_x(); Y += Fl::event_y_root() - Fl::event_y(); } menuwindow mw(this, X, Y, W, H, initial_item, t, menubar); Fl::grab(mw); menustate p; ::p = &p; p.p[0] = &mw; p.nummenus = 1; p.menubar = menubar; p.state = INITIAL_STATE; menuwindow *fakemenu = 0; // kludge for buttons in menubar // preselected item, pop up submenus if necessary: if (initial_item && mw.selected >= 0) { setitem(0, mw.selected); goto STARTUP; } p.current_item = 0; p.menu_number = 0; p.item_number = -1; if (menubar) mw.handle(FL_DRAG); // find the initial menu initial_item = p.current_item; if (initial_item) goto STARTUP; // the main loop, runs until p.state goes to DONE_STATE: for (;;) { // make sure all the menus are shown: { for (int k = menubar; k < p.nummenus; k++) if (!p.p[k]->shown()) { if (p.p[k]->title) p.p[k]->title->show(); p.p[k]->show(); } } // get events: { const Fl_Menu_Item *oldi = p.current_item; Fl::wait(); if (p.state == DONE_STATE) break; // done. if (p.current_item == oldi) continue; } // only do rest if item changes: delete fakemenu; fakemenu = 0; // turn off "menubar button" if (!p.current_item) { // pointing at nothing // turn off selection in deepest menu, but don't erase other menus: p.p[p.nummenus - 1]->set_selected(-1); continue; } delete fakemenu; fakemenu = 0; initial_item = 0; // stop the startup code p.p[p.menu_number]->autoscroll(p.item_number); STARTUP: menuwindow & cw = *p.p[p.menu_number]; const Fl_Menu_Item *m = p.current_item; if (!m->activevisible()) { // pointing at inactive item cw.set_selected(-1); initial_item = 0; // turn off startup code continue; } cw.set_selected(p.item_number); if (m == initial_item) initial_item = 0; // stop the startup code if item found if (m->submenu()) { const Fl_Menu_Item *title = m; const Fl_Menu_Item *menutable; if (m->flags & FL_SUBMENU) menutable = m + 1; else menutable = (Fl_Menu_Item *) (m)->user_data_; // figure out where new menu goes: int nX, nY; if (!p.menu_number && p.menubar) { // menu off a menubar: nX = cw.x() + cw.titlex(p.item_number); nY = cw.y() + cw.h(); initial_item = 0; } else { nX = cw.x() + cw.w(); nY = cw.y() + 1 + p.item_number * cw.itemheight; title = 0; } if (initial_item) { // bring up submenu containing initial item: menuwindow *n = new menuwindow(menutable, X, Y, W, H, initial_item, title); p.p[p.nummenus++] = n; // move all earlier menus to line up with this new one: if (n->selected >= 0) { int dy = n->y() - nY; int dx = n->x() - nX; for (int menu = 0; menu <= p.menu_number; menu++) { menuwindow *t = p.p[menu]; int nx = t->x() + dx; if (nx < 0) { nx = 0; dx = -t->x(); } int ny = t->y() + dy + 1; if (ny < 0) { ny = 0; dy = -t->y() - 1; } t->position(nx, ny); } setitem(p.nummenus - 1, n->selected); goto STARTUP; } } else if (p.nummenus > p.menu_number + 1 && p.p[p.menu_number + 1]->menu == menutable) { // the menu is already up: while (p.nummenus > p.menu_number + 2) delete p.p[--p.nummenus]; p.p[p.nummenus - 1]->set_selected(-1); } else { // delete all the old menus and create new one: while (p.nummenus > p.menu_number + 1) delete p.p[--p.nummenus]; p.p[p.nummenus++] = new menuwindow(menutable, nX, nY, title ? 1 : 0, 0, 0, title, 0, menubar); } } else { // !m->submenu(): while (p.nummenus > p.menu_number + 1) delete p.p[--p.nummenus]; if (!p.menu_number && p.menubar) { // kludge so "menubar buttons" turn "on" by using menu title: fakemenu = new menuwindow(0, cw.x() + cw.titlex(p.item_number), cw.y() + cw.h(), 0, 0, 0, m, 0, 1); fakemenu->title->show(); } } } const Fl_Menu_Item *m = p.current_item; delete fakemenu; while (p.nummenus > 1) delete p.p[--p.nummenus]; mw.hide(); Fl::release(); return m;}const Fl_Menu_Item *Fl_Menu_Item::popup(int X, int Y, const char *title, const Fl_Menu_Item * picked, const Fl_Menu_ * button) const{ static Fl_Menu_Item dummy; // static so it is all zeros dummy.text = title; return pulldown(X, Y, 0, 0, picked, button, title ? &dummy : 0);}const Fl_Menu_Item *Fl_Menu_Item::test_shortcut() const{ const Fl_Menu_Item *m = this; const Fl_Menu_Item *ret = 0; if (m) for (; m->text; m = m->next()) { if (m->activevisible()) { // return immediately any match of an item in top level menu: if (Fl::test_shortcut(m->shortcut_)) return m; // if (Fl_Widget::test_shortcut(m->text)) return m; // only return matches from lower menu if nothing found in top menu: if (!ret && m->submenu()) { const Fl_Menu_Item *s = (m->flags & FL_SUBMENU) ? m + 1 : (const Fl_Menu_Item *) m->user_data_; ret = s->test_shortcut(); } } } return ret;}//// End of "$Id: Fl_Menu.cxx,v 1.1.1.1 2003/08/07 21:18:40 jasonk Exp $".//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -