menu.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,300 行 · 第 1/5 页

CPP
2,300
字号
        m_popupMenu->SelectFirst();
    }

    // the geometry might have changed since the last time we were shown, so
    // always resize
    m_popupMenu->SetClientSize(GetGeometryInfo().GetSize());

    // position it as specified
    m_popupMenu->Position(pos, size);

    // the menu can't have the focus itself (it is a Windows limitation), so
    // always keep the focus at the originating window
    wxWindow *focus = GetRootWindow();

    wxASSERT_MSG( focus, _T("no window to keep focus on?") );

    // and show it
    m_popupMenu->Popup(focus);
}

void wxMenu::Dismiss()
{
    wxCHECK_RET( IsShown(), _T("can't dismiss hidden menu") );

    m_popupMenu->Dismiss();
}

// ----------------------------------------------------------------------------
// wxMenu event processing
// ----------------------------------------------------------------------------

bool wxMenu::ProcessKeyDown(int key)
{
    wxCHECK_MSG( m_popupMenu, false,
                 _T("can't process key events if not shown") );

    return m_popupMenu->ProcessKeyDown(key);
}

bool wxMenu::ClickItem(wxMenuItem *item)
{
    int isChecked;
    if ( item->IsCheckable() )
    {
        // update the item state
        isChecked = !item->IsChecked();

        item->Check(isChecked != 0);
    }
    else
    {
        // not applicabled
        isChecked = -1;
    }

    return SendEvent(item->GetId(), isChecked);
}

// ----------------------------------------------------------------------------
// wxMenu accel support
// ----------------------------------------------------------------------------

#if wxUSE_ACCEL

bool wxMenu::ProcessAccelEvent(const wxKeyEvent& event)
{
    // do we have an item for this accel?
    wxMenuItem *item = m_accelTable.GetMenuItem(event);
    if ( item && item->IsEnabled() )
    {
        return ClickItem(item);
    }

    // try our submenus
    for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
          node;
          node = node->GetNext() )
    {
        const wxMenuItem *item = node->GetData();
        if ( item->IsSubMenu() && item->IsEnabled() )
        {
            // try its elements
            if ( item->GetSubMenu()->ProcessAccelEvent(event) )
            {
                return true;
            }
        }
    }

    return false;
}

void wxMenu::AddAccelFor(wxMenuItem *item)
{
    wxAcceleratorEntry *accel = item->GetAccel();
    if ( accel )
    {
        accel->SetMenuItem(item);

        m_accelTable.Add(*accel);

        delete accel;
    }
}

void wxMenu::RemoveAccelFor(wxMenuItem *item)
{
    wxAcceleratorEntry *accel = item->GetAccel();
    if ( accel )
    {
        m_accelTable.Remove(*accel);

        delete accel;
    }
}

#endif // wxUSE_ACCEL

// ----------------------------------------------------------------------------
// wxMenuItem construction
// ----------------------------------------------------------------------------

wxMenuItem::wxMenuItem(wxMenu *parentMenu,
                       int id,
                       const wxString& text,
                       const wxString& help,
                       wxItemKind kind,
                       wxMenu *subMenu)
          : wxMenuItemBase(parentMenu, id, text, help, kind, subMenu)
{
    m_posY =
    m_height = wxDefaultCoord;

    m_radioGroup.start = -1;
    m_isRadioGroupStart = false;

    m_bmpDisabled = wxNullBitmap;

    UpdateAccelInfo();
}

wxMenuItem::~wxMenuItem()
{
}

// ----------------------------------------------------------------------------
// wxMenuItemBase methods implemented here
// ----------------------------------------------------------------------------

/* static */
wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu,
                                int id,
                                const wxString& name,
                                const wxString& help,
                                wxItemKind kind,
                                wxMenu *subMenu)
{
    return new wxMenuItem(parentMenu, id, name, help, kind, subMenu);
}

/* static */
wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
{
    return wxStripMenuCodes(text);
}

// ----------------------------------------------------------------------------
// wxMenuItem operations
// ----------------------------------------------------------------------------

void wxMenuItem::NotifyMenu()
{
    m_parentMenu->RefreshItem(this);
}

void wxMenuItem::UpdateAccelInfo()
{
    m_indexAccel = wxControl::FindAccelIndex(m_text);

    // will be empty if the text contains no TABs - ok
    m_strAccel = m_text.AfterFirst(_T('\t'));
}

void wxMenuItem::SetText(const wxString& text)
{
    if ( text != m_text )
    {
        // first call the base class version to change m_text
        wxMenuItemBase::SetText(text);

        UpdateAccelInfo();

        NotifyMenu();
    }
}

void wxMenuItem::SetCheckable(bool checkable)
{
    if ( checkable != IsCheckable() )
    {
        wxMenuItemBase::SetCheckable(checkable);

        NotifyMenu();
    }
}

void wxMenuItem::SetBitmaps(const wxBitmap& bmpChecked,
                            const wxBitmap& bmpUnchecked)
{
    m_bmpChecked = bmpChecked;
    m_bmpUnchecked = bmpUnchecked;

    NotifyMenu();
}

void wxMenuItem::Enable(bool enable)
{
    if ( enable != m_isEnabled )
    {
        wxMenuItemBase::Enable(enable);

        NotifyMenu();
    }
}

