*** empty log message ***
[wxWidgets.git] / src / os2 / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/10/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/frame.h"
17 #include "wx/menu.h"
18 #include "wx/utils.h"
19 #include "wx/intl.h"
20 #endif
21
22 #if wxUSE_OWNER_DRAWN
23 #include "wx/ownerdrw.h"
24 #endif
25
26 #include "wx/os2/private.h"
27 #include "wx/menu.h"
28 #include "wx/menuitem.h"
29 #include "wx/log.h"
30
31 // other standard headers
32 #include <string.h>
33
34 // ----------------------------------------------------------------------------
35 // global variables
36 // ----------------------------------------------------------------------------
37
38 extern wxMenu *wxCurrentPopupMenu;
39
40 // ----------------------------------------------------------------------------
41 // constants
42 // ----------------------------------------------------------------------------
43
44 // the (popup) menu title has this special id
45 static const int idMenuTitle = -2;
46
47 // ----------------------------------------------------------------------------
48 // macros
49 // ----------------------------------------------------------------------------
50
51 #if !USE_SHARED_LIBRARY
52 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
53 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
54 #endif
55
56 // ============================================================================
57 // implementation
58 // ============================================================================
59
60 // ---------------------------------------------------------------------------
61 // wxMenu construction, adding and removing menu items
62 // ---------------------------------------------------------------------------
63
64 // Construct a menu with optional title (then use append)
65 void wxMenu::Init(const wxString& title, const wxFunction func )
66 {
67 m_title = title;
68 m_parent = NULL;
69 m_eventHandler = this;
70 m_pInvokingWindow = NULL;
71 m_doBreak = FALSE ;
72 m_noItems = 0;
73 m_menuBar = NULL;
74 m_hMenu = 0; //(WXHMENU) CreatePopupMenu();
75 m_savehMenu = 0 ;
76 m_topLevelMenu = this;
77 m_clientData = (void*) NULL;
78
79 if ( !!m_title )
80 {
81 Append(idMenuTitle, m_title) ;
82 AppendSeparator() ;
83 }
84
85 Callback(func);
86 }
87
88 // The wxWindow destructor will take care of deleting the submenus.
89 wxMenu::~wxMenu()
90 {
91 // free Windows resources
92 if ( m_hMenu )
93 {
94 // ::DestroyMenu((HMENU)m_hMenu);
95 m_hMenu = 0;
96 }
97
98 // delete submenus
99 wxNode *node = m_menuItems.First();
100 while ( node )
101 {
102 wxMenuItem *item = (wxMenuItem *)node->Data();
103
104 // Delete child menus.
105 // Beware: they must not be appended to children list!!!
106 // (because order of delete is significant)
107 if ( item->IsSubMenu() )
108 item->DeleteSubMenu();
109
110 wxNode *next = node->Next();
111 delete item;
112 delete node;
113 node = next;
114 }
115 }
116
117 void wxMenu::Break()
118 {
119 m_doBreak = TRUE;
120 }
121
122 // function appends a new item or submenu to the menu
123 void wxMenu::Append(wxMenuItem *pItem)
124 {
125 wxCHECK_RET( pItem != NULL, wxT("can't append NULL item to the menu") );
126
127 #if wxUSE_ACCEL
128 // check for accelerators: they are given after '\t'
129 wxString label = pItem->GetName();
130 int posTab = label.Find(wxT('\t'));
131 if ( posTab != wxNOT_FOUND ) {
132 // parse the accelerator string
133 int keyCode = 0;
134 int accelFlags = wxACCEL_NORMAL;
135 wxString current;
136 for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) {
137 if ( (label[n] == '+') || (label[n] == '-') ) {
138 if ( current == _("ctrl") )
139 accelFlags |= wxACCEL_CTRL;
140 else if ( current == _("alt") )
141 accelFlags |= wxACCEL_ALT;
142 else if ( current == _("shift") )
143 accelFlags |= wxACCEL_SHIFT;
144 else {
145 wxLogDebug(wxT("Unknown accel modifier: '%s'"),
146 current.c_str());
147 }
148
149 current.Empty();
150 }
151 else {
152 current += wxTolower(label[n]);
153 }
154 }
155
156 if ( current.IsEmpty() ) {
157 wxLogDebug(wxT("No accel key found, accel string ignored."));
158 }
159 else {
160 if ( current.Len() == 1 ) {
161 // it's a letter
162 keyCode = wxToupper(current[0U]);
163 }
164 else {
165 // it should be a function key
166 if ( current[0U] == 'f' && isdigit(current[1U]) &&
167 (current.Len() == 2 ||
168 (current.Len() == 3 && isdigit(current[2U]))) ) {
169 int n;
170 wxSscanf(current.c_str() + 1, wxT("%d"), &n);
171
172 keyCode = VK_F1 + n - 1;
173 }
174 else {
175 wxLogDebug(wxT("Unrecognized accel key '%s', accel "
176 "string ignored."), current.c_str());
177 }
178 }
179 }
180
181 if ( keyCode ) {
182 // do add an entry
183 m_accelKeyCodes.Add(keyCode);
184 m_accelFlags.Add(accelFlags);
185 m_accelIds.Add(pItem->GetId());
186 }
187 }
188 #endif // wxUSE_ACCEL
189
190 UINT flags = 0;
191
192 // TODO:
193 /*
194 // if "Break" has just been called, insert a menu break before this item
195 // (and don't forget to reset the flag)
196 if ( m_doBreak ) {
197 flags |= MF_MENUBREAK;
198 m_doBreak = FALSE;
199 }
200
201 if ( pItem->IsSeparator() ) {
202 flags |= MF_SEPARATOR;
203 }
204
205 // id is the numeric id for normal menu items and HMENU for submenus as
206 // required by ::AppendMenu() API
207 UINT id;
208 wxMenu *submenu = pItem->GetSubMenu();
209 if ( submenu != NULL ) {
210 wxASSERT( submenu->GetHMenu() != (WXHMENU) NULL );
211
212 id = (UINT)submenu->GetHMenu();
213 submenu->m_topLevelMenu = m_topLevelMenu;
214 submenu->m_parent = this;
215 submenu->m_savehMenu = (WXHMENU)id;
216 submenu->m_hMenu = 0;
217
218 flags |= MF_POPUP;
219 }
220 else {
221 id = pItem->GetId();
222 }
223
224 const char* pData;
225
226 #if wxUSE_OWNER_DRAWN
227 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
228 // item draws itself, pass pointer to it in data parameter
229 flags |= MF_OWNERDRAW;
230 pData = (const char*)pItem;
231 }
232 else
233 #endif
234 {
235 // menu is just a normal string (passed in data parameter)
236 flags |= MF_STRING;
237 pData = label;
238 }
239 if ( !::AppendMenu(GetHmenu(), flags, id, pData) )
240 {
241 wxLogLastError("AppendMenu");
242 }
243 else
244 {
245 if ( id == idMenuTitle )
246 {
247 // visually select the menu title
248 MENUITEMINFO mii;
249 mii.cbSize = sizeof(mii);
250 mii.fMask = MIIM_STATE;
251 mii.fState = MFS_DEFAULT;
252
253 if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
254 {
255 wxLogLastError(wxT("SetMenuItemInfo"));
256 }
257 }
258 m_menuItems.Append(pItem);
259 m_noItems++;
260 }
261 */
262 }
263
264 void wxMenu::AppendSeparator()
265 {
266 Append(new wxMenuItem(this, ID_SEPARATOR));
267 }
268
269 // Pullright item
270 void wxMenu::Append(int id,
271 const wxString& label,
272 wxMenu *SubMenu,
273 const wxString& helpString)
274 {
275 Append(new wxMenuItem(this, id, label, helpString, FALSE, SubMenu));
276 }
277
278 // Ordinary menu item
279 void wxMenu::Append(int id,
280 const wxString& label,
281 const wxString& helpString,
282 bool checkable)
283 {
284 // 'checkable' parameter is useless for Windows.
285 Append(new wxMenuItem(this, id, label, helpString, checkable));
286 }
287
288 // delete item by id
289 void wxMenu::Delete(int id)
290 {
291 wxMenuItem *item = NULL;
292 int pos;
293 wxNode *node;
294 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
295 {
296 item = (wxMenuItem *)node->Data();
297 if ( item->GetId() == id )
298 break;
299 }
300
301 wxCHECK_RET( node, wxT("wxMenu::Delete(): item doesn't exist") );
302
303 HMENU menu = GetHmenu();
304
305 wxMenu *pSubMenu = item->GetSubMenu();
306 if ( pSubMenu != NULL )
307 {
308 // RemoveMenu(menu, (UINT)pos, MF_BYPOSITION);
309 pSubMenu->m_hMenu = pSubMenu->m_savehMenu;
310 pSubMenu->m_savehMenu = 0;
311 pSubMenu->m_parent = NULL;
312 // RemoveChild(item->subMenu);
313 pSubMenu->m_topLevelMenu = NULL;
314 // TODO: Why isn't subMenu deleted here???
315 // Will put this in for now. Assuming this is supposed
316 // to delete the menu, not just remove it.
317 item->DeleteSubMenu();
318 }
319 // else
320 // {
321 // DeleteMenu(menu, (UINT)pos, MF_BYPOSITION);
322 // }
323
324 m_menuItems.DeleteNode(node);
325 delete item;
326 }
327
328 #if wxUSE_ACCEL
329
330 // ---------------------------------------------------------------------------
331 // accelerator helpers
332 // ---------------------------------------------------------------------------
333
334 // create the wxAcceleratorEntries for our accels and put them into provided
335 // array - return the number of accels we have
336 size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
337 {
338 size_t count = GetAccelCount();
339 for ( size_t n = 0; n < count; n++ )
340 {
341 (*accels++).Set(m_accelFlags[n], m_accelKeyCodes[n], m_accelIds[n]);
342 }
343
344 return count;
345 }
346
347 #endif // wxUSE_ACCEL
348
349 // ---------------------------------------------------------------------------
350 // wxMenu functions implemented in wxMenuItem
351 // ---------------------------------------------------------------------------
352
353 void wxMenu::Enable(int id, bool Flag)
354 {
355 wxMenuItem *item = FindItemForId(id);
356 wxCHECK_RET( item != NULL, wxT("can't enable non-existing menu item") );
357
358 item->Enable(Flag);
359 }
360
361 bool wxMenu::IsEnabled(int id) const
362 {
363 wxMenuItem *item = FindItemForId(id);
364 wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") );
365
366 return item->IsEnabled();
367 }
368
369 void wxMenu::Check(int id, bool Flag)
370 {
371 wxMenuItem *item = FindItemForId(id);
372 wxCHECK_RET( item != NULL, wxT("can't get status of non-existing menu item") );
373
374 item->Check(Flag);
375 }
376
377 bool wxMenu::IsChecked(int id) const
378 {
379 wxMenuItem *item = FindItemForId(id);
380 wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") );
381
382 return item->IsChecked();
383 }
384
385 void wxMenu::SetLabel(int id, const wxString& label)
386 {
387 wxMenuItem *item = FindItemForId(id) ;
388 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
389
390 item->SetName(label);
391 }
392
393 wxString wxMenu::GetLabel(int id) const
394 {
395 wxString label;
396 wxMenuItem *pItem = FindItemForId(id) ;
397 if (pItem)
398 label = pItem->GetName() ;
399 else
400 wxFAIL_MSG(wxT("wxMenu::GetLabel: item doesn't exist"));
401
402 return label;
403 }
404
405 void wxMenu::SetHelpString(int itemId, const wxString& helpString)
406 {
407 wxMenuItem *item = FindItemForId (itemId);
408 if (item)
409 item->SetHelp(helpString);
410 else
411 wxFAIL_MSG(wxT("wxMenu::SetHelpString: item doesn't exist"));
412 }
413
414 wxString wxMenu::GetHelpString (int itemId) const
415 {
416 wxString help;
417 wxMenuItem *item = FindItemForId (itemId);
418 if (item)
419 help = item->GetHelp();
420 else
421 wxFAIL_MSG(wxT("wxMenu::GetHelpString: item doesn't exist"));
422
423 return help;
424 }
425
426 // ---------------------------------------------------------------------------
427 // wxMenu title
428 // ---------------------------------------------------------------------------
429
430 void wxMenu::SetTitle(const wxString& label)
431 {
432 bool hasNoTitle = m_title.IsEmpty();
433 m_title = label;
434
435 HMENU hMenu = GetHmenu();
436 // TODO
437 /*
438 if ( hasNoTitle )
439 {
440 if ( !label.IsEmpty() )
441 {
442 if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
443 (unsigned)idMenuTitle, m_title) ||
444 !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
445 {
446 wxLogLastError(wxT("InsertMenu"));
447 }
448 }
449 }
450 else
451 {
452 if ( label.IsEmpty() )
453 {
454 // remove the title and the separator after it
455 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
456 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
457 {
458 wxLogLastError("RemoveMenu");
459 }
460 }
461 else
462 {
463 // modify the title
464 if ( !ModifyMenu(hMenu, 0u,
465 MF_BYPOSITION | MF_STRING,
466 (unsigned)idMenuTitle, m_title) )
467 {
468 wxLogLastError("ModifyMenu");
469 }
470 }
471 }
472
473 // put the title string in bold face
474 if ( !m_title.IsEmpty() )
475 {
476 MENUITEMINFO mii;
477 mii.cbSize = sizeof(mii);
478 mii.fMask = MIIM_STATE;
479 mii.fState = MFS_DEFAULT;
480
481 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
482 {
483 wxLogLastError("SetMenuItemInfo");
484 }
485 }
486 */
487 }
488
489 const wxString wxMenu::GetTitle() const
490 {
491 return m_title;
492 }
493
494 // ---------------------------------------------------------------------------
495 // event processing
496 // ---------------------------------------------------------------------------
497
498 bool wxMenu::OS2Command(WXUINT WXUNUSED(param), WXWORD id)
499 {
500 // ignore commands from the menu title
501
502 if ( id != (WXWORD)idMenuTitle )
503 {
504 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
505 event.SetEventObject( this );
506 event.SetId( id );
507 event.SetInt( id );
508 ProcessCommand(event);
509 }
510
511 return TRUE;
512 }
513
514 bool wxMenu::ProcessCommand(wxCommandEvent & event)
515 {
516 bool processed = FALSE;
517
518 // Try a callback
519 if (m_callback)
520 {
521 (void)(*(m_callback))(*this, event);
522 processed = TRUE;
523 }
524
525 // Try the menu's event handler
526 if ( !processed && GetEventHandler())
527 {
528 processed = GetEventHandler()->ProcessEvent(event);
529 }
530
531 // Try the window the menu was popped up from (and up through the
532 // hierarchy)
533 wxWindow *win = GetInvokingWindow();
534 if ( !processed && win )
535 processed = win->GetEventHandler()->ProcessEvent(event);
536
537 return processed;
538 }
539
540 // ---------------------------------------------------------------------------
541 // Item search
542 // ---------------------------------------------------------------------------
543
544 // Finds the item id matching the given string, -1 if not found.
545 int wxMenu::FindItem (const wxString& itemString) const
546 {
547 wxString itemLabel = wxStripMenuCodes(itemString);
548 for ( wxNode *node = m_menuItems.First(); node; node = node->Next() )
549 {
550 wxMenuItem *item = (wxMenuItem *)node->Data();
551 if ( item->IsSubMenu() )
552 {
553 int ans = item->GetSubMenu()->FindItem(itemString);
554 if ( ans != wxNOT_FOUND )
555 return ans;
556 }
557 else if ( !item->IsSeparator() )
558 {
559 wxString label = wxStripMenuCodes(item->GetName());
560 if ( itemLabel == label )
561 return item->GetId();
562 }
563 }
564
565 return wxNOT_FOUND;
566 }
567
568 wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
569 {
570 if ( itemMenu )
571 *itemMenu = NULL;
572
573 wxMenuItem *item = NULL;
574 for ( wxNode *node = m_menuItems.First(); node && !item; node = node->Next() )
575 {
576 item = (wxMenuItem *)node->Data();
577
578 if ( item->GetId() == itemId )
579 {
580 if (itemMenu)
581 *itemMenu = (wxMenu *)this;
582 }
583 else if ( item->IsSubMenu() )
584 {
585 item = item->GetSubMenu()->FindItemForId(itemId, itemMenu);
586 }
587 else
588 {
589 // don't exit the loop
590 item = NULL;
591 }
592 }
593
594 return item;
595 }
596
597 // ---------------------------------------------------------------------------
598 // other
599 // ---------------------------------------------------------------------------
600
601 void wxMenu::Attach(wxMenuBar *menubar)
602 {
603 // menu can be in at most one menubar because otherwise they would both
604 // delete the menu pointer
605 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
606
607 m_menuBar = menubar;
608 m_savehMenu = m_hMenu;
609 m_hMenu = 0;
610 }
611
612 void wxMenu::Detach()
613 {
614 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
615
616 m_hMenu = m_savehMenu;
617 m_savehMenu = 0;
618 }
619
620 // ---------------------------------------------------------------------------
621 // Menu Bar
622 // ---------------------------------------------------------------------------
623
624 void wxMenuBar::Init()
625 {
626 m_eventHandler = this;
627 m_menuCount = 0;
628 m_menus = NULL;
629 m_titles = NULL;
630 m_menuBarFrame = NULL;
631 m_hMenu = 0;
632 }
633
634 wxMenuBar::wxMenuBar()
635 {
636 Init();
637 }
638
639 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
640 {
641 Init();
642 }
643
644 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
645 {
646 Init();
647
648 m_menuCount = count;
649 m_menus = menus;
650 m_titles = new wxString[count];
651
652 int i;
653 for ( i = 0; i < count; i++ )
654 m_titles[i] = titles[i];
655
656 for ( i = 0; i < count; i++ )
657 m_menus[i]->Attach(this);
658 }
659
660 wxMenuBar::~wxMenuBar()
661 {
662 for ( int i = 0; i < m_menuCount; i++ )
663 {
664 delete m_menus[i];
665 }
666
667 delete[] m_menus;
668 delete[] m_titles;
669 }
670
671 // ---------------------------------------------------------------------------
672 // wxMenuBar helpers
673 // ---------------------------------------------------------------------------
674
675 void wxMenuBar::Refresh()
676 {
677 wxCHECK_RET( m_menuBarFrame, wxT("can't refresh a menubar withotu a frame") );
678
679 // TODO DrawMenuBar((HWND)m_menuBarFrame->GetHWND()) ;
680 }
681
682 WXHMENU wxMenuBar::Create()
683 {
684 if (m_hMenu != 0 )
685 return m_hMenu;
686
687 wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") );
688
689 m_hMenu = 0; // TODO: (WXHMENU)::CreateMenu();
690
691 if ( !m_hMenu )
692 {
693 wxLogLastError("CreateMenu");
694 }
695 else
696 {
697 for ( int i = 0; i < m_menuCount; i++ )
698 {
699 // if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
700 // (UINT)m_menus[i]->GetHMenu(),
701 // m_titles[i]) )
702 // {
703 // wxLogLastError("AppendMenu");
704 // }
705 }
706 }
707
708 return m_hMenu;
709 }
710
711 // ---------------------------------------------------------------------------
712 // wxMenuBar functions forwarded to wxMenuItem
713 // ---------------------------------------------------------------------------
714
715 // Must only be used AFTER menu has been attached to frame,
716 // otherwise use individual menus to enable/disable items
717 void wxMenuBar::Enable(int id, bool enable)
718 {
719 wxMenu *itemMenu = NULL;
720 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
721
722 wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") );
723
724 item->Enable(enable);
725 }
726
727 void wxMenuBar::EnableTop(int pos, bool enable)
728 {
729 int flag = 0; // TODO enable ? MF_ENABLED : MF_GRAYED;;
730
731 // EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
732 }
733
734 // Must only be used AFTER menu has been attached to frame,
735 // otherwise use individual menus
736 void wxMenuBar::Check(int id, bool check)
737 {
738 wxMenu *itemMenu = NULL;
739 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
740
741 wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") );
742 wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") );
743
744 item->Check(check);
745 }
746
747 bool wxMenuBar::IsChecked(int id) const
748 {
749 wxMenu *itemMenu = NULL;
750 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
751
752 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") );
753
754 // int flag = ::GetMenuState(GetHmenuOf(itemMenu), id, MF_BYCOMMAND);
755
756 // return (flag & MF_CHECKED) != 0;
757 return FALSE;
758 }
759
760 bool wxMenuBar::IsEnabled(int id) const
761 {
762 wxMenu *itemMenu = NULL;
763 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
764
765 wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") );
766
767 // int flag = ::GetMenuState(GetHmenuOf(itemMenu), id, MF_BYCOMMAND) ;
768
769 // don't "and" with MF_ENABLED because its value is 0
770 // return (flag & MF_DISABLED) == 0;
771 return FALSE;
772 }
773
774 void wxMenuBar::SetLabel(int id, const wxString& label)
775 {
776 wxMenu *itemMenu = NULL;
777 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
778
779 wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") );
780
781 item->SetName(label);
782 }
783
784 wxString wxMenuBar::GetLabel(int id) const
785 {
786 wxMenu *itemMenu = NULL;
787 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
788
789 wxCHECK_MSG( item, wxT(""), wxT("wxMenuBar::GetLabel(): no such item") );
790
791 return item->GetName();
792 }
793
794 void wxMenuBar::SetHelpString (int id, const wxString& helpString)
795 {
796 wxMenu *itemMenu = NULL;
797 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
798
799 wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") );
800
801 item->SetHelp(helpString);
802 }
803
804 wxString wxMenuBar::GetHelpString (int id) const
805 {
806 wxMenu *itemMenu = NULL;
807 wxMenuItem *item = FindItemForId(id, &itemMenu) ;
808
809 wxCHECK_MSG( item, wxT(""), wxT("wxMenuBar::GetHelpString(): no such item") );
810
811 return item->GetHelp();
812 }
813
814 // ---------------------------------------------------------------------------
815 // wxMenuBar functions to work with the top level submenus
816 // ---------------------------------------------------------------------------
817
818 // NB: we don't support owner drawn top level items for now, if we do these
819 // functions would have to be changed to use wxMenuItem as well
820
821 void wxMenuBar::SetLabelTop(int pos, const wxString& label)
822 {
823 UINT id;
824 UINT flagsOld = 0; // TODO: ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
825 if ( flagsOld == 0xFFFFFFFF )
826 {
827 wxLogLastError(wxT("GetMenuState"));
828
829 return;
830 }
831
832 // if ( flagsOld & MF_POPUP )
833 // {
834 // // HIBYTE contains the number of items in the submenu in this case
835 // flagsOld &= 0xff ;
836 // id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos) ;
837 // }
838 // else
839 // {
840 // id = pos;
841 // }
842
843 // if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
844 // id, label) == 0xFFFFFFFF )
845 // {
846 // wxLogLastError("ModifyMenu");
847 // }
848 }
849
850 wxString wxMenuBar::GetLabelTop(int pos) const
851 {
852 int len = 0; // TODO: ::GetMenuString((HMENU)m_hMenu, pos, NULL, 0, MF_BYCOMMAND);
853
854 len++; // for the NUL character
855 wxString label;
856 // ::GetMenuString(GetHmenu(), pos, label.GetWriteBuf(len), len, MF_BYCOMMAND);
857 label.UngetWriteBuf();
858
859 return label;
860 }
861
862 // ---------------------------------------------------------------------------
863 // wxMenuBar notifications
864 // ---------------------------------------------------------------------------
865
866 bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
867 {
868 if ( !m_menuBarFrame )
869 return TRUE;
870
871 // TODO
872 /*
873 if ( ::RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION) )
874 {
875 // VZ: I'm not sure about what's going on here, so I leave an assert
876 wxASSERT_MSG( m_menus[pos] == a_menu, wxT("what is this parameter for??") );
877
878 a_menu->Detach();
879
880 if ( m_menuBarFrame )
881 Refresh();
882
883 return TRUE;
884 }
885 else
886 {
887 wxLogLastError("RemoveMenu");
888 }
889 */
890 return FALSE;
891 }
892
893 bool wxMenuBar::OnAppend(wxMenu *a_menu, const wxChar *title)
894 {
895 WXHMENU submenu = a_menu->GetHMenu();
896 if ( !submenu )
897 return FALSE;
898
899 if ( !m_menuBarFrame )
900 return TRUE;
901
902 a_menu->Attach(this);
903
904 // if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
905 // (UINT)submenu, title) )
906 // {
907 // wxLogLastError(wxT("AppendMenu"));
908 // }
909
910 Refresh();
911
912 return TRUE;
913 }
914
915 // ---------------------------------------------------------------------------
916 // wxMenuBar construction
917 // ---------------------------------------------------------------------------
918 int wxMenuBar::FindMenu(const wxString& title)
919 {
920 wxString menuTitle = wxStripMenuCodes(title);
921 for ( int i = 0; i < m_menuCount; i++ )
922 {
923 wxString title = wxStripMenuCodes(m_titles[i]);
924 if ( menuTitle == title )
925 return i;
926 }
927
928 return wxNOT_FOUND;
929
930 }
931
932
933 void wxMenuBar::ReplaceMenu(int pos, wxMenu * new_menu, const wxString& title)
934 {
935 if (m_menuBarFrame) return;
936
937 if ( pos >= 0 && pos < m_menuCount )
938 {
939 wxMenu *old_menu = m_menus[pos];
940 m_menus[pos] = new_menu;
941 delete old_menu;
942 }
943
944 }
945
946
947 void wxMenuBar::Insert(int pos, wxMenu * menu, const wxString& title)
948 {
949 if (m_menuBarFrame) return;
950 if ( pos < 0 && pos >= m_menuCount ) return;
951
952 m_menuCount ++;
953 wxMenu **new_menus = new wxMenu *[m_menuCount];
954 wxString *new_titles = new wxString[m_menuCount];
955 int i;
956
957 for (i = 0; i < pos; i++)
958 {
959 new_menus[i] = m_menus[i];
960 m_menus[i] = NULL;
961 new_titles[i] = m_titles[i];
962 m_titles[i] = wxT("");
963 }
964
965 new_menus[pos] = (wxMenu *)menu;
966 new_titles[i] = title;
967
968 for (i = pos+1; i < m_menuCount; i++)
969 {
970 new_menus[i] = m_menus[i-1];
971 m_menus[i-1] = NULL;
972 new_titles[i] = m_titles[i-1];
973 m_titles[i-1] = wxT("");
974 }
975 if (m_menus)
976 {
977 delete[]m_menus;
978 delete[]m_titles;
979 }
980 m_menus = new_menus;
981 m_titles = new_titles;
982
983 menu->SetParent(this);
984
985 }
986
987
988 void wxMenuBar::Append (wxMenu * menu, const wxString& title)
989 {
990 if (!OnAppend(menu, title))
991 return;
992
993 m_menuCount ++;
994 wxMenu **new_menus = new wxMenu *[m_menuCount];
995 wxString *new_titles = new wxString[m_menuCount];
996 int i;
997
998 for (i = 0; i < m_menuCount - 1; i++)
999 {
1000 new_menus[i] = m_menus[i];
1001 m_menus[i] = NULL;
1002 new_titles[i] = m_titles[i];
1003 m_titles[i] = wxT("");
1004 }
1005 if (m_menus)
1006 {
1007 delete[]m_menus;
1008 delete[]m_titles;
1009 }
1010 m_menus = new_menus;
1011 m_titles = new_titles;
1012
1013 m_menus[m_menuCount - 1] = (wxMenu *)menu;
1014 m_titles[m_menuCount - 1] = title;
1015
1016 menu->SetParent(this);
1017 }
1018
1019 void wxMenuBar::Delete(wxMenu * menu, int i)
1020 {
1021 int j;
1022 int ii = (int) i;
1023
1024 if (menu != 0) {
1025 for (ii = 0; ii < m_menuCount; ii++) {
1026 if (m_menus[ii] == menu)
1027 break;
1028 }
1029 if (ii >= m_menuCount)
1030 return;
1031 } else {
1032 if (ii < 0 || ii >= m_menuCount)
1033 return;
1034 menu = m_menus[ii];
1035 }
1036
1037 if (!OnDelete(menu, ii))
1038 return;
1039
1040 menu->SetParent(NULL);
1041
1042 -- m_menuCount;
1043 for (j = ii; j < m_menuCount; j++) {
1044 m_menus[j] = m_menus[j + 1];
1045 m_titles[j] = m_titles[j + 1];
1046 }
1047 }
1048
1049 void wxMenuBar::Attach(wxFrame *frame)
1050 {
1051 wxASSERT_MSG( !m_menuBarFrame, wxT("menubar already attached!") );
1052
1053 m_menuBarFrame = frame;
1054
1055 #if wxUSE_ACCEL
1056 // create the accel table - we consider that the menubar construction is
1057 // finished
1058 size_t nAccelCount = 0;
1059 int i;
1060 for ( i = 0; i < m_menuCount; i++ )
1061 {
1062 nAccelCount += m_menus[i]->GetAccelCount();
1063 }
1064
1065 if ( nAccelCount )
1066 {
1067 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
1068
1069 nAccelCount = 0;
1070 for ( i = 0; i < m_menuCount; i++ )
1071 {
1072 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
1073 }
1074
1075 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
1076
1077 delete [] accelEntries;
1078 }
1079 #endif // wxUSE_ACCEL
1080 }
1081
1082 void wxMenuBar::Detach()
1083 {
1084 // ::DestroyMenu((HMENU)m_hMenu);
1085 m_hMenu = NULL;
1086 m_menuBarFrame = NULL;
1087 }
1088
1089
1090 // ---------------------------------------------------------------------------
1091 // wxMenuBar searching for menu items
1092 // ---------------------------------------------------------------------------
1093
1094 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1095 int wxMenuBar::FindMenuItem(const wxString& menuString,
1096 const wxString& itemString) const
1097 {
1098 wxString menuLabel = wxStripMenuCodes(menuString);
1099 for ( int i = 0; i < m_menuCount; i++ )
1100 {
1101 wxString title = wxStripMenuCodes(m_titles[i]);
1102 if ( menuString == title )
1103 return m_menus[i]->FindItem(itemString);
1104 }
1105
1106 return wxNOT_FOUND;
1107 }
1108
1109 wxMenuItem *wxMenuBar::FindItemForId (int id, wxMenu **itemMenu) const
1110 {
1111 if ( itemMenu )
1112 *itemMenu = NULL;
1113
1114 wxMenuItem *item = NULL;
1115 for ( int i = 0; !item && (i < m_menuCount); i++ )
1116 {
1117 item = m_menus[i]->FindItemForId(id, itemMenu);
1118 }
1119
1120 return item;
1121 }
1122
1123
1124 // ----------------------------------------------------------------------------
1125 // helper functions
1126 // ----------------------------------------------------------------------------
1127
1128 wxWindow *wxMenu::GetWindow() const
1129 {
1130 if ( m_pInvokingWindow != NULL )
1131 return m_pInvokingWindow;
1132 else if ( m_menuBar != NULL)
1133 return m_menuBar->GetFrame();
1134
1135 return NULL;
1136 }
1137
1138 WXHMENU wxMenu::GetHMenu() const
1139 {
1140 if ( m_hMenu != 0 )
1141 return m_hMenu;
1142 else if ( m_savehMenu != 0 )
1143 return m_savehMenu;
1144
1145 wxFAIL_MSG(wxT("wxMenu without HMENU"));
1146
1147 return 0;
1148 }
1149
1150 // Update a menu and all submenus recursively. source is the object that has
1151 // the update event handlers defined for it. If NULL, the menu or associated
1152 // window will be used.
1153 void wxMenu::UpdateUI(wxEvtHandler* source)
1154 {
1155 if (!source && GetInvokingWindow())
1156 source = GetInvokingWindow()->GetEventHandler();
1157 if (!source)
1158 source = GetEventHandler();
1159 if (!source)
1160 source = this;
1161
1162 wxNode* node = GetItems().First();
1163 while (node)
1164 {
1165 wxMenuItem* item = (wxMenuItem*) node->Data();
1166 if ( !item->IsSeparator() )
1167 {
1168 wxWindowID id = item->GetId();
1169 wxUpdateUIEvent event(id);
1170 event.SetEventObject( source );
1171
1172 if (source->ProcessEvent(event))
1173 {
1174 if (event.GetSetText())
1175 SetLabel(id, event.GetText());
1176 if (event.GetSetChecked())
1177 Check(id, event.GetChecked());
1178 if (event.GetSetEnabled())
1179 Enable(id, event.GetEnabled());
1180 }
1181
1182 if (item->GetSubMenu())
1183 item->GetSubMenu()->UpdateUI(source);
1184 }
1185 node = node->Next();
1186 }
1187 }
1188