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 extern void wxapp_install_idle_handler();
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
34 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
36 wxMenuBar::wxMenuBar( long style
)
38 /* the parent window is known after wxFrame::SetMenu() */
41 m_invokingWindow
= (wxWindow
*) NULL
;
43 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
44 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
46 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
50 m_menus
.DeleteContents( TRUE
);
52 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
53 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
54 m_accel
= gtk_accel_group_new();
55 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
56 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
58 m_menubar
= gtk_menu_bar_new();
61 if (style
& wxMB_DOCKABLE
)
63 m_widget
= gtk_handle_box_new();
64 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
65 gtk_widget_show( GTK_WIDGET(m_menubar
) );
69 m_widget
= GTK_WIDGET(m_menubar
);
75 wxMenuBar::wxMenuBar()
77 /* the parent window is known after wxFrame::SetMenu() */
80 m_invokingWindow
= (wxWindow
*) NULL
;
82 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
83 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
85 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
89 m_menus
.DeleteContents( TRUE
);
91 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
92 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
93 m_accel
= gtk_accel_group_new();
94 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
95 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
97 m_menubar
= gtk_menu_bar_new();
100 m_widget
= GTK_WIDGET(m_menubar
);
105 wxMenuBar::~wxMenuBar()
107 // gtk_object_unref( GTK_OBJECT(m_factory) ); why not ?
110 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
112 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
114 #if (GTK_MINOR_VERSION > 0)
115 wxWindow
*top_frame
= win
;
116 while (top_frame
->GetParent()) top_frame
= top_frame
->GetParent();
118 /* support for native hot keys */
119 gtk_accel_group_detach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
122 wxNode
*node
= menu
->GetItems().First();
125 wxMenuItem
*menuitem
= (wxMenuItem
*)node
->Data();
126 if (menuitem
->IsSubMenu())
127 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
132 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
134 menu
->SetInvokingWindow( win
);
136 #if (GTK_MINOR_VERSION > 0)
137 wxWindow
*top_frame
= win
;
138 while (top_frame
->GetParent())
139 top_frame
= top_frame
->GetParent();
141 /* support for native hot keys */
142 gtk_accel_group_attach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
145 wxNode
*node
= menu
->GetItems().First();
148 wxMenuItem
*menuitem
= (wxMenuItem
*)node
->Data();
149 if (menuitem
->IsSubMenu())
150 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
155 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
157 m_invokingWindow
= win
;
158 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
159 wxWindow
*top_frame
= win
;
160 while (top_frame
->GetParent())
161 top_frame
= top_frame
->GetParent();
163 /* support for native key accelerators indicated by underscroes */
164 gtk_accel_group_attach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
167 wxNode
*node
= m_menus
.First();
170 wxMenu
*menu
= (wxMenu
*)node
->Data();
171 wxMenubarSetInvokingWindow( menu
, win
);
176 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
178 m_invokingWindow
= (wxWindow
*) NULL
;
179 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
180 wxWindow
*top_frame
= win
;
181 while (top_frame
->GetParent())
182 top_frame
= top_frame
->GetParent();
184 /* support for native key accelerators indicated by underscroes */
185 gtk_accel_group_detach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
188 wxNode
*node
= m_menus
.First();
191 wxMenu
*menu
= (wxMenu
*)node
->Data();
192 wxMenubarUnsetInvokingWindow( menu
, win
);
197 void wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
199 m_menus
.Append( menu
);
203 /* GTK 1.2 wants to have "_" instead of "&" for accelerators */
205 for ( pc
= title
; *pc
!= wxT('\0'); pc
++ )
209 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
212 else if (*pc
== wxT('/'))
220 if ( *pc
== wxT('_') )
222 // underscores must be doubled to prevent them from being
223 // interpreted as accelerator character prefix by GTK
232 /* this doesn't have much effect right now */
233 menu
->SetTitle( str
);
235 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
236 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
238 /* local buffer in multibyte form */
240 buf
<< wxT('/') << str
.c_str();
242 char *cbuf
= new char[buf
.Length()+1];
243 strcpy(cbuf
, buf
.mbc_str());
245 GtkItemFactoryEntry entry
;
246 entry
.path
= (gchar
*)cbuf
; // const_cast
247 entry
.accelerator
= (gchar
*) NULL
;
248 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
249 entry
.callback_action
= 0;
250 entry
.item_type
= "<Branch>";
252 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
253 /* in order to get the pointer to the item we need the item text _without_ underscores */
254 wxString tmp
= wxT("<main>/");
255 for ( pc
= str
; *pc
!= wxT('\0'); pc
++ )
257 // contrary to the common sense, we must throw out _all_ underscores,
258 // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we
259 // might naively think). IMHO it's a bug in GTK+ (VZ)
260 while (*pc
== wxT('_'))
264 menu
->m_owner
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() );
265 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
269 menu
->m_owner
= gtk_menu_item_new_with_label( str
.mb_str() );
270 gtk_widget_show( menu
->m_owner
);
271 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
273 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
277 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
278 // adding menu later on.
279 if (m_invokingWindow
)
280 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
283 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
285 if (menu
->GetTitle() == menuString
)
287 int res
= menu
->FindItem( itemString
);
288 if (res
!= wxNOT_FOUND
)
292 wxNode
*node
= ((wxMenu
*)menu
)->GetItems().First(); // const_cast
295 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
296 if (item
->IsSubMenu())
297 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
305 wxMenuItem
*wxMenuBar::FindItemForId(int itemId
, wxMenu
**menuForItem
) const
309 // TODO return the pointer to the menu
314 return FindItem(itemId
);
317 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
319 wxNode
*node
= m_menus
.First();
322 wxMenu
*menu
= (wxMenu
*)node
->Data();
323 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
324 if (res
!= -1) return res
;
330 // Find a wxMenuItem using its id. Recurses down into sub-menus
331 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
333 wxMenuItem
* result
= menu
->FindItem(id
);
335 wxNode
*node
= ((wxMenu
*)menu
)->GetItems().First(); // const_cast
336 while ( node
&& result
== NULL
)
338 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
339 if (item
->IsSubMenu())
341 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
349 wxMenuItem
* wxMenuBar::FindItem( int id
) const
351 wxMenuItem
* result
= 0;
352 wxNode
*node
= m_menus
.First();
353 while (node
&& result
== 0)
355 wxMenu
*menu
= (wxMenu
*)node
->Data();
356 result
= FindMenuItemByIdRecursive( menu
, id
);
363 void wxMenuBar::Check( int id
, bool check
)
365 wxMenuItem
* item
= FindMenuItemById( id
);
367 wxCHECK_RET( item
, wxT("wxMenuBar::Check: no such item") );
372 bool wxMenuBar::IsChecked( int id
) const
374 wxMenuItem
* item
= FindMenuItemById( id
);
376 wxCHECK_MSG( item
, FALSE
, wxT("wxMenuBar::IsChecked: no such item") );
378 return item
->IsChecked();
381 void wxMenuBar::Enable( int id
, bool enable
)
383 wxMenuItem
* item
= FindMenuItemById( id
);
385 wxCHECK_RET( item
, wxT("wxMenuBar::Enable: no such item") );
387 item
->Enable(enable
);
390 bool wxMenuBar::IsEnabled( int id
) const
392 wxMenuItem
* item
= FindMenuItemById( id
);
394 wxCHECK_MSG( item
, FALSE
, wxT("wxMenuBar::IsEnabled: no such item") );
396 return item
->IsEnabled();
399 wxString
wxMenuBar::GetLabel( int id
) const
401 wxMenuItem
* item
= FindMenuItemById( id
);
403 wxCHECK_MSG( item
, wxT(""), wxT("wxMenuBar::GetLabel: no such item") );
405 return item
->GetText();
408 void wxMenuBar::SetLabel( int id
, const wxString
&label
)
410 wxMenuItem
* item
= FindMenuItemById( id
);
412 wxCHECK_RET( item
, wxT("wxMenuBar::SetLabel: no such item") );
414 item
->SetText( label
);
417 void wxMenuBar::EnableTop( int pos
, bool flag
)
419 wxNode
*node
= m_menus
.Nth( pos
);
421 wxCHECK_RET( node
, wxT("menu not found") );
423 wxMenu
* menu
= (wxMenu
*)node
->Data();
426 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
429 wxString
wxMenuBar::GetLabelTop( int pos
) const
431 wxNode
*node
= m_menus
.Nth( pos
);
433 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
435 wxMenu
* menu
= (wxMenu
*)node
->Data();
437 return menu
->GetTitle();
440 void wxMenuBar::SetLabelTop( int pos
, const wxString
& label
)
442 wxNode
*node
= m_menus
.Nth( pos
);
444 wxCHECK_RET( node
, wxT("menu not found") );
446 wxMenu
* menu
= (wxMenu
*)node
->Data();
448 menu
->SetTitle( label
);
451 void wxMenuBar::SetHelpString( int id
, const wxString
& helpString
)
453 wxMenuItem
* item
= FindMenuItemById( id
);
455 wxCHECK_RET( item
, wxT("wxMenuBar::SetHelpString: no such item") );
457 item
->SetHelp( helpString
);
460 wxString
wxMenuBar::GetHelpString( int id
) const
462 wxMenuItem
* item
= FindMenuItemById( id
);
464 wxCHECK_MSG( item
, wxT(""), wxT("wxMenuBar::GetHelpString: no such item") );
466 return item
->GetHelp();
469 //-----------------------------------------------------------------------------
471 //-----------------------------------------------------------------------------
473 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
475 if (g_isIdle
) wxapp_install_idle_handler();
477 int id
= menu
->FindMenuIdByMenuItem(widget
);
479 /* should find it for normal (not popup) menu */
480 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
482 if (!menu
->IsEnabled(id
))
485 wxMenuItem
* item
= menu
->FindItem( id
);
486 wxCHECK_RET( item
, wxT("error in menu item callback") );
488 if (item
->IsCheckable())
490 if (item
->GetCheckedFlag() == item
->IsChecked())
492 /* the menu item has been checked by calling wxMenuItem->Check() */
497 /* the user pressed on the menu item -> report */
498 item
->SetCheckedFlag(item
->IsChecked()); /* make consistent again */
502 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
503 event
.SetEventObject( menu
);
506 if (menu
->GetCallback())
508 (void) (*(menu
->GetCallback())) (*menu
, event
);
512 if (menu
->GetEventHandler()->ProcessEvent(event
))
515 wxWindow
*win
= menu
->GetInvokingWindow();
517 win
->GetEventHandler()->ProcessEvent( event
);
520 //-----------------------------------------------------------------------------
522 //-----------------------------------------------------------------------------
524 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
526 if (g_isIdle
) wxapp_install_idle_handler();
528 int id
= menu
->FindMenuIdByMenuItem(widget
);
530 wxASSERT( id
!= -1 ); // should find it!
532 if (!menu
->IsEnabled(id
))
535 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
536 event
.SetEventObject( menu
);
538 if (menu
->GetEventHandler()->ProcessEvent(event
))
541 wxWindow
*win
= menu
->GetInvokingWindow();
542 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
545 //-----------------------------------------------------------------------------
547 //-----------------------------------------------------------------------------
549 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
551 if (g_isIdle
) wxapp_install_idle_handler();
553 int id
= menu
->FindMenuIdByMenuItem(widget
);
555 wxASSERT( id
!= -1 ); // should find it!
557 if (!menu
->IsEnabled(id
))
560 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
561 event
.SetEventObject( menu
);
563 if (menu
->GetEventHandler()->ProcessEvent(event
))
566 wxWindow
*win
= menu
->GetInvokingWindow();
568 win
->GetEventHandler()->ProcessEvent( event
);
571 //-----------------------------------------------------------------------------
573 //-----------------------------------------------------------------------------
575 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
,wxObject
)
577 wxMenuItem::wxMenuItem()
580 m_isCheckMenu
= FALSE
;
583 m_subMenu
= (wxMenu
*) NULL
;
584 m_menuItem
= (GtkWidget
*) NULL
;
587 wxMenuItem::~wxMenuItem()
589 // don't delete menu items, the menus take care of that
592 // it's valid for this function to be called even if m_menuItem == NULL
593 void wxMenuItem::SetName( const wxString
& str
)
595 /* '\t' is the deliminator indicating a hot key */
597 const wxChar
*pc
= str
;
598 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
602 #if (GTK_MINOR_VERSION > 0)
605 else if ( *pc
== wxT('_') ) // escape underscores
609 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
611 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
618 /* only GTK 1.2 knows about hot keys */
620 #if (GTK_MINOR_VERSION > 0)
630 GtkLabel
*label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
631 gtk_label_set( label
, m_text
.mb_str());
635 void wxMenuItem::Check( bool check
)
637 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
639 wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") )
641 if (check
== m_isChecked
) return;
644 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
647 void wxMenuItem::Enable( bool enable
)
649 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
651 gtk_widget_set_sensitive( m_menuItem
, enable
);
652 m_isEnabled
= enable
;
655 bool wxMenuItem::IsChecked() const
657 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
659 wxCHECK( IsCheckable(), FALSE
); // can't get state of uncheckable item!
661 bool bIsChecked
= ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
666 //-----------------------------------------------------------------------------
668 //-----------------------------------------------------------------------------
670 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
673 wxMenu::Init( const wxString
& title
,
675 const wxFunction func
679 m_items
.DeleteContents( TRUE
);
680 m_invokingWindow
= (wxWindow
*) NULL
;
683 #if (GTK_MINOR_VERSION > 0)
684 m_accel
= gtk_accel_group_new();
685 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
686 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
688 m_menu
= gtk_menu_new(); // Do not show!
693 m_eventHandler
= this;
694 m_clientData
= (void*) NULL
;
696 if (m_title
.IsNull()) m_title
= wxT("");
697 if (m_title
!= wxT(""))
703 m_owner
= (GtkWidget
*) NULL
;
705 #if (GTK_MINOR_VERSION > 0)
706 /* Tearoffs are entries, just like separators. So if we want this
707 menu to be a tear-off one, we just append a tearoff entry
709 if(m_style
& wxMENU_TEAROFF
)
711 GtkItemFactoryEntry entry
;
712 entry
.path
= "/tearoff";
713 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
714 entry
.callback_action
= 0;
715 entry
.item_type
= "<Tearoff>";
716 entry
.accelerator
= (gchar
*) NULL
;
717 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
718 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
725 wxNode
*node
= m_items
.First();
728 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
729 wxMenu
*submenu
= item
->GetSubMenu();
735 gtk_widget_destroy( m_menu
);
737 gtk_object_unref( GTK_OBJECT(m_factory
) );
740 void wxMenu::SetTitle( const wxString
& title
)
742 // TODO Waiting for something better
746 const wxString
wxMenu::GetTitle() const
751 void wxMenu::AppendSeparator()
753 wxMenuItem
*mitem
= new wxMenuItem();
754 mitem
->SetId(ID_SEPARATOR
);
756 #if (GTK_MINOR_VERSION > 0)
757 GtkItemFactoryEntry entry
;
759 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
760 entry
.callback_action
= 0;
761 entry
.item_type
= "<Separator>";
762 entry
.accelerator
= (gchar
*) NULL
;
764 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
766 /* this will be wrong for more than one separator. do we care? */
767 GtkWidget
*menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
769 GtkWidget
*menuItem
= gtk_menu_item_new();
770 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
771 gtk_widget_show( menuItem
);
774 mitem
->SetMenuItem(menuItem
);
775 m_items
.Append( mitem
);
778 #if (GTK_MINOR_VERSION > 0)
779 static char* GetHotKey( const wxString
&hotkey
, char *hotbuf
)
781 if (hotkey
.IsEmpty()) return (char*) NULL
;
785 case wxT('a'): /* Alt */
787 case wxT('m'): /* Meta */
790 strcpy( hotbuf
, "<alt>" );
791 wxString last
= hotkey
.Right(1);
792 strcat( hotbuf
, last
.mb_str() );
795 case wxT('c'): /* Ctrl */
797 case wxT('s'): /* Strg, yeah man, I'm German */
800 strcpy( hotbuf
, "<control>" );
801 wxString last
= hotkey
.Right(1);
802 strcat( hotbuf
, last
.mb_str() );
805 case wxT('F'): /* function keys */
807 strcpy( hotbuf
, hotkey
.mb_str() );
818 void wxMenu::Append( int id
, const wxString
&item
, const wxString
&helpStr
, bool checkable
)
820 wxMenuItem
*mitem
= new wxMenuItem();
822 mitem
->SetText(item
);
823 mitem
->SetHelp(helpStr
);
824 mitem
->SetCheckable(checkable
);
826 #if (GTK_MINOR_VERSION > 0)
827 /* text has "_" instead of "&" after mitem->SetText() */
828 wxString
text( mitem
->GetText() );
830 /* local buffer in multibyte form */
833 strcat( buf
, text
.mb_str() );
835 GtkItemFactoryEntry entry
;
837 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
838 entry
.callback_action
= 0;
840 entry
.item_type
= "<CheckItem>";
842 entry
.item_type
= "<Item>";
845 entry
.accelerator
= GetHotKey( mitem
->GetHotKey(), hotbuf
);
847 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
849 /* in order to get the pointer to the item we need the item text _without_ underscores */
850 wxString s
= wxT("<main>/");
851 for ( const wxChar
*pc
= text
; *pc
!= wxT('\0'); pc
++ )
853 while (*pc
== wxT('_')) pc
++; /* skip it */
857 GtkWidget
*menuItem
= gtk_item_factory_get_widget( m_factory
, s
.mb_str() );
861 GtkWidget
*menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
862 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
864 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
865 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
868 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
869 gtk_widget_show( menuItem
);
873 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
874 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
877 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
878 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
881 mitem
->SetMenuItem(menuItem
);
883 m_items
.Append( mitem
);
886 void wxMenu::Append( int id
, const wxString
&item
, wxMenu
*subMenu
, const wxString
&helpStr
)
888 wxMenuItem
*mitem
= new wxMenuItem();
890 mitem
->SetText(item
);
891 mitem
->SetHelp(helpStr
);
893 #if (GTK_MINOR_VERSION > 0)
894 /* text has "_" instead of "&" after mitem->SetText() */
895 wxString
text( mitem
->GetText() );
897 /* local buffer in multibyte form */
900 strcat( buf
, text
.mb_str() );
902 GtkItemFactoryEntry entry
;
904 entry
.callback
= (GtkItemFactoryCallback
) 0;
905 entry
.callback_action
= 0;
906 entry
.item_type
= "<Branch>";
908 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
910 /* in order to get the pointer to the item we need the item text _without_ underscores */
911 wxString s
= wxT("<main>/");
912 for ( const wxChar
*pc
= text
; *pc
!= wxT('\0'); pc
++ )
914 if (*pc
== wxT('_')) pc
++; /* skip it */
918 GtkWidget
*menuItem
= gtk_item_factory_get_item( m_factory
, s
.mb_str() );
922 GtkWidget
*menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
924 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
925 gtk_widget_show( menuItem
);
929 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
930 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
933 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
934 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
937 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), subMenu
->m_menu
);
939 mitem
->SetMenuItem(menuItem
);
940 mitem
->SetSubMenu(subMenu
);
942 m_items
.Append( mitem
);
945 void wxMenu::Append( wxMenuItem
*item
)
947 m_items
.Append( item
);
949 GtkWidget
*menuItem
= (GtkWidget
*) NULL
;
951 if (item
->IsSeparator())
952 menuItem
= gtk_menu_item_new();
953 else if (item
->IsSubMenu())
954 menuItem
= gtk_menu_item_new_with_label(item
->GetText().mbc_str());
956 menuItem
= item
->IsCheckable() ? gtk_check_menu_item_new_with_label(item
->GetText().mbc_str())
957 : gtk_menu_item_new_with_label(item
->GetText().mbc_str());
959 if (!item
->IsSeparator())
961 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
962 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
965 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
966 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
969 if (!item
->IsSubMenu())
971 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
972 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
977 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
978 gtk_widget_show( menuItem
);
979 item
->SetMenuItem(menuItem
);
982 void wxMenu::Delete( int id
)
984 wxNode
*node
= m_items
.First();
987 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
988 if (item
->GetId() == id
)
990 gtk_widget_destroy( item
->GetMenuItem() );
991 m_items
.DeleteNode( node
);
998 int wxMenu::FindItem( const wxString itemString
) const
1000 wxString s
= wxT("");
1001 for ( const wxChar
*pc
= itemString
; *pc
!= wxT('\0'); pc
++ )
1003 if (*pc
== wxT('&'))
1006 #if (GTK_MINOR_VERSION > 0)
1013 wxNode
*node
= m_items
.First();
1016 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1017 if (item
->GetText() == s
)
1019 return item
->GetId();
1021 node
= node
->Next();
1027 void wxMenu::Enable( int id
, bool enable
)
1029 wxMenuItem
*item
= FindItem(id
);
1031 wxCHECK_RET( item
, wxT("wxMenu::Enable: no such item") );
1033 item
->Enable(enable
);
1036 bool wxMenu::IsEnabled( int id
) const
1038 wxMenuItem
*item
= FindItem(id
);
1040 wxCHECK_MSG( item
, FALSE
, wxT("wxMenu::IsEnabled: no such item") );
1042 return item
->IsEnabled();
1045 void wxMenu::Check( int id
, bool enable
)
1047 wxMenuItem
*item
= FindItem(id
);
1049 wxCHECK_RET( item
, wxT("wxMenu::Check: no such item") );
1051 item
->Check(enable
);
1054 bool wxMenu::IsChecked( int id
) const
1056 wxMenuItem
*item
= FindItem(id
);
1058 wxCHECK_MSG( item
, FALSE
, wxT("wxMenu::IsChecked: no such item") );
1060 return item
->IsChecked();
1063 void wxMenu::SetLabel( int id
, const wxString
&label
)
1065 wxMenuItem
*item
= FindItem(id
);
1067 wxCHECK_RET( item
, wxT("wxMenu::SetLabel: no such item") );
1069 item
->SetText(label
);
1072 wxString
wxMenu::GetLabel( int id
) const
1074 wxMenuItem
*item
= FindItem(id
);
1076 wxCHECK_MSG( item
, wxT(""), wxT("wxMenu::GetLabel: no such item") );
1078 return item
->GetText();
1081 void wxMenu::SetHelpString( int id
, const wxString
& helpString
)
1083 wxMenuItem
*item
= FindItem(id
);
1085 wxCHECK_RET( item
, wxT("wxMenu::SetHelpString: no such item") );
1087 item
->SetHelp( helpString
);
1090 wxString
wxMenu::GetHelpString( int id
) const
1092 wxMenuItem
*item
= FindItem(id
);
1094 wxCHECK_MSG( item
, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
1096 return item
->GetHelp();
1099 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1101 wxNode
*node
= m_items
.First();
1104 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1105 if (item
->GetMenuItem() == menuItem
)
1106 return item
->GetId();
1107 node
= node
->Next();
1113 wxMenuItem
*wxMenu::FindItem(int id
) const
1115 wxNode
*node
= m_items
.First();
1118 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1119 if (item
->GetId() == id
)
1123 node
= node
->Next();
1126 /* Not finding anything here can be correct
1127 * when search the entire menu system for
1128 * an entry -> no error message. */
1130 return (wxMenuItem
*) NULL
;
1133 void wxMenu::SetInvokingWindow( wxWindow
*win
)
1135 m_invokingWindow
= win
;
1138 wxWindow
*wxMenu::GetInvokingWindow()
1140 return m_invokingWindow
;
1143 // Update a menu and all submenus recursively. source is the object that has
1144 // the update event handlers defined for it. If NULL, the menu or associated
1145 // window will be used.
1146 void wxMenu::UpdateUI(wxEvtHandler
* source
)
1148 if (!source
&& GetInvokingWindow())
1149 source
= GetInvokingWindow()->GetEventHandler();
1151 source
= GetEventHandler();
1155 wxNode
* node
= GetItems().First();
1158 wxMenuItem
* item
= (wxMenuItem
*) node
->Data();
1159 if ( !item
->IsSeparator() )
1161 wxWindowID id
= item
->GetId();
1162 wxUpdateUIEvent
event(id
);
1163 event
.SetEventObject( source
);
1165 if (source
->ProcessEvent(event
))
1167 if (event
.GetSetText())
1168 SetLabel(id
, event
.GetText());
1169 if (event
.GetSetChecked())
1170 Check(id
, event
.GetChecked());
1171 if (event
.GetSetEnabled())
1172 Enable(id
, event
.GetEnabled());
1175 if (item
->GetSubMenu())
1176 item
->GetSubMenu()->UpdateUI(source
);
1178 node
= node
->Next();