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
);
85 wxMenuBar::wxMenuBar()
87 /* the parent window is known after wxFrame::SetMenu() */
90 m_invokingWindow
= (wxWindow
*) NULL
;
92 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
93 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
95 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
99 m_menus
.DeleteContents( TRUE
);
101 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
102 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
103 m_accel
= gtk_accel_group_new();
104 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU_BAR
, "<main>", m_accel
);
105 m_menubar
= gtk_item_factory_get_widget( m_factory
, "<main>" );
107 m_menubar
= gtk_menu_bar_new();
110 m_widget
= GTK_WIDGET(m_menubar
);
117 wxMenuBar::~wxMenuBar()
119 // gtk_object_unref( GTK_OBJECT(m_factory) ); why not ?
122 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
124 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
126 #if (GTK_MINOR_VERSION > 0)
127 wxWindow
*top_frame
= win
;
128 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
129 top_frame
= top_frame
->GetParent();
131 /* support for native hot keys */
132 gtk_accel_group_detach( menu
->m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
135 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
138 wxMenuItem
*menuitem
= node
->GetData();
139 if (menuitem
->IsSubMenu())
140 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
141 node
= node
->GetNext();
145 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
147 menu
->SetInvokingWindow( win
);
149 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
150 wxWindow
*top_frame
= win
;
151 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
152 top_frame
= top_frame
->GetParent();
154 /* support for native hot keys */
155 GtkObject
*obj
= GTK_OBJECT(top_frame
->m_widget
);
156 if ( !g_slist_find( menu
->m_accel
->attach_objects
, obj
) )
157 gtk_accel_group_attach( menu
->m_accel
, obj
);
160 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
163 wxMenuItem
*menuitem
= node
->GetData();
164 if (menuitem
->IsSubMenu())
165 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
166 node
= node
->GetNext();
170 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
172 m_invokingWindow
= win
;
173 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
174 wxWindow
*top_frame
= win
;
175 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
176 top_frame
= top_frame
->GetParent();
178 /* support for native key accelerators indicated by underscroes */
179 GtkObject
*obj
= GTK_OBJECT(top_frame
->m_widget
);
180 if ( !g_slist_find( m_accel
->attach_objects
, obj
) )
181 gtk_accel_group_attach( m_accel
, obj
);
184 wxMenuList::Node
*node
= m_menus
.GetFirst();
187 wxMenu
*menu
= node
->GetData();
188 wxMenubarSetInvokingWindow( menu
, win
);
189 node
= node
->GetNext();
193 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
195 m_invokingWindow
= (wxWindow
*) NULL
;
196 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
197 wxWindow
*top_frame
= win
;
198 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
199 top_frame
= top_frame
->GetParent();
201 /* support for native key accelerators indicated by underscroes */
202 gtk_accel_group_detach( m_accel
, GTK_OBJECT(top_frame
->m_widget
) );
205 wxMenuList::Node
*node
= m_menus
.GetFirst();
208 wxMenu
*menu
= node
->GetData();
209 wxMenubarUnsetInvokingWindow( menu
, win
);
210 node
= node
->GetNext();
214 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
216 if ( !wxMenuBarBase::Append( menu
, title
) )
219 return GtkAppend(menu
, title
);
222 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
)
226 /* GTK 1.2 wants to have "_" instead of "&" for accelerators */
228 for ( pc
= title
; *pc
!= wxT('\0'); pc
++ )
232 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
235 else if (*pc
== wxT('/'))
243 if ( *pc
== wxT('_') )
245 // underscores must be doubled to prevent them from being
246 // interpreted as accelerator character prefix by GTK
255 /* this doesn't have much effect right now */
256 menu
->SetTitle( str
);
258 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
259 #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
261 /* local buffer in multibyte form */
263 buf
<< wxT('/') << str
.c_str();
265 char *cbuf
= new char[buf
.Length()+1];
266 strcpy(cbuf
, buf
.mbc_str());
268 GtkItemFactoryEntry entry
;
269 entry
.path
= (gchar
*)cbuf
; // const_cast
270 entry
.accelerator
= (gchar
*) NULL
;
271 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
272 entry
.callback_action
= 0;
273 entry
.item_type
= "<Branch>";
275 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
276 /* in order to get the pointer to the item we need the item text _without_ underscores */
277 wxString tmp
= wxT("<main>/");
278 for ( pc
= str
; *pc
!= wxT('\0'); pc
++ )
280 // contrary to the common sense, we must throw out _all_ underscores,
281 // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we
282 // might naively think). IMHO it's a bug in GTK+ (VZ)
283 while (*pc
== wxT('_'))
287 menu
->m_owner
= gtk_item_factory_get_item( m_factory
, tmp
.mb_str() );
288 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
292 menu
->m_owner
= gtk_menu_item_new_with_label( str
.mb_str() );
293 gtk_widget_show( menu
->m_owner
);
294 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
296 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
300 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
301 // adding menu later on.
302 if (m_invokingWindow
)
303 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
308 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
310 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
314 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
315 // of version 1.2.6), so we first append the item and then change its
317 if ( !GtkAppend(menu
, title
) )
320 if (pos
+1 >= m_menus
.GetCount())
323 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
324 gpointer data
= g_list_last(menu_shell
->children
)->data
;
325 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
326 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
330 // this should be easy to do with GTK 1.0 - can use standard functions for
331 // this and don't need any hacks like above, but as I don't have GTK 1.0
332 // any more I can't do it
333 wxFAIL_MSG( wxT("TODO") );
336 #endif // GTK 1.2/1.0
339 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
341 // remove the old item and insert a new one
342 wxMenu
*menuOld
= Remove(pos
);
343 if ( menuOld
&& !Insert(pos
, menu
, title
) )
345 return (wxMenu
*) NULL
;
348 // either Insert() succeeded or Remove() failed and menuOld is NULL
352 wxMenu
*wxMenuBar::Remove(size_t pos
)
354 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
356 return (wxMenu
*) NULL
;
359 GtkMenuShell *menu_shell = GTK_MENU_SHELL(m_factory->widget);
361 printf( "factory entries before %d\n", (int)g_slist_length(m_factory->items) );
362 printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) );
365 // unparent calls unref() and that would delete the widget so we raise
366 // the ref count to 2 artificially before invoking unparent.
367 gtk_widget_ref( menu
->m_menu
);
368 gtk_widget_unparent( menu
->m_menu
);
370 gtk_widget_destroy( menu
->m_owner
);
373 printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) );
374 printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) );
380 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
382 if (menu
->GetTitle() == menuString
)
384 int res
= menu
->FindItem( itemString
);
385 if (res
!= wxNOT_FOUND
)
389 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
392 wxMenuItem
*item
= node
->GetData();
393 if (item
->IsSubMenu())
394 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
396 node
= node
->GetNext();
402 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
404 wxMenuList::Node
*node
= m_menus
.GetFirst();
407 wxMenu
*menu
= node
->GetData();
408 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
411 node
= node
->GetNext();
417 // Find a wxMenuItem using its id. Recurses down into sub-menus
418 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
420 wxMenuItem
* result
= menu
->FindChildItem(id
);
422 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
423 while ( node
&& result
== NULL
)
425 wxMenuItem
*item
= node
->GetData();
426 if (item
->IsSubMenu())
428 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
430 node
= node
->GetNext();
436 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
438 wxMenuItem
* result
= 0;
439 wxMenuList::Node
*node
= m_menus
.GetFirst();
440 while (node
&& result
== 0)
442 wxMenu
*menu
= node
->GetData();
443 result
= FindMenuItemByIdRecursive( menu
, id
);
444 node
= node
->GetNext();
449 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
455 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
457 wxMenuList::Node
*node
= m_menus
.Item( pos
);
459 wxCHECK_RET( node
, wxT("menu not found") );
461 wxMenu
* menu
= node
->GetData();
464 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
467 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
469 wxMenuList::Node
*node
= m_menus
.Item( pos
);
471 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
473 wxMenu
* menu
= node
->GetData();
475 return menu
->GetTitle();
478 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
480 wxMenuList::Node
*node
= m_menus
.Item( pos
);
482 wxCHECK_RET( node
, wxT("menu not found") );
484 wxMenu
* menu
= node
->GetData();
486 menu
->SetTitle( label
);
489 //-----------------------------------------------------------------------------
491 //-----------------------------------------------------------------------------
493 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
495 if (g_isIdle
) wxapp_install_idle_handler();
497 int id
= menu
->FindMenuIdByMenuItem(widget
);
499 /* should find it for normal (not popup) menu */
500 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
502 if (!menu
->IsEnabled(id
))
505 wxMenuItem
* item
= menu
->FindChildItem( id
);
506 wxCHECK_RET( item
, wxT("error in menu item callback") );
508 if (item
->IsCheckable())
510 bool isReallyChecked
= item
->IsChecked();
511 if ( item
->wxMenuItemBase::IsChecked() == isReallyChecked
)
513 /* the menu item has been checked by calling wxMenuItem->Check() */
518 /* the user pressed on the menu item -> report and make consistent
520 item
->wxMenuItemBase::Check(isReallyChecked
);
524 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
525 event
.SetEventObject( menu
);
528 #if wxUSE_MENU_CALLBACK
529 if (menu
->GetCallback())
531 (void) (*(menu
->GetCallback())) (*menu
, event
);
534 #endif // wxUSE_MENU_CALLBACK
536 if (menu
->GetEventHandler()->ProcessEvent(event
))
539 wxWindow
*win
= menu
->GetInvokingWindow();
541 win
->GetEventHandler()->ProcessEvent( event
);
544 //-----------------------------------------------------------------------------
546 //-----------------------------------------------------------------------------
548 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
550 if (g_isIdle
) wxapp_install_idle_handler();
552 int id
= menu
->FindMenuIdByMenuItem(widget
);
554 wxASSERT( id
!= -1 ); // should find it!
556 if (!menu
->IsEnabled(id
))
559 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
560 event
.SetEventObject( menu
);
562 if (menu
->GetEventHandler()->ProcessEvent(event
))
565 wxWindow
*win
= menu
->GetInvokingWindow();
566 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
569 //-----------------------------------------------------------------------------
571 //-----------------------------------------------------------------------------
573 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
575 if (g_isIdle
) wxapp_install_idle_handler();
577 int id
= menu
->FindMenuIdByMenuItem(widget
);
579 wxASSERT( id
!= -1 ); // should find it!
581 if (!menu
->IsEnabled(id
))
584 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
585 event
.SetEventObject( menu
);
587 if (menu
->GetEventHandler()->ProcessEvent(event
))
590 wxWindow
*win
= menu
->GetInvokingWindow();
592 win
->GetEventHandler()->ProcessEvent( event
);
595 //-----------------------------------------------------------------------------
597 //-----------------------------------------------------------------------------
599 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxMenuItemBase
)
601 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
603 const wxString
& name
,
604 const wxString
& help
,
608 return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
);
611 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
613 const wxString
& text
,
614 const wxString
& help
,
619 m_isCheckable
= isCheckable
;
623 m_parentMenu
= parentMenu
;
626 m_menuItem
= (GtkWidget
*) NULL
;
631 wxMenuItem::~wxMenuItem()
633 // don't delete menu items, the menus take care of that
636 // return the menu item text without any menu accels
638 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
641 #if (GTK_MINOR_VERSION > 0)
642 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
644 if ( *pc
== wxT('_') || *pc
== wxT('&') )
646 // '_' is the escape character for GTK+ and '&' is the one for
647 // wxWindows - skip both of them
655 #endif // GTK+ 1.2/1.0
660 void wxMenuItem::SetText( const wxString
& str
)
666 GtkLabel
*label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
669 gtk_label_set( label
, m_text
.mb_str());
671 /* reparse key accel */
672 (void)gtk_label_parse_uline (GTK_LABEL(label
), m_text
.mb_str() );
673 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
677 // it's valid for this function to be called even if m_menuItem == NULL
678 void wxMenuItem::DoSetText( const wxString
& str
)
680 /* '\t' is the deliminator indicating a hot key */
682 const wxChar
*pc
= str
;
683 for (; (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')); pc
++ )
687 #if (GTK_MINOR_VERSION > 0)
690 else if ( *pc
== wxT('_') ) // escape underscores
694 else if (*pc
== wxT('/')) /* we have to filter out slashes ... */
696 m_text
<< wxT('\\'); /* ... and replace them with back slashes */
703 /* only GTK 1.2 knows about hot keys */
705 #if (GTK_MINOR_VERSION > 0)
716 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
721 return (wxAcceleratorEntry
*)NULL
;
724 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
726 label
<< wxT('\t') << GetHotKey();
728 return wxGetAccelFromString(label
);
731 #endif // wxUSE_ACCEL
733 void wxMenuItem::Check( bool check
)
735 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
737 wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") )
739 if (check
== m_isChecked
)
742 wxMenuItemBase::Check( check
);
743 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
746 void wxMenuItem::Enable( bool enable
)
748 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
750 gtk_widget_set_sensitive( m_menuItem
, enable
);
751 wxMenuItemBase::Enable( enable
);
754 bool wxMenuItem::IsChecked() const
756 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
758 wxCHECK_MSG( IsCheckable(), FALSE
,
759 wxT("can't get state of uncheckable item!") );
761 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
764 wxString
wxMenuItem::GetFactoryPath() const
766 /* in order to get the pointer to the item we need the item text _without_
768 wxString
path( wxT("<main>/") );
774 //-----------------------------------------------------------------------------
776 //-----------------------------------------------------------------------------
778 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
782 #if (GTK_MINOR_VERSION > 0)
783 m_accel
= gtk_accel_group_new();
784 m_factory
= gtk_item_factory_new( GTK_TYPE_MENU
, "<main>", m_accel
);
785 m_menu
= gtk_item_factory_get_widget( m_factory
, "<main>" );
787 m_menu
= gtk_menu_new(); // Do not show!
790 m_owner
= (GtkWidget
*) NULL
;
792 #if (GTK_MINOR_VERSION > 0)
793 /* Tearoffs are entries, just like separators. So if we want this
794 menu to be a tear-off one, we just append a tearoff entry
796 if(m_style
& wxMENU_TEAROFF
)
798 GtkItemFactoryEntry entry
;
799 entry
.path
= "/tearoff";
800 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
801 entry
.callback_action
= 0;
802 entry
.item_type
= "<Tearoff>";
803 entry
.accelerator
= (gchar
*) NULL
;
804 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
805 //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
809 // append the title as the very first entry if we have it
821 gtk_widget_destroy( m_menu
);
823 gtk_object_unref( GTK_OBJECT(m_factory
) );
826 bool wxMenu::GtkAppend(wxMenuItem
*mitem
)
830 if ( mitem
->IsSeparator() )
832 #if (GTK_MINOR_VERSION > 0)
833 GtkItemFactoryEntry entry
;
835 entry
.callback
= (GtkItemFactoryCallback
) NULL
;
836 entry
.callback_action
= 0;
837 entry
.item_type
= "<Separator>";
838 entry
.accelerator
= (gchar
*) NULL
;
840 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
842 /* this will be wrong for more than one separator. do we care? */
843 menuItem
= gtk_item_factory_get_widget( m_factory
, "<main>/sep" );
845 menuItem
= gtk_menu_item_new();
846 #endif // GTK 1.2/1.0
848 else if ( mitem
->IsSubMenu() )
850 #if (GTK_MINOR_VERSION > 0)
851 /* text has "_" instead of "&" after mitem->SetText() */
852 wxString
text( mitem
->GetText() );
854 /* local buffer in multibyte form */
857 strcat( buf
, text
.mb_str() );
859 GtkItemFactoryEntry entry
;
861 entry
.callback
= (GtkItemFactoryCallback
) 0;
862 entry
.callback_action
= 0;
863 entry
.item_type
= "<Branch>";
864 entry
.accelerator
= (gchar
*) NULL
;
866 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
868 wxString
path( mitem
->GetFactoryPath() );
869 menuItem
= gtk_item_factory_get_item( m_factory
, path
.mb_str() );
871 menuItem
= gtk_menu_item_new_with_label(mitem
->GetText().mbc_str());
872 #endif // GTK 1.2/1.0
874 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
876 // if adding a submenu to a menu already existing in the menu bar, we
877 // must set invoking window to allow processing events from this
879 if ( m_invokingWindow
)
880 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
882 else // a normal item
884 #if (GTK_MINOR_VERSION > 0)
885 /* text has "_" instead of "&" after mitem->SetText() */
886 wxString
text( mitem
->GetText() );
888 /* local buffer in multibyte form */
891 strcat( buf
, text
.mb_str() );
893 GtkItemFactoryEntry entry
;
895 entry
.callback
= (GtkItemFactoryCallback
) gtk_menu_clicked_callback
;
896 entry
.callback_action
= 0;
897 if ( mitem
->IsCheckable() )
898 entry
.item_type
= "<CheckItem>";
900 entry
.item_type
= "<Item>";
901 entry
.accelerator
= (gchar
*) NULL
;
904 // due to an apparent bug in GTK+, we have to use a static buffer here -
905 // otherwise GTK+ 1.2.2 manages to override the memory we pass to it
907 static char s_accel
[32]; // must be big enough for <control><alt><shift>F12
908 strncpy(s_accel
, GetHotKey(*mitem
).mb_str(), WXSIZEOF(s_accel
));
909 entry
.accelerator
= s_accel
;
910 #else // !wxUSE_ACCEL
911 entry
.accelerator
= (char*) NULL
;
912 #endif // wxUSE_ACCEL/!wxUSE_ACCEL
914 gtk_item_factory_create_item( m_factory
, &entry
, (gpointer
) this, 2 ); /* what is 2 ? */
916 wxString
path( mitem
->GetFactoryPath() );
917 menuItem
= gtk_item_factory_get_widget( m_factory
, path
.mb_str() );
919 menuItem
= checkable
? gtk_check_menu_item_new_with_label( mitem
->GetText().mb_str() )
920 : gtk_menu_item_new_with_label( mitem
->GetText().mb_str() );
922 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
923 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
925 #endif // GTK+ 1.2/1.0
928 if ( !mitem
->IsSeparator() )
930 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
931 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
934 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
935 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
939 #if GTK_MINOR_VERSION == 0
940 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
941 gtk_widget_show( menuItem
);
944 mitem
->SetMenuItem(menuItem
);
949 bool wxMenu::DoAppend(wxMenuItem
*mitem
)
951 return GtkAppend(mitem
) && wxMenuBase::DoAppend(mitem
);
954 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
956 if ( !wxMenuBase::DoInsert(pos
, item
) )
960 // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
961 // of version 1.2.6), so we first append the item and then change its
963 if ( !GtkAppend(item
) )
966 GtkMenuShell
*menu_shell
= GTK_MENU_SHELL(m_factory
->widget
);
967 gpointer data
= g_list_last(menu_shell
->children
)->data
;
968 menu_shell
->children
= g_list_remove(menu_shell
->children
, data
);
969 menu_shell
->children
= g_list_insert(menu_shell
->children
, data
, pos
);
973 // this should be easy to do...
974 wxFAIL_MSG( wxT("not implemented") );
977 #endif // GTK 1.2/1.0
980 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
982 if ( !wxMenuBase::DoRemove(item
) )
983 return (wxMenuItem
*)NULL
;
985 // TODO: this code doesn't delete the item factory item and this seems
986 // impossible as of GTK 1.2.6.
987 gtk_widget_destroy( item
->GetMenuItem() );
992 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
994 wxNode
*node
= m_items
.First();
997 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
998 if (item
->GetMenuItem() == menuItem
)
999 return item
->GetId();
1000 node
= node
->Next();
1006 // ----------------------------------------------------------------------------
1008 // ----------------------------------------------------------------------------
1010 #if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL
1011 static wxString
GetHotKey( const wxMenuItem
& item
)
1015 wxAcceleratorEntry
*accel
= item
.GetAccel();
1018 int flags
= accel
->GetFlags();
1019 if ( flags
& wxACCEL_ALT
)
1020 hotkey
+= wxT("<alt>");
1021 if ( flags
& wxACCEL_CTRL
)
1022 hotkey
+= wxT("<control>");
1023 if ( flags
& wxACCEL_SHIFT
)
1024 hotkey
+= wxT("<shift>");
1026 int code
= accel
->GetKeyCode();
1041 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1044 // if there are any other keys wxGetAccelFromString() may return,
1045 // we should process them here
1048 if ( wxIsalnum(code
) )
1050 hotkey
<< (wxChar
)code
;
1055 wxFAIL_MSG( wxT("unknown keyboard accel") );
1063 #endif // wxUSE_ACCEL