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