1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "menu.h"
12 #pragma implementation "menuitem.h"
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
27 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
29 wxMenuBar::wxMenuBar( long style
)
31 m_needParent
= FALSE
; // hmmm
33 PreCreation( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, "menu" );
35 m_menus
.DeleteContents( TRUE
);
37 m_menubar
= gtk_menu_bar_new();
39 if (style
& wxMB_DOCKABLE
)
41 m_widget
= gtk_handle_box_new();
42 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
43 gtk_widget_show( GTK_WIDGET(m_menubar
) );
47 m_widget
= GTK_WIDGET(m_menubar
);
55 wxMenuBar::wxMenuBar()
57 m_needParent
= FALSE
; // hmmm
59 PreCreation( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, "menu" );
61 m_menus
.DeleteContents( TRUE
);
63 m_menubar
= gtk_menu_bar_new();
65 m_widget
= GTK_WIDGET(m_menubar
);
72 void wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
74 m_menus
.Append( menu
);
75 wxString title2
= title
;
80 pos
= title2
.First( '&' );
81 if (pos
!= wxNOT_FOUND
)
82 title2
.Remove( pos
, 1 );
83 } while (pos
!= wxNOT_FOUND
);
85 menu
->SetTitle(title2
);
87 menu
->m_owner
= gtk_menu_item_new_with_label( WXSTRINGCAST(title2
) );
88 gtk_widget_show( menu
->m_owner
);
89 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
91 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
94 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
96 if (menu
->GetTitle() == menuString
)
98 int res
= menu
->FindItem( itemString
);
99 if (res
!= wxNOT_FOUND
)
103 wxNode
*node
= ((wxMenu
*)menu
)->GetItems().First(); // const_cast
106 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
107 if (item
->IsSubMenu())
108 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
116 wxMenuItem
*wxMenuBar::FindItemForId(int itemId
, wxMenu
**menuForItem
= NULL
) const
120 // TODO return the pointer to the menu
125 return FindItem(itemId
);
128 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
130 wxNode
*node
= m_menus
.First();
133 wxMenu
*menu
= (wxMenu
*)node
->Data();
134 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
135 if (res
!= -1) return res
;
141 // Find a wxMenuItem using its id. Recurses down into sub-menus
142 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
144 wxMenuItem
* result
= menu
->FindItem(id
);
146 wxNode
*node
= ((wxMenu
*)menu
)->GetItems().First(); // const_cast
147 while ( node
&& result
== NULL
)
149 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
150 if (item
->IsSubMenu())
152 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
160 wxMenuItem
* wxMenuBar::FindItem( int id
) const
162 wxMenuItem
* result
= 0;
163 wxNode
*node
= m_menus
.First();
164 while (node
&& result
== 0)
166 wxMenu
*menu
= (wxMenu
*)node
->Data();
167 result
= FindMenuItemByIdRecursive( menu
, id
);
174 void wxMenuBar::Check( int id
, bool check
)
176 wxMenuItem
* item
= FindMenuItemById( id
);
178 wxCHECK_RET( item
, "wxMenuBar::Check: no such item" );
183 bool wxMenuBar::IsChecked( int id
) const
185 wxMenuItem
* item
= FindMenuItemById( id
);
187 wxCHECK_MSG( item
, FALSE
, "wxMenuBar::IsChecked: no such item" );
189 return item
->IsChecked();
192 void wxMenuBar::Enable( int id
, bool enable
)
194 wxMenuItem
* item
= FindMenuItemById( id
);
196 wxCHECK_RET( item
, "wxMenuBar::Enable: no such item" );
198 item
->Enable(enable
);
201 bool wxMenuBar::IsEnabled( int id
) const
203 wxMenuItem
* item
= FindMenuItemById( id
);
205 wxCHECK_MSG( item
, FALSE
, "wxMenuBar::IsEnabled: no such item" );
207 return item
->IsEnabled();
210 wxString
wxMenuBar::GetLabel( int id
) const
212 wxMenuItem
* item
= FindMenuItemById( id
);
214 wxCHECK_MSG( item
, "", "wxMenuBar::GetLabel: no such item" );
216 return item
->GetText();
219 void wxMenuBar::SetLabel( int id
, const wxString
&label
)
221 wxMenuItem
* item
= FindMenuItemById( id
);
223 wxCHECK_RET( item
, "wxMenuBar::SetLabel: no such item" );
225 item
->SetText( label
);
228 void wxMenuBar::EnableTop( int pos
, bool flag
)
230 wxNode
*node
= m_menus
.Nth( pos
);
232 wxCHECK_RET( node
, "menu not found" );
234 wxMenu
* menu
= (wxMenu
*)node
->Data();
237 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
240 wxString
wxMenuBar::GetLabelTop( int pos
) const
242 wxNode
*node
= m_menus
.Nth( pos
);
244 wxCHECK_MSG( node
, "invalid", "menu not found" );
246 wxMenu
* menu
= (wxMenu
*)node
->Data();
248 return menu
->GetTitle();
251 void wxMenuBar::SetLabelTop( int pos
, const wxString
& label
)
253 wxNode
*node
= m_menus
.Nth( pos
);
255 wxCHECK_RET( node
, "menu not found" );
257 wxMenu
* menu
= (wxMenu
*)node
->Data();
259 menu
->SetTitle( label
);
262 void wxMenuBar::SetHelpString( int id
, const wxString
& helpString
)
264 wxMenuItem
* item
= FindMenuItemById( id
);
266 wxCHECK_RET( item
, "wxMenuBar::SetHelpString: no such item" );
268 item
->SetHelp( helpString
);
271 wxString
wxMenuBar::GetHelpString( int id
) const
273 wxMenuItem
* item
= FindMenuItemById( id
);
275 wxCHECK_MSG( item
, "", "wxMenuBar::GetHelpString: no such item" );
277 return item
->GetHelp();
280 //-----------------------------------------------------------------------------
282 //-----------------------------------------------------------------------------
284 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
286 int id
= menu
->FindMenuIdByMenuItem(widget
);
288 /* should find it for normal (not popup) menu */
289 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
291 if (!menu
->IsEnabled(id
))
294 wxMenuItem
* item
= menu
->FindItem( id
);
295 wxCHECK_RET( item
, "error in menu item callback" );
297 if (item
->IsCheckable())
299 if (item
->GetCheckedFlag() == item
->IsChecked())
301 /* the menu item has been checked by calling wxMenuItem->Check() */
306 /* the user pressed on the menu item -> report */
307 item
->SetCheckedFlag(item
->IsChecked()); /* make consistent again */
311 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
312 event
.SetEventObject( menu
);
315 if (menu
->GetCallback())
317 (void) (*(menu
->GetCallback())) (*menu
, event
);
321 if (menu
->GetEventHandler()->ProcessEvent(event
))
324 wxWindow
*win
= menu
->GetInvokingWindow();
326 win
->GetEventHandler()->ProcessEvent( event
);
329 //-----------------------------------------------------------------------------
331 //-----------------------------------------------------------------------------
333 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
335 int id
= menu
->FindMenuIdByMenuItem(widget
);
337 wxASSERT( id
!= -1 ); // should find it!
339 if (!menu
->IsEnabled(id
))
342 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
343 event
.SetEventObject( menu
);
345 /* wxMSW doesn't call callback here either
347 if (menu->m_callback)
349 (void) (*(menu->m_callback)) (*menu, event);
354 if (menu
->GetEventHandler()->ProcessEvent(event
))
357 wxWindow
*win
= menu
->GetInvokingWindow();
358 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
361 //-----------------------------------------------------------------------------
363 //-----------------------------------------------------------------------------
365 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
367 int id
= menu
->FindMenuIdByMenuItem(widget
);
369 wxASSERT( id
!= -1 ); // should find it!
371 if (!menu
->IsEnabled(id
))
374 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
375 event
.SetEventObject( menu
);
377 if (menu
->GetEventHandler()->ProcessEvent(event
))
380 wxWindow
*win
= menu
->GetInvokingWindow();
382 win
->GetEventHandler()->ProcessEvent( event
);
385 //-----------------------------------------------------------------------------
387 //-----------------------------------------------------------------------------
389 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
,wxObject
)
391 wxMenuItem::wxMenuItem()
394 m_isCheckMenu
= FALSE
;
397 m_subMenu
= (wxMenu
*) NULL
;
398 m_menuItem
= (GtkWidget
*) NULL
;
401 // it's valid for this function to be called even if m_menuItem == NULL
402 void wxMenuItem::SetName( const wxString
& str
)
405 for ( const char *pc
= str
; *pc
!= '\0'; pc
++ )
407 if (*pc
== '&') pc
++; /* skip it */
413 GtkLabel
*label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
414 gtk_label_set( label
, m_text
.c_str());
418 void wxMenuItem::Check( bool check
)
420 wxCHECK_RET( m_menuItem
, "invalid menu item" );
422 wxCHECK_RET( IsCheckable(), "Can't check uncheckable item!" )
424 if (check
== m_isChecked
) return;
427 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
430 void wxMenuItem::Enable( bool enable
)
432 wxCHECK_RET( m_menuItem
, "invalid menu item" );
434 gtk_widget_set_sensitive( m_menuItem
, enable
);
435 m_isEnabled
= enable
;
438 bool wxMenuItem::IsChecked() const
440 wxCHECK_MSG( m_menuItem
, FALSE
, "invalid menu item" );
442 wxCHECK( IsCheckable(), FALSE
); // can't get state of uncheckable item!
444 bool bIsChecked
= ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
449 //-----------------------------------------------------------------------------
451 //-----------------------------------------------------------------------------
453 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
455 wxMenu::wxMenu( const wxString
& title
, const wxFunction func
)
458 m_items
.DeleteContents( TRUE
);
459 m_invokingWindow
= (wxWindow
*) NULL
;
460 m_menu
= gtk_menu_new(); // Do not show!
463 m_eventHandler
= this;
464 m_clientData
= (void*) NULL
;
466 if (m_title
.IsNull()) m_title
= "";
473 m_owner
= (GtkWidget
*) NULL
;
476 void wxMenu::SetTitle( const wxString
& title
)
478 // TODO Waiting for something better
482 const wxString
wxMenu::GetTitle() const
487 void wxMenu::AppendSeparator()
489 wxMenuItem
*mitem
= new wxMenuItem();
490 mitem
->SetId(ID_SEPARATOR
);
492 GtkWidget
*menuItem
= gtk_menu_item_new();
493 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
494 gtk_widget_show( menuItem
);
495 mitem
->SetMenuItem(menuItem
);
496 m_items
.Append( mitem
);
499 void wxMenu::Append( int id
, const wxString
&item
, const wxString
&helpStr
, bool checkable
)
501 wxMenuItem
*mitem
= new wxMenuItem();
503 mitem
->SetText(item
);
504 mitem
->SetHelp(helpStr
);
505 mitem
->SetCheckable(checkable
);
506 const char *text
= mitem
->GetText();
507 GtkWidget
*menuItem
= checkable
? gtk_check_menu_item_new_with_label(text
)
508 : gtk_menu_item_new_with_label(text
);
510 mitem
->SetMenuItem(menuItem
);
512 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
513 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
516 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
517 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
520 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
521 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
524 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
525 gtk_widget_show( menuItem
);
526 m_items
.Append( mitem
);
529 void wxMenu::Append( int id
, const wxString
&text
, wxMenu
*subMenu
, const wxString
&helpStr
)
531 wxMenuItem
*mitem
= new wxMenuItem();
533 mitem
->SetText(text
);
534 mitem
->SetHelp(helpStr
);
536 GtkWidget
*menuItem
= gtk_menu_item_new_with_label(mitem
->GetText());
537 mitem
->SetMenuItem(menuItem
);
538 mitem
->SetSubMenu(subMenu
);
540 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
541 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
544 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
545 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
548 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), subMenu
->m_menu
);
549 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
550 gtk_widget_show( menuItem
);
551 m_items
.Append( mitem
);
554 void wxMenu::Append( wxMenuItem
*item
)
556 m_items
.Append( item
);
558 GtkWidget
*menuItem
= (GtkWidget
*) NULL
;
560 if (item
->IsSeparator())
561 menuItem
= gtk_menu_item_new();
562 else if (item
->IsSubMenu())
563 menuItem
= gtk_menu_item_new_with_label(item
->GetText());
565 menuItem
= item
->IsCheckable() ? gtk_check_menu_item_new_with_label(item
->GetText())
566 : gtk_menu_item_new_with_label(item
->GetText());
568 if (!item
->IsSeparator())
570 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
571 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
574 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
575 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
578 if (!item
->IsSubMenu())
580 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
581 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
586 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
587 gtk_widget_show( menuItem
);
588 item
->SetMenuItem(menuItem
);
591 int wxMenu::FindItem( const wxString itemString
) const
593 wxString
s( itemString
);
598 pos
= s
.First( '&' );
599 if (pos
!= -1) s
.Remove( pos
, 1 );
602 wxNode
*node
= m_items
.First();
605 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
606 if (item
->GetText() == s
)
608 return item
->GetId();
616 void wxMenu::Enable( int id
, bool enable
)
618 wxMenuItem
*item
= FindItem(id
);
620 wxCHECK_RET( item
, "wxMenu::Enable: no such item" );
622 item
->Enable(enable
);
625 bool wxMenu::IsEnabled( int id
) const
627 wxMenuItem
*item
= FindItem(id
);
629 wxCHECK_MSG( item
, FALSE
, "wxMenu::IsEnabled: no such item" );
631 return item
->IsEnabled();
634 void wxMenu::Check( int id
, bool enable
)
636 wxMenuItem
*item
= FindItem(id
);
638 wxCHECK_RET( item
, "wxMenu::Check: no such item" );
643 bool wxMenu::IsChecked( int id
) const
645 wxMenuItem
*item
= FindItem(id
);
647 wxCHECK_MSG( item
, FALSE
, "wxMenu::IsChecked: no such item" );
649 return item
->IsChecked();
652 void wxMenu::SetLabel( int id
, const wxString
&label
)
654 wxMenuItem
*item
= FindItem(id
);
656 wxCHECK_RET( item
, "wxMenu::SetLabel: no such item" );
658 item
->SetText(label
);
661 wxString
wxMenu::GetLabel( int id
) const
663 wxMenuItem
*item
= FindItem(id
);
665 wxCHECK_MSG( item
, "", "wxMenu::GetLabel: no such item" );
667 return item
->GetText();
670 void wxMenu::SetHelpString( int id
, const wxString
& helpString
)
672 wxMenuItem
*item
= FindItem(id
);
674 wxCHECK_RET( item
, "wxMenu::SetHelpString: no such item" );
676 item
->SetHelp( helpString
);
679 wxString
wxMenu::GetHelpString( int id
) const
681 wxMenuItem
*item
= FindItem(id
);
683 wxCHECK_MSG( item
, "", "wxMenu::GetHelpString: no such item" );
685 return item
->GetHelp();
688 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
690 wxNode
*node
= m_items
.First();
693 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
694 if (item
->GetMenuItem() == menuItem
)
695 return item
->GetId();
702 wxMenuItem
*wxMenu::FindItem(int id
) const
704 wxNode
*node
= m_items
.First();
707 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
708 if (item
->GetId() == id
)
715 /* Not finding anything here can be correct
716 * when search the entire menu system for
717 * an entry -> no error message. */
719 return (wxMenuItem
*) NULL
;
722 void wxMenu::SetInvokingWindow( wxWindow
*win
)
724 m_invokingWindow
= win
;
727 wxWindow
*wxMenu::GetInvokingWindow()
729 return m_invokingWindow
;
732 // Update a menu and all submenus recursively. source is the object that has
733 // the update event handlers defined for it. If NULL, the menu or associated
734 // window will be used.
735 void wxMenu::UpdateUI(wxEvtHandler
* source
)
737 if (!source
&& GetInvokingWindow())
738 source
= GetInvokingWindow()->GetEventHandler();
740 source
= GetEventHandler();
744 wxNode
* node
= GetItems().First();
747 wxMenuItem
* item
= (wxMenuItem
*) node
->Data();
748 if ( !item
->IsSeparator() )
750 wxWindowID id
= item
->GetId();
751 wxUpdateUIEvent
event(id
);
752 event
.SetEventObject( source
);
754 if (source
->ProcessEvent(event
))
756 if (event
.GetSetText())
757 SetLabel(id
, event
.GetText());
758 if (event
.GetSetChecked())
759 Check(id
, event
.GetChecked());
760 if (event
.GetSetEnabled())
761 Enable(id
, event
.GetEnabled());
764 if (item
->GetSubMenu())
765 item
->GetSubMenu()->UpdateUI(source
);