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