]> git.saurik.com Git - wxWidgets.git/blame - src/common/menucmn.cpp
fingers crossed..
[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 }
adb21613
VZ
269
270 // we execute this code for submenus as well to alllow finding them by
271 // name just like the ordinary items
272 if ( !item->IsSeparator() )
717a57c2
VZ
273 {
274 if ( item->GetLabel() == label )
275 return item->GetId();
276 }
277 }
278
279 return wxNOT_FOUND;
280}
281
282// recursive search for item by id
283wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const
284{
285 if ( itemMenu )
286 *itemMenu = NULL;
287
288 wxMenuItem *item = NULL;
289 for ( wxMenuItemList::Node *node = m_items.GetFirst();
290 node && !item;
291 node = node->GetNext() )
292 {
293 item = node->GetData();
294
295 if ( item->GetId() == itemId )
296 {
297 if ( itemMenu )
298 *itemMenu = (wxMenu *)this;
299 }
300 else if ( item->IsSubMenu() )
301 {
302 item = item->GetSubMenu()->FindItem(itemId, itemMenu);
303 }
304 else
305 {
306 // don't exit the loop
307 item = NULL;
308 }
309 }
310
311 return item;
312}
313
314// non recursive search
315wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const
316{
317 wxMenuItem *item = (wxMenuItem *)NULL;
318 wxMenuItemList::Node *node = GetMenuItems().GetFirst();
319
320 size_t pos;
321 for ( pos = 0; node; pos++ )
322 {
1dddf838
VZ
323 if ( node->GetData()->GetId() == id )
324 {
325 item = node->GetData();
326
717a57c2 327 break;
1dddf838 328 }
717a57c2
VZ
329
330 node = node->GetNext();
331 }
332
333 if ( ppos )
334 {
1987af7e 335 *ppos = item ? pos : (size_t)wxNOT_FOUND;
717a57c2
VZ
336 }
337
338 return item;
339}
340
341// ----------------------------------------------------------------------------
342// wxMenu helpers
343// ----------------------------------------------------------------------------
344
345// Update a menu and all submenus recursively. source is the object that has
346// the update event handlers defined for it. If NULL, the menu or associated
347// window will be used.
348void wxMenuBase::UpdateUI(wxEvtHandler* source)
349{
350 if ( !source && GetInvokingWindow() )
351 source = GetInvokingWindow()->GetEventHandler();
352 if ( !source )
353 source = GetEventHandler();
354 if ( !source )
355 source = this;
356
357 wxMenuItemList::Node* node = GetMenuItems().GetFirst();
358 while ( node )
359 {
360 wxMenuItem* item = node->GetData();
361 if ( !item->IsSeparator() )
362 {
363 wxWindowID id = item->GetId();
364 wxUpdateUIEvent event(id);
365 event.SetEventObject( source );
366
367 if ( source->ProcessEvent(event) )
368 {
369 // if anything changed, update the chanegd attribute
370 if (event.GetSetText())
371 SetLabel(id, event.GetText());
372 if (event.GetSetChecked())
373 Check(id, event.GetChecked());
374 if (event.GetSetEnabled())
375 Enable(id, event.GetEnabled());
376 }
377
378 // recurse to the submenus
379 if ( item->GetSubMenu() )
380 item->GetSubMenu()->UpdateUI(source);
381 }
382 //else: item is a separator (which don't process update UI events)
383
384 node = node->GetNext();
385 }
386}
387
388// ----------------------------------------------------------------------------
389// wxMenu functions forwarded to wxMenuItem
390// ----------------------------------------------------------------------------
391
392void wxMenuBase::Enable( int id, bool enable )
393{
394 wxMenuItem *item = FindItem(id);
395
396 wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") );
397
398 item->Enable(enable);
399}
400
401bool wxMenuBase::IsEnabled( int id ) const
402{
403 wxMenuItem *item = FindItem(id);
404
405 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsEnabled: no such item") );
406
407 return item->IsEnabled();
408}
409
410void wxMenuBase::Check( int id, bool enable )
411{
412 wxMenuItem *item = FindItem(id);
413
414 wxCHECK_RET( item, wxT("wxMenu::Check: no such item") );
415
416 item->Check(enable);
417}
418
419bool wxMenuBase::IsChecked( int id ) const
420{
421 wxMenuItem *item = FindItem(id);
422
423 wxCHECK_MSG( item, FALSE, wxT("wxMenu::IsChecked: no such item") );
424
425 return item->IsChecked();
426}
427
428void wxMenuBase::SetLabel( int id, const wxString &label )
429{
430 wxMenuItem *item = FindItem(id);
431
432 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
433
434 item->SetText(label);
435}
436
437wxString wxMenuBase::GetLabel( int id ) const
438{
439 wxMenuItem *item = FindItem(id);
440
441 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetLabel: no such item") );
442
443 return item->GetText();
444}
445
446void wxMenuBase::SetHelpString( int id, const wxString& helpString )
447{
448 wxMenuItem *item = FindItem(id);
449
450 wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") );
451
452 item->SetHelp( helpString );
453}
454
455wxString wxMenuBase::GetHelpString( int id ) const
456{
457 wxMenuItem *item = FindItem(id);
458
459 wxCHECK_MSG( item, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
460
461 return item->GetHelp();
462}
463
464// ----------------------------------------------------------------------------
465// wxMenuBarBase ctor and dtor
3dfac970
VZ
466// ----------------------------------------------------------------------------
467
468wxMenuBarBase::wxMenuBarBase()
469{
470 // we own the menus when we get them
471 m_menus.DeleteContents(TRUE);
472}
473
474wxMenuBarBase::~wxMenuBarBase()
475{
476 // nothing to do, the list will delete the menus because of the call to
477 // DeleteContents() above
478}
479
480// ----------------------------------------------------------------------------
481// wxMenuBar item access: the base class versions manage m_menus list, the
482// derived class should reflect the changes in the real menubar
483// ----------------------------------------------------------------------------
484
485wxMenu *wxMenuBarBase::GetMenu(size_t pos) const
486{
487 wxMenuList::Node *node = m_menus.Item(pos);
488 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") );
489
490 return node->GetData();
491}
492
493bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title))
494{
495 wxCHECK_MSG( menu, FALSE, wxT("can't append NULL menu") );
496
497 m_menus.Append(menu);
498
499 return TRUE;
500}
501
502bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu,
32db328c 503 const wxString& title)
3dfac970 504{
32db328c
VZ
505 if ( pos == m_menus.GetCount() )
506 {
186baeb2 507 return wxMenuBarBase::Append(menu, title);
32db328c
VZ
508 }
509 else
510 {
511 wxCHECK_MSG( menu, FALSE, wxT("can't insert NULL menu") );
3dfac970 512
32db328c
VZ
513 wxMenuList::Node *node = m_menus.Item(pos);
514 wxCHECK_MSG( node, FALSE, wxT("bad index in wxMenuBar::Insert()") );
3dfac970 515
32db328c 516 m_menus.Insert(node, menu);
3dfac970 517
32db328c
VZ
518 return TRUE;
519 }
3dfac970
VZ
520}
521
522wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu,
523 const wxString& WXUNUSED(title))
524{
525 wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") );
526
527 wxMenuList::Node *node = m_menus.Item(pos);
528 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") );
529
530 wxMenu *menuOld = node->GetData();
531 node->SetData(menu);
532
533 return menuOld;
534}
535
536wxMenu *wxMenuBarBase::Remove(size_t pos)
537{
538 wxMenuList::Node *node = m_menus.Item(pos);
539 wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") );
540
541 node = m_menus.DetachNode(node);
542 wxCHECK( node, NULL ); // unexpected
543 wxMenu *menu = node->GetData();
544
545 delete node;
546
547 return menu;
548}
549
270e8b6a 550int wxMenuBarBase::FindMenu(const wxString& title) const
52130557
VZ
551{
552 wxString label = wxMenuItem::GetLabelFromText(title);
553
554 size_t count = GetMenuCount();
555 for ( size_t i = 0; i < count; i++ )
556 {
557 wxString title2 = GetLabelTop(i);
558 if ( (title2 == title) ||
559 (wxMenuItem::GetLabelFromText(title2) == label) )
560 {
561 // found
562 return (int)i;
563 }
564 }
565
566 return wxNOT_FOUND;
567
568}
569
3dfac970
VZ
570// ---------------------------------------------------------------------------
571// wxMenuBar functions forwarded to wxMenuItem
572// ---------------------------------------------------------------------------
573
574void wxMenuBarBase::Enable(int id, bool enable)
575{
576 wxMenuItem *item = FindItem(id);
577
578 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
579
580 item->Enable(enable);
581}
582
583void wxMenuBarBase::Check(int id, bool check)
584{
585 wxMenuItem *item = FindItem(id);
586
587 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
588 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
589
590 item->Check(check);
591}
592
593bool wxMenuBarBase::IsChecked(int id) const
594{
595 wxMenuItem *item = FindItem(id);
596
597 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
598
599 return item->IsChecked();
600}
601
602bool wxMenuBarBase::IsEnabled(int id) const
603{
604 wxMenuItem *item = FindItem(id);
605
606 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
607
608 return item->IsEnabled();
609}
610
611void wxMenuBarBase::SetLabel(int id, const wxString& label)
612{
613 wxMenuItem *item = FindItem(id);
614
615 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
616
617 item->SetText(label);
618}
619
620wxString wxMenuBarBase::GetLabel(int id) const
621{
622 wxMenuItem *item = FindItem(id);
623
624 wxCHECK_MSG( item, wxEmptyString,
625 wxT("wxMenuBar::GetLabel(): no such item") );
626
627 return item->GetText();
628}
629
630void wxMenuBarBase::SetHelpString(int id, const wxString& helpString)
631{
632 wxMenuItem *item = FindItem(id);
633
634 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
635
636 item->SetHelp(helpString);
637}
638
639wxString wxMenuBarBase::GetHelpString(int id) const
640{
641 wxMenuItem *item = FindItem(id);
642
643 wxCHECK_MSG( item, wxEmptyString,
644 wxT("wxMenuBar::GetHelpString(): no such item") );
645
646 return item->GetHelp();
647}
648