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