]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menu.cpp
Added a constructor that allows creation of independent wxControl
[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"
717a57c2 36 #include "wx/log.h"
2bda0e17
KB
37#endif
38
47d67540 39#if wxUSE_OWNER_DRAWN
c626a8b7 40 #include "wx/ownerdrw.h"
2bda0e17
KB
41#endif
42
43#include "wx/msw/private.h"
2bda0e17
KB
44
45// other standard headers
2bda0e17
KB
46#include <string.h>
47
c626a8b7
VZ
48// ----------------------------------------------------------------------------
49// global variables
50// ----------------------------------------------------------------------------
51
52extern wxMenu *wxCurrentPopupMenu;
53
b8d3a4f1
VZ
54// ----------------------------------------------------------------------------
55// constants
56// ----------------------------------------------------------------------------
57
58// the (popup) menu title has this special id
59static const int idMenuTitle = -2;
60
61// ----------------------------------------------------------------------------
c626a8b7 62// macros
b8d3a4f1 63// ----------------------------------------------------------------------------
c626a8b7 64
c626a8b7
VZ
65 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
66 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
2bda0e17
KB
67
68// ============================================================================
69// implementation
70// ============================================================================
71
c2dcfdef
VZ
72// ---------------------------------------------------------------------------
73// wxMenu construction, adding and removing menu items
74// ---------------------------------------------------------------------------
2bda0e17
KB
75
76// Construct a menu with optional title (then use append)
717a57c2 77void wxMenu::Init()
c626a8b7 78{
ad9bb75f 79 m_doBreak = FALSE;
c626a8b7 80
717a57c2
VZ
81 // create the menu
82 m_hMenu = (WXHMENU)CreatePopupMenu();
83 if ( !m_hMenu )
84 {
85 wxLogLastError("CreatePopupMenu");
86 }
87
88 // if we have a title, insert it in the beginning of the menu
c626a8b7
VZ
89 if ( !!m_title )
90 {
ad9bb75f
VZ
91 Append(idMenuTitle, m_title);
92 AppendSeparator();
c626a8b7 93 }
2bda0e17
KB
94}
95
96// The wxWindow destructor will take care of deleting the submenus.
b8d3a4f1 97wxMenu::~wxMenu()
2bda0e17 98{
717a57c2
VZ
99 // we should free Windows resources only if Windows doesn't do it for us
100 // which happens if we're attached to a menubar or a submenu of another
101 // menu
102 if ( !IsAttached() && !GetParent() )
c2dcfdef 103 {
ad9bb75f
VZ
104 if ( !::DestroyMenu(GetHmenu()) )
105 {
106 wxLogLastError("DestroyMenu");
107 }
c2dcfdef 108 }
c626a8b7 109
ad9bb75f
VZ
110#if wxUSE_ACCEL
111 // delete accels
112 WX_CLEAR_ARRAY(m_accels);
113#endif // wxUSE_ACCEL
2bda0e17
KB
114}
115
b8d3a4f1 116void wxMenu::Break()
2bda0e17 117{
717a57c2 118 // this will take effect during the next call to Append()
c2dcfdef 119 m_doBreak = TRUE;
2bda0e17
KB
120}
121
717a57c2
VZ
122#if wxUSE_ACCEL
123
124int wxMenu::FindAccel(int id) const
125{
126 size_t n, count = m_accels.GetCount();
127 for ( n = 0; n < count; n++ )
128 {
129 if ( m_accels[n]->m_command == id )
130 return n;
131 }
132
133 return wxNOT_FOUND;
134}
135
136void wxMenu::UpdateAccel(wxMenuItem *item)
2bda0e17 137{
717a57c2
VZ
138 // find the (new) accel for this item
139 wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText());
140 if ( accel )
141 accel->m_command = item->GetId();
2bda0e17 142
717a57c2
VZ
143 // find the old one
144 int n = FindAccel(item->GetId());
145 if ( n == wxNOT_FOUND )
146 {
147 // no old, add new if any
148 if ( accel )
149 m_accels.Add(accel);
150 else
151 return; // skipping RebuildAccelTable() below
152 }
153 else
154 {
155 // replace old with new or just remove the old one if no new
156 delete m_accels[n];
157 if ( accel )
158 m_accels[n] = accel;
159 else
160 m_accels.Remove(n);
161 }
162
163 if ( IsAttached() )
164 {
165 m_menuBar->RebuildAccelTable();
42e69d6b 166 }
717a57c2
VZ
167}
168
169#endif // wxUSE_ACCEL
170
171// append a new item or submenu to the menu
172bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
173{
174#if wxUSE_ACCEL
175 UpdateAccel(pItem);
d427503c 176#endif // wxUSE_ACCEL
42e69d6b 177
c626a8b7 178 UINT flags = 0;
2bda0e17 179
c2dcfdef
VZ
180 // if "Break" has just been called, insert a menu break before this item
181 // (and don't forget to reset the flag)
c626a8b7
VZ
182 if ( m_doBreak ) {
183 flags |= MF_MENUBREAK;
184 m_doBreak = FALSE;
185 }
186
187 if ( pItem->IsSeparator() ) {
188 flags |= MF_SEPARATOR;
189 }
2bda0e17 190
c2dcfdef
VZ
191 // id is the numeric id for normal menu items and HMENU for submenus as
192 // required by ::AppendMenu() API
c626a8b7 193 UINT id;
c2dcfdef
VZ
194 wxMenu *submenu = pItem->GetSubMenu();
195 if ( submenu != NULL ) {
717a57c2
VZ
196 wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") );
197
198 submenu->SetParent(this);
2bda0e17 199
c2dcfdef 200 id = (UINT)submenu->GetHMenu();
2bda0e17 201
c626a8b7
VZ
202 flags |= MF_POPUP;
203 }
204 else {
205 id = pItem->GetId();
206 }
2bda0e17 207
837e5743 208 LPCTSTR pData;
2bda0e17 209
47d67540 210#if wxUSE_OWNER_DRAWN
c626a8b7
VZ
211 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
212 // item draws itself, pass pointer to it in data parameter
213 flags |= MF_OWNERDRAW;
837e5743 214 pData = (LPCTSTR)pItem;
c626a8b7
VZ
215 }
216 else
2bda0e17 217#endif
c626a8b7
VZ
218 {
219 // menu is just a normal string (passed in data parameter)
220 flags |= MF_STRING;
8fb3a512 221
974e8d94 222 pData = (char*)pItem->GetText().c_str();
c626a8b7 223 }
2bda0e17 224
717a57c2
VZ
225 BOOL ok;
226 if ( pos == (size_t)-1 )
227 {
228 ok = ::AppendMenu(GetHmenu(), flags, id, pData);
229 }
230 else
231 {
232 ok = ::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData);
233 }
234
235 if ( !ok )
c626a8b7 236 {
717a57c2
VZ
237 wxLogLastError("Insert or AppendMenu");
238
239 return FALSE;
c626a8b7 240 }
c2dcfdef
VZ
241 else
242 {
717a57c2 243 // if we just appended the title, highlight it
42e69d6b 244#ifdef __WIN32__
a17e237f 245 if ( (int)id == idMenuTitle )
42e69d6b
VZ
246 {
247 // visually select the menu title
248 MENUITEMINFO mii;
249 mii.cbSize = sizeof(mii);
250 mii.fMask = MIIM_STATE;
251 mii.fState = MFS_DEFAULT;
252
c50f1fb9 253 if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
42e69d6b 254 {
223d09f6 255 wxLogLastError(wxT("SetMenuItemInfo"));
42e69d6b
VZ
256 }
257 }
258#endif // __WIN32__
259
717a57c2
VZ
260 // if we're already attached to the menubar, we must update it
261 if ( IsAttached() )
262 {
263 m_menuBar->Refresh();
264 }
2bda0e17 265
717a57c2
VZ
266 return TRUE;
267 }
2bda0e17
KB
268}
269
717a57c2 270bool wxMenu::DoAppend(wxMenuItem *item)
2bda0e17 271{
717a57c2 272 return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
2bda0e17
KB
273}
274
717a57c2 275bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
2bda0e17 276{
717a57c2 277 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
2bda0e17
KB
278}
279
717a57c2 280wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
2bda0e17 281{
717a57c2
VZ
282 // we need to find the items position in the child list
283 size_t pos;
284 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
285 for ( pos = 0; node; pos++ )
c626a8b7 286 {
717a57c2 287 if ( node->GetData() == item )
c626a8b7 288 break;
717a57c2
VZ
289
290 node = node->GetNext();
c626a8b7
VZ
291 }
292
717a57c2
VZ
293 // DoRemove() (unlike Remove) can only be called for existing item!
294 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
c626a8b7 295
717a57c2
VZ
296#if wxUSE_ACCEL
297 // remove the corresponding accel from the accel table
298 int n = FindAccel(item->GetId());
299 if ( n != wxNOT_FOUND )
300 {
301 delete m_accels[n];
c626a8b7 302
717a57c2 303 m_accels.Remove(n);
c626a8b7 304 }
717a57c2
VZ
305 //else: this item doesn't have an accel, nothing to do
306#endif // wxUSE_ACCEL
307
308 // remove the item from the menu
309 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
310 {
311 wxLogLastError("RemoveMenu");
c626a8b7
VZ
312 }
313
717a57c2
VZ
314 if ( IsAttached() )
315 {
316 // otherwise, the chane won't be visible
317 m_menuBar->Refresh();
318 }
2bda0e17 319
717a57c2
VZ
320 // and from internal data structures
321 return wxMenuBase::DoRemove(item);
322}
d427503c 323
42e69d6b
VZ
324// ---------------------------------------------------------------------------
325// accelerator helpers
326// ---------------------------------------------------------------------------
327
717a57c2
VZ
328#if wxUSE_ACCEL
329
42e69d6b
VZ
330// create the wxAcceleratorEntries for our accels and put them into provided
331// array - return the number of accels we have
332size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
333{
334 size_t count = GetAccelCount();
335 for ( size_t n = 0; n < count; n++ )
336 {
974e8d94 337 *accels++ = *m_accels[n];
42e69d6b
VZ
338 }
339
340 return count;
341}
342
d427503c
VZ
343#endif // wxUSE_ACCEL
344
c2dcfdef 345// ---------------------------------------------------------------------------
717a57c2 346// set wxMenu title
c2dcfdef
VZ
347// ---------------------------------------------------------------------------
348
2bda0e17
KB
349void wxMenu::SetTitle(const wxString& label)
350{
c626a8b7
VZ
351 bool hasNoTitle = m_title.IsEmpty();
352 m_title = label;
b8d3a4f1 353
c50f1fb9 354 HMENU hMenu = GetHmenu();
b8d3a4f1 355
c626a8b7 356 if ( hasNoTitle )
b8d3a4f1 357 {
c626a8b7
VZ
358 if ( !label.IsEmpty() )
359 {
717a57c2
VZ
360 if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
361 (unsigned)idMenuTitle, m_title) ||
362 !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
c626a8b7 363 {
717a57c2 364 wxLogLastError("InsertMenu");
c626a8b7
VZ
365 }
366 }
b8d3a4f1
VZ
367 }
368 else
369 {
c626a8b7
VZ
370 if ( label.IsEmpty() )
371 {
372 // remove the title and the separator after it
373 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
374 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
375 {
376 wxLogLastError("RemoveMenu");
377 }
378 }
379 else
380 {
381 // modify the title
382 if ( !ModifyMenu(hMenu, 0u,
717a57c2
VZ
383 MF_BYPOSITION | MF_STRING,
384 (unsigned)idMenuTitle, m_title) )
c626a8b7
VZ
385 {
386 wxLogLastError("ModifyMenu");
387 }
388 }
b8d3a4f1 389 }
b8d3a4f1 390
42e69d6b 391#ifdef __WIN32__
c626a8b7
VZ
392 // put the title string in bold face
393 if ( !m_title.IsEmpty() )
a3f4e9e8 394 {
c626a8b7
VZ
395 MENUITEMINFO mii;
396 mii.cbSize = sizeof(mii);
397 mii.fMask = MIIM_STATE;
398 mii.fState = MFS_DEFAULT;
399
400 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
401 {
402 wxLogLastError("SetMenuItemInfo");
403 }
a3f4e9e8 404 }
717a57c2 405#endif // Win32
2bda0e17
KB
406}
407
c2dcfdef
VZ
408// ---------------------------------------------------------------------------
409// event processing
410// ---------------------------------------------------------------------------
2bda0e17 411
debe6624 412bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
2bda0e17 413{
a3f4e9e8
VZ
414 // ignore commands from the menu title
415
416 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
417 if ( id != (WXWORD)idMenuTitle )
418 {
419 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
420 event.SetEventObject( this );
421 event.SetId( id );
422 event.SetInt( id );
423 ProcessCommand(event);
424 }
425
426 return TRUE;
2bda0e17
KB
427}
428
42e69d6b 429bool wxMenu::ProcessCommand(wxCommandEvent & event)
c2dcfdef
VZ
430{
431 bool processed = FALSE;
432
9739d9ee 433#if wxUSE_MENU_CALLBACK
c2dcfdef
VZ
434 // Try a callback
435 if (m_callback)
436 {
437 (void)(*(m_callback))(*this, event);
438 processed = TRUE;
439 }
9739d9ee 440#endif // wxUSE_MENU_CALLBACK
c2dcfdef
VZ
441
442 // Try the menu's event handler
443 if ( !processed && GetEventHandler())
444 {
445 processed = GetEventHandler()->ProcessEvent(event);
446 }
447
448 // Try the window the menu was popped up from (and up through the
449 // hierarchy)
450 wxWindow *win = GetInvokingWindow();
451 if ( !processed && win )
452 processed = win->GetEventHandler()->ProcessEvent(event);
42e69d6b
VZ
453
454 return processed;
c2dcfdef
VZ
455}
456
c2dcfdef
VZ
457// ---------------------------------------------------------------------------
458// other
459// ---------------------------------------------------------------------------
2bda0e17 460
c2dcfdef
VZ
461void wxMenu::Attach(wxMenuBar *menubar)
462{
463 // menu can be in at most one menubar because otherwise they would both
464 // delete the menu pointer
223d09f6 465 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
c2dcfdef
VZ
466
467 m_menuBar = menubar;
c2dcfdef
VZ
468}
469
470void wxMenu::Detach()
471{
223d09f6 472 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
c2dcfdef 473
ad9bb75f 474 m_menuBar = NULL;
717a57c2
VZ
475}
476
477wxWindow *wxMenu::GetWindow() const
478{
479 if ( m_invokingWindow != NULL )
480 return m_invokingWindow;
481 else if ( m_menuBar != NULL)
482 return m_menuBar->GetFrame();
483
484 return NULL;
c2dcfdef
VZ
485}
486
487// ---------------------------------------------------------------------------
2bda0e17 488// Menu Bar
c2dcfdef
VZ
489// ---------------------------------------------------------------------------
490
491void wxMenuBar::Init()
2bda0e17 492{
c626a8b7 493 m_eventHandler = this;
c626a8b7
VZ
494 m_menuBarFrame = NULL;
495 m_hMenu = 0;
cba2db0c 496}
2bda0e17 497
c2dcfdef
VZ
498wxMenuBar::wxMenuBar()
499{
500 Init();
501}
502
cba2db0c
JS
503wxMenuBar::wxMenuBar( long WXUNUSED(style) )
504{
c2dcfdef 505 Init();
2bda0e17
KB
506}
507
c2dcfdef 508wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
2bda0e17 509{
c2dcfdef
VZ
510 Init();
511
a8cfd0cb 512 m_titles.Alloc(count);
c2dcfdef 513
a8cfd0cb
VZ
514 for ( int i = 0; i < count; i++ )
515 {
516 m_menus.Append(menus[i]);
517 m_titles.Add(titles[i]);
2bda0e17 518
a8cfd0cb
VZ
519 menus[i]->Attach(this);
520 }
2bda0e17
KB
521}
522
b8d3a4f1 523wxMenuBar::~wxMenuBar()
2bda0e17 524{
c2dcfdef 525}
2bda0e17 526
c2dcfdef
VZ
527// ---------------------------------------------------------------------------
528// wxMenuBar helpers
529// ---------------------------------------------------------------------------
530
531void wxMenuBar::Refresh()
532{
065de612 533 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
c2dcfdef 534
ad9bb75f 535 DrawMenuBar(GetHwndOf(m_menuBarFrame));
c2dcfdef
VZ
536}
537
538WXHMENU wxMenuBar::Create()
539{
1cf27c63 540 if (m_hMenu != 0 )
717a57c2 541 return m_hMenu;
1cf27c63 542
223d09f6 543 wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") );
c2dcfdef
VZ
544
545 m_hMenu = (WXHMENU)::CreateMenu();
2bda0e17 546
c2dcfdef 547 if ( !m_hMenu )
c626a8b7 548 {
c2dcfdef 549 wxLogLastError("CreateMenu");
c626a8b7 550 }
c2dcfdef 551 else
c626a8b7 552 {
a8cfd0cb
VZ
553 size_t count = GetMenuCount();
554 for ( size_t i = 0; i < count; i++ )
c2dcfdef
VZ
555 {
556 if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
557 (UINT)m_menus[i]->GetHMenu(),
558 m_titles[i]) )
559 {
560 wxLogLastError("AppendMenu");
561 }
562 }
c626a8b7 563 }
c626a8b7 564
c2dcfdef 565 return m_hMenu;
2bda0e17
KB
566}
567
c2dcfdef 568// ---------------------------------------------------------------------------
3dfac970 569// wxMenuBar functions to work with the top level submenus
c2dcfdef
VZ
570// ---------------------------------------------------------------------------
571
3dfac970
VZ
572// NB: we don't support owner drawn top level items for now, if we do these
573// functions would have to be changed to use wxMenuItem as well
2bda0e17 574
a8cfd0cb 575void wxMenuBar::EnableTop(size_t pos, bool enable)
2bda0e17 576{
717a57c2
VZ
577 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
578
579 int flag = enable ? MF_ENABLED : MF_GRAYED;
2bda0e17 580
c626a8b7 581 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
adc6fb16
VZ
582
583 Refresh();
2bda0e17
KB
584}
585
a8cfd0cb 586void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
2bda0e17 587{
717a57c2
VZ
588 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
589
590 m_titles[pos] = label;
591
592 if ( !IsAttached() )
593 {
594 return;
595 }
596 //else: have to modify the existing menu
597
8cd85069 598 UINT id;
c2dcfdef
VZ
599 UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
600 if ( flagsOld == 0xFFFFFFFF )
c626a8b7 601 {
223d09f6 602 wxLogLastError(wxT("GetMenuState"));
c2dcfdef
VZ
603
604 return;
605 }
606
607 if ( flagsOld & MF_POPUP )
608 {
609 // HIBYTE contains the number of items in the submenu in this case
ad9bb75f
VZ
610 flagsOld &= 0xff;
611 id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos);
c626a8b7
VZ
612 }
613 else
8cd85069
VZ
614 {
615 id = pos;
616 }
617
c50f1fb9 618 if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
a17e237f 619 id, label) == (int)0xFFFFFFFF )
c2dcfdef
VZ
620 {
621 wxLogLastError("ModifyMenu");
622 }
717a57c2
VZ
623
624 Refresh();
2bda0e17
KB
625}
626
a8cfd0cb 627wxString wxMenuBar::GetLabelTop(size_t pos) const
2bda0e17 628{
717a57c2
VZ
629 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
630 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
8cd85069 631
717a57c2 632 return m_titles[pos];
2bda0e17
KB
633}
634
1cf27c63
UM
635int wxMenuBar::FindMenu(const wxString& title)
636{
637 wxString menuTitle = wxStripMenuCodes(title);
a8cfd0cb
VZ
638
639 size_t count = GetMenuCount();
640 for ( size_t i = 0; i < count; i++ )
1cf27c63
UM
641 {
642 wxString title = wxStripMenuCodes(m_titles[i]);
643 if ( menuTitle == title )
644 return i;
645 }
646
647 return wxNOT_FOUND;
648
649}
650
ad9bb75f
VZ
651// ---------------------------------------------------------------------------
652// wxMenuBar construction
653// ---------------------------------------------------------------------------
654
a8cfd0cb 655wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
1cf27c63 656{
ad9bb75f
VZ
657 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
658 if ( !menuOld )
659 return FALSE;
660 m_titles[pos] = title;
a8cfd0cb 661
ad9bb75f 662 if ( IsAttached() )
a8cfd0cb 663 {
ad9bb75f
VZ
664 // can't use ModifyMenu() because it deletes the submenu it replaces
665 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
a8cfd0cb 666 {
ad9bb75f 667 wxLogLastError("RemoveMenu");
a8cfd0cb 668 }
1cf27c63 669
ad9bb75f
VZ
670 if ( !::InsertMenu(GetHmenu(), (UINT)pos,
671 MF_BYPOSITION | MF_POPUP | MF_STRING,
672 (UINT)GetHmenuOf(menu), title) )
673 {
674 wxLogLastError("InsertMenu");
675 }
676
717a57c2
VZ
677#if wxUSE_ACCEL
678 if ( menuOld->HasAccels() || menu->HasAccels() )
679 {
680 // need to rebuild accell table
681 RebuildAccelTable();
682 }
683#endif // wxUSE_ACCEL
684
ad9bb75f 685 Refresh();
a8cfd0cb 686 }
ad9bb75f
VZ
687
688 return menuOld;
1cf27c63
UM
689}
690
a8cfd0cb 691bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
1cf27c63 692{
ad9bb75f 693 if ( !wxMenuBarBase::Insert(pos, menu, title) )
a8cfd0cb 694 return FALSE;
1cf27c63 695
ad9bb75f
VZ
696 m_titles.Insert(title, pos);
697
698 menu->Attach(this);
1cf27c63 699
ad9bb75f
VZ
700 if ( IsAttached() )
701 {
702 if ( !::InsertMenu(GetHmenu(), pos,
703 MF_BYPOSITION | MF_POPUP | MF_STRING,
704 (UINT)GetHmenuOf(menu), title) )
705 {
706 wxLogLastError("InsertMenu");
707 }
708
717a57c2
VZ
709#if wxUSE_ACCEL
710 if ( menu->HasAccels() )
711 {
712 // need to rebuild accell table
713 RebuildAccelTable();
714 }
715#endif // wxUSE_ACCEL
716
ad9bb75f 717 Refresh();
a8cfd0cb 718 }
ad9bb75f
VZ
719
720 return TRUE;
1cf27c63
UM
721}
722
ad9bb75f 723bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
2bda0e17 724{
ad9bb75f
VZ
725 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
726 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
2bda0e17 727
717a57c2
VZ
728 if ( !wxMenuBarBase::Append(menu, title) )
729 return FALSE;
730
ad9bb75f 731 menu->Attach(this);
2bda0e17 732
717a57c2
VZ
733 m_titles.Add(title);
734
ad9bb75f
VZ
735 if ( IsAttached() )
736 {
737 if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
738 (UINT)submenu, title) )
739 {
740 wxLogLastError(wxT("AppendMenu"));
741 }
742
717a57c2
VZ
743#if wxUSE_ACCEL
744 if ( menu->HasAccels() )
745 {
746 // need to rebuild accell table
747 RebuildAccelTable();
748 }
749#endif // wxUSE_ACCEL
750
ad9bb75f
VZ
751 Refresh();
752 }
2bda0e17 753
a8cfd0cb 754 return TRUE;
2bda0e17
KB
755}
756
a8cfd0cb 757wxMenu *wxMenuBar::Remove(size_t pos)
2bda0e17 758{
a8cfd0cb
VZ
759 wxMenu *menu = wxMenuBarBase::Remove(pos);
760 if ( !menu )
761 return NULL;
c626a8b7 762
ad9bb75f
VZ
763 if ( IsAttached() )
764 {
765 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
766 {
767 wxLogLastError("RemoveMenu");
768 }
2bda0e17 769
ad9bb75f
VZ
770 menu->Detach();
771
717a57c2
VZ
772#if wxUSE_ACCEL
773 if ( menu->HasAccels() )
774 {
775 // need to rebuild accell table
776 RebuildAccelTable();
777 }
778#endif // wxUSE_ACCEL
779
ad9bb75f
VZ
780 Refresh();
781 }
2bda0e17 782
a8cfd0cb 783 m_titles.Remove(pos);
2bda0e17 784
a8cfd0cb 785 return menu;
2bda0e17
KB
786}
787
d427503c 788#if wxUSE_ACCEL
717a57c2
VZ
789
790void wxMenuBar::RebuildAccelTable()
791{
792 // merge the accelerators of all menus into one accel table
42e69d6b 793 size_t nAccelCount = 0;
a8cfd0cb
VZ
794 size_t i, count = GetMenuCount();
795 for ( i = 0; i < count; i++ )
42e69d6b
VZ
796 {
797 nAccelCount += m_menus[i]->GetAccelCount();
798 }
799
5df1250b 800 if ( nAccelCount )
42e69d6b 801 {
5df1250b 802 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
42e69d6b 803
5df1250b 804 nAccelCount = 0;
a8cfd0cb 805 for ( i = 0; i < count; i++ )
5df1250b
VZ
806 {
807 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
808 }
809
810 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
42e69d6b 811
5df1250b
VZ
812 delete [] accelEntries;
813 }
717a57c2
VZ
814}
815
816#endif // wxUSE_ACCEL
817
818void wxMenuBar::Attach(wxFrame *frame)
819{
065de612 820// wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
717a57c2
VZ
821
822 m_menuBarFrame = frame;
823
824#if wxUSE_ACCEL
825 RebuildAccelTable();
d427503c 826#endif // wxUSE_ACCEL
42e69d6b
VZ
827}
828
1cf27c63
UM
829void wxMenuBar::Detach()
830{
831// ::DestroyMenu((HMENU)m_hMenu);
a17e237f 832 m_hMenu = (WXHMENU)NULL;
1cf27c63
UM
833 m_menuBarFrame = NULL;
834}
835
836
c2dcfdef
VZ
837// ---------------------------------------------------------------------------
838// wxMenuBar searching for menu items
839// ---------------------------------------------------------------------------
840
841// Find the itemString in menuString, and return the item id or wxNOT_FOUND
842int wxMenuBar::FindMenuItem(const wxString& menuString,
843 const wxString& itemString) const
2bda0e17 844{
c2dcfdef 845 wxString menuLabel = wxStripMenuCodes(menuString);
a8cfd0cb
VZ
846 size_t count = GetMenuCount();
847 for ( size_t i = 0; i < count; i++ )
2bda0e17 848 {
c2dcfdef
VZ
849 wxString title = wxStripMenuCodes(m_titles[i]);
850 if ( menuString == title )
851 return m_menus[i]->FindItem(itemString);
2bda0e17 852 }
c2dcfdef
VZ
853
854 return wxNOT_FOUND;
2bda0e17
KB
855}
856
a8cfd0cb 857wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
2bda0e17 858{
c2dcfdef 859 if ( itemMenu )
c626a8b7 860 *itemMenu = NULL;
2bda0e17 861
c626a8b7 862 wxMenuItem *item = NULL;
a8cfd0cb
VZ
863 size_t count = GetMenuCount();
864 for ( size_t i = 0; !item && (i < count); i++ )
c626a8b7 865 {
dd60b9ec 866 item = m_menus[i]->FindItem(id, itemMenu);
c626a8b7 867 }
2bda0e17 868
c2dcfdef 869 return item;
2bda0e17
KB
870}
871