]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menu.cpp
Added a file
[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
1e6feb95
VZ
31#if wxUSE_MENUS
32
2bda0e17 33#ifndef WX_PRECOMP
c626a8b7
VZ
34 #include "wx/frame.h"
35 #include "wx/menu.h"
36 #include "wx/utils.h"
0c589ad0 37 #include "wx/intl.h"
717a57c2 38 #include "wx/log.h"
2bda0e17
KB
39#endif
40
47d67540 41#if wxUSE_OWNER_DRAWN
c626a8b7 42 #include "wx/ownerdrw.h"
2bda0e17
KB
43#endif
44
45#include "wx/msw/private.h"
2bda0e17
KB
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
641f5461
VZ
67IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
68IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
2bda0e17
KB
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 {
f6bcfd97 87 wxLogLastError(wxT("CreatePopupMenu"));
717a57c2
VZ
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 {
f6bcfd97 108 wxLogLastError(wxT("DestroyMenu"));
ad9bb75f 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{
f6bcfd97 140 if ( item->IsSubMenu() )
717a57c2 141 {
f6bcfd97
BP
142 wxMenu *submenu = item->GetSubMenu();
143 wxMenuItemList::Node *node = submenu->GetMenuItems().GetFirst();
144 while ( node )
145 {
146 UpdateAccel(node->GetData());
147
148 node = node->GetNext();
149 }
717a57c2 150 }
f6bcfd97 151 else if ( !item->IsSeparator() )
717a57c2 152 {
f6bcfd97
BP
153 // find the (new) accel for this item
154 wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText());
717a57c2 155 if ( accel )
f6bcfd97
BP
156 accel->m_command = item->GetId();
157
158 // find the old one
159 int n = FindAccel(item->GetId());
160 if ( n == wxNOT_FOUND )
161 {
162 // no old, add new if any
163 if ( accel )
164 m_accels.Add(accel);
165 else
166 return; // skipping RebuildAccelTable() below
167 }
717a57c2 168 else
f6bcfd97
BP
169 {
170 // replace old with new or just remove the old one if no new
171 delete m_accels[n];
172 if ( accel )
173 m_accels[n] = accel;
174 else
175 m_accels.Remove(n);
176 }
717a57c2 177
f6bcfd97
BP
178 if ( IsAttached() )
179 {
180 m_menuBar->RebuildAccelTable();
181 }
42e69d6b 182 }
f6bcfd97 183 //else: it is a separator, they can't have accels, nothing to do
717a57c2
VZ
184}
185
186#endif // wxUSE_ACCEL
187
188// append a new item or submenu to the menu
189bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
190{
191#if wxUSE_ACCEL
192 UpdateAccel(pItem);
d427503c 193#endif // wxUSE_ACCEL
42e69d6b 194
c626a8b7 195 UINT flags = 0;
2bda0e17 196
c2dcfdef
VZ
197 // if "Break" has just been called, insert a menu break before this item
198 // (and don't forget to reset the flag)
c626a8b7
VZ
199 if ( m_doBreak ) {
200 flags |= MF_MENUBREAK;
201 m_doBreak = FALSE;
202 }
203
204 if ( pItem->IsSeparator() ) {
205 flags |= MF_SEPARATOR;
206 }
2bda0e17 207
c2dcfdef
VZ
208 // id is the numeric id for normal menu items and HMENU for submenus as
209 // required by ::AppendMenu() API
c626a8b7 210 UINT id;
c2dcfdef
VZ
211 wxMenu *submenu = pItem->GetSubMenu();
212 if ( submenu != NULL ) {
717a57c2
VZ
213 wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") );
214
215 submenu->SetParent(this);
2bda0e17 216
c2dcfdef 217 id = (UINT)submenu->GetHMenu();
2bda0e17 218
c626a8b7
VZ
219 flags |= MF_POPUP;
220 }
221 else {
222 id = pItem->GetId();
223 }
2bda0e17 224
837e5743 225 LPCTSTR pData;
2bda0e17 226
47d67540 227#if wxUSE_OWNER_DRAWN
c626a8b7
VZ
228 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
229 // item draws itself, pass pointer to it in data parameter
230 flags |= MF_OWNERDRAW;
837e5743 231 pData = (LPCTSTR)pItem;
c626a8b7
VZ
232 }
233 else
2bda0e17 234#endif
c626a8b7
VZ
235 {
236 // menu is just a normal string (passed in data parameter)
237 flags |= MF_STRING;
8fb3a512 238
f5166ed4 239 pData = (wxChar*)pItem->GetText().c_str();
c626a8b7 240 }
2bda0e17 241
717a57c2
VZ
242 BOOL ok;
243 if ( pos == (size_t)-1 )
244 {
245 ok = ::AppendMenu(GetHmenu(), flags, id, pData);
246 }
247 else
248 {
249 ok = ::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData);
250 }
251
252 if ( !ok )
c626a8b7 253 {
f6bcfd97 254 wxLogLastError(wxT("Insert or AppendMenu"));
717a57c2
VZ
255
256 return FALSE;
c626a8b7 257 }
c2dcfdef
VZ
258 else
259 {
717a57c2 260 // if we just appended the title, highlight it
42e69d6b 261#ifdef __WIN32__
a17e237f 262 if ( (int)id == idMenuTitle )
42e69d6b
VZ
263 {
264 // visually select the menu title
265 MENUITEMINFO mii;
266 mii.cbSize = sizeof(mii);
267 mii.fMask = MIIM_STATE;
268 mii.fState = MFS_DEFAULT;
269
c50f1fb9 270 if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
42e69d6b 271 {
223d09f6 272 wxLogLastError(wxT("SetMenuItemInfo"));
42e69d6b
VZ
273 }
274 }
275#endif // __WIN32__
276
717a57c2 277 // if we're already attached to the menubar, we must update it
4bc1afd5 278 if ( IsAttached() && m_menuBar->IsAttached() )
717a57c2
VZ
279 {
280 m_menuBar->Refresh();
281 }
2bda0e17 282
717a57c2
VZ
283 return TRUE;
284 }
2bda0e17
KB
285}
286
717a57c2 287bool wxMenu::DoAppend(wxMenuItem *item)
2bda0e17 288{
717a57c2 289 return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
2bda0e17
KB
290}
291
717a57c2 292bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
2bda0e17 293{
717a57c2 294 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
2bda0e17
KB
295}
296
717a57c2 297wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
2bda0e17 298{
717a57c2
VZ
299 // we need to find the items position in the child list
300 size_t pos;
301 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
302 for ( pos = 0; node; pos++ )
c626a8b7 303 {
717a57c2 304 if ( node->GetData() == item )
c626a8b7 305 break;
717a57c2
VZ
306
307 node = node->GetNext();
c626a8b7
VZ
308 }
309
717a57c2
VZ
310 // DoRemove() (unlike Remove) can only be called for existing item!
311 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
c626a8b7 312
717a57c2
VZ
313#if wxUSE_ACCEL
314 // remove the corresponding accel from the accel table
315 int n = FindAccel(item->GetId());
316 if ( n != wxNOT_FOUND )
317 {
318 delete m_accels[n];
c626a8b7 319
717a57c2 320 m_accels.Remove(n);
c626a8b7 321 }
717a57c2
VZ
322 //else: this item doesn't have an accel, nothing to do
323#endif // wxUSE_ACCEL
324
325 // remove the item from the menu
326 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
327 {
f6bcfd97 328 wxLogLastError(wxT("RemoveMenu"));
c626a8b7
VZ
329 }
330
4bc1afd5 331 if ( IsAttached() && m_menuBar->IsAttached() )
717a57c2
VZ
332 {
333 // otherwise, the chane won't be visible
334 m_menuBar->Refresh();
335 }
2bda0e17 336
717a57c2
VZ
337 // and from internal data structures
338 return wxMenuBase::DoRemove(item);
339}
d427503c 340
42e69d6b
VZ
341// ---------------------------------------------------------------------------
342// accelerator helpers
343// ---------------------------------------------------------------------------
344
717a57c2
VZ
345#if wxUSE_ACCEL
346
42e69d6b
VZ
347// create the wxAcceleratorEntries for our accels and put them into provided
348// array - return the number of accels we have
349size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
350{
351 size_t count = GetAccelCount();
352 for ( size_t n = 0; n < count; n++ )
353 {
974e8d94 354 *accels++ = *m_accels[n];
42e69d6b
VZ
355 }
356
357 return count;
358}
359
d427503c
VZ
360#endif // wxUSE_ACCEL
361
c2dcfdef 362// ---------------------------------------------------------------------------
717a57c2 363// set wxMenu title
c2dcfdef
VZ
364// ---------------------------------------------------------------------------
365
2bda0e17
KB
366void wxMenu::SetTitle(const wxString& label)
367{
c626a8b7
VZ
368 bool hasNoTitle = m_title.IsEmpty();
369 m_title = label;
b8d3a4f1 370
c50f1fb9 371 HMENU hMenu = GetHmenu();
b8d3a4f1 372
c626a8b7 373 if ( hasNoTitle )
b8d3a4f1 374 {
c626a8b7
VZ
375 if ( !label.IsEmpty() )
376 {
717a57c2
VZ
377 if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
378 (unsigned)idMenuTitle, m_title) ||
379 !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
c626a8b7 380 {
f6bcfd97 381 wxLogLastError(wxT("InsertMenu"));
c626a8b7
VZ
382 }
383 }
b8d3a4f1
VZ
384 }
385 else
386 {
c626a8b7
VZ
387 if ( label.IsEmpty() )
388 {
389 // remove the title and the separator after it
390 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
391 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
392 {
f6bcfd97 393 wxLogLastError(wxT("RemoveMenu"));
c626a8b7
VZ
394 }
395 }
396 else
397 {
398 // modify the title
399 if ( !ModifyMenu(hMenu, 0u,
717a57c2
VZ
400 MF_BYPOSITION | MF_STRING,
401 (unsigned)idMenuTitle, m_title) )
c626a8b7 402 {
f6bcfd97 403 wxLogLastError(wxT("ModifyMenu"));
c626a8b7
VZ
404 }
405 }
b8d3a4f1 406 }
b8d3a4f1 407
42e69d6b 408#ifdef __WIN32__
c626a8b7
VZ
409 // put the title string in bold face
410 if ( !m_title.IsEmpty() )
a3f4e9e8 411 {
c626a8b7
VZ
412 MENUITEMINFO mii;
413 mii.cbSize = sizeof(mii);
414 mii.fMask = MIIM_STATE;
415 mii.fState = MFS_DEFAULT;
416
417 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
418 {
f6bcfd97 419 wxLogLastError(wxT("SetMenuItemInfo"));
c626a8b7 420 }
a3f4e9e8 421 }
717a57c2 422#endif // Win32
2bda0e17
KB
423}
424
c2dcfdef
VZ
425// ---------------------------------------------------------------------------
426// event processing
427// ---------------------------------------------------------------------------
2bda0e17 428
debe6624 429bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
2bda0e17 430{
a3f4e9e8
VZ
431 // ignore commands from the menu title
432
433 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
434 if ( id != (WXWORD)idMenuTitle )
435 {
3ca6a5f0
BP
436 // VZ: previosuly, the command int was set to id too which was quite
437 // useless anyhow (as it could be retrieved using GetId()) and
438 // uncompatible with wxGTK, so now we use the command int instead
439 // to pass the checked status
1e6feb95 440 SendEvent(id, ::GetMenuState(GetHmenu(), id, MF_BYCOMMAND) & MF_CHECKED);
a3f4e9e8
VZ
441 }
442
443 return TRUE;
2bda0e17
KB
444}
445
c2dcfdef
VZ
446// ---------------------------------------------------------------------------
447// other
448// ---------------------------------------------------------------------------
2bda0e17 449
717a57c2
VZ
450wxWindow *wxMenu::GetWindow() const
451{
452 if ( m_invokingWindow != NULL )
453 return m_invokingWindow;
454 else if ( m_menuBar != NULL)
455 return m_menuBar->GetFrame();
456
457 return NULL;
c2dcfdef
VZ
458}
459
460// ---------------------------------------------------------------------------
2bda0e17 461// Menu Bar
c2dcfdef
VZ
462// ---------------------------------------------------------------------------
463
464void wxMenuBar::Init()
2bda0e17 465{
c626a8b7 466 m_eventHandler = this;
c626a8b7 467 m_hMenu = 0;
cba2db0c 468}
2bda0e17 469
c2dcfdef
VZ
470wxMenuBar::wxMenuBar()
471{
472 Init();
473}
474
cba2db0c
JS
475wxMenuBar::wxMenuBar( long WXUNUSED(style) )
476{
c2dcfdef 477 Init();
2bda0e17
KB
478}
479
c2dcfdef 480wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
2bda0e17 481{
c2dcfdef
VZ
482 Init();
483
a8cfd0cb 484 m_titles.Alloc(count);
c2dcfdef 485
a8cfd0cb
VZ
486 for ( int i = 0; i < count; i++ )
487 {
488 m_menus.Append(menus[i]);
489 m_titles.Add(titles[i]);
2bda0e17 490
a8cfd0cb
VZ
491 menus[i]->Attach(this);
492 }
2bda0e17
KB
493}
494
b8d3a4f1 495wxMenuBar::~wxMenuBar()
2bda0e17 496{
c2dcfdef 497}
2bda0e17 498
c2dcfdef
VZ
499// ---------------------------------------------------------------------------
500// wxMenuBar helpers
501// ---------------------------------------------------------------------------
502
503void wxMenuBar::Refresh()
504{
065de612 505 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
c2dcfdef 506
1e6feb95 507 DrawMenuBar(GetHwndOf(GetFrame()));
c2dcfdef
VZ
508}
509
510WXHMENU wxMenuBar::Create()
511{
3ca6a5f0 512 if ( m_hMenu != 0 )
717a57c2 513 return m_hMenu;
1cf27c63 514
c2dcfdef 515 m_hMenu = (WXHMENU)::CreateMenu();
2bda0e17 516
c2dcfdef 517 if ( !m_hMenu )
c626a8b7 518 {
f6bcfd97 519 wxLogLastError(wxT("CreateMenu"));
c626a8b7 520 }
c2dcfdef 521 else
c626a8b7 522 {
a8cfd0cb
VZ
523 size_t count = GetMenuCount();
524 for ( size_t i = 0; i < count; i++ )
c2dcfdef
VZ
525 {
526 if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
527 (UINT)m_menus[i]->GetHMenu(),
528 m_titles[i]) )
529 {
f6bcfd97 530 wxLogLastError(wxT("AppendMenu"));
c2dcfdef
VZ
531 }
532 }
c626a8b7 533 }
c626a8b7 534
c2dcfdef 535 return m_hMenu;
2bda0e17
KB
536}
537
c2dcfdef 538// ---------------------------------------------------------------------------
3dfac970 539// wxMenuBar functions to work with the top level submenus
c2dcfdef
VZ
540// ---------------------------------------------------------------------------
541
3dfac970
VZ
542// NB: we don't support owner drawn top level items for now, if we do these
543// functions would have to be changed to use wxMenuItem as well
2bda0e17 544
a8cfd0cb 545void wxMenuBar::EnableTop(size_t pos, bool enable)
2bda0e17 546{
717a57c2
VZ
547 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
548
549 int flag = enable ? MF_ENABLED : MF_GRAYED;
2bda0e17 550
c626a8b7 551 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
adc6fb16
VZ
552
553 Refresh();
2bda0e17
KB
554}
555
a8cfd0cb 556void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
2bda0e17 557{
717a57c2
VZ
558 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
559
560 m_titles[pos] = label;
561
562 if ( !IsAttached() )
563 {
564 return;
565 }
566 //else: have to modify the existing menu
567
8cd85069 568 UINT id;
c2dcfdef
VZ
569 UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
570 if ( flagsOld == 0xFFFFFFFF )
c626a8b7 571 {
223d09f6 572 wxLogLastError(wxT("GetMenuState"));
c2dcfdef
VZ
573
574 return;
575 }
576
577 if ( flagsOld & MF_POPUP )
578 {
579 // HIBYTE contains the number of items in the submenu in this case
ad9bb75f
VZ
580 flagsOld &= 0xff;
581 id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos);
c626a8b7
VZ
582 }
583 else
8cd85069
VZ
584 {
585 id = pos;
586 }
587
c50f1fb9 588 if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
a17e237f 589 id, label) == (int)0xFFFFFFFF )
c2dcfdef 590 {
f6bcfd97 591 wxLogLastError(wxT("ModifyMenu"));
c2dcfdef 592 }
717a57c2
VZ
593
594 Refresh();
2bda0e17
KB
595}
596
a8cfd0cb 597wxString wxMenuBar::GetLabelTop(size_t pos) const
2bda0e17 598{
717a57c2
VZ
599 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
600 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
8cd85069 601
717a57c2 602 return m_titles[pos];
2bda0e17
KB
603}
604
ad9bb75f
VZ
605// ---------------------------------------------------------------------------
606// wxMenuBar construction
607// ---------------------------------------------------------------------------
608
a8cfd0cb 609wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
1cf27c63 610{
ad9bb75f
VZ
611 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
612 if ( !menuOld )
613 return FALSE;
614 m_titles[pos] = title;
a8cfd0cb 615
ad9bb75f 616 if ( IsAttached() )
a8cfd0cb 617 {
ad9bb75f
VZ
618 // can't use ModifyMenu() because it deletes the submenu it replaces
619 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
a8cfd0cb 620 {
f6bcfd97 621 wxLogLastError(wxT("RemoveMenu"));
a8cfd0cb 622 }
1cf27c63 623
ad9bb75f
VZ
624 if ( !::InsertMenu(GetHmenu(), (UINT)pos,
625 MF_BYPOSITION | MF_POPUP | MF_STRING,
626 (UINT)GetHmenuOf(menu), title) )
627 {
f6bcfd97 628 wxLogLastError(wxT("InsertMenu"));
ad9bb75f
VZ
629 }
630
717a57c2
VZ
631#if wxUSE_ACCEL
632 if ( menuOld->HasAccels() || menu->HasAccels() )
633 {
634 // need to rebuild accell table
635 RebuildAccelTable();
636 }
637#endif // wxUSE_ACCEL
638
ad9bb75f 639 Refresh();
a8cfd0cb 640 }
ad9bb75f
VZ
641
642 return menuOld;
1cf27c63
UM
643}
644
a8cfd0cb 645bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
1cf27c63 646{
ad9bb75f 647 if ( !wxMenuBarBase::Insert(pos, menu, title) )
a8cfd0cb 648 return FALSE;
1cf27c63 649
ad9bb75f
VZ
650 m_titles.Insert(title, pos);
651
652 menu->Attach(this);
1cf27c63 653
ad9bb75f
VZ
654 if ( IsAttached() )
655 {
656 if ( !::InsertMenu(GetHmenu(), pos,
657 MF_BYPOSITION | MF_POPUP | MF_STRING,
658 (UINT)GetHmenuOf(menu), title) )
659 {
f6bcfd97 660 wxLogLastError(wxT("InsertMenu"));
ad9bb75f
VZ
661 }
662
717a57c2
VZ
663#if wxUSE_ACCEL
664 if ( menu->HasAccels() )
665 {
666 // need to rebuild accell table
667 RebuildAccelTable();
668 }
669#endif // wxUSE_ACCEL
670
ad9bb75f 671 Refresh();
a8cfd0cb 672 }
ad9bb75f
VZ
673
674 return TRUE;
1cf27c63
UM
675}
676
ad9bb75f 677bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
2bda0e17 678{
ad9bb75f
VZ
679 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
680 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
2bda0e17 681
717a57c2
VZ
682 if ( !wxMenuBarBase::Append(menu, title) )
683 return FALSE;
684
ff8b6290
JS
685 // Already done in Append above
686 //menu->Attach(this);
2bda0e17 687
717a57c2
VZ
688 m_titles.Add(title);
689
ad9bb75f
VZ
690 if ( IsAttached() )
691 {
692 if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
693 (UINT)submenu, title) )
694 {
695 wxLogLastError(wxT("AppendMenu"));
696 }
697
717a57c2
VZ
698#if wxUSE_ACCEL
699 if ( menu->HasAccels() )
700 {
701 // need to rebuild accell table
702 RebuildAccelTable();
703 }
704#endif // wxUSE_ACCEL
705
ad9bb75f
VZ
706 Refresh();
707 }
2bda0e17 708
a8cfd0cb 709 return TRUE;
2bda0e17
KB
710}
711
a8cfd0cb 712wxMenu *wxMenuBar::Remove(size_t pos)
2bda0e17 713{
a8cfd0cb
VZ
714 wxMenu *menu = wxMenuBarBase::Remove(pos);
715 if ( !menu )
716 return NULL;
c626a8b7 717
ad9bb75f
VZ
718 if ( IsAttached() )
719 {
720 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
721 {
f6bcfd97 722 wxLogLastError(wxT("RemoveMenu"));
ad9bb75f 723 }
2bda0e17 724
ad9bb75f
VZ
725 menu->Detach();
726
717a57c2
VZ
727#if wxUSE_ACCEL
728 if ( menu->HasAccels() )
729 {
730 // need to rebuild accell table
731 RebuildAccelTable();
732 }
733#endif // wxUSE_ACCEL
734
ad9bb75f
VZ
735 Refresh();
736 }
2bda0e17 737
a8cfd0cb 738 m_titles.Remove(pos);
2bda0e17 739
a8cfd0cb 740 return menu;
2bda0e17
KB
741}
742
d427503c 743#if wxUSE_ACCEL
717a57c2
VZ
744
745void wxMenuBar::RebuildAccelTable()
746{
747 // merge the accelerators of all menus into one accel table
42e69d6b 748 size_t nAccelCount = 0;
a8cfd0cb
VZ
749 size_t i, count = GetMenuCount();
750 for ( i = 0; i < count; i++ )
42e69d6b
VZ
751 {
752 nAccelCount += m_menus[i]->GetAccelCount();
753 }
754
5df1250b 755 if ( nAccelCount )
42e69d6b 756 {
5df1250b 757 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
42e69d6b 758
5df1250b 759 nAccelCount = 0;
a8cfd0cb 760 for ( i = 0; i < count; i++ )
5df1250b
VZ
761 {
762 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
763 }
764
765 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
42e69d6b 766
5df1250b
VZ
767 delete [] accelEntries;
768 }
717a57c2
VZ
769}
770
771#endif // wxUSE_ACCEL
772
773void wxMenuBar::Attach(wxFrame *frame)
774{
1e6feb95 775 wxMenuBarBase::Attach(frame);
717a57c2
VZ
776
777 m_menuBarFrame = frame;
778
779#if wxUSE_ACCEL
780 RebuildAccelTable();
d427503c 781#endif // wxUSE_ACCEL
42e69d6b
VZ
782}
783
1cf27c63
UM
784void wxMenuBar::Detach()
785{
a17e237f 786 m_hMenu = (WXHMENU)NULL;
2bda0e17 787
1e6feb95 788 wxMenuBarBase::Detach();
2bda0e17
KB
789}
790
1e6feb95 791#endif // wxUSE_MENUS