]>
git.saurik.com Git - wxWidgets.git/blob - src/common/menucmn.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: common/menucmn.cpp
3 // Purpose: wxMenu and wxMenuBar methods common to all ports
4 // Author: Vadim Zeitlin
8 // Copyright: (c) wxWindows team
9 // Licence: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "menubase.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
35 // ----------------------------------------------------------------------------
37 // ----------------------------------------------------------------------------
39 #include "wx/listimpl.cpp"
41 WX_DEFINE_LIST(wxMenuList
);
42 WX_DEFINE_LIST(wxMenuItemList
);
44 // ============================================================================
46 // ============================================================================
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 wxMenuItemBase::~wxMenuItemBase()
60 void wxMenuItemBase::SetAccel(wxAcceleratorEntry
*accel
)
62 wxString text
= m_text
.BeforeFirst(wxT('\t'));
67 int flags
= accel
->GetFlags();
68 if ( flags
& wxACCEL_ALT
)
70 if ( flags
& wxACCEL_CTRL
)
72 if ( flags
& wxACCEL_SHIFT
)
73 text
+= wxT("Shift-");
75 int code
= accel
->GetKeyCode();
90 text
<< wxT('F') << code
- WXK_F1
+ 1;
93 // if there are any other keys wxGetAccelFromString() may return,
94 // we should process them here
97 if ( wxIsalnum(code
) )
104 wxFAIL_MSG( wxT("unknown keyboard accel") );
111 #endif // wxUSE_ACCEL
113 // ----------------------------------------------------------------------------
114 // wxMenu ctor and dtor
115 // ----------------------------------------------------------------------------
117 void wxMenuBase::Init(long style
)
119 m_items
.DeleteContents(TRUE
);
121 m_menuBar
= (wxMenuBar
*)NULL
;
122 m_menuParent
= (wxMenu
*)NULL
;
124 m_invokingWindow
= (wxWindow
*)NULL
;
126 m_clientData
= (void *)NULL
;
127 m_eventHandler
= this;
129 #if wxUSE_MENU_CALLBACK
130 m_callback
= (wxFunction
) NULL
;
131 #endif // wxUSE_MENU_CALLBACK
134 wxMenuBase::~wxMenuBase()
136 // nothing to do, wxMenuItemList dtor will delete the menu items.
137 // Actually, in GTK, the submenus have to get deleted first.
140 // ----------------------------------------------------------------------------
141 // wxMenu item adding/removing
142 // ----------------------------------------------------------------------------
144 bool wxMenuBase::DoAppend(wxMenuItem
*item
)
146 wxCHECK_MSG( item
, FALSE
, wxT("invalid item in wxMenu::Append()") );
148 m_items
.Append(item
);
153 bool wxMenuBase::Insert(size_t pos
, wxMenuItem
*item
)
155 wxCHECK_MSG( item
, FALSE
, wxT("invalid item in wxMenu::Insert") );
157 if ( pos
== GetMenuItemCount() )
159 return DoAppend(item
);
163 wxCHECK_MSG( pos
< GetMenuItemCount(), FALSE
,
164 wxT("invalid index in wxMenu::Insert") );
166 return DoInsert(pos
, item
);
170 bool wxMenuBase::DoInsert(size_t pos
, wxMenuItem
*item
)
172 wxCHECK_MSG( item
, FALSE
, wxT("invalid item in wxMenu::Insert()") );
174 wxMenuItemList::Node
*node
= m_items
.Item(pos
);
175 wxCHECK_MSG( node
, FALSE
, wxT("invalid index in wxMenu::Insert()") );
177 m_items
.Insert(node
, item
);
182 wxMenuItem
*wxMenuBase::Remove(wxMenuItem
*item
)
184 wxCHECK_MSG( item
, NULL
, wxT("invalid item in wxMenu::Remove") );
186 return DoRemove(item
);
189 wxMenuItem
*wxMenuBase::DoRemove(wxMenuItem
*item
)
191 wxMenuItemList::Node
*node
= m_items
.Find(item
);
193 // if we get here, the item is valid or one of Remove() functions is broken
194 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
196 // we detach the item, but we do delete the list node (i.e. don't call
197 // DetachNode() here!)
198 node
->SetData((wxMenuItem
*)NULL
); // to prevent it from deleting the item
199 m_items
.DeleteNode(node
);
201 // item isn't attached to anything any more
202 wxMenu
*submenu
= item
->GetSubMenu();
205 submenu
->SetParent((wxMenu
*)NULL
);
211 bool wxMenuBase::Delete(wxMenuItem
*item
)
213 wxCHECK_MSG( item
, NULL
, wxT("invalid item in wxMenu::Delete") );
215 return DoDelete(item
);
218 bool wxMenuBase::DoDelete(wxMenuItem
*item
)
220 wxMenuItem
*item2
= DoRemove(item
);
221 wxCHECK_MSG( item2
, FALSE
, wxT("failed to delete menu item") );
223 // don't delete the submenu
224 item2
->SetSubMenu((wxMenu
*)NULL
);
231 bool wxMenuBase::Destroy(wxMenuItem
*item
)
233 wxCHECK_MSG( item
, NULL
, wxT("invalid item in wxMenu::Destroy") );
235 return DoDestroy(item
);
238 bool wxMenuBase::DoDestroy(wxMenuItem
*item
)
240 wxMenuItem
*item2
= DoRemove(item
);
241 wxCHECK_MSG( item2
, FALSE
, wxT("failed to delete menu item") );
248 // ----------------------------------------------------------------------------
249 // wxMenu searching for items
250 // ----------------------------------------------------------------------------
252 // Finds the item id matching the given string, -1 if not found.
253 int wxMenuBase::FindItem(const wxString
& text
) const
255 wxString label
= wxMenuItem::GetLabelFromText(text
);
256 for ( wxMenuItemList::Node
*node
= m_items
.GetFirst();
258 node
= node
->GetNext() )
260 wxMenuItem
*item
= node
->GetData();
261 if ( item
->IsSubMenu() )
263 int rc
= item
->GetSubMenu()->FindItem(label
);
264 if ( rc
!= wxNOT_FOUND
)
267 else if ( !item
->IsSeparator() )
269 if ( item
->GetLabel() == label
)
270 return item
->GetId();
277 // recursive search for item by id
278 wxMenuItem
*wxMenuBase::FindItem(int itemId
, wxMenu
**itemMenu
) const
283 wxMenuItem
*item
= NULL
;
284 for ( wxMenuItemList::Node
*node
= m_items
.GetFirst();
286 node
= node
->GetNext() )
288 item
= node
->GetData();
290 if ( item
->GetId() == itemId
)
293 *itemMenu
= (wxMenu
*)this;
295 else if ( item
->IsSubMenu() )
297 item
= item
->GetSubMenu()->FindItem(itemId
, itemMenu
);
301 // don't exit the loop
309 // non recursive search
310 wxMenuItem
*wxMenuBase::FindChildItem(int id
, size_t *ppos
) const
312 wxMenuItem
*item
= (wxMenuItem
*)NULL
;
313 wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
316 for ( pos
= 0; node
; pos
++ )
318 if ( node
->GetData()->GetId() == id
)
320 item
= node
->GetData();
325 node
= node
->GetNext();
330 *ppos
= item
? pos
: (size_t)wxNOT_FOUND
;
336 // ----------------------------------------------------------------------------
338 // ----------------------------------------------------------------------------
340 // Update a menu and all submenus recursively. source is the object that has
341 // the update event handlers defined for it. If NULL, the menu or associated
342 // window will be used.
343 void wxMenuBase::UpdateUI(wxEvtHandler
* source
)
345 if ( !source
&& GetInvokingWindow() )
346 source
= GetInvokingWindow()->GetEventHandler();
348 source
= GetEventHandler();
352 wxMenuItemList::Node
* node
= GetMenuItems().GetFirst();
355 wxMenuItem
* item
= node
->GetData();
356 if ( !item
->IsSeparator() )
358 wxWindowID id
= item
->GetId();
359 wxUpdateUIEvent
event(id
);
360 event
.SetEventObject( source
);
362 if ( source
->ProcessEvent(event
) )
364 // if anything changed, update the chanegd attribute
365 if (event
.GetSetText())
366 SetLabel(id
, event
.GetText());
367 if (event
.GetSetChecked())
368 Check(id
, event
.GetChecked());
369 if (event
.GetSetEnabled())
370 Enable(id
, event
.GetEnabled());
373 // recurse to the submenus
374 if ( item
->GetSubMenu() )
375 item
->GetSubMenu()->UpdateUI(source
);
377 //else: item is a separator (which don't process update UI events)
379 node
= node
->GetNext();
383 // ----------------------------------------------------------------------------
384 // wxMenu functions forwarded to wxMenuItem
385 // ----------------------------------------------------------------------------
387 void wxMenuBase::Enable( int id
, bool enable
)
389 wxMenuItem
*item
= FindItem(id
);
391 wxCHECK_RET( item
, wxT("wxMenu::Enable: no such item") );
393 item
->Enable(enable
);
396 bool wxMenuBase::IsEnabled( int id
) const
398 wxMenuItem
*item
= FindItem(id
);
400 wxCHECK_MSG( item
, FALSE
, wxT("wxMenu::IsEnabled: no such item") );
402 return item
->IsEnabled();
405 void wxMenuBase::Check( int id
, bool enable
)
407 wxMenuItem
*item
= FindItem(id
);
409 wxCHECK_RET( item
, wxT("wxMenu::Check: no such item") );
414 bool wxMenuBase::IsChecked( int id
) const
416 wxMenuItem
*item
= FindItem(id
);
418 wxCHECK_MSG( item
, FALSE
, wxT("wxMenu::IsChecked: no such item") );
420 return item
->IsChecked();
423 void wxMenuBase::SetLabel( int id
, const wxString
&label
)
425 wxMenuItem
*item
= FindItem(id
);
427 wxCHECK_RET( item
, wxT("wxMenu::SetLabel: no such item") );
429 item
->SetText(label
);
432 wxString
wxMenuBase::GetLabel( int id
) const
434 wxMenuItem
*item
= FindItem(id
);
436 wxCHECK_MSG( item
, wxT(""), wxT("wxMenu::GetLabel: no such item") );
438 return item
->GetText();
441 void wxMenuBase::SetHelpString( int id
, const wxString
& helpString
)
443 wxMenuItem
*item
= FindItem(id
);
445 wxCHECK_RET( item
, wxT("wxMenu::SetHelpString: no such item") );
447 item
->SetHelp( helpString
);
450 wxString
wxMenuBase::GetHelpString( int id
) const
452 wxMenuItem
*item
= FindItem(id
);
454 wxCHECK_MSG( item
, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
456 return item
->GetHelp();
459 // ----------------------------------------------------------------------------
460 // wxMenuBarBase ctor and dtor
461 // ----------------------------------------------------------------------------
463 wxMenuBarBase::wxMenuBarBase()
465 // we own the menus when we get them
466 m_menus
.DeleteContents(TRUE
);
469 wxMenuBarBase::~wxMenuBarBase()
471 // nothing to do, the list will delete the menus because of the call to
472 // DeleteContents() above
475 // ----------------------------------------------------------------------------
476 // wxMenuBar item access: the base class versions manage m_menus list, the
477 // derived class should reflect the changes in the real menubar
478 // ----------------------------------------------------------------------------
480 wxMenu
*wxMenuBarBase::GetMenu(size_t pos
) const
482 wxMenuList::Node
*node
= m_menus
.Item(pos
);
483 wxCHECK_MSG( node
, NULL
, wxT("bad index in wxMenuBar::GetMenu()") );
485 return node
->GetData();
488 bool wxMenuBarBase::Append(wxMenu
*menu
, const wxString
& WXUNUSED(title
))
490 wxCHECK_MSG( menu
, FALSE
, wxT("can't append NULL menu") );
492 m_menus
.Append(menu
);
497 bool wxMenuBarBase::Insert(size_t pos
, wxMenu
*menu
,
498 const wxString
& title
)
500 if ( pos
== m_menus
.GetCount() )
502 return Append(menu
, title
);
506 wxCHECK_MSG( menu
, FALSE
, wxT("can't insert NULL menu") );
508 wxMenuList::Node
*node
= m_menus
.Item(pos
);
509 wxCHECK_MSG( node
, FALSE
, wxT("bad index in wxMenuBar::Insert()") );
511 m_menus
.Insert(node
, menu
);
517 wxMenu
*wxMenuBarBase::Replace(size_t pos
, wxMenu
*menu
,
518 const wxString
& WXUNUSED(title
))
520 wxCHECK_MSG( menu
, NULL
, wxT("can't insert NULL menu") );
522 wxMenuList::Node
*node
= m_menus
.Item(pos
);
523 wxCHECK_MSG( node
, NULL
, wxT("bad index in wxMenuBar::Replace()") );
525 wxMenu
*menuOld
= node
->GetData();
531 wxMenu
*wxMenuBarBase::Remove(size_t pos
)
533 wxMenuList::Node
*node
= m_menus
.Item(pos
);
534 wxCHECK_MSG( node
, NULL
, wxT("bad index in wxMenuBar::Remove()") );
536 node
= m_menus
.DetachNode(node
);
537 wxCHECK( node
, NULL
); // unexpected
538 wxMenu
*menu
= node
->GetData();
545 // ---------------------------------------------------------------------------
546 // wxMenuBar functions forwarded to wxMenuItem
547 // ---------------------------------------------------------------------------
549 void wxMenuBarBase::Enable(int id
, bool enable
)
551 wxMenuItem
*item
= FindItem(id
);
553 wxCHECK_RET( item
, wxT("attempt to enable an item which doesn't exist") );
555 item
->Enable(enable
);
558 void wxMenuBarBase::Check(int id
, bool check
)
560 wxMenuItem
*item
= FindItem(id
);
562 wxCHECK_RET( item
, wxT("attempt to check an item which doesn't exist") );
563 wxCHECK_RET( item
->IsCheckable(), wxT("attempt to check an uncheckable item") );
568 bool wxMenuBarBase::IsChecked(int id
) const
570 wxMenuItem
*item
= FindItem(id
);
572 wxCHECK_MSG( item
, FALSE
, wxT("wxMenuBar::IsChecked(): no such item") );
574 return item
->IsChecked();
577 bool wxMenuBarBase::IsEnabled(int id
) const
579 wxMenuItem
*item
= FindItem(id
);
581 wxCHECK_MSG( item
, FALSE
, wxT("wxMenuBar::IsEnabled(): no such item") );
583 return item
->IsEnabled();
586 void wxMenuBarBase::SetLabel(int id
, const wxString
& label
)
588 wxMenuItem
*item
= FindItem(id
);
590 wxCHECK_RET( item
, wxT("wxMenuBar::SetLabel(): no such item") );
592 item
->SetText(label
);
595 wxString
wxMenuBarBase::GetLabel(int id
) const
597 wxMenuItem
*item
= FindItem(id
);
599 wxCHECK_MSG( item
, wxEmptyString
,
600 wxT("wxMenuBar::GetLabel(): no such item") );
602 return item
->GetText();
605 void wxMenuBarBase::SetHelpString(int id
, const wxString
& helpString
)
607 wxMenuItem
*item
= FindItem(id
);
609 wxCHECK_RET( item
, wxT("wxMenuBar::SetHelpString(): no such item") );
611 item
->SetHelp(helpString
);
614 wxString
wxMenuBarBase::GetHelpString(int id
) const
616 wxMenuItem
*item
= FindItem(id
);
618 wxCHECK_MSG( item
, wxEmptyString
,
619 wxT("wxMenuBar::GetHelpString(): no such item") );
621 return item
->GetHelp();