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 // Make sure we can change a hotkey even if the label is unaltered
822 wxString oldhotkey
= GetHotKey();
826 if (oldLabel
== label1
&& oldhotkey
== GetHotKey())
833 label
= (GtkLabel
*) m_labelWidget
;
835 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
838 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
841 gtk_label_set( label
, wxGTK_CONV( m_text
) );
844 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
845 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
851 GdkModifierType accel_mods
;
852 wxCharBuffer oldbuf
= wxGTK_CONV( oldhotkey
);
853 gtk_accelerator_parse( (const char*) oldbuf
, &accel_key
, &accel_mods
);
856 gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem
),
857 m_parentMenu
->m_accel
,
862 wxCharBuffer buf
= wxGTK_CONV( GetGtkHotKey(*this) );
863 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
866 gtk_widget_add_accelerator( GTK_WIDGET(m_menuItem
),
868 m_parentMenu
->m_accel
,
876 // it's valid for this function to be called even if m_menuItem == NULL
877 void wxMenuItem::DoSetText( const wxString
& str
)
879 // '\t' is the deliminator indicating a hot key
881 const wxChar
*pc
= str
;
882 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
884 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
886 // "&" is doubled to indicate "&" instead of accelerator
890 else if (*pc
== wxT('&'))
894 else if ( *pc
== wxT('_') ) // escape underscores
913 // wxPrintf( wxT("DoSetText(): str %s m_text %s hotkey %s\n"), str.c_str(), m_text.c_str(), m_hotKey.c_str() );
918 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
923 return (wxAcceleratorEntry
*)NULL
;
926 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
928 label
<< wxT('\t') << GetHotKey();
930 return wxGetAccelFromString(label
);
933 #endif // wxUSE_ACCEL
935 void wxMenuItem::Check( bool check
)
937 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
939 if (check
== m_isChecked
)
942 wxMenuItemBase::Check( check
);
948 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
952 wxFAIL_MSG( _T("can't check this item") );
956 void wxMenuItem::Enable( bool enable
)
958 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
960 gtk_widget_set_sensitive( m_menuItem
, enable
);
961 wxMenuItemBase::Enable( enable
);
964 bool wxMenuItem::IsChecked() const
966 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
968 wxCHECK_MSG( IsCheckable(), FALSE
,
969 wxT("can't get state of uncheckable item!") );
971 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
974 //-----------------------------------------------------------------------------
976 //-----------------------------------------------------------------------------
978 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
982 m_accel
= gtk_accel_group_new();
983 m_menu
= gtk_menu_new();
984 // NB: keep reference to the menu so that it is not destroyed behind
985 // our back by GTK+ e.g. when it is removed from menubar:
986 gtk_widget_ref(m_menu
);
988 m_owner
= (GtkWidget
*) NULL
;
990 // Tearoffs are entries, just like separators. So if we want this
991 // menu to be a tear-off one, we just append a tearoff entry
993 if ( m_style
& wxMENU_TEAROFF
)
995 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
997 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
1002 // append the title as the very first entry if we have it
1003 if ( !m_title
.empty() )
1005 Append(wxGTK_TITLE_ID
, m_title
);
1012 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1014 if ( GTK_IS_WIDGET( m_menu
))
1017 gtk_widget_unref( m_menu
);
1018 // if the menu is inserted in another menu at this time, there was
1019 // one more reference to it:
1021 gtk_widget_destroy( m_menu
);
1025 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
1027 GtkWidget
*menuItem
;
1029 if ( mitem
->IsSeparator() )
1032 menuItem
= gtk_separator_menu_item_new();
1035 menuItem
= gtk_menu_item_new();
1038 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1040 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1042 else if ( mitem
->IsSubMenu() )
1044 // text has "_" instead of "&" after mitem->SetText()
1045 wxString
text( mitem
->GetText() );
1048 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1050 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1051 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1053 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1054 // reparse key accel
1055 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1056 if (accel_key
!= GDK_VoidSymbol
)
1058 gtk_widget_add_accelerator (menuItem
,
1060 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1067 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1069 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1071 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1073 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1075 // if adding a submenu to a menu already existing in the menu bar, we
1076 // must set invoking window to allow processing events from this
1078 if ( m_invokingWindow
)
1079 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1083 else if (mitem
->GetBitmap().Ok())
1085 wxString text
= mitem
->GetText();
1086 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1089 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1092 if (bitmap
->HasPixbuf())
1094 image
= gtk_image_new_from_pixbuf(bitmap
->GetPixbuf());
1098 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1099 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ?
1100 bitmap
->GetMask()->GetBitmap() :
1102 image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1105 gtk_widget_show(image
);
1107 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1109 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1110 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1114 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1116 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1118 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1119 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1121 menuItem
= gtk_pixmap_menu_item_new ();
1122 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1123 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1124 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1126 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1128 GdkModifierType accel_mods
;
1130 // accelerator for the item, as specified by its label
1131 // (ex. Ctrl+O for open)
1132 gtk_accelerator_parse(GetGtkHotKey(*mitem
).c_str(), &accel_key
,
1134 if (accel_key
!= GDK_VoidSymbol
)
1136 gtk_widget_add_accelerator (menuItem
,
1139 accel_key
, accel_mods
,
1143 // accelerator for the underlined char (ex ALT+F for the File menu)
1144 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1145 if (accel_key
!= GDK_VoidSymbol
)
1147 gtk_widget_add_accelerator (menuItem
,
1149 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1155 gtk_widget_show (label
);
1157 mitem
->SetLabelWidget(label
);
1159 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1160 gtk_widget_show(pixmap
);
1161 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1163 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1164 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1168 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1170 gtk_menu_insert( GTK_MENU(m_menu
), menuItem
, pos
);
1171 gtk_widget_show( menuItem
);
1176 else // a normal item
1178 // text has "_" instead of "&" after mitem->SetText() so don't use it
1179 wxString
text( mitem
->GetText() );
1181 switch ( mitem
->GetKind() )
1186 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1188 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1189 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1191 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1192 // reparse key accel
1193 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1194 if (accel_key
!= GDK_VoidSymbol
)
1196 gtk_widget_add_accelerator (menuItem
,
1198 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1210 GSList
*group
= NULL
;
1211 if ( m_prevRadio
== NULL
)
1213 // start of a new radio group
1215 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1217 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1218 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1220 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1221 // reparse key accel
1222 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1223 if (accel_key
!= GDK_VoidSymbol
)
1225 gtk_widget_add_accelerator (menuItem
,
1227 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1234 else // continue the radio group
1237 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1238 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1240 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1241 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1242 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1244 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1245 // reparse key accel
1246 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1247 if (accel_key
!= GDK_VoidSymbol
)
1249 gtk_widget_add_accelerator (menuItem
,
1251 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1262 wxFAIL_MSG( _T("unexpected menu item kind") );
1268 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1270 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1271 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1273 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1274 // reparse key accel
1275 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1276 if (accel_key
!= GDK_VoidSymbol
)
1278 gtk_widget_add_accelerator (menuItem
,
1280 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1291 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1292 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1296 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1298 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1302 GdkModifierType accel_mods
;
1303 wxCharBuffer buf
= wxGTK_CONV( GetGtkHotKey(*mitem
) );
1305 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetGtkHotKey(*mitem).c_str() );
1306 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1309 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1317 gtk_widget_show( menuItem
);
1319 if ( !mitem
->IsSeparator() )
1321 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1323 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1324 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1327 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1328 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1332 mitem
->SetMenuItem(menuItem
);
1336 // This doesn't even exist!
1337 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1343 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1345 if (!GtkAppend(mitem
))
1348 return wxMenuBase::DoAppend(mitem
);
1351 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1353 if ( !wxMenuBase::DoInsert(pos
, item
) )
1357 if ( !GtkAppend(item
, (int)pos
) )
1363 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1365 if ( !wxMenuBase::DoRemove(item
) )
1366 return (wxMenuItem
*)NULL
;
1368 // TODO: this code doesn't delete the item factory item and this seems
1369 // impossible as of GTK 1.2.6.
1370 gtk_widget_destroy( item
->GetMenuItem() );
1375 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1377 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1380 wxMenuItem
*item
= node
->GetData();
1381 if (item
->GetMenuItem() == menuItem
)
1382 return item
->GetId();
1383 node
= node
->GetNext();
1389 // ----------------------------------------------------------------------------
1391 // ----------------------------------------------------------------------------
1395 static wxString
GetGtkHotKey( const wxMenuItem
& item
)
1399 wxAcceleratorEntry
*accel
= item
.GetAccel();
1402 int flags
= accel
->GetFlags();
1403 if ( flags
& wxACCEL_ALT
)
1404 hotkey
+= wxT("<alt>");
1405 if ( flags
& wxACCEL_CTRL
)
1406 hotkey
+= wxT("<control>");
1407 if ( flags
& wxACCEL_SHIFT
)
1408 hotkey
+= wxT("<shift>");
1410 int code
= accel
->GetKeyCode();
1425 hotkey
+= wxString::Format(wxT("F%d"), code
- WXK_F1
+ 1);
1428 // TODO: we should use gdk_keyval_name() (a.k.a.
1429 // XKeysymToString) here as well as hardcoding the keysym
1430 // names this might be not portable
1431 case WXK_NUMPAD_INSERT
:
1432 hotkey
<< wxT("KP_Insert" );
1434 case WXK_NUMPAD_DELETE
:
1435 hotkey
<< wxT("KP_Delete" );
1438 hotkey
<< wxT("Insert" );
1441 hotkey
<< wxT("Delete" );
1444 hotkey
<< wxT("Up" );
1447 hotkey
<< wxT("Down" );
1451 hotkey
<< wxT("Prior" );
1455 hotkey
<< wxT("Next" );
1458 hotkey
<< wxT("Left" );
1461 hotkey
<< wxT("Right" );
1464 hotkey
<< wxT("Home" );
1467 hotkey
<< wxT("End" );
1470 hotkey
<< wxT("Return" );
1473 // if there are any other keys wxGetAccelFromString() may
1474 // return, we should process them here
1479 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1487 wxFAIL_MSG( wxT("unknown keyboard accel") );
1496 #endif // wxUSE_ACCEL
1499 //-----------------------------------------------------------------------------
1500 // substitute for missing GtkPixmapMenuItem
1501 //-----------------------------------------------------------------------------
1506 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1507 * All rights reserved.
1509 * This file is part of the Gnome Library.
1511 * The Gnome Library is free software; you can redistribute it and/or
1512 * modify it under the terms of the GNU Library General Public License as
1513 * published by the Free Software Foundation; either version 2 of the
1514 * License, or (at your option) any later version.
1516 * The Gnome Library is distributed in the hope that it will be useful,
1517 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1518 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1519 * Library General Public License for more details.
1521 * You should have received a copy of the GNU Library General Public
1522 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1523 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1524 * Boston, MA 02111-1307, USA.
1530 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1532 #include <gtk/gtkaccellabel.h>
1533 #include <gtk/gtksignal.h>
1534 #include <gtk/gtkmenuitem.h>
1535 #include <gtk/gtkmenu.h>
1536 #include <gtk/gtkcontainer.h>
1541 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1542 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1543 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1544 GdkRectangle
*area
);
1545 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1546 GdkEventExpose
*event
);
1548 /* we must override the following functions */
1550 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1551 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1552 GtkAllocation
*allocation
);
1553 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1554 gboolean include_internals
,
1555 GtkCallback callback
,
1556 gpointer callback_data
);
1557 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1558 GtkRequisition
*requisition
);
1559 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1562 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1564 static GtkMenuItemClass
*parent_class
= NULL
;
1568 #define BORDER_SPACING 3
1569 #define PMAP_WIDTH 20
1572 gtk_pixmap_menu_item_get_type (void)
1574 static GtkType pixmap_menu_item_type
= 0;
1576 if (!pixmap_menu_item_type
)
1578 GtkTypeInfo pixmap_menu_item_info
=
1580 (char *)"GtkPixmapMenuItem",
1581 sizeof (GtkPixmapMenuItem
),
1582 sizeof (GtkPixmapMenuItemClass
),
1583 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1584 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1585 /* reserved_1 */ NULL
,
1586 /* reserved_2 */ NULL
,
1587 (GtkClassInitFunc
) NULL
,
1590 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1591 &pixmap_menu_item_info
);
1594 return pixmap_menu_item_type
;
1600 * gtk_pixmap_menu_item_new
1602 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1603 * to set the pixmap wich is displayed at the left side.
1606 * &GtkWidget pointer to new menu item
1610 gtk_pixmap_menu_item_new (void)
1612 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1616 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1618 GtkObjectClass
*object_class
;
1619 GtkWidgetClass
*widget_class
;
1620 GtkMenuItemClass
*menu_item_class
;
1621 GtkContainerClass
*container_class
;
1623 object_class
= (GtkObjectClass
*) klass
;
1624 widget_class
= (GtkWidgetClass
*) klass
;
1625 menu_item_class
= (GtkMenuItemClass
*) klass
;
1626 container_class
= (GtkContainerClass
*) klass
;
1628 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1630 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1631 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1632 widget_class
->map
= gtk_pixmap_menu_item_map
;
1633 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1634 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1636 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1637 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1639 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1640 klass
->have_pixmap_count
= 0;
1644 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1648 mi
= GTK_MENU_ITEM (menu_item
);
1650 menu_item
->pixmap
= NULL
;
1654 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1657 g_return_if_fail (widget
!= NULL
);
1658 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1659 g_return_if_fail (area
!= NULL
);
1661 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1662 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1664 if (GTK_WIDGET_DRAWABLE (widget
) &&
1665 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1666 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1671 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1672 GdkEventExpose
*event
)
1674 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1675 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1676 g_return_val_if_fail (event
!= NULL
, FALSE
);
1678 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1679 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1681 if (GTK_WIDGET_DRAWABLE (widget
) &&
1682 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1683 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1690 * gtk_pixmap_menu_item_set_pixmap
1691 * @menu_item: Pointer to the pixmap menu item
1692 * @pixmap: Pointer to a pixmap widget
1694 * Set the pixmap of the menu item.
1699 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1702 g_return_if_fail (menu_item
!= NULL
);
1703 g_return_if_fail (pixmap
!= NULL
);
1704 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1705 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1706 g_return_if_fail (menu_item
->pixmap
== NULL
);
1708 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1709 menu_item
->pixmap
= pixmap
;
1711 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1712 !GTK_WIDGET_REALIZED (pixmap
))
1713 gtk_widget_realize (pixmap
);
1715 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1716 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1717 GTK_WIDGET_VISIBLE(pixmap
) &&
1718 !GTK_WIDGET_MAPPED (pixmap
))
1719 gtk_widget_map (pixmap
);
1722 changed_have_pixmap_status(menu_item
);
1724 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1725 gtk_widget_queue_resize (pixmap
);
1729 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1731 GtkPixmapMenuItem
*menu_item
;
1733 g_return_if_fail (widget
!= NULL
);
1734 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1736 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1738 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1740 if (menu_item
->pixmap
&&
1741 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1742 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1743 gtk_widget_map (menu_item
->pixmap
);
1747 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1748 GtkAllocation
*allocation
)
1750 GtkPixmapMenuItem
*pmenu_item
;
1752 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1754 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1756 GtkAllocation child_allocation
;
1759 border_width
= GTK_CONTAINER (widget
)->border_width
;
1761 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1762 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1763 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1764 child_allocation
.y
= (border_width
+ BORDER_SPACING
1765 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1766 / 2)); /* center pixmaps vertically */
1767 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1770 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1771 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1775 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1776 gboolean include_internals
,
1777 GtkCallback callback
,
1778 gpointer callback_data
)
1780 GtkPixmapMenuItem
*menu_item
;
1782 g_return_if_fail (container
!= NULL
);
1783 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1784 g_return_if_fail (callback
!= NULL
);
1786 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1788 if (menu_item
->pixmap
)
1789 (* callback
) (menu_item
->pixmap
, callback_data
);
1791 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1792 callback
,callback_data
);
1796 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1797 GtkRequisition
*requisition
)
1799 GtkPixmapMenuItem
*menu_item
;
1800 GtkRequisition req
= {0, 0};
1802 g_return_if_fail (widget
!= NULL
);
1803 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1804 g_return_if_fail (requisition
!= NULL
);
1806 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1808 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1810 if (menu_item
->pixmap
)
1811 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1813 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1814 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1818 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1822 gboolean widget_was_visible
;
1824 g_return_if_fail (container
!= NULL
);
1825 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1826 g_return_if_fail (child
!= NULL
);
1827 g_return_if_fail (GTK_IS_WIDGET (child
));
1829 bin
= GTK_BIN (container
);
1830 g_return_if_fail ((bin
->child
== child
||
1831 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1833 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1835 gtk_widget_unparent (child
);
1836 if (bin
->child
== child
)
1839 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1840 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1843 if (widget_was_visible
)
1844 gtk_widget_queue_resize (GTK_WIDGET (container
));
1848 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1850 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1852 if (menu_item
->pixmap
!= NULL
) {
1853 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1855 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1856 /* Install pixmap toggle size */
1857 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1860 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1862 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1863 /* Install normal toggle size */
1864 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1868 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1869 whenever the klass->toggle_size changes; but by doing it anytime
1870 this function is called, we get the same effect, just because of
1871 how the preferences option to show pixmaps works. Bogus, broken.
1873 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1874 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));
1879 #endif // !__WXGTK20__