]> git.saurik.com Git - wxWidgets.git/blame - src/mac/menu.cpp
Added helper functions for string -> XmString conversion.
[wxWidgets.git] / src / mac / menu.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
a31a5f85 4// Author: Stefan Csomor
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
e40298d5 9// Licence: wxWindows licence
e9576ca5
SC
10/////////////////////////////////////////////////////////////////////////////
11
eb22f2a6
GD
12#ifdef __GNUG__
13#pragma implementation "menu.h"
14#pragma implementation "menuitem.h"
15#endif
16
e9576ca5
SC
17// ============================================================================
18// headers & declarations
19// ============================================================================
20
21// wxWindows headers
22// -----------------
23
03e11df5 24#include "wx/app.h"
e9576ca5
SC
25#include "wx/menu.h"
26#include "wx/menuitem.h"
03e11df5 27#include "wx/window.h"
e9576ca5
SC
28#include "wx/log.h"
29#include "wx/utils.h"
2b5f62a0 30#include "wx/frame.h"
e9576ca5 31
519cb848
SC
32#include "wx/mac/uma.h"
33
e9576ca5
SC
34// other standard headers
35// ----------------------
36#include <string.h>
37
2f1ae414 38#if !USE_SHARED_LIBRARY
e9576ca5
SC
39IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
40IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
2f1ae414 41#endif
e9576ca5 42
519cb848
SC
43// the (popup) menu title has this special id
44static const int idMenuTitle = -2;
b03e4fcd 45static MenuItemIndex firstUserHelpMenuItem = 0 ;
519cb848
SC
46
47const short kwxMacMenuBarResource = 1 ;
48const short kwxMacAppleMenuId = 1 ;
49
e9576ca5
SC
50// ============================================================================
51// implementation
52// ============================================================================
7c15086c
SC
53static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) ;
54static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win );
519cb848 55
e9576ca5
SC
56// Menus
57
58// Construct a menu with optional title (then use append)
519cb848 59
f5c6eb5c 60#ifdef __DARWIN__
82ca6dbc
GD
61short wxMenu::s_macNextMenuId = 3 ;
62#else
519cb848 63short wxMenu::s_macNextMenuId = 2 ;
82ca6dbc 64#endif
519cb848 65
e7549107 66void wxMenu::Init()
e9576ca5 67{
e7549107 68 m_doBreak = FALSE;
7c15086c 69 m_startRadioGroup = -1;
e7549107
SC
70
71 // create the menu
e40298d5
JS
72 m_macMenuId = s_macNextMenuId++;
73 m_hMenu = UMANewMenu(m_macMenuId, m_title);
e7549107
SC
74
75 if ( !m_hMenu )
76 {
7c15086c 77 wxLogLastError("UMANewMenu failed");
e7549107
SC
78 }
79
80 // if we have a title, insert it in the beginning of the menu
81 if ( !!m_title )
e9576ca5 82 {
519cb848 83 Append(idMenuTitle, m_title) ;
e9576ca5
SC
84 AppendSeparator() ;
85 }
e7549107 86}
e9576ca5 87
e7549107
SC
88wxMenu::~wxMenu()
89{
e40298d5
JS
90 if (MAC_WXHMENU(m_hMenu))
91 ::DisposeMenu(MAC_WXHMENU(m_hMenu));
e9576ca5
SC
92}
93
e7549107 94void wxMenu::Break()
e9576ca5 95{
e40298d5 96 // not available on the mac platform
e7549107 97}
e9576ca5 98
7c15086c 99void wxMenu::Attach(wxMenuBarBase *menubar)
e7549107 100{
7c15086c 101 wxMenuBase::Attach(menubar);
e7549107 102
7c15086c 103 EndRadioGroup();
e9576ca5
SC
104}
105
e9576ca5 106// function appends a new item or submenu to the menu
e7549107
SC
107// append a new item or submenu to the menu
108bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
e9576ca5 109{
e7549107 110 wxASSERT_MSG( pItem != NULL, "can't append NULL item to the menu" );
e9576ca5 111
e40298d5
JS
112 if ( pItem->IsSeparator() )
113 {
114 if ( pos == (size_t)-1 )
115 MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-");
116 else
117 MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos);
118 }
119 else
120 {
121 wxMenu *pSubMenu = pItem->GetSubMenu() ;
122 if ( pSubMenu != NULL )
123 {
124 wxASSERT_MSG( pSubMenu->m_hMenu != NULL , "invalid submenu added");
125 pSubMenu->m_menuParent = this ;
126
127 if (wxMenuBar::MacGetInstalledMenuBar() == m_menuBar)
d46342af
SC
128 {
129 pSubMenu->MacBeforeDisplay( true ) ;
130 }
e40298d5
JS
131
132 if ( pos == (size_t)-1 )
133 UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), pSubMenu->m_macMenuId);
134 else
135 UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText() , pos, pSubMenu->m_macMenuId);
136 pItem->UpdateItemBitmap() ;
137 pItem->UpdateItemStatus() ;
138 }
139 else
140 {
141 if ( pos == (size_t)-1 )
142 {
143 UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), "a" );
144 pos = CountMenuItems(MAC_WXHMENU(m_hMenu)) ;
145 }
146 else
147 {
148 UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), "a" , pos);
149 }
150
151 SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , pos , pItem->GetId() ) ;
152 pItem->UpdateItemText() ;
153 pItem->UpdateItemBitmap() ;
154 pItem->UpdateItemStatus() ;
155
156 if ( pItem->GetId() == idMenuTitle )
157 {
158 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , pos , false ) ;
159 }
160 }
161 }
e7549107
SC
162 // if we're already attached to the menubar, we must update it
163 if ( IsAttached() )
164 {
165 m_menuBar->Refresh();
166 }
e40298d5 167 return TRUE ;
e9576ca5
SC
168}
169
7c15086c
SC
170void wxMenu::EndRadioGroup()
171{
172 // we're not inside a radio group any longer
173 m_startRadioGroup = -1;
174}
175
e7549107 176bool wxMenu::DoAppend(wxMenuItem *item)
e9576ca5 177{
7c15086c
SC
178 wxCHECK_MSG( item, FALSE, _T("NULL item in wxMenu::DoAppend") );
179
180 bool check = FALSE;
181
182 if ( item->GetKind() == wxITEM_RADIO )
183 {
184 int count = GetMenuItemCount();
185
186 if ( m_startRadioGroup == -1 )
187 {
188 // start a new radio group
189 m_startRadioGroup = count;
190
191 // for now it has just one element
192 item->SetAsRadioGroupStart();
193 item->SetRadioGroupEnd(m_startRadioGroup);
194
195 // ensure that we have a checked item in the radio group
196 check = TRUE;
197 }
198 else // extend the current radio group
199 {
200 // we need to update its end item
201 item->SetRadioGroupStart(m_startRadioGroup);
202 wxMenuItemList::Node *node = GetMenuItems().Item(m_startRadioGroup);
203
204 if ( node )
205 {
206 node->GetData()->SetRadioGroupEnd(count);
207 }
208 else
209 {
210 wxFAIL_MSG( _T("where is the radio group start item?") );
211 }
212 }
213 }
214 else // not a radio item
215 {
216 EndRadioGroup();
217 }
218
219 if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
220 {
221 return FALSE;
222 }
223
224 if ( check )
225 {
226 // check the item initially
227 item->Check(TRUE);
228 }
229
230 return TRUE;
e9576ca5
SC
231}
232
e7549107 233bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
e9576ca5 234{
e7549107 235 return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos);
e9576ca5
SC
236}
237
e7549107 238wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
e9576ca5 239{
e7549107
SC
240 // we need to find the items position in the child list
241 size_t pos;
242 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
243 for ( pos = 0; node; pos++ )
244 {
245 if ( node->GetData() == item )
246 break;
e9576ca5 247
e7549107 248 node = node->GetNext();
e9576ca5
SC
249 }
250
e7549107
SC
251 // DoRemove() (unlike Remove) can only be called for existing item!
252 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
519cb848 253
e40298d5 254 ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1);
e9576ca5 255
e7549107
SC
256 if ( IsAttached() )
257 {
7c15086c 258 // otherwise, the change won't be visible
e7549107
SC
259 m_menuBar->Refresh();
260 }
e9576ca5 261
e7549107
SC
262 // and from internal data structures
263 return wxMenuBase::DoRemove(item);
e9576ca5
SC
264}
265
e9576ca5
SC
266void wxMenu::SetTitle(const wxString& label)
267{
e40298d5
JS
268 m_title = label ;
269 UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , label ) ;
e9576ca5 270}
e7549107 271bool wxMenu::ProcessCommand(wxCommandEvent & event)
e9576ca5
SC
272{
273 bool processed = FALSE;
274
e7549107 275#if WXWIN_COMPATIBILITY
e9576ca5
SC
276 // Try a callback
277 if (m_callback)
278 {
e7549107
SC
279 (void)(*(m_callback))(*this, event);
280 processed = TRUE;
e9576ca5 281 }
e7549107 282#endif WXWIN_COMPATIBILITY
e9576ca5
SC
283
284 // Try the menu's event handler
285 if ( !processed && GetEventHandler())
286 {
e7549107 287 processed = GetEventHandler()->ProcessEvent(event);
e9576ca5 288 }
519cb848 289
e7549107
SC
290 // Try the window the menu was popped up from (and up through the
291 // hierarchy)
292 wxWindow *win = GetInvokingWindow();
293 if ( !processed && win )
294 processed = win->GetEventHandler()->ProcessEvent(event);
295
296 return processed;
297}
298
299
300// ---------------------------------------------------------------------------
301// other
302// ---------------------------------------------------------------------------
303
e7549107
SC
304wxWindow *wxMenu::GetWindow() const
305{
306 if ( m_invokingWindow != NULL )
307 return m_invokingWindow;
308 else if ( m_menuBar != NULL)
03e11df5 309 return (wxWindow *) m_menuBar->GetFrame();
e7549107
SC
310
311 return NULL;
312}
519cb848 313
519cb848
SC
314// helper functions returning the mac menu position for a certain item, note that this is
315// mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0
316
317int wxMenu::MacGetIndexFromId( int id )
318{
e7549107
SC
319 size_t pos;
320 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
321 for ( pos = 0; node; pos++ )
519cb848 322 {
e7549107
SC
323 if ( node->GetData()->GetId() == id )
324 break;
519cb848 325
e7549107
SC
326 node = node->GetNext();
327 }
e40298d5 328
519cb848 329 if (!node)
e40298d5
JS
330 return 0;
331
332 return pos + 1 ;
519cb848
SC
333}
334
335int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem )
336{
e7549107
SC
337 size_t pos;
338 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
339 for ( pos = 0; node; pos++ )
519cb848 340 {
e7549107
SC
341 if ( node->GetData() == pItem )
342 break;
343
344 node = node->GetNext();
519cb848
SC
345 }
346
347 if (!node)
e40298d5
JS
348 return 0;
349
350 return pos + 1 ;
519cb848
SC
351}
352
353void wxMenu::MacEnableMenu( bool bDoEnable )
354{
e40298d5
JS
355 UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 , bDoEnable ) ;
356
357 ::DrawMenuBar() ;
519cb848
SC
358}
359
d46342af
SC
360// MacOS needs to know about submenus somewhere within this menu
361// before it can be displayed , also hide special menu items like preferences
362// that are handled by the OS
363void wxMenu::MacBeforeDisplay( bool isSubMenu )
364{
365 wxMenuItem* previousItem = NULL ;
366 int pos ;
367 wxMenuItemList::Node *node;
368 wxMenuItem *item;
369 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
370 {
371 item = (wxMenuItem *)node->GetData();
372 wxMenu* subMenu = item->GetSubMenu() ;
373 if (subMenu)
374 {
375 subMenu->MacBeforeDisplay( true ) ;
376 }
377 else
378 {
379 #if TARGET_CARBON
380 if ( UMAGetSystemVersion() >= 0x1000 )
381 {
382 if ( item->GetId() == wxApp::s_macPreferencesMenuItemId || item->GetId() == wxApp::s_macExitMenuItemId)
383 {
384 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos + 1, kMenuItemAttrHidden, 0 );
385 if ( GetMenuItems().GetCount() == pos + 1 && previousItem != NULL && previousItem->IsSeparator() )
386 {
387 ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos , kMenuItemAttrHidden, 0 );
388 }
389 }
390 }
391 #endif
392 }
393 previousItem = item ;
394 }
395
396 if ( isSubMenu )
397 ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1);
398
399}
400// undo all changes from the MacBeforeDisplay call
401void wxMenu::MacAfterDisplay( bool isSubMenu )
402{
403 if ( isSubMenu )
404 ::DeleteMenu(MacGetMenuId());
405
406 wxMenuItem* previousItem = NULL ;
407 int pos ;
408 wxMenuItemList::Node *node;
409 wxMenuItem *item;
410 for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
411 {
412 item = (wxMenuItem *)node->GetData();
413 wxMenu* subMenu = item->GetSubMenu() ;
414 if (subMenu)
415 {
416 subMenu->MacAfterDisplay( true ) ;
417 }
418 else
419 {
420 // no need to undo hidings
421 }
422 previousItem = item ;
423 }
424}
425
e9576ca5 426// Menu Bar
519cb848
SC
427
428/*
429
430Mac Implementation note :
431
432The Mac has only one global menubar, so we attempt to install the currently
433active menubar from a frame, we currently don't take into account mdi-frames
434which would ask for menu-merging
435
436Secondly there is no mac api for changing a menubar that is not the current
437menubar, so we have to wait for preparing the actual menubar until the
438wxMenubar is to be used
439
440We can in subsequent versions use MacInstallMenuBar to provide some sort of
441auto-merge for MDI in case this will be necessary
442
443*/
444
445wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ;
446
e7549107 447void wxMenuBar::Init()
e9576ca5
SC
448{
449 m_eventHandler = this;
e9576ca5 450 m_menuBarFrame = NULL;
7c15086c 451 m_invokingWindow = (wxWindow*) NULL;
e9576ca5
SC
452}
453
51abe921
SC
454wxMenuBar::wxMenuBar()
455{
456 Init();
457}
458
459wxMenuBar::wxMenuBar( long WXUNUSED(style) )
460{
461 Init();
462}
463
e7549107
SC
464
465wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
e9576ca5 466{
e7549107
SC
467 Init();
468
469 m_titles.Alloc(count);
470
471 for ( int i = 0; i < count; i++ )
472 {
473 m_menus.Append(menus[i]);
474 m_titles.Add(titles[i]);
475
476 menus[i]->Attach(this);
477 }
e9576ca5
SC
478}
479
480wxMenuBar::~wxMenuBar()
481{
e40298d5
JS
482 if (s_macInstalledMenuBar == this)
483 {
484 ::ClearMenuBar();
485 s_macInstalledMenuBar = NULL;
486 }
519cb848 487
e7549107
SC
488}
489
6d6da89c 490void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
e7549107
SC
491{
492 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
e9576ca5 493
e7549107 494 DrawMenuBar();
e9576ca5
SC
495}
496
519cb848
SC
497void wxMenuBar::MacInstallMenuBar()
498{
2b8a6962
GD
499 if ( s_macInstalledMenuBar == this )
500 return ;
e40298d5 501
d9e054bc 502 wxStAppResource resload ;
e40298d5 503
2b8a6962
GD
504 Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ;
505 wxString message ;
506 wxCHECK_RET( menubar != NULL, "can't read MBAR resource" );
507 ::SetMenuBar( menubar ) ;
a3590de1
SC
508#if TARGET_API_MAC_CARBON
509 ::DisposeMenuBar( menubar ) ;
510#else
2b8a6962 511 ::DisposeHandle( menubar ) ;
a3590de1 512#endif
519cb848 513
a3590de1 514#if TARGET_API_MAC_OS8
2b8a6962 515 MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ;
d9e054bc
SC
516 if ( CountMenuItems( menu ) == 2 )
517 {
2b8a6962
GD
518 ::AppendResMenu(menu, 'DRVR');
519 }
a3590de1 520#endif
519cb848 521
7c15086c 522 // clean-up the help menu before adding new items
e40298d5
JS
523 MenuHandle mh = NULL ;
524 if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr )
525 {
526 for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i )
527 {
528 DeleteMenuItem( mh , i ) ;
529 }
530 }
531 else
532 {
533 mh = NULL ;
534 }
7c15086c 535#if TARGET_CARBON
e40298d5
JS
536 if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId)
537 {
538 wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ;
539 if ( item == NULL || !(item->IsEnabled()) )
540 DisableMenuCommand( NULL , kHICommandPreferences ) ;
541 else
542 EnableMenuCommand( NULL , kHICommandPreferences ) ;
543 }
7c15086c 544#endif
e40298d5
JS
545 for (size_t i = 0; i < m_menus.GetCount(); i++)
546 {
547 Str255 label;
f823cacb 548 wxMenuItemList::Node *node;
2b5f62a0
VZ
549 wxMenuItem *item;
550 int pos ;
e40298d5
JS
551 wxMenu* menu = m_menus[i] , *subMenu = NULL ;
552
553 if( m_titles[i] == "?" || m_titles[i] == "&?" || m_titles[i] == wxApp::s_macHelpMenuTitleName )
554 {
555 if ( mh == NULL )
556 {
557 continue ;
558 }
559
560 for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++)
561 {
562 item = (wxMenuItem *)node->GetData();
563 subMenu = item->GetSubMenu() ;
564 if (subMenu)
565 {
566 // we don't support hierarchical menus in the help menu yet
567 }
568 else
569 {
570 if ( item->IsSeparator() )
571 {
572 if ( mh )
573 MacAppendMenu(mh, "\p-" );
574 }
575 else
576 {
577 wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ;
578
579 if ( item->GetId() == wxApp::s_macAboutMenuItemId )
580 {
581 UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() );
582 UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true );
583 SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ;
584 UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ;
585 }
586 else
587 {
588 if ( mh )
589 {
590 UMAAppendMenuItem(mh, item->GetText() , entry );
591 SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ;
592 }
593 }
594
595 delete entry ;
596 }
597 }
598 }
599 }
600 else
601 {
602 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i] ) ;
d46342af 603 m_menus[i]->MacBeforeDisplay(false) ;
e40298d5 604 ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0);
e40298d5
JS
605 }
606 }
607 ::DrawMenuBar() ;
608 s_macInstalledMenuBar = this;
519cb848
SC
609}
610
e7549107 611void wxMenuBar::EnableTop(size_t pos, bool enable)
e9576ca5 612{
e7549107 613 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
e40298d5 614 m_menus[pos]->MacEnableMenu( enable ) ;
e7549107 615 Refresh();
e9576ca5
SC
616}
617
e7549107 618void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
e9576ca5 619{
e7549107 620 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
e9576ca5 621
e7549107 622 m_titles[pos] = label;
e9576ca5 623
e7549107
SC
624 if ( !IsAttached() )
625 {
e9576ca5 626 return;
e7549107 627 }
e9576ca5 628
519cb848 629 m_menus[pos]->SetTitle( label ) ;
e40298d5
JS
630 if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ?
631 {
632 ::SetMenuBar( GetMenuBar() ) ;
633 ::InvalMenuBar() ;
634 }
e9576ca5
SC
635}
636
e7549107 637wxString wxMenuBar::GetLabelTop(size_t pos) const
e9576ca5 638{
e7549107
SC
639 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
640 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
519cb848 641
e7549107 642 return m_titles[pos];
e9576ca5
SC
643}
644
e7549107 645int wxMenuBar::FindMenu(const wxString& title)
e9576ca5 646{
e7549107 647 wxString menuTitle = wxStripMenuCodes(title);
e9576ca5 648
e7549107
SC
649 size_t count = GetMenuCount();
650 for ( size_t i = 0; i < count; i++ )
e9576ca5 651 {
e7549107
SC
652 wxString title = wxStripMenuCodes(m_titles[i]);
653 if ( menuTitle == title )
654 return i;
e9576ca5 655 }
e9576ca5 656
e7549107 657 return wxNOT_FOUND;
e9576ca5 658
e9576ca5
SC
659}
660
e7549107
SC
661
662// ---------------------------------------------------------------------------
663// wxMenuBar construction
664// ---------------------------------------------------------------------------
665
666// ---------------------------------------------------------------------------
667// wxMenuBar construction
668// ---------------------------------------------------------------------------
669
670wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 671{
e7549107
SC
672 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
673 if ( !menuOld )
674 return FALSE;
675 m_titles[pos] = title;
e9576ca5 676
e7549107 677 if ( IsAttached() )
e9576ca5 678 {
e40298d5
JS
679 if (s_macInstalledMenuBar == this)
680 {
d46342af 681 menuOld->MacAfterDisplay( false ) ;
e40298d5
JS
682 ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
683 {
d46342af 684 menu->MacBeforeDisplay( false ) ;
e40298d5
JS
685 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
686 if ( pos == m_menus.GetCount() - 1)
687 {
688 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
689 }
690 else
691 {
692 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
693 }
694 }
695 }
e9576ca5 696
e7549107 697 Refresh();
e9576ca5 698 }
e9576ca5 699
e7549107 700 return menuOld;
e9576ca5
SC
701}
702
e7549107 703bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
e9576ca5 704{
e7549107
SC
705 if ( !wxMenuBarBase::Insert(pos, menu, title) )
706 return FALSE;
e9576ca5 707
e7549107 708 m_titles.Insert(title, pos);
e9576ca5 709
e40298d5 710 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
e7549107 711
d46342af 712 if ( IsAttached() && s_macInstalledMenuBar == this )
e9576ca5 713 {
d46342af 714 if (s_macInstalledMenuBar == this)
e40298d5 715 {
d46342af
SC
716 menu->MacBeforeDisplay( false ) ;
717 if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() )
718 {
719 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
720 }
721 else
722 {
723 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ;
724 }
e40298d5 725 }
e7549107 726 Refresh();
e9576ca5 727 }
e7549107
SC
728
729 return TRUE;
e9576ca5
SC
730}
731
51abe921
SC
732wxMenu *wxMenuBar::Remove(size_t pos)
733{
734 wxMenu *menu = wxMenuBarBase::Remove(pos);
735 if ( !menu )
736 return NULL;
737
738 if ( IsAttached() )
739 {
e40298d5
JS
740 if (s_macInstalledMenuBar == this)
741 {
742 ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ;
743 }
51abe921
SC
744
745 menu->Detach();
746
51abe921
SC
747 Refresh();
748 }
749
750 m_titles.Remove(pos);
751
752 return menu;
753}
754
755bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
756{
757 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
758 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
759
760 if ( !wxMenuBarBase::Append(menu, title) )
761 return FALSE;
762
51abe921 763 m_titles.Add(title);
40325b26 764
e40298d5 765 UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title ) ;
51abe921
SC
766
767 if ( IsAttached() )
768 {
e40298d5
JS
769 if (s_macInstalledMenuBar == this)
770 {
771 ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ;
772 }
51abe921
SC
773
774 Refresh();
775 }
776
7c15086c
SC
777 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
778 // adding menu later on.
779 if (m_invokingWindow)
780 wxMenubarSetInvokingWindow( menu, m_invokingWindow );
781
51abe921
SC
782 return TRUE;
783}
784
2b5f62a0
VZ
785static void wxMenubarUnsetInvokingWindow( wxMenu *menu )
786{
787 menu->SetInvokingWindow( (wxWindow*) NULL );
788
789 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
790 while (node)
791 {
792 wxMenuItem *menuitem = node->GetData();
793 if (menuitem->IsSubMenu())
794 wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() );
795 node = node->GetNext();
796 }
797}
798
799static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win )
800{
801 menu->SetInvokingWindow( win );
802
803 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
804 while (node)
805 {
806 wxMenuItem *menuitem = node->GetData();
807 if (menuitem->IsSubMenu())
808 wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win );
809 node = node->GetNext();
810 }
811}
812
813void wxMenuBar::UnsetInvokingWindow()
814{
7c15086c 815 m_invokingWindow = (wxWindow*) NULL;
2b5f62a0
VZ
816 wxMenuList::Node *node = m_menus.GetFirst();
817 while (node)
818 {
819 wxMenu *menu = node->GetData();
820 wxMenubarUnsetInvokingWindow( menu );
821 node = node->GetNext();
822 }
823}
824
825void wxMenuBar::SetInvokingWindow(wxFrame *frame)
826{
7c15086c 827 m_invokingWindow = frame;
2b5f62a0
VZ
828 wxMenuList::Node *node = m_menus.GetFirst();
829 while (node)
830 {
831 wxMenu *menu = node->GetData();
832 wxMenubarSetInvokingWindow( menu, frame );
833 node = node->GetNext();
834 }
835}
836
90b959ae 837void wxMenuBar::Detach()
2f1ae414 838{
90b959ae
SC
839 wxMenuBarBase::Detach() ;
840}
2f1ae414 841
90b959ae
SC
842void wxMenuBar::Attach(wxFrame *frame)
843{
844 wxMenuBarBase::Attach( frame ) ;
2f1ae414 845}
51abe921
SC
846// ---------------------------------------------------------------------------
847// wxMenuBar searching for menu items
848// ---------------------------------------------------------------------------
849
850// Find the itemString in menuString, and return the item id or wxNOT_FOUND
851int wxMenuBar::FindMenuItem(const wxString& menuString,
852 const wxString& itemString) const
853{
854 wxString menuLabel = wxStripMenuCodes(menuString);
855 size_t count = GetMenuCount();
856 for ( size_t i = 0; i < count; i++ )
857 {
858 wxString title = wxStripMenuCodes(m_titles[i]);
859 if ( menuString == title )
860 return m_menus[i]->FindItem(itemString);
861 }
862
863 return wxNOT_FOUND;
864}
865
866wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
867{
868 if ( itemMenu )
869 *itemMenu = NULL;
870
871 wxMenuItem *item = NULL;
872 size_t count = GetMenuCount();
873 for ( size_t i = 0; !item && (i < count); i++ )
874 {
875 item = m_menus[i]->FindItem(id, itemMenu);
876 }
877
878 return item;
879}
880
881