menu_window.cpp
来自「ncbi源码」· C++ 代码 · 共 1,678 行 · 第 1/4 页
CPP
1,678 行
void CPopupMenu1::SetSelected(CMenuItem* item){ if(m_MenuBar) { // delegate CMenuItem* new_item = NULL; if(item) { CMenuItem* root = m_MenuBar->GetRootItem(); new_item = root->FindEqualSubItem(*item); _ASSERT(new_item); // must exist } m_MenuBar->SetSelected(new_item); } CMenu::SetSelected(item);}CRect CPopupMenu1::x_GetPopupItemRect(const CMenuItem& item){ CRect rc = CMenu::x_GetPopupItemRect(item); if(! x_IsMenuBar()) { rc.Inflate(m_Border, 0); } return rc;}/// this functions shows Popup menu and all its submenus and provides event /// loop for handling all events.void CPopupMenu1::Popup(){ if(sm_Popups.size()) { ERR_POST("CPopupMenu1::Popup() - must not be called recursively."); return; } sm_Popups.push_back(this); sm_bMenubar = (this->m_MenuBar != NULL); Fl_Group::current(0); //grab events and do initialization Fl_Window* prev_grab = Fl::grab(); Fl::grab(*this); // set initial state for this menu if(sm_bMenubar) { sm_CurrItem = m_Selected; // inherit selection from menubar if(m_MenuBar->x_IsKeyActivated()) { // do not expand submenus automatically sm_State = eIdle; } else { m_Selected = NULL; // to trigger submenu expansion sm_State = eTrackSubmenus; } } else { sm_CurrItem = NULL; sm_State = eIdle; } sm_CurrPopup = this; CMenuItem* prev_item = NULL; m_Timer.Init(1, kMenuDelay, false, this); do { // message loop - works while popup menus are on screen // show hidden menus for( size_t i_popup = 0; i_popup < sm_Popups.size(); i_popup++ ) { CPopupMenu1* p_popup = sm_Popups[i_popup]; if(! p_popup->shown()) { p_popup->show(); } } Fl::wait(); // handle events and calculate new state if(sm_CurrItem != prev_item) { x_UpdateListener(); } // performs actions depending on cuurent state switch(sm_State) { case eIdle: case eDone: break; case eHide: { //hide one popup if(sm_Popups.size() > 1) { // except the first one CPopupMenu1* dead_menu = sm_Popups.back(); delete dead_menu; sm_Popups.pop_back(); } sm_State = eIdle; }; break; default: if(sm_CurrItem == NULL) { // turn off selection in deepest menu, but don't erase other menus: if(sm_Popups.size()) { sm_Popups.back()->SetSelected(NULL); } } else if(! sm_CurrItem->IsSeparator()) { // change selected itme (if it isn;t a separator) if(sm_State == eTrackSubmenus && sm_CurrPopup->m_Selected == sm_CurrItem) { sm_State = eIdle; // nothing changed } else { TPopupVector::iterator it = std::find(sm_Popups.begin(), sm_Popups.end(), sm_CurrPopup); CMenuItem* item = sm_CurrItem; for( int i = it - sm_Popups.begin(); i >= 0; i-- ) { sm_Popups[i]->SetSelected(item); item = item->GetParent(); } } sm_CurrPopup->SetSelected(sm_CurrItem); switch(sm_State) { case eTrack: { x_CollapseToCurrent(); // close expanded submenus }; break; case eExpand: { x_ShowCurrItemSubmenu(true); //expand submenu and select item sm_State = eIdle; }; break; case eMenuPush: { x_CollapseToCurrent(); // close expanded submenus x_ShowCurrItemSubmenu(false); //expand new submenu }; break; case eTrackSubmenus: { if(sm_CurrPopup && sm_CurrPopup->x_IsMenuBar()) { x_CollapseToCurrent(); // close expanded submenus x_ShowCurrItemSubmenu(false); //expand new submenu } else { m_Timer.ReStart(); } }; break; default: break; }; //switch sm_State = eIdle; // procesing finished - go to neutral state }; prev_item = sm_CurrItem; }//switch } while(sm_State != eDone); _ASSERT(sm_State == eDone); // check exit condition m_Timer.Stop(); for( size_t i = 1; i < sm_Popups.size(); i++ ) { delete sm_Popups[i]; } sm_Popups.clear(); hide(); // close window Fl::grab(prev_grab); //return grab to previous owner sm_CurrItem = NULL; sm_CurrPopup = NULL; sm_State = eIdle; if(m_Cmd != eCmdInvalid) { if(GetCmdTarget()) { GetCmdTarget()->OnCommand(m_Cmd); } else { ERR_POST("CMenu cannot execute command - no command target specifed."); } }}// close all submenus up to current menuvoid CPopupMenu1::x_CollapseToCurrent(void){ // delete all submenus from the last one to "sm_CurrPopup" while(sm_Popups.size() > 1) { // except the first one CPopupMenu1* dead_menu = sm_Popups.back(); if(dead_menu != sm_CurrPopup) { delete dead_menu; sm_Popups.pop_back(); } else break; }}void CPopupMenu1::x_ShowCurrItemSubmenu(bool b_select){ _ASSERT(sm_CurrItem); if(sm_CurrItem->IsSubmenu() && ! sm_CurrItem->IsSubmenuEmpty()) { // show submenu CRect rc = sm_CurrPopup->x_GetPopupItemRect(*sm_CurrItem); rc.Offset(sm_CurrPopup->x(), sm_CurrPopup->y()); // to screen coords int x, y; if(sm_CurrPopup->x_IsMenuBar()) { x = rc.Left(); y = rc.Bottom(); } else { x = rc.Right(); y = rc.Top(); } int left = rc.Left(); int top = rc.Top(); CPopupMenu1* submenu = new CPopupMenu1(x, y, left, top, sm_CurrItem, GetCmdTarget(), GetHintListener()); sm_Popups.push_back(submenu); sm_CurrPopup = submenu; if(b_select) { x_SelectNextItem(); } else { sm_CurrItem = NULL; } sm_CurrPopup->SetSelected(sm_CurrItem); sm_CurrPopup->show(); }}// changes current item's state to oppositevoid CPopupMenu1::x_TogglePushItem(){ _ASSERT(m_bKeyActivated); // not supposed to be used overwise if(m_PushedItem == NULL) { m_MenuBar->m_PushedItem = m_PushedItem = sm_CurrItem; } else { m_MenuBar->m_PushedItem = m_PushedItem = NULL; redraw(); x_CloseItemSubmenu(); // collapse menu hierarhy } redraw();}/// handles events for all CPopupMenu-s being active at the momentint CPopupMenu1::handle(int event){ m_Event.OnFLTKEvent(event); switch(event) { case FL_KEYDOWN: return x_HandleKeyboard(); case FL_ENTER: case FL_LEAVE: case FL_MOVE: case FL_DRAG: case FL_PUSH: case FL_RELEASE: { // locate menu item being hit CPopupMenu1* popup = NULL; CMenuItem* item = NULL; int i_popup = sm_Popups.size() - 1; while(item == NULL && i_popup >= 0) { popup = sm_Popups[i_popup]; int x = Fl::event_x_root(); int y = Fl::event_y_root(); item = popup->x_HitTest(x, y); if(item == NULL) { i_popup--; } } if(item && item->IsSeparator()) { item = NULL; } switch(event) { case FL_PUSH: { sm_CurrItem = item; sm_CurrPopup = item ? popup : NULL; // if m_bSkipFirstRelease is "true" then Popup was shown on FL_RELEASE // and we do not need to skip next FL_RELEASE m_bSkipFirstRelease = false; if(sm_CurrItem && sm_CurrItem->IsSubmenu()) { if(x_IsKeyActivated()) { x_TogglePushItem(); sm_State = m_PushedItem ? eMenuPush : eHide; return 1; } sm_State = eMenuPush; } else { sm_State = ePush; } }; break; case FL_RELEASE: { if(m_bSkipFirstRelease) { m_bSkipFirstRelease = false; } else { bool b_skip = x_IsKeyActivated() || (item && ! item->IsEnabled()); if(! b_skip) { if(item == NULL || item->IsItem()) // command item pushed { if(item) { x_SetExecuteCommand(*item); } sm_State = eDone; } else if(popup && popup->m_MenuBar) { sm_State = eDone; } } } }; break; default: { if(! x_IsKeyActivated() || item) { sm_CurrItem = item; sm_CurrPopup = item ? popup : NULL; } sm_State = (! x_IsKeyActivated() || m_PushedItem) ? eTrackSubmenus : eTrack; }; }; if(event == FL_ENTER || event == FL_LEAVE) { redraw(); // we need to repaint itseld to reflect changes in "focused" state } return 1; }; };// switch return Fl_Window::handle(event);}int CPopupMenu1::x_HandleKeyboard(){ if(x_HandleShortcuts()) { return 1; } int key = Fl::event_key(); if(key == FL_Tab) { key = (Fl::event_shift()) ? FL_BackSpace : FL_Down; } switch(key) { case FL_Down: { if(! sm_CurrPopup->x_IsMenuBar()) { // Up-Down works only in submenus x_SelectNextItem(); } else if(x_IsKeyActivated()) { x_TogglePushItem(); sm_State = eExpand; } return 1; }; case FL_Up: { if(! sm_CurrPopup->x_IsMenuBar()) { // Up-Down works only in submenus x_SelectPrevItem(); } return 1; }; case FL_Right: { x_OnRightPressed(); return 1; }; case FL_Left: { x_OnLeftPressed(); return 1; }; case FL_Page_Up: case FL_Home: { x_SelectTopItem(); return 1; }; case FL_Page_Down: case FL_End: { x_SelectBottomItem(); return 1; }; case FL_Enter: case ' ': { if(sm_CurrItem && sm_CurrItem->IsEnabled()) { if(sm_CurrItem->IsItem()) { x_SetExecuteCommand(*sm_CurrItem); sm_State = eDone; } else { sm_State = eExpand; } } return 1; }; case FL_Escape: { if(x_IsMenuBar() && x_IsKeyActivated() && sm_Popups.size() > 1) { x_TogglePushItem(); // "unpush" selected item and close submenus } else { sm_CurrPopup = NULL; sm_State = eDone; // exit menus } return 1; }; }; return 0;}// handle both type of keyboard shortcuts - Access Keys and Acceleratorsint CPopupMenu1::x_HandleShortcuts(void){ // first try accelerators int accel = m_Event.GetAccelByEvent(); TCmdID cmd = eCmdInvalid; if(CAccelTable::GetCommandByAccel(accel, cmd)) { m_Cmd = cmd; sm_State = eDone; return 1; } // now handling access keys if(sm_CurrPopup) { char ch = tolower(Fl::event_key()); TAccessKeyToItemMap::const_iterator it = sm_CurrPopup->m_AccessKeyToItem.find(ch); if(it != sm_CurrPopup->m_AccessKeyToItem.end()) { sm_CurrItem = it->second; if(sm_CurrItem && sm_CurrItem->IsEnabled()) { if(sm_CurrItem->IsItem()) { x_SetExecuteCommand(*sm_CurrItem); sm_State = eDone; } else if(sm_CurrItem->IsSubmenu()) { sm_State = sm_CurrPopup->x_IsMenuBar() ? eTrackSubmenus : eTrack; } } return 1; } } return 0;}void CPopupMenu1::x_OnLeftPressed(void){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?