]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menu.cpp
wxTopLevelWindows is now a wxWindowList, better compatibility with the old
[wxWidgets.git] / src / msw / menu.cpp
CommitLineData
2bda0e17
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
4// Author: Julian Smart
5// Modified by: Vadim Zeitlin
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
c626a8b7 9// Licence: wxWindows license
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
2bda0e17 12#ifdef __GNUG__
c626a8b7 13 #pragma implementation "menu.h"
2bda0e17
KB
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
c626a8b7 20 #pragma hdrstop
2bda0e17
KB
21#endif
22
23#ifndef WX_PRECOMP
c626a8b7
VZ
24 #include "wx/frame.h"
25 #include "wx/menu.h"
26 #include "wx/utils.h"
2bda0e17
KB
27#endif
28
47d67540 29#if wxUSE_OWNER_DRAWN
c626a8b7 30 #include "wx/ownerdrw.h"
2bda0e17
KB
31#endif
32
33#include "wx/msw/private.h"
34#include "wx/msw/menu.h"
35#include "wx/menuitem.h"
36#include "wx/log.h"
37
38// other standard headers
2bda0e17
KB
39#include <string.h>
40
c626a8b7
VZ
41// ----------------------------------------------------------------------------
42// global variables
43// ----------------------------------------------------------------------------
44
45extern wxMenu *wxCurrentPopupMenu;
46
b8d3a4f1
VZ
47// ----------------------------------------------------------------------------
48// constants
49// ----------------------------------------------------------------------------
50
51// the (popup) menu title has this special id
52static const int idMenuTitle = -2;
53
54// ----------------------------------------------------------------------------
c626a8b7 55// macros
b8d3a4f1 56// ----------------------------------------------------------------------------
c626a8b7 57
2bda0e17 58#if !USE_SHARED_LIBRARY
c626a8b7
VZ
59 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
60 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
2bda0e17
KB
61#endif
62
c626a8b7 63// convenience macro
8cd85069
VZ
64#define GetHMENU() ((HMENU)GetHMenu())
65#define GetHMenuOf(menu) ((HMENU)menu->GetHMenu())
c626a8b7 66
2bda0e17
KB
67// ============================================================================
68// implementation
69// ============================================================================
70
71// Menus
72
73// Construct a menu with optional title (then use append)
c626a8b7
VZ
74wxMenu::wxMenu(const wxString& title, const wxFunction func)
75 : m_title(title)
76{
77 m_parent = NULL;
78 m_eventHandler = this;
79 m_pInvokingWindow = NULL;
80 m_doBreak = FALSE ;
81 m_noItems = 0;
82 m_menuBar = NULL;
83 m_hMenu = (WXHMENU) CreatePopupMenu();
84 m_savehMenu = 0 ;
85 m_topLevelMenu = this;
86 m_clientData = (void*) NULL;
87
88 if ( !!m_title )
89 {
90 Append(idMenuTitle, m_title) ;
91 AppendSeparator() ;
92 }
2bda0e17 93
c626a8b7 94 Callback(func);
2bda0e17
KB
95}
96
97// The wxWindow destructor will take care of deleting the submenus.
b8d3a4f1 98wxMenu::~wxMenu()
2bda0e17 99{
c626a8b7
VZ
100 if (m_hMenu)
101 DestroyMenu((HMENU) m_hMenu);
102 m_hMenu = 0;
103
104 // Windows seems really bad on Menu de-allocation...
105 // After many try, here is what I do: RemoveMenu() will ensure
106 // that popup are "disconnected" from their parent; then call
107 // delete method on each child (which in turn do a recursive job),
108 // and finally, DestroyMenu()
109 //
110 // With that, BoundCheckers is happy, and no complaints...
111 /*
112 int N = 0 ;
113 if (m_hMenu)
114 N = GetMenuItemCount(m_hMenu);
115 int i;
116 for (i = N-1; i >= 0; i--)
117 RemoveMenu(m_hMenu, i, MF_BYPOSITION);
118 */
119
120 // How is deleting submenus in this loop any different from deleting
121 // the submenus in the children list, via ~wxWindow ?
122 // I'll reinstate this deletion for now and remove addition
123 // from children list (which doesn't exist now)
124 // Julian 1/3/97
125 wxNode *node = m_menuItems.First();
126 while (node)
127 {
128 wxMenuItem *item = (wxMenuItem *)node->Data();
129
130 // Delete child menus.
131 // Beware: they must not be appended to children list!!!
132 // (because order of delete is significant)
133 if (item->GetSubMenu())
134 item->DeleteSubMenu();
135
136 wxNode *next = node->Next();
137 delete item;
138 delete node;
139 node = next;
140 }
141 /*
142 if (m_hMenu)
143 DestroyMenu(m_hMenu);
144 m_hMenu = 0;
145 */
2bda0e17
KB
146}
147
b8d3a4f1 148void wxMenu::Break()
2bda0e17 149{
c626a8b7 150 m_doBreak = TRUE ;
2bda0e17
KB
151}
152
153// function appends a new item or submenu to the menu
154void wxMenu::Append(wxMenuItem *pItem)
155{
c626a8b7 156 wxCHECK_RET( pItem != NULL, "can't append NULL item to the menu" );
2bda0e17 157
c626a8b7 158 m_menuItems.Append(pItem);
2bda0e17 159
c626a8b7 160 UINT flags = 0;
2bda0e17 161
c626a8b7
VZ
162 if ( m_doBreak ) {
163 flags |= MF_MENUBREAK;
164 m_doBreak = FALSE;
165 }
166
167 if ( pItem->IsSeparator() ) {
168 flags |= MF_SEPARATOR;
169 }
2bda0e17 170
c626a8b7
VZ
171 // id is the numeric id for normal menu items and HMENU for submenus
172 UINT id;
173 wxMenu *SubMenu = pItem->GetSubMenu();
174 if ( SubMenu != NULL ) {
175 wxASSERT( SubMenu->m_hMenu != (WXHMENU) NULL );
2bda0e17 176
c626a8b7 177 id = (UINT)SubMenu->m_hMenu;
2bda0e17 178
c626a8b7
VZ
179 SubMenu->m_topLevelMenu = m_topLevelMenu;
180 SubMenu->m_parent = this;
181 SubMenu->m_savehMenu = (WXHMENU)id;
182 SubMenu->m_hMenu = 0;
2bda0e17 183
c626a8b7
VZ
184 flags |= MF_POPUP;
185 }
186 else {
187 id = pItem->GetId();
188 }
2bda0e17 189
c626a8b7 190 LPCSTR pData;
2bda0e17 191
47d67540 192#if wxUSE_OWNER_DRAWN
c626a8b7
VZ
193 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
194 // item draws itself, pass pointer to it in data parameter
195 flags |= MF_OWNERDRAW;
196 pData = (LPCSTR)pItem;
197 }
198 else
2bda0e17 199#endif
c626a8b7
VZ
200 {
201 // menu is just a normal string (passed in data parameter)
202 flags |= MF_STRING;
203 pData = pItem->GetName();
204 }
2bda0e17 205
c626a8b7
VZ
206 // visually select the menu title
207 if ( id == idMenuTitle )
208 {
209 // TODO use SetMenuItemInfo(MFS_DEFAULT) to put it in bold face
210 }
2bda0e17 211
c626a8b7
VZ
212 if ( !AppendMenu(GetHMENU(), flags, id, pData) )
213 {
214 wxLogLastError("AppendMenu");
215 }
2bda0e17 216
c626a8b7 217 m_noItems++;
2bda0e17
KB
218}
219
b8d3a4f1 220void wxMenu::AppendSeparator()
2bda0e17 221{
c626a8b7 222 Append(new wxMenuItem(this, ID_SEPARATOR));
2bda0e17
KB
223}
224
225// Pullright item
8cd85069 226void wxMenu::Append(int id, const wxString& label,
c626a8b7 227 wxMenu *SubMenu, const wxString& helpString)
2bda0e17 228{
8cd85069 229 Append(new wxMenuItem(this, id, label, helpString, FALSE, SubMenu));
2bda0e17
KB
230}
231
232// Ordinary menu item
8cd85069 233void wxMenu::Append(int id, const wxString& label,
c626a8b7 234 const wxString& helpString, bool checkable)
2bda0e17 235{
c626a8b7 236 // 'checkable' parameter is useless for Windows.
8cd85069 237 Append(new wxMenuItem(this, id, label, helpString, checkable));
2bda0e17
KB
238}
239
240void wxMenu::Delete(int id)
241{
c626a8b7
VZ
242 wxMenuItem *item = NULL;
243 int pos;
244 wxNode *node;
245 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
246 {
247 item = (wxMenuItem *)node->Data();
248 if ( item->GetId() == id )
249 break;
250 }
251
252 wxCHECK_RET( node, "wxMenu::Delete(): item doesn't exist" );
253
254 HMENU menu = GetHMENU();
255
256 wxMenu *pSubMenu = item->GetSubMenu();
257 if ( pSubMenu != NULL ) {
258 RemoveMenu(menu, (UINT)pos, MF_BYPOSITION);
259 pSubMenu->m_hMenu = pSubMenu->m_savehMenu;
260 pSubMenu->m_savehMenu = 0;
261 pSubMenu->m_parent = NULL;
262 // RemoveChild(item->subMenu);
263 pSubMenu->m_topLevelMenu = NULL;
264 // TODO: Why isn't subMenu deleted here???
265 // Will put this in for now. Assuming this is supposed
266 // to delete the menu, not just remove it.
267 item->DeleteSubMenu();
268 }
269 else {
270 DeleteMenu(menu, (UINT)pos, MF_BYPOSITION);
271 }
272
273 m_menuItems.DeleteNode(node);
274 delete item;
2bda0e17
KB
275}
276
8cd85069 277void wxMenu::Enable(int id, bool Flag)
2bda0e17 278{
8cd85069 279 wxMenuItem *item = FindItemForId(id);
c626a8b7 280 wxCHECK_RET( item != NULL, "can't enable non-existing menu item" );
2bda0e17 281
c626a8b7 282 item->Enable(Flag);
2bda0e17
KB
283}
284
8cd85069 285bool wxMenu::IsEnabled(int id) const
2bda0e17 286{
8cd85069
VZ
287 wxMenuItem *item = FindItemForId(id);
288 wxCHECK_MSG( item != NULL, FALSE, "invalid item id" );
2bda0e17 289
c626a8b7 290 return item->IsEnabled();
2bda0e17
KB
291}
292
8cd85069 293void wxMenu::Check(int id, bool Flag)
2bda0e17 294{
8cd85069 295 wxMenuItem *item = FindItemForId(id);
c626a8b7 296 wxCHECK_RET( item != NULL, "can't get status of non-existing menu item" );
2bda0e17 297
c626a8b7 298 item->Check(Flag);
2bda0e17
KB
299}
300
8cd85069 301bool wxMenu::IsChecked(int id) const
2bda0e17 302{
8cd85069
VZ
303 wxMenuItem *item = FindItemForId(id);
304 wxCHECK_MSG( item != NULL, FALSE, "invalid item id" );
2bda0e17 305
c626a8b7 306 return item->IsChecked();
2bda0e17
KB
307}
308
309void wxMenu::SetTitle(const wxString& label)
310{
c626a8b7
VZ
311 bool hasNoTitle = m_title.IsEmpty();
312 m_title = label;
b8d3a4f1 313
c626a8b7 314 HMENU hMenu = GetHMENU();
b8d3a4f1 315
c626a8b7 316 if ( hasNoTitle )
b8d3a4f1 317 {
c626a8b7
VZ
318 if ( !label.IsEmpty() )
319 {
320 if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
321 (unsigned)idMenuTitle, m_title) ||
322 !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
323 {
324 wxLogLastError("InsertMenu");
325 }
326 }
b8d3a4f1
VZ
327 }
328 else
329 {
c626a8b7
VZ
330 if ( label.IsEmpty() )
331 {
332 // remove the title and the separator after it
333 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
334 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
335 {
336 wxLogLastError("RemoveMenu");
337 }
338 }
339 else
340 {
341 // modify the title
342 if ( !ModifyMenu(hMenu, 0u,
343 MF_BYPOSITION | MF_STRING,
344 (unsigned)idMenuTitle, m_title) )
345 {
346 wxLogLastError("ModifyMenu");
347 }
348 }
b8d3a4f1 349 }
b8d3a4f1 350
750b78ba 351#ifndef __WIN16__
c626a8b7
VZ
352 // put the title string in bold face
353 if ( !m_title.IsEmpty() )
a3f4e9e8 354 {
c626a8b7
VZ
355 MENUITEMINFO mii;
356 mii.cbSize = sizeof(mii);
357 mii.fMask = MIIM_STATE;
358 mii.fState = MFS_DEFAULT;
359
360 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
361 {
362 wxLogLastError("SetMenuItemInfo");
363 }
a3f4e9e8 364 }
750b78ba 365#endif
2bda0e17
KB
366}
367
f7387de5 368const wxString wxMenu::GetTitle() const
2bda0e17 369{
c626a8b7 370 return m_title;
2bda0e17
KB
371}
372
8cd85069 373void wxMenu::SetLabel(int id, const wxString& label)
2bda0e17 374{
8cd85069 375 wxMenuItem *item = FindItemForId(id) ;
c626a8b7
VZ
376 if (item==NULL)
377 return;
2bda0e17 378
c626a8b7 379 if (item->GetSubMenu()==NULL)
2bda0e17 380 {
c626a8b7
VZ
381 HMENU hMenu = GetHMENU();
382
8cd85069
VZ
383 UINT was_flag = GetMenuState(hMenu, id, MF_BYCOMMAND);
384 ModifyMenu(hMenu, id, MF_BYCOMMAND | MF_STRING | was_flag, id, label);
2bda0e17 385 }
c626a8b7 386 else
2bda0e17 387 {
c626a8b7
VZ
388 wxMenu *father = item->GetSubMenu()->m_topLevelMenu ;
389 wxNode *node = father->m_menuItems.First() ;
390 int i = 0 ;
391 while (node)
392 {
393 wxMenuItem *matched = (wxMenuItem*)node->Data() ;
394 if (matched==item)
395 break ;
396 i++ ;
397 node = node->Next() ;
398 }
399 // Here, we have the position.
400 ModifyMenu((HMENU)father->m_savehMenu,i,
401 MF_BYPOSITION|MF_STRING|MF_POPUP,
402 (UINT)item->GetSubMenu()->m_savehMenu,(const char *)label) ;
2bda0e17 403 }
c626a8b7 404 item->SetName(label);
2bda0e17
KB
405}
406
47bc1060 407wxString wxMenu::GetLabel(int id) const
2bda0e17 408{
c626a8b7 409 wxString label;
47bc1060
JS
410 wxMenuItem *pItem = FindItemForId(id) ;
411 if (pItem)
c626a8b7 412 label = pItem->GetName() ;
47bc1060 413 else
c626a8b7
VZ
414 wxFAIL_MSG("wxMenu::GetLabel: item doesn't exist");
415
416 return label;
2bda0e17
KB
417}
418
debe6624 419bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
2bda0e17 420{
a3f4e9e8
VZ
421 // ignore commands from the menu title
422
423 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
424 if ( id != (WXWORD)idMenuTitle )
425 {
426 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
427 event.SetEventObject( this );
428 event.SetId( id );
429 event.SetInt( id );
430 ProcessCommand(event);
431 }
432
433 return TRUE;
2bda0e17
KB
434}
435
436// Finds the item id matching the given string, -1 if not found.
437int wxMenu::FindItem (const wxString& itemString) const
438{
c626a8b7
VZ
439 // FIXME fixed size buffer
440 char buf1[200];
441 char buf2[200];
442 wxStripMenuCodes ((char *)(const char *)itemString, buf1);
2bda0e17 443
c626a8b7 444 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
2bda0e17 445 {
c626a8b7
VZ
446 wxMenuItem *item = (wxMenuItem *) node->Data ();
447 if (item->GetSubMenu())
448 {
449 int ans = item->GetSubMenu()->FindItem(itemString);
450 if (ans > -1)
451 return ans;
452 }
453 if ( !item->IsSeparator() )
454 {
455 wxStripMenuCodes((char *)item->GetName().c_str(), buf2);
456 if (strcmp(buf1, buf2) == 0)
457 return item->GetId();
458 }
2bda0e17
KB
459 }
460
c626a8b7 461 return wxNOT_FOUND;
2bda0e17
KB
462}
463
debe6624 464wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
2bda0e17 465{
c626a8b7
VZ
466 if (itemMenu)
467 *itemMenu = NULL;
468 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
2bda0e17 469 {
c626a8b7
VZ
470 wxMenuItem *item = (wxMenuItem *) node->Data ();
471
472 if (item->GetId() == itemId)
473 {
474 if (itemMenu)
475 *itemMenu = (wxMenu *) this;
476 return item;
477 }
478
479 if (item->GetSubMenu())
480 {
481 wxMenuItem *ans = item->GetSubMenu()->FindItemForId (itemId, itemMenu);
482 if (ans)
483 return ans;
484 }
2bda0e17
KB
485 }
486
c626a8b7
VZ
487 if (itemMenu)
488 *itemMenu = NULL;
489 return NULL;
2bda0e17
KB
490}
491
debe6624 492void wxMenu::SetHelpString(int itemId, const wxString& helpString)
2bda0e17 493{
c626a8b7
VZ
494 wxMenuItem *item = FindItemForId (itemId);
495 if (item)
496 item->SetHelp(helpString);
497 else
498 wxFAIL_MSG("wxMenu::SetHelpString: item doesn't exist");
2bda0e17
KB
499}
500
debe6624 501wxString wxMenu::GetHelpString (int itemId) const
2bda0e17 502{
c626a8b7
VZ
503 wxString help;
504 wxMenuItem *item = FindItemForId (itemId);
505 if (item)
506 help = item->GetHelp();
507 else
508 wxFAIL_MSG("wxMenu::GetHelpString: item doesn't exist");
509
510 return help;
2bda0e17
KB
511}
512
513void wxMenu::ProcessCommand(wxCommandEvent & event)
514{
c626a8b7 515 bool processed = FALSE;
2bda0e17 516
c626a8b7
VZ
517 // Try a callback
518 if (m_callback)
519 {
520 (void)(*(m_callback))(*this, event);
521 processed = TRUE;
522 }
2bda0e17 523
c626a8b7
VZ
524 // Try the menu's event handler
525 if ( !processed && GetEventHandler())
526 {
527 processed = GetEventHandler()->ProcessEvent(event);
528 }
2bda0e17 529
c626a8b7
VZ
530 // Try the window the menu was popped up from (and up through the
531 // hierarchy)
532 wxWindow *win = GetInvokingWindow();
533 if ( !processed && win )
534 processed = win->GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
535}
536
debe6624 537bool wxWindow::PopupMenu(wxMenu *menu, int x, int y)
2bda0e17 538{
c626a8b7
VZ
539 menu->SetInvokingWindow(this);
540 menu->UpdateUI();
2bda0e17 541
c626a8b7
VZ
542 HWND hWnd = (HWND) GetHWND();
543 HMENU hMenu = (HMENU)menu->m_hMenu;
544 POINT point;
545 point.x = x;
546 point.y = y;
547 ::ClientToScreen(hWnd, &point);
548 wxCurrentPopupMenu = menu;
549 ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
550 wxYield();
551 wxCurrentPopupMenu = NULL;
2bda0e17 552
c626a8b7 553 menu->SetInvokingWindow(NULL);
2bda0e17 554
c626a8b7 555 return TRUE;
2bda0e17
KB
556}
557
558// Menu Bar
b8d3a4f1 559wxMenuBar::wxMenuBar()
2bda0e17 560{
c626a8b7
VZ
561 m_eventHandler = this;
562 m_menuCount = 0;
563 m_menus = NULL;
564 m_titles = NULL;
565 m_menuBarFrame = NULL;
566 m_hMenu = 0;
cba2db0c 567}
2bda0e17 568
cba2db0c
JS
569wxMenuBar::wxMenuBar( long WXUNUSED(style) )
570{
c626a8b7
VZ
571 m_eventHandler = this;
572 m_menuCount = 0;
573 m_menus = NULL;
574 m_titles = NULL;
575 m_menuBarFrame = NULL;
576 m_hMenu = 0;
2bda0e17
KB
577}
578
debe6624 579wxMenuBar::wxMenuBar(int N, wxMenu *Menus[], const wxString Titles[])
2bda0e17 580{
c626a8b7
VZ
581 m_eventHandler = this;
582 m_menuCount = N;
583 m_menus = Menus;
584 m_titles = new wxString[N];
585 int i;
586 for ( i = 0; i < N; i++ )
587 m_titles[i] = Titles[i];
588 m_menuBarFrame = NULL;
589 for (i = 0; i < N; i++)
590 m_menus[i]->m_menuBar = (wxMenuBar *) this;
2bda0e17 591
c626a8b7 592 m_hMenu = 0;
2bda0e17
KB
593}
594
b8d3a4f1 595wxMenuBar::~wxMenuBar()
2bda0e17 596{
c626a8b7
VZ
597 // In fact, don't want menu to be destroyed before MDI
598 // shuffling has taken place. Let it be destroyed
599 // automatically when the window is destroyed.
2bda0e17 600
c626a8b7
VZ
601 // DestroyMenu(menu);
602 // m_hMenu = NULL;
2bda0e17 603
c626a8b7
VZ
604 int i;
605 /*
606 // See remarks in ::~wxMenu() method
607 // BEWARE - this may interfere with MDI fixes, so
608 // may need to remove
609 int N = 0 ;
2bda0e17 610
c626a8b7
VZ
611 if (m_menuBarFrame && ((m_menuBarFrame->GetWindowStyleFlag() & wxSDI) == wxSDI))
612 {
2bda0e17 613 if (menu)
c626a8b7 614 N = GetMenuItemCount(menu) ;
2bda0e17 615 for (i = N-1; i >= 0; i--)
c626a8b7
VZ
616 RemoveMenu(menu, i, MF_BYPOSITION);
617 }
618 */
619 for (i = 0; i < m_menuCount; i++)
620 {
621 delete m_menus[i];
622 }
623 delete[] m_menus;
624 delete[] m_titles;
625
626 /* Don't destroy menu here, in case we're MDI and
627 need to do some shuffling with VALID menu handles.
628 if (menu)
629 DestroyMenu(menu);
630 m_hMenu = 0;
631 */
2bda0e17
KB
632}
633
634// Must only be used AFTER menu has been attached to frame,
635// otherwise use individual menus to enable/disable items
8cd85069 636void wxMenuBar::Enable(int id, bool enable)
2bda0e17 637{
c626a8b7 638 int flag = enable ? MF_ENABLED : MF_GRAYED;
2bda0e17 639
c626a8b7 640 wxMenu *itemMenu = NULL;
8cd85069 641 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
2bda0e17 642
c626a8b7 643 wxCHECK_RET( item, "attempt to enable an item which doesn't exist" );
2bda0e17 644
8cd85069 645 EnableMenuItem(GetHMenuOf(itemMenu), id, MF_BYCOMMAND | flag);
2bda0e17
KB
646}
647
c626a8b7 648void wxMenuBar::EnableTop(int pos, bool enable)
2bda0e17 649{
c626a8b7 650 int flag = enable ? MF_ENABLED : MF_GRAYED;;
2bda0e17 651
c626a8b7 652 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
8cd85069 653 DrawMenuBar((HWND)m_menuBarFrame->GetHWND()) ;
2bda0e17
KB
654}
655
656// Must only be used AFTER menu has been attached to frame,
657// otherwise use individual menus
8cd85069 658void wxMenuBar::Check(int id, bool check)
c626a8b7
VZ
659{
660 wxMenu *itemMenu = NULL;
8cd85069 661 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
c626a8b7
VZ
662
663 wxCHECK_RET( item, "attempt to check an item which doesn't exist" );
664 wxCHECK_RET( item->IsCheckable(), "attempt to check an uncheckable item" );
2bda0e17 665
c626a8b7 666 int flag = check ? MF_CHECKED : MF_UNCHECKED;
8cd85069 667 CheckMenuItem(GetHMenuOf(itemMenu), id, MF_BYCOMMAND | flag);
c626a8b7
VZ
668}
669
8cd85069 670bool wxMenuBar::IsChecked(int id) const
c626a8b7
VZ
671{
672 wxMenu *itemMenu = NULL;
8cd85069 673 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
2bda0e17 674
c626a8b7 675 wxCHECK_MSG( item, FALSE, "wxMenuItem::IsChecked(): no such item" );
2bda0e17 676
8cd85069 677 int flag = ::GetMenuState(GetHMenuOf(itemMenu), id, MF_BYCOMMAND);
2bda0e17 678
c626a8b7 679 return (flag & MF_CHECKED) != 0;
2bda0e17
KB
680}
681
8cd85069 682bool wxMenuBar::IsEnabled(int id) const
2bda0e17 683{
c626a8b7 684 wxMenu *itemMenu = NULL;
8cd85069 685 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
2bda0e17 686
c626a8b7 687 wxCHECK_MSG( item, FALSE, "wxMenuItem::IsEnabled(): no such item" );
2bda0e17 688
8cd85069 689 int flag = ::GetMenuState(GetHMenuOf(itemMenu), id, MF_BYCOMMAND) ;
2bda0e17 690
c626a8b7 691 return (flag & MF_ENABLED) != 0;
2bda0e17
KB
692}
693
8cd85069 694void wxMenuBar::SetLabel(int id, const wxString& label)
2bda0e17 695{
c626a8b7 696 wxMenu *itemMenu = NULL;
8cd85069 697 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
2bda0e17 698
c626a8b7
VZ
699 if (!item)
700 return;
2bda0e17 701
8cd85069
VZ
702 HMENU hMenu = GetHMenuOf(itemMenu);
703 UINT was_flag = ::GetMenuState(hMenu, id, MF_BYCOMMAND);
704 ::ModifyMenu(hMenu, id, MF_BYCOMMAND | MF_STRING | was_flag, id, label);
2bda0e17
KB
705}
706
8cd85069 707wxString wxMenuBar::GetLabel(int id) const
2bda0e17 708{
c626a8b7 709 wxMenu *itemMenu = NULL;
8cd85069 710 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
2bda0e17 711
c626a8b7 712 wxCHECK_MSG( item, "", "wxMenuItem::GetLabel(): no such item" );
2bda0e17 713
8cd85069
VZ
714 HMENU hMenu = GetHMenuOf(itemMenu);
715 int len = ::GetMenuString(hMenu, id, NULL, 0, MF_BYCOMMAND);
716
717 len++; // for the NUL character
718 wxString label;
719 ::GetMenuString(hMenu, id, label.GetWriteBuf(len), len, MF_BYCOMMAND);
720 label.UngetWriteBuf();
2bda0e17 721
8cd85069 722 return label;
2bda0e17
KB
723}
724
debe6624 725void wxMenuBar::SetLabelTop(int pos, const wxString& label)
2bda0e17 726{
8cd85069
VZ
727 UINT id;
728 UINT was_flag = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
729 if (was_flag & MF_POPUP)
c626a8b7
VZ
730 {
731 was_flag &= 0xff ;
8cd85069 732 id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos) ;
c626a8b7
VZ
733 }
734 else
8cd85069
VZ
735 {
736 id = pos;
737 }
738
739 ::ModifyMenu((HMENU)m_hMenu, pos, MF_BYPOSITION | MF_STRING | was_flag,
740 id, label) ;
2bda0e17
KB
741}
742
debe6624 743wxString wxMenuBar::GetLabelTop(int pos) const
2bda0e17 744{
8cd85069
VZ
745 int len = ::GetMenuString((HMENU)m_hMenu, pos, NULL, 0, MF_BYCOMMAND);
746
747 len++; // for the NUL character
748 wxString label;
749 ::GetMenuString((HMENU)m_hMenu, pos, label.GetWriteBuf(len), len, MF_BYCOMMAND);
750 label.UngetWriteBuf();
751
752 return label;
2bda0e17
KB
753}
754
debe6624 755bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
2bda0e17 756{
c626a8b7
VZ
757 if (!m_menuBarFrame)
758 return TRUE;
2bda0e17 759
c626a8b7
VZ
760 if (RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION)) {
761 m_menus[pos]->m_hMenu = m_menus[pos]->m_savehMenu;
762 m_menus[pos]->m_savehMenu = 0;
2bda0e17 763
c626a8b7
VZ
764 if (m_menuBarFrame) {
765 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
766 }
2bda0e17 767
c626a8b7
VZ
768 return TRUE;
769 }
2bda0e17 770
c626a8b7 771 return FALSE;
2bda0e17
KB
772}
773
774bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title)
775{
c626a8b7
VZ
776 if (!a_menu->m_hMenu)
777 return FALSE;
2bda0e17 778
c626a8b7
VZ
779 if (!m_menuBarFrame)
780 return TRUE;
2bda0e17 781
c626a8b7
VZ
782 a_menu->m_savehMenu = a_menu->m_hMenu;
783 a_menu->m_hMenu = 0;
2bda0e17 784
c626a8b7 785 AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, (UINT)a_menu->m_savehMenu, title);
2bda0e17 786
c626a8b7 787 DrawMenuBar((HWND)m_menuBarFrame->GetHWND());
2bda0e17 788
c626a8b7 789 return TRUE;
2bda0e17
KB
790}
791
792void wxMenuBar::Append (wxMenu * menu, const wxString& title)
793{
c626a8b7
VZ
794 if (!OnAppend(menu, title))
795 return;
2bda0e17 796
c626a8b7
VZ
797 m_menuCount ++;
798 wxMenu **new_menus = new wxMenu *[m_menuCount];
799 wxString *new_titles = new wxString[m_menuCount];
800 int i;
2bda0e17 801
c626a8b7
VZ
802 for (i = 0; i < m_menuCount - 1; i++)
803 {
804 new_menus[i] = m_menus[i];
805 m_menus[i] = NULL;
806 new_titles[i] = m_titles[i];
807 m_titles[i] = "";
808 }
809 if (m_menus)
810 {
811 delete[]m_menus;
812 delete[]m_titles;
813 }
814 m_menus = new_menus;
815 m_titles = new_titles;
2bda0e17 816
c626a8b7
VZ
817 m_menus[m_menuCount - 1] = (wxMenu *)menu;
818 m_titles[m_menuCount - 1] = title;
2bda0e17 819
c626a8b7
VZ
820 ((wxMenu *)menu)->m_menuBar = (wxMenuBar *) this;
821 ((wxMenu *)menu)->SetParent(this);
2bda0e17
KB
822}
823
debe6624 824void wxMenuBar::Delete(wxMenu * menu, int i)
2bda0e17 825{
c626a8b7
VZ
826 int j;
827 int ii = (int) i;
828
829 if (menu != 0) {
830 for (ii = 0; ii < m_menuCount; ii++) {
831 if (m_menus[ii] == menu)
832 break;
833 }
834 if (ii >= m_menuCount)
835 return;
836 } else {
837 if (ii < 0 || ii >= m_menuCount)
838 return;
839 menu = m_menus[ii];
840 }
2bda0e17 841
c626a8b7
VZ
842 if (!OnDelete(menu, ii))
843 return;
2bda0e17 844
c626a8b7 845 menu->SetParent(NULL);
2bda0e17 846
c626a8b7
VZ
847 -- m_menuCount;
848 for (j = ii; j < m_menuCount; j++) {
849 m_menus[j] = m_menus[j + 1];
850 m_titles[j] = m_titles[j + 1];
851 }
2bda0e17
KB
852}
853
854// Find the menu menuString, item itemString, and return the item id.
855// Returns -1 if none found.
856int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemString) const
857{
c626a8b7
VZ
858 char buf1[200];
859 char buf2[200];
860 wxStripMenuCodes ((char *)(const char *)menuString, buf1);
861 int i;
862 for (i = 0; i < m_menuCount; i++)
2bda0e17 863 {
c626a8b7
VZ
864 wxStripMenuCodes ((char *)(const char *)m_titles[i], buf2);
865 if (strcmp (buf1, buf2) == 0)
866 return m_menus[i]->FindItem (itemString);
2bda0e17 867 }
c626a8b7 868 return -1;
2bda0e17
KB
869}
870
8cd85069 871wxMenuItem *wxMenuBar::FindItemForId (int id, wxMenu ** itemMenu) const
2bda0e17 872{
c626a8b7
VZ
873 if (itemMenu)
874 *itemMenu = NULL;
2bda0e17 875
c626a8b7
VZ
876 wxMenuItem *item = NULL;
877 int i;
878 for (i = 0; i < m_menuCount; i++)
879 {
8cd85069 880 item = m_menus[i]->FindItemForId (id, itemMenu);
c626a8b7
VZ
881 if (item)
882 return item;
883 }
884 return NULL;
2bda0e17
KB
885}
886
8cd85069 887void wxMenuBar::SetHelpString (int id, const wxString& helpString)
2bda0e17 888{
c626a8b7
VZ
889 int i;
890 for (i = 0; i < m_menuCount; i++)
2bda0e17 891 {
8cd85069 892 if (m_menus[i]->FindItemForId (id))
c626a8b7 893 {
8cd85069 894 m_menus[i]->SetHelpString (id, helpString);
c626a8b7
VZ
895 return;
896 }
2bda0e17
KB
897 }
898}
899
8cd85069 900wxString wxMenuBar::GetHelpString (int id) const
2bda0e17 901{
c626a8b7
VZ
902 wxString helpString;
903
904 for (int i = 0; i < m_menuCount; i++)
2bda0e17 905 {
8cd85069 906 wxMenuItem *item = m_menus[i]->FindItemForId(id);
c626a8b7
VZ
907 if ( item )
908 {
909 helpString = item->GetHelp();
910
911 break;
912 }
2bda0e17 913 }
c626a8b7
VZ
914
915 return helpString;
2bda0e17
KB
916}
917
c626a8b7
VZ
918// ----------------------------------------------------------------------------
919// helper functions
920// ----------------------------------------------------------------------------
921
2bda0e17 922wxWindow *wxMenu::GetWindow() const
c626a8b7
VZ
923{
924 if ( m_pInvokingWindow != NULL )
925 return m_pInvokingWindow;
926 else if ( m_menuBar != NULL)
927 return m_menuBar->m_menuBarFrame;
928
929 return NULL;
2bda0e17
KB
930}
931
932WXHMENU wxMenu::GetHMenu() const
933{
c626a8b7
VZ
934 if ( m_hMenu != 0 )
935 return m_hMenu;
936 else if ( m_savehMenu != 0 )
937 return m_savehMenu;
938
939 wxFAIL_MSG("wxMenu without HMENU");
2bda0e17 940
c626a8b7 941 return 0;
2bda0e17
KB
942}
943
c626a8b7
VZ
944// Update a menu and all submenus recursively. source is the object that has
945// the update event handlers defined for it. If NULL, the menu or associated
946// window will be used.
631f1bfe
JS
947void wxMenu::UpdateUI(wxEvtHandler* source)
948{
c626a8b7
VZ
949 if (!source && GetInvokingWindow())
950 source = GetInvokingWindow()->GetEventHandler();
951 if (!source)
952 source = GetEventHandler();
953 if (!source)
954 source = this;
955
956 wxNode* node = GetItems().First();
957 while (node)
631f1bfe 958 {
c626a8b7
VZ
959 wxMenuItem* item = (wxMenuItem*) node->Data();
960 if ( !item->IsSeparator() )
961 {
962 wxWindowID id = item->GetId();
963 wxUpdateUIEvent event(id);
964 event.SetEventObject( source );
965
966 if (source->ProcessEvent(event))
967 {
968 if (event.GetSetText())
969 SetLabel(id, event.GetText());
970 if (event.GetSetChecked())
971 Check(id, event.GetChecked());
972 if (event.GetSetEnabled())
973 Enable(id, event.GetEnabled());
974 }
975
976 if (item->GetSubMenu())
977 item->GetSubMenu()->UpdateUI(source);
978 }
979 node = node->Next();
980 }
631f1bfe 981}