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