1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "menu.h"
12 #pragma implementation "menuitem.h"
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
27 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
29 wxMenuBar::wxMenuBar()
31 m_needParent
= FALSE
; // hmmm
33 PreCreation( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, "menu" );
35 m_menus
.DeleteContents( TRUE
);
37 m_menubar
= gtk_menu_bar_new();
39 m_widget
= GTK_WIDGET(m_menubar
);
46 void wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
48 m_menus
.Append( menu
);
49 menu
->m_title
= title
;
54 pos
= menu
->m_title
.First( '&' );
55 if (pos
!= -1) menu
->m_title
.Remove( pos
, 1 );
58 menu
->m_owner
= gtk_menu_item_new_with_label( WXSTRINGCAST(menu
->m_title
) );
59 gtk_widget_show( menu
->m_owner
);
60 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu
->m_owner
), menu
->m_menu
);
62 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), menu
->m_owner
);
65 static int FindMenuItemRecursive( const wxMenu
*menu
, const wxString
&menuString
, const wxString
&itemString
)
67 if (menu
->m_title
== menuString
)
69 int res
= menu
->FindItem( itemString
);
70 if (res
!= -1) return res
;
73 wxNode
*node
= menu
->m_items
.First();
76 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
77 if (item
->IsSubMenu())
78 return FindMenuItemRecursive(item
->GetSubMenu(), menuString
, itemString
);
86 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
88 wxNode
*node
= m_menus
.First();
91 wxMenu
*menu
= (wxMenu
*)node
->Data();
92 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
93 if (res
!= -1) return res
;
99 /* Find a wxMenuItem using its id. Recurses down into sub-menus */
100 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
102 wxMenuItem
* result
= menu
->FindItem(id
);
104 wxNode
*node
= menu
->m_items
.First();
105 while ( node
&& result
== NULL
)
107 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
108 if (item
->IsSubMenu())
110 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
118 wxMenuItem
* wxMenuBar::FindMenuItemById( int id
) const
120 wxMenuItem
* result
= 0;
121 wxNode
*node
= m_menus
.First();
122 while (node
&& result
== 0)
124 wxMenu
*menu
= (wxMenu
*)node
->Data();
125 result
= FindMenuItemByIdRecursive( menu
, id
);
132 void wxMenuBar::Check( int id
, bool check
)
134 wxMenuItem
* item
= FindMenuItemById( id
);
135 if (item
) item
->Check(check
);
138 bool wxMenuBar::Checked( int id
) const
140 wxMenuItem
* item
= FindMenuItemById( id
);
141 if (item
) return item
->IsChecked();
145 void wxMenuBar::Enable( int id
, bool enable
)
147 wxMenuItem
* item
= FindMenuItemById( id
);
148 if (item
) item
->Enable(enable
);
151 bool wxMenuBar::Enabled( int id
) const
153 wxMenuItem
* item
= FindMenuItemById( id
);
154 if (item
) return item
->IsEnabled();
159 wxString
wxMenuBar::GetLabel( int id
) const
161 wxMenuItem
* item
= FindMenuItemById( id
);
163 if (item
) return item
->GetText();
168 void wxMenuBar::SetLabel( int id
, const wxString
&label
)
170 wxMenuItem
* item
= FindMenuItemById( id
);
172 if (item
) item
->SetText( label
);
175 void wxMenuBar::EnableTop( int pos
, bool flag
)
177 wxNode
*node
= m_menus
.Nth( pos
);
179 wxCHECK_RET( node
, "menu not found" );
181 wxMenu
* menu
= (wxMenu
*)node
->Data();
183 if (menu
->m_owner
) gtk_widget_set_sensitive( menu
->m_owner
, flag
);
186 wxString
wxMenuBar::GetLabelTop( int pos
) const
188 wxNode
*node
= m_menus
.Nth( pos
);
190 wxCHECK_MSG( node
, "invalid", "menu not found" );
192 wxMenu
* menu
= (wxMenu
*)node
->Data();
194 return menu
->GetTitle();
197 void wxMenuBar::SetLabelTop( int pos
, const wxString
& label
)
199 wxNode
*node
= m_menus
.Nth( pos
);
201 wxCHECK_RET( node
, "menu not found" );
203 wxMenu
* menu
= (wxMenu
*)node
->Data();
205 menu
->SetTitle( label
);
208 void wxMenuBar::SetHelpString( int id
, const wxString
& helpString
)
210 wxMenuItem
* item
= FindMenuItemById( id
);
212 if (item
) item
->SetHelp( helpString
);
215 wxString
wxMenuBar::GetHelpString( int id
) const
217 wxMenuItem
* item
= FindMenuItemById( id
);
220 return item
->GetHelp();
225 //-----------------------------------------------------------------------------
227 //-----------------------------------------------------------------------------
229 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
231 int id
= menu
->FindMenuIdByMenuItem(widget
);
233 /* should find it for normal (not popup) menu */
234 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
236 if (!menu
->IsEnabled(id
)) return;
238 wxMenuItem
* item
= menu
->FindItem( id
);
239 wxCHECK_RET( item
, "error in menu item callback" );
241 if (item
->m_isCheckMenu
)
243 if (item
->m_isChecked
== item
->IsChecked())
245 /* the menu item has been checked by calling wxMenuItem->Check() */
250 /* the user pressed on the menu item -> report */
251 item
->m_isChecked
= item
->IsChecked(); /* make consistent again */
255 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
256 event
.SetEventObject( menu
);
259 if (menu
->m_callback
)
261 (void) (*(menu
->m_callback
)) (*menu
, event
);
265 if (menu
->GetEventHandler()->ProcessEvent(event
)) return;
267 wxWindow
*win
= menu
->GetInvokingWindow();
268 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
271 //-----------------------------------------------------------------------------
273 //-----------------------------------------------------------------------------
275 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
277 int id
= menu
->FindMenuIdByMenuItem(widget
);
279 wxASSERT( id
!= -1 ); // should find it!
281 if (!menu
->IsEnabled(id
)) return;
283 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
284 event
.SetEventObject( menu
);
286 /* wxMSW doesn't call callback here either
288 if (menu->m_callback)
290 (void) (*(menu->m_callback)) (*menu, event);
295 if (menu
->GetEventHandler()->ProcessEvent(event
)) return;
297 wxWindow
*win
= menu
->GetInvokingWindow();
298 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
301 //-----------------------------------------------------------------------------
303 //-----------------------------------------------------------------------------
305 static void gtk_menu_nolight_callback( GtkWidget
*widget
, wxMenu
*menu
)
307 int id
= menu
->FindMenuIdByMenuItem(widget
);
309 wxASSERT( id
!= -1 ); // should find it!
311 if (!menu
->IsEnabled(id
)) return;
313 wxMenuEvent
event( wxEVT_MENU_HIGHLIGHT
, -1 );
314 event
.SetEventObject( menu
);
316 if (menu
->GetEventHandler()->ProcessEvent(event
)) return;
318 wxWindow
*win
= menu
->GetInvokingWindow();
319 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
322 //-----------------------------------------------------------------------------
324 //-----------------------------------------------------------------------------
326 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
,wxObject
)
328 wxMenuItem::wxMenuItem()
331 m_isCheckMenu
= FALSE
;
334 m_subMenu
= (wxMenu
*) NULL
;
335 m_menuItem
= (GtkWidget
*) NULL
;
338 /* it's valid for this function to be called even if m_menuItem == NULL */
339 void wxMenuItem::SetName( const wxString
& str
)
342 for ( const char *pc
= str
; *pc
!= '\0'; pc
++ )
344 if (*pc
== '&') pc
++; /* skip it */
350 GtkLabel
*label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
351 gtk_label_set( label
, m_text
.c_str());
355 void wxMenuItem::Check( bool check
)
357 wxCHECK_RET( m_menuItem
, "invalid menu item" );
359 wxCHECK_RET( IsCheckable(), "Can't check uncheckable item!" )
361 if (check
== m_isChecked
) return;
364 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
367 void wxMenuItem::Enable( bool enable
)
369 wxCHECK_RET( m_menuItem
, "invalid menu item" );
371 gtk_widget_set_sensitive( m_menuItem
, enable
);
372 m_isEnabled
= enable
;
375 bool wxMenuItem::IsChecked() const
377 wxCHECK_MSG( m_menuItem
, FALSE
, "invalid menu item" );
379 wxCHECK( IsCheckable(), FALSE
); // can't get state of uncheckable item!
381 bool bIsChecked
= ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
386 //-----------------------------------------------------------------------------
388 //-----------------------------------------------------------------------------
390 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
392 wxMenu::wxMenu( const wxString
& title
, const wxFunction func
)
395 m_items
.DeleteContents( TRUE
);
396 m_invokingWindow
= (wxWindow
*) NULL
;
397 m_menu
= gtk_menu_new(); // Do not show!
400 m_eventHandler
= this;
401 m_clientData
= (void*) NULL
;
403 if (m_title
.IsNull()) m_title
= "";
410 m_owner
= (GtkWidget
*) NULL
;
413 void wxMenu::SetTitle( const wxString
& title
)
415 /* Waiting for something better. */
419 const wxString
wxMenu::GetTitle() const
424 void wxMenu::AppendSeparator()
426 wxMenuItem
*mitem
= new wxMenuItem();
427 mitem
->SetId(ID_SEPARATOR
);
429 GtkWidget
*menuItem
= gtk_menu_item_new();
430 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
431 gtk_widget_show( menuItem
);
432 mitem
->SetMenuItem(menuItem
);
433 m_items
.Append( mitem
);
436 void wxMenu::Append( int id
, const wxString
&item
, const wxString
&helpStr
, bool checkable
)
438 wxMenuItem
*mitem
= new wxMenuItem();
440 mitem
->SetText(item
);
441 mitem
->SetHelp(helpStr
);
442 mitem
->SetCheckable(checkable
);
443 const char *text
= mitem
->GetText();
444 GtkWidget
*menuItem
= checkable
? gtk_check_menu_item_new_with_label(text
)
445 : gtk_menu_item_new_with_label(text
);
447 mitem
->SetMenuItem(menuItem
);
449 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
450 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
453 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
454 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
457 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
458 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
461 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
462 gtk_widget_show( menuItem
);
463 m_items
.Append( mitem
);
466 void wxMenu::Append( int id
, const wxString
&text
, wxMenu
*subMenu
, const wxString
&helpStr
)
468 wxMenuItem
*mitem
= new wxMenuItem();
470 mitem
->SetText(text
);
472 GtkWidget
*menuItem
= gtk_menu_item_new_with_label(mitem
->GetText());
473 mitem
->SetHelp(helpStr
);
474 mitem
->SetMenuItem(menuItem
);
475 mitem
->SetSubMenu(subMenu
);
477 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
478 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
481 gtk_signal_connect( GTK_OBJECT(menuItem
), "deselect",
482 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback
),
485 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), subMenu
->m_menu
);
486 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
487 gtk_widget_show( menuItem
);
488 m_items
.Append( mitem
);
491 int wxMenu::FindItem( const wxString itemString
) const
493 wxString
s( itemString
);
498 pos
= s
.First( '&' );
499 if (pos
!= -1) s
.Remove( pos
, 1 );
502 wxNode
*node
= m_items
.First();
505 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
506 if (item
->GetText() == s
)
508 return item
->GetId();
516 void wxMenu::Enable( int id
, bool enable
)
518 wxMenuItem
*item
= FindItem(id
);
521 item
->Enable(enable
);
525 bool wxMenu::IsEnabled( int id
) const
527 wxMenuItem
*item
= FindItem(id
);
530 return item
->IsEnabled();
538 void wxMenu::Check( int id
, bool enable
)
540 wxMenuItem
*item
= FindItem(id
);
547 bool wxMenu::IsChecked( int id
) const
549 wxMenuItem
*item
= FindItem(id
);
552 return item
->IsChecked();
560 void wxMenu::SetLabel( int id
, const wxString
&label
)
562 wxMenuItem
*item
= FindItem(id
);
565 item
->SetText(label
);
569 wxString
wxMenu::GetLabel( int id
) const
571 wxMenuItem
*item
= FindItem(id
);
574 return item
->GetText();
582 void wxMenu::SetHelpString( int id
, const wxString
& helpString
)
584 wxMenuItem
*item
= FindItem(id
);
585 if (item
) item
->SetHelp( helpString
);
588 wxString
wxMenu::GetHelpString( int id
) const
590 wxMenuItem
*item
= FindItem(id
);
593 return item
->GetHelp();
601 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
603 wxNode
*node
= m_items
.First();
606 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
607 if (item
->GetMenuItem() == menuItem
)
608 return item
->GetId();
615 wxMenuItem
*wxMenu::FindItem(int id
) const
617 wxNode
*node
= m_items
.First();
620 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
621 if (item
->GetId() == id
)
628 /* Not finding anything here can be correct
629 * when search the entire menu system for
630 * an entry -> no error message. */
632 return (wxMenuItem
*) NULL
;
635 void wxMenu::SetInvokingWindow( wxWindow
*win
)
637 m_invokingWindow
= win
;
640 wxWindow
*wxMenu::GetInvokingWindow()
642 return m_invokingWindow
;
645 // Update a menu and all submenus recursively.
646 // source is the object that has the update event handlers
647 // defined for it. If NULL, the menu or associated window
649 void wxMenu::UpdateUI(wxEvtHandler
* source
)
651 if (!source
&& GetInvokingWindow())
652 source
= GetInvokingWindow()->GetEventHandler();
654 source
= GetEventHandler();
658 wxNode
* node
= GetItems().First();
661 wxMenuItem
* item
= (wxMenuItem
*) node
->Data();
662 if ( !item
->IsSeparator() )
664 wxWindowID id
= item
->GetId();
665 wxUpdateUIEvent
event(id
);
666 event
.SetEventObject( source
);
668 if (source
->ProcessEvent(event
))
670 if (event
.GetSetText())
671 SetLabel(id
, event
.GetText());
672 if (event
.GetSetChecked())
673 Check(id
, event
.GetChecked());
674 if (event
.GetSetEnabled())
675 Enable(id
, event
.GetEnabled());
678 if (item
->GetSubMenu())
679 item
->GetSubMenu()->UpdateUI(source
);