// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
+#ifdef __GNUG__
+ #pragma implementation "menu.h"
+#endif
+
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
+ #include "wx/app.h"
#include "wx/frame.h"
#include "wx/menu.h"
#include "wx/utils.h"
// global variables
// ----------------------------------------------------------------------------
-extern wxMenu *wxCurrentPopupMenu;
+extern wxMenu* wxCurrentPopupMenu;
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
-// the (popup) menu title has this special id
-static const int idMenuTitle = -2;
+//
+// The (popup) menu title has this special id
+//
+static const int idMenuTitle = -2;
+
+//
+// The unique ID for Menus
+//
+#ifdef __VISAGECPP__
+USHORT wxMenu::m_nextMenuId = 0;
+#else
+static USHORT wxMenu::m_nextMenuId = 0;
+#endif
// ----------------------------------------------------------------------------
// macros
IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
+// ----------------------------------------------------------------------------
+// static function for translating menu labels
+// ----------------------------------------------------------------------------
+
+static wxString TextToLabel(
+ const wxString& rsTitle
+)
+{
+ wxString sTitle = "";
+ const wxChar* zPc;
+
+ if (rsTitle.IsEmpty())
+ return sTitle;
+ for (zPc = rsTitle.c_str(); *zPc != wxT('\0'); zPc++ )
+ {
+ if (*zPc == wxT('&') )
+ {
+ if (*(zPc + 1) == wxT('&'))
+ {
+ zPc++;
+ sTitle << wxT('&');
+ }
+ else
+ sTitle << wxT('~');
+ }
+ else
+ {
+ if ( *zPc == wxT('~') )
+ {
+ //
+ // Tildes must be doubled to prevent them from being
+ // interpreted as accelerator character prefix by PM ???
+ //
+ sTitle << *zPc;
+ }
+ sTitle << *zPc;
+ }
+ }
+ return sTitle;
+} // end of TextToLabel
+
// ============================================================================
// implementation
// ============================================================================
// wxMenu construction, adding and removing menu items
// ---------------------------------------------------------------------------
+//
// Construct a menu with optional title (then use append)
+//
void wxMenu::Init()
{
- m_doBreak = FALSE;
-
- // create the menu
- m_hMenu = (WXHMENU)0; // CreatePopupMenu();
- if ( !m_hMenu )
+ m_bDoBreak = FALSE;
+ m_nStartRadioGroup = -1;
+
+ //
+ // Create the menu (to be used as a submenu or a popup)
+ //
+ if ((m_hMenu = ::WinCreateWindow( HWND_DESKTOP
+ ,WC_MENU
+ ,"Menu"
+ ,0L
+ ,0L
+ ,0L
+ ,0L
+ ,0L
+ ,NULLHANDLE
+ ,HWND_TOP
+ ,0L
+ ,NULL
+ ,NULL
+ )) == 0)
{
- wxLogLastError("CreatePopupMenu");
+ wxLogLastError("WinLoadMenu");
}
-
- // if we have a title, insert it in the beginning of the menu
- if ( !!m_title )
+ m_vMenuData.iPosition = 0;
+ m_vMenuData.afStyle = MIS_SUBMENU | MIS_TEXT;
+ m_vMenuData.afAttribute = (USHORT)0;
+ m_vMenuData.id = m_nextMenuId++;
+ m_vMenuData.hwndSubMenu = m_hMenu;
+ m_vMenuData.hItem = NULLHANDLE;
+
+ //
+ // If we have a title, insert it in the beginning of the menu
+ //
+ if (!m_title.IsEmpty())
{
- Append(idMenuTitle, m_title);
+ Append( idMenuTitle
+ ,m_title
+ ,wxEmptyString
+ ,wxITEM_NORMAL
+ );
AppendSeparator();
}
-}
+} // end of wxMenu::Init
+//
// 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
+ //
+ // We should free PM resources only if PM 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 (!IsAttached() && !GetParent())
{
-/*
- if ( !::DestroyMenu(GetHmenu()) )
+ if (!::WinDestroyWindow((HWND)GetHmenu()) )
{
- wxLogLastError("DestroyMenu");
+ wxLogLastError("WinDestroyWindow");
}
-*/
}
#if wxUSE_ACCEL
- // delete accels
- WX_CLEAR_ARRAY(m_accels);
+ //
+ // Delete accels
+ //
+ WX_CLEAR_ARRAY(m_vAccels);
#endif // wxUSE_ACCEL
-}
+} // end of wxMenu::~wxMenu
void wxMenu::Break()
{
// this will take effect during the next call to Append()
- m_doBreak = TRUE;
-}
+ m_bDoBreak = TRUE;
+} // end of wxMenu::Break
+
+void wxMenu::Attach(
+ wxMenuBarBase* pMenubar
+)
+{
+ wxMenuBase::Attach(pMenubar);
+ EndRadioGroup();
+} // end of wxMenu::Break;
#if wxUSE_ACCEL
-int wxMenu::FindAccel(int id) const
+int wxMenu::FindAccel(
+ int nId
+) const
{
- size_t n, count = m_accels.GetCount();
- for ( n = 0; n < count; n++ )
- {
- if ( m_accels[n]->m_command == id )
- return n;
- }
+ size_t n;
+ size_t nCount = m_vAccels.GetCount();
+ for (n = 0; n < nCount; n++)
+ if (m_vAccels[n]->m_command == nId)
+ return n;
return wxNOT_FOUND;
-}
+} // end of wxMenu::FindAccel
-void wxMenu::UpdateAccel(wxMenuItem *item)
+void wxMenu::UpdateAccel(
+ wxMenuItem* pItem
+)
{
- // 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 )
+ if (pItem->IsSubMenu())
{
- // no old, add new if any
- if ( accel )
- m_accels.Add(accel);
- else
- return; // skipping RebuildAccelTable() below
+ wxMenu* pSubmenu = pItem->GetSubMenu();
+ wxMenuItemList::Node* pNode = pSubmenu->GetMenuItems().GetFirst();
+
+ while (pNode)
+ {
+ UpdateAccel(pNode->GetData());
+ pNode = pNode->GetNext();
+ }
}
- else
+ else if (!pItem->IsSeparator())
{
- // replace old with new or just remove the old one if no new
- delete m_accels[n];
- if ( accel )
- m_accels[n] = accel;
+ //
+ // Find the (new) accel for this item
+ //
+ wxAcceleratorEntry* pAccel = wxGetAccelFromString(pItem->GetText());
+
+ if (pAccel)
+ pAccel->m_command = pItem->GetId();
+
+ //
+ // Find the old one
+ //
+ size_t n = FindAccel(pItem->GetId());
+
+ if (n == wxNOT_FOUND)
+ {
+ //
+ // No old, add new if any
+ //
+ if (pAccel)
+ m_vAccels.Add(pAccel);
+ else
+ return;
+ }
else
- m_accels.Remove(n);
- }
+ {
+ //
+ // Replace old with new or just remove the old one if no new
+ //
+ delete m_vAccels[n];
+ if (pAccel)
+ m_vAccels[n] = pAccel;
+ else
+ m_vAccels.RemoveAt(n);
+ }
- if ( IsAttached() )
- {
- m_menuBar->RebuildAccelTable();
+ if (IsAttached())
+ {
+ m_menuBar->RebuildAccelTable();
+ }
}
-}
+} // wxMenu::UpdateAccel
#endif // wxUSE_ACCEL
-// append a new item or submenu to the menu
-bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
+//
+// Append a new item or submenu to the menu
+//
+bool wxMenu::DoInsertOrAppend(
+ wxMenuItem* pItem
+, size_t nPos
+)
{
+ wxMenu* pSubmenu = pItem->GetSubMenu();
+ MENUITEM& rItem = (pSubmenu != NULL)?pSubmenu->m_vMenuData:
+ pItem->m_vMenuData;
+
+ ERRORID vError;
+ wxString sError;
+ char zMsg[128];
+
#if wxUSE_ACCEL
UpdateAccel(pItem);
#endif // wxUSE_ACCEL
- UINT flags = 0;
-// TODO:
-/*
- // if "Break" has just been called, insert a menu break before this item
+ //
+ // 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 (m_bDoBreak)
+ {
+ rItem.afStyle |= MIS_BREAK;
+ m_bDoBreak = FALSE;
}
- if ( pItem->IsSeparator() ) {
- flags |= MF_SEPARATOR;
+ if (pItem->IsSeparator())
+ {
+ rItem.afStyle |= MIS_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") );
+ //
+ // Id is the numeric id for normal menu items and HMENU for submenus as
+ // required by ::MM_INSERTITEM message API
+ //
- submenu->SetParent(this);
-
- id = (UINT)submenu->GetHMenu();
+ if (pSubmenu != NULL)
+ {
+ wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
+ pSubmenu->SetParent(this);
- flags |= MF_POPUP;
+ rItem.iPosition = 0; // submenus have a 0 position
+ rItem.id = (USHORT)pSubmenu->GetHMenu();
+ rItem.afStyle |= MIS_SUBMENU | MIS_TEXT;
}
- else {
- id = pItem->GetId();
+ else
+ {
+ rItem.id = pItem->GetId();
}
- LPCTSTR pData;
+ BYTE* pData;
#if wxUSE_OWNER_DRAWN
- if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
- // item draws itself, pass pointer to it in data parameter
- flags |= MF_OWNERDRAW;
- pData = (LPCTSTR)pItem;
+ if (pItem->IsOwnerDrawn())
+ {
+ //
+ // Want to get {Measure|Draw}Item messages?
+ // item draws itself, passing pointer to data doesn't work in OS/2
+ // Will eventually need to set the image handle somewhere into vItem.hItem
+ //
+ rItem.afStyle |= MIS_OWNERDRAW;
+ pData = (BYTE*)NULL;
+ rItem.hItem = (HBITMAP)pItem->GetBitmap().GetHBITMAP();
+ pItem->m_vMenuData.afStyle = rItem.afStyle;
+ pItem->m_vMenuData.hItem = rItem.hItem;
}
else
#endif
{
- // menu is just a normal string (passed in data parameter)
- flags |= MF_STRING;
-
+ //
+ // Menu is just a normal string (passed in data parameter)
+ //
+ rItem.afStyle |= MIS_TEXT;
pData = (char*)pItem->GetText().c_str();
}
- BOOL ok;
- if ( pos == (size_t)-1 )
+ if (nPos == (size_t)-1)
{
- ok = ::AppendMenu(GetHmenu(), flags, id, pData);
+ rItem.iPosition = MIT_END;
}
else
{
- ok = ::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData);
+ rItem.iPosition = nPos;
}
- if ( !ok )
+ APIRET rc;
+
+ rc = (APIRET)::WinSendMsg( GetHmenu()
+ ,MM_INSERTITEM
+ ,(MPARAM)&rItem
+ ,(MPARAM)pData
+ );
+#if wxUSE_OWNER_DRAWN
+ if (pItem->IsOwnerDrawn())
{
+ BOOL rc;
+ MENUITEM vMenuItem;
+
+ ::WinSendMsg( GetHmenu()
+ ,MM_QUERYITEM
+ ,MPFROM2SHORT( (USHORT)pItem->GetId()
+ ,(USHORT)(FALSE)
+ )
+ ,&vMenuItem
+ );
+ }
+#endif
+ if (rc == MIT_MEMERROR || rc == MIT_ERROR)
+ {
+ vError = ::WinGetLastError(vHabmain);
+ sError = wxPMErrorToStr(vError);
+ wxLogError("Error inserting or appending a menuitem. Error: %s\n", sError);
wxLogLastError("Insert or AppendMenu");
-
return FALSE;
}
else
{
- // if we just appended the title, highlight it
-#ifdef __WIN32__
- if ( (int)id == idMenuTitle )
- {
- // visually select the menu title
- MENUITEMINFO mii;
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STATE;
- mii.fState = MFS_DEFAULT;
-
- if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
- {
- wxLogLastError(wxT("SetMenuItemInfo"));
- }
- }
-#endif // __WIN32__
-
- // if we're already attached to the menubar, we must update it
- if ( IsAttached() )
+ //
+ // If we're already attached to the menubar, we must update it
+ //
+ if (IsAttached() && m_menuBar->IsAttached())
{
m_menuBar->Refresh();
}
-
return TRUE;
}
-*/
return FALSE;
-}
+} // end of wxMenu::DoInsertOrAppend
-bool wxMenu::DoAppend(wxMenuItem *item)
+void wxMenu::EndRadioGroup()
{
- return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
-}
-
-bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
+ //
+ // We're not inside a radio group any longer
+ //
+ m_nStartRadioGroup = -1;
+} // end of wxMenu::EndRadioGroup
+
+bool wxMenu::DoAppend(
+ wxMenuItem* pItem
+)
{
- return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
-}
+ wxCHECK_MSG( pItem, FALSE, _T("NULL item in wxMenu::DoAppend") );
+
+ bool bCheck = FALSE;
+
+ if (pItem->GetKind() == wxITEM_RADIO)
+ {
+ int nCount = GetMenuItemCount();
+
+ if (m_nStartRadioGroup == -1)
+ {
+ //
+ // Start a new radio group
+ //
+ m_nStartRadioGroup = nCount;
+
+ //
+ // For now it has just one element
+ //
+ pItem->SetAsRadioGroupStart();
+ pItem->SetRadioGroupEnd(m_nStartRadioGroup);
+
+ //
+ // Ensure that we have a checked item in the radio group
+ //
+ bCheck = TRUE;
+ }
+ else // extend the current radio group
+ {
+ //
+ // We need to update its end item
+ //
+ pItem->SetRadioGroupStart(m_nStartRadioGroup);
+
+ wxMenuItemList::Node* pNode = GetMenuItems().Item(m_nStartRadioGroup);
+
+ if (pNode)
+ {
+ pNode->GetData()->SetRadioGroupEnd(nCount);
+ }
+ else
+ {
+ wxFAIL_MSG( _T("where is the radio group start item?") );
+ }
+ }
+ }
+ else // not a radio item
+ {
+ EndRadioGroup();
+ }
+
+ if (!wxMenuBase::DoAppend(pItem) || !DoInsertOrAppend(pItem))
+ {
+ return FALSE;
+ }
+ if (bCheck)
+ {
+ //
+ // Check the item initially
+ //
+ pItem->Check(TRUE);
+ }
+ return TRUE;
+} // end of wxMenu::DoAppend
-wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
+bool wxMenu::DoInsert(
+ size_t nPos
+, wxMenuItem* pItem
+)
+{
+ return ( wxMenuBase::DoInsert( nPos
+ ,pItem) &&
+ DoInsertOrAppend( pItem
+ ,nPos
+ )
+ );
+} // end of wxMenu::DoInsert
+
+wxMenuItem* wxMenu::DoRemove(
+ wxMenuItem* pItem
+)
{
- // we need to find the items position in the child list
- size_t pos;
- wxMenuItemList::Node *node = GetMenuItems().GetFirst();
- for ( pos = 0; node; pos++ )
+ //
+ // We need to find the items position in the child list
+ //
+ size_t nPos;
+ wxMenuItemList::Node* pNode = GetMenuItems().GetFirst();
+
+ for (nPos = 0; pNode; nPos++)
{
- if ( node->GetData() == item )
+ if (pNode->GetData() == pItem)
break;
-
- node = node->GetNext();
+ pNode = pNode->GetNext();
}
+ //
// DoRemove() (unlike Remove) can only be called for existing item!
- wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
+ //
+ wxCHECK_MSG(pNode, NULL, wxT("bug in wxMenu::Remove logic"));
#if wxUSE_ACCEL
- // remove the corresponding accel from the accel table
- int n = FindAccel(item->GetId());
- if ( n != wxNOT_FOUND )
- {
- delete m_accels[n];
+ //
+ // Remove the corresponding accel from the accel table
+ //
+ int n = FindAccel(pItem->GetId());
- m_accels.Remove(n);
- }
- //else: this item doesn't have an accel, nothing to do
-#endif // wxUSE_ACCEL
-/*
- // remove the item from the menu
- if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
+ if (n != wxNOT_FOUND)
{
- wxLogLastError("RemoveMenu");
+ delete m_vAccels[n];
+ m_vAccels.RemoveAt(n);
}
-*/
- if ( IsAttached() )
+
+#endif // wxUSE_ACCEL
+ //
+ // Remove the item from the menu
+ //
+ ::WinSendMsg( GetHmenu()
+ ,MM_REMOVEITEM
+ ,MPFROM2SHORT(pItem->GetId(), TRUE)
+ ,(MPARAM)0
+ );
+ if (IsAttached() && m_menuBar->IsAttached())
{
- // otherwise, the chane won't be visible
+ //
+ // Otherwise, the chane won't be visible
+ //
m_menuBar->Refresh();
}
- // and from internal data structures
- return wxMenuBase::DoRemove(item);
-}
+ //
+ // And from internal data structures
+ //
+ return wxMenuBase::DoRemove(pItem);
+} // end of wxMenu::DoRemove
// ---------------------------------------------------------------------------
// accelerator helpers
#if wxUSE_ACCEL
-// create the wxAcceleratorEntries for our accels and put them into provided
+//
+// Create the wxAcceleratorEntries for our accels and put them into provided
// array - return the number of accels we have
-size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
+//
+size_t wxMenu::CopyAccels(
+ wxAcceleratorEntry* pAccels
+) const
{
- size_t count = GetAccelCount();
- for ( size_t n = 0; n < count; n++ )
+ size_t nCount = GetAccelCount();
+
+ for (size_t n = 0; n < nCount; n++)
{
- *accels++ = *m_accels[n];
+ *pAccels++ = *m_vAccels[n];
}
-
- return count;
-}
+ return nCount;
+} // end of wxMenu::CopyAccels
#endif // wxUSE_ACCEL
// set wxMenu title
// ---------------------------------------------------------------------------
-void wxMenu::SetTitle(const wxString& label)
+void wxMenu::SetTitle(
+ const wxString& rLabel
+)
{
- bool hasNoTitle = m_title.IsEmpty();
- m_title = label;
-
- HMENU hMenu = GetHmenu();
+ bool bHasNoTitle = m_title.IsEmpty();
+ HWND hMenu = GetHmenu();
- if ( hasNoTitle )
+ m_title = rLabel;
+ if (bHasNoTitle)
{
- if ( !label.IsEmpty() )
+ if (!rLabel.IsEmpty())
{
-/*
- if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
- (unsigned)idMenuTitle, m_title) ||
- !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
+ if (!::WinSetWindowText(hMenu, rLabel.c_str()))
{
- wxLogLastError("InsertMenu");
+ wxLogLastError("SetMenuTitle");
}
-*/
}
}
else
{
- if ( label.IsEmpty() )
+ if (rLabel.IsEmpty() )
{
-/*
- // remove the title and the separator after it
- if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
- !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
- {
- wxLogLastError("RemoveMenu");
- }
-*/
+ ::WinSendMsg( GetHmenu()
+ ,MM_REMOVEITEM
+ ,MPFROM2SHORT(hMenu, TRUE)
+ ,(MPARAM)0
+ );
}
else
{
-/*
- // modify the title
- if ( !ModifyMenu(hMenu, 0u,
- MF_BYPOSITION | MF_STRING,
- (unsigned)idMenuTitle, m_title) )
+ //
+ // Modify the title
+ //
+ if (!::WinSetWindowText(hMenu, rLabel.c_str()))
{
- wxLogLastError("ModifyMenu");
+ wxLogLastError("SetMenuTitle");
}
-*/
}
}
-/*
-#ifdef __WIN32__
- // 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("SetMenuItemInfo");
- }
- }
-#endif // Win32
-*/
-}
+} // end of wxMenu::SetTitle
// ---------------------------------------------------------------------------
// event processing
// ---------------------------------------------------------------------------
-bool wxMenu::OS2Command(WXUINT WXUNUSED(param), WXWORD id)
+bool wxMenu::OS2Command(
+ WXUINT WXUNUSED(uParam)
+, WXWORD vId
+)
{
- // ignore commands from the menu title
+ //
+ // Ignore commands from the menu title
+ //
- // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
- if ( id != (WXWORD)idMenuTitle )
+ if (vId != (WXWORD)idMenuTitle)
{
- wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
- event.SetEventObject( this );
- event.SetId( id );
- event.SetInt( id );
- ProcessCommand(event);
+ SendEvent( vId
+ ,(int)::WinSendMsg( GetHmenu()
+ ,MM_QUERYITEMATTR
+ ,(MPARAM)vId
+ ,(MPARAM)MIA_CHECKED
+ )
+ );
}
-
return TRUE;
-}
-
-bool wxMenu::ProcessCommand(wxCommandEvent & event)
-{
- bool processed = FALSE;
-
-#if WXWIN_COMPATIBILITY
- // Try a callback
- if (m_callback)
- {
- (void)(*(m_callback))(*this, event);
- processed = TRUE;
- }
-#endif // WXWIN_COMPATIBILITY
-
- // Try the menu's event handler
- if ( !processed && GetEventHandler())
- {
- processed = GetEventHandler()->ProcessEvent(event);
- }
-
- // Try the window the menu was popped up from (and up through the
- // hierarchy)
- wxWindow *win = GetInvokingWindow();
- if ( !processed && win )
- processed = win->GetEventHandler()->ProcessEvent(event);
-
- return processed;
-}
+} // end of wxMenu::OS2Command
// ---------------------------------------------------------------------------
// other
// ---------------------------------------------------------------------------
-void wxMenu::Attach(wxMenuBar *menubar)
+wxWindow* wxMenu::GetWindow() const
{
- // menu can be in at most one menubar because otherwise they would both
- // delete the menu pointer
- wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
-
- m_menuBar = menubar;
-}
-
-void wxMenu::Detach()
-{
- wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
-
- m_menuBar = NULL;
-}
-
-wxWindow *wxMenu::GetWindow() const
-{
- if ( m_invokingWindow != NULL )
+ if (m_invokingWindow != NULL)
return m_invokingWindow;
else if ( m_menuBar != NULL)
return m_menuBar->GetFrame();
return NULL;
-}
+} // end of wxMenu::GetWindow
+
+// recursive search for item by id
+wxMenuItem* wxMenu::FindItem(
+ int nItemId
+, ULONG hItem
+, wxMenu** ppItemMenu
+) const
+{
+ if ( ppItemMenu )
+ *ppItemMenu = NULL;
+
+ wxMenuItem* pItem = NULL;
+
+ for ( wxMenuItemList::Node *node = m_items.GetFirst();
+ node && !pItem;
+ node = node->GetNext() )
+ {
+ pItem = node->GetData();
+
+ if ( pItem->GetId() == nItemId && pItem->m_vMenuData.hItem == hItem)
+ {
+ if ( ppItemMenu )
+ *ppItemMenu = (wxMenu *)this;
+ }
+ else if ( pItem->IsSubMenu() )
+ {
+ pItem = pItem->GetSubMenu()->FindItem( nItemId
+ ,hItem
+ ,ppItemMenu
+ );
+ if (pItem)
+ break;
+ }
+ else
+ {
+ // don't exit the loop
+ pItem = NULL;
+ }
+ }
+ return pItem;
+} // end of wxMenu::FindItem
// ---------------------------------------------------------------------------
// Menu Bar
m_eventHandler = this;
m_menuBarFrame = NULL;
m_hMenu = 0;
-}
+} // end of wxMenuBar::Init
wxMenuBar::wxMenuBar()
{
Init();
-}
+} // end of wxMenuBar::wxMenuBar
-wxMenuBar::wxMenuBar( long WXUNUSED(style) )
+wxMenuBar::wxMenuBar(
+ long WXUNUSED(lStyle)
+)
{
Init();
-}
+} // end of wxMenuBar::wxMenuBar
-wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
+wxMenuBar::wxMenuBar(
+ int nCount
+, wxMenu* vMenus[]
+, const wxString sTitles[]
+)
{
Init();
- m_titles.Alloc(count);
-
- for ( int i = 0; i < count; i++ )
+ m_titles.Alloc(nCount);
+ for ( int i = 0; i < nCount; i++ )
{
- m_menus.Append(menus[i]);
- m_titles.Add(titles[i]);
-
- menus[i]->Attach(this);
+ m_menus.Append(vMenus[i]);
+ m_titles.Add(sTitles[i]);
+ vMenus[i]->Attach(this);
}
-}
+} // end of wxMenuBar::wxMenuBar
wxMenuBar::~wxMenuBar()
{
-}
+ //
+ // We should free PM's resources only if PM doesn't do it for us
+ // which happens if we're attached to a frame
+ //
+ if (m_hMenu && !IsAttached())
+ {
+ ::WinDestroyWindow((HMENU)m_hMenu);
+ m_hMenu = (WXHMENU)NULL;
+ }
+} // end of wxMenuBar::~wxMenuBar
// ---------------------------------------------------------------------------
// wxMenuBar helpers
// ---------------------------------------------------------------------------
-void wxMenuBar::Refresh(
- bool WXUNUSED(bEraseBackground)
-, const wxRect* WXUNUSED(pRect)
-)
+void wxMenuBar::Refresh()
{
wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
-// DrawMenuBar(GetHwndOf(m_menuBarFrame));
-}
+ WinSendMsg(GetWinHwnd(m_menuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
+} // end of wxMenuBar::Refresh
WXHMENU wxMenuBar::Create()
{
+ MENUITEM vItem;
+ HWND hFrame;
+
if (m_hMenu != 0 )
return m_hMenu;
- wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") );
-
-// TODO:
-/*
+ wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
- m_hMenu = (WXHMENU)::CreateMenu();
-
- if ( !m_hMenu )
+ //
+ // Menubars should be associated with a frame otherwise they are popups
+ //
+ if (m_menuBarFrame != NULL)
+ hFrame = GetWinHwnd(m_menuBarFrame);
+ else
+ hFrame = HWND_DESKTOP;
+ //
+ // Create an empty menu and then fill it with insertions
+ //
+ if ((m_hMenu = ::WinCreateWindow( hFrame
+ ,WC_MENU
+ ,(PSZ)NULL
+ ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
+ ,0L
+ ,0L
+ ,0L
+ ,0L
+ ,hFrame
+ ,HWND_TOP
+ ,FID_MENU
+ ,NULL
+ ,NULL
+ )) == 0)
{
- wxLogLastError("CreateMenu");
+ wxLogLastError("WinLoadMenu");
}
else
{
- size_t count = GetMenuCount();
- for ( size_t i = 0; i < count; i++ )
+ size_t nCount = GetMenuCount();
+
+ for (size_t i = 0; i < nCount; i++)
{
- if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
- (UINT)m_menus[i]->GetHMenu(),
- m_titles[i]) )
+ APIRET rc;
+ ERRORID vError;
+ wxString sError;
+ HWND hSubMenu;
+
+ //
+ // Set the parent and owner of the submenues to be the menubar, not the desktop
+ //
+ hSubMenu = m_menus[i]->m_vMenuData.hwndSubMenu;
+ if (!::WinSetParent(m_menus[i]->m_vMenuData.hwndSubMenu, m_hMenu, FALSE))
+ {
+ vError = ::WinGetLastError(vHabmain);
+ sError = wxPMErrorToStr(vError);
+ wxLogError("Error setting parent for submenu. Error: %s\n", sError);
+ return NULLHANDLE;
+ }
+
+ if (!::WinSetOwner(m_menus[i]->m_vMenuData.hwndSubMenu, m_hMenu))
+ {
+ vError = ::WinGetLastError(vHabmain);
+ sError = wxPMErrorToStr(vError);
+ wxLogError("Error setting parent for submenu. Error: %s\n", sError);
+ return NULLHANDLE;
+ }
+
+ m_menus[i]->m_vMenuData.iPosition = i;
+
+ rc = (APIRET)::WinSendMsg(m_hMenu, MM_INSERTITEM, (MPARAM)&m_menus[i]->m_vMenuData, (MPARAM)m_titles[i].c_str());
+ if (rc == MIT_MEMERROR || rc == MIT_ERROR)
{
- wxLogLastError("AppendMenu");
+ vError = ::WinGetLastError(vHabmain);
+ sError = wxPMErrorToStr(vError);
+ wxLogError("Error inserting or appending a menuitem. Error: %s\n", sError);
+ return NULLHANDLE;
}
}
}
-
return m_hMenu;
-*/
- return (WXHMENU)0;
-}
+} // end of wxMenuBar::Create
// ---------------------------------------------------------------------------
// wxMenuBar functions to work with the top level submenus
// ---------------------------------------------------------------------------
+//
// NB: we don't support owner drawn top level items for now, if we do these
// functions would have to be changed to use wxMenuItem as well
-
-void wxMenuBar::EnableTop(size_t pos, bool enable)
+//
+void wxMenuBar::EnableTop(
+ size_t nPos
+, bool bEnable
+)
{
- wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
-
-// int flag = enable ? MF_ENABLED : MF_GRAYED;
+ wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
+ USHORT uFlag = 0;
+ SHORT nId;
-// EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
+ if(!bEnable)
+ uFlag = MIA_DISABLED;
+ nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
+ if (nId == MIT_ERROR)
+ {
+ wxLogLastError("LogLastError");
+ return;
+ }
+ ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(MIA_DISABLED, uFlag));
Refresh();
-}
+} // end of wxMenuBar::EnableTop
-void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
+void wxMenuBar::SetLabelTop(
+ size_t nPos
+, const wxString& rLabel
+)
{
- wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
+ SHORT nId;
+ MENUITEM vItem;
- m_titles[pos] = label;
+ wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
+ m_titles[nPos] = rLabel;
- if ( !IsAttached() )
+ if (!IsAttached())
{
return;
}
- //else: have to modify the existing menu
-// TODO:
-/*
- UINT id;
- UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
- if ( flagsOld == 0xFFFFFFFF )
+ nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
+ if (nId == MIT_ERROR)
{
- wxLogLastError(wxT("GetMenuState"));
-
+ wxLogLastError("LogLastError");
return;
}
-
- if ( flagsOld & MF_POPUP )
+ if(!::WinSendMsg( (HWND)m_hMenu
+ ,MM_QUERYITEM
+ ,MPFROM2SHORT(nId, TRUE)
+ ,MPARAM(&vItem)
+ ))
{
- // HIBYTE contains the number of items in the submenu in this case
- flagsOld &= 0xff;
- id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos);
- }
- else
- {
- id = pos;
+ wxLogLastError("QueryItem");
}
+ nId = vItem.id;
- if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
- id, label) == (int)0xFFFFFFFF )
+ if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
{
wxLogLastError("ModifyMenu");
}
-*/
Refresh();
-}
+} // end of wxMenuBar::SetLabelTop
-wxString wxMenuBar::GetLabelTop(size_t pos) const
+wxString wxMenuBar::GetLabelTop(
+ size_t nPos
+) const
{
- wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
+ wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
wxT("invalid menu index in wxMenuBar::GetLabelTop") );
-
- return m_titles[pos];
-}
-
-int wxMenuBar::FindMenu(const wxString& title)
-{
- wxString menuTitle = wxStripMenuCodes(title);
-
- size_t count = GetMenuCount();
- for ( size_t i = 0; i < count; i++ )
- {
- wxString title = wxStripMenuCodes(m_titles[i]);
- if ( menuTitle == title )
- return i;
- }
-
- return wxNOT_FOUND;
-
-}
+ return m_titles[nPos];
+} // end of wxMenuBar::GetLabelTop
// ---------------------------------------------------------------------------
// wxMenuBar construction
// ---------------------------------------------------------------------------
-wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
+wxMenu* wxMenuBar::Replace(
+ size_t nPos
+, wxMenu* pMenu
+, const wxString& rTitle
+)
{
- wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
- if ( !menuOld )
- return FALSE;
- m_titles[pos] = title;
-// TODO:
-/*
- if ( IsAttached() )
- {
- // can't use ModifyMenu() because it deletes the submenu it replaces
- if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
- {
- wxLogLastError("RemoveMenu");
- }
+ SHORT nId;
+ wxString sTitle = TextToLabel(rTitle);
+ wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
+ ,pMenu
+ ,sTitle
+ );
- if ( !::InsertMenu(GetHmenu(), (UINT)pos,
- MF_BYPOSITION | MF_POPUP | MF_STRING,
- (UINT)GetHmenuOf(menu), title) )
- {
- wxLogLastError("InsertMenu");
- }
+
+ nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
+ if (nId == MIT_ERROR)
+ {
+ wxLogLastError("LogLastError");
+ return NULL;
+ }
+ if (!pMenuOld)
+ return NULL;
+ m_titles[nPos] = sTitle;
+ if (IsAttached())
+ {
+ ::WinSendMsg((HWND)m_hMenu, MM_REMOVEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
+ ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
#if wxUSE_ACCEL
- if ( menuOld->HasAccels() || menu->HasAccels() )
+ if (pMenuOld->HasAccels() || pMenu->HasAccels())
{
- // need to rebuild accell table
+ //
+ // Need to rebuild accell table
+ //
RebuildAccelTable();
}
#endif // wxUSE_ACCEL
-
Refresh();
}
-*/
- return menuOld;
-}
+ return pMenuOld;
+} // end of wxMenuBar::Replace
-bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
+bool wxMenuBar::Insert(
+ size_t nPos
+, wxMenu* pMenu
+, const wxString& rTitle
+)
{
- if ( !wxMenuBarBase::Insert(pos, menu, title) )
+ wxString sTitle = TextToLabel(rTitle);
+
+ if (!wxMenuBarBase::Insert( nPos
+ ,pMenu
+ ,sTitle
+ ))
return FALSE;
- m_titles.Insert(title, pos);
+ m_titles.Insert( sTitle
+ ,nPos
+ );
- menu->Attach(this);
-// TODO:
-/*
- if ( IsAttached() )
+ if (IsAttached())
{
- if ( !::InsertMenu(GetHmenu(), pos,
- MF_BYPOSITION | MF_POPUP | MF_STRING,
- (UINT)GetHmenuOf(menu), title) )
- {
- wxLogLastError("InsertMenu");
- }
-
+ pMenu->m_vMenuData.iPosition = nPos;
+ ::WinSendMsg( (HWND)m_hMenu
+ ,MM_INSERTITEM
+ ,(MPARAM)&pMenu->m_vMenuData
+ ,(MPARAM)sTitle.c_str()
+ );
#if wxUSE_ACCEL
- if ( menu->HasAccels() )
+ if (pMenu->HasAccels())
{
// need to rebuild accell table
RebuildAccelTable();
}
#endif // wxUSE_ACCEL
-
Refresh();
}
-*/
return TRUE;
-}
+} // end of wxMenuBar::Insert
-bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
+bool wxMenuBar::Append(
+ wxMenu* pMenu
+, const wxString& rsTitle
+)
{
- WXHMENU submenu = menu ? menu->GetHMenu() : 0;
- wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
+ WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
+
+ wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
+
+ wxString sTitle = TextToLabel(rsTitle);
- if ( !wxMenuBarBase::Append(menu, title) )
+ if (!wxMenuBarBase::Append(pMenu, sTitle))
return FALSE;
- menu->Attach(this);
+ m_titles.Add(sTitle);
- m_titles.Add(title);
-// TODO:
-/*
if ( IsAttached() )
{
- if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
- (UINT)submenu, title) )
- {
- wxLogLastError(wxT("AppendMenu"));
- }
-
+ pMenu->m_vMenuData.iPosition = MIT_END;
+ ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
#if wxUSE_ACCEL
- if ( menu->HasAccels() )
+ if (pMenu->HasAccels())
{
- // need to rebuild accell table
+ //
+ // Need to rebuild accell table
+ //
RebuildAccelTable();
}
#endif // wxUSE_ACCEL
-
Refresh();
}
-*/
return TRUE;
-}
+} // end of wxMenuBar::Append
-wxMenu *wxMenuBar::Remove(size_t pos)
+wxMenu* wxMenuBar::Remove(
+ size_t nPos
+)
{
- wxMenu *menu = wxMenuBarBase::Remove(pos);
- if ( !menu )
+ wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
+ SHORT nId;
+
+ if (!pMenu)
return NULL;
-// TODO:
-/*
- if ( IsAttached() )
- {
- if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
- {
- wxLogLastError("RemoveMenu");
- }
- menu->Detach();
+ nId = SHORT1FROMMR(::WinSendMsg( (HWND)GetHmenu()
+ ,MM_ITEMIDFROMPOSITION
+ ,MPFROMSHORT(nPos)
+ ,(MPARAM)0)
+ );
+ if (nId == MIT_ERROR)
+ {
+ wxLogLastError("LogLastError");
+ return NULL;
+ }
+ if (IsAttached())
+ {
+ ::WinSendMsg( (HWND)GetHmenu()
+ ,MM_REMOVEITEM
+ ,MPFROM2SHORT(nId, TRUE)
+ ,(MPARAM)0
+ );
#if wxUSE_ACCEL
- if ( menu->HasAccels() )
+ if (pMenu->HasAccels())
{
- // need to rebuild accell table
+ //
+ // Need to rebuild accell table
+ //
RebuildAccelTable();
}
#endif // wxUSE_ACCEL
-
Refresh();
}
-
- m_titles.Remove(pos);
-*/
- return menu;
-}
+ m_titles.Remove(nPos);
+ return pMenu;
+} // end of wxMenuBar::Remove
#if wxUSE_ACCEL
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++ )
+ //
+ // Merge the accelerators of all menus into one accel table
+ //
+ size_t nAccelCount = 0;
+ size_t i;
+ size_t nCount = GetMenuCount();
+
+ for (i = 0; i < nCount; i++)
{
nAccelCount += m_menus[i]->GetAccelCount();
}
- if ( nAccelCount )
+ if (nAccelCount)
{
- wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
+ wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
nAccelCount = 0;
- for ( i = 0; i < count; i++ )
+ for (i = 0; i < nCount; i++)
{
- nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
+ nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
}
-
- m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
-
- delete [] accelEntries;
+ m_vAccelTable = wxAcceleratorTable( nAccelCount
+ ,pAccelEntries
+ );
+ delete [] pAccelEntries;
}
-}
+} // end of wxMenuBar::RebuildAccelTable
#endif // wxUSE_ACCEL
-void wxMenuBar::Attach(wxFrame *frame)
+void wxMenuBar::Attach(
+ wxFrame* pFrame
+)
{
- wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
-
- m_menuBarFrame = frame;
+ wxMenuBarBase::Attach(pFrame);
#if wxUSE_ACCEL
RebuildAccelTable();
+ //
+ // Ensure the accelerator table is set to the frame (not the client!)
+ //
+ if (!::WinSetAccelTable( vHabmain
+ ,m_vAccelTable.GetHACCEL()
+ ,(HWND)pFrame->GetFrame()
+ ))
+ wxLogLastError("WinSetAccelTable");
#endif // wxUSE_ACCEL
-}
+} // end of wxMenuBar::Attach
void wxMenuBar::Detach()
{
-// ::DestroyMenu((HMENU)m_hMenu);
+ ::WinDestroyWindow((HWND)m_hMenu);
m_hMenu = (WXHMENU)NULL;
m_menuBarFrame = NULL;
-}
-
+} // end of wxMenuBar::Detach
// ---------------------------------------------------------------------------
// wxMenuBar searching for menu items
// ---------------------------------------------------------------------------
+//
// Find the itemString in menuString, and return the item id or wxNOT_FOUND
-int wxMenuBar::FindMenuItem(const wxString& menuString,
- const wxString& itemString) const
+//
+int wxMenuBar::FindMenuItem(
+ const wxString& rMenuString
+, const wxString& rItemString
+) const
{
- wxString menuLabel = wxStripMenuCodes(menuString);
- size_t count = GetMenuCount();
- for ( size_t i = 0; i < count; i++ )
+ wxString sMenuLabel = wxStripMenuCodes(rMenuString);
+ size_t nCount = GetMenuCount();
+
+ for (size_t i = 0; i < nCount; i++)
{
- wxString title = wxStripMenuCodes(m_titles[i]);
- if ( menuString == title )
- return m_menus[i]->FindItem(itemString);
- }
+ wxString sTitle = wxStripMenuCodes(m_titles[i]);
+ if (rMenuString == sTitle)
+ return m_menus[i]->FindItem(rItemString);
+ }
return wxNOT_FOUND;
-}
+} // end of wxMenuBar::FindMenuItem
-wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
+wxMenuItem* wxMenuBar::FindItem(
+ int nId
+, wxMenu** ppItemMenu
+) const
{
- if ( itemMenu )
- *itemMenu = NULL;
+ if (ppItemMenu)
+ *ppItemMenu = NULL;
- wxMenuItem *item = NULL;
- size_t count = GetMenuCount();
- for ( size_t i = 0; !item && (i < count); i++ )
+ wxMenuItem* pItem = NULL;
+ size_t nCount = GetMenuCount();
+
+ for (size_t i = 0; !pItem && (i < nCount); i++)
{
- item = m_menus[i]->FindItem(id, itemMenu);
+ pItem = m_menus[i]->FindItem( nId
+ ,ppItemMenu
+ );
}
+ return pItem;
+} // end of wxMenuBar::FindItem
+
+wxMenuItem* wxMenuBar::FindItem(
+ int nId
+, ULONG hItem
+, wxMenu** ppItemMenu
+) const
+{
+ if (ppItemMenu)
+ *ppItemMenu = NULL;
- return item;
-}
+ wxMenuItem* pItem = NULL;
+ size_t nCount = GetMenuCount();
+
+ for (size_t i = 0; !pItem && (i < nCount); i++)
+ {
+ pItem = m_menus[i]->FindItem( nId
+ ,hItem
+ ,ppItemMenu
+ );
+ }
+ return pItem;
+} // end of wxMenuBar::FindItem