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 + -
显示快捷键?