menu.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,300 行 · 第 1/5 页
CPP
2,300 行
// close just this menu
Dismiss();
HandleDismiss(false);
break;
case WXK_RETURN:
processed = ActivateItem(item);
break;
case WXK_HOME:
ChangeCurrent(m_menu->GetMenuItems().GetFirst());
break;
case WXK_END:
ChangeCurrent(m_menu->GetMenuItems().GetLast());
break;
case WXK_UP:
case WXK_DOWN:
{
bool up = key == WXK_UP;
wxMenuItemList::compatibility_iterator nodeStart = up ? GetPrevNode()
: GetNextNode(),
node = nodeStart;
while ( node && node->GetData()->IsSeparator() )
{
node = up ? GetPrevNode(node) : GetNextNode(node);
if ( node == nodeStart )
{
// nothing but separators and disabled items in this
// menu, break out
#if wxUSE_STL
node = wxMenuItemList::compatibility_iterator();
#else
node = NULL;
#endif
}
}
if ( node )
{
ChangeCurrent(node);
}
else
{
processed = false;
}
}
break;
case WXK_RIGHT:
// don't try to reopen an already opened menu
if ( !HasOpenSubmenu() && CanOpen(item) )
{
OpenSubmenu(item);
}
else
{
processed = false;
}
break;
default:
// look for the menu item starting with this letter
if ( wxIsalnum((wxChar)key) )
{
// we want to start from the item after this one because
// if we're already on the item with the given accel we want to
// go to the next one, not to stay in place
wxMenuItemList::compatibility_iterator nodeStart = GetNextNode();
// do we have more than one item with this accel?
bool notUnique = false;
// translate everything to lower case before comparing
wxChar chAccel = (wxChar)wxTolower(key);
// loop through all items searching for the item with this
// accel
wxMenuItemList::compatibility_iterator node = nodeStart,
#if wxUSE_STL
nodeFound = wxMenuItemList::compatibility_iterator();
#else
nodeFound = NULL;
#endif
for ( ;; )
{
item = node->GetData();
int idxAccel = item->GetAccelIndex();
if ( idxAccel != -1 &&
wxTolower(item->GetLabel()[(size_t)idxAccel])
== chAccel )
{
// ok, found an item with this accel
if ( !nodeFound )
{
// store it but continue searching as we need to
// know if it's the only item with this accel or if
// there are more
nodeFound = node;
}
else // we already had found such item
{
notUnique = true;
// no need to continue further, we won't find
// anything we don't already know
break;
}
}
// we want to iterate over all items wrapping around if
// necessary
node = GetNextNode(node);
if ( node == nodeStart )
{
// we've seen all nodes
break;
}
}
if ( nodeFound )
{
item = nodeFound->GetData();
// go to this item anyhow
ChangeCurrent(nodeFound);
if ( !notUnique && item->IsEnabled() )
{
// unique item with this accel - activate it
processed = ActivateItem(item);
}
//else: just select it but don't activate as the user might
// have wanted to activate another item
// skip "processed = false" below
break;
}
}
processed = false;
}
return processed;
}
// ----------------------------------------------------------------------------
// wxMenu
// ----------------------------------------------------------------------------
void wxMenu::Init()
{
m_geometry = NULL;
m_popupMenu = NULL;
m_startRadioGroup = -1;
}
wxMenu::~wxMenu()
{
delete m_geometry;
delete m_popupMenu;
}
// ----------------------------------------------------------------------------
// wxMenu and wxMenuGeometryInfo
// ----------------------------------------------------------------------------
wxMenuGeometryInfo::~wxMenuGeometryInfo()
{
}
const wxMenuGeometryInfo& wxMenu::GetGeometryInfo() const
{
if ( !m_geometry )
{
if ( m_popupMenu )
{
wxConstCast(this, wxMenu)->m_geometry =
m_popupMenu->GetRenderer()->GetMenuGeometry(m_popupMenu, *this);
}
else
{
wxFAIL_MSG( _T("can't get geometry without window") );
}
}
return *m_geometry;
}
void wxMenu::InvalidateGeometryInfo()
{
if ( m_geometry )
{
delete m_geometry;
m_geometry = NULL;
}
}
// ----------------------------------------------------------------------------
// wxMenu adding/removing items
// ----------------------------------------------------------------------------
void wxMenu::OnItemAdded(wxMenuItem *item)
{
InvalidateGeometryInfo();
#if wxUSE_ACCEL
AddAccelFor(item);
#endif // wxUSE_ACCEL
// the submenus of a popup menu should have the same invoking window as it
// has
if ( m_invokingWindow && item->IsSubMenu() )
{
item->GetSubMenu()->SetInvokingWindow(m_invokingWindow);
}
}
void wxMenu::EndRadioGroup()
{
// we're not inside a radio group any longer
m_startRadioGroup = -1;
}
wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
{
if ( item->GetKind() == wxITEM_RADIO )
{
int count = GetMenuItemCount();
if ( m_startRadioGroup == -1 )
{
// start a new radio group
m_startRadioGroup = count;
// for now it has just one element
item->SetAsRadioGroupStart();
item->SetRadioGroupEnd(m_startRadioGroup);
}
else // extend the current radio group
{
// we need to update its end item
item->SetRadioGroupStart(m_startRadioGroup);
wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_startRadioGroup);
if ( node )
{
node->GetData()->SetRadioGroupEnd(count);
}
else
{
wxFAIL_MSG( _T("where is the radio group start item?") );
}
}
}
else // not a radio item
{
EndRadioGroup();
}
if ( !wxMenuBase::DoAppend(item) )
return NULL;
OnItemAdded(item);
return item;
}
wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
{
if ( !wxMenuBase::DoInsert(pos, item) )
return NULL;
OnItemAdded(item);
return item;
}
wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
{
wxMenuItem *itemOld = wxMenuBase::DoRemove(item);
if ( itemOld )
{
InvalidateGeometryInfo();
#if wxUSE_ACCEL
RemoveAccelFor(item);
#endif // wxUSE_ACCEL
}
return itemOld;
}
// ----------------------------------------------------------------------------
// wxMenu attaching/detaching
// ----------------------------------------------------------------------------
void wxMenu::Attach(wxMenuBarBase *menubar)
{
wxMenuBase::Attach(menubar);
wxCHECK_RET( m_menuBar, _T("menubar can't be NULL after attaching") );
// unfortunately, we can't use m_menuBar->GetEventHandler() here because,
// if the menubar is currently showing a menu, its event handler is a
// temporary one installed by wxPopupWindow and so will disappear soon any
// any attempts to use it from the newly attached menu would result in a
// crash
//
// so we use the menubar itself, even if it's a pity as it means we can't
// redirect all menu events by changing the menubar handler (FIXME)
SetNextHandler(m_menuBar);
}
void wxMenu::Detach()
{
wxMenuBase::Detach();
}
// ----------------------------------------------------------------------------
// wxMenu misc functions
// ----------------------------------------------------------------------------
wxWindow *wxMenu::GetRootWindow() const
{
if ( GetMenuBar() )
{
// simple case - a normal menu attached to the menubar
return GetMenuBar();
}
// we're a popup menu but the trouble is that only the top level popup menu
// has a pointer to the invoking window, so we must walk up the menu chain
// if needed
wxWindow *win = GetInvokingWindow();
if ( win )
{
// we already have it
return win;
}
wxMenu *menu = GetParent();
while ( menu )
{
// We are a submenu of a menu of a menubar
if (menu->GetMenuBar())
return menu->GetMenuBar();
win = menu->GetInvokingWindow();
if ( win )
break;
menu = menu->GetParent();
}
// we're probably going to crash in the caller anyhow, but try to detect
// this error as soon as possible
wxASSERT_MSG( win, _T("menu without any associated window?") );
// also remember it in this menu so that we don't have to search for it the
// next time
wxConstCast(this, wxMenu)->m_invokingWindow = win;
return win;
}
wxRenderer *wxMenu::GetRenderer() const
{
// we're going to crash without renderer!
wxCHECK_MSG( m_popupMenu, NULL, _T("neither popup nor menubar menu?") );
return m_popupMenu->GetRenderer();
}
void wxMenu::RefreshItem(wxMenuItem *item)
{
// the item geometry changed, so our might have changed as well
InvalidateGeometryInfo();
if ( IsShown() )
{
// this would be a bug in IsShown()
wxCHECK_RET( m_popupMenu, _T("must have popup window if shown!") );
// recalc geometry to update the item height and such
(void)GetGeometryInfo();
m_popupMenu->RefreshItem(item);
}
}
// ----------------------------------------------------------------------------
// wxMenu showing and hiding
// ----------------------------------------------------------------------------
bool wxMenu::IsShown() const
{
return m_popupMenu && m_popupMenu->IsShown();
}
void wxMenu::OnDismiss(bool dismissParent)
{
if ( m_menuParent )
{
// always notify the parent about submenu disappearance
wxPopupMenuWindow *win = m_menuParent->m_popupMenu;
if ( win )
{
win->OnSubmenuDismiss( true );
}
else
{
wxFAIL_MSG( _T("parent menu not shown?") );
}
// and if we dismiss everything, propagate to parent
if ( dismissParent )
{
// dismissParent is recursive
m_menuParent->Dismiss();
m_menuParent->OnDismiss(true);
}
}
else // no parent menu
{
// notify the menu bar if we're a top level menu
if ( m_menuBar )
{
m_menuBar->OnDismissMenu(dismissParent);
}
else // popup menu
{
wxCHECK_RET( m_invokingWindow, _T("what kind of menu is this?") );
m_invokingWindow->DismissPopupMenu();
// Why reset it here? We need it for sending the event to...
// SetInvokingWindow(NULL);
}
}
}
void wxMenu::Popup(const wxPoint& pos, const wxSize& size, bool selectFirst)
{
// create the popup window if not done yet
if ( !m_popupMenu )
{
m_popupMenu = new wxPopupMenuWindow(GetRootWindow(), this);
}
// select the first item unless disabled
if ( selectFirst )
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?