]> git.saurik.com Git - wxWidgets.git/blame - src/msw/menu.cpp
fixed incorrect GetTextExtent for wxTELETYPE font
[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 );
3ca6a5f0
BP
437
438 // VZ: previosuly, the command int was set to id too which was quite
439 // useless anyhow (as it could be retrieved using GetId()) and
440 // uncompatible with wxGTK, so now we use the command int instead
441 // to pass the checked status
442 event.SetInt(::GetMenuState(GetHmenu(), id, MF_BYCOMMAND) & MF_CHECKED);
443
a3f4e9e8
VZ
444 ProcessCommand(event);
445 }
446
447 return TRUE;
2bda0e17
KB
448}
449
42e69d6b 450bool wxMenu::ProcessCommand(wxCommandEvent & event)
c2dcfdef
VZ
451{
452 bool processed = FALSE;
453
9739d9ee 454#if wxUSE_MENU_CALLBACK
c2dcfdef
VZ
455 // Try a callback
456 if (m_callback)
457 {
458 (void)(*(m_callback))(*this, event);
459 processed = TRUE;
460 }
9739d9ee 461#endif // wxUSE_MENU_CALLBACK
c2dcfdef
VZ
462
463 // Try the menu's event handler
464 if ( !processed && GetEventHandler())
465 {
466 processed = GetEventHandler()->ProcessEvent(event);
467 }
468
469 // Try the window the menu was popped up from (and up through the
470 // hierarchy)
471 wxWindow *win = GetInvokingWindow();
472 if ( !processed && win )
473 processed = win->GetEventHandler()->ProcessEvent(event);
42e69d6b
VZ
474
475 return processed;
c2dcfdef
VZ
476}
477
c2dcfdef
VZ
478// ---------------------------------------------------------------------------
479// other
480// ---------------------------------------------------------------------------
2bda0e17 481
c2dcfdef
VZ
482void wxMenu::Attach(wxMenuBar *menubar)
483{
484 // menu can be in at most one menubar because otherwise they would both
485 // delete the menu pointer
223d09f6 486 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
c2dcfdef
VZ
487
488 m_menuBar = menubar;
c2dcfdef
VZ
489}
490
491void wxMenu::Detach()
492{
223d09f6 493 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
c2dcfdef 494
ad9bb75f 495 m_menuBar = NULL;
717a57c2
VZ
496}
497
498wxWindow *wxMenu::GetWindow() const
499{
500 if ( m_invokingWindow != NULL )
501 return m_invokingWindow;
502 else if ( m_menuBar != NULL)
503 return m_menuBar->GetFrame();
504
505 return NULL;
c2dcfdef
VZ
506}
507
508// ---------------------------------------------------------------------------
2bda0e17 509// Menu Bar
c2dcfdef
VZ
510// ---------------------------------------------------------------------------
511
512void wxMenuBar::Init()
2bda0e17 513{
c626a8b7 514 m_eventHandler = this;
c626a8b7
VZ
515 m_menuBarFrame = NULL;
516 m_hMenu = 0;
cba2db0c 517}
2bda0e17 518
c2dcfdef
VZ
519wxMenuBar::wxMenuBar()
520{
521 Init();
522}
523
cba2db0c
JS
524wxMenuBar::wxMenuBar( long WXUNUSED(style) )
525{
c2dcfdef 526 Init();
2bda0e17
KB
527}
528
c2dcfdef 529wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
2bda0e17 530{
c2dcfdef
VZ
531 Init();
532
a8cfd0cb 533 m_titles.Alloc(count);
c2dcfdef 534
a8cfd0cb
VZ
535 for ( int i = 0; i < count; i++ )
536 {
537 m_menus.Append(menus[i]);
538 m_titles.Add(titles[i]);
2bda0e17 539
a8cfd0cb
VZ
540 menus[i]->Attach(this);
541 }
2bda0e17
KB
542}
543
b8d3a4f1 544wxMenuBar::~wxMenuBar()
2bda0e17 545{
c2dcfdef 546}
2bda0e17 547
c2dcfdef
VZ
548// ---------------------------------------------------------------------------
549// wxMenuBar helpers
550// ---------------------------------------------------------------------------
551
552void wxMenuBar::Refresh()
553{
065de612 554 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
c2dcfdef 555
ad9bb75f 556 DrawMenuBar(GetHwndOf(m_menuBarFrame));
c2dcfdef
VZ
557}
558
559WXHMENU wxMenuBar::Create()
560{
3ca6a5f0 561 if ( m_hMenu != 0 )
717a57c2 562 return m_hMenu;
1cf27c63 563
c2dcfdef 564 m_hMenu = (WXHMENU)::CreateMenu();
2bda0e17 565
c2dcfdef 566 if ( !m_hMenu )
c626a8b7 567 {
f6bcfd97 568 wxLogLastError(wxT("CreateMenu"));
c626a8b7 569 }
c2dcfdef 570 else
c626a8b7 571 {
a8cfd0cb
VZ
572 size_t count = GetMenuCount();
573 for ( size_t i = 0; i < count; i++ )
c2dcfdef
VZ
574 {
575 if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
576 (UINT)m_menus[i]->GetHMenu(),
577 m_titles[i]) )
578 {
f6bcfd97 579 wxLogLastError(wxT("AppendMenu"));
c2dcfdef
VZ
580 }
581 }
c626a8b7 582 }
c626a8b7 583
c2dcfdef 584 return m_hMenu;
2bda0e17
KB
585}
586
c2dcfdef 587// ---------------------------------------------------------------------------
3dfac970 588// wxMenuBar functions to work with the top level submenus
c2dcfdef
VZ
589// ---------------------------------------------------------------------------
590
3dfac970
VZ
591// NB: we don't support owner drawn top level items for now, if we do these
592// functions would have to be changed to use wxMenuItem as well
2bda0e17 593
a8cfd0cb 594void wxMenuBar::EnableTop(size_t pos, bool enable)
2bda0e17 595{
717a57c2
VZ
596 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
597
598 int flag = enable ? MF_ENABLED : MF_GRAYED;
2bda0e17 599
c626a8b7 600 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
adc6fb16
VZ
601
602 Refresh();
2bda0e17
KB
603}
604
a8cfd0cb 605void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
2bda0e17 606{
717a57c2
VZ
607 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
608
609 m_titles[pos] = label;
610
611 if ( !IsAttached() )
612 {
613 return;
614 }
615 //else: have to modify the existing menu
616
8cd85069 617 UINT id;
c2dcfdef
VZ
618 UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
619 if ( flagsOld == 0xFFFFFFFF )
c626a8b7 620 {
223d09f6 621 wxLogLastError(wxT("GetMenuState"));
c2dcfdef
VZ
622
623 return;
624 }
625
626 if ( flagsOld & MF_POPUP )
627 {
628 // HIBYTE contains the number of items in the submenu in this case
ad9bb75f
VZ
629 flagsOld &= 0xff;
630 id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos);
c626a8b7
VZ
631 }
632 else
8cd85069
VZ
633 {
634 id = pos;
635 }
636
c50f1fb9 637 if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
a17e237f 638 id, label) == (int)0xFFFFFFFF )
c2dcfdef 639 {
f6bcfd97 640 wxLogLastError(wxT("ModifyMenu"));
c2dcfdef 641 }
717a57c2
VZ
642
643 Refresh();
2bda0e17
KB
644}
645
a8cfd0cb 646wxString wxMenuBar::GetLabelTop(size_t pos) const
2bda0e17 647{
717a57c2
VZ
648 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
649 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
8cd85069 650
717a57c2 651 return m_titles[pos];
2bda0e17
KB
652}
653
ad9bb75f
VZ
654// ---------------------------------------------------------------------------
655// wxMenuBar construction
656// ---------------------------------------------------------------------------
657
a8cfd0cb 658wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
1cf27c63 659{
ad9bb75f
VZ
660 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
661 if ( !menuOld )
662 return FALSE;
663 m_titles[pos] = title;
a8cfd0cb 664
ad9bb75f 665 if ( IsAttached() )
a8cfd0cb 666 {
ad9bb75f
VZ
667 // can't use ModifyMenu() because it deletes the submenu it replaces
668 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
a8cfd0cb 669 {
f6bcfd97 670 wxLogLastError(wxT("RemoveMenu"));
a8cfd0cb 671 }
1cf27c63 672
ad9bb75f
VZ
673 if ( !::InsertMenu(GetHmenu(), (UINT)pos,
674 MF_BYPOSITION | MF_POPUP | MF_STRING,
675 (UINT)GetHmenuOf(menu), title) )
676 {
f6bcfd97 677 wxLogLastError(wxT("InsertMenu"));
ad9bb75f
VZ
678 }
679
717a57c2
VZ
680#if wxUSE_ACCEL
681 if ( menuOld->HasAccels() || menu->HasAccels() )
682 {
683 // need to rebuild accell table
684 RebuildAccelTable();
685 }
686#endif // wxUSE_ACCEL
687
ad9bb75f 688 Refresh();
a8cfd0cb 689 }
ad9bb75f
VZ
690
691 return menuOld;
1cf27c63
UM
692}
693
a8cfd0cb 694bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
1cf27c63 695{
ad9bb75f 696 if ( !wxMenuBarBase::Insert(pos, menu, title) )
a8cfd0cb 697 return FALSE;
1cf27c63 698
ad9bb75f
VZ
699 m_titles.Insert(title, pos);
700
701 menu->Attach(this);
1cf27c63 702
ad9bb75f
VZ
703 if ( IsAttached() )
704 {
705 if ( !::InsertMenu(GetHmenu(), pos,
706 MF_BYPOSITION | MF_POPUP | MF_STRING,
707 (UINT)GetHmenuOf(menu), title) )
708 {
f6bcfd97 709 wxLogLastError(wxT("InsertMenu"));
ad9bb75f
VZ
710 }
711
717a57c2
VZ
712#if wxUSE_ACCEL
713 if ( menu->HasAccels() )
714 {
715 // need to rebuild accell table
716 RebuildAccelTable();
717 }
718#endif // wxUSE_ACCEL
719
ad9bb75f 720 Refresh();
a8cfd0cb 721 }
ad9bb75f
VZ
722
723 return TRUE;
1cf27c63
UM
724}
725
ad9bb75f 726bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
2bda0e17 727{
ad9bb75f
VZ
728 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
729 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
2bda0e17 730
717a57c2
VZ
731 if ( !wxMenuBarBase::Append(menu, title) )
732 return FALSE;
733
ad9bb75f 734 menu->Attach(this);
2bda0e17 735
717a57c2
VZ
736 m_titles.Add(title);
737
ad9bb75f
VZ
738 if ( IsAttached() )
739 {
740 if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
741 (UINT)submenu, title) )
742 {
743 wxLogLastError(wxT("AppendMenu"));
744 }
745
717a57c2
VZ
746#if wxUSE_ACCEL
747 if ( menu->HasAccels() )
748 {
749 // need to rebuild accell table
750 RebuildAccelTable();
751 }
752#endif // wxUSE_ACCEL
753
ad9bb75f
VZ
754 Refresh();
755 }
2bda0e17 756
a8cfd0cb 757 return TRUE;
2bda0e17
KB
758}
759
a8cfd0cb 760wxMenu *wxMenuBar::Remove(size_t pos)
2bda0e17 761{
a8cfd0cb
VZ
762 wxMenu *menu = wxMenuBarBase::Remove(pos);
763 if ( !menu )
764 return NULL;
c626a8b7 765
ad9bb75f
VZ
766 if ( IsAttached() )
767 {
768 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
769 {
f6bcfd97 770 wxLogLastError(wxT("RemoveMenu"));
ad9bb75f 771 }
2bda0e17 772
ad9bb75f
VZ
773 menu->Detach();
774
717a57c2
VZ
775#if wxUSE_ACCEL
776 if ( menu->HasAccels() )
777 {
778 // need to rebuild accell table
779 RebuildAccelTable();
780 }
781#endif // wxUSE_ACCEL
782
ad9bb75f
VZ
783 Refresh();
784 }
2bda0e17 785
a8cfd0cb 786 m_titles.Remove(pos);
2bda0e17 787
a8cfd0cb 788 return menu;
2bda0e17
KB
789}
790
d427503c 791#if wxUSE_ACCEL
717a57c2
VZ
792
793void wxMenuBar::RebuildAccelTable()
794{
795 // merge the accelerators of all menus into one accel table
42e69d6b 796 size_t nAccelCount = 0;
a8cfd0cb
VZ
797 size_t i, count = GetMenuCount();
798 for ( i = 0; i < count; i++ )
42e69d6b
VZ
799 {
800 nAccelCount += m_menus[i]->GetAccelCount();
801 }
802
5df1250b 803 if ( nAccelCount )
42e69d6b 804 {
5df1250b 805 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
42e69d6b 806
5df1250b 807 nAccelCount = 0;
a8cfd0cb 808 for ( i = 0; i < count; i++ )
5df1250b
VZ
809 {
810 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
811 }
812
813 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
42e69d6b 814
5df1250b
VZ
815 delete [] accelEntries;
816 }
717a57c2
VZ
817}
818
819#endif // wxUSE_ACCEL
820
821void wxMenuBar::Attach(wxFrame *frame)
822{
065de612 823// wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
717a57c2
VZ
824
825 m_menuBarFrame = frame;
826
827#if wxUSE_ACCEL
828 RebuildAccelTable();
d427503c 829#endif // wxUSE_ACCEL
42e69d6b
VZ
830}
831
1cf27c63
UM
832void wxMenuBar::Detach()
833{
834// ::DestroyMenu((HMENU)m_hMenu);
a17e237f 835 m_hMenu = (WXHMENU)NULL;
1cf27c63
UM
836 m_menuBarFrame = NULL;
837}
838
839
c2dcfdef
VZ
840// ---------------------------------------------------------------------------
841// wxMenuBar searching for menu items
842// ---------------------------------------------------------------------------
843
844// Find the itemString in menuString, and return the item id or wxNOT_FOUND
845int wxMenuBar::FindMenuItem(const wxString& menuString,
846 const wxString& itemString) const
2bda0e17 847{
c2dcfdef 848 wxString menuLabel = wxStripMenuCodes(menuString);
a8cfd0cb
VZ
849 size_t count = GetMenuCount();
850 for ( size_t i = 0; i < count; i++ )
2bda0e17 851 {
c2dcfdef 852 wxString title = wxStripMenuCodes(m_titles[i]);
f6bcfd97 853 if ( menuLabel == title )
c2dcfdef 854 return m_menus[i]->FindItem(itemString);
2bda0e17 855 }
c2dcfdef
VZ
856
857 return wxNOT_FOUND;
2bda0e17
KB
858}
859
a8cfd0cb 860wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
2bda0e17 861{
c2dcfdef 862 if ( itemMenu )
c626a8b7 863 *itemMenu = NULL;
2bda0e17 864
c626a8b7 865 wxMenuItem *item = NULL;
a8cfd0cb
VZ
866 size_t count = GetMenuCount();
867 for ( size_t i = 0; !item && (i < count); i++ )
c626a8b7 868 {
dd60b9ec 869 item = m_menus[i]->FindItem(id, itemMenu);
c626a8b7 870 }
2bda0e17 871
c2dcfdef 872 return item;
2bda0e17
KB
873}
874