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