menu.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,300 行 · 第 1/5 页
CPP
2,300 行
/////////////////////////////////////////////////////////////////////////////
// Name: univ/menu.cpp
// Purpose: wxMenuItem, wxMenu and wxMenuBar implementation
// Author: Vadim Zeitlin
// Modified by:
// Created: 25.08.00
// RCS-ID: $Id: menu.cpp,v 1.57 2005/05/18 21:36:13 MW Exp $
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "univmenuitem.h"
#pragma implementation "univmenu.h"
#endif
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/dynarray.h"
#include "wx/control.h" // for FindAccelIndex()
#include "wx/menu.h"
#include "wx/settings.h"
#include "wx/accel.h"
#include "wx/log.h"
#endif // WX_PRECOMP
#if wxUSE_MENUS
#include "wx/popupwin.h"
#include "wx/evtloop.h"
#include "wx/dcclient.h"
#include "wx/frame.h"
#include "wx/univ/renderer.h"
#ifdef __WXMSW__
#include "wx/msw/private.h"
#endif // __WXMSW__
// ----------------------------------------------------------------------------
// wxMenuInfo contains all extra information about top level menus we need
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxMenuInfo
{
public:
// ctor
wxMenuInfo(const wxString& text)
{
SetLabel(text);
SetEnabled();
}
// modifiers
void SetLabel(const wxString& text)
{
// remember the accel char (may be -1 if none)
m_indexAccel = wxControl::FindAccelIndex(text, &m_label);
// calculate the width later, after the menu bar is created
m_width = 0;
}
void SetEnabled(bool enabled = true) { m_isEnabled = enabled; }
// accessors
const wxString& GetLabel() const { return m_label; }
bool IsEnabled() const { return m_isEnabled; }
wxCoord GetWidth(wxMenuBar *menubar) const
{
if ( !m_width )
{
wxConstCast(this, wxMenuInfo)->CalcWidth(menubar);
}
return m_width;
}
int GetAccelIndex() const { return m_indexAccel; }
private:
void CalcWidth(wxMenuBar *menubar)
{
wxSize size;
wxClientDC dc(menubar);
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
dc.GetTextExtent(m_label, &size.x, &size.y);
// adjust for the renderer we use and store the width
m_width = menubar->GetRenderer()->GetMenuBarItemSize(size).x;
}
wxString m_label;
wxCoord m_width;
int m_indexAccel;
bool m_isEnabled;
};
#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(wxMenuInfoArray);
// ----------------------------------------------------------------------------
// wxPopupMenuWindow: a popup window showing a menu
// ----------------------------------------------------------------------------
class wxPopupMenuWindow : public wxPopupTransientWindow
{
public:
wxPopupMenuWindow(wxWindow *parent, wxMenu *menu);
~wxPopupMenuWindow();
// override the base class version to select the first item initially
virtual void Popup(wxWindow *focus = NULL);
// override the base class version to dismiss any open submenus
virtual void Dismiss();
// notify the menu when the window disappears from screen
virtual void OnDismiss();
// called when a submenu is dismissed
void OnSubmenuDismiss(bool dismissParent);
// the default wxMSW wxPopupTransientWindow::OnIdle disables the capture
// when the cursor is inside the popup, which dsables the menu tracking
// so override it to do nothing
#ifdef __WXMSW__
void OnIdle(wxIdleEvent& WXUNUSED(event)) { }
#endif
// get the currently selected item (may be NULL)
wxMenuItem *GetCurrentItem() const
{
return m_nodeCurrent ? m_nodeCurrent->GetData() : NULL;
}
// find the menu item at given position
wxMenuItemList::compatibility_iterator GetMenuItemFromPoint(const wxPoint& pt) const;
// refresh the given item
void RefreshItem(wxMenuItem *item);
// preselect the first item
void SelectFirst() { SetCurrent(m_menu->GetMenuItems().GetFirst()); }
// process the key event, return true if done
bool ProcessKeyDown(int key);
// process mouse move event
void ProcessMouseMove(const wxPoint& pt);
// don't dismiss the popup window if the parent menu was clicked
virtual bool ProcessLeftDown(wxMouseEvent& event);
protected:
// how did we perform this operation?
enum InputMethod
{
WithKeyboard,
WithMouse
};
// draw the menu inside this window
virtual void DoDraw(wxControlRenderer *renderer);
// event handlers
void OnLeftUp(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
void OnMouseLeave(wxMouseEvent& event);
void OnKeyDown(wxKeyEvent& event);
// reset the current item and node
void ResetCurrent();
// set the current node and item withotu refreshing anything
void SetCurrent(wxMenuItemList::compatibility_iterator node);
virtual bool SetCurrent(bool doit = true){return wxPopupTransientWindow::SetCurrent(doit);};
// change the current item refreshing the old and new items
void ChangeCurrent(wxMenuItemList::compatibility_iterator node);
// activate item, i.e. call either ClickItem() or OpenSubmenu() depending
// on what it is, return true if something was done (i.e. it's not a
// separator...)
bool ActivateItem(wxMenuItem *item, InputMethod how = WithKeyboard);
// send the event about the item click
void ClickItem(wxMenuItem *item);
// show the submenu for this item
void OpenSubmenu(wxMenuItem *item, InputMethod how = WithKeyboard);
// can this tiem be opened?
bool CanOpen(wxMenuItem *item)
{
return item && item->IsEnabled() && item->IsSubMenu();
}
// dismiss the menu and all parent menus too
void DismissAndNotify();
// react to dimissing this menu and also dismiss the parent if
// dismissParent
void HandleDismiss(bool dismissParent);
// do we have an open submenu?
bool HasOpenSubmenu() const { return m_hasOpenSubMenu; }
// get previous node after the current one
wxMenuItemList::compatibility_iterator GetPrevNode() const;
// get previous node before the given one, wrapping if it's the first one
wxMenuItemList::compatibility_iterator GetPrevNode(wxMenuItemList::compatibility_iterator node) const;
// get next node after the current one
wxMenuItemList::compatibility_iterator GetNextNode() const;
// get next node after the given one, wrapping if it's the last one
wxMenuItemList::compatibility_iterator GetNextNode(wxMenuItemList::compatibility_iterator node) const;
private:
// the menu we show
wxMenu *m_menu;
// the menu node corresponding to the current item
wxMenuItemList::compatibility_iterator m_nodeCurrent;
// do we currently have an opened submenu?
bool m_hasOpenSubMenu;
DECLARE_EVENT_TABLE()
};
// ----------------------------------------------------------------------------
// wxMenuKbdRedirector: an event handler which redirects kbd input to wxMenu
// ----------------------------------------------------------------------------
class wxMenuKbdRedirector : public wxEvtHandler
{
public:
wxMenuKbdRedirector(wxMenu *menu) { m_menu = menu; }
virtual bool ProcessEvent(wxEvent& event)
{
if ( event.GetEventType() == wxEVT_KEY_DOWN )
{
return m_menu->ProcessKeyDown(((wxKeyEvent &)event).GetKeyCode());
}
else
{
// return false;
return wxEvtHandler::ProcessEvent(event);
}
}
private:
wxMenu *m_menu;
};
// ----------------------------------------------------------------------------
// wxWin macros
// ----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
BEGIN_EVENT_TABLE(wxPopupMenuWindow, wxPopupTransientWindow)
EVT_KEY_DOWN(wxPopupMenuWindow::OnKeyDown)
EVT_LEFT_UP(wxPopupMenuWindow::OnLeftUp)
EVT_MOTION(wxPopupMenuWindow::OnMouseMove)
EVT_LEAVE_WINDOW(wxPopupMenuWindow::OnMouseLeave)
#ifdef __WXMSW__
EVT_IDLE(wxPopupMenuWindow::OnIdle)
#endif
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(wxMenuBar, wxMenuBarBase)
EVT_KILL_FOCUS(wxMenuBar::OnKillFocus)
EVT_KEY_DOWN(wxMenuBar::OnKeyDown)
EVT_LEFT_DOWN(wxMenuBar::OnLeftDown)
EVT_MOTION(wxMenuBar::OnMouseMove)
END_EVENT_TABLE()
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxPopupMenuWindow
// ----------------------------------------------------------------------------
wxPopupMenuWindow::wxPopupMenuWindow(wxWindow *parent, wxMenu *menu)
{
m_menu = menu;
m_hasOpenSubMenu = false;
ResetCurrent();
(void)Create(parent, wxBORDER_RAISED);
SetCursor(wxCURSOR_ARROW);
}
wxPopupMenuWindow::~wxPopupMenuWindow()
{
// When m_popupMenu in wxMenu is deleted because it
// is a child of an old menu bar being deleted (note: it does
// not get destroyed by the wxMenu destructor, but
// by DestroyChildren()), m_popupMenu should be reset to NULL.
m_menu->m_popupMenu = NULL;
}
// ----------------------------------------------------------------------------
// wxPopupMenuWindow current item/node handling
// ----------------------------------------------------------------------------
void wxPopupMenuWindow::ResetCurrent()
{
#if wxUSE_STL
SetCurrent(wxMenuItemList::compatibility_iterator());
#else
SetCurrent((wxwxMenuItemListNode *)NULL);
#endif
}
void wxPopupMenuWindow::SetCurrent(wxMenuItemList::compatibility_iterator node)
{
m_nodeCurrent = node;
}
void wxPopupMenuWindow::ChangeCurrent(wxMenuItemList::compatibility_iterator node)
{
if ( node != m_nodeCurrent )
{
wxMenuItemList::compatibility_iterator nodeOldCurrent = m_nodeCurrent;
m_nodeCurrent = node;
if ( nodeOldCurrent )
{
wxMenuItem *item = nodeOldCurrent->GetData();
wxCHECK_RET( item, _T("no current item?") );
// if it was the currently opened menu, close it
if ( item->IsSubMenu() && item->GetSubMenu()->IsShown() )
{
item->GetSubMenu()->Dismiss();
OnSubmenuDismiss( false );
}
RefreshItem(item);
}
if ( m_nodeCurrent )
RefreshItem(m_nodeCurrent->GetData());
}
}
wxMenuItemList::compatibility_iterator wxPopupMenuWindow::GetPrevNode() const
{
// return the last node if there had been no previously selected one
return m_nodeCurrent ? GetPrevNode(m_nodeCurrent)
: m_menu->GetMenuItems().GetLast();
}
wxMenuItemList::compatibility_iterator
wxPopupMenuWindow::GetPrevNode(wxMenuItemList::compatibility_iterator node) const
{
if ( node )
{
node = node->GetPrevious();
if ( !node )
{
node = m_menu->GetMenuItems().GetLast();
}
}
//else: the menu is empty
return node;
}
wxMenuItemList::compatibility_iterator wxPopupMenuWindow::GetNextNode() const
{
// return the first node if there had been no previously selected one
return m_nodeCurrent ? GetNextNode(m_nodeCurrent)
: m_menu->GetMenuItems().GetFirst();
}
wxMenuItemList::compatibility_iterator
wxPopupMenuWindow::GetNextNode(wxMenuItemList::compatibility_iterator node) const
{
if ( node )
{
node = node->GetNext();
if ( !node )
{
node = m_menu->GetMenuItems().GetFirst();
}
}
//else: the menu is empty
return node;
}
// ----------------------------------------------------------------------------
// wxPopupMenuWindow popup/dismiss
// ----------------------------------------------------------------------------
void wxPopupMenuWindow::Popup(wxWindow *focus)
{
// check that the current item had been properly reset before
wxASSERT_MSG( !m_nodeCurrent ||
m_nodeCurrent == m_menu->GetMenuItems().GetFirst(),
_T("menu current item preselected incorrectly") );
wxPopupTransientWindow::Popup(focus);
// the base class no-longer captures the mouse automatically when Popup
// is called, so do it here to allow the menu tracking to work
if ( !HasCapture() )
CaptureMouse();
#ifdef __WXMSW__
// ensure that this window is really on top of everything: without using
// SetWindowPos() it can be covered by its parent menu which is not
// really what we want
wxMenu *menuParent = m_menu->GetParent();
if ( menuParent )
{
wxPopupMenuWindow *win = menuParent->m_popupMenu;
// if we're shown, the parent menu must be also shown
wxCHECK_RET( win, _T("parent menu is not shown?") );
if ( !::SetWindowPos(GetHwndOf(win), GetHwnd(),
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW) )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?