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"
22 //-----------------------------------------------------------------------------
24 //-----------------------------------------------------------------------------
26 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
,wxWindow
)
28 wxMenuBar::wxMenuBar()
30 m_needParent
= FALSE
; // hmmm
32 PreCreation( (wxWindow
*) NULL
, -1, wxDefaultPosition
, wxDefaultSize
, 0, "menu" );
34 m_menus
.DeleteContents( TRUE
);
36 m_menubar
= gtk_menu_bar_new();
38 m_widget
= GTK_WIDGET(m_menubar
);
45 void wxMenuBar::Append( wxMenu
*menu
, const wxString
&title
)
47 m_menus
.Append( menu
);
48 menu
->m_title
= title
;
53 pos
= menu
->m_title
.First( '&' );
54 if (pos
!= -1) menu
->m_title
.Remove( pos
, 1 );
58 root_menu
= gtk_menu_item_new_with_label( WXSTRINGCAST(menu
->m_title
) );
59 gtk_widget_show( root_menu
);
60 gtk_menu_item_set_submenu( GTK_MENU_ITEM(root_menu
), menu
->m_menu
);
62 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar
), root_menu
);
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
);
85 int wxMenuBar::FindMenuItem( const wxString
&menuString
, const wxString
&itemString
) const
87 wxNode
*node
= m_menus
.First();
90 wxMenu
*menu
= (wxMenu
*)node
->Data();
91 int res
= FindMenuItemRecursive( menu
, menuString
, itemString
);
92 if (res
!= -1) return res
;
98 /* Find a wxMenuItem using its id. Recurses down into sub-menus */
99 static wxMenuItem
* FindMenuItemByIdRecursive(const wxMenu
* menu
, int id
)
101 wxMenuItem
* result
= menu
->FindItem(id
);
103 wxNode
*node
= menu
->m_items
.First();
104 while ( node
&& result
== NULL
)
106 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
107 if (item
->IsSubMenu())
109 result
= FindMenuItemByIdRecursive( item
->GetSubMenu(), id
);
117 wxMenuItem
* wxMenuBar::FindMenuItemById( int id
) const
119 wxMenuItem
* result
= 0;
120 wxNode
*node
= m_menus
.First();
121 while (node
&& result
== 0)
123 wxMenu
*menu
= (wxMenu
*)node
->Data();
124 result
= FindMenuItemByIdRecursive( menu
, id
);
131 void wxMenuBar::Check( int id
, bool check
)
133 wxMenuItem
* item
= FindMenuItemById( id
);
134 if (item
) item
->Check(check
);
137 bool wxMenuBar::Checked( int id
) const
139 wxMenuItem
* item
= FindMenuItemById( id
);
140 if (item
) return item
->IsChecked();
144 void wxMenuBar::Enable( int id
, bool enable
)
146 wxMenuItem
* item
= FindMenuItemById( id
);
147 if (item
) item
->Enable(enable
);
150 bool wxMenuBar::Enabled( int id
) const
152 wxMenuItem
* item
= FindMenuItemById( id
);
153 if (item
) return item
->IsEnabled();
157 //-----------------------------------------------------------------------------
159 //-----------------------------------------------------------------------------
161 static void gtk_menu_clicked_callback( GtkWidget
*widget
, wxMenu
*menu
)
163 int id
= menu
->FindMenuIdByMenuItem(widget
);
165 /* should find it for normal (not popup) menu */
166 wxASSERT( (id
!= -1) || (menu
->GetInvokingWindow() != NULL
) );
168 if (!menu
->IsEnabled(id
)) return;
170 wxMenuItem
* item
= menu
->FindItem( id
);
171 wxCHECK_RET( item
, "error in menu item callback" );
173 if (item
->m_isCheckMenu
)
175 if (item
->m_isChecked
== item
->IsChecked())
177 /* the menu item has been checked by calling wxMenuItem->Check() */
182 /* the user pressed on the menu item -> report */
183 item
->m_isChecked
= item
->IsChecked(); /* make consistent again */
187 wxCommandEvent
event( wxEVT_COMMAND_MENU_SELECTED
, id
);
188 event
.SetEventObject( menu
);
191 if (menu
->m_callback
)
193 (void) (*(menu
->m_callback
)) (*menu
, event
);
197 if (menu
->GetEventHandler()->ProcessEvent(event
)) return;
199 wxWindow
*win
= menu
->GetInvokingWindow();
200 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
203 //-----------------------------------------------------------------------------
205 //-----------------------------------------------------------------------------
207 static void gtk_menu_hilight_callback( GtkWidget
*widget
, wxMenu
*menu
)
209 int id
= menu
->FindMenuIdByMenuItem(widget
);
211 wxASSERT( id
!= -1 ); // should find it!
213 if (!menu
->IsEnabled(id
)) return;
215 wxCommandEvent
event( wxEVT_MENU_HIGHLIGHT
, id
);
216 event
.SetEventObject( menu
);
219 /* wxMSW doesn't call callback here either
221 if (menu->m_callback)
223 (void) (*(menu->m_callback)) (*menu, event);
228 if (menu
->GetEventHandler()->ProcessEvent(event
)) return;
230 wxWindow
*win
= menu
->GetInvokingWindow();
231 if (win
) win
->GetEventHandler()->ProcessEvent( event
);
234 //-----------------------------------------------------------------------------
236 //-----------------------------------------------------------------------------
238 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
,wxObject
)
240 wxMenuItem::wxMenuItem()
243 m_isCheckMenu
= FALSE
;
246 m_subMenu
= (wxMenu
*) NULL
;
247 m_menuItem
= (GtkWidget
*) NULL
;
250 /* it's valid for this function to be called even if m_menuItem == NULL */
251 void wxMenuItem::SetName( const wxString
& str
)
254 for ( const char *pc
= str
; *pc
!= '\0'; pc
++ )
256 if (*pc
== '&') pc
++; /* skip it */
262 GtkLabel
*label
= GTK_LABEL( GTK_BIN(m_menuItem
)->child
);
263 gtk_label_set( label
, m_text
.c_str());
267 void wxMenuItem::Check( bool check
)
269 wxCHECK_RET( m_menuItem
, "invalid menu item" );
271 wxCHECK_RET( IsCheckable(), "Can't check uncheckable item!" )
273 if (check
== m_isChecked
) return;
276 gtk_check_menu_item_set_state( (GtkCheckMenuItem
*)m_menuItem
, (gint
)check
);
279 void wxMenuItem::Enable( bool enable
)
281 wxCHECK_RET( m_menuItem
, "invalid menu item" );
283 gtk_widget_set_sensitive( m_menuItem
, enable
);
284 m_isEnabled
= enable
;
287 bool wxMenuItem::IsChecked() const
289 wxCHECK_MSG( m_menuItem
, FALSE
, "invalid menu item" );
291 wxCHECK( IsCheckable(), FALSE
); // can't get state of uncheckable item!
293 bool bIsChecked
= ((GtkCheckMenuItem
*)m_menuItem
)->active
!= 0;
298 //-----------------------------------------------------------------------------
300 //-----------------------------------------------------------------------------
302 IMPLEMENT_DYNAMIC_CLASS(wxMenu
,wxEvtHandler
)
304 wxMenu::wxMenu( const wxString
& title
, const wxFunction func
)
307 m_items
.DeleteContents( TRUE
);
308 m_invokingWindow
= (wxWindow
*) NULL
;
309 m_menu
= gtk_menu_new(); // Do not show!
312 m_eventHandler
= this;
313 m_clientData
= (void*) NULL
;
315 if (m_title
.IsNull()) m_title
= "";
323 void wxMenu::SetTitle( const wxString
& title
)
325 /* Waiting for something better. */
329 const wxString
wxMenu::GetTitle() const
334 void wxMenu::AppendSeparator()
336 wxMenuItem
*mitem
= new wxMenuItem();
337 mitem
->SetId(ID_SEPARATOR
);
339 GtkWidget
*menuItem
= gtk_menu_item_new();
340 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
341 gtk_widget_show( menuItem
);
342 mitem
->SetMenuItem(menuItem
);
343 m_items
.Append( mitem
);
346 void wxMenu::Append( int id
, const wxString
&item
, const wxString
&helpStr
, bool checkable
)
348 wxMenuItem
*mitem
= new wxMenuItem();
350 mitem
->SetText(item
);
351 mitem
->SetHelp(helpStr
);
352 mitem
->SetCheckable(checkable
);
353 const char *text
= mitem
->GetText();
354 GtkWidget
*menuItem
= checkable
? gtk_check_menu_item_new_with_label(text
)
355 : gtk_menu_item_new_with_label(text
);
357 mitem
->SetMenuItem(menuItem
);
359 gtk_signal_connect( GTK_OBJECT(menuItem
), "activate",
360 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback
),
363 gtk_signal_connect( GTK_OBJECT(menuItem
), "select",
364 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback
),
367 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
368 gtk_widget_show( menuItem
);
369 m_items
.Append( mitem
);
372 void wxMenu::Append( int id
, const wxString
&text
, wxMenu
*subMenu
, const wxString
&helpStr
)
374 wxMenuItem
*mitem
= new wxMenuItem();
376 mitem
->SetText(text
);
378 GtkWidget
*menuItem
= gtk_menu_item_new_with_label(mitem
->GetText());
379 mitem
->SetHelp(helpStr
);
380 mitem
->SetMenuItem(menuItem
);
381 mitem
->SetSubMenu(subMenu
);
383 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem
), subMenu
->m_menu
);
384 gtk_menu_append( GTK_MENU(m_menu
), menuItem
);
385 gtk_widget_show( menuItem
);
386 m_items
.Append( mitem
);
389 int wxMenu::FindItem( const wxString itemString
) const
391 wxString
s( itemString
);
396 pos
= s
.First( '&' );
397 if (pos
!= -1) s
.Remove( pos
, 1 );
400 wxNode
*node
= m_items
.First();
403 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
404 if (item
->GetText() == s
)
406 return item
->GetId();
414 void wxMenu::Enable( int id
, bool enable
)
416 wxMenuItem
*item
= FindItem(id
);
419 item
->Enable(enable
);
423 bool wxMenu::IsEnabled( int id
) const
425 wxMenuItem
*item
= FindItem(id
);
428 return item
->IsEnabled();
436 void wxMenu::Check( int id
, bool enable
)
438 wxMenuItem
*item
= FindItem(id
);
445 bool wxMenu::IsChecked( int id
) const
447 wxMenuItem
*item
= FindItem(id
);
450 return item
->IsChecked();
458 void wxMenu::SetLabel( int id
, const wxString
&label
)
460 wxMenuItem
*item
= FindItem(id
);
463 item
->SetText(label
);
467 wxString
wxMenu::GetLabel( int id
) const
469 wxMenuItem
*item
= FindItem(id
);
472 return item
->GetText();
480 void wxMenu::SetHelpString( int id
, const wxString
& helpString
)
482 wxMenuItem
*item
= FindItem(id
);
483 if (item
) item
->SetHelp( helpString
);
486 wxString
wxMenu::GetHelpString( int id
) const
488 wxMenuItem
*item
= FindItem(id
);
491 return item
->GetHelp();
499 int wxMenu::FindMenuIdByMenuItem( GtkWidget
*menuItem
) const
501 wxNode
*node
= m_items
.First();
504 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
505 if (item
->GetMenuItem() == menuItem
)
506 return item
->GetId();
513 wxMenuItem
*wxMenu::FindItem(int id
) const
515 wxNode
*node
= m_items
.First();
518 wxMenuItem
*item
= (wxMenuItem
*)node
->Data();
519 if (item
->GetId() == id
)
526 /* Not finding anything here can be correct
527 * when search the entire menu system for
528 * an entry -> no error message. */
530 return (wxMenuItem
*) NULL
;
533 void wxMenu::SetInvokingWindow( wxWindow
*win
)
535 m_invokingWindow
= win
;
538 wxWindow
*wxMenu::GetInvokingWindow()
540 return m_invokingWindow
;