menu.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,300 行 · 第 1/5 页
CPP
2,300 行
return m_menuInfos[pos].IsEnabled();
}
void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
{
wxCHECK_RET( pos < GetCount(), _T("invalid index in EnableTop") );
if ( label != m_menuInfos[pos].GetLabel() )
{
m_menuInfos[pos].SetLabel(label);
RefreshItem(pos);
}
//else: nothing to do
}
wxString wxMenuBar::GetLabelTop(size_t pos) const
{
wxCHECK_MSG( pos < GetCount(), wxEmptyString, _T("invalid index in GetLabelTop") );
return m_menuInfos[pos].GetLabel();
}
// ----------------------------------------------------------------------------
// wxMenuBar drawing
// ----------------------------------------------------------------------------
void wxMenuBar::RefreshAllItemsAfter(size_t pos)
{
if ( !IsCreated() )
{
// no need to refresh if nothing is shown yet
return;
}
wxRect rect = GetItemRect(pos);
rect.width = GetClientSize().x - rect.x;
RefreshRect(rect);
}
void wxMenuBar::RefreshItem(size_t pos)
{
wxCHECK_RET( pos != (size_t)-1,
_T("invalid item in wxMenuBar::RefreshItem") );
if ( !IsCreated() )
{
// no need to refresh if nothing is shown yet
return;
}
RefreshRect(GetItemRect(pos));
}
void wxMenuBar::DoDraw(wxControlRenderer *renderer)
{
wxDC& dc = renderer->GetDC();
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
// redraw only the items which must be redrawn
// we don't have to use GetUpdateClientRect() here because our client rect
// is the same as total one
wxRect rectUpdate = GetUpdateRegion().GetBox();
int flagsMenubar = GetStateFlags();
wxRect rect;
rect.y = 0;
rect.height = GetClientSize().y;
wxCoord x = 0;
size_t count = GetCount();
for ( size_t n = 0; n < count; n++ )
{
if ( x > rectUpdate.GetRight() )
{
// all remaining items are to the right of rectUpdate
break;
}
rect.x = x;
rect.width = GetItemWidth(n);
x += rect.width;
if ( x < rectUpdate.x )
{
// this item is still to the left of rectUpdate
continue;
}
int flags = flagsMenubar;
if ( m_current != -1 && n == (size_t)m_current )
{
flags |= wxCONTROL_SELECTED;
}
if ( !IsEnabledTop(n) )
{
flags |= wxCONTROL_DISABLED;
}
GetRenderer()->DrawMenuBarItem
(
dc,
rect,
m_menuInfos[n].GetLabel(),
flags,
m_menuInfos[n].GetAccelIndex()
);
}
}
// ----------------------------------------------------------------------------
// wxMenuBar geometry
// ----------------------------------------------------------------------------
wxRect wxMenuBar::GetItemRect(size_t pos) const
{
wxASSERT_MSG( pos < GetCount(), _T("invalid menu bar item index") );
wxASSERT_MSG( IsCreated(), _T("can't call this method yet") );
wxRect rect;
rect.x =
rect.y = 0;
rect.height = GetClientSize().y;
for ( size_t n = 0; n < pos; n++ )
{
rect.x += GetItemWidth(n);
}
rect.width = GetItemWidth(pos);
return rect;
}
wxSize wxMenuBar::DoGetBestClientSize() const
{
wxSize size;
if ( GetMenuCount() > 0 )
{
wxClientDC dc(wxConstCast(this, wxMenuBar));
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
dc.GetTextExtent(GetLabelTop(0), &size.x, &size.y);
// adjust for the renderer we use
size = GetRenderer()->GetMenuBarItemSize(size);
}
else // empty menubar
{
size.x =
size.y = 0;
}
// the width is arbitrary, of course, for horizontal menubar
size.x = 100;
return size;
}
int wxMenuBar::GetMenuFromPoint(const wxPoint& pos) const
{
if ( pos.x < 0 || pos.y < 0 || pos.y > GetClientSize().y )
return -1;
// do find it
wxCoord x = 0;
size_t count = GetCount();
for ( size_t item = 0; item < count; item++ )
{
x += GetItemWidth(item);
if ( x > pos.x )
{
return item;
}
}
// to the right of the last menu item
return -1;
}
// ----------------------------------------------------------------------------
// wxMenuBar menu operations
// ----------------------------------------------------------------------------
void wxMenuBar::SelectMenu(size_t pos)
{
SetFocus();
wxLogTrace(_T("mousecapture"), _T("Capturing mouse from wxMenuBar::SelectMenu"));
CaptureMouse();
DoSelectMenu(pos);
}
void wxMenuBar::DoSelectMenu(size_t pos)
{
wxCHECK_RET( pos < GetCount(), _T("invalid menu index in DoSelectMenu") );
int posOld = m_current;
m_current = pos;
if ( posOld != -1 )
{
// close the previous menu
if ( IsShowingMenu() )
{
// restore m_shouldShowMenu flag after DismissMenu() which resets
// it to false
bool old = m_shouldShowMenu;
DismissMenu();
m_shouldShowMenu = old;
}
RefreshItem((size_t)posOld);
}
RefreshItem(pos);
}
void wxMenuBar::PopupMenu(size_t pos)
{
wxCHECK_RET( pos < GetCount(), _T("invalid menu index in PopupCurrentMenu") );
SetFocus();
DoSelectMenu(pos);
PopupCurrentMenu();
}
// ----------------------------------------------------------------------------
// wxMenuBar input handing
// ----------------------------------------------------------------------------
/*
Note that wxMenuBar doesn't use wxInputHandler but handles keyboard and
mouse in the same way under all platforms. This is because it doesn't derive
from wxControl (which works with input handlers) but directly from wxWindow.
Also, menu bar input handling is rather simple, so maybe it's not really
worth making it themeable - at least I've decided against doing it now as it
would merging the changes back into trunk more difficult. But it still could
be done later if really needed.
*/
void wxMenuBar::OnKillFocus(wxFocusEvent& event)
{
if ( m_current != -1 )
{
RefreshItem((size_t)m_current);
m_current = -1;
}
event.Skip();
}
void wxMenuBar::OnLeftDown(wxMouseEvent& event)
{
if ( HasCapture() )
{
OnDismiss();
event.Skip();
}
else // we didn't have mouse capture, capture it now
{
m_current = GetMenuFromPoint(event.GetPosition());
if ( m_current == -1 )
{
// unfortunately, we can't prevent wxMSW from giving us the focus,
// so we can only give it back
GiveAwayFocus();
}
else // on item
{
wxLogTrace(_T("mousecapture"), _T("Capturing mouse from wxMenuBar::OnLeftDown"));
CaptureMouse();
// show it as selected
RefreshItem((size_t)m_current);
// show the menu
PopupCurrentMenu(false /* don't select first item - as Windows does */);
}
}
}
void wxMenuBar::OnMouseMove(wxMouseEvent& event)
{
if ( HasCapture() )
{
(void)ProcessMouseEvent(event.GetPosition());
}
else
{
event.Skip();
}
}
bool wxMenuBar::ProcessMouseEvent(const wxPoint& pt)
{
// a hack to ignore the extra mouse events MSW sends us: this is similar to
// wxUSE_MOUSEEVENT_HACK in wxWin itself but it isn't enough for us here as
// we get the messages from different windows (old and new popup menus for
// example)
#ifdef __WXMSW__
static wxPoint s_ptLast;
if ( pt == s_ptLast )
{
return false;
}
s_ptLast = pt;
#endif // __WXMSW__
int currentNew = GetMenuFromPoint(pt);
if ( (currentNew == -1) || (currentNew == m_current) )
{
return false;
}
// select the new active item
DoSelectMenu(currentNew);
// show the menu if we know that we should, even if we hadn't been showing
// it before (this may happen if the previous menu was disabled)
if ( m_shouldShowMenu && !m_menuShown)
{
// open the new menu if the old one we closed had been opened
PopupCurrentMenu(false /* don't select first item - as Windows does */);
}
return true;
}
void wxMenuBar::OnKeyDown(wxKeyEvent& event)
{
// ensure that we have a current item - we might not have it if we're
// given the focus with Alt or F10 press (and under GTK+ the menubar
// somehow gets the keyboard events even when it doesn't have focus...)
if ( m_current == -1 )
{
if ( !HasCapture() )
{
SelectMenu(0);
}
else // we do have capture
{
// we always maintain a valid current item while we're in modal
// state (i.e. have the capture)
wxFAIL_MSG( _T("how did we manage to lose current item?") );
return;
}
}
int key = event.GetKeyCode();
// first let the menu have it
if ( IsShowingMenu() && m_menuShown->ProcessKeyDown(key) )
{
return;
}
// cycle through the menu items when left/right arrows are pressed and open
// the menu when up/down one is
switch ( key )
{
case WXK_ALT:
// Alt must be processed at wxWindow level too
event.Skip();
// fall through
case WXK_ESCAPE:
// remove the selection and give the focus away
if ( m_current != -1 )
{
if ( IsShowingMenu() )
{
DismissMenu();
}
OnDismiss();
}
break;
case WXK_LEFT:
case WXK_RIGHT:
{
size_t count = GetCount();
if ( count == 1 )
{
// the item won't change anyhow
break;
}
//else: otherwise, it will
// remember if we were showing a menu - if we did, we should
// show the new menu after changing the item
bool wasMenuOpened = IsShowingMenu();
if ( wasMenuOpened )
{
DismissMenu();
}
// cast is safe as we tested for -1 above
size_t currentNew = (size_t)m_current;
if ( key == WXK_LEFT )
{
if ( currentNew-- == 0 )
currentNew = count - 1;
}
else // right
{
if ( ++currentNew == count )
currentNew = 0;
}
DoSelectMenu(currentNew);
if ( wasMenuOpened )
{
PopupCurrentMenu();
}
}
break;
case WXK_DOWN:
case WXK_UP:
case WXK_RETURN:
// open the menu
PopupCurrentMenu();
break;
default:
// letters open the corresponding menu
{
bool unique;
int idxFound = FindNextItemForAccel(m_current, key, &unique);
if ( idxFound != -1 )
{
if ( IsShowingMenu() )
{
DismissMenu();
}
DoSelectMenu((size_t)idxFound);
// if the item is not unique, just select it but don't
// activate as the user might have wanted to activate
// another item
//
// also, don't try to open a disabled menu
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?