X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/820b49cdbf6fa6e6aac6bbb66e84ea9f5f5f745d..7d2d5d81951888e76f93b33aca9899a9c480022b:/src/msw/menu.cpp diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index e4299163f2..6f1343b30c 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -5,8 +5,8 @@ // Modified by: Vadim Zeitlin // Created: 04/01/98 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // =========================================================================== @@ -17,7 +17,7 @@ // headers // --------------------------------------------------------------------------- -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "menu.h" #endif @@ -44,6 +44,20 @@ #include "wx/msw/private.h" +#ifdef __WXWINCE__ +#include +#include +#include +#include +#include +#include + +#ifndef TBSTYLE_NO_DROPDOWN_ARROW +#define TBSTYLE_NO_DROPDOWN_ARROW 0x0080 +#endif + +#endif + // other standard headers #include @@ -61,16 +75,63 @@ extern wxMenu *wxCurrentPopupMenu; static const int idMenuTitle = -2; // ---------------------------------------------------------------------------- -// macros +// private functions // ---------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler) -IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow) +// make the given menu item default +static void SetDefaultMenuItem(HMENU hmenu, UINT 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; + if ( !GetMenuItemInfo(hMenu, id, flags & MF_BYCOMMAND ? FALSE : TRUE, & info) ) + wxLogLastError(wxT("GetMenuItemInfo")); + return info.fState; +} +#endif // ============================================================================ // implementation // ============================================================================ +IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler) +IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow) + +/* + TODO PROPERTIES + wxMenu + label + help + + separator + break + label + accel + radio + checkable + help + bitmap + wxMenuItem +*/ + // --------------------------------------------------------------------------- // wxMenu construction, adding and removing menu items // --------------------------------------------------------------------------- @@ -79,6 +140,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow) void wxMenu::Init() { m_doBreak = FALSE; + m_startRadioGroup = -1; // create the menu m_hMenu = (WXHMENU)CreatePopupMenu(); @@ -121,6 +183,13 @@ void wxMenu::Break() m_doBreak = TRUE; } +void wxMenu::Attach(wxMenuBarBase *menubar) +{ + wxMenuBase::Attach(menubar); + + EndRadioGroup(); +} + #if wxUSE_ACCEL int wxMenu::FindAccel(int id) const @@ -140,7 +209,7 @@ void wxMenu::UpdateAccel(wxMenuItem *item) if ( item->IsSubMenu() ) { wxMenu *submenu = item->GetSubMenu(); - wxMenuItemList::Node *node = submenu->GetMenuItems().GetFirst(); + wxMenuItemList::compatibility_iterator node = submenu->GetMenuItems().GetFirst(); while ( node ) { UpdateAccel(node->GetData()); @@ -222,6 +291,10 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) id = pItem->GetId(); } +#ifdef __WXWINCE__ + wxString strippedString; +#endif + LPCTSTR pData; #if wxUSE_OWNER_DRAWN @@ -236,7 +309,12 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) // menu is just a normal string (passed in data parameter) flags |= MF_STRING; +#ifdef __WXWINCE__ + strippedString = wxStripMenuCodes(pItem->GetText()); + pData = (wxChar*)strippedString.c_str(); +#else pData = (wxChar*)pItem->GetText().c_str(); +#endif } BOOL ok; @@ -255,38 +333,86 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) return FALSE; } - else - { - // if we just appended the title, highlight it + + // if we just appended the title, highlight it #ifdef __WIN32__ - if ( (int)id == idMenuTitle ) + if ( (int)id == idMenuTitle ) + { + // visually select the menu title + SetDefaultMenuItem(GetHmenu(), id); + } +#endif // __WIN32__ + + // if we're already attached to the menubar, we must update it + if ( IsAttached() && m_menuBar->IsAttached() ) + { + m_menuBar->Refresh(); + } + + return TRUE; +} + +void wxMenu::EndRadioGroup() +{ + // we're not inside a radio group any longer + m_startRadioGroup = -1; +} + +bool wxMenu::DoAppend(wxMenuItem *item) +{ + wxCHECK_MSG( item, FALSE, _T("NULL item in wxMenu::DoAppend") ); + + bool check = FALSE; + + if ( item->GetKind() == wxITEM_RADIO ) + { + int count = GetMenuItemCount(); + + if ( m_startRadioGroup == -1 ) { - // visually select the menu title - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STATE; - mii.fState = MFS_DEFAULT; + // start a new radio group + m_startRadioGroup = count; + + // for now it has just one element + item->SetAsRadioGroupStart(); + item->SetRadioGroupEnd(m_startRadioGroup); - if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) ) + // ensure that we have a checked item in the radio group + check = TRUE; + } + 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 ) { - wxLogLastError(wxT("SetMenuItemInfo")); + node->GetData()->SetRadioGroupEnd(count); + } + else + { + wxFAIL_MSG( _T("where is the radio group start item?") ); } } -#endif // __WIN32__ + } + else // not a radio item + { + EndRadioGroup(); + } - // if we're already attached to the menubar, we must update it - if ( IsAttached() && m_menuBar->IsAttached() ) - { - m_menuBar->Refresh(); - } + if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) ) + { + return FALSE; + } - return TRUE; + if ( check ) + { + // check the item initially + item->Check(TRUE); } -} -bool wxMenu::DoAppend(wxMenuItem *item) -{ - return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item); + return TRUE; } bool wxMenu::DoInsert(size_t pos, wxMenuItem *item) @@ -298,7 +424,7 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) { // we need to find the items position in the child list size_t pos; - wxMenuItemList::Node *node = GetMenuItems().GetFirst(); + wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); for ( pos = 0; node; pos++ ) { if ( node->GetData() == item ) @@ -396,12 +522,26 @@ void wxMenu::SetTitle(const wxString& label) else { // modify the title +#ifdef __WXWINCE__ + MENUITEMINFO info; + wxZeroMemory(info); + info.cbSize = sizeof(info); + info.fMask = MIIM_TYPE; + info.fType = MFT_STRING; + info.cch = m_title.Length(); + info.dwTypeData = (LPTSTR) m_title.c_str(); + if ( !SetMenuItemInfo(hMenu, 0, TRUE, & info) ) + { + wxLogLastError(wxT("SetMenuItemInfo")); + } +#else if ( !ModifyMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING, (unsigned)idMenuTitle, m_title) ) { wxLogLastError(wxT("ModifyMenu")); } +#endif } } @@ -409,15 +549,7 @@ void wxMenu::SetTitle(const wxString& label) // put the title string in bold face if ( !m_title.IsEmpty() ) { - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STATE; - mii.fState = MFS_DEFAULT; - - if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) ) - { - wxLogLastError(wxT("SetMenuItemInfo")); - } + SetDefaultMenuItem(GetHmenu(), (UINT)idMenuTitle); } #endif // Win32 } @@ -437,7 +569,8 @@ bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id) // useless anyhow (as it could be retrieved using GetId()) and // uncompatible with wxGTK, so now we use the command int instead // to pass the checked status - SendEvent(id, ::GetMenuState(GetHmenu(), id, MF_BYCOMMAND) & MF_CHECKED); + UINT menuState = ::GetMenuState(GetHmenu(), id, MF_BYCOMMAND) ; + SendEvent(id, menuState & MF_CHECKED); } return TRUE; @@ -465,6 +598,9 @@ void wxMenuBar::Init() { m_eventHandler = this; m_hMenu = 0; +#ifdef __WXWINCE__ + m_toolBar = NULL; +#endif } wxMenuBar::wxMenuBar() @@ -494,6 +630,20 @@ wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[]) wxMenuBar::~wxMenuBar() { + // In Windows CE, the menubar is always associated + // with a toolbar, which destroys the menu implicitly. +#ifdef __WXWINCE__ + if (GetToolBar()) + GetToolBar()->SetMenuBar(NULL); +#else + // we should free Windows resources only if Windows doesn't do it for us + // which happens if we're attached to a frame + if (m_hMenu && !IsAttached()) + { + ::DestroyMenu((HMENU)m_hMenu); + m_hMenu = (WXHMENU)NULL; + } +#endif } // --------------------------------------------------------------------------- @@ -504,11 +654,59 @@ void wxMenuBar::Refresh() { wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") ); +#ifdef __WXWINCE__ + if (GetToolBar()) + { + CommandBar_DrawMenuBar((HWND) GetToolBar()->GetHWND(), 0); + } +#else DrawMenuBar(GetHwndOf(GetFrame())); +#endif } WXHMENU wxMenuBar::Create() { + // Note: this totally doesn't work on Smartphone, + // since you have to use resources. + // We'll have to find another way to add a menu + // by changing/adding menu items to an existing menu. +#ifdef __WXWINCE__ + if ( m_hMenu != 0 ) + return m_hMenu; + + if (!GetToolBar()) + return 0; + + HWND hCommandBar = (HWND) GetToolBar()->GetHWND(); + HMENU hMenu = (HMENU)::SendMessage(hCommandBar, SHCMBM_GETMENU, (WPARAM)0, (LPARAM)0); + if (hMenu) + { + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = I_IMAGENONE; + tbButton.fsState = TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE; + + size_t i; + for (i = 0; i < GetMenuCount(); i++) + { + HMENU hPopupMenu = (HMENU) GetMenu(i)->GetHMenu() ; + tbButton.dwData = (DWORD)hPopupMenu; + wxString label = wxStripMenuCodes(GetLabelTop(i)); + tbButton.iString = (int) label.c_str(); + + int position = i; + + tbButton.idCommand = NewControlId(); + if (!::SendMessage(hCommandBar, TB_INSERTBUTTON, position, (LPARAM)&tbButton)) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + } + } + } + m_hMenu = (WXHMENU) hMenu; + return m_hMenu; +#else if ( m_hMenu != 0 ) return m_hMenu; @@ -520,11 +718,12 @@ WXHMENU wxMenuBar::Create() } else { - size_t count = GetMenuCount(); - for ( size_t i = 0; i < count; i++ ) + size_t count = GetMenuCount(), i; + wxMenuList::iterator it; + for ( i = 0, it = m_menus.begin(); i < count; i++, it++ ) { if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, - (UINT)m_menus[i]->GetHMenu(), + (UINT)(*it)->GetHMenu(), m_titles[i]) ) { wxLogLastError(wxT("AppendMenu")); @@ -533,6 +732,7 @@ WXHMENU wxMenuBar::Create() } return m_hMenu; +#endif } // --------------------------------------------------------------------------- @@ -585,11 +785,26 @@ void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) id = pos; } +#ifdef __WXWINCE__ + MENUITEMINFO info; + wxZeroMemory(info); + info.cbSize = sizeof(info); + info.fMask = MIIM_TYPE; + info.fType = MFT_STRING; + info.cch = label.Length(); + info.dwTypeData = (LPTSTR) label.c_str(); + if ( !SetMenuItemInfo(GetHmenu(), id, TRUE, & info) ) + { + wxLogLastError(wxT("SetMenuItemInfo")); + } + +#else if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld, - id, label) == (int)0xFFFFFFFF ) + id, label) == (int)0xFFFFFFFF ) { wxLogLastError(wxT("ModifyMenu")); } +#endif Refresh(); } @@ -610,7 +825,8 @@ wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) { wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title); if ( !menuOld ) - return FALSE; + return NULL; + m_titles[pos] = title; if ( IsAttached() ) @@ -651,13 +867,34 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) if ( IsAttached() ) { +#ifdef __WXWINCE__ + if (!GetToolBar()) + return FALSE; + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = I_IMAGENONE; + tbButton.fsState = TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE; + + HMENU hPopupMenu = (HMENU) menu->GetHMenu() ; + tbButton.dwData = (DWORD)hPopupMenu; + wxString label = wxStripMenuCodes(title); + tbButton.iString = (int) label.c_str(); + + tbButton.idCommand = NewControlId(); + if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_INSERTBUTTON, pos, (LPARAM)&tbButton)) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + return FALSE; + } +#else if ( !::InsertMenu(GetHmenu(), pos, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT)GetHmenuOf(menu), title) ) { wxLogLastError(wxT("InsertMenu")); } - +#endif #if wxUSE_ACCEL if ( menu->HasAccels() ) { @@ -680,23 +917,43 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title) if ( !wxMenuBarBase::Append(menu, title) ) return FALSE; - // Already done in Append above - //menu->Attach(this); - m_titles.Add(title); if ( IsAttached() ) { +#ifdef __WXWINCE__ + if (!GetToolBar()) + return FALSE; + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = I_IMAGENONE; + tbButton.fsState = TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_DROPDOWN | TBSTYLE_NO_DROPDOWN_ARROW | TBSTYLE_AUTOSIZE; + + size_t pos = GetMenuCount(); + HMENU hPopupMenu = (HMENU) menu->GetHMenu() ; + tbButton.dwData = (DWORD)hPopupMenu; + wxString label = wxStripMenuCodes(title); + tbButton.iString = (int) label.c_str(); + + tbButton.idCommand = NewControlId(); + if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_INSERTBUTTON, pos, (LPARAM)&tbButton)) + { + wxLogLastError(wxT("TB_INSERTBUTTON")); + return FALSE; + } +#else if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING, (UINT)submenu, title) ) { wxLogLastError(wxT("AppendMenu")); } +#endif #if wxUSE_ACCEL if ( menu->HasAccels() ) { - // need to rebuild accell table + // need to rebuild accelerator table RebuildAccelTable(); } #endif // wxUSE_ACCEL @@ -715,11 +972,20 @@ wxMenu *wxMenuBar::Remove(size_t pos) if ( IsAttached() ) { +#ifdef __WXWINCE__ + if (GetToolBar()) + { + if (!::SendMessage((HWND) GetToolBar()->GetHWND(), TB_DELETEBUTTON, (UINT) pos, (LPARAM) 0)) + { + wxLogLastError(wxT("TB_DELETEBUTTON")); + } + } +#else if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) ) { wxLogLastError(wxT("RemoveMenu")); } - +#endif #if wxUSE_ACCEL if ( menu->HasAccels() ) { @@ -731,7 +997,7 @@ wxMenu *wxMenuBar::Remove(size_t pos) Refresh(); } - m_titles.Remove(pos); + m_titles.RemoveAt(pos); return menu; } @@ -743,9 +1009,10 @@ void wxMenuBar::RebuildAccelTable() // merge the accelerators of all menus into one accel table size_t nAccelCount = 0; size_t i, count = GetMenuCount(); - for ( i = 0; i < count; i++ ) + wxMenuList::iterator it; + for ( i = 0, it = m_menus.begin(); i < count; i++, it++ ) { - nAccelCount += m_menus[i]->GetAccelCount(); + nAccelCount += (*it)->GetAccelCount(); } if ( nAccelCount ) @@ -753,9 +1020,9 @@ void wxMenuBar::RebuildAccelTable() wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount]; nAccelCount = 0; - for ( i = 0; i < count; i++ ) + for ( i = 0, it = m_menus.begin(); i < count; i++, it++ ) { - nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]); + nAccelCount += (*it)->CopyAccels(&accelEntries[nAccelCount]); } m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries); @@ -777,8 +1044,6 @@ void wxMenuBar::Attach(wxFrame *frame) void wxMenuBar::Detach() { - m_hMenu = (WXHMENU)NULL; - wxMenuBarBase::Detach(); }