]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/menu.cpp
background colour changes for listbox and combobox
[wxWidgets.git] / src / gtk / menu.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: menu.cpp
3// Purpose:
4// Author: Robert Roebling
96fd301f 5// Id: $Id$
a81258be 6// Copyright: (c) 1998 Robert Roebling
96fd301f 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
c801d85f
KB
10#ifdef __GNUG__
11#pragma implementation "menu.h"
6ca41e57 12#pragma implementation "menuitem.h"
c801d85f
KB
13#endif
14
15#include "wx/menu.h"
96fd301f 16#include "wx/log.h"
30dea054 17#include "wx/intl.h"
06cfab17 18#include "wx/app.h"
c801d85f 19
83624f79
RR
20#include "gdk/gdk.h"
21#include "gtk/gtk.h"
22
acfd422a
RR
23//-----------------------------------------------------------------------------
24// idle system
25//-----------------------------------------------------------------------------
26
27extern void wxapp_install_idle_handler();
28extern bool g_isIdle;
29
c801d85f
KB
30//-----------------------------------------------------------------------------
31// wxMenuBar
32//-----------------------------------------------------------------------------
33
34IMPLEMENT_DYNAMIC_CLASS(wxMenuBar,wxWindow)
35
3502e687
RR
36wxMenuBar::wxMenuBar( long style )
37{
1e133b7d
RR
38 /* the parent window is known after wxFrame::SetMenu() */
39 m_needParent = FALSE;
3502e687 40
16bcc879 41 PreCreation( (wxWindow *) NULL, -1, wxDefaultPosition, wxDefaultSize, style, "menu" );
3502e687
RR
42
43 m_menus.DeleteContents( TRUE );
44
1e133b7d
RR
45 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
46#if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
47 m_accel = gtk_accel_group_new();
48 m_factory = gtk_item_factory_new( GTK_TYPE_MENU_BAR, "<main>", m_accel );
49 m_menubar = gtk_item_factory_get_widget( m_factory, "<main>" );
50#else
3502e687 51 m_menubar = gtk_menu_bar_new();
1e133b7d 52#endif
3502e687
RR
53
54 if (style & wxMB_DOCKABLE)
55 {
56 m_widget = gtk_handle_box_new();
c626a8b7
VZ
57 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_menubar) );
58 gtk_widget_show( GTK_WIDGET(m_menubar) );
3502e687
RR
59 }
60 else
61 {
62 m_widget = GTK_WIDGET(m_menubar);
63 }
64
65 PostCreation();
66
67 Show( TRUE );
68}
69
96fd301f 70wxMenuBar::wxMenuBar()
c801d85f 71{
1e133b7d
RR
72 /* the parent window is known after wxFrame::SetMenu() */
73 m_needParent = FALSE;
96fd301f 74
83624f79 75 PreCreation( (wxWindow *) NULL, -1, wxDefaultPosition, wxDefaultSize, 0, "menu" );
c801d85f 76
83624f79 77 m_menus.DeleteContents( TRUE );
96fd301f 78
1e133b7d
RR
79 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
80#if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
81 m_accel = gtk_accel_group_new();
82 m_factory = gtk_item_factory_new( GTK_TYPE_MENU_BAR, "<main>", m_accel );
83 m_menubar = gtk_item_factory_get_widget( m_factory, "<main>" );
84#else
83624f79 85 m_menubar = gtk_menu_bar_new();
1e133b7d 86#endif
8bbe427f 87
828f655f 88 m_widget = GTK_WIDGET(m_menubar);
96fd301f 89
83624f79 90 PostCreation();
c801d85f 91
83624f79 92 Show( TRUE );
6de97a3b 93}
c801d85f 94
1e133b7d
RR
95wxMenuBar::~wxMenuBar()
96{
97 // how to destroy a GtkItemFactory ?
98}
99
c801d85f
KB
100void wxMenuBar::Append( wxMenu *menu, const wxString &title )
101{
83624f79 102 m_menus.Append( menu );
034be888 103
1e133b7d
RR
104 /* GTK 1.2 wants to have "_" instead of "&" for accelerators */
105 wxString str;
b019151f 106 for ( const wxChar *pc = title; *pc != _T('\0'); pc++ )
83624f79 107 {
b019151f 108 if (*pc == _T('&'))
034be888
RR
109 {
110 pc++; /* skip it */
1e133b7d
RR
111#if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
112 str << _T('_');
034be888
RR
113#endif
114 }
1e133b7d
RR
115 str << *pc;
116 }
117
118 /* this doesn't have much effect right now */
119 menu->SetTitle( str );
120
121 /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
122#if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0)
123
124 /* local buffer in multibyte form */
125 char buf[200];
126 strcpy( buf, "/" );
127 strcat( buf, str.mb_str() );
128
129 GtkItemFactoryEntry entry;
130 entry.path = buf;
131 entry.accelerator = (gchar*) NULL;
132 entry.callback = (GtkItemFactoryCallback) NULL;
133 entry.callback_action = 0;
134 entry.item_type = "<Branch>";
135
136 gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */
137
138 /* in order to get the pointer to the item we need the item text _without_ underscores */
139 wxString tmp = _T("<main>/");
140 for ( const wxChar *pc = str; *pc != _T('\0'); pc++ )
141 {
142 if (*pc == _T('_')) pc++; /* skip it */
143 tmp << *pc;
034be888 144 }
1e133b7d
RR
145
146 menu->m_owner = gtk_item_factory_get_item( m_factory, tmp.mb_str() );
147
148 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu->m_owner), menu->m_menu );
149
150#else
96fd301f 151
1e133b7d 152 menu->m_owner = gtk_menu_item_new_with_label( str.mb_str() );
2b1c162e
RR
153 gtk_widget_show( menu->m_owner );
154 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu->m_owner), menu->m_menu );
96fd301f 155
2b1c162e 156 gtk_menu_bar_append( GTK_MENU_BAR(m_menubar), menu->m_owner );
1e133b7d
RR
157
158#endif
6de97a3b 159}
96fd301f 160
716b7364 161static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString, const wxString &itemString )
c801d85f 162{
c626a8b7 163 if (menu->GetTitle() == menuString)
83624f79
RR
164 {
165 int res = menu->FindItem( itemString );
c626a8b7
VZ
166 if (res != wxNOT_FOUND)
167 return res;
83624f79 168 }
c626a8b7
VZ
169
170 wxNode *node = ((wxMenu *)menu)->GetItems().First(); // const_cast
83624f79
RR
171 while (node)
172 {
173 wxMenuItem *item = (wxMenuItem*)node->Data();
174 if (item->IsSubMenu())
175 return FindMenuItemRecursive(item->GetSubMenu(), menuString, itemString);
2b1c162e 176
83624f79
RR
177 node = node->Next();
178 }
179
c626a8b7
VZ
180 return wxNOT_FOUND;
181}
182
183wxMenuItem *wxMenuBar::FindItemForId(int itemId, wxMenu **menuForItem = NULL) const
184{
185 if ( menuForItem )
186 {
187 // TODO return the pointer to the menu
188
189 *menuForItem = NULL;
190 }
191
192 return FindItem(itemId);
6de97a3b 193}
c801d85f
KB
194
195int wxMenuBar::FindMenuItem( const wxString &menuString, const wxString &itemString ) const
196{
83624f79
RR
197 wxNode *node = m_menus.First();
198 while (node)
199 {
200 wxMenu *menu = (wxMenu*)node->Data();
201 int res = FindMenuItemRecursive( menu, menuString, itemString);
202 if (res != -1) return res;
203 node = node->Next();
204 }
205 return -1;
6de97a3b 206}
c801d85f 207
c626a8b7 208// Find a wxMenuItem using its id. Recurses down into sub-menus
96fd301f 209static wxMenuItem* FindMenuItemByIdRecursive(const wxMenu* menu, int id)
716b7364 210{
83624f79 211 wxMenuItem* result = menu->FindItem(id);
716b7364 212
c626a8b7
VZ
213 wxNode *node = ((wxMenu *)menu)->GetItems().First(); // const_cast
214 while ( node && result == NULL )
83624f79
RR
215 {
216 wxMenuItem *item = (wxMenuItem*)node->Data();
217 if (item->IsSubMenu())
c626a8b7 218 {
83624f79 219 result = FindMenuItemByIdRecursive( item->GetSubMenu(), id );
c626a8b7 220 }
83624f79
RR
221 node = node->Next();
222 }
96fd301f 223
83624f79 224 return result;
6de97a3b 225}
716b7364 226
c626a8b7 227wxMenuItem* wxMenuBar::FindItem( int id ) const
716b7364 228{
83624f79
RR
229 wxMenuItem* result = 0;
230 wxNode *node = m_menus.First();
231 while (node && result == 0)
232 {
233 wxMenu *menu = (wxMenu*)node->Data();
234 result = FindMenuItemByIdRecursive( menu, id );
235 node = node->Next();
236 }
c626a8b7 237
83624f79 238 return result;
716b7364
RR
239}
240
54ff4a70
RR
241void wxMenuBar::Check( int id, bool check )
242{
83624f79 243 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 244
b019151f 245 wxCHECK_RET( item, _T("wxMenuBar::Check: no such item") );
c626a8b7
VZ
246
247 item->Check(check);
6de97a3b 248}
54ff4a70 249
c626a8b7 250bool wxMenuBar::IsChecked( int id ) const
716b7364 251{
83624f79 252 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 253
b019151f 254 wxCHECK_MSG( item, FALSE, _T("wxMenuBar::IsChecked: no such item") );
c626a8b7
VZ
255
256 return item->IsChecked();
6de97a3b 257}
716b7364 258
54ff4a70
RR
259void wxMenuBar::Enable( int id, bool enable )
260{
83624f79 261 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 262
b019151f 263 wxCHECK_RET( item, _T("wxMenuBar::Enable: no such item") );
c626a8b7
VZ
264
265 item->Enable(enable);
6de97a3b 266}
54ff4a70 267
c626a8b7 268bool wxMenuBar::IsEnabled( int id ) const
716b7364 269{
83624f79 270 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 271
b019151f 272 wxCHECK_MSG( item, FALSE, _T("wxMenuBar::IsEnabled: no such item") );
c626a8b7
VZ
273
274 return item->IsEnabled();
6de97a3b 275}
716b7364 276
bbe0af5b
RR
277wxString wxMenuBar::GetLabel( int id ) const
278{
279 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 280
b019151f 281 wxCHECK_MSG( item, _T(""), _T("wxMenuBar::GetLabel: no such item") );
c626a8b7
VZ
282
283 return item->GetText();
bbe0af5b
RR
284}
285
286void wxMenuBar::SetLabel( int id, const wxString &label )
287{
288 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 289
b019151f 290 wxCHECK_RET( item, _T("wxMenuBar::SetLabel: no such item") );
c626a8b7
VZ
291
292 item->SetText( label );
bbe0af5b
RR
293}
294
2b1c162e 295void wxMenuBar::EnableTop( int pos, bool flag )
bbe0af5b 296{
2b1c162e 297 wxNode *node = m_menus.Nth( pos );
c626a8b7 298
b019151f 299 wxCHECK_RET( node, _T("menu not found") );
c626a8b7 300
2b1c162e 301 wxMenu* menu = (wxMenu*)node->Data();
c626a8b7
VZ
302
303 if (menu->m_owner)
304 gtk_widget_set_sensitive( menu->m_owner, flag );
bbe0af5b
RR
305}
306
2b1c162e 307wxString wxMenuBar::GetLabelTop( int pos ) const
bbe0af5b 308{
2b1c162e 309 wxNode *node = m_menus.Nth( pos );
c626a8b7 310
b019151f 311 wxCHECK_MSG( node, _T("invalid"), _T("menu not found") );
c626a8b7 312
2b1c162e 313 wxMenu* menu = (wxMenu*)node->Data();
c626a8b7 314
2b1c162e 315 return menu->GetTitle();
bbe0af5b
RR
316}
317
2b1c162e 318void wxMenuBar::SetLabelTop( int pos, const wxString& label )
bbe0af5b 319{
2b1c162e 320 wxNode *node = m_menus.Nth( pos );
c626a8b7 321
b019151f 322 wxCHECK_RET( node, _T("menu not found") );
c626a8b7 323
2b1c162e 324 wxMenu* menu = (wxMenu*)node->Data();
c626a8b7 325
2b1c162e 326 menu->SetTitle( label );
bbe0af5b
RR
327}
328
342b6a2f
RR
329void wxMenuBar::SetHelpString( int id, const wxString& helpString )
330{
331 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 332
b019151f 333 wxCHECK_RET( item, _T("wxMenuBar::SetHelpString: no such item") );
c626a8b7
VZ
334
335 item->SetHelp( helpString );
342b6a2f
RR
336}
337
338wxString wxMenuBar::GetHelpString( int id ) const
339{
340 wxMenuItem* item = FindMenuItemById( id );
c626a8b7 341
b019151f 342 wxCHECK_MSG( item, _T(""), _T("wxMenuBar::GetHelpString: no such item") );
c626a8b7
VZ
343
344 return item->GetHelp();
342b6a2f
RR
345}
346
c801d85f 347//-----------------------------------------------------------------------------
cf7a7e13 348// "activate"
c801d85f
KB
349//-----------------------------------------------------------------------------
350
6de97a3b 351static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu )
c801d85f 352{
acfd422a
RR
353 if (g_isIdle) wxapp_install_idle_handler();
354
83624f79 355 int id = menu->FindMenuIdByMenuItem(widget);
96fd301f 356
83624f79 357 /* should find it for normal (not popup) menu */
c626a8b7 358 wxASSERT( (id != -1) || (menu->GetInvokingWindow() != NULL) );
96fd301f 359
c626a8b7
VZ
360 if (!menu->IsEnabled(id))
361 return;
96fd301f 362
2d17d68f 363 wxMenuItem* item = menu->FindItem( id );
b019151f 364 wxCHECK_RET( item, _T("error in menu item callback") );
c626a8b7
VZ
365
366 if (item->IsCheckable())
2d17d68f 367 {
c626a8b7 368 if (item->GetCheckedFlag() == item->IsChecked())
2d17d68f 369 {
c626a8b7 370 /* the menu item has been checked by calling wxMenuItem->Check() */
2d17d68f 371 return;
c626a8b7
VZ
372 }
373 else
374 {
375 /* the user pressed on the menu item -> report */
376 item->SetCheckedFlag(item->IsChecked()); /* make consistent again */
377 }
2d17d68f
RR
378 }
379
83624f79
RR
380 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, id );
381 event.SetEventObject( menu );
382 event.SetInt(id );
8bbe427f 383
c626a8b7 384 if (menu->GetCallback())
83624f79 385 {
c626a8b7 386 (void) (*(menu->GetCallback())) (*menu, event);
83624f79
RR
387 return;
388 }
cf7a7e13 389
c626a8b7
VZ
390 if (menu->GetEventHandler()->ProcessEvent(event))
391 return;
cf7a7e13 392
83624f79 393 wxWindow *win = menu->GetInvokingWindow();
c626a8b7
VZ
394 if (win)
395 win->GetEventHandler()->ProcessEvent( event );
cf7a7e13
RR
396}
397
398//-----------------------------------------------------------------------------
399// "select"
400//-----------------------------------------------------------------------------
401
402static void gtk_menu_hilight_callback( GtkWidget *widget, wxMenu *menu )
403{
acfd422a
RR
404 if (g_isIdle) wxapp_install_idle_handler();
405
83624f79
RR
406 int id = menu->FindMenuIdByMenuItem(widget);
407
408 wxASSERT( id != -1 ); // should find it!
cf7a7e13 409
c626a8b7
VZ
410 if (!menu->IsEnabled(id))
411 return;
cf7a7e13 412
342b6a2f 413 wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, id );
83624f79 414 event.SetEventObject( menu );
cf7a7e13 415
83624f79 416/* wxMSW doesn't call callback here either
8bbe427f 417
83624f79
RR
418 if (menu->m_callback)
419 {
420 (void) (*(menu->m_callback)) (*menu, event);
421 return;
422 }
13439807 423*/
6de97a3b 424
c626a8b7
VZ
425 if (menu->GetEventHandler()->ProcessEvent(event))
426 return;
6de97a3b 427
83624f79
RR
428 wxWindow *win = menu->GetInvokingWindow();
429 if (win) win->GetEventHandler()->ProcessEvent( event );
6de97a3b 430}
c801d85f 431
cd743a6f
RR
432//-----------------------------------------------------------------------------
433// "deselect"
434//-----------------------------------------------------------------------------
435
436static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu )
437{
acfd422a
RR
438 if (g_isIdle) wxapp_install_idle_handler();
439
cd743a6f
RR
440 int id = menu->FindMenuIdByMenuItem(widget);
441
442 wxASSERT( id != -1 ); // should find it!
443
c626a8b7
VZ
444 if (!menu->IsEnabled(id))
445 return;
cd743a6f
RR
446
447 wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, -1 );
448 event.SetEventObject( menu );
449
c626a8b7
VZ
450 if (menu->GetEventHandler()->ProcessEvent(event))
451 return;
cd743a6f
RR
452
453 wxWindow *win = menu->GetInvokingWindow();
c626a8b7
VZ
454 if (win)
455 win->GetEventHandler()->ProcessEvent( event );
cd743a6f
RR
456}
457
cf7a7e13 458//-----------------------------------------------------------------------------
db1b4961 459// wxMenuItem
cf7a7e13
RR
460//-----------------------------------------------------------------------------
461
c801d85f 462IMPLEMENT_DYNAMIC_CLASS(wxMenuItem,wxObject)
96fd301f
VZ
463
464wxMenuItem::wxMenuItem()
c801d85f 465{
83624f79
RR
466 m_id = ID_SEPARATOR;
467 m_isCheckMenu = FALSE;
468 m_isChecked = FALSE;
469 m_isEnabled = TRUE;
470 m_subMenu = (wxMenu *) NULL;
471 m_menuItem = (GtkWidget *) NULL;
6de97a3b 472}
c801d85f 473
c626a8b7 474// it's valid for this function to be called even if m_menuItem == NULL
83624f79 475void wxMenuItem::SetName( const wxString& str )
716b7364 476{
b019151f
OK
477 m_text = _T("");
478 for ( const wxChar *pc = str; *pc != _T('\0'); pc++ )
83624f79 479 {
b019151f 480 if (*pc == _T('&'))
034be888
RR
481 {
482 pc++; /* skip it */
483#if (GTK_MINOR_VERSION > 0)
b019151f 484 m_text << _T('_');
034be888
RR
485#endif
486 }
83624f79
RR
487 m_text << *pc;
488 }
96fd301f 489
83624f79
RR
490 if (m_menuItem)
491 {
492 GtkLabel *label = GTK_LABEL( GTK_BIN(m_menuItem)->child );
1e133b7d 493 gtk_label_set( label, m_text.mb_str());
83624f79 494 }
716b7364
RR
495}
496
96fd301f 497void wxMenuItem::Check( bool check )
716b7364 498{
b019151f 499 wxCHECK_RET( m_menuItem, _T("invalid menu item") );
db1b4961 500
b019151f 501 wxCHECK_RET( IsCheckable(), _T("Can't check uncheckable item!") )
96fd301f 502
2d17d68f
RR
503 if (check == m_isChecked) return;
504
83624f79
RR
505 m_isChecked = check;
506 gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check );
716b7364
RR
507}
508
8bbe427f
VZ
509void wxMenuItem::Enable( bool enable )
510{
b019151f 511 wxCHECK_RET( m_menuItem, _T("invalid menu item") );
db1b4961 512
83624f79
RR
513 gtk_widget_set_sensitive( m_menuItem, enable );
514 m_isEnabled = enable;
a9c96bcc
RR
515}
516
96fd301f 517bool wxMenuItem::IsChecked() const
716b7364 518{
b019151f 519 wxCHECK_MSG( m_menuItem, FALSE, _T("invalid menu item") );
db1b4961 520
83624f79 521 wxCHECK( IsCheckable(), FALSE ); // can't get state of uncheckable item!
96fd301f 522
83624f79 523 bool bIsChecked = ((GtkCheckMenuItem*)m_menuItem)->active != 0;
96fd301f 524
83624f79 525 return bIsChecked;
716b7364
RR
526}
527
db1b4961 528//-----------------------------------------------------------------------------
83624f79 529// wxMenu
db1b4961
RR
530//-----------------------------------------------------------------------------
531
c801d85f
KB
532IMPLEMENT_DYNAMIC_CLASS(wxMenu,wxEvtHandler)
533
6de97a3b 534wxMenu::wxMenu( const wxString& title, const wxFunction func )
c801d85f 535{
83624f79
RR
536 m_title = title;
537 m_items.DeleteContents( TRUE );
538 m_invokingWindow = (wxWindow *) NULL;
034be888
RR
539
540#if (GTK_MINOR_VERSION > 0)
541 m_accel = gtk_accel_group_new();
542 m_factory = gtk_item_factory_new( GTK_TYPE_MENU, "<main>", m_accel );
543 m_menu = gtk_item_factory_get_widget( m_factory, "<main>" );
544#else
83624f79 545 m_menu = gtk_menu_new(); // Do not show!
034be888 546#endif
8bbe427f 547
83624f79
RR
548 m_callback = func;
549 m_eventHandler = this;
550 m_clientData = (void*) NULL;
8bbe427f 551
b019151f
OK
552 if (m_title.IsNull()) m_title = _T("");
553 if (m_title != _T(""))
83624f79
RR
554 {
555 Append(-2, m_title);
556 AppendSeparator();
557 }
c626a8b7 558
2b1c162e 559 m_owner = (GtkWidget*) NULL;
6de97a3b 560}
c801d85f 561
034be888
RR
562wxMenu::~wxMenu()
563{
564 /* how do we delete an item-factory ? */
565}
566
c2dd8380
GL
567void wxMenu::SetTitle( const wxString& title )
568{
c626a8b7 569 // TODO Waiting for something better
83624f79 570 m_title = title;
c2dd8380
GL
571}
572
573const wxString wxMenu::GetTitle() const
574{
83624f79 575 return m_title;
c2dd8380
GL
576}
577
96fd301f 578void wxMenu::AppendSeparator()
c801d85f 579{
83624f79
RR
580 wxMenuItem *mitem = new wxMenuItem();
581 mitem->SetId(ID_SEPARATOR);
96fd301f 582
83624f79
RR
583 GtkWidget *menuItem = gtk_menu_item_new();
584 gtk_menu_append( GTK_MENU(m_menu), menuItem );
585 gtk_widget_show( menuItem );
034be888 586
83624f79
RR
587 mitem->SetMenuItem(menuItem);
588 m_items.Append( mitem );
6de97a3b 589}
c801d85f 590
debe6624 591void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool checkable )
c801d85f 592{
83624f79
RR
593 wxMenuItem *mitem = new wxMenuItem();
594 mitem->SetId(id);
595 mitem->SetText(item);
596 mitem->SetHelp(helpStr);
597 mitem->SetCheckable(checkable);
034be888
RR
598
599#if (GTK_MINOR_VERSION > 0)
1e133b7d
RR
600 /* text has "_" instead of "&" after mitem->SetText() */
601 wxString text( mitem->GetText() );
602
603 /* local buffer in multibyte form */
604 char buf[200];
605 strcpy( buf, "/" );
606 strcat( buf, text.mb_str() );
034be888
RR
607
608 GtkItemFactoryEntry entry;
1e133b7d 609 entry.path = buf;
034be888
RR
610 entry.accelerator = (gchar*) NULL;
611 entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback;
612 entry.callback_action = 0;
613 if (checkable)
614 entry.item_type = "<CheckItem>";
615 else
616 entry.item_type = "<Item>";
617
618 gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */
619
620 /* in order to get the pointer to the item we need the item text _without_ underscores */
b019151f
OK
621 wxString s = _T("<main>/");
622 for ( const wxChar *pc = text; *pc != _T('\0'); pc++ )
034be888 623 {
b019151f 624 if (*pc == _T('_')) pc++; /* skip it */
034be888
RR
625 s << *pc;
626 }
627
1e133b7d 628 GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, s.mb_str() );
034be888
RR
629
630#else
631
1e133b7d
RR
632 GtkWidget *menuItem = checkable ? gtk_check_menu_item_new_with_label( item.mb_str() )
633 : gtk_menu_item_new_with_label( item.mb_str() );
034be888 634
83624f79
RR
635 gtk_signal_connect( GTK_OBJECT(menuItem), "activate",
636 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback),
034be888
RR
637 (gpointer)this );
638
639 gtk_menu_append( GTK_MENU(m_menu), menuItem );
640 gtk_widget_show( menuItem );
641
642#endif
96fd301f 643
83624f79
RR
644 gtk_signal_connect( GTK_OBJECT(menuItem), "select",
645 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback),
034be888 646 (gpointer)this );
cf7a7e13 647
cd743a6f
RR
648 gtk_signal_connect( GTK_OBJECT(menuItem), "deselect",
649 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback),
034be888
RR
650 (gpointer)this );
651
652 mitem->SetMenuItem(menuItem);
cd743a6f 653
83624f79 654 m_items.Append( mitem );
6de97a3b 655}
c801d85f 656
96fd301f 657void wxMenu::Append( int id, const wxString &text, wxMenu *subMenu, const wxString &helpStr )
c801d85f 658{
83624f79
RR
659 wxMenuItem *mitem = new wxMenuItem();
660 mitem->SetId(id);
661 mitem->SetText(text);
828f655f 662 mitem->SetHelp(helpStr);
96fd301f 663
b019151f 664 GtkWidget *menuItem = gtk_menu_item_new_with_label(mitem->GetText().mbc_str());
83624f79
RR
665 mitem->SetMenuItem(menuItem);
666 mitem->SetSubMenu(subMenu);
96fd301f 667
cd743a6f
RR
668 gtk_signal_connect( GTK_OBJECT(menuItem), "select",
669 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback),
670 (gpointer*)this );
671
672 gtk_signal_connect( GTK_OBJECT(menuItem), "deselect",
673 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback),
674 (gpointer*)this );
675
83624f79
RR
676 gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu );
677 gtk_menu_append( GTK_MENU(m_menu), menuItem );
678 gtk_widget_show( menuItem );
679 m_items.Append( mitem );
6de97a3b 680}
c801d85f 681
828f655f
RR
682void wxMenu::Append( wxMenuItem *item )
683{
684 m_items.Append( item );
c626a8b7 685
828f655f
RR
686 GtkWidget *menuItem = (GtkWidget*) NULL;
687
c626a8b7 688 if (item->IsSeparator())
828f655f 689 menuItem = gtk_menu_item_new();
c626a8b7 690 else if (item->IsSubMenu())
b019151f 691 menuItem = gtk_menu_item_new_with_label(item->GetText().mbc_str());
c626a8b7 692 else
b019151f
OK
693 menuItem = item->IsCheckable() ? gtk_check_menu_item_new_with_label(item->GetText().mbc_str())
694 : gtk_menu_item_new_with_label(item->GetText().mbc_str());
828f655f
RR
695
696 if (!item->IsSeparator())
697 {
698 gtk_signal_connect( GTK_OBJECT(menuItem), "select",
699 GTK_SIGNAL_FUNC(gtk_menu_hilight_callback),
700 (gpointer*)this );
701
702 gtk_signal_connect( GTK_OBJECT(menuItem), "deselect",
703 GTK_SIGNAL_FUNC(gtk_menu_nolight_callback),
704 (gpointer*)this );
c626a8b7
VZ
705
706 if (!item->IsSubMenu())
707 {
828f655f
RR
708 gtk_signal_connect( GTK_OBJECT(menuItem), "activate",
709 GTK_SIGNAL_FUNC(gtk_menu_clicked_callback),
710 (gpointer*)this );
c626a8b7 711 }
828f655f 712 }
c626a8b7 713
828f655f
RR
714 gtk_menu_append( GTK_MENU(m_menu), menuItem );
715 gtk_widget_show( menuItem );
716 item->SetMenuItem(menuItem);
717}
718
c801d85f
KB
719int wxMenu::FindItem( const wxString itemString ) const
720{
b019151f
OK
721 wxString s = _T("");
722 for ( const wxChar *pc = itemString; *pc != _T('\0'); pc++ )
83624f79 723 {
b019151f 724 if (*pc == _T('&'))
034be888
RR
725 {
726 pc++; /* skip it */
727#if (GTK_MINOR_VERSION > 0)
b019151f 728 s << _T('_');
034be888
RR
729#endif
730 }
731 s << *pc;
732 }
96fd301f 733
83624f79
RR
734 wxNode *node = m_items.First();
735 while (node)
736 {
737 wxMenuItem *item = (wxMenuItem*)node->Data();
738 if (item->GetText() == s)
c626a8b7 739 {
83624f79 740 return item->GetId();
c626a8b7 741 }
83624f79
RR
742 node = node->Next();
743 }
96fd301f 744
c626a8b7 745 return wxNOT_FOUND;
6de97a3b 746}
c801d85f 747
96fd301f 748void wxMenu::Enable( int id, bool enable )
716b7364 749{
83624f79 750 wxMenuItem *item = FindItem(id);
c626a8b7 751
b019151f 752 wxCHECK_RET( item, _T("wxMenu::Enable: no such item") );
c626a8b7
VZ
753
754 item->Enable(enable);
6de97a3b 755}
716b7364 756
96fd301f 757bool wxMenu::IsEnabled( int id ) const
e2414cbe 758{
83624f79 759 wxMenuItem *item = FindItem(id);
c626a8b7 760
b019151f 761 wxCHECK_MSG( item, FALSE, _T("wxMenu::IsEnabled: no such item") );
c626a8b7
VZ
762
763 return item->IsEnabled();
6de97a3b 764}
e2414cbe 765
96fd301f 766void wxMenu::Check( int id, bool enable )
c801d85f 767{
83624f79 768 wxMenuItem *item = FindItem(id);
c626a8b7 769
b019151f 770 wxCHECK_RET( item, _T("wxMenu::Check: no such item") );
c626a8b7
VZ
771
772 item->Check(enable);
6de97a3b 773}
c801d85f 774
96fd301f 775bool wxMenu::IsChecked( int id ) const
c801d85f 776{
83624f79 777 wxMenuItem *item = FindItem(id);
c626a8b7 778
b019151f 779 wxCHECK_MSG( item, FALSE, _T("wxMenu::IsChecked: no such item") );
c626a8b7
VZ
780
781 return item->IsChecked();
6de97a3b 782}
c801d85f 783
debe6624 784void wxMenu::SetLabel( int id, const wxString &label )
c801d85f 785{
83624f79 786 wxMenuItem *item = FindItem(id);
c626a8b7 787
b019151f 788 wxCHECK_RET( item, _T("wxMenu::SetLabel: no such item") );
c626a8b7
VZ
789
790 item->SetText(label);
6de97a3b 791}
96fd301f 792
c33c4050
RR
793wxString wxMenu::GetLabel( int id ) const
794{
83624f79 795 wxMenuItem *item = FindItem(id);
c626a8b7 796
b019151f 797 wxCHECK_MSG( item, _T(""), _T("wxMenu::GetLabel: no such item") );
c626a8b7
VZ
798
799 return item->GetText();
c33c4050
RR
800}
801
802void wxMenu::SetHelpString( int id, const wxString& helpString )
803{
83624f79 804 wxMenuItem *item = FindItem(id);
c626a8b7 805
b019151f 806 wxCHECK_RET( item, _T("wxMenu::SetHelpString: no such item") );
c626a8b7
VZ
807
808 item->SetHelp( helpString );
c33c4050
RR
809}
810
811wxString wxMenu::GetHelpString( int id ) const
812{
83624f79 813 wxMenuItem *item = FindItem(id);
c626a8b7 814
b019151f 815 wxCHECK_MSG( item, _T(""), _T("wxMenu::GetHelpString: no such item") );
c626a8b7
VZ
816
817 return item->GetHelp();
c33c4050
RR
818}
819
96fd301f
VZ
820int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const
821{
83624f79
RR
822 wxNode *node = m_items.First();
823 while (node)
824 {
825 wxMenuItem *item = (wxMenuItem*)node->Data();
826 if (item->GetMenuItem() == menuItem)
827 return item->GetId();
828 node = node->Next();
829 }
96fd301f 830
c626a8b7 831 return wxNOT_FOUND;
6de97a3b 832}
c801d85f 833
96fd301f 834wxMenuItem *wxMenu::FindItem(int id) const
c801d85f 835{
83624f79 836 wxNode *node = m_items.First();
c626a8b7 837 while (node)
83624f79
RR
838 {
839 wxMenuItem *item = (wxMenuItem*)node->Data();
840 if (item->GetId() == id)
c626a8b7 841 {
83624f79 842 return item;
c626a8b7 843 }
83624f79
RR
844 node = node->Next();
845 }
96fd301f 846
83624f79
RR
847 /* Not finding anything here can be correct
848 * when search the entire menu system for
849 * an entry -> no error message. */
8bbe427f 850
83624f79 851 return (wxMenuItem *) NULL;
96fd301f 852}
c801d85f
KB
853
854void wxMenu::SetInvokingWindow( wxWindow *win )
855{
83624f79 856 m_invokingWindow = win;
6de97a3b 857}
c801d85f 858
96fd301f 859wxWindow *wxMenu::GetInvokingWindow()
c801d85f 860{
83624f79 861 return m_invokingWindow;
6de97a3b 862}
c801d85f 863
c626a8b7
VZ
864// Update a menu and all submenus recursively. source is the object that has
865// the update event handlers defined for it. If NULL, the menu or associated
866// window will be used.
631f1bfe
JS
867void wxMenu::UpdateUI(wxEvtHandler* source)
868{
869 if (!source && GetInvokingWindow())
870 source = GetInvokingWindow()->GetEventHandler();
871 if (!source)
872 source = GetEventHandler();
873 if (!source)
874 source = this;
875
876 wxNode* node = GetItems().First();
877 while (node)
878 {
879 wxMenuItem* item = (wxMenuItem*) node->Data();
880 if ( !item->IsSeparator() )
881 {
882 wxWindowID id = item->GetId();
883 wxUpdateUIEvent event(id);
884 event.SetEventObject( source );
885
886 if (source->ProcessEvent(event))
887 {
888 if (event.GetSetText())
889 SetLabel(id, event.GetText());
890 if (event.GetSetChecked())
891 Check(id, event.GetChecked());
892 if (event.GetSetEnabled())
893 Enable(id, event.GetEnabled());
894 }
895
896 if (item->GetSubMenu())
897 item->GetSubMenu()->UpdateUI(source);
898 }
899 node = node->Next();
900 }
901}
902