1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "menu.h"
12 #pragma implementation "menuitem.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
22 #include "wx/bitmap.h"
28 #include "wx/gtk/private.h"
30 #include <gdk/gdkkeysyms.h>
32 // FIXME: is this right? somehow I don't think so (VZ)
34 #include <glib-object.h>
36 #define gtk_accel_group_attach(g, o) gtk_window_add_accel_group((o), (g))
37 #define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g))
38 #define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m)
40 #define ACCEL_OBJECT GtkWindow
41 #define ACCEL_OBJECTS(a) (a)->acceleratables
42 #define ACCEL_OBJ_CAST(obj) ((GtkWindow*) obj)
44 #define ACCEL_OBJECT GtkObject
45 #define ACCEL_OBJECTS(a) (a)->attach_objects
46 #define ACCEL_OBJ_CAST(obj) GTK_OBJECT(obj)
49 // we use normal item but with a special id for the menu title
50 static const int wxGTK_TITLE_ID
= -3;
52 //-----------------------------------------------------------------------------
54 //-----------------------------------------------------------------------------
56 extern void wxapp_install_idle_handler();
60 static wxString
GetGtkHotKey( const wxMenuItem
& item
);
63 //-----------------------------------------------------------------------------
64 // substitute for missing GtkPixmapMenuItem
65 //-----------------------------------------------------------------------------
69 #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ())
70 #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem))
71 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass))
72 #define GTK_IS_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
73 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM))
74 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
75 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
77 #ifndef GTK_MENU_ITEM_GET_CLASS
78 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
81 typedef struct _GtkPixmapMenuItem GtkPixmapMenuItem
;
82 typedef struct _GtkPixmapMenuItemClass GtkPixmapMenuItemClass
;
84 struct _GtkPixmapMenuItem
86 GtkMenuItem menu_item
;
91 struct _GtkPixmapMenuItemClass
93 GtkMenuItemClass parent_class
;
95 guint orig_toggle_size
;
96 guint have_pixmap_count
;
100 GtkType
gtk_pixmap_menu_item_get_type (void);
101 GtkWidget
* gtk_pixmap_menu_item_new (void);
102 void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
106 #endif // !__WXGTK20__
108 //-----------------------------------------------------------------------------
110 //-----------------------------------------------------------------------------
112 static wxString
wxReplaceUnderscore( const wxString
& title
)
116 // GTK 1.2 wants to have "_" instead of "&" for accelerators
119 while (*pc
!= wxT('\0'))
121 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
123 // "&" is doubled to indicate "&" instead of accelerator
127 else if (*pc
== wxT('&'))
133 if ( *pc
== wxT('_') )
135 // underscores must be doubled to prevent them from being
136 // interpreted as accelerator character prefix by GTK
145 // wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() );
150 //-----------------------------------------------------------------------------
151 // activate message from GTK
152 //-----------------------------------------------------------------------------
155 static void gtk_menu_open_callback( GtkWidget
*widget
, wxMenu
*menu
)
157 if (g_isIdle
) wxapp_install_idle_handler();
159 wxMenuEvent
event( wxEVT_MENU_OPEN
, -1, menu
);
160 event
.SetEventObject( menu
);
162 wxEvtHandler
* handler
= menu
->GetEventHandler();
163 if (handler
&& handler
->ProcessEvent(event
))
166 wxWindow
*win
= menu
->GetInvokingWindow();
167 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
171 //-----------------------------------------------------------------------------
173 //-----------------------------------------------------------------------------
175 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
177 void wxMenuBar::Init(size_t n
, wxMenu
*menus
[], const wxString titles
[], long style
)
179 // the parent window is known after wxFrame::SetMenu()
180 m_needParent
= FALSE
;
182 m_invokingWindow
= (wxWindow
*) NULL
;
184 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
185 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
187 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
191 m_menubar
= gtk_menu_bar_new();
193 m_accel
= gtk_accel_group_new();
196 if (style
& wxMB_DOCKABLE
)
198 m_widget
= gtk_handle_box_new();
199 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
200 gtk_widget_show( GTK_WIDGET(m_menubar
) );
204 m_widget
= GTK_WIDGET(m_menubar
);
211 for (size_t i
= 0; i
< n
; ++i
)
212 Append(menus
[i
], titles
[i
]);
215 wxMenuBar::wxMenuBar(size_t n
, wxMenu
*menus
[], const wxString titles
[], long style
)
217 Init(n
, menus
, titles
, style
);
220 wxMenuBar::wxMenuBar(long style
)
222 Init(0, NULL
, NULL
, style
);
225 wxMenuBar::wxMenuBar()
227 Init(0, NULL
, NULL
, 0);
230 wxMenuBar::~wxMenuBar()
234 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
236 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
238 wxWindow
*top_frame
= win
;
239 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
240 top_frame
= top_frame
->GetParent();
243 // support for native hot keys
244 gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
247 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
250 wxMenuItem
*menuitem
= node
->GetData();
251 if (menuitem
->IsSubMenu())
252 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
253 node
= node
->GetNext();
257 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
259 menu
->SetInvokingWindow( win
);
261 wxWindow
*top_frame
= win
;
262 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
263 top_frame
= top_frame
->GetParent();
265 // support for native hot keys
266 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
267 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
268 gtk_accel_group_attach( menu
->m_accel
, obj
);
270 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
273 wxMenuItem
*menuitem
= node
->GetData();
274 if (menuitem
->IsSubMenu())
275 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
276 node
= node
->GetNext();
280 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
282 m_invokingWindow
= win
;
283 wxWindow
*top_frame
= win
;
284 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
285 top_frame
= top_frame
->GetParent();
288 // support for native key accelerators indicated by underscroes
289 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
290 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
291 gtk_accel_group_attach( m_accel
, obj
);
294 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
297 wxMenu
*menu
= node
->GetData();
298 wxMenubarSetInvokingWindow( menu
, win
);
299 node
= node
->GetNext();
303 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
305 m_invokingWindow
= (wxWindow
*) NULL
;
306 wxWindow
*top_frame
= win
;
307 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
308 top_frame
= top_frame
->GetParent();
311 // support for native key accelerators indicated by underscroes
312 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
315 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
318 wxMenu
*menu
= node
->GetData();
319 wxMenubarUnsetInvokingWindow( menu
, win
);
320 node
= node
->GetNext();
324 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
326 if ( !wxMenuBarBase::Append( menu
, title
) )
329 return GtkAppend(menu
, title
);
332 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
, int pos
)
334 wxString
str( wxReplaceUnderscore( title
) );
336 // This doesn't have much effect right now.
337 menu
->SetTitle( str
);
339 // The "m_owner" is the "menu item"
341 menu
->m_owner
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str
) );
343 menu
->m_owner
= gtk_menu_item_new_with_label( wxGTK_CONV( str
) );
344 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
346 gtk_label_set_text( label
, wxGTK_CONV( str
) );
348 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
349 if (accel_key
!= GDK_VoidSymbol
)
351 gtk_widget_add_accelerator (menu
->m_owner
,
353 m_accel
, //gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)),
360 gtk_widget_show( menu
->m_owner
);
362 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
365 gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
);
367 gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
, pos
);
369 gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate",
370 GTK_SIGNAL_FUNC(gtk_menu_open_callback
),
373 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
374 // addings menu later on.
375 if (m_invokingWindow
)
377 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
379 // OPTIMISE ME: we should probably cache this, or pass it
380 // directly, but for now this is a minimal
381 // change to validate the new dynamic sizing.
382 // see (and refactor :) similar code in Remove
385 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
388 frame
->UpdateMenuBarSize();
394 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
396 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
401 if ( !GtkAppend(menu
, title
, (int)pos
) )
407 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
409 // remove the old item and insert a new one
410 wxMenu
*menuOld
= Remove(pos
);
411 if ( menuOld
&& !Insert(pos
, menu
, title
) )
413 return (wxMenu
*) NULL
;
416 // either Insert() succeeded or Remove() failed and menuOld is NULL
420 wxMenu
*wxMenuBar::Remove(size_t pos
)
422 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
424 return (wxMenu
*) NULL
;
426 gtk_menu_item_remove_submenu( GTK_MENU_ITEM(menu
->m_owner
) );
427 gtk_container_remove(GTK_CONTAINER(m_menubar
), menu
->m_owner
);
429 gtk_widget_destroy( menu
->m_owner
);
430 menu
->m_owner
= NULL
;
432 if (m_invokingWindow
)
434 // OPTIMISE ME: see comment in GtkAppend
435 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
438 frame
->UpdateMenuBarSize();
444 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
446 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
448 int res
= menu
->FindItem( itemString
);
449 if (res
!= wxNOT_FOUND
)
453 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
456 wxMenuItem
*item
= node
->GetData();
457 if (item
->IsSubMenu())
458 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
460 node
= node
->GetNext();
466 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
468 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
471 wxMenu
*menu
= node
->GetData();
472 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
475 node
= node
->GetNext();
481 // Find a wxMenuItem using its id. Recurses down into sub-menus
482 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
484 wxMenuItem
* result
= menu
->FindChildItem(id
);
486 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
487 while ( node
&& result
== NULL
)
489 wxMenuItem
*item
= node
->GetData();
490 if (item
->IsSubMenu())
492 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
494 node
= node
->GetNext();
500 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
502 wxMenuItem
* result
= 0;
503 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
504 while (node
&& result
== 0)
506 wxMenu
*menu
= node
->GetData();
507 result
= FindMenuItemByIdRecursive( menu
, id
);
508 node
= node
->GetNext();
513 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
519 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
521 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
523 wxCHECK_RET( node
, wxT("menu not found") );
525 wxMenu
* menu
= node
->GetData();
528 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
531 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
533 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
535 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
537 wxMenu
* menu
= node
->GetData();
540 wxString
text( menu
->GetTitle() );
541 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
543 if ( *pc
== wxT('_') )
545 // '_' is the escape character for GTK+
549 // don't remove ampersands '&' since if we have them in the menu title
550 // it means that they were doubled to indicate "&" instead of accelerator
558 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
560 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
562 wxCHECK_RET( node
, wxT("menu not found") );
564 wxMenu
* menu
= node
->GetData();
566 wxString
str( wxReplaceUnderscore( label
) );
568 menu
->SetTitle( str
);
572 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
575 gtk_label_set( label
, wxGTK_CONV( str
) );
577 /* reparse key accel */
578 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
579 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
584 //-----------------------------------------------------------------------------
586 //-----------------------------------------------------------------------------
589 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
592 wxapp_install_idle_handler();
594 int id
= menu
->FindMenuIdByMenuItem(widget
);
596 /* should find it for normal (not popup) menu */
597 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
598 _T("menu item not found in gtk_menu_clicked_callback") );
600 if (!menu
->IsEnabled(id
))
603 wxMenuItem
* item
= menu
->FindChildItem( id
);
604 wxCHECK_RET( item
, wxT("error in menu item callback") );
606 if ( item
->GetId() == wxGTK_TITLE_ID
)
608 // ignore events from the menu title
612 if (item
->IsCheckable())
614 bool isReallyChecked
= item
->IsChecked(),
615 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
617 // ensure that the internal state is always consistent with what is
618 // shown on the screen
619 item
->wxMenuItemBase::Check(isReallyChecked
);
621 // we must not report the events for the radio button going up nor the
622 // events resulting from the calls to wxMenuItem::Check()
623 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
624 (isInternallyChecked
== isReallyChecked
) )
631 // Is this menu on a menubar? (possibly nested)
632 wxFrame
* frame
= NULL
;
633 if(menu
->IsAttached())
634 frame
= menu
->GetMenuBar()->GetFrame();
636 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
637 // normally wxMenu::SendEvent() should be enough, if it doesn't work
638 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
639 // should be fixed instead of working around it here...
642 // If it is attached then let the frame send the event.
643 // Don't call frame->ProcessCommand(id) because it toggles
644 // checkable items and we've already done that above.
645 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
646 commandEvent
.SetEventObject(frame
);
647 if (item
->IsCheckable())
648 commandEvent
.SetInt(item
->IsChecked());
649 commandEvent
.SetEventObject(menu
);
651 frame
->GetEventHandler()->ProcessEvent(commandEvent
);
655 // otherwise let the menu have it
656 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
661 //-----------------------------------------------------------------------------
663 //-----------------------------------------------------------------------------
666 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
668 if (g_isIdle
) wxapp_install_idle_handler();
670 int id
= menu
->FindMenuIdByMenuItem(widget
);
672 wxASSERT( id
!= -1 ); // should find it!
674 if (!menu
->IsEnabled(id
))
677 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
678 event
.SetEventObject( menu
);
680 wxEvtHandler
* handler
= menu
->GetEventHandler();
681 if (handler
&& handler
->ProcessEvent(event
))
684 wxWindow
*win
= menu
->GetInvokingWindow();
685 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
689 //-----------------------------------------------------------------------------
691 //-----------------------------------------------------------------------------
694 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
696 if (g_isIdle
) wxapp_install_idle_handler();
698 int id
= menu
->FindMenuIdByMenuItem(widget
);
700 wxASSERT( id
!= -1 ); // should find it!
702 if (!menu
->IsEnabled(id
))
705 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
706 event
.SetEventObject( menu
);
708 wxEvtHandler
* handler
= menu
->GetEventHandler();
709 if (handler
&& handler
->ProcessEvent(event
))
712 wxWindow
*win
= menu
->GetInvokingWindow();
714 win
->GetEventHandler()->ProcessEvent( event
);
718 //-----------------------------------------------------------------------------
720 //-----------------------------------------------------------------------------
722 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
724 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
726 const wxString
& name
,
727 const wxString
& help
,
731 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
734 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
736 const wxString
& text
,
737 const wxString
& help
,
740 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
745 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
747 const wxString
& text
,
748 const wxString
& help
,
751 : wxMenuItemBase(parentMenu
, id
, text
, help
,
752 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
757 void wxMenuItem::Init(const wxString
& text
)
759 m_labelWidget
= (GtkWidget
*) NULL
;
760 m_menuItem
= (GtkWidget
*) NULL
;
765 wxMenuItem::~wxMenuItem()
767 // don't delete menu items, the menus take care of that
770 // return the menu item text without any menu accels
772 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
776 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
778 if ( *pc
== wxT('\t'))
781 if ( *pc
== wxT('_') )
783 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
790 if ( *pc
== wxT('\\') )
792 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
799 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
802 // "&" is doubled to indicate "&" instead of accelerator
809 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
814 void wxMenuItem::SetText( const wxString
& str
)
816 // Some optimization to avoid flicker
817 wxString oldLabel
= m_text
;
818 oldLabel
= wxStripMenuCodes(oldLabel
);
819 oldLabel
.Replace(wxT("_"), wxT(""));
820 wxString label1
= wxStripMenuCodes(str
);
821 wxString oldhotkey
= GetHotKey(); // Store the old hotkey in Ctrl-foo format
822 wxCharBuffer oldbuf
= wxGTK_CONV( GetGtkHotKey(*this) ); // and as <control>foo
826 if (oldLabel
== label1
&&
827 oldhotkey
== GetHotKey()) // Make sure we can change a hotkey even if the label is unaltered
834 label
= (GtkLabel
*) m_labelWidget
;
836 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
839 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
842 gtk_label_set( label
, wxGTK_CONV( m_text
) );
845 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
846 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
851 GdkModifierType accel_mods
;
852 gtk_accelerator_parse( (const char*) oldbuf
, &accel_key
, &accel_mods
);
855 gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem
),
856 m_parentMenu
->m_accel
,
861 wxCharBuffer buf
= wxGTK_CONV( GetGtkHotKey(*this) );
862 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
865 gtk_widget_add_accelerator( GTK_WIDGET(m_menuItem
),
867 m_parentMenu
->m_accel
,
874 // it's valid for this function to be called even if m_menuItem == NULL
875 void wxMenuItem::DoSetText( const wxString
& str
)
877 // '\t' is the deliminator indicating a hot key
879 const wxChar
*pc
= str
;
880 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
882 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
884 // "&" is doubled to indicate "&" instead of accelerator
888 else if (*pc
== wxT('&'))
892 else if ( *pc
== wxT('_') ) // escape underscores
911 // wxPrintf( wxT("DoSetText(): str %s m_text %s hotkey %s\n"), str.c_str(), m_text.c_str(), m_hotKey.c_str() );
916 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
921 return (wxAcceleratorEntry
*)NULL
;
924 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
926 label
<< wxT('\t') << GetHotKey();
928 return wxGetAccelFromString(label
);
931 #endif // wxUSE_ACCEL
933 void wxMenuItem::Check( bool check
)
935 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
937 if (check
== m_isChecked
)
940 wxMenuItemBase::Check( check
);
946 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
950 wxFAIL_MSG( _T("can't check this item") );
954 void wxMenuItem::Enable( bool enable
)
956 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
958 gtk_widget_set_sensitive( m_menuItem
, enable
);
959 wxMenuItemBase::Enable( enable
);
962 bool wxMenuItem::IsChecked() const
964 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
966 wxCHECK_MSG( IsCheckable(), FALSE
,
967 wxT("can't get state of uncheckable item!") );
969 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
972 //-----------------------------------------------------------------------------
974 //-----------------------------------------------------------------------------
976 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
980 m_accel
= gtk_accel_group_new();
981 m_menu
= gtk_menu_new();
982 // NB: keep reference to the menu so that it is not destroyed behind
983 // our back by GTK+ e.g. when it is removed from menubar:
984 gtk_widget_ref(m_menu
);
986 m_owner
= (GtkWidget
*) NULL
;
988 // Tearoffs are entries, just like separators. So if we want this
989 // menu to be a tear-off one, we just append a tearoff entry
991 if ( m_style
& wxMENU_TEAROFF
)
993 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
995 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
1000 // append the title as the very first entry if we have it
1001 if ( !m_title
.empty() )
1003 Append(wxGTK_TITLE_ID
, m_title
);
1010 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1012 if ( GTK_IS_WIDGET( m_menu
))
1015 gtk_widget_unref( m_menu
);
1016 // if the menu is inserted in another menu at this time, there was
1017 // one more reference to it:
1019 gtk_widget_destroy( m_menu
);
1023 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
1025 GtkWidget
*menuItem
;
1032 if ( mitem
->IsSeparator() )
1035 menuItem
= gtk_separator_menu_item_new();
1038 menuItem
= gtk_menu_item_new();
1041 else if (mitem
->GetBitmap().Ok())
1043 text
= mitem
->GetText();
1044 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1047 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1050 if (bitmap
->HasPixbuf())
1052 image
= gtk_image_new_from_pixbuf(bitmap
->GetPixbuf());
1056 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1057 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ?
1058 bitmap
->GetMask()->GetBitmap() :
1060 image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1063 gtk_widget_show(image
);
1065 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1068 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1069 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1071 menuItem
= gtk_pixmap_menu_item_new ();
1072 label
= GTK_LABEL(gtk_accel_label_new ( wxGTK_CONV( text
) ));
1073 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1074 gtk_container_add (GTK_CONTAINER (menuItem
), GTK_WIDGET(label
));
1076 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1078 gtk_widget_show (GTK_WIDGET(label
));
1080 mitem
->SetLabelWidget(GTK_WIDGET(label
));
1082 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1083 gtk_widget_show(pixmap
);
1084 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1090 else // a normal item
1092 // text has "_" instead of "&" after mitem->SetText() so don't use it
1093 text
= mitem
->GetText() ;
1095 switch ( mitem
->GetKind() )
1100 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1102 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1103 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1105 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1113 GSList
*group
= NULL
;
1114 if ( m_prevRadio
== NULL
)
1116 // start of a new radio group
1118 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1120 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1121 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1123 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1126 else // continue the radio group
1129 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1130 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1132 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1133 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1134 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1141 wxFAIL_MSG( _T("unexpected menu item kind") );
1147 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1149 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1150 label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1160 GdkModifierType accel_mods
;
1161 wxCharBuffer buf
= wxGTK_CONV( GetGtkHotKey(*mitem
) );
1163 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetGtkHotKey(*mitem).c_str() );
1164 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1167 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1176 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1178 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1180 gtk_widget_show( menuItem
);
1182 if ( !mitem
->IsSeparator() )
1184 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1186 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1187 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1190 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1191 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1194 if ( mitem
->IsSubMenu() && mitem
->GetKind() != wxITEM_RADIO
&& mitem
->GetKind() != wxITEM_CHECK
)
1196 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1198 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1200 // if adding a submenu to a menu already existing in the menu bar, we
1201 // must set invoking window to allow processing events from this
1203 if ( m_invokingWindow
)
1204 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1208 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1209 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1214 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1215 if (accel_key
!= GDK_VoidSymbol
)
1217 gtk_widget_add_accelerator (menuItem
,
1219 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1227 mitem
->SetMenuItem(menuItem
);
1231 // This doesn't even exist!
1232 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1238 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1240 if (!GtkAppend(mitem
))
1243 return wxMenuBase::DoAppend(mitem
);
1246 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1248 if ( !wxMenuBase::DoInsert(pos
, item
) )
1252 if ( !GtkAppend(item
, (int)pos
) )
1258 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1260 if ( !wxMenuBase::DoRemove(item
) )
1261 return (wxMenuItem
*)NULL
;
1263 // TODO: this code doesn't delete the item factory item and this seems
1264 // impossible as of GTK 1.2.6.
1265 gtk_widget_destroy( item
->GetMenuItem() );
1270 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1272 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1275 wxMenuItem
*item
= node
->GetData();
1276 if (item
->GetMenuItem() == menuItem
)
1277 return item
->GetId();
1278 node
= node
->GetNext();
1284 // ----------------------------------------------------------------------------
1286 // ----------------------------------------------------------------------------
1290 static wxString
GetGtkHotKey( const wxMenuItem
& item
)
1294 wxAcceleratorEntry
*accel
= item
.GetAccel();
1297 int flags
= accel
->GetFlags();
1298 if ( flags
& wxACCEL_ALT
)
1299 hotkey
+= wxT("<alt>");
1300 if ( flags
& wxACCEL_CTRL
)
1301 hotkey
+= wxT("<control>");
1302 if ( flags
& wxACCEL_SHIFT
)
1303 hotkey
+= wxT("<shift>");
1305 int code
= accel
->GetKeyCode();
1332 hotkey
+= wxString::Format(wxT("F%d"), code
- WXK_F1
+ 1);
1335 // TODO: we should use gdk_keyval_name() (a.k.a.
1336 // XKeysymToString) here as well as hardcoding the keysym
1337 // names this might be not portable
1339 hotkey
<< wxT("Insert" );
1342 hotkey
<< wxT("Delete" );
1345 hotkey
<< wxT("Up" );
1348 hotkey
<< wxT("Down" );
1352 hotkey
<< wxT("Prior" );
1356 hotkey
<< wxT("Next" );
1359 hotkey
<< wxT("Left" );
1362 hotkey
<< wxT("Right" );
1365 hotkey
<< wxT("Home" );
1368 hotkey
<< wxT("End" );
1371 hotkey
<< wxT("Return" );
1374 hotkey
<< wxT("BackSpace" );
1377 hotkey
<< wxT("Tab" );
1380 hotkey
<< wxT("Esc" );
1383 hotkey
<< wxT("space" );
1386 hotkey
<< wxT("Multiply" );
1389 hotkey
<< wxT("Add" );
1392 hotkey
<< wxT("Separator" );
1395 hotkey
<< wxT("Subtract" );
1398 hotkey
<< wxT("Decimal" );
1401 hotkey
<< wxT("Divide" );
1404 hotkey
<< wxT("Cancel" );
1407 hotkey
<< wxT("Clear" );
1410 hotkey
<< wxT("Menu" );
1413 hotkey
<< wxT("Pause" );
1416 hotkey
<< wxT("Capital" );
1419 hotkey
<< wxT("Select" );
1422 hotkey
<< wxT("Print" );
1425 hotkey
<< wxT("Execute" );
1428 hotkey
<< wxT("Snapshot" );
1431 hotkey
<< wxT("Help" );
1434 hotkey
<< wxT("Num_Lock" );
1437 hotkey
<< wxT("Scroll_Lock" );
1439 case WXK_NUMPAD_INSERT
:
1440 hotkey
<< wxT("KP_Insert" );
1442 case WXK_NUMPAD_DELETE
:
1443 hotkey
<< wxT("KP_Delete" );
1445 case WXK_NUMPAD_SPACE
:
1446 hotkey
<< wxT("KP_Space" );
1448 case WXK_NUMPAD_TAB
:
1449 hotkey
<< wxT("KP_Tab" );
1451 case WXK_NUMPAD_ENTER
:
1452 hotkey
<< wxT("KP_Enter" );
1454 case WXK_NUMPAD_F1
: case WXK_NUMPAD_F2
: case WXK_NUMPAD_F3
:
1456 hotkey
+= wxString::Format(wxT("KP_F%d"), code
- WXK_NUMPAD_F1
+ 1);
1458 case WXK_NUMPAD_HOME
:
1459 hotkey
<< wxT("KP_Home" );
1461 case WXK_NUMPAD_LEFT
:
1462 hotkey
<< wxT("KP_Left" );
1465 hotkey
<< wxT("KP_Up" );
1467 case WXK_NUMPAD_RIGHT
:
1468 hotkey
<< wxT("KP_Right" );
1470 case WXK_NUMPAD_DOWN
:
1471 hotkey
<< wxT("KP_Down" );
1473 case WXK_NUMPAD_PRIOR
: case WXK_NUMPAD_PAGEUP
:
1474 hotkey
<< wxT("KP_Prior" );
1476 case WXK_NUMPAD_NEXT
: case WXK_NUMPAD_PAGEDOWN
:
1477 hotkey
<< wxT("KP_Next" );
1479 case WXK_NUMPAD_END
:
1480 hotkey
<< wxT("KP_End" );
1482 case WXK_NUMPAD_BEGIN
:
1483 hotkey
<< wxT("KP_Begin" );
1485 case WXK_NUMPAD_EQUAL
:
1486 hotkey
<< wxT("KP_Equal" );
1488 case WXK_NUMPAD_MULTIPLY
:
1489 hotkey
<< wxT("KP_Multiply" );
1491 case WXK_NUMPAD_ADD
:
1492 hotkey
<< wxT("KP_Add" );
1494 case WXK_NUMPAD_SEPARATOR
:
1495 hotkey
<< wxT("KP_Separator" );
1497 case WXK_NUMPAD_SUBTRACT
:
1498 hotkey
<< wxT("KP_Subtract" );
1500 case WXK_NUMPAD_DECIMAL
:
1501 hotkey
<< wxT("KP_Decimal" );
1503 case WXK_NUMPAD_DIVIDE
:
1504 hotkey
<< wxT("KP_Divide" );
1506 case WXK_NUMPAD0
: case WXK_NUMPAD1
: case WXK_NUMPAD2
:
1507 case WXK_NUMPAD3
: case WXK_NUMPAD4
: case WXK_NUMPAD5
:
1508 case WXK_NUMPAD6
: case WXK_NUMPAD7
: case WXK_NUMPAD8
: case WXK_NUMPAD9
:
1509 hotkey
+= wxString::Format(wxT("KP_%d"), code
- WXK_NUMPAD0
);
1511 case WXK_WINDOWS_LEFT
:
1512 hotkey
<< wxT("Super_L" );
1514 case WXK_WINDOWS_RIGHT
:
1515 hotkey
<< wxT("Super_R" );
1517 case WXK_WINDOWS_MENU
:
1518 hotkey
<< wxT("Menu" );
1521 hotkey
<< wxT("Command" );
1523 /* These probably wouldn't work as there is no SpecialX in gdk/keynames.txt
1524 case WXK_SPECIAL1: case WXK_SPECIAL2: case WXK_SPECIAL3: case WXK_SPECIAL4:
1525 case WXK_SPECIAL5: case WXK_SPECIAL6: case WXK_SPECIAL7: case WXK_SPECIAL8:
1526 case WXK_SPECIAL9: case WXK_SPECIAL10: case WXK_SPECIAL11: case WXK_SPECIAL12:
1527 case WXK_SPECIAL13: case WXK_SPECIAL14: case WXK_SPECIAL15: case WXK_SPECIAL16:
1528 case WXK_SPECIAL17: case WXK_SPECIAL18: case WXK_SPECIAL19: case WXK_SPECIAL20:
1529 hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1);
1532 // if there are any other keys wxGetAccelFromString() may
1533 // return, we should process them here
1538 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1546 wxFAIL_MSG( wxT("unknown keyboard accel") );
1555 #endif // wxUSE_ACCEL
1558 //-----------------------------------------------------------------------------
1559 // substitute for missing GtkPixmapMenuItem
1560 //-----------------------------------------------------------------------------
1565 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1566 * All rights reserved.
1568 * This file is part of the Gnome Library.
1570 * The Gnome Library is free software; you can redistribute it and/or
1571 * modify it under the terms of the GNU Library General Public License as
1572 * published by the Free Software Foundation; either version 2 of the
1573 * License, or (at your option) any later version.
1575 * The Gnome Library is distributed in the hope that it will be useful,
1576 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1577 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1578 * Library General Public License for more details.
1580 * You should have received a copy of the GNU Library General Public
1581 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1582 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1583 * Boston, MA 02111-1307, USA.
1589 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1591 #include <gtk/gtkaccellabel.h>
1592 #include <gtk/gtksignal.h>
1593 #include <gtk/gtkmenuitem.h>
1594 #include <gtk/gtkmenu.h>
1595 #include <gtk/gtkcontainer.h>
1600 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1601 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1602 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1603 GdkRectangle
*area
);
1604 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1605 GdkEventExpose
*event
);
1607 /* we must override the following functions */
1609 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1610 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1611 GtkAllocation
*allocation
);
1612 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1613 gboolean include_internals
,
1614 GtkCallback callback
,
1615 gpointer callback_data
);
1616 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1617 GtkRequisition
*requisition
);
1618 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1621 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1623 static GtkMenuItemClass
*parent_class
= NULL
;
1627 #define BORDER_SPACING 3
1628 #define PMAP_WIDTH 20
1631 gtk_pixmap_menu_item_get_type (void)
1633 static GtkType pixmap_menu_item_type
= 0;
1635 if (!pixmap_menu_item_type
)
1637 GtkTypeInfo pixmap_menu_item_info
=
1639 (char *)"GtkPixmapMenuItem",
1640 sizeof (GtkPixmapMenuItem
),
1641 sizeof (GtkPixmapMenuItemClass
),
1642 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1643 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1644 /* reserved_1 */ NULL
,
1645 /* reserved_2 */ NULL
,
1646 (GtkClassInitFunc
) NULL
,
1649 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1650 &pixmap_menu_item_info
);
1653 return pixmap_menu_item_type
;
1659 * gtk_pixmap_menu_item_new
1661 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1662 * to set the pixmap wich is displayed at the left side.
1665 * &GtkWidget pointer to new menu item
1669 gtk_pixmap_menu_item_new (void)
1671 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1675 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1677 GtkObjectClass
*object_class
;
1678 GtkWidgetClass
*widget_class
;
1679 GtkMenuItemClass
*menu_item_class
;
1680 GtkContainerClass
*container_class
;
1682 object_class
= (GtkObjectClass
*) klass
;
1683 widget_class
= (GtkWidgetClass
*) klass
;
1684 menu_item_class
= (GtkMenuItemClass
*) klass
;
1685 container_class
= (GtkContainerClass
*) klass
;
1687 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1689 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1690 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1691 widget_class
->map
= gtk_pixmap_menu_item_map
;
1692 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1693 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1695 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1696 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1698 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1699 klass
->have_pixmap_count
= 0;
1703 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1707 mi
= GTK_MENU_ITEM (menu_item
);
1709 menu_item
->pixmap
= NULL
;
1713 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1716 g_return_if_fail (widget
!= NULL
);
1717 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1718 g_return_if_fail (area
!= NULL
);
1720 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1721 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1723 if (GTK_WIDGET_DRAWABLE (widget
) &&
1724 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1725 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1730 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1731 GdkEventExpose
*event
)
1733 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1734 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1735 g_return_val_if_fail (event
!= NULL
, FALSE
);
1737 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1738 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1740 if (GTK_WIDGET_DRAWABLE (widget
) &&
1741 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1742 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1749 * gtk_pixmap_menu_item_set_pixmap
1750 * @menu_item: Pointer to the pixmap menu item
1751 * @pixmap: Pointer to a pixmap widget
1753 * Set the pixmap of the menu item.
1758 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1761 g_return_if_fail (menu_item
!= NULL
);
1762 g_return_if_fail (pixmap
!= NULL
);
1763 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1764 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1765 g_return_if_fail (menu_item
->pixmap
== NULL
);
1767 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1768 menu_item
->pixmap
= pixmap
;
1770 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1771 !GTK_WIDGET_REALIZED (pixmap
))
1772 gtk_widget_realize (pixmap
);
1774 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1775 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1776 GTK_WIDGET_VISIBLE(pixmap
) &&
1777 !GTK_WIDGET_MAPPED (pixmap
))
1778 gtk_widget_map (pixmap
);
1781 changed_have_pixmap_status(menu_item
);
1783 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1784 gtk_widget_queue_resize (pixmap
);
1788 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1790 GtkPixmapMenuItem
*menu_item
;
1792 g_return_if_fail (widget
!= NULL
);
1793 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1795 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1797 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1799 if (menu_item
->pixmap
&&
1800 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1801 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1802 gtk_widget_map (menu_item
->pixmap
);
1806 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1807 GtkAllocation
*allocation
)
1809 GtkPixmapMenuItem
*pmenu_item
;
1811 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1813 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1815 GtkAllocation child_allocation
;
1818 border_width
= GTK_CONTAINER (widget
)->border_width
;
1820 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1821 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1822 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1823 child_allocation
.y
= (border_width
+ BORDER_SPACING
1824 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1825 / 2)); /* center pixmaps vertically */
1826 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1829 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1830 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1834 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1835 gboolean include_internals
,
1836 GtkCallback callback
,
1837 gpointer callback_data
)
1839 GtkPixmapMenuItem
*menu_item
;
1841 g_return_if_fail (container
!= NULL
);
1842 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1843 g_return_if_fail (callback
!= NULL
);
1845 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1847 if (menu_item
->pixmap
)
1848 (* callback
) (menu_item
->pixmap
, callback_data
);
1850 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1851 callback
,callback_data
);
1855 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1856 GtkRequisition
*requisition
)
1858 GtkPixmapMenuItem
*menu_item
;
1859 GtkRequisition req
= {0, 0};
1861 g_return_if_fail (widget
!= NULL
);
1862 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1863 g_return_if_fail (requisition
!= NULL
);
1865 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1867 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1869 if (menu_item
->pixmap
)
1870 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1872 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1873 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1877 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1881 gboolean widget_was_visible
;
1883 g_return_if_fail (container
!= NULL
);
1884 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1885 g_return_if_fail (child
!= NULL
);
1886 g_return_if_fail (GTK_IS_WIDGET (child
));
1888 bin
= GTK_BIN (container
);
1889 g_return_if_fail ((bin
->child
== child
||
1890 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1892 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1894 gtk_widget_unparent (child
);
1895 if (bin
->child
== child
)
1898 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1899 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1902 if (widget_was_visible
)
1903 gtk_widget_queue_resize (GTK_WIDGET (container
));
1907 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1909 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1911 if (menu_item
->pixmap
!= NULL
) {
1912 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1914 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1915 /* Install pixmap toggle size */
1916 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1919 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1921 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1922 /* Install normal toggle size */
1923 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1927 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1928 whenever the klass->toggle_size changes; but by doing it anytime
1929 this function is called, we get the same effect, just because of
1930 how the preferences option to show pixmaps works. Bogus, broken.
1932 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1933 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));
1938 #endif // !__WXGTK20__