X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2e297951cd2eca56fac39fc21d7ebecc4cb51e52..a56a99abe859f37615251c865bc807bf13e8b180:/src/msw/menu.cpp diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index f883a23128..46346acca8 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -29,7 +29,6 @@ #include "wx/menu.h" #ifndef WX_PRECOMP - #include "wx/msw/wrapcctl.h" // include "properly" #include "wx/frame.h" #include "wx/utils.h" #include "wx/intl.h" @@ -40,7 +39,10 @@ #include "wx/ownerdrw.h" #endif +#include "wx/ptr_scpd.h" + #include "wx/msw/private.h" +#include "wx/msw/wrapcctl.h" // include "properly" #ifdef __WXWINCE__ #include @@ -59,24 +61,6 @@ // other standard headers #include -//VC6 needs these defining, though they are in winuser.h -#ifndef MIIM_BITMAP -#define MIIM_STRING 0x00000040 -#define MIIM_BITMAP 0x00000080 -#define MIIM_FTYPE 0x00000100 -#define HBMMENU_CALLBACK ((HBITMAP) -1) -typedef struct tagMENUINFO -{ - DWORD cbSize; - DWORD fMask; - DWORD dwStyle; - UINT cyMax; - HBRUSH hbrBack; - DWORD dwContextHelpID; - DWORD dwMenuData; -} MENUINFO, FAR *LPMENUINFO; -#endif - #if wxUSE_OWNER_DRAWN #include "wx/dynlib.h" #endif @@ -97,15 +81,18 @@ typedef struct tagMENUINFO // ---------------------------------------------------------------------------- // the (popup) menu title has this special id -static const int idMenuTitle = -3; +static const UINT idMenuTitle = (UINT)-3; // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- +namespace +{ + // make the given menu item default -static void SetDefaultMenuItem(HMENU WXUNUSED_IN_WINCE(hmenu), - UINT WXUNUSED_IN_WINCE(id)) +void SetDefaultMenuItem(HMENU WXUNUSED_IN_WINCE(hmenu), + UINT WXUNUSED_IN_WINCE(id)) { #ifndef __WXWINCE__ MENUITEMINFO mii; @@ -133,7 +120,18 @@ UINT GetMenuState(HMENU hMenu, UINT id, UINT flags) wxLogLastError(wxT("GetMenuItemInfo")); return info.fState; } -#endif +#endif // __WXWINCE__ + +bool IsLessThanStdSize(const wxBitmap& bmp) +{ + // FIXME: these +4 are chosen so that 16*16 bitmaps pass this test with + // default SM_CXMENUCHECK value but I have no idea what do we really + // need to use here + return bmp.GetWidth() < ::GetSystemMetrics(SM_CXMENUCHECK) + 4 && + bmp.GetHeight() < ::GetSystemMetrics(SM_CYMENUCHECK) + 4; +} + +} // anonymous namespace // ============================================================================ // implementation @@ -227,7 +225,7 @@ const wxMenuInfoList& wxMenuBar::GetMenuInfos() const for( size_t i = 0 ; i < GetMenuCount() ; ++i ) { wxMenuInfo* info = new wxMenuInfo() ; - info->Create( const_cast(this)->GetMenu(i) , GetLabelTop(i) ) ; + info->Create( const_cast(this)->GetMenu(i) , GetMenuLabel(i) ) ; list->Append( info ) ; } return m_menuInfos ; @@ -331,7 +329,7 @@ void wxMenu::UpdateAccel(wxMenuItem *item) } // find the (new) accel for this item - wxAcceleratorEntry *accel = wxAcceleratorEntry::Create(item->GetText()); + wxAcceleratorEntry *accel = wxAcceleratorEntry::Create(item->GetItemLabel()); if ( accel ) accel->m_command = item->GetId(); @@ -372,7 +370,8 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) UpdateAccel(pItem); #endif // wxUSE_ACCEL - UINT flags = 0; + // we should support disabling the item even prior to adding it to the menu + UINT flags = pItem->IsEnabled() ? MF_ENABLED : MF_GRAYED; // if "Break" has just been called, insert a menu break before this item // (and don't forget to reset the flag) @@ -387,24 +386,24 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) // id is the numeric id for normal menu items and HMENU for submenus as // required by ::AppendMenu() API - UINT id; + UINT_PTR id; wxMenu *submenu = pItem->GetSubMenu(); if ( submenu != NULL ) { wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") ); submenu->SetParent(this); - id = (UINT)submenu->GetHMenu(); + id = (UINT_PTR)submenu->GetHMenu(); flags |= MF_POPUP; } else { - id = pItem->GetId(); + id = pItem->GetMSWId(); } // prepare to insert the item in the menu - wxString itemText = pItem->GetText(); + wxString itemText = pItem->GetItemLabel(); LPCTSTR pData = NULL; if ( pos == (size_t)-1 ) { @@ -445,91 +444,100 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) #if wxUSE_OWNER_DRAWN if ( pItem->IsOwnerDrawn() ) { - // is the item owner-drawn just because of the [checked] bitmap? - if ( (pItem->GetBitmap(false).Ok() || pItem->GetBitmap(true).Ok()) && - !pItem->GetTextColour().Ok() && - !pItem->GetBackgroundColour().Ok() && - !pItem->GetFont().Ok() ) - { - // try to use InsertMenuItem() as it's guaranteed to look correct - // while our owner-drawn code is not #ifndef __DMC__ - // DMC at march 2007 doesn't have HBITMAP hbmpItem tagMENUITEMINFOA /W - // MIIM_BITMAP only works under WinME/2000+ + // if the item is owner-drawn just because of the [checked] bitmap and + // the bitmap uses standard menu bitmap size we can avoid making it + // owner-drawn and use built-in support for menu bitmaps instead + bool mustUseOwnerDrawn = pItem->GetTextColour().Ok() || + pItem->GetBackgroundColour().Ok() || + pItem->GetFont().Ok(); + if ( !mustUseOwnerDrawn ) + { + const wxBitmap& bmpUnchecked = pItem->GetBitmap(false), + bmpChecked = pItem->GetBitmap(true); + if ( (bmpUnchecked.Ok() && !IsLessThanStdSize(bmpUnchecked)) || + (bmpChecked.Ok() && !IsLessThanStdSize(bmpChecked)) ) + { + mustUseOwnerDrawn = true; + } + } + + // MIIM_BITMAP only works under WinME/2000+ + if ( !mustUseOwnerDrawn && wxGetWinVersion() >= wxWinVersion_98 ) + { + // use InsertMenuItem() as it's guaranteed to look correct while + // our owner-drawn code is not WinStruct mii; - if ( wxGetWinVersion() >= wxWinVersion_98 ) + mii.fMask = MIIM_STRING | MIIM_DATA | MIIM_BITMAP; + if ( pItem->IsCheckable() ) { - mii.fMask = MIIM_STRING | MIIM_DATA | MIIM_BITMAP; - if ( pItem->IsCheckable() ) - { - // need to set checked/unchecked bitmaps as otherwise our - // MSWOnDrawItem() item is not called - mii.fMask |= MIIM_CHECKMARKS; - } + // need to set checked/unchecked bitmaps as otherwise our + // MSWOnDrawItem() item is not called + mii.fMask |= MIIM_CHECKMARKS; + } - mii.cch = itemText.length(); - mii.dwTypeData = wx_const_cast(wxChar *, itemText.wx_str()); + mii.cch = itemText.length(); + mii.dwTypeData = const_cast(itemText.wx_str()); - if (flags & MF_POPUP) - { - mii.fMask |= MIIM_SUBMENU; - mii.hSubMenu = (HMENU)pItem->GetSubMenu()->GetHMenu(); - } - else - { - mii.fMask |= MIIM_ID; - mii.wID = id; - } + 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 inverts 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); - if ( pItem->IsCheckable() ) - { - mii.hbmpChecked = - mii.hbmpUnchecked = HBMMENU_CALLBACK; - } - mii.hbmpItem = HBMMENU_CALLBACK; + // 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 inverts the bitmap for the selected + // item and this looks downright ugly + // + // so instead draw it ourselves in MSWOnDrawItem() + mii.dwItemData = reinterpret_cast(pItem); + if ( pItem->IsCheckable() ) + { + mii.hbmpChecked = + mii.hbmpUnchecked = HBMMENU_CALLBACK; + } + mii.hbmpItem = HBMMENU_CALLBACK; - ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii); - if ( !ok ) - { - wxLogLastError(wxT("InsertMenuItem()")); - } - else // InsertMenuItem() ok + ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii); + if ( !ok ) + { + wxLogLastError(wxT("InsertMenuItem()")); + } + else // InsertMenuItem() ok + { + // we need to remove the extra indent which is reserved for + // the checkboxes by default as it looks ugly unless check + // boxes are used together with bitmaps and this is not the + // case in wx API + WinStruct mi; + + // don't call SetMenuInfo() directly, this would prevent + // the app from starting up under Windows 95/NT 4 + typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *); + + wxDynamicLibrary dllUser(_T("user32")); + wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser); + if ( pfnSetMenuInfo ) { - // we need to remove the extra indent which is reserved for - // the checkboxes by default as it looks ugly unless check - // boxes are used together with bitmaps and this is not the - // case in wx API - WinStruct mi; - - // don't call SetMenuInfo() directly, this would prevent - // the app from starting up under Windows 95/NT 4 - typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *); - - wxDynamicLibrary dllUser(_T("user32")); - wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser); - if ( pfnSetMenuInfo ) - { - mi.fMask = MIM_STYLE; - mi.dwStyle = MNS_CHECKORBMP; - if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) ) - wxLogLastError(_T("SetMenuInfo(MNS_NOCHECK)")); - } - - // tell the item that it's not really owner-drawn but only - // needs to draw its bitmap, the rest is done by Windows - pItem->ResetOwnerDrawn(); + mi.fMask = MIM_STYLE; + mi.dwStyle = MNS_CHECKORBMP; + if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) ) + wxLogLastError(_T("SetMenuInfo(MNS_NOCHECK)")); } + + // tell the item that it's not really owner-drawn but only + // needs to draw its bitmap, the rest is done by Windows + pItem->ResetOwnerDrawn(); } -#endif // __DMC__ } +#endif // __DMC__ if ( !ok ) { @@ -545,7 +553,7 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) flags |= MF_STRING; #ifdef __WXWINCE__ - itemText = wxMenuItem::GetLabelFromText(itemText); + itemText = wxMenuItem::GetLabelText(itemText); #endif pData = (wxChar*)itemText.wx_str(); @@ -564,7 +572,7 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) // if we just appended the title, highlight it - if ( (int)id == idMenuTitle ) + if ( id == idMenuTitle ) { // visually select the menu title SetDefaultMenuItem(GetHmenu(), id); @@ -713,6 +721,15 @@ size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const return count; } +wxAcceleratorTable *wxMenu::CreateAccelTable() const +{ + const size_t count = m_accels.size(); + wxScopedArray accels(new wxAcceleratorEntry[count]); + CopyAccels(accels.get()); + + return new wxAcceleratorTable(count, accels.get()); +} + #endif // wxUSE_ACCEL // --------------------------------------------------------------------------- @@ -731,7 +748,7 @@ void wxMenu::SetTitle(const wxString& label) if ( !label.empty() ) { if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING, - (unsigned)idMenuTitle, m_title.wx_str()) || + idMenuTitle, m_title.wx_str()) || !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) ) { wxLogLastError(wxT("InsertMenu")); @@ -759,7 +776,7 @@ void wxMenu::SetTitle(const wxString& label) info.fMask = MIIM_TYPE; info.fType = MFT_STRING; info.cch = m_title.length(); - info.dwTypeData = wx_const_cast(wxChar *, m_title.wx_str()); + info.dwTypeData = const_cast(m_title.wx_str()); if ( !SetMenuItemInfo(hMenu, 0, TRUE, & info) ) { wxLogLastError(wxT("SetMenuItemInfo")); @@ -767,7 +784,7 @@ void wxMenu::SetTitle(const wxString& label) #else if ( !ModifyMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING, - (unsigned)idMenuTitle, m_title.wx_str()) ) + idMenuTitle, m_title.wx_str()) ) { wxLogLastError(wxT("ModifyMenu")); } @@ -779,7 +796,7 @@ void wxMenu::SetTitle(const wxString& label) // put the title string in bold face if ( !m_title.empty() ) { - SetDefaultMenuItem(GetHmenu(), (UINT)idMenuTitle); + SetDefaultMenuItem(GetHmenu(), idMenuTitle); } #endif // Win32 } @@ -788,10 +805,12 @@ void wxMenu::SetTitle(const wxString& label) // event processing // --------------------------------------------------------------------------- -bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id) +bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id_) { + const int id = (signed short)id_; + // ignore commands from the menu title - if ( id != (WXWORD)idMenuTitle ) + if ( id != (int)idMenuTitle ) { // update the check item when it's clicked wxMenuItem * const item = FindItem(id); @@ -927,7 +946,7 @@ WXHMENU wxMenuBar::Create() if ( m_hMenu != 0 ) return m_hMenu; - wxToolMenuBar * const bar = wx_static_cast(wxToolMenuBar *, GetToolBar()); + wxToolMenuBar * const bar = static_cast(GetToolBar()); if ( !bar ) return NULL; @@ -949,7 +968,7 @@ WXHMENU wxMenuBar::Create() { HMENU hPopupMenu = (HMENU) GetMenu(i)->GetHMenu(); tbButton.dwData = (DWORD)hPopupMenu; - wxString label = wxStripMenuCodes(GetLabelTop(i)); + wxString label = wxStripMenuCodes(GetMenuLabel(i)); tbButton.iString = (int) label.wx_str(); tbButton.idCommand = NewControlId(); @@ -978,7 +997,7 @@ WXHMENU wxMenuBar::Create() for ( i = 0, it = m_menus.begin(); i < count; i++, it++ ) { if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, - (UINT)(*it)->GetHMenu(), + (UINT_PTR)(*it)->GetHMenu(), m_titles[i].wx_str()) ) { wxLogLastError(wxT("AppendMenu")); @@ -1036,7 +1055,7 @@ void wxMenuBar::EnableTop(size_t pos, bool enable) Refresh(); } -void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) +void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label) { wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") ); @@ -1050,7 +1069,7 @@ void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) int mswpos = MSWPositionForWxMenu(GetMenu(pos),pos); - UINT id; + UINT_PTR id; UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, mswpos, MF_BYPOSITION); if ( flagsOld == 0xFFFFFFFF ) { @@ -1063,7 +1082,7 @@ void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) { // HIBYTE contains the number of items in the submenu in this case flagsOld &= 0xff; - id = (UINT)::GetSubMenu((HMENU)m_hMenu, mswpos); + id = (UINT_PTR)::GetSubMenu((HMENU)m_hMenu, mswpos); } else { @@ -1077,8 +1096,8 @@ void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) info.fMask = MIIM_TYPE; info.fType = MFT_STRING; info.cch = label.length(); - info.dwTypeData = wx_const_cast(wxChar *, label.wx_str()); - if ( !SetMenuItemInfo(GetHmenu(), id, TRUE, & info) ) + info.dwTypeData = const_cast(label.wx_str()); + if ( !SetMenuItemInfo(GetHmenu(), id, TRUE, &info) ) { wxLogLastError(wxT("SetMenuItemInfo")); } @@ -1094,12 +1113,12 @@ void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) Refresh(); } -wxString wxMenuBar::GetLabelTop(size_t pos) const +wxString wxMenuBar::GetMenuLabel(size_t pos) const { wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString, - wxT("invalid menu index in wxMenuBar::GetLabelTop") ); + wxT("invalid menu index in wxMenuBar::GetMenuLabel") ); - return wxMenuItem::GetLabelFromText(m_titles[pos]); + return m_titles[pos]; } // --------------------------------------------------------------------------- @@ -1130,7 +1149,7 @@ wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) if ( !::InsertMenu(GetHmenu(), (UINT)mswpos, MF_BYPOSITION | MF_POPUP | MF_STRING, - (UINT)GetHmenuOf(menu), title.wx_str()) ) + (UINT_PTR)GetHmenuOf(menu), title.wx_str()) ) { wxLogLastError(wxT("InsertMenu")); } @@ -1197,7 +1216,7 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) #else if ( !::InsertMenu(GetHmenu(), mswpos, MF_BYPOSITION | MF_POPUP | MF_STRING, - (UINT)GetHmenuOf(menu), title.wx_str()) ) + (UINT_PTR)GetHmenuOf(menu), title.wx_str()) ) { wxLogLastError(wxT("InsertMenu")); } @@ -1256,7 +1275,7 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title) } #else if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING, - (UINT)submenu, title.wx_str()) ) + (UINT_PTR)submenu, title.wx_str()) ) { wxLogLastError(wxT("AppendMenu")); } @@ -1344,7 +1363,7 @@ void wxMenuBar::RebuildAccelTable() nAccelCount += (*it)->CopyAccels(&accelEntries[nAccelCount]); } - m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries); + SetAcceleratorTable(wxAcceleratorTable(nAccelCount, accelEntries)); delete [] accelEntries; }