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"
21 #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 //-----------------------------------------------------------------------------
51 //-----------------------------------------------------------------------------
53 extern void wxapp_install_idle_handler();
57 static wxString
GetHotKey( const wxMenuItem
& item
);
60 //-----------------------------------------------------------------------------
61 // substitute for missing GtkPixmapMenuItem
62 //-----------------------------------------------------------------------------
66 #define GTK_TYPE_PIXMAP_MENU_ITEM (gtk_pixmap_menu_item_get_type ())
67 #define GTK_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItem))
68 #define GTK_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PIXMAP_MENU_ITEM, GtkPixmapMenuItemClass))
69 #define GTK_IS_PIXMAP_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
70 #define GTK_IS_PIXMAP_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PIXMAP_MENU_ITEM))
71 //#define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PIXMAP_MENU_ITEM))
72 #define GTK_PIXMAP_MENU_ITEM_GET_CLASS(obj) (GTK_PIXMAP_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
74 #ifndef GTK_MENU_ITEM_GET_CLASS
75 #define GTK_MENU_ITEM_GET_CLASS(obj) (GTK_MENU_ITEM_CLASS( GTK_OBJECT_GET_CLASS(obj)))
78 typedef struct _GtkPixmapMenuItem GtkPixmapMenuItem
;
79 typedef struct _GtkPixmapMenuItemClass GtkPixmapMenuItemClass
;
81 struct _GtkPixmapMenuItem
83 GtkMenuItem menu_item
;
88 struct _GtkPixmapMenuItemClass
90 GtkMenuItemClass parent_class
;
92 guint orig_toggle_size
;
93 guint have_pixmap_count
;
97 GtkType
gtk_pixmap_menu_item_get_type (void);
98 GtkWidget
* gtk_pixmap_menu_item_new (void);
99 void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
103 //-----------------------------------------------------------------------------
105 //-----------------------------------------------------------------------------
107 static wxString
wxReplaceUnderscore( const wxString
& title
)
111 // GTK 1.2 wants to have "_" instead of "&" for accelerators
114 while (*pc
!= wxT('\0'))
116 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
118 // "&" is doubled to indicate "&" instead of accelerator
122 else if (*pc
== wxT('&'))
128 if ( *pc
== wxT('_') )
130 // underscores must be doubled to prevent them from being
131 // interpreted as accelerator character prefix by GTK
140 // wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() );
145 //-----------------------------------------------------------------------------
146 // activate message from GTK
147 //-----------------------------------------------------------------------------
149 static void gtk_menu_open_callback( GtkWidget
*widget
, wxMenu
*menu
)
151 if (g_isIdle
) wxapp_install_idle_handler();
153 wxMenuEvent
event( wxEVT_MENU_OPEN
, -1, menu
);
154 event
.SetEventObject( menu
);
156 wxEvtHandler
* handler
= menu
->GetEventHandler();
157 if (handler
&& handler
->ProcessEvent(event
))
160 wxWindow
*win
= menu
->GetInvokingWindow();
161 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
164 //-----------------------------------------------------------------------------
166 //-----------------------------------------------------------------------------
168 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
170 wxMenuBar::wxMenuBar( long style
)
172 // the parent window is known after wxFrame::SetMenu()
173 m_needParent
= FALSE
;
175 m_invokingWindow
= (wxWindow
*) NULL
;
177 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
178 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("menubar") ))
180 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
184 m_menubar
= gtk_menu_bar_new();
186 m_accel
= gtk_accel_group_new();
189 if (style
& wxMB_DOCKABLE
)
191 m_widget
= gtk_handle_box_new();
192 gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_menubar
) );
193 gtk_widget_show( GTK_WIDGET(m_menubar
) );
197 m_widget
= GTK_WIDGET(m_menubar
);
205 wxMenuBar::wxMenuBar()
207 // the parent window is known after wxFrame::SetMenu()
208 m_needParent
= FALSE
;
210 m_invokingWindow
= (wxWindow
*) NULL
;
212 if (!PreCreation( (wxWindow
*) NULL
, wxDefaultPosition
, wxDefaultSize
) ||
213 !CreateBase( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, wxDefaultValidator
, wxT("menubar") ))
215 wxFAIL_MSG( wxT("wxMenuBar creation failed") );
219 m_menubar
= gtk_menu_bar_new();
221 m_accel
= gtk_accel_group_new();
224 m_widget
= GTK_WIDGET(m_menubar
);
231 wxMenuBar::~wxMenuBar()
235 static void wxMenubarUnsetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
237 menu
->SetInvokingWindow( (wxWindow
*) NULL
);
239 wxWindow
*top_frame
= win
;
240 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
241 top_frame
= top_frame
->GetParent();
244 // support for native hot keys
245 gtk_accel_group_detach( menu
->m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
248 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
251 wxMenuItem
*menuitem
= node
->GetData();
252 if (menuitem
->IsSubMenu())
253 wxMenubarUnsetInvokingWindow( menuitem
->GetSubMenu(), win
);
254 node
= node
->GetNext();
258 static void wxMenubarSetInvokingWindow( wxMenu
*menu
, wxWindow
*win
)
260 menu
->SetInvokingWindow( win
);
262 wxWindow
*top_frame
= win
;
263 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
264 top_frame
= top_frame
->GetParent();
266 // support for native hot keys
267 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
268 if ( !g_slist_find( ACCEL_OBJECTS(menu
->m_accel
), obj
) )
269 gtk_accel_group_attach( menu
->m_accel
, obj
);
271 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
274 wxMenuItem
*menuitem
= node
->GetData();
275 if (menuitem
->IsSubMenu())
276 wxMenubarSetInvokingWindow( menuitem
->GetSubMenu(), win
);
277 node
= node
->GetNext();
281 void wxMenuBar::SetInvokingWindow( wxWindow
*win
)
283 m_invokingWindow
= win
;
284 wxWindow
*top_frame
= win
;
285 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
286 top_frame
= top_frame
->GetParent();
289 // support for native key accelerators indicated by underscroes
290 ACCEL_OBJECT
*obj
= ACCEL_OBJ_CAST(top_frame
->m_widget
);
291 if ( !g_slist_find( ACCEL_OBJECTS(m_accel
), obj
) )
292 gtk_accel_group_attach( m_accel
, obj
);
295 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
298 wxMenu
*menu
= node
->GetData();
299 wxMenubarSetInvokingWindow( menu
, win
);
300 node
= node
->GetNext();
304 void wxMenuBar::UnsetInvokingWindow( wxWindow
*win
)
306 m_invokingWindow
= (wxWindow
*) NULL
;
307 wxWindow
*top_frame
= win
;
308 while (top_frame
->GetParent() && !(top_frame
->IsTopLevel()))
309 top_frame
= top_frame
->GetParent();
312 // support for native key accelerators indicated by underscroes
313 gtk_accel_group_detach( m_accel
, ACCEL_OBJ_CAST(top_frame
->m_widget
) );
316 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
319 wxMenu
*menu
= node
->GetData();
320 wxMenubarUnsetInvokingWindow( menu
, win
);
321 node
= node
->GetNext();
325 bool wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
327 if ( !wxMenuBarBase::Append( menu
, title
) )
330 return GtkAppend(menu
, title
);
333 bool wxMenuBar::GtkAppend(wxMenu
*menu
, const wxString
& title
, int pos
)
335 wxString
str( wxReplaceUnderscore( title
) );
337 // This doesn't have much effect right now.
338 menu
->SetTitle( str
);
340 // The "m_owner" is the "menu item"
342 menu
->m_owner
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str
) );
344 menu
->m_owner
= gtk_menu_item_new_with_label( wxGTK_CONV( str
) );
345 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
347 gtk_label_set_text( label
, wxGTK_CONV( str
) );
349 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
350 if (accel_key
!= GDK_VoidSymbol
)
352 gtk_widget_add_accelerator (menu
->m_owner
,
354 m_accel
,//gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menubar)),
361 gtk_widget_show( menu
->m_owner
);
363 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
366 gtk_menu_shell_append( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
);
368 gtk_menu_shell_insert( GTK_MENU_SHELL(m_menubar
), menu
->m_owner
, pos
);
370 gtk_signal_connect( GTK_OBJECT(menu
->m_owner
), "activate",
371 GTK_SIGNAL_FUNC(gtk_menu_open_callback
),
374 // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
375 // addings menu later on.
376 if (m_invokingWindow
)
378 wxMenubarSetInvokingWindow( menu
, m_invokingWindow
);
380 // OPTIMISE ME: we should probably cache this, or pass it
381 // directly, but for now this is a minimal
382 // change to validate the new dynamic sizing.
383 // see (and refactor :) similar code in Remove
386 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
389 frame
->UpdateMenuBarSize();
395 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
397 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
402 if ( !GtkAppend(menu
, title
, (int)pos
) )
408 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
410 // remove the old item and insert a new one
411 wxMenu
*menuOld
= Remove(pos
);
412 if ( menuOld
&& !Insert(pos
, menu
, title
) )
414 return (wxMenu
*) NULL
;
417 // either Insert() succeeded or Remove() failed and menuOld is NULL
421 static wxMenu
*CopyMenu (wxMenu
*menu
)
423 wxMenu
*menucopy
= new wxMenu ();
424 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
427 wxMenuItem
*item
= node
->GetData();
428 int itemid
= item
->GetId();
429 wxString text
= item
->GetText();
430 text
.Replace(wxT("_"), wxT("&"));
431 wxMenu
*submenu
= item
->GetSubMenu();
434 wxMenuItem
* itemcopy
= new wxMenuItem(menucopy
,
436 menu
->GetHelpString(itemid
));
437 itemcopy
->SetBitmap(item
->GetBitmap());
438 itemcopy
->SetCheckable(item
->IsCheckable());
439 menucopy
->Append(itemcopy
);
442 menucopy
->Append (itemid
, text
, CopyMenu(submenu
),
443 menu
->GetHelpString(itemid
));
445 node
= node
->GetNext();
451 wxMenu
*wxMenuBar::Remove(size_t pos
)
453 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
455 return (wxMenu
*) NULL
;
457 wxMenu
*menucopy
= CopyMenu( menu
);
459 // unparent calls unref() and that would delete the widget so we raise
460 // the ref count to 2 artificially before invoking unparent.
461 gtk_widget_ref( menu
->m_menu
);
462 gtk_widget_unparent( menu
->m_menu
);
464 gtk_widget_destroy( menu
->m_owner
);
469 if (m_invokingWindow
)
471 // OPTIMISE ME: see comment in GtkAppend
472 wxFrame
*frame
= wxDynamicCast( m_invokingWindow
, wxFrame
);
475 frame
->UpdateMenuBarSize();
481 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
483 if (wxMenuItem::GetLabelFromText(menu
->GetTitle()) == wxMenuItem::GetLabelFromText(menuString
))
485 int res
= menu
->FindItem( itemString
);
486 if (res
!= wxNOT_FOUND
)
490 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
493 wxMenuItem
*item
= node
->GetData();
494 if (item
->IsSubMenu())
495 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
497 node
= node
->GetNext();
503 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
505 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
508 wxMenu
*menu
= node
->GetData();
509 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
512 node
= node
->GetNext();
518 // Find a wxMenuItem using its id. Recurses down into sub-menus
519 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
521 wxMenuItem
* result
= menu
->FindChildItem(id
);
523 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
524 while ( node
&& result
== NULL
)
526 wxMenuItem
*item
= node
->GetData();
527 if (item
->IsSubMenu())
529 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
531 node
= node
->GetNext();
537 wxMenuItem
* wxMenuBar::FindItem( int id
, wxMenu
**menuForItem
) const
539 wxMenuItem
* result
= 0;
540 wxMenuList::compatibility_iterator node
= m_menus
.GetFirst();
541 while (node
&& result
== 0)
543 wxMenu
*menu
= node
->GetData();
544 result
= FindMenuItemByIdRecursive( menu
, id
);
545 node
= node
->GetNext();
550 *menuForItem
= result
? result
->GetMenu() : (wxMenu
*)NULL
;
556 void wxMenuBar::EnableTop( size_t pos
, bool flag
)
558 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
560 wxCHECK_RET( node
, wxT("menu not found") );
562 wxMenu
* menu
= node
->GetData();
565 gtk_widget_set_sensitive( menu
->m_owner
, flag
);
568 wxString
wxMenuBar::GetLabelTop( size_t pos
) const
570 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
572 wxCHECK_MSG( node
, wxT("invalid"), wxT("menu not found") );
574 wxMenu
* menu
= node
->GetData();
577 wxString
text( menu
->GetTitle() );
578 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
580 if ( *pc
== wxT('_') )
582 // '_' is the escape character for GTK+
586 // don't remove ampersands '&' since if we have them in the menu title
587 // it means that they were doubled to indicate "&" instead of accelerator
595 void wxMenuBar::SetLabelTop( size_t pos
, const wxString
& label
)
597 wxMenuList::compatibility_iterator node
= m_menus
.Item( pos
);
599 wxCHECK_RET( node
, wxT("menu not found") );
601 wxMenu
* menu
= node
->GetData();
603 wxString
str( wxReplaceUnderscore( label
) );
605 menu
->SetTitle( str
);
609 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menu
->m_owner
)->child
);
612 gtk_label_set( label
, wxGTK_CONV( str
) );
614 /* reparse key accel */
615 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( str
) );
616 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
621 //-----------------------------------------------------------------------------
623 //-----------------------------------------------------------------------------
625 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
628 wxapp_install_idle_handler();
630 int id
= menu
->FindMenuIdByMenuItem(widget
);
632 /* should find it for normal (not popup) menu */
633 wxASSERT_MSG( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
),
634 _T("menu item not found in gtk_menu_clicked_callback") );
636 if (!menu
->IsEnabled(id
))
639 wxMenuItem
* item
= menu
->FindChildItem( id
);
640 wxCHECK_RET( item
, wxT("error in menu item callback") );
642 if (item
->IsCheckable())
644 bool isReallyChecked
= item
->IsChecked(),
645 isInternallyChecked
= item
->wxMenuItemBase::IsChecked();
647 // ensure that the internal state is always consistent with what is
648 // shown on the screen
649 item
->wxMenuItemBase::Check(isReallyChecked
);
651 // we must not report the events for the radio button going up nor the
652 // events resulting from the calls to wxMenuItem::Check()
653 if ( (item
->GetKind() == wxITEM_RADIO
&& !isReallyChecked
) ||
654 (isInternallyChecked
== isReallyChecked
) )
661 // Is this menu on a menubar? (possibly nested)
662 wxFrame
* frame
= NULL
;
663 if(menu
->IsAttached())
664 frame
= menu
->GetMenuBar()->GetFrame();
666 // FIXME: why do we have to call wxFrame::GetEventHandler() directly here?
667 // normally wxMenu::SendEvent() should be enough, if it doesn't work
668 // in wxGTK then we have a bug in wxMenu::GetInvokingWindow() which
669 // should be fixed instead of working around it here...
672 // If it is attached then let the frame send the event.
673 // Don't call frame->ProcessCommand(id) because it toggles
674 // checkable items and we've already done that above.
675 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
676 commandEvent
.SetEventObject(frame
);
677 if (item
->IsCheckable())
678 commandEvent
.SetInt(item
->IsChecked());
679 commandEvent
.SetEventObject(menu
);
681 frame
->GetEventHandler()->ProcessEvent(commandEvent
);
685 // otherwise let the menu have it
686 menu
->SendEvent(id
, item
->IsCheckable() ? item
->IsChecked() : -1);
690 //-----------------------------------------------------------------------------
692 //-----------------------------------------------------------------------------
694 static void gtk_menu_hilight_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
, id
);
706 event
.SetEventObject( menu
);
708 wxEvtHandler
* handler
= menu
->GetEventHandler();
709 if (handler
&& handler
->ProcessEvent(event
))
712 wxWindow
*win
= menu
->GetInvokingWindow();
713 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
716 //-----------------------------------------------------------------------------
718 //-----------------------------------------------------------------------------
720 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
722 if (g_isIdle
) wxapp_install_idle_handler();
724 int id
= menu
->FindMenuIdByMenuItem(widget
);
726 wxASSERT( id
!= -1 ); // should find it!
728 if (!menu
->IsEnabled(id
))
731 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
732 event
.SetEventObject( menu
);
734 wxEvtHandler
* handler
= menu
->GetEventHandler();
735 if (handler
&& handler
->ProcessEvent(event
))
738 wxWindow
*win
= menu
->GetInvokingWindow();
740 win
->GetEventHandler()->ProcessEvent( event
);
743 //-----------------------------------------------------------------------------
745 //-----------------------------------------------------------------------------
747 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
749 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
751 const wxString
& name
,
752 const wxString
& help
,
756 return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
);
759 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
761 const wxString
& text
,
762 const wxString
& help
,
765 : wxMenuItemBase(parentMenu
, id
, text
, help
, kind
, subMenu
)
770 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
772 const wxString
& text
,
773 const wxString
& help
,
776 : wxMenuItemBase(parentMenu
, id
, text
, help
,
777 isCheckable
? wxITEM_CHECK
: wxITEM_NORMAL
, subMenu
)
782 void wxMenuItem::Init(const wxString
& text
)
784 m_labelWidget
= (GtkWidget
*) NULL
;
785 m_menuItem
= (GtkWidget
*) NULL
;
790 wxMenuItem::~wxMenuItem()
792 // don't delete menu items, the menus take care of that
795 // return the menu item text without any menu accels
797 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
801 for ( const wxChar
*pc
= text
.c_str(); *pc
; pc
++ )
803 if ( *pc
== wxT('\t'))
806 if ( *pc
== wxT('_') )
808 // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx"
815 if ( *pc
== wxT('\\') )
817 // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx"
824 if ( (*pc
== wxT('&')) && (*(pc
+1) != wxT('&')) )
827 // "&" is doubled to indicate "&" instead of accelerator
834 // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
839 void wxMenuItem::SetText( const wxString
& str
)
841 // Some optimization to avoid flicker
842 wxString oldLabel
= m_text
;
843 oldLabel
= wxStripMenuCodes(oldLabel
.BeforeFirst('\t'));
844 oldLabel
.Replace(wxT("_"), wxT(""));
845 wxString label1
= wxStripMenuCodes(str
.BeforeFirst('\t'));
846 if (oldLabel
== label1
)
855 label
= (GtkLabel
*) m_labelWidget
;
857 label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
860 gtk_label_set_text_with_mnemonic( GTK_LABEL(label
), wxGTK_CONV(m_text
) );
863 gtk_label_set( label
, wxGTK_CONV( m_text
) );
866 (void)gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV(m_text
) );
867 gtk_accel_label_refetch( GTK_ACCEL_LABEL(label
) );
872 // it's valid for this function to be called even if m_menuItem == NULL
873 void wxMenuItem::DoSetText( const wxString
& str
)
875 // '\t' is the deliminator indicating a hot key
877 const wxChar
*pc
= str
;
878 while ( (*pc
!= wxT('\0')) && (*pc
!= wxT('\t')) )
880 if ((*pc
== wxT('&')) && (*(pc
+1) == wxT('&')))
882 // "&" is doubled to indicate "&" instead of accelerator
886 else if (*pc
== wxT('&'))
890 else if ( *pc
== wxT('_') ) // escape underscores
901 // wxPrintf( wxT("DoSetText(): str %s m_text %s\n"), str.c_str(), m_text.c_str() );
914 wxAcceleratorEntry
*wxMenuItem::GetAccel() const
919 return (wxAcceleratorEntry
*)NULL
;
922 // as wxGetAccelFromString() looks for TAB, insert a dummy one here
924 label
<< wxT('\t') << GetHotKey();
926 return wxGetAccelFromString(label
);
929 #endif // wxUSE_ACCEL
931 void wxMenuItem::Check( bool check
)
933 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
935 if (check
== m_isChecked
)
938 wxMenuItemBase::Check( check
);
944 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
948 wxFAIL_MSG( _T("can't check this item") );
952 void wxMenuItem::Enable( bool enable
)
954 wxCHECK_RET( m_menuItem
, wxT("invalid menu item") );
956 gtk_widget_set_sensitive( m_menuItem
, enable
);
957 wxMenuItemBase::Enable( enable
);
960 bool wxMenuItem::IsChecked() const
962 wxCHECK_MSG( m_menuItem
, FALSE
, wxT("invalid menu item") );
964 wxCHECK_MSG( IsCheckable(), FALSE
,
965 wxT("can't get state of uncheckable item!") );
967 return ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
970 //-----------------------------------------------------------------------------
972 //-----------------------------------------------------------------------------
974 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
978 m_accel
= gtk_accel_group_new();
979 m_menu
= gtk_menu_new();
981 m_owner
= (GtkWidget
*) NULL
;
983 // Tearoffs are entries, just like separators. So if we want this
984 // menu to be a tear-off one, we just append a tearoff entry
986 if(m_style
& wxMENU_TEAROFF
)
988 GtkWidget
*tearoff
= gtk_tearoff_menu_item_new();
990 gtk_menu_append(GTK_MENU(m_menu
), tearoff
);
995 // append the title as the very first entry if we have it
1005 WX_CLEAR_LIST(wxMenuItemList
, m_items
);
1007 if ( GTK_IS_WIDGET( m_menu
))
1008 gtk_widget_destroy( m_menu
);
1011 bool wxMenu::GtkAppend(wxMenuItem
*mitem
, int pos
)
1013 GtkWidget
*menuItem
;
1015 if ( mitem
->IsSeparator() )
1018 menuItem
= gtk_separator_menu_item_new();
1021 menuItem
= gtk_menu_item_new();
1024 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1026 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1028 else if ( mitem
->IsSubMenu() )
1030 // text has "_" instead of "&" after mitem->SetText()
1031 wxString
text( mitem
->GetText() );
1034 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1036 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1037 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1039 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1040 // reparse key accel
1041 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1042 if (accel_key
!= GDK_VoidSymbol
)
1044 gtk_widget_add_accelerator (menuItem
,
1046 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1053 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), mitem
->GetSubMenu()->m_menu
);
1055 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1057 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1059 gtk_widget_show( mitem
->GetSubMenu()->m_menu
);
1061 // if adding a submenu to a menu already existing in the menu bar, we
1062 // must set invoking window to allow processing events from this
1064 if ( m_invokingWindow
)
1065 wxMenubarSetInvokingWindow(mitem
->GetSubMenu(), m_invokingWindow
);
1069 else if (mitem
->GetBitmap().Ok())
1071 wxString text
= mitem
->GetText();
1072 const wxBitmap
*bitmap
= &mitem
->GetBitmap();
1073 GdkPixmap
*gdk_pixmap
= bitmap
->GetPixmap();
1074 GdkBitmap
*gdk_bitmap
= bitmap
->GetMask() ? bitmap
->GetMask()->GetBitmap() : (GdkBitmap
*) NULL
;
1077 menuItem
= gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1079 GtkWidget
*image
= gtk_image_new_from_pixmap( gdk_pixmap
, gdk_bitmap
);
1080 gtk_widget_show(image
);
1082 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem
), image
);
1084 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1085 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1089 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1091 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1094 menuItem
= gtk_pixmap_menu_item_new ();
1095 GtkWidget
*label
= gtk_accel_label_new ( wxGTK_CONV( text
) );
1096 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1097 gtk_container_add (GTK_CONTAINER (menuItem
), label
);
1099 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label
), menuItem
);
1101 GdkModifierType accel_mods
;
1103 // accelerator for the item, as specified by its label
1104 // (ex. Ctrl+O for open)
1105 gtk_accelerator_parse(GetHotKey(*mitem
).c_str(), &accel_key
,
1107 if (accel_key
!= GDK_VoidSymbol
)
1109 gtk_widget_add_accelerator (menuItem
,
1112 accel_key
, accel_mods
,
1116 // accelerator for the underlined char (ex ALT+F for the File menu)
1117 accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1118 if (accel_key
!= GDK_VoidSymbol
)
1120 gtk_widget_add_accelerator (menuItem
,
1122 gtk_menu_ensure_uline_accel_group(GTK_MENU (m_menu
)),
1128 gtk_widget_show (label
);
1130 mitem
->SetLabelWidget(label
);
1132 GtkWidget
* pixmap
= gtk_pixmap_new( gdk_pixmap
, gdk_bitmap
);
1133 gtk_widget_show(pixmap
);
1134 gtk_pixmap_menu_item_set_pixmap(GTK_PIXMAP_MENU_ITEM( menuItem
), pixmap
);
1136 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1137 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1141 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
1143 gtk_menu_insert( GTK_MENU(m_menu
), menuItem
, pos
);
1144 gtk_widget_show( menuItem
);
1149 else // a normal item
1151 // text has "_" instead of "&" after mitem->SetText() so don't use it
1152 wxString
text( mitem
->GetText() );
1154 switch ( mitem
->GetKind() )
1159 menuItem
= gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1161 menuItem
= gtk_check_menu_item_new_with_label( wxGTK_CONV( text
) );
1162 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1164 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1165 // reparse key accel
1166 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1167 if (accel_key
!= GDK_VoidSymbol
)
1169 gtk_widget_add_accelerator (menuItem
,
1171 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1183 GSList
*group
= NULL
;
1184 if ( m_prevRadio
== NULL
)
1186 // start of a new radio group
1188 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1190 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1191 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1193 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1194 // reparse key accel
1195 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1196 if (accel_key
!= GDK_VoidSymbol
)
1198 gtk_widget_add_accelerator (menuItem
,
1200 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1207 else // continue the radio group
1210 group
= gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1211 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_mnemonic( group
, wxGTK_CONV( text
) );
1213 group
= gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (m_prevRadio
));
1214 m_prevRadio
= menuItem
= gtk_radio_menu_item_new_with_label( group
, wxGTK_CONV( text
) );
1215 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1217 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1218 // reparse key accel
1219 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1220 if (accel_key
!= GDK_VoidSymbol
)
1222 gtk_widget_add_accelerator (menuItem
,
1224 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1235 wxFAIL_MSG( _T("unexpected menu item kind") );
1241 menuItem
= gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text
) );
1243 menuItem
= gtk_menu_item_new_with_label( wxGTK_CONV( text
) );
1244 GtkLabel
*label
= GTK_LABEL( GTK_BIN(menuItem
)->child
);
1246 gtk_label_set_text( label
, wxGTK_CONV( text
) );
1247 // reparse key accel
1248 guint accel_key
= gtk_label_parse_uline (GTK_LABEL(label
), wxGTK_CONV( text
) );
1249 if (accel_key
!= GDK_VoidSymbol
)
1251 gtk_widget_add_accelerator (menuItem
,
1253 gtk_menu_ensure_uline_accel_group(GTK_MENU(m_menu
)),
1264 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
1265 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
1269 gtk_menu_shell_append(GTK_MENU_SHELL(m_menu
), menuItem
);
1271 gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu
), menuItem
, pos
);
1275 GdkModifierType accel_mods
;
1276 wxCharBuffer buf
= wxGTK_CONV( GetHotKey(*mitem
) );
1278 // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetHotKey(*mitem).c_str() );
1280 gtk_accelerator_parse( (const char*) buf
, &accel_key
, &accel_mods
);
1283 gtk_widget_add_accelerator (GTK_WIDGET(menuItem
),
1291 gtk_widget_show( menuItem
);
1293 if ( !mitem
->IsSeparator() )
1295 wxASSERT_MSG( menuItem
, wxT("invalid menuitem") );
1297 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
1298 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
1301 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
1302 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
1306 mitem
->SetMenuItem(menuItem
);
1310 // This doesn't even exist!
1311 // gtk_widget_lock_accelerators(mitem->GetMenuItem());
1317 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*mitem
)
1319 if (!GtkAppend(mitem
))
1322 return wxMenuBase::DoAppend(mitem
);
1325 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1327 if ( !wxMenuBase::DoInsert(pos
, item
) )
1331 if ( !GtkAppend(item
, (int)pos
) )
1337 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1339 if ( !wxMenuBase::DoRemove(item
) )
1340 return (wxMenuItem
*)NULL
;
1342 // TODO: this code doesn't delete the item factory item and this seems
1343 // impossible as of GTK 1.2.6.
1344 gtk_widget_destroy( item
->GetMenuItem() );
1349 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
1351 wxMenuItemList::compatibility_iterator node
= m_items
.GetFirst();
1354 wxMenuItem
*item
= node
->GetData();
1355 if (item
->GetMenuItem() == menuItem
)
1356 return item
->GetId();
1357 node
= node
->GetNext();
1363 // ----------------------------------------------------------------------------
1365 // ----------------------------------------------------------------------------
1369 static wxString
GetHotKey( const wxMenuItem
& item
)
1373 wxAcceleratorEntry
*accel
= item
.GetAccel();
1376 int flags
= accel
->GetFlags();
1377 if ( flags
& wxACCEL_ALT
)
1378 hotkey
+= wxT("<alt>");
1379 if ( flags
& wxACCEL_CTRL
)
1380 hotkey
+= wxT("<control>");
1381 if ( flags
& wxACCEL_SHIFT
)
1382 hotkey
+= wxT("<shift>");
1384 int code
= accel
->GetKeyCode();
1399 hotkey
<< wxT('F') << code
- WXK_F1
+ 1;
1402 // TODO: we should use gdk_keyval_name() (a.k.a.
1403 // XKeysymToString) here as well as hardcoding the keysym
1404 // names this might be not portable
1405 case WXK_NUMPAD_INSERT
:
1406 hotkey
<< wxT("KP_Insert" );
1408 case WXK_NUMPAD_DELETE
:
1409 hotkey
<< wxT("KP_Delete" );
1412 hotkey
<< wxT("Insert" );
1415 hotkey
<< wxT("Delete" );
1418 hotkey
<< wxT("Up" );
1421 hotkey
<< wxT("Down" );
1425 hotkey
<< wxT("Prior" );
1429 hotkey
<< wxT("Next" );
1432 hotkey
<< wxT("Left" );
1435 hotkey
<< wxT("Right" );
1438 hotkey
<< wxT("Home" );
1441 hotkey
<< wxT("End" );
1444 hotkey
<< wxT("Return" );
1447 // if there are any other keys wxGetAccelFromString() may
1448 // return, we should process them here
1453 wxString name
= wxGTK_CONV_BACK( gdk_keyval_name((guint
)code
) );
1461 wxFAIL_MSG( wxT("unknown keyboard accel") );
1470 #endif // wxUSE_ACCEL
1473 //-----------------------------------------------------------------------------
1474 // substitute for missing GtkPixmapMenuItem
1475 //-----------------------------------------------------------------------------
1480 * Copyright (C) 1998, 1999, 2000 Free Software Foundation
1481 * All rights reserved.
1483 * This file is part of the Gnome Library.
1485 * The Gnome Library is free software; you can redistribute it and/or
1486 * modify it under the terms of the GNU Library General Public License as
1487 * published by the Free Software Foundation; either version 2 of the
1488 * License, or (at your option) any later version.
1490 * The Gnome Library is distributed in the hope that it will be useful,
1491 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1492 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1493 * Library General Public License for more details.
1495 * You should have received a copy of the GNU Library General Public
1496 * License along with the Gnome Library; see the file COPYING.LIB. If not,
1497 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1498 * Boston, MA 02111-1307, USA.
1504 /* Author: Dietmar Maurer <dm@vlsivie.tuwien.ac.at> */
1506 #include <gtk/gtkaccellabel.h>
1507 #include <gtk/gtksignal.h>
1508 #include <gtk/gtkmenuitem.h>
1509 #include <gtk/gtkmenu.h>
1510 #include <gtk/gtkcontainer.h>
1515 static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
);
1516 static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
);
1517 static void gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1518 GdkRectangle
*area
);
1519 static gint
gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1520 GdkEventExpose
*event
);
1522 /* we must override the following functions */
1524 static void gtk_pixmap_menu_item_map (GtkWidget
*widget
);
1525 static void gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1526 GtkAllocation
*allocation
);
1527 static void gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1528 gboolean include_internals
,
1529 GtkCallback callback
,
1530 gpointer callback_data
);
1531 static void gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1532 GtkRequisition
*requisition
);
1533 static void gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1536 static void changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
);
1538 static GtkMenuItemClass
*parent_class
= NULL
;
1542 #define BORDER_SPACING 3
1543 #define PMAP_WIDTH 20
1546 gtk_pixmap_menu_item_get_type (void)
1548 static GtkType pixmap_menu_item_type
= 0;
1550 if (!pixmap_menu_item_type
)
1552 GtkTypeInfo pixmap_menu_item_info
=
1554 (char *)"GtkPixmapMenuItem",
1555 sizeof (GtkPixmapMenuItem
),
1556 sizeof (GtkPixmapMenuItemClass
),
1557 (GtkClassInitFunc
) gtk_pixmap_menu_item_class_init
,
1558 (GtkObjectInitFunc
) gtk_pixmap_menu_item_init
,
1559 /* reserved_1 */ NULL
,
1560 /* reserved_2 */ NULL
,
1561 (GtkClassInitFunc
) NULL
,
1564 pixmap_menu_item_type
= gtk_type_unique (gtk_menu_item_get_type (),
1565 &pixmap_menu_item_info
);
1568 return pixmap_menu_item_type
;
1572 * gtk_pixmap_menu_item_new
1574 * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap()
1575 * to set the pixmap wich is displayed at the left side.
1578 * &GtkWidget pointer to new menu item
1582 gtk_pixmap_menu_item_new (void)
1584 return GTK_WIDGET (gtk_type_new (gtk_pixmap_menu_item_get_type ()));
1588 gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass
*klass
)
1590 GtkObjectClass
*object_class
;
1591 GtkWidgetClass
*widget_class
;
1592 GtkMenuItemClass
*menu_item_class
;
1593 GtkContainerClass
*container_class
;
1595 object_class
= (GtkObjectClass
*) klass
;
1596 widget_class
= (GtkWidgetClass
*) klass
;
1597 menu_item_class
= (GtkMenuItemClass
*) klass
;
1598 container_class
= (GtkContainerClass
*) klass
;
1600 parent_class
= (GtkMenuItemClass
*) gtk_type_class (gtk_menu_item_get_type ());
1602 widget_class
->draw
= gtk_pixmap_menu_item_draw
;
1603 widget_class
->expose_event
= gtk_pixmap_menu_item_expose
;
1604 widget_class
->map
= gtk_pixmap_menu_item_map
;
1605 widget_class
->size_allocate
= gtk_pixmap_menu_item_size_allocate
;
1606 widget_class
->size_request
= gtk_pixmap_menu_item_size_request
;
1608 container_class
->forall
= gtk_pixmap_menu_item_forall
;
1609 container_class
->remove
= gtk_pixmap_menu_item_remove
;
1611 klass
->orig_toggle_size
= menu_item_class
->toggle_size
;
1612 klass
->have_pixmap_count
= 0;
1616 gtk_pixmap_menu_item_init (GtkPixmapMenuItem
*menu_item
)
1620 mi
= GTK_MENU_ITEM (menu_item
);
1622 menu_item
->pixmap
= NULL
;
1626 gtk_pixmap_menu_item_draw (GtkWidget
*widget
,
1629 g_return_if_fail (widget
!= NULL
);
1630 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1631 g_return_if_fail (area
!= NULL
);
1633 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1634 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, area
);
1636 if (GTK_WIDGET_DRAWABLE (widget
) &&
1637 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1638 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1643 gtk_pixmap_menu_item_expose (GtkWidget
*widget
,
1644 GdkEventExpose
*event
)
1646 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1647 g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
), FALSE
);
1648 g_return_val_if_fail (event
!= NULL
, FALSE
);
1650 if (GTK_WIDGET_CLASS (parent_class
)->expose_event
)
1651 (* GTK_WIDGET_CLASS (parent_class
)->expose_event
) (widget
, event
);
1653 if (GTK_WIDGET_DRAWABLE (widget
) &&
1654 GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
) {
1655 gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget
)->pixmap
),NULL
);
1662 * gtk_pixmap_menu_item_set_pixmap
1663 * @menu_item: Pointer to the pixmap menu item
1664 * @pixmap: Pointer to a pixmap widget
1666 * Set the pixmap of the menu item.
1671 gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem
*menu_item
,
1674 g_return_if_fail (menu_item
!= NULL
);
1675 g_return_if_fail (pixmap
!= NULL
);
1676 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (menu_item
));
1677 g_return_if_fail (GTK_IS_WIDGET (pixmap
));
1678 g_return_if_fail (menu_item
->pixmap
== NULL
);
1680 gtk_widget_set_parent (pixmap
, GTK_WIDGET (menu_item
));
1681 menu_item
->pixmap
= pixmap
;
1683 if (GTK_WIDGET_REALIZED (pixmap
->parent
) &&
1684 !GTK_WIDGET_REALIZED (pixmap
))
1685 gtk_widget_realize (pixmap
);
1687 if (GTK_WIDGET_VISIBLE (pixmap
->parent
)) {
1688 if (GTK_WIDGET_MAPPED (pixmap
->parent
) &&
1689 GTK_WIDGET_VISIBLE(pixmap
) &&
1690 !GTK_WIDGET_MAPPED (pixmap
))
1691 gtk_widget_map (pixmap
);
1694 changed_have_pixmap_status(menu_item
);
1696 if (GTK_WIDGET_VISIBLE (pixmap
) && GTK_WIDGET_VISIBLE (menu_item
))
1697 gtk_widget_queue_resize (pixmap
);
1701 gtk_pixmap_menu_item_map (GtkWidget
*widget
)
1703 GtkPixmapMenuItem
*menu_item
;
1705 g_return_if_fail (widget
!= NULL
);
1706 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget
));
1708 menu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1710 GTK_WIDGET_CLASS(parent_class
)->map(widget
);
1712 if (menu_item
->pixmap
&&
1713 GTK_WIDGET_VISIBLE (menu_item
->pixmap
) &&
1714 !GTK_WIDGET_MAPPED (menu_item
->pixmap
))
1715 gtk_widget_map (menu_item
->pixmap
);
1719 gtk_pixmap_menu_item_size_allocate (GtkWidget
*widget
,
1720 GtkAllocation
*allocation
)
1722 GtkPixmapMenuItem
*pmenu_item
;
1724 pmenu_item
= GTK_PIXMAP_MENU_ITEM(widget
);
1726 if (pmenu_item
->pixmap
&& GTK_WIDGET_VISIBLE(pmenu_item
))
1728 GtkAllocation child_allocation
;
1731 border_width
= GTK_CONTAINER (widget
)->border_width
;
1733 child_allocation
.width
= pmenu_item
->pixmap
->requisition
.width
;
1734 child_allocation
.height
= pmenu_item
->pixmap
->requisition
.height
;
1735 child_allocation
.x
= border_width
+ BORDER_SPACING
;
1736 child_allocation
.y
= (border_width
+ BORDER_SPACING
1737 + (((allocation
->height
- child_allocation
.height
) - child_allocation
.x
)
1738 / 2)); /* center pixmaps vertically */
1739 gtk_widget_size_allocate (pmenu_item
->pixmap
, &child_allocation
);
1742 if (GTK_WIDGET_CLASS (parent_class
)->size_allocate
)
1743 GTK_WIDGET_CLASS(parent_class
)->size_allocate (widget
, allocation
);
1747 gtk_pixmap_menu_item_forall (GtkContainer
*container
,
1748 gboolean include_internals
,
1749 GtkCallback callback
,
1750 gpointer callback_data
)
1752 GtkPixmapMenuItem
*menu_item
;
1754 g_return_if_fail (container
!= NULL
);
1755 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1756 g_return_if_fail (callback
!= NULL
);
1758 menu_item
= GTK_PIXMAP_MENU_ITEM (container
);
1760 if (menu_item
->pixmap
)
1761 (* callback
) (menu_item
->pixmap
, callback_data
);
1763 GTK_CONTAINER_CLASS(parent_class
)->forall(container
,include_internals
,
1764 callback
,callback_data
);
1768 gtk_pixmap_menu_item_size_request (GtkWidget
*widget
,
1769 GtkRequisition
*requisition
)
1771 GtkPixmapMenuItem
*menu_item
;
1772 GtkRequisition req
= {0, 0};
1774 g_return_if_fail (widget
!= NULL
);
1775 g_return_if_fail (GTK_IS_MENU_ITEM (widget
));
1776 g_return_if_fail (requisition
!= NULL
);
1778 GTK_WIDGET_CLASS(parent_class
)->size_request(widget
,requisition
);
1780 menu_item
= GTK_PIXMAP_MENU_ITEM (widget
);
1782 if (menu_item
->pixmap
)
1783 gtk_widget_size_request(menu_item
->pixmap
, &req
);
1785 requisition
->height
= MAX(req
.height
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
, (unsigned int) requisition
->height
);
1786 requisition
->width
+= (req
.width
+ GTK_CONTAINER(widget
)->border_width
+ BORDER_SPACING
);
1790 gtk_pixmap_menu_item_remove (GtkContainer
*container
,
1794 gboolean widget_was_visible
;
1796 g_return_if_fail (container
!= NULL
);
1797 g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (container
));
1798 g_return_if_fail (child
!= NULL
);
1799 g_return_if_fail (GTK_IS_WIDGET (child
));
1801 bin
= GTK_BIN (container
);
1802 g_return_if_fail ((bin
->child
== child
||
1803 (GTK_PIXMAP_MENU_ITEM(container
)->pixmap
== child
)));
1805 widget_was_visible
= GTK_WIDGET_VISIBLE (child
);
1807 gtk_widget_unparent (child
);
1808 if (bin
->child
== child
)
1811 GTK_PIXMAP_MENU_ITEM(container
)->pixmap
= NULL
;
1812 changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container
));
1815 if (widget_was_visible
)
1816 gtk_widget_queue_resize (GTK_WIDGET (container
));
1820 /* important to only call this if there was actually a _change_ in pixmap == NULL */
1822 changed_have_pixmap_status (GtkPixmapMenuItem
*menu_item
)
1824 if (menu_item
->pixmap
!= NULL
) {
1825 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
+= 1;
1827 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 1) {
1828 /* Install pixmap toggle size */
1829 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= MAX(GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
, PMAP_WIDTH
);
1832 GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
-= 1;
1834 if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->have_pixmap_count
== 0) {
1835 /* Install normal toggle size */
1836 GTK_MENU_ITEM_GET_CLASS(menu_item
)->toggle_size
= GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item
)->orig_toggle_size
;
1840 /* Note that we actually need to do this for _all_ GtkPixmapMenuItem
1841 whenever the klass->toggle_size changes; but by doing it anytime
1842 this function is called, we get the same effect, just because of
1843 how the preferences option to show pixmaps works. Bogus, broken.
1845 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item
)))
1846 gtk_widget_queue_resize(GTK_WIDGET(menu_item
));