]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
Added icons.
[wxWidgets.git] / src / common / menucmn.cpp
CommitLineData
3dfac970
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: common/menucmn.cpp
3// Purpose: wxMenu and wxMenuBar methods common to all ports
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 26.10.99
7// RCS-ID: $Id$
8// Copyright: (c) wxWindows team
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "menubase.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
ff0ea71c
GT
27#include <ctype.h>
28
3dfac970
VZ
29#ifdef __BORLANDC__
30 #pragma hdrstop
31#endif
32
33#ifndef WX_PRECOMP
34 #include "wx/menu.h"
35#endif
36
37// ----------------------------------------------------------------------------
38// template lists
39// ----------------------------------------------------------------------------
40
41#include "wx/listimpl.cpp"
717a57c2 42
3dfac970 43WX_DEFINE_LIST(wxMenuList);
717a57c2 44WX_DEFINE_LIST(wxMenuItemList);
3dfac970
VZ
45
46// ============================================================================
47// implementation
48// ============================================================================
49
50// ----------------------------------------------------------------------------
717a57c2
VZ
51// wxMenuItem
52// ----------------------------------------------------------------------------
53
54wxMenuItemBase::~wxMenuItemBase()
55{
a583e623
RR
56 if (m_subMenu)
57 delete m_subMenu;
717a57c2
VZ
58}
59
60#if wxUSE_ACCEL
61
62void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel)
63{
64 wxString text = m_text.BeforeFirst(wxT('\t'));
65 if ( accel )
66 {
67 text += wxT('\t');
68
69 int flags = accel->GetFlags();
70 if ( flags & wxACCEL_ALT )
71 text += wxT("Alt-");
72 if ( flags & wxACCEL_CTRL )
73 text += wxT("Ctrl-");
74 if ( flags & wxACCEL_SHIFT )
75 text += wxT("Shift-");
76
77 int code = accel->GetKeyCode();
78 switch ( code )
79 {
80 case WXK_F1:
81 case WXK_F2:
82 case WXK_F3:
83 case WXK_F4:
84 case WXK_F5:
85 case WXK_F6:
86 case WXK_F7:
87 case WXK_F8:
88 case WXK_F9:
89 case WXK_F10:
90 case WXK_F11:
91 case WXK_F12:
92 text << wxT('F') << code - WXK_F1 + 1;
93 break;
94
95 // if there are any other keys wxGetAccelFromString() may return,
96 // we should process them here
97
98 default:
99 if ( wxIsalnum(code) )
100 {
101 text << (wxChar)code;
102
103 break;
104 }
105
106 wxFAIL_MSG( wxT("unknown keyboard accel") );
107 }
108 }
109
110 SetText(text);
111}
112
113#endif // wxUSE_ACCEL
114
115// ----------------------------------------------------------------------------
116// wxMenu ctor and dtor
117// ----------------------------------------------------------------------------
118
119void wxMenuBase::Init(long style)
120{
121 m_items.DeleteContents(TRUE);
122
123 m_menuBar = (wxMenuBar *)NULL;
124 m_menuParent = (wxMenu *)NULL;
125
126 m_invokingWindow = (wxWindow *)NULL;
127 m_style = style;
128 m_clientData = (void *)NULL;
129 m_eventHandler = this;
9739d9ee
VZ
130
131#if wxUSE_MENU_CALLBACK
5b0d48b3 132 m_callback = (wxFunction) NULL;
9739d9ee 133#endif // wxUSE_MENU_CALLBACK
717a57c2
VZ
134}
135
136wxMenuBase::~wxMenuBase()
137{
a583e623
RR
138 // nothing to do, wxMenuItemList dtor will delete the menu items.
139 // Actually, in GTK, the submenus have to get deleted first.
717a57c2
VZ
140}
141
142// ----------------------------------------------------------------------------
143// wxMenu item adding/removing
144// ----------------------------------------------------------------------------
145
146bool wxMenuBase::DoAppend(wxMenuItem *item)
147{
148 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Append()") );
149
150 m_items.Append(item);
151
152 return TRUE;
153}
154
155bool wxMenuBase::Insert(size_t pos, wxMenuItem *item)
156{
157 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert") );
717a57c2 158
32db328c
VZ
159 if ( pos == GetMenuItemCount() )
160 {
161 return DoAppend(item);
162 }
163 else
164 {
165 wxCHECK_MSG( pos < GetMenuItemCount(), FALSE,
166 wxT("invalid index in wxMenu::Insert") );
167
168 return DoInsert(pos, item);
169 }
717a57c2
VZ
170}
171
172bool wxMenuBase::DoInsert(size_t pos, wxMenuItem *item)
173{
174 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Insert()") );
175
176 wxMenuItemList::Node *node = m_items.Item(pos);
177 wxCHECK_MSG( node, FALSE, wxT("invalid index in wxMenu::Insert()") );
178
179 m_items.Insert(node, item);
180
181 return TRUE;
182}
183
184wxMenuItem *wxMenuBase::Remove(wxMenuItem *item)
185{
186 wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") );
187
188 return DoRemove(item);
189}
190
191wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item)
192{
193 wxMenuItemList::Node *node = m_items.Find(item);
194
195 // if we get here, the item is valid or one of Remove() functions is broken
196 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
197
198 // we detach the item, but we do delete the list node (i.e. don't call
199 // DetachNode() here!)
200 node->SetData((wxMenuItem *)NULL); // to prevent it from deleting the item
201 m_items.DeleteNode(node);
202
203 // item isn't attached to anything any more
204 wxMenu *submenu = item->GetSubMenu();
205 if ( submenu )
206 {
207 submenu->SetParent((wxMenu *)NULL);
208 }
209
210 return item;
211}
212
213bool wxMenuBase::Delete(wxMenuItem *item)
214{
39d03faf 215 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Delete") );
717a57c2
VZ
216
217 return DoDelete(item);
218}
219
220bool wxMenuBase::DoDelete(wxMenuItem *item)
221{
222 wxMenuItem *item2 = DoRemove(item);
223 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
224
225 // don't delete the submenu
226 item2->SetSubMenu((wxMenu *)NULL);
227
228 delete item2;
229
230 return TRUE;
231}
232
233bool wxMenuBase::Destroy(wxMenuItem *item)
234{
39d03faf 235 wxCHECK_MSG( item, FALSE, wxT("invalid item in wxMenu::Destroy") );
717a57c2
VZ
236
237 return DoDestroy(item);
238}
239
240bool wxMenuBase::DoDestroy(wxMenuItem *item)
241{
242 wxMenuItem *item2 = DoRemove(item);
243 wxCHECK_MSG( item2, FALSE, wxT("failed to delete menu item") );
244
245 delete item2;
246
247 return TRUE;
248}
249
250// ----------------------------------------------------------------------------
251// wxMenu searching for items
252// ----------------------------------------------------------------------------
253
254// Finds the item id matching the given string, -1 if not found.
255int wxMenuBase::FindItem(const wxString& text) const
256{
3b59cdbf 257 wxString label = wxMenuItem::GetLabelFromText(text);
717a57c2
VZ
258 for ( wxMenuItemList::Node *node = m_items.GetFirst();
259 node;
260 node = node->GetNext() )
261 {
262 wxMenuItem *item = node->GetData();
263 if ( item->IsSubMenu() )
264 {
265 int rc = item->GetSubMenu()->FindItem(label);
266 if ( rc != wxNOT_FOUND )
267 return rc;
268 }
269 else if ( !item->IsSeparator() )
270 {
271 if ( item->GetLabel() == label )
272 return item->GetId();
273 }
274 }
275
276 return wxNOT_FOUND;
277}
278
279// recursive search for item by id
280wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
281{
282 if ( itemMenu )
283 *itemMenu = NULL;
284
285 wxMenuItem *item = NULL;
286 for ( wxMenuItemList::Node *node = m_items.GetFirst();
287 node && !item;
288 node = node->GetNext() )
289 {
290 item = node->GetData();
291
292 if ( item->GetId() == itemId )
293 {
294 if ( itemMenu )
295 *itemMenu = (wxMenu *)this;
296 }
297 else if ( item->IsSubMenu() )
298 {
299 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
300 }
301 else
302 {
303 // don't exit the loop
304 item = NULL;
305 }
306 }
307
308 return item;
309}
310
311// non recursive search
312wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
313{
314 wxMenuItem *item = (wxMenuItem *)NULL;
315 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
316
317 size_t pos;
318 for ( pos = 0; node; pos++ )
319 {
1dddf838
VZ
320 if ( node->GetData()->GetId() == id )
321 {
322 item = node->GetData();
323
717a57c2 324 break;
1dddf838 325 }
717a57c2
VZ
326
327 node = node->GetNext();
328 }
329
330 if ( ppos )
331 {
1987af7e 332 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
333 }
334
335 return item;
336}
337
338// ----------------------------------------------------------------------------
339// wxMenu helpers
340// ----------------------------------------------------------------------------
341
342// Update a menu and all submenus recursively. source is the object that has
343// the update event handlers defined for it. If NULL, the menu or associated
344// window will be used.
345void wxMenuBase::UpdateUI(wxEvtHandler* source)
346{
347 if ( !source && GetInvokingWindow() )
348 source = GetInvokingWindow()->GetEventHandler();
349 if ( !source )
350 source = GetEventHandler();
351 if ( !source )
352 source = this;
353
354 wxMenuItemList::Node* node = GetMenuItems().GetFirst();
355 while ( node )
356 {
357 wxMenuItem* item = node->GetData();
358 if ( !item->IsSeparator() )
359 {
360 wxWindowID id = item->GetId();
361 wxUpdateUIEvent event(id);
362 event.SetEventObject( source );
363
364 if ( source->ProcessEvent(event) )
365 {
366 // if anything changed, update the chanegd attribute
367 if (event.GetSetText())
368 SetLabel(id, event.GetText());
369 if (event.GetSetChecked())
370 Check(id, event.GetChecked());
371 if (event.GetSetEnabled())
372 Enable(id, event.GetEnabled());
373 }
374
375 // recurse to the submenus
376 if ( item->GetSubMenu() )
377 item->GetSubMenu()->UpdateUI(source);
378 }
379 //else: item is a separator (which don't process update UI events)
380
381 node = node->GetNext();
382 }
383}
384
385// ----------------------------------------------------------------------------
386// wxMenu functions forwarded to wxMenuItem
387// ----------------------------------------------------------------------------
388
389void wxMenuBase::Enable( int id, bool enable )
390{
391 wxMenuItem *item = FindItem(id);
392
393 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
394
395 item->Enable(enable);
396}
397
398bool wxMenuBase::IsEnabled( int id ) const
399{
400 wxMenuItem *item = FindItem(id);
401
402 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") );
403
404 return item->IsEnabled();
405}
406
407void wxMenuBase::Check( int id, bool enable )
408{
409 wxMenuItem *item = FindItem(id);
410
411 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
412
413 item->Check(enable);
414}
415
416bool wxMenuBase::IsChecked( int id ) const
417{
418 wxMenuItem *item = FindItem(id);
419
420 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") );
421
422 return item->IsChecked();
423}
424
425void wxMenuBase::SetLabel( int id, const wxString &label )
426{
427 wxMenuItem *item = FindItem(id);
428
429 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
430
431 item->SetText(label);
432}
433
434wxString wxMenuBase::GetLabel( int id ) const
435{
436 wxMenuItem *item = FindItem(id);
437
438 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") );
439
440 return item->GetText();
441}
442
443void wxMenuBase::SetHelpString( int id, const wxString& helpString )
444{
445 wxMenuItem *item = FindItem(id);
446
447 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
448
449 item->SetHelp( helpString );
450}
451
452wxString wxMenuBase::GetHelpString( int id ) const
453{
454 wxMenuItem *item = FindItem(id);
455
456 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
457
458 return item->GetHelp();
459}
460
461// ----------------------------------------------------------------------------
462// wxMenuBarBase ctor and dtor
3dfac970
VZ
463// ----------------------------------------------------------------------------
464
465wxMenuBarBase::wxMenuBarBase()
466{
467 // we own the menus when we get them
468 m_menus.DeleteContents(TRUE);
469}
470
471wxMenuBarBase::~wxMenuBarBase()
472{
473 // nothing to do, the list will delete the menus because of the call to
474 // DeleteContents() above
475}
476
477// ----------------------------------------------------------------------------
478// wxMenuBar item access: the base class versions manage m_menus list, the
479// derived class should reflect the changes in the real menubar
480// ----------------------------------------------------------------------------
481
482wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
483{
484 wxMenuList::Node *node = m_menus.Item(pos);
485 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
486
487 return node->GetData();
488}
489
490bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
491{
492 wxCHECK_MSG( menu, FALSE, wxT("can't append NULL menu") );
493
494 m_menus.Append(menu);
495
496 return TRUE;
497}
498
499bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 500 const wxString& title)
3dfac970 501{
32db328c
VZ
502 if ( pos == m_menus.GetCount() )
503 {
504 return Append(menu, title);
505 }
506 else
507 {
508 wxCHECK_MSG( menu, FALSE, wxT("can't insert NULL menu") );
3dfac970 509
32db328c
VZ
510 wxMenuList::Node *node = m_menus.Item(pos);
511 wxCHECK_MSG( node, FALSE, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 512
32db328c 513 m_menus.Insert(node, menu);
3dfac970 514
32db328c
VZ
515 return TRUE;
516 }
3dfac970
VZ
517}
518
519wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
520 const wxString& WXUNUSED(title))
521{
522 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
523
524 wxMenuList::Node *node = m_menus.Item(pos);
525 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
526
527 wxMenu *menuOld = node->GetData();
528 node->SetData(menu);
529
530 return menuOld;
531}
532
533wxMenu *wxMenuBarBase::Remove(size_t pos)
534{
535 wxMenuList::Node *node = m_menus.Item(pos);
536 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
537
538 node = m_menus.DetachNode(node);
539 wxCHECK( node, NULL ); // unexpected
540 wxMenu *menu = node->GetData();
541
542 delete node;
543
544 return menu;
545}
546
270e8b6a 547int wxMenuBarBase::FindMenu(const wxString& title) const
52130557
VZ
548{
549 wxString label = wxMenuItem::GetLabelFromText(title);
550
551 size_t count = GetMenuCount();
552 for ( size_t i = 0; i < count; i++ )
553 {
554 wxString title2 = GetLabelTop(i);
555 if ( (title2 == title) ||
556 (wxMenuItem::GetLabelFromText(title2) == label) )
557 {
558 // found
559 return (int)i;
560 }
561 }
562
563 return wxNOT_FOUND;
564
565}
566
3dfac970
VZ
567// ---------------------------------------------------------------------------
568// wxMenuBar functions forwarded to wxMenuItem
569// ---------------------------------------------------------------------------
570
571void wxMenuBarBase::Enable(int id, bool enable)
572{
573 wxMenuItem *item = FindItem(id);
574
575 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
576
577 item->Enable(enable);
578}
579
580void wxMenuBarBase::Check(int id, bool check)
581{
582 wxMenuItem *item = FindItem(id);
583
584 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
585 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
586
587 item->Check(check);
588}
589
590bool wxMenuBarBase::IsChecked(int id) const
591{
592 wxMenuItem *item = FindItem(id);
593
594 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
595
596 return item->IsChecked();
597}
598
599bool wxMenuBarBase::IsEnabled(int id) const
600{
601 wxMenuItem *item = FindItem(id);
602
603 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
604
605 return item->IsEnabled();
606}
607
608void wxMenuBarBase::SetLabel(int id, const wxString& label)
609{
610 wxMenuItem *item = FindItem(id);
611
612 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
613
614 item->SetText(label);
615}
616
617wxString wxMenuBarBase::GetLabel(int id) const
618{
619 wxMenuItem *item = FindItem(id);
620
621 wxCHECK_MSG( item, wxEmptyString,
622 wxT("wxMenuBar::GetLabel(): no such item") );
623
624 return item->GetText();
625}
626
627void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
628{
629 wxMenuItem *item = FindItem(id);
630
631 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
632
633 item->SetHelp(helpString);
634}
635
636wxString wxMenuBarBase::GetHelpString(int id) const
637{
638 wxMenuItem *item = FindItem(id);
639
640 wxCHECK_MSG( item, wxEmptyString,
641 wxT("wxMenuBar::GetHelpString(): no such item") );
642
643 return item->GetHelp();
644}
645