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"
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 extern void wxapp_install_idle_handler();
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
38 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
40 wxMenuBar::wxMenuBar( long style
)
42 /* the parent window is known after wxFrame::SetMenu() */
45 m_invokingWindow
= (wxWindow
*) NULL
;
47 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
48 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
50 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
54 m_menus
.DeleteContents( TRUE
);
56 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
57 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
58 m_accel
= gtk_accel_group_new();
59 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
60 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
62 m_menubar
= gtk_menu_bar_new();
65 if (style
& wxMB_DOCKABLE
)
67 m_widget
= gtk_handle_box_new();
68 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
69 gtk_widget_show( GTK_WIDGET(m_menubar
) );
73 m_widget
= GTK_WIDGET(m_menubar
);
79 wxMenuBar::wxMenuBar()
81 /* the parent window is known after wxFrame::SetMenu() */
84 m_invokingWindow
= (wxWindow
*) NULL
;
86 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
87 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
89 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
93 m_menus
.DeleteContents( TRUE
);
95 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
96 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
97 m_accel
= gtk_accel_group_new();
98 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
99 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
101 m_menubar
= gtk_menu_bar_new();
104 m_widget
= GTK_WIDGET(m_menubar
);
109 wxMenuBar::~wxMenuBar()
111 // gtk_object_unref( GTK_OBJECT(m_factory) ); why not ?
114 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
116 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
118 #if (GTK_MINOR_VERSION > 0)
119 wxWindow
*top_frame
= win
;
120 while (top_frame
->GetParent() && !(top_frame
->GetParent()->m_isFrame
))
121 top_frame
= top_frame
->GetParent();
123 /* support for native hot keys */
124 gtk_accel_group_detach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
127 wxNode
*node
= menu
->GetItems().First();
130 wxMenuItem
*menuitem
= (wxMenuItem
*)node
->Data();
131 if (menuitem
->IsSubMenu())
132 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
137 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
139 menu
->SetInvokingWindow( win
);
141 #if (GTK_MINOR_VERSION > 0)
142 wxWindow
*top_frame
= win
;
143 while (top_frame
->GetParent() && !(top_frame
->GetParent()->m_isFrame
))
144 top_frame
= top_frame
->GetParent();
146 /* support for native hot keys */
147 gtk_accel_group_attach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
150 wxNode
*node
= menu
->GetItems().First();
153 wxMenuItem
*menuitem
= (wxMenuItem
*)node
->Data();
154 if (menuitem
->IsSubMenu())
155 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
160 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
162 m_invokingWindow
= win
;
163 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
164 wxWindow
*top_frame
= win
;
165 while (top_frame
->GetParent() && !(top_frame
->GetParent()->m_isFrame
))
166 top_frame
= top_frame
->GetParent();
168 /* support for native key accelerators indicated by underscroes */
169 gtk_accel_group_attach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
172 wxNode
*node
= m_menus
.First();
175 wxMenu
*menu
= (wxMenu
*)node
->Data();
176 wxMenubarSetInvokingWindow( menu
, win
);
181 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
183 m_invokingWindow
= (wxWindow
*) NULL
;
184 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
185 wxWindow
*top_frame
= win
;
186 while (top_frame
->GetParent() && !(top_frame
->GetParent()->m_isFrame
))
187 top_frame
= top_frame
->GetParent();
189 /* support for native key accelerators indicated by underscroes */
190 gtk_accel_group_detach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
193 wxNode
*node
= m_menus
.First();
196 wxMenu
*menu
= (wxMenu
*)node
->Data();
197 wxMenubarUnsetInvokingWindow( menu
, win
);
202 void wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
204 m_menus
.Append( menu
);
208 /* GTK 1.2 wants to have "_" instead of "&" for accelerators */
210 for ( pc
= title
; *pc
!= wxT('\0'); pc
++ )
214 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
217 else if (*pc
== wxT('/'))
225 if ( *pc
== wxT('_') )
227 // underscores must be doubled to prevent them from being
228 // interpreted as accelerator character prefix by GTK
237 /* this doesn't have much effect right now */
238 menu
->SetTitle( str
);
240 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
241 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
243 /* local buffer in multibyte form */
245 buf
<< wxT('/') << str
.c_str();
247 char *cbuf
= new char[buf
.Length()+1];
248 strcpy(cbuf
, buf
.mbc_str());
250 GtkItemFactoryEntry entry
;
251 entry
.path
= (gchar
*)cbuf
; // const_cast
252 entry
.accelerator
= (gchar
*) NULL
;
253 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
254 entry
.callback_action
= 0;
255 entry
.item_type
= "<Branch>";
257 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
258 /* in order to get the pointer to the item we need the item text _without_ underscores */
259 wxString tmp
= wxT("<main>/");
260 for ( pc
= str
; *pc
!= wxT('\0'); pc
++ )
262 // contrary to the common sense, we must throw out _all_ underscores,
263 // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we
264 // might naively think). IMHO it's a bug in GTK+ (VZ)
265 while (*pc
== wxT('_'))
269 menu
->m_owner
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() );
270 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
274 menu
->m_owner
= gtk_menu_item_new_with_label( str
.mb_str() );
275 gtk_widget_show( menu
->m_owner
);
276 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
278 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
282 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
283 // adding menu later on.
284 if (m_invokingWindow
)
285 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
288 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
290 if (menu
->GetTitle() == menuString
)
292 int res
= menu
->FindItem( itemString
);
293 if (res
!= wxNOT_FOUND
)
297 wxNode
*node
= ((wxMenu
*)menu
)->GetItems().First(); // const_cast
300 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
301 if (item
->IsSubMenu())
302 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
310 wxMenuItem
*wxMenuBar::FindItemForId(int itemId
, wxMenu
**menuForItem
) const
314 // TODO return the pointer to the menu
319 return FindItem(itemId
);
322 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
324 wxNode
*node
= m_menus
.First();
327 wxMenu
*menu
= (wxMenu
*)node
->Data();
328 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
329 if (res
!= -1) return res
;
335 // Find a wxMenuItem using its id. Recurses down into sub-menus
336 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
338 wxMenuItem
* result
= menu
->FindItem(id
);
340 wxNode
*node
= ((wxMenu
*)menu
)->GetItems().First(); // const_cast
341 while ( node
&& result
== NULL
)
343 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
344 if (item
->IsSubMenu())
346 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
354 wxMenuItem
* wxMenuBar::FindItem( int id
) const
356 wxMenuItem
* result
= 0;
357 wxNode
*node
= m_menus
.First();
358 while (node
&& result
== 0)
360 wxMenu
*menu
= (wxMenu
*)node
->Data();
361 result
= FindMenuItemByIdRecursive( menu
, id
);
368 void wxMenuBar::Check( int id
, bool check
)
370 wxMenuItem
* item
= FindMenuItemById( id
);
372 wxCHECK_RET( item
, wxT("wxMenuBar::Check: no such item") );
377 bool wxMenuBar::IsChecked( int id
) const
379 wxMenuItem
* item
= FindMenuItemById( id
);
381 wxCHECK_MSG( item
, FALSE
, wxT("wxMenuBar::IsChecked: no such item") );
383 return item
->IsChecked();
386 void wxMenuBar::Enable( int id
, bool enable
)
388 wxMenuItem
* item
= FindMenuItemById( id
);
390 wxCHECK_RET( item
, wxT("wxMenuBar::Enable: no such item") );
392 item
->Enable(enable
);
395 bool wxMenuBar::IsEnabled( int id
) const
397 wxMenuItem
* item
= FindMenuItemById( id
);
399 wxCHECK_MSG( item
, FALSE
, wxT("wxMenuBar::IsEnabled: no such item") );
401 return item
->IsEnabled();
404 wxString
wxMenuBar::GetLabel( int id
) const
406 wxMenuItem
* item
= FindMenuItemById( id
);
408 wxCHECK_MSG( item
, wxT(""), wxT("wxMenuBar::GetLabel: no such item") );
410 return item
->GetText();
413 void wxMenuBar::SetLabel( int id
, const wxString
&label
)
415 wxMenuItem
* item
= FindMenuItemById( id
);
417 wxCHECK_RET( item
, wxT("wxMenuBar::SetLabel: no such item") );
419 item
->SetText( label
);
422 void wxMenuBar::EnableTop( int pos
, bool flag
)
424 wxNode
*node
= m_menus
.Nth( pos
);
426 wxCHECK_RET( node
, wxT("menu not found") );
428 wxMenu
* menu
= (wxMenu
*)node
->Data();
431 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
434 wxString
wxMenuBar::GetLabelTop( int pos
) const
436 wxNode
*node
= m_menus
.Nth( pos
);
438 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
440 wxMenu
* menu
= (wxMenu
*)node
->Data();
442 return menu
->GetTitle();
445 void wxMenuBar::SetLabelTop( int pos
, const wxString
& label
)
447 wxNode
*node
= m_menus
.Nth( pos
);
449 wxCHECK_RET( node
, wxT("menu not found") );
451 wxMenu
* menu
= (wxMenu
*)node
->Data();
453 menu
->SetTitle( label
);
456 void wxMenuBar::SetHelpString( int id
, const wxString
& helpString
)
458 wxMenuItem
* item
= FindMenuItemById( id
);
460 wxCHECK_RET( item
, wxT("wxMenuBar::SetHelpString: no such item") );
462 item
->SetHelp( helpString
);
465 wxString
wxMenuBar::GetHelpString( int id
) const
467 wxMenuItem
* item
= FindMenuItemById( id
);
469 wxCHECK_MSG( item
, wxT(""), wxT("wxMenuBar::GetHelpString: no such item") );
471 return item
->GetHelp();
474 //-----------------------------------------------------------------------------
476 //-----------------------------------------------------------------------------
478 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
480 if (g_isIdle
) wxapp_install_idle_handler();
482 int id
= menu
->FindMenuIdByMenuItem(widget
);
484 /* should find it for normal (not popup) menu */
485 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
487 if (!menu
->IsEnabled(id
))
490 wxMenuItem
* item
= menu
->FindItem( id
);
491 wxCHECK_RET( item
, wxT("error in menu item callback") );
493 if (item
->IsCheckable())
495 bool isReallyChecked
= item
->IsChecked();
496 if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked
)
498 /* the menu item has been checked by calling wxMenuItem->Check() */
503 /* the user pressed on the menu item -> report and make consistent
505 item
->wxMenuItemBase::Check(isReallyChecked
);
509 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
510 event
.SetEventObject( menu
);
513 if (menu
->GetCallback())
515 (void) (*(menu
->GetCallback())) (*menu
, event
);
519 if (menu
->GetEventHandler()->ProcessEvent(event
))
522 wxWindow
*win
= menu
->GetInvokingWindow();
524 win
->GetEventHandler()->ProcessEvent( event
);
527 //-----------------------------------------------------------------------------
529 //-----------------------------------------------------------------------------
531 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
533 if (g_isIdle
) wxapp_install_idle_handler();
535 int id
= menu
->FindMenuIdByMenuItem(widget
);
537 wxASSERT( id
!= -1 ); // should find it!
539 if (!menu
->IsEnabled(id
))
542 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
543 event
.SetEventObject( menu
);
545 if (menu
->GetEventHandler()->ProcessEvent(event
))
548 wxWindow
*win
= menu
->GetInvokingWindow();
549 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
552 //-----------------------------------------------------------------------------
554 //-----------------------------------------------------------------------------
556 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
558 if (g_isIdle
) wxapp_install_idle_handler();
560 int id
= menu
->FindMenuIdByMenuItem(widget
);
562 wxASSERT( id
!= -1 ); // should find it!
564 if (!menu
->IsEnabled(id
))
567 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
568 event
.SetEventObject( menu
);
570 if (menu
->GetEventHandler()->ProcessEvent(event
))
573 wxWindow
*win
= menu
->GetInvokingWindow();
575 win
->GetEventHandler()->ProcessEvent( event
);
578 //-----------------------------------------------------------------------------
580 //-----------------------------------------------------------------------------
582 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxMenuItemBase
)
584 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
586 const wxString
& name
,
587 const wxString
& help
,
591 return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
);
594 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
596 const wxString
& text
,
597 const wxString
& help
,
602 m_isCheckable
= isCheckable
;
606 m_parentMenu
= parentMenu
;
609 m_menuItem
= (GtkWidget
*) NULL
;
611 // call it after initializing m_menuItem to NULL
615 wxMenuItem::~wxMenuItem()
617 // don't delete menu items, the menus take care of that
620 // it's valid for this function to be called even if m_menuItem == NULL
621 void wxMenuItem::DoSetText( const wxString
& str
)
623 /* '\t' is the deliminator indicating a hot key */
625 const wxChar
*pc
= str
;
626 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
630 #if (GTK_MINOR_VERSION > 0)
633 else if ( *pc
== wxT('_') ) // escape underscores
637 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
639 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
646 /* only GTK 1.2 knows about hot keys */
648 #if (GTK_MINOR_VERSION > 0)
658 GtkLabel
*label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
659 gtk_label_set( label
, m_text
.mb_str());
663 void wxMenuItem::Check( bool check
)
665 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
667 wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") )
669 if (check
== m_isChecked
)
672 wxMenuItemBase::Check( check
);
673 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
676 void wxMenuItem::Enable( bool enable
)
678 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
680 gtk_widget_set_sensitive( m_menuItem
, enable
);
681 wxMenuItemBase::Enable( enable
);
684 bool wxMenuItem::IsChecked() const
686 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
688 wxCHECK_MSG( IsCheckable(), FALSE
,
689 wxT("can't get state of uncheckable item!") );
691 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
694 //-----------------------------------------------------------------------------
696 //-----------------------------------------------------------------------------
698 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
701 wxMenu::Init( const wxString
& title
,
703 const wxFunction func
707 m_items
.DeleteContents( TRUE
);
708 m_invokingWindow
= (wxWindow
*) NULL
;
711 #if (GTK_MINOR_VERSION > 0)
712 m_accel
= gtk_accel_group_new();
713 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
714 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
716 m_menu
= gtk_menu_new(); // Do not show!
721 m_eventHandler
= this;
722 m_clientData
= (void*) NULL
;
724 if (m_title
.IsNull()) m_title
= wxT("");
725 if (m_title
!= wxT(""))
731 m_owner
= (GtkWidget
*) NULL
;
733 #if (GTK_MINOR_VERSION > 0)
734 /* Tearoffs are entries, just like separators. So if we want this
735 menu to be a tear-off one, we just append a tearoff entry
737 if(m_style
& wxMENU_TEAROFF
)
739 GtkItemFactoryEntry entry
;
740 entry
.path
= "/tearoff";
741 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
742 entry
.callback_action
= 0;
743 entry
.item_type
= "<Tearoff>";
744 entry
.accelerator
= (gchar
*) NULL
;
745 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
746 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
753 wxNode
*node
= m_items
.First();
756 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
757 wxMenu
*submenu
= item
->GetSubMenu();
763 gtk_widget_destroy( m_menu
);
765 gtk_object_unref( GTK_OBJECT(m_factory
) );
768 void wxMenu::SetTitle( const wxString
& title
)
770 // TODO Waiting for something better
774 const wxString
wxMenu::GetTitle() const
779 void wxMenu::AppendSeparator()
781 wxMenuItem
*mitem
= new wxMenuItem(this, wxID_SEPARATOR
);
783 #if (GTK_MINOR_VERSION > 0)
784 GtkItemFactoryEntry entry
;
786 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
787 entry
.callback_action
= 0;
788 entry
.item_type
= "<Separator>";
789 entry
.accelerator
= (gchar
*) NULL
;
791 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
793 /* this will be wrong for more than one separator. do we care? */
794 GtkWidget
*menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
796 GtkWidget
*menuItem
= gtk_menu_item_new();
797 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
798 gtk_widget_show( menuItem
);
801 mitem
->SetMenuItem(menuItem
);
802 m_items
.Append( mitem
);
805 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL
806 static wxString
GetHotKey( const wxMenuItem
& item
)
810 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
812 label
<< wxT('\t') << item
.GetHotKey();
813 wxAcceleratorEntry
*accel
= wxGetAccelFromString(label
);
816 int flags
= accel
->GetFlags();
817 if ( flags
& wxACCEL_ALT
)
818 hotkey
+= wxT("<alt>");
819 if ( flags
& wxACCEL_CTRL
)
820 hotkey
+= wxT("<control>");
821 if ( flags
& wxACCEL_SHIFT
)
822 hotkey
+= wxT("<shift>");
824 int code
= accel
->GetKeyCode();
839 hotkey
<< wxT('F') << code
= WXK_F1
+ 1;
842 // if there are any other keys wxGetAccelFromString() may return,
843 // we should process them here
846 if ( wxIsalnum(code
) )
848 hotkey
<< (wxChar
)code
;
853 wxFAIL_MSG( wxT("unknown keyboard accel") );
859 #endif // wxUSE_ACCEL
861 void wxMenu::Append( int id
, const wxString
&item
, const wxString
&helpStr
, bool checkable
)
863 wxMenuItem
*mitem
= new wxMenuItem(this, id
, item
, helpStr
, checkable
);
865 #if (GTK_MINOR_VERSION > 0)
866 /* text has "_" instead of "&" after mitem->SetText() */
867 wxString
text( mitem
->GetText() );
869 /* local buffer in multibyte form */
872 strcat( buf
, text
.mb_str() );
874 GtkItemFactoryEntry entry
;
876 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
877 entry
.callback_action
= 0;
879 entry
.item_type
= "<CheckItem>";
881 entry
.item_type
= "<Item>";
884 // due to an apparent bug in GTK+, we have to use a static buffer here -
885 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
887 static char s_accel
[32]; // must be big enough for <control><alt><shift>F12
888 strncpy(s_accel
, GetHotKey(*mitem
).mb_str(), WXSIZEOF(s_accel
));
889 entry
.accelerator
= s_accel
;
891 entry
.accelerator
= NULL
;
894 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
896 /* in order to get the pointer to the item we need the item text _without_ underscores */
897 wxString s
= wxT("<main>/");
898 for ( const wxChar
*pc
= text
; *pc
!= wxT('\0'); pc
++ )
900 while (*pc
== wxT('_')) pc
++; /* skip it */
904 GtkWidget
*menuItem
= gtk_item_factory_get_widget( m_factory
, s
.mb_str() );
908 GtkWidget
*menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
909 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
911 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
912 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
915 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
916 gtk_widget_show( menuItem
);
920 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
921 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
924 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
925 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
928 mitem
->SetMenuItem(menuItem
);
930 m_items
.Append( mitem
);
933 void wxMenu::Append( int id
, const wxString
&item
, wxMenu
*subMenu
, const wxString
&helpStr
)
935 wxMenuItem
*mitem
= new wxMenuItem(this, id
, item
, helpStr
, FALSE
, subMenu
);
937 #if (GTK_MINOR_VERSION > 0)
938 /* text has "_" instead of "&" after mitem->SetText() */
939 wxString
text( mitem
->GetText() );
941 /* local buffer in multibyte form */
944 strcat( buf
, text
.mb_str() );
946 GtkItemFactoryEntry entry
;
948 entry
.callback
= (GtkItemFactoryCallback
) 0;
949 entry
.callback_action
= 0;
950 entry
.item_type
= "<Branch>";
952 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
954 /* in order to get the pointer to the item we need the item text _without_ underscores */
955 wxString s
= wxT("<main>/");
956 for ( const wxChar
*pc
= text
; *pc
!= wxT('\0'); pc
++ )
958 if (*pc
== wxT('_')) pc
++; /* skip it */
962 GtkWidget
*menuItem
= gtk_item_factory_get_item( m_factory
, s
.mb_str() );
966 GtkWidget
*menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
968 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
969 gtk_widget_show( menuItem
);
973 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
974 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
977 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
978 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
981 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), subMenu
->m_menu
);
983 mitem
->SetMenuItem(menuItem
);
985 m_items
.Append( mitem
);
988 void wxMenu::Append( wxMenuItem
*item
)
990 m_items
.Append( item
);
992 GtkWidget
*menuItem
= (GtkWidget
*) NULL
;
994 if (item
->IsSeparator())
995 menuItem
= gtk_menu_item_new();
996 else if (item
->IsSubMenu())
997 menuItem
= gtk_menu_item_new_with_label(item
->GetText().mbc_str());
999 menuItem
= item
->IsCheckable() ? gtk_check_menu_item_new_with_label(item
->GetText().mbc_str())
1000 : gtk_menu_item_new_with_label(item
->GetText().mbc_str());
1002 if (!item
->IsSeparator())
1004 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1005 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1008 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1009 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1012 if (!item
->IsSubMenu())
1014 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1015 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1020 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1021 gtk_widget_show( menuItem
);
1022 item
->SetMenuItem(menuItem
);
1025 void wxMenu::Delete( int id
)
1027 wxNode
*node
= m_items
.First();
1030 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1031 if (item
->GetId() == id
)
1033 gtk_widget_destroy( item
->GetMenuItem() );
1034 m_items
.DeleteNode( node
);
1037 node
= node
->Next();
1041 int wxMenu::FindItem( const wxString itemString
) const
1043 wxString s
= wxT("");
1044 for ( const wxChar
*pc
= itemString
; *pc
!= wxT('\0'); pc
++ )
1046 if (*pc
== wxT('&'))
1049 #if (GTK_MINOR_VERSION > 0)
1056 wxNode
*node
= m_items
.First();
1059 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1060 if (item
->GetText() == s
)
1062 return item
->GetId();
1064 node
= node
->Next();
1070 void wxMenu::Enable( int id
, bool enable
)
1072 wxMenuItem
*item
= FindItem(id
);
1074 wxCHECK_RET( item
, wxT("wxMenu::Enable: no such item") );
1076 item
->Enable(enable
);
1079 bool wxMenu::IsEnabled( int id
) const
1081 wxMenuItem
*item
= FindItem(id
);
1083 wxCHECK_MSG( item
, FALSE
, wxT("wxMenu::IsEnabled: no such item") );
1085 return item
->IsEnabled();
1088 void wxMenu::Check( int id
, bool enable
)
1090 wxMenuItem
*item
= FindItem(id
);
1092 wxCHECK_RET( item
, wxT("wxMenu::Check: no such item") );
1094 item
->Check(enable
);
1097 bool wxMenu::IsChecked( int id
) const
1099 wxMenuItem
*item
= FindItem(id
);
1101 wxCHECK_MSG( item
, FALSE
, wxT("wxMenu::IsChecked: no such item") );
1103 return item
->IsChecked();
1106 void wxMenu::SetLabel( int id
, const wxString
&label
)
1108 wxMenuItem
*item
= FindItem(id
);
1110 wxCHECK_RET( item
, wxT("wxMenu::SetLabel: no such item") );
1112 item
->SetText(label
);
1115 wxString
wxMenu::GetLabel( int id
) const
1117 wxMenuItem
*item
= FindItem(id
);
1119 wxCHECK_MSG( item
, wxT(""), wxT("wxMenu::GetLabel: no such item") );
1121 return item
->GetText();
1124 void wxMenu::SetHelpString( int id
, const wxString
& helpString
)
1126 wxMenuItem
*item
= FindItem(id
);
1128 wxCHECK_RET( item
, wxT("wxMenu::SetHelpString: no such item") );
1130 item
->SetHelp( helpString
);
1133 wxString
wxMenu::GetHelpString( int id
) const
1135 wxMenuItem
*item
= FindItem(id
);
1137 wxCHECK_MSG( item
, wxT(""), wxT("wxMenu::GetHelpString: no such item") );
1139 return item
->GetHelp();
1142 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1144 wxNode
*node
= m_items
.First();
1147 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1148 if (item
->GetMenuItem() == menuItem
)
1149 return item
->GetId();
1150 node
= node
->Next();
1156 wxMenuItem
*wxMenu::FindItem(int id
) const
1158 wxNode
*node
= m_items
.First();
1161 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1162 if (item
->GetId() == id
)
1166 node
= node
->Next();
1169 /* Not finding anything here can be correct
1170 * when search the entire menu system for
1171 * an entry -> no error message. */
1173 return (wxMenuItem
*) NULL
;
1176 void wxMenu::SetInvokingWindow( wxWindow
*win
)
1178 m_invokingWindow
= win
;
1181 wxWindow
*wxMenu::GetInvokingWindow()
1183 return m_invokingWindow
;
1186 // Update a menu and all submenus recursively. source is the object that has
1187 // the update event handlers defined for it. If NULL, the menu or associated
1188 // window will be used.
1189 void wxMenu::UpdateUI(wxEvtHandler
* source
)
1191 if (!source
&& GetInvokingWindow())
1192 source
= GetInvokingWindow()->GetEventHandler();
1194 source
= GetEventHandler();
1198 wxNode
* node
= GetItems().First();
1201 wxMenuItem
* item
= (wxMenuItem
*) node
->Data();
1202 if ( !item
->IsSeparator() )
1204 wxWindowID id
= item
->GetId();
1205 wxUpdateUIEvent
event(id
);
1206 event
.SetEventObject( source
);
1208 if (source
->ProcessEvent(event
))
1210 if (event
.GetSetText())
1211 SetLabel(id
, event
.GetText());
1212 if (event
.GetSetChecked())
1213 Check(id
, event
.GetChecked());
1214 if (event
.GetSetEnabled())
1215 Enable(id
, event
.GetEnabled());
1218 if (item
->GetSubMenu())
1219 item
->GetSubMenu()->UpdateUI(source
);
1221 node
= node
->Next();