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 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL
35 static wxString
GetHotKey( const wxMenuItem
& item
);
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
42 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
44 wxMenuBar::wxMenuBar( long style
)
46 /* the parent window is known after wxFrame::SetMenu() */
49 m_invokingWindow
= (wxWindow
*) NULL
;
51 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
52 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
54 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
58 m_menus
.DeleteContents( TRUE
);
60 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
61 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
62 m_accel
= gtk_accel_group_new();
63 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
64 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
66 m_menubar
= gtk_menu_bar_new();
69 if (style
& wxMB_DOCKABLE
)
71 m_widget
= gtk_handle_box_new();
72 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
73 gtk_widget_show( GTK_WIDGET(m_menubar
) );
77 m_widget
= GTK_WIDGET(m_menubar
);
83 wxMenuBar::wxMenuBar()
85 /* the parent window is known after wxFrame::SetMenu() */
88 m_invokingWindow
= (wxWindow
*) NULL
;
90 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
91 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
93 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
97 m_menus
.DeleteContents( TRUE
);
99 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
100 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
101 m_accel
= gtk_accel_group_new();
102 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
103 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
105 m_menubar
= gtk_menu_bar_new();
108 m_widget
= GTK_WIDGET(m_menubar
);
113 wxMenuBar::~wxMenuBar()
115 // gtk_object_unref( GTK_OBJECT(m_factory) ); why not ?
118 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
120 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
122 #if (GTK_MINOR_VERSION > 0)
123 wxWindow
*top_frame
= win
;
124 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
125 top_frame
= top_frame
->GetParent();
127 /* support for native hot keys */
128 gtk_accel_group_detach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
131 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
134 wxMenuItem
*menuitem
= node
->GetData();
135 if (menuitem
->IsSubMenu())
136 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
137 node
= node
->GetNext();
141 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
143 menu
->SetInvokingWindow( win
);
145 #if (GTK_MINOR_VERSION > 0)
146 wxWindow
*top_frame
= win
;
147 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
148 top_frame
= top_frame
->GetParent();
150 /* support for native hot keys */
151 gtk_accel_group_attach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
154 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
157 wxMenuItem
*menuitem
= node
->GetData();
158 if (menuitem
->IsSubMenu())
159 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
160 node
= node
->GetNext();
164 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
166 m_invokingWindow
= win
;
167 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
168 wxWindow
*top_frame
= win
;
169 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
170 top_frame
= top_frame
->GetParent();
172 /* support for native key accelerators indicated by underscroes */
173 gtk_accel_group_attach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
176 wxMenuList::Node
*node
= m_menus
.GetFirst();
179 wxMenu
*menu
= node
->GetData();
180 wxMenubarSetInvokingWindow( menu
, win
);
181 node
= node
->GetNext();
185 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
187 m_invokingWindow
= (wxWindow
*) NULL
;
188 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
189 wxWindow
*top_frame
= win
;
190 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
191 top_frame
= top_frame
->GetParent();
193 /* support for native key accelerators indicated by underscroes */
194 gtk_accel_group_detach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
197 wxMenuList::Node
*node
= m_menus
.GetFirst();
200 wxMenu
*menu
= node
->GetData();
201 wxMenubarUnsetInvokingWindow( menu
, win
);
202 node
= node
->GetNext();
206 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
208 if ( !wxMenuBarBase::Append( menu
, title
) )
211 return GtkAppend(menu
, title
);
214 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
)
218 /* GTK 1.2 wants to have "_" instead of "&" for accelerators */
220 for ( pc
= title
; *pc
!= wxT('\0'); pc
++ )
224 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
227 else if (*pc
== wxT('/'))
235 if ( *pc
== wxT('_') )
237 // underscores must be doubled to prevent them from being
238 // interpreted as accelerator character prefix by GTK
247 /* this doesn't have much effect right now */
248 menu
->SetTitle( str
);
250 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
251 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
253 /* local buffer in multibyte form */
255 buf
<< wxT('/') << str
.c_str();
257 char *cbuf
= new char[buf
.Length()+1];
258 strcpy(cbuf
, buf
.mbc_str());
260 GtkItemFactoryEntry entry
;
261 entry
.path
= (gchar
*)cbuf
; // const_cast
262 entry
.accelerator
= (gchar
*) NULL
;
263 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
264 entry
.callback_action
= 0;
265 entry
.item_type
= "<Branch>";
267 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
268 /* in order to get the pointer to the item we need the item text _without_ underscores */
269 wxString tmp
= wxT("<main>/");
270 for ( pc
= str
; *pc
!= wxT('\0'); pc
++ )
272 // contrary to the common sense, we must throw out _all_ underscores,
273 // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we
274 // might naively think). IMHO it's a bug in GTK+ (VZ)
275 while (*pc
== wxT('_'))
279 menu
->m_owner
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() );
280 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
284 menu
->m_owner
= gtk_menu_item_new_with_label( str
.mb_str() );
285 gtk_widget_show( menu
->m_owner
);
286 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
288 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
292 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
293 // adding menu later on.
294 if (m_invokingWindow
)
295 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
300 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
302 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
306 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
307 // of version 1.2.6), so we first append the item and then change its
309 if ( !GtkAppend(menu
, title
) )
312 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
313 gpointer data
= g_list_last(menu_shell
->children
)->data
;
314 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
315 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
319 // this should be easy to do with GTK 1.0 - can use standard functions for
320 // this and don't need any hacks like above, but as I don't have GTK 1.0
321 // any more I can't do it
322 wxFAIL_MSG( wxT("TODO") );
325 #endif // GTK 1.2/1.0
328 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
330 if ( !wxMenuBarBase::Replace(pos
, menu
, title
) )
333 // remove the old item and insert a new one
334 wxMenu
*menuOld
= Remove(pos
);
335 if ( menuOld
&& !Insert(pos
, menu
, title
) )
340 // either Insert() succeeded or Remove() failed and menuOld is NULL
344 wxMenu
*wxMenuBar::Remove(size_t pos
)
346 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
351 // gtk_item_factory_delete_entry() is buggy as of GTK+ 1.2.6, so don't use
352 // it but delete the widget manually instead
353 wxString path
= _T("<main>/"),
354 title
= menu
->GetTitle();
355 for ( const wxChar
*p
= title
.c_str(); *p
; p
++ )
361 GtkWidget
*widget
= gtk_item_factory_get_item(m_factory
, path
.mb_str());
364 gtk_widget_destroy(widget
);
369 // shouldn't happen (FIXME but does now)
370 wxFAIL_MSG( _T("gtk_item_factory_get_item() failed") );
372 // this should be very simple to implement
373 wxFAIL_MSG( wxT("TODO") );
374 #endif // GTK 1.2/1.0
379 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
381 if (menu
->GetTitle() == menuString
)
383 int res
= menu
->FindItem( itemString
);
384 if (res
!= wxNOT_FOUND
)
388 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
391 wxMenuItem
*item
= node
->GetData();
392 if (item
->IsSubMenu())
393 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
395 node
= node
->GetNext();
401 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
403 wxMenuList::Node
*node
= m_menus
.GetFirst();
406 wxMenu
*menu
= node
->GetData();
407 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
410 node
= node
->GetNext();
416 // Find a wxMenuItem using its id. Recurses down into sub-menus
417 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
419 wxMenuItem
* result
= menu
->FindChildItem(id
);
421 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
422 while ( node
&& result
== NULL
)
424 wxMenuItem
*item
= node
->GetData();
425 if (item
->IsSubMenu())
427 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
429 node
= node
->GetNext();
435 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
437 wxMenuItem
* result
= 0;
438 wxMenuList::Node
*node
= m_menus
.GetFirst();
439 while (node
&& result
== 0)
441 wxMenu
*menu
= node
->GetData();
442 result
= FindMenuItemByIdRecursive( menu
, id
);
443 node
= node
->GetNext();
448 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
454 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
456 wxMenuList::Node
*node
= m_menus
.Item( pos
);
458 wxCHECK_RET( node
, wxT("menu not found") );
460 wxMenu
* menu
= node
->GetData();
463 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
466 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
468 wxMenuList::Node
*node
= m_menus
.Item( pos
);
470 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
472 wxMenu
* menu
= node
->GetData();
474 return menu
->GetTitle();
477 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
479 wxMenuList::Node
*node
= m_menus
.Item( pos
);
481 wxCHECK_RET( node
, wxT("menu not found") );
483 wxMenu
* menu
= node
->GetData();
485 menu
->SetTitle( label
);
488 //-----------------------------------------------------------------------------
490 //-----------------------------------------------------------------------------
492 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
494 if (g_isIdle
) wxapp_install_idle_handler();
496 int id
= menu
->FindMenuIdByMenuItem(widget
);
498 /* should find it for normal (not popup) menu */
499 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
501 if (!menu
->IsEnabled(id
))
504 wxMenuItem
* item
= menu
->FindChildItem( id
);
505 wxCHECK_RET( item
, wxT("error in menu item callback") );
507 if (item
->IsCheckable())
509 bool isReallyChecked
= item
->IsChecked();
510 if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked
)
512 /* the menu item has been checked by calling wxMenuItem->Check() */
517 /* the user pressed on the menu item -> report and make consistent
519 item
->wxMenuItemBase::Check(isReallyChecked
);
523 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
524 event
.SetEventObject( menu
);
527 #if wxUSE_MENU_CALLBACK
528 if (menu
->GetCallback())
530 (void) (*(menu
->GetCallback())) (*menu
, event
);
533 #endif // wxUSE_MENU_CALLBACK
535 if (menu
->GetEventHandler()->ProcessEvent(event
))
538 wxWindow
*win
= menu
->GetInvokingWindow();
540 win
->GetEventHandler()->ProcessEvent( event
);
543 //-----------------------------------------------------------------------------
545 //-----------------------------------------------------------------------------
547 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
549 if (g_isIdle
) wxapp_install_idle_handler();
551 int id
= menu
->FindMenuIdByMenuItem(widget
);
553 wxASSERT( id
!= -1 ); // should find it!
555 if (!menu
->IsEnabled(id
))
558 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
559 event
.SetEventObject( menu
);
561 if (menu
->GetEventHandler()->ProcessEvent(event
))
564 wxWindow
*win
= menu
->GetInvokingWindow();
565 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
568 //-----------------------------------------------------------------------------
570 //-----------------------------------------------------------------------------
572 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
574 if (g_isIdle
) wxapp_install_idle_handler();
576 int id
= menu
->FindMenuIdByMenuItem(widget
);
578 wxASSERT( id
!= -1 ); // should find it!
580 if (!menu
->IsEnabled(id
))
583 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
584 event
.SetEventObject( menu
);
586 if (menu
->GetEventHandler()->ProcessEvent(event
))
589 wxWindow
*win
= menu
->GetInvokingWindow();
591 win
->GetEventHandler()->ProcessEvent( event
);
594 //-----------------------------------------------------------------------------
596 //-----------------------------------------------------------------------------
598 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxMenuItemBase
)
600 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
602 const wxString
& name
,
603 const wxString
& help
,
607 return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
);
610 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
612 const wxString
& text
,
613 const wxString
& help
,
618 m_isCheckable
= isCheckable
;
622 m_parentMenu
= parentMenu
;
625 m_menuItem
= (GtkWidget
*) NULL
;
630 wxMenuItem::~wxMenuItem()
632 // don't delete menu items, the menus take care of that
635 // return the menu item text without any menu accels
636 wxString
wxMenuItem::GetLabel() const
639 #if (GTK_MINOR_VERSION > 0)
640 for ( const wxChar
*pc
= m_text
.c_str(); *pc
; pc
++ )
642 if ( *pc
== wxT('_') )
644 // this is the escape character for GTK+ - skip it
652 #endif // GTK+ 1.2/1.0
657 void wxMenuItem::SetText( const wxString
& str
)
663 GtkLabel
*label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
666 gtk_label_set( label
, m_text
.mb_str());
668 /* reparse key accel */
669 (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() );
670 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
674 // it's valid for this function to be called even if m_menuItem == NULL
675 void wxMenuItem::DoSetText( const wxString
& str
)
677 /* '\t' is the deliminator indicating a hot key */
679 const wxChar
*pc
= str
;
680 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
684 #if (GTK_MINOR_VERSION > 0)
687 else if ( *pc
== wxT('_') ) // escape underscores
691 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
693 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
700 /* only GTK 1.2 knows about hot keys */
702 #if (GTK_MINOR_VERSION > 0)
713 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
718 return (wxAcceleratorEntry
*)NULL
;
721 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
723 label
<< wxT('\t') << GetHotKey();
725 return wxGetAccelFromString(label
);
728 #endif // wxUSE_ACCEL
730 void wxMenuItem::Check( bool check
)
732 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
734 wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") )
736 if (check
== m_isChecked
)
739 wxMenuItemBase::Check( check
);
740 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
743 void wxMenuItem::Enable( bool enable
)
745 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
747 gtk_widget_set_sensitive( m_menuItem
, enable
);
748 wxMenuItemBase::Enable( enable
);
751 bool wxMenuItem::IsChecked() const
753 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
755 wxCHECK_MSG( IsCheckable(), FALSE
,
756 wxT("can't get state of uncheckable item!") );
758 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
761 wxString
wxMenuItem::GetFactoryPath() const
763 /* in order to get the pointer to the item we need the item text _without_
765 wxString
path( wxT("<main>/") );
771 //-----------------------------------------------------------------------------
773 //-----------------------------------------------------------------------------
775 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
779 #if (GTK_MINOR_VERSION > 0)
780 m_accel
= gtk_accel_group_new();
781 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
782 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
784 m_menu
= gtk_menu_new(); // Do not show!
787 m_owner
= (GtkWidget
*) NULL
;
789 #if (GTK_MINOR_VERSION > 0)
790 /* Tearoffs are entries, just like separators. So if we want this
791 menu to be a tear-off one, we just append a tearoff entry
793 if(m_style
& wxMENU_TEAROFF
)
795 GtkItemFactoryEntry entry
;
796 entry
.path
= "/tearoff";
797 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
798 entry
.callback_action
= 0;
799 entry
.item_type
= "<Tearoff>";
800 entry
.accelerator
= (gchar
*) NULL
;
801 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
802 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
806 // append the title as the very first entry if we have it
818 gtk_widget_destroy( m_menu
);
820 gtk_object_unref( GTK_OBJECT(m_factory
) );
823 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
827 if ( mitem
->IsSeparator() )
829 #if (GTK_MINOR_VERSION > 0)
830 GtkItemFactoryEntry entry
;
832 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
833 entry
.callback_action
= 0;
834 entry
.item_type
= "<Separator>";
835 entry
.accelerator
= (gchar
*) NULL
;
837 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
839 /* this will be wrong for more than one separator. do we care? */
840 menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
842 menuItem
= gtk_menu_item_new();
843 #endif // GTK 1.2/1.0
845 else if ( mitem
->IsSubMenu() )
847 #if (GTK_MINOR_VERSION > 0)
848 /* text has "_" instead of "&" after mitem->SetText() */
849 wxString
text( mitem
->GetText() );
851 /* local buffer in multibyte form */
854 strcat( buf
, text
.mb_str() );
856 GtkItemFactoryEntry entry
;
858 entry
.callback
= (GtkItemFactoryCallback
) 0;
859 entry
.callback_action
= 0;
860 entry
.item_type
= "<Branch>";
861 entry
.accelerator
= (gchar
*) NULL
;
863 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
865 wxString
path( mitem
->GetFactoryPath() );
866 menuItem
= gtk_item_factory_get_item( m_factory
, path
.mb_str() );
868 menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
869 #endif // GTK 1.2/1.0
871 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
873 else // a normal item
875 #if (GTK_MINOR_VERSION > 0)
876 /* text has "_" instead of "&" after mitem->SetText() */
877 wxString
text( mitem
->GetText() );
879 /* local buffer in multibyte form */
882 strcat( buf
, text
.mb_str() );
884 GtkItemFactoryEntry entry
;
886 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
887 entry
.callback_action
= 0;
888 if ( mitem
->IsCheckable() )
889 entry
.item_type
= "<CheckItem>";
891 entry
.item_type
= "<Item>";
892 entry
.accelerator
= (gchar
*) NULL
;
895 // due to an apparent bug in GTK+, we have to use a static buffer here -
896 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
898 static char s_accel
[32]; // must be big enough for <control><alt><shift>F12
899 strncpy(s_accel
, GetHotKey(*mitem
).mb_str(), WXSIZEOF(s_accel
));
900 entry
.accelerator
= s_accel
;
901 #else // !wxUSE_ACCEL
902 entry
.accelerator
= (char*) NULL
;
903 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
905 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
907 wxString
path( mitem
->GetFactoryPath() );
908 menuItem
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() );
910 menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
911 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
913 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
914 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
916 #endif // GTK+ 1.2/1.0
919 if ( !mitem
->IsSeparator() )
921 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
922 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
925 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
926 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
930 #if GTK_MINOR_VERSION == 0
931 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
932 gtk_widget_show( menuItem
);
935 mitem
->SetMenuItem(menuItem
);
937 return wxMenuBase::DoAppend(mitem
);
940 // VZ: this seems to be GTK+ 1.0 only code, I don't understand why there were
941 // both specialized versions of Append() and this one before my changes,
942 // but it seems that the others are better...
944 void wxMenu::Append( wxMenuItem
*item
)
946 GtkWidget
*menuItem
= (GtkWidget
*) NULL
;
948 if (item
->IsSeparator())
949 menuItem
= gtk_menu_item_new();
950 else if (item
->IsSubMenu())
951 menuItem
= gtk_menu_item_new_with_label(item
->GetText().mbc_str());
953 menuItem
= item
->IsCheckable() ? gtk_check_menu_item_new_with_label(item
->GetText().mbc_str())
954 : gtk_menu_item_new_with_label(item
->GetText().mbc_str());
956 if (!item
->IsSeparator())
958 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
959 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
962 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
963 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
966 if (!item
->IsSubMenu())
968 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
969 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
974 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
975 gtk_widget_show( menuItem
);
977 item
->SetMenuItem(menuItem
);
981 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
983 if ( !wxMenuBase::DoInsert(pos
, item
) )
986 wxFAIL_MSG(wxT("not implemented"));
991 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
993 if ( !wxMenuBase::DoRemove(item
) )
994 return (wxMenuItem
*)NULL
;
996 // TODO: this code doesn't delete the item factory item and this seems
997 // impossible as of GTK 1.2.6.
998 gtk_widget_destroy( item
->GetMenuItem() );
1003 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1005 wxNode
*node
= m_items
.First();
1008 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
1009 if (item
->GetMenuItem() == menuItem
)
1010 return item
->GetId();
1011 node
= node
->Next();
1017 // ----------------------------------------------------------------------------
1019 // ----------------------------------------------------------------------------
1021 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL
1022 static wxString
GetHotKey( const wxMenuItem
& item
)
1026 wxAcceleratorEntry
*accel
= item
.GetAccel();
1029 int flags
= accel
->GetFlags();
1030 if ( flags
& wxACCEL_ALT
)
1031 hotkey
+= wxT("<alt>");
1032 if ( flags
& wxACCEL_CTRL
)
1033 hotkey
+= wxT("<control>");
1034 if ( flags
& wxACCEL_SHIFT
)
1035 hotkey
+= wxT("<shift>");
1037 int code
= accel
->GetKeyCode();
1052 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1055 // if there are any other keys wxGetAccelFromString() may return,
1056 // we should process them here
1059 if ( wxIsalnum(code
) )
1061 hotkey
<< (wxChar
)code
;
1066 wxFAIL_MSG( wxT("unknown keyboard accel") );
1074 #endif // wxUSE_ACCEL