menu.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,349 行 · 第 1/3 页
CPP
1,349 行
/////////////////////////////////////////////////////////////////////////////
// Name: menu.cpp
// Purpose: wxMenu, wxMenuBar, wxMenuItem
// Author: Julian Smart
// Modified by: Vadim Zeitlin
// Created: 04/01/98
// RCS-ID: $Id: menu.cpp,v 1.124.2.4 2006/03/15 09:55:55 JS Exp $
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "menu.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_MENUS
#ifndef WX_PRECOMP
#include "wx/frame.h"
#include "wx/menu.h"
#include "wx/utils.h"
#include "wx/intl.h"
#include "wx/log.h"
#endif
#if wxUSE_OWNER_DRAWN
#include "wx/ownerdrw.h"
#endif
#include "wx/msw/private.h"
#ifdef __WXWINCE__
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <ole2.h>
#include <shellapi.h>
#include <commctrl.h>
#if (_WIN32_WCE < 400) && !defined(__HANDHELDPC__)
#include <aygshell.h>
#endif
#include "wx/msw/wince/missing.h"
#endif
// other standard headers
#include <string.h>
#if wxUSE_OWNER_DRAWN && defined(MIIM_BITMAP)
#include "wx/dynlib.h"
#endif
#ifndef MNS_CHECKORBMP
#define MNS_CHECKORBMP 0x04000000
#endif
#ifndef MIM_STYLE
#define MIM_STYLE 0x00000010
#endif
// ----------------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// the (popup) menu title has this special id
static const int idMenuTitle = -3;
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// make the given menu item default
static void SetDefaultMenuItem(HMENU WXUNUSED_IN_WINCE(hmenu),
UINT WXUNUSED_IN_WINCE(id))
{
#ifndef __WXWINCE__
MENUITEMINFO mii;
wxZeroMemory(mii);
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE;
mii.fState = MFS_DEFAULT;
if ( !::SetMenuItemInfo(hmenu, id, FALSE, &mii) )
{
wxLogLastError(wxT("SetMenuItemInfo"));
}
#endif
}
#ifdef __WXWINCE__
UINT GetMenuState(HMENU hMenu, UINT id, UINT flags)
{
MENUITEMINFO info;
wxZeroMemory(info);
info.cbSize = sizeof(info);
info.fMask = MIIM_STATE;
// MF_BYCOMMAND is zero so test MF_BYPOSITION
if ( !::GetMenuItemInfo(hMenu, id, flags & MF_BYPOSITION ? TRUE : FALSE , & info) )
wxLogLastError(wxT("GetMenuItemInfo"));
return info.fState;
}
#endif
// ============================================================================
// implementation
// ============================================================================
#include <wx/listimpl.cpp>
WX_DEFINE_LIST( wxMenuInfoList ) ;
#if wxUSE_EXTENDED_RTTI
WX_DEFINE_FLAGS( wxMenuStyle )
wxBEGIN_FLAGS( wxMenuStyle )
wxFLAGS_MEMBER(wxMENU_TEAROFF)
wxEND_FLAGS( wxMenuStyle )
IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler,"wx/menu.h")
wxCOLLECTION_TYPE_INFO( wxMenuItem * , wxMenuItemList ) ;
template<> void wxCollectionToVariantArray( wxMenuItemList const &theList, wxxVariantArray &value)
{
wxListCollectionToVariantArray<wxMenuItemList::compatibility_iterator>( theList , value ) ;
}
wxBEGIN_PROPERTIES_TABLE(wxMenu)
wxEVENT_PROPERTY( Select , wxEVT_COMMAND_MENU_SELECTED , wxCommandEvent)
wxPROPERTY( Title, wxString , SetTitle, GetTitle, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
wxREADONLY_PROPERTY_FLAGS( MenuStyle , wxMenuStyle , long , GetStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
wxPROPERTY_COLLECTION( MenuItems , wxMenuItemList , wxMenuItem* , Append , GetMenuItems , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxEND_PROPERTIES_TABLE()
wxBEGIN_HANDLERS_TABLE(wxMenu)
wxEND_HANDLERS_TABLE()
wxDIRECT_CONSTRUCTOR_2( wxMenu , wxString , Title , long , MenuStyle )
WX_DEFINE_FLAGS( wxMenuBarStyle )
wxBEGIN_FLAGS( wxMenuBarStyle )
wxFLAGS_MEMBER(wxMB_DOCKABLE)
wxEND_FLAGS( wxMenuBarStyle )
// the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxWriter * , wxPersister * , wxxVariantArray & )
{
return true ;
}
IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow ,"wx/menu.h",wxMenuBarStreamingCallback)
IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo, wxObject , "wx/menu.h" )
wxBEGIN_PROPERTIES_TABLE(wxMenuInfo)
wxREADONLY_PROPERTY( Menu , wxMenu* , GetMenu , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxREADONLY_PROPERTY( Title , wxString , GetTitle , wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxEND_PROPERTIES_TABLE()
wxBEGIN_HANDLERS_TABLE(wxMenuInfo)
wxEND_HANDLERS_TABLE()
wxCONSTRUCTOR_2( wxMenuInfo , wxMenu* , Menu , wxString , Title )
wxCOLLECTION_TYPE_INFO( wxMenuInfo * , wxMenuInfoList ) ;
template<> void wxCollectionToVariantArray( wxMenuInfoList const &theList, wxxVariantArray &value)
{
wxListCollectionToVariantArray<wxMenuInfoList::compatibility_iterator>( theList , value ) ;
}
wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
wxPROPERTY_COLLECTION( MenuInfos , wxMenuInfoList , wxMenuInfo* , Append , GetMenuInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxEND_PROPERTIES_TABLE()
wxBEGIN_HANDLERS_TABLE(wxMenuBar)
wxEND_HANDLERS_TABLE()
wxCONSTRUCTOR_DUMMY( wxMenuBar )
#else
IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo, wxObject)
#endif
const wxMenuInfoList& wxMenuBar::GetMenuInfos() const
{
wxMenuInfoList* list = const_cast< wxMenuInfoList* >( &m_menuInfos ) ;
WX_CLEAR_LIST( wxMenuInfoList , *list ) ;
for( size_t i = 0 ; i < GetMenuCount() ; ++i )
{
wxMenuInfo* info = new wxMenuInfo() ;
info->Create( const_cast<wxMenuBar*>(this)->GetMenu(i) , GetLabelTop(i) ) ;
list->Append( info ) ;
}
return m_menuInfos ;
}
// ---------------------------------------------------------------------------
// wxMenu construction, adding and removing menu items
// ---------------------------------------------------------------------------
// Construct a menu with optional title (then use append)
void wxMenu::Init()
{
m_doBreak = false;
m_startRadioGroup = -1;
// create the menu
m_hMenu = (WXHMENU)CreatePopupMenu();
if ( !m_hMenu )
{
wxLogLastError(wxT("CreatePopupMenu"));
}
// if we have a title, insert it in the beginning of the menu
if ( !m_title.empty() )
{
Append(idMenuTitle, m_title);
AppendSeparator();
}
}
// The wxWindow destructor will take care of deleting the submenus.
wxMenu::~wxMenu()
{
// we should free Windows resources only if Windows doesn't do it for us
// which happens if we're attached to a menubar or a submenu of another
// menu
if ( !IsAttached() && !GetParent() )
{
if ( !::DestroyMenu(GetHmenu()) )
{
wxLogLastError(wxT("DestroyMenu"));
}
}
#if wxUSE_ACCEL
// delete accels
WX_CLEAR_ARRAY(m_accels);
#endif // wxUSE_ACCEL
}
void wxMenu::Break()
{
// this will take effect during the next call to Append()
m_doBreak = true;
}
void wxMenu::Attach(wxMenuBarBase *menubar)
{
wxMenuBase::Attach(menubar);
EndRadioGroup();
}
#if wxUSE_ACCEL
int wxMenu::FindAccel(int id) const
{
size_t n, count = m_accels.GetCount();
for ( n = 0; n < count; n++ )
{
if ( m_accels[n]->m_command == id )
return n;
}
return wxNOT_FOUND;
}
void wxMenu::UpdateAccel(wxMenuItem *item)
{
if ( item->IsSubMenu() )
{
wxMenu *submenu = item->GetSubMenu();
wxMenuItemList::compatibility_iterator node = submenu->GetMenuItems().GetFirst();
while ( node )
{
UpdateAccel(node->GetData());
node = node->GetNext();
}
}
else if ( !item->IsSeparator() )
{
// recurse upwards: we should only modify m_accels of the top level
// menus, not of the submenus as wxMenuBar doesn't look at them
// (alternative and arguable cleaner solution would be to recurse
// downwards in GetAccelCount() and CopyAccels())
if ( GetParent() )
{
GetParent()->UpdateAccel(item);
return;
}
// find the (new) accel for this item
wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText());
if ( accel )
accel->m_command = item->GetId();
// find the old one
int n = FindAccel(item->GetId());
if ( n == wxNOT_FOUND )
{
// no old, add new if any
if ( accel )
m_accels.Add(accel);
else
return; // skipping RebuildAccelTable() below
}
else
{
// replace old with new or just remove the old one if no new
delete m_accels[n];
if ( accel )
m_accels[n] = accel;
else
m_accels.RemoveAt(n);
}
if ( IsAttached() )
{
GetMenuBar()->RebuildAccelTable();
}
}
//else: it is a separator, they can't have accels, nothing to do
}
#endif // wxUSE_ACCEL
// append a new item or submenu to the menu
bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
{
#if wxUSE_ACCEL
UpdateAccel(pItem);
#endif // wxUSE_ACCEL
UINT flags = 0;
// if "Break" has just been called, insert a menu break before this item
// (and don't forget to reset the flag)
if ( m_doBreak ) {
flags |= MF_MENUBREAK;
m_doBreak = false;
}
if ( pItem->IsSeparator() ) {
flags |= MF_SEPARATOR;
}
// id is the numeric id for normal menu items and HMENU for submenus as
// required by ::AppendMenu() API
UINT id;
wxMenu *submenu = pItem->GetSubMenu();
if ( submenu != NULL ) {
wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") );
submenu->SetParent(this);
id = (UINT)submenu->GetHMenu();
flags |= MF_POPUP;
}
else {
id = pItem->GetId();
}
// prepare to insert the item in the menu
wxString itemText = pItem->GetText();
LPCTSTR pData = NULL;
if ( pos == (size_t)-1 )
{
// append at the end (note that the item is already appended to
// internal data structures)
pos = GetMenuItemCount() - 1;
}
// adjust position to account for the title, if any
if ( !m_title.empty() )
pos += 2; // for the title itself and its separator
BOOL ok = false;
// check if we have something more than a simple text item
#if wxUSE_OWNER_DRAWN
if ( pItem->IsOwnerDrawn() )
{
// is the item owner-drawn just because of the bitmap?
if ( pItem->GetBitmap().Ok() &&
!pItem->GetTextColour().Ok() &&
!pItem->GetBackgroundColour().Ok() &&
!pItem->GetFont().Ok() &&
!pItem->GetBitmap(true).Ok() )
{
// try to use InsertMenuItem() as it's guaranteed to look correctly
// while our owner-drawning code is not
// first compile-time check
#ifdef MIIM_BITMAP
WinStruct<MENUITEMINFO> mii;
// now run-time one: MIIM_BITMAP only works under WinME/2000+
if ( wxGetWinVersion() >= wxWinVersion_98 )
{
mii.fMask = MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
mii.cch = itemText.length();
mii.dwTypeData = wx_const_cast(wxChar *, itemText.c_str());
if (flags & MF_POPUP)
{
mii.fMask |= MIIM_SUBMENU;
mii.hSubMenu = (HMENU)pItem->GetSubMenu()->GetHMenu();
}
else
{
mii.fMask |= MIIM_ID;
mii.wID = id;
}
// we can't pass HBITMAP directly as hbmpItem for 2 reasons:
// 1. we can't draw it with transparency then (this is not
// very important now but would be with themed menu bg)
// 2. worse, Windows inverses the bitmap for the selected
// item and this looks downright ugly
//
// so instead draw it ourselves in MSWOnDrawItem()
mii.dwItemData = wx_reinterpret_cast(ULONG_PTR, pItem);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?