void wxMenuItem::Check(bool check)
{
    wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );

    if ( m_isChecked == check )
        return;

    if ( GetKind() == wxITEM_RADIO )
    {
        // it doesn't make sense to uncheck a radio item - what would this do?
        if ( !check )
            return;

        // get the index of this item in the menu
        const wxMenuItemList& items = m_parentMenu->GetMenuItems();
        int pos = items.IndexOf(this);
        wxCHECK_RET( pos != wxNOT_FOUND,
                     _T("menuitem not found in the menu items list?") );

        // get the radio group range
        int start,
            end;

        if ( m_isRadioGroupStart )
        {
            // we already have all information we need
            start = pos;
            end = m_radioGroup.end;
        }
        else // next radio group item
        {
            // get the radio group end from the start item
            start = m_radioGroup.start;
            end = items.Item(start)->GetData()->m_radioGroup.end;
        }

        // also uncheck all the other items in this radio group
        wxMenuItemList::compatibility_iterator node = items.Item(start);
        for ( int n = start; n <= end && node; n++ )
        {
            if ( n != pos )
            {
                node->GetData()->m_isChecked = false;
            }
            node = node->GetNext();
        }
    }

    wxMenuItemBase::Check(check);

    NotifyMenu();
}

// radio group stuff
// -----------------

void wxMenuItem::SetAsRadioGroupStart()
{
    m_isRadioGroupStart = true;
}

void wxMenuItem::SetRadioGroupStart(int start)
{
    wxASSERT_MSG( !m_isRadioGroupStart,
                  _T("should only be called for the next radio items") );

    m_radioGroup.start = start;
}

void wxMenuItem::SetRadioGroupEnd(int end)
{
    wxASSERT_MSG( m_isRadioGroupStart,
                  _T("should only be called for the first radio item") );

    m_radioGroup.end = end;
}

// ----------------------------------------------------------------------------
// wxMenuBar creation
// ----------------------------------------------------------------------------

void wxMenuBar::Init()
{
    m_frameLast = NULL;

    m_current = -1;

    m_menuShown = NULL;

    m_shouldShowMenu = false;
}

wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
{
    Init();

    for (size_t i = 0; i < n; ++i )
        Append(menus[i], titles[i]);
}

void wxMenuBar::Attach(wxFrame *frame)
{
    // maybe you really wanted to call Detach()?
    wxCHECK_RET( frame, _T("wxMenuBar::Attach(NULL) called") );

    wxMenuBarBase::Attach(frame);

    if ( IsCreated() )
    {
        // reparent if necessary
        if ( m_frameLast != frame )
        {
            Reparent(frame);
        }

        // show it back - was hidden by Detach()
        Show();
    }
    else // not created yet, do it now
    {
        // we have no way to return the error from here anyhow :-(
        (void)Create(frame, wxID_ANY);

        SetCursor(wxCURSOR_ARROW);

        SetFont(wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT));

        // calculate and set our height (it won't be changed any more)
        SetSize(wxDefaultCoord, GetBestSize().y);
    }

    // remember the last frame which had us to avoid unnecessarily reparenting
    // above
    m_frameLast = frame;
}

void wxMenuBar::Detach()
{
    // don't delete the window because we may be reattached later, just hide it
    if ( m_frameLast )
    {
        Hide();
    }

    wxMenuBarBase::Detach();
}

wxMenuBar::~wxMenuBar()
{
}

// ----------------------------------------------------------------------------
// wxMenuBar adding/removing items
// ----------------------------------------------------------------------------

bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
{
    return Insert(GetCount(), menu, title);
}

bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
{
    if ( !wxMenuBarBase::Insert(pos, menu, title) )
        return false;

    wxMenuInfo *info = new wxMenuInfo(title);
    m_menuInfos.Insert(info, pos);

    RefreshAllItemsAfter(pos);

    return true;
}

wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
{
    wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);

    if ( menuOld )
    {
        wxMenuInfo& info = m_menuInfos[pos];

        info.SetLabel(title);

        // even if the old menu was disabled, the new one is not any more
        info.SetEnabled();

        // even if we change only this one, the new label has different width,
        // so we need to refresh everything beyond this item as well
        RefreshAllItemsAfter(pos);
    }

    return menuOld;
}

wxMenu *wxMenuBar::Remove(size_t pos)
{
    wxMenu *menuOld = wxMenuBarBase::Remove(pos);

    if ( menuOld )
    {
        m_menuInfos.RemoveAt(pos);

        // this doesn't happen too often, so don't try to be too smart - just
        // refresh everything
        Refresh();
    }

    return menuOld;
}

// ----------------------------------------------------------------------------
// wxMenuBar top level menus access
// ----------------------------------------------------------------------------

wxCoord wxMenuBar::GetItemWidth(size_t pos) const
{
    return m_menuInfos[pos].GetWidth(wxConstCast(this, wxMenuBar));
}

void wxMenuBar::EnableTop(size_t pos, bool enable)
{
    wxCHECK_RET( pos < GetCount(), _T("invalid index in EnableTop") );

    if ( enable != m_menuInfos[pos].IsEnabled() )
    {
        m_menuInfos[pos].SetEnabled(enable);

        RefreshItem(pos);
    }
    //else: nothing to do
}

bool wxMenuBar::IsEnabledTop(size_t pos) const
{
    wxCHECK_MSG( pos < GetCount(), false, _T("invalid index in IsEnabledTop") );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?