]> git.saurik.com Git - wxWidgets.git/blob - src/os2/menu.cpp
guard against nullptr
[wxWidgets.git] / src / os2 / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/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 #include "wx/menu.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/app.h"
19 #include "wx/frame.h"
20 #include "wx/utils.h"
21 #include "wx/intl.h"
22 #include "wx/log.h"
23 #endif
24
25 #if wxUSE_OWNER_DRAWN
26 #include "wx/ownerdrw.h"
27 #endif
28
29 #include "wx/os2/private.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 //
45 // The (popup) menu title has this special id
46 //
47 static const int idMenuTitle = -3;
48
49 //
50 // The unique ID for Menus
51 //
52 USHORT wxMenu::m_nextMenuId = 0;
53
54 // ----------------------------------------------------------------------------
55 // macros
56 // ----------------------------------------------------------------------------
57
58 // ============================================================================
59 // implementation
60 // ============================================================================
61
62 // ---------------------------------------------------------------------------
63 // wxMenu construction, adding and removing menu items
64 // ---------------------------------------------------------------------------
65
66 //
67 // Construct a menu with optional title (then use append)
68 //
69 void wxMenu::Init()
70 {
71 m_bDoBreak = false;
72 m_nStartRadioGroup = -1;
73
74 //
75 // Create the menu (to be used as a submenu or a popup)
76 //
77 if ((m_hMenu = ::WinCreateWindow( HWND_DESKTOP
78 ,WC_MENU
79 ,"Menu"
80 ,0L
81 ,0L
82 ,0L
83 ,0L
84 ,0L
85 ,NULLHANDLE
86 ,HWND_TOP
87 ,0L
88 ,NULL
89 ,NULL
90 )) == 0)
91 {
92 wxLogLastError(wxT("WinLoadMenu"));
93 }
94 m_vMenuData.iPosition = 0;
95 m_vMenuData.afStyle = MIS_SUBMENU | MIS_TEXT;
96 m_vMenuData.afAttribute = (USHORT)0;
97 m_vMenuData.id = m_nextMenuId++;
98 m_vMenuData.hwndSubMenu = m_hMenu;
99 m_vMenuData.hItem = NULLHANDLE;
100
101 //
102 // If we have a title, insert it in the beginning of the menu
103 //
104 if (!m_title.empty())
105 {
106 Append( idMenuTitle
107 ,m_title
108 ,wxEmptyString
109 ,wxITEM_NORMAL
110 );
111 AppendSeparator();
112 }
113 } // end of wxMenu::Init
114
115 //
116 // The wxWindow destructor will take care of deleting the submenus.
117 //
118 wxMenu::~wxMenu()
119 {
120 //
121 // We should free PM resources only if PM doesn't do it for us
122 // which happens if we're attached to a menubar or a submenu of another
123 // menu
124 if (!IsAttached() && !GetParent())
125 {
126 if (!::WinDestroyWindow((HWND)GetHmenu()) )
127 {
128 wxLogLastError(wxT("WinDestroyWindow"));
129 }
130 }
131
132 #if wxUSE_ACCEL
133 //
134 // Delete accels
135 //
136 WX_CLEAR_ARRAY(m_vAccels);
137 #endif // wxUSE_ACCEL
138 } // end of wxMenu::~wxMenu
139
140 void wxMenu::Break()
141 {
142 // this will take effect during the next call to Append()
143 m_bDoBreak = true;
144 } // end of wxMenu::Break
145
146 void wxMenu::Attach(
147 wxMenuBarBase* pMenubar
148 )
149 {
150 wxMenuBase::Attach(pMenubar);
151 EndRadioGroup();
152 } // end of wxMenu::Break;
153
154 #if wxUSE_ACCEL
155
156 int wxMenu::FindAccel(
157 int nId
158 ) const
159 {
160 size_t n;
161 size_t nCount = m_vAccels.GetCount();
162
163 for (n = 0; n < nCount; n++)
164 if (m_vAccels[n]->m_command == nId)
165 return n;
166 return wxNOT_FOUND;
167 } // end of wxMenu::FindAccel
168
169 void wxMenu::UpdateAccel(
170 wxMenuItem* pItem
171 )
172 {
173 if (pItem->IsSubMenu())
174 {
175 wxMenu* pSubmenu = pItem->GetSubMenu();
176 wxMenuItemList::compatibility_iterator node = pSubmenu->GetMenuItems().GetFirst();
177
178 while (node)
179 {
180 UpdateAccel(node->GetData());
181 node = node->GetNext();
182 }
183 }
184 else if (!pItem->IsSeparator())
185 {
186 //
187 // Recurse upwards: we should only modify m_accels of the top level
188 // menus, not of the submenus as wxMenuBar doesn't look at them
189 // (alternative and arguable cleaner solution would be to recurse
190 // downwards in GetAccelCount() and CopyAccels())
191 //
192 if (GetParent())
193 {
194 GetParent()->UpdateAccel(pItem);
195 return;
196 }
197
198 //
199 // Find the (new) accel for this item
200 //
201 wxAcceleratorEntry* pAccel = wxAcceleratorEntry::Create(pItem->GetItemLabel());
202
203 if (pAccel)
204 pAccel->m_command = pItem->GetId();
205
206 //
207 // Find the old one
208 //
209 size_t n = FindAccel(pItem->GetId());
210
211 if (n == (size_t)wxNOT_FOUND)
212 {
213 //
214 // No old, add new if any
215 //
216 if (pAccel)
217 m_vAccels.Add(pAccel);
218 else
219 return;
220 }
221 else
222 {
223 //
224 // Replace old with new or just remove the old one if no new
225 //
226 delete m_vAccels[n];
227 if (pAccel)
228 m_vAccels[n] = pAccel;
229 else
230 m_vAccels.RemoveAt(n);
231 }
232
233 if (IsAttached())
234 {
235 GetMenuBar()->RebuildAccelTable();
236 }
237 }
238 } // wxMenu::UpdateAccel
239
240 #endif // wxUSE_ACCEL
241
242 //
243 // Append a new item or submenu to the menu
244 //
245 bool wxMenu::DoInsertOrAppend( wxMenuItem* pItem,
246 size_t nPos )
247 {
248 wxMenu* pSubmenu = pItem->GetSubMenu();
249 MENUITEM& rItem = (pSubmenu != NULL)?pSubmenu->m_vMenuData:
250 pItem->m_vMenuData;
251
252 ERRORID vError;
253 wxString sError;
254
255 #if wxUSE_ACCEL
256 UpdateAccel(pItem);
257 #endif // wxUSE_ACCEL
258
259 //
260 // If "Break" has just been called, insert a menu break before this item
261 // (and don't forget to reset the flag)
262 //
263 if (m_bDoBreak)
264 {
265 rItem.afStyle |= MIS_BREAK;
266 m_bDoBreak = false;
267 }
268
269 //
270 // Id is the numeric id for normal menu items and HMENU for submenus as
271 // required by ::MM_INSERTITEM message API
272 //
273 if (pSubmenu != NULL)
274 {
275 wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
276 pSubmenu->SetParent(this);
277
278 rItem.iPosition = 0; // submenus have a 0 position
279 rItem.id = (USHORT)pSubmenu->GetHMenu();
280 rItem.afStyle |= MIS_SUBMENU | MIS_TEXT;
281 }
282 else
283 {
284 rItem.id = (USHORT)pItem->GetId();
285 }
286
287 char *pData = NULL;
288
289 #if wxUSE_OWNER_DRAWN
290 if (pItem->IsOwnerDrawn())
291 {
292 //
293 // Want to get {Measure|Draw}Item messages?
294 // item draws itself, passing pointer to data doesn't work in OS/2
295 // Will eventually need to set the image handle somewhere into vItem.hItem
296 //
297 rItem.afStyle |= MIS_OWNERDRAW;
298 pData = NULL;
299 rItem.hItem = (HBITMAP)pItem->GetBitmap().GetHBITMAP();
300 pItem->m_vMenuData.afStyle = rItem.afStyle;
301 pItem->m_vMenuData.hItem = rItem.hItem;
302 }
303 else
304 #endif
305 if (pItem->IsSeparator())
306 {
307 rItem.afStyle = MIS_SEPARATOR;
308 }
309 else
310 {
311 if (pItem->GetId() == idMenuTitle)
312 {
313 // Item is an unselectable title to be passed via pData
314 rItem.afStyle = MIS_STATIC;
315 }
316 else
317 {
318 //
319 // Menu is just a normal string (passed in data parameter)
320 //
321 rItem.afStyle |= MIS_TEXT;
322 }
323 pData = (char*) pItem->GetItemLabel().wx_str();
324 }
325
326 if (nPos == (size_t)-1)
327 {
328 rItem.iPosition = MIT_END;
329 }
330 else
331 {
332 rItem.iPosition = (SHORT)nPos;
333 }
334
335 APIRET rc;
336
337 rc = (APIRET)::WinSendMsg( GetHmenu()
338 ,MM_INSERTITEM
339 ,(MPARAM)&rItem
340 ,(MPARAM)pData
341 );
342 #if wxUSE_OWNER_DRAWN
343 if (pItem->IsOwnerDrawn())
344 {
345 MENUITEM vMenuItem;
346
347 ::WinSendMsg( GetHmenu()
348 ,MM_QUERYITEM
349 ,MPFROM2SHORT( (USHORT)pItem->GetId()
350 ,(USHORT)(FALSE)
351 )
352 ,&vMenuItem
353 );
354 }
355 #endif
356
357 if (rc == (APIRET)MIT_MEMERROR || rc == (APIRET)MIT_ERROR)
358 {
359 vError = ::WinGetLastError(vHabmain);
360 sError = wxPMErrorToStr(vError);
361 wxLogError(wxT("Error inserting or appending a menuitem. Error: %s\n"), sError.c_str());
362 wxLogLastError(wxT("Insert or AppendMenu"));
363 return false;
364 }
365
366 //
367 // If we're already attached to the menubar, we must update it
368 //
369 if (IsAttached() && GetMenuBar()->IsAttached())
370 {
371 GetMenuBar()->Refresh();
372 }
373
374 return true;
375 } // end of wxMenu::DoInsertOrAppend
376
377 void wxMenu::EndRadioGroup()
378 {
379 //
380 // We're not inside a radio group any longer
381 //
382 m_nStartRadioGroup = -1;
383 } // end of wxMenu::EndRadioGroup
384
385 wxMenuItem* wxMenu::DoAppend( wxMenuItem* pItem )
386 {
387 wxCHECK_MSG( pItem, NULL, wxT("NULL item in wxMenu::DoAppend") );
388
389 bool bCheck = false;
390
391 if (pItem->GetKind() == wxITEM_RADIO)
392 {
393 int nCount = GetMenuItemCount();
394
395 if (m_nStartRadioGroup == -1)
396 {
397 //
398 // Start a new radio group
399 //
400 m_nStartRadioGroup = nCount;
401
402 //
403 // For now it has just one element
404 //
405 pItem->SetAsRadioGroupStart();
406 pItem->SetRadioGroupEnd(m_nStartRadioGroup);
407
408 //
409 // Ensure that we have a checked item in the radio group
410 //
411 bCheck = true;
412 }
413 else // extend the current radio group
414 {
415 //
416 // We need to update its end item
417 //
418 pItem->SetRadioGroupStart(m_nStartRadioGroup);
419
420 wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_nStartRadioGroup);
421
422 if (node)
423 {
424 node->GetData()->SetRadioGroupEnd(nCount);
425 }
426 else
427 {
428 wxFAIL_MSG( wxT("where is the radio group start item?") );
429 }
430 }
431 }
432 else // not a radio item
433 {
434 EndRadioGroup();
435 }
436
437 if (!wxMenuBase::DoAppend(pItem) || !DoInsertOrAppend(pItem))
438 {
439 return NULL;
440 }
441 if (bCheck)
442 {
443 //
444 // Check the item initially
445 //
446 pItem->Check(true);
447 }
448 return pItem;
449 } // end of wxMenu::DoAppend
450
451 wxMenuItem* wxMenu::DoInsert(
452 size_t nPos
453 , wxMenuItem* pItem
454 )
455 {
456 if ( wxMenuBase::DoInsert( nPos
457 ,pItem) &&
458 DoInsertOrAppend( pItem
459 ,nPos
460 ))
461 return pItem;
462 else
463 return NULL;
464 } // end of wxMenu::DoInsert
465
466 wxMenuItem* wxMenu::DoRemove(
467 wxMenuItem* pItem
468 )
469 {
470 //
471 // We need to find the items position in the child list
472 //
473 size_t nPos;
474 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
475
476 for (nPos = 0; node; nPos++)
477 {
478 if (node->GetData() == pItem)
479 break;
480 node = node->GetNext();
481 }
482
483 //
484 // DoRemove() (unlike Remove) can only be called for existing item!
485 //
486 wxCHECK_MSG(node, NULL, wxT("bug in wxMenu::Remove logic"));
487
488 #if wxUSE_ACCEL
489 //
490 // Remove the corresponding accel from the accel table
491 //
492 int n = FindAccel(pItem->GetId());
493
494 if (n != wxNOT_FOUND)
495 {
496 delete m_vAccels[n];
497 m_vAccels.RemoveAt(n);
498 }
499
500 #endif // wxUSE_ACCEL
501 //
502 // Remove the item from the menu
503 //
504 ::WinSendMsg( GetHmenu()
505 ,MM_REMOVEITEM
506 ,MPFROM2SHORT(pItem->GetId(), TRUE)
507 ,(MPARAM)0
508 );
509 if (IsAttached() && GetMenuBar()->IsAttached())
510 {
511 //
512 // Otherwise, the chane won't be visible
513 //
514 GetMenuBar()->Refresh();
515 }
516
517 //
518 // And from internal data structures
519 //
520 return wxMenuBase::DoRemove(pItem);
521 } // end of wxMenu::DoRemove
522
523 // ---------------------------------------------------------------------------
524 // accelerator helpers
525 // ---------------------------------------------------------------------------
526
527 #if wxUSE_ACCEL
528
529 //
530 // Create the wxAcceleratorEntries for our accels and put them into provided
531 // array - return the number of accels we have
532 //
533 size_t wxMenu::CopyAccels(
534 wxAcceleratorEntry* pAccels
535 ) const
536 {
537 size_t nCount = GetAccelCount();
538
539 for (size_t n = 0; n < nCount; n++)
540 {
541 *pAccels++ = *m_vAccels[n];
542 }
543 return nCount;
544 } // end of wxMenu::CopyAccels
545
546 #endif // wxUSE_ACCEL
547
548 // ---------------------------------------------------------------------------
549 // set wxMenu title
550 // ---------------------------------------------------------------------------
551
552 void wxMenu::SetTitle( const wxString& rLabel )
553 {
554 bool bHasNoTitle = m_title.empty();
555 HWND hMenu = GetHmenu();
556
557 m_title = rLabel;
558 if (bHasNoTitle)
559 {
560 if (!rLabel.empty())
561 {
562 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
563 {
564 wxLogLastError(wxT("SetMenuTitle"));
565 }
566 }
567 }
568 else
569 {
570 if (rLabel.empty() )
571 {
572 ::WinSendMsg( GetHmenu()
573 ,MM_REMOVEITEM
574 ,MPFROM2SHORT(hMenu, TRUE)
575 ,(MPARAM)0
576 );
577 }
578 else
579 {
580 //
581 // Modify the title
582 //
583 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
584 {
585 wxLogLastError(wxT("SetMenuTitle"));
586 }
587 }
588 }
589 } // end of wxMenu::SetTitle
590
591 // ---------------------------------------------------------------------------
592 // event processing
593 // ---------------------------------------------------------------------------
594
595 bool wxMenu::OS2Command( WXUINT WXUNUSED(uParam),
596 WXWORD vId )
597 {
598 //
599 // Ignore commands from the menu title
600 //
601
602 if (vId != (WXWORD)idMenuTitle)
603 {
604 SendEvent( vId
605 ,(int)::WinSendMsg( GetHmenu()
606 ,MM_QUERYITEMATTR
607 ,MPFROMSHORT(vId)
608 ,(MPARAM)MIA_CHECKED
609 )
610 );
611 }
612 return true;
613 } // end of wxMenu::OS2Command
614
615 // ---------------------------------------------------------------------------
616 // other
617 // ---------------------------------------------------------------------------
618
619 wxWindow* wxMenu::GetWindow() const
620 {
621 if (m_invokingWindow != NULL)
622 return m_invokingWindow;
623 else if ( GetMenuBar() != NULL)
624 return GetMenuBar()->GetFrame();
625
626 return NULL;
627 } // end of wxMenu::GetWindow
628
629 // recursive search for item by id
630 wxMenuItem* wxMenu::FindItem(
631 int nItemId
632 , ULONG hItem
633 , wxMenu** ppItemMenu
634 ) const
635 {
636 if ( ppItemMenu )
637 *ppItemMenu = NULL;
638
639 wxMenuItem* pItem = NULL;
640
641 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
642 node && !pItem;
643 node = node->GetNext() )
644 {
645 pItem = node->GetData();
646
647 if ( pItem->GetId() == nItemId && pItem->m_vMenuData.hItem == hItem)
648 {
649 if ( ppItemMenu )
650 *ppItemMenu = (wxMenu *)this;
651 }
652 else if ( pItem->IsSubMenu() )
653 {
654 pItem = pItem->GetSubMenu()->FindItem( nItemId
655 ,hItem
656 ,ppItemMenu
657 );
658 if (pItem)
659 break;
660 }
661 else
662 {
663 // don't exit the loop
664 pItem = NULL;
665 }
666 }
667 return pItem;
668 } // end of wxMenu::FindItem
669
670 // ---------------------------------------------------------------------------
671 // Menu Bar
672 // ---------------------------------------------------------------------------
673
674 void wxMenuBar::Init()
675 {
676 m_eventHandler = this;
677 m_menuBarFrame = NULL;
678 m_hMenu = 0;
679 } // end of wxMenuBar::Init
680
681 wxMenuBar::wxMenuBar()
682 {
683 Init();
684 } // end of wxMenuBar::wxMenuBar
685
686 wxMenuBar::wxMenuBar(
687 long WXUNUSED(lStyle)
688 )
689 {
690 Init();
691 } // end of wxMenuBar::wxMenuBar
692
693 wxMenuBar::wxMenuBar(
694 int nCount
695 , wxMenu* vMenus[]
696 , const wxString sTitles[]
697 , long WXUNUSED(lStyle)
698 )
699 {
700 Init();
701
702 m_titles.Alloc(nCount);
703 for ( int i = 0; i < nCount; i++ )
704 {
705 m_menus.Append(vMenus[i]);
706 m_titles.Add(sTitles[i]);
707 vMenus[i]->Attach(this);
708 }
709 } // end of wxMenuBar::wxMenuBar
710
711 wxMenuBar::~wxMenuBar()
712 {
713 //
714 // We should free PM's resources only if PM doesn't do it for us
715 // which happens if we're attached to a frame
716 //
717 if (m_hMenu && !IsAttached())
718 {
719 ::WinDestroyWindow((HMENU)m_hMenu);
720 m_hMenu = (WXHMENU)NULL;
721 }
722 } // end of wxMenuBar::~wxMenuBar
723
724 // ---------------------------------------------------------------------------
725 // wxMenuBar helpers
726 // ---------------------------------------------------------------------------
727
728 void wxMenuBar::Refresh()
729 {
730 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
731
732 WinSendMsg(GetWinHwnd(m_menuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
733 } // end of wxMenuBar::Refresh
734
735 WXHMENU wxMenuBar::Create()
736 {
737 HWND hFrame;
738
739 if (m_hMenu != 0 )
740 return m_hMenu;
741
742 wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
743
744 //
745 // Menubars should be associated with a frame otherwise they are popups
746 //
747 if (m_menuBarFrame != NULL)
748 hFrame = GetWinHwnd(m_menuBarFrame);
749 else
750 hFrame = HWND_DESKTOP;
751 //
752 // Create an empty menu and then fill it with insertions
753 //
754 if ((m_hMenu = ::WinCreateWindow( hFrame
755 ,WC_MENU
756 ,NULL
757 ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
758 ,0L
759 ,0L
760 ,0L
761 ,0L
762 ,hFrame
763 ,HWND_TOP
764 ,FID_MENU
765 ,NULL
766 ,NULL
767 )) == 0)
768 {
769 wxLogLastError(wxT("WinLoadMenu"));
770 }
771 else
772 {
773 size_t nCount = GetMenuCount(), i;
774 wxMenuList::iterator it;
775 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
776 {
777 APIRET rc;
778 ERRORID vError;
779 wxString sError;
780 HWND hSubMenu;
781
782 //
783 // Set the parent and owner of the submenues to be the menubar, not the desktop
784 //
785 hSubMenu = (*it)->m_vMenuData.hwndSubMenu;
786 if (!::WinSetParent((*it)->m_vMenuData.hwndSubMenu, m_hMenu, FALSE))
787 {
788 vError = ::WinGetLastError(vHabmain);
789 sError = wxPMErrorToStr(vError);
790 wxLogError(wxT("Error setting parent for submenu. Error: %s\n"), sError.c_str());
791 return NULLHANDLE;
792 }
793
794 if (!::WinSetOwner((*it)->m_vMenuData.hwndSubMenu, m_hMenu))
795 {
796 vError = ::WinGetLastError(vHabmain);
797 sError = wxPMErrorToStr(vError);
798 wxLogError(wxT("Error setting parent for submenu. Error: %s\n"), sError.c_str());
799 return NULLHANDLE;
800 }
801
802 (*it)->m_vMenuData.iPosition = (SHORT)i;
803
804 rc = (APIRET)::WinSendMsg(m_hMenu, MM_INSERTITEM, (MPARAM)&(*it)->m_vMenuData, (MPARAM)m_titles[i].wx_str());
805 if (rc == (APIRET)MIT_MEMERROR || rc == (APIRET)MIT_ERROR)
806 {
807 vError = ::WinGetLastError(vHabmain);
808 sError = wxPMErrorToStr(vError);
809 wxLogError(wxT("Error inserting or appending a menuitem. Error: %s\n"), sError.c_str());
810 return NULLHANDLE;
811 }
812 }
813 }
814 return m_hMenu;
815 } // end of wxMenuBar::Create
816
817 // ---------------------------------------------------------------------------
818 // wxMenuBar functions to work with the top level submenus
819 // ---------------------------------------------------------------------------
820
821 //
822 // NB: we don't support owner drawn top level items for now, if we do these
823 // functions would have to be changed to use wxMenuItem as well
824 //
825 void wxMenuBar::EnableTop(
826 size_t nPos
827 , bool bEnable
828 )
829 {
830 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
831 USHORT uFlag = 0;
832 SHORT nId;
833
834 if(!bEnable)
835 uFlag = MIA_DISABLED;
836
837 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
838 if (nId == MIT_ERROR)
839 {
840 wxLogLastError(wxT("LogLastError"));
841 return;
842 }
843 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(MIA_DISABLED, uFlag));
844 Refresh();
845 } // end of wxMenuBar::EnableTop
846
847 void wxMenuBar::SetMenuLabel(
848 size_t nPos
849 , const wxString& rLabel
850 )
851 {
852 SHORT nId;
853 MENUITEM vItem;
854
855 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
856 m_titles[nPos] = rLabel;
857
858 if (!IsAttached())
859 {
860 return;
861 }
862
863 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
864 if (nId == MIT_ERROR)
865 {
866 wxLogLastError(wxT("LogLastError"));
867 return;
868 }
869 if(!::WinSendMsg( (HWND)m_hMenu
870 ,MM_QUERYITEM
871 ,MPFROM2SHORT(nId, TRUE)
872 ,MPARAM(&vItem)
873 ))
874 {
875 wxLogLastError(wxT("QueryItem"));
876 }
877 nId = vItem.id;
878
879 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.wx_str()));
880 {
881 wxLogLastError(wxT("ModifyMenu"));
882 }
883 Refresh();
884 } // end of wxMenuBar::SetMenuLabel
885
886 wxString wxMenuBar::GetMenuLabel(
887 size_t nPos
888 ) const
889 {
890 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
891 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
892 return m_titles[nPos];
893 } // end of wxMenuBar::GetMenuLabel
894
895 // ---------------------------------------------------------------------------
896 // wxMenuBar construction
897 // ---------------------------------------------------------------------------
898
899 wxMenu* wxMenuBar::Replace(
900 size_t nPos
901 , wxMenu* pMenu
902 , const wxString& rTitle
903 )
904 {
905 SHORT nId;
906 wxString sTitle = wxPMTextToLabel(rTitle);
907 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
908 ,pMenu
909 ,sTitle
910 );
911
912
913 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
914 if (nId == MIT_ERROR)
915 {
916 wxLogLastError(wxT("LogLastError"));
917 return NULL;
918 }
919 if (!pMenuOld)
920 return NULL;
921 m_titles[nPos] = sTitle;
922 if (IsAttached())
923 {
924 ::WinSendMsg((HWND)m_hMenu, MM_REMOVEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
925 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.wx_str());
926
927 #if wxUSE_ACCEL
928 if (pMenuOld->HasAccels() || pMenu->HasAccels())
929 {
930 //
931 // Need to rebuild accell table
932 //
933 RebuildAccelTable();
934 }
935 #endif // wxUSE_ACCEL
936 Refresh();
937 }
938 return pMenuOld;
939 } // end of wxMenuBar::Replace
940
941 bool wxMenuBar::Insert( size_t nPos,
942 wxMenu* pMenu,
943 const wxString& rTitle )
944 {
945 wxString sTitle = wxPMTextToLabel(rTitle);
946
947 if (!wxMenuBarBase::Insert( nPos, pMenu, sTitle ))
948 return false;
949
950 m_titles.Insert( sTitle, nPos );
951
952 if (IsAttached())
953 {
954 pMenu->m_vMenuData.iPosition = (SHORT)nPos;
955 ::WinSendMsg( (HWND)m_hMenu
956 ,MM_INSERTITEM
957 ,(MPARAM)&pMenu->m_vMenuData
958 ,(MPARAM)sTitle.wx_str()
959 );
960 #if wxUSE_ACCEL
961 if (pMenu->HasAccels())
962 {
963 // need to rebuild accell table
964 RebuildAccelTable();
965 }
966 #endif // wxUSE_ACCEL
967 Refresh();
968 }
969
970 return true;
971 } // end of wxMenuBar::Insert
972
973 bool wxMenuBar::Append( wxMenu* pMenu,
974 const wxString& rsTitle )
975 {
976 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
977
978 wxCHECK_MSG(hSubmenu, false, wxT("can't append invalid menu to menubar"));
979
980 wxString sTitle = wxPMTextToLabel(rsTitle);
981
982 if (!wxMenuBarBase::Append(pMenu, sTitle))
983 return false;
984
985 m_titles.Add(sTitle);
986
987 if ( IsAttached() )
988 {
989 pMenu->m_vMenuData.iPosition = MIT_END;
990 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.wx_str());
991 #if wxUSE_ACCEL
992 if (pMenu->HasAccels())
993 {
994 //
995 // Need to rebuild accell table
996 //
997 RebuildAccelTable();
998 }
999 #endif // wxUSE_ACCEL
1000 Refresh();
1001 }
1002 return true;
1003 } // end of wxMenuBar::Append
1004
1005 wxMenu* wxMenuBar::Remove(
1006 size_t nPos
1007 )
1008 {
1009 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
1010 SHORT nId;
1011
1012 if (!pMenu)
1013 return NULL;
1014
1015 nId = SHORT1FROMMR(::WinSendMsg( (HWND)GetHmenu()
1016 ,MM_ITEMIDFROMPOSITION
1017 ,MPFROMSHORT(nPos)
1018 ,(MPARAM)0)
1019 );
1020 if (nId == MIT_ERROR)
1021 {
1022 wxLogLastError(wxT("LogLastError"));
1023 return NULL;
1024 }
1025 if (IsAttached())
1026 {
1027 ::WinSendMsg( (HWND)GetHmenu()
1028 ,MM_REMOVEITEM
1029 ,MPFROM2SHORT(nId, TRUE)
1030 ,(MPARAM)0
1031 );
1032
1033 #if wxUSE_ACCEL
1034 if (pMenu->HasAccels())
1035 {
1036 //
1037 // Need to rebuild accell table
1038 //
1039 RebuildAccelTable();
1040 }
1041 #endif // wxUSE_ACCEL
1042 Refresh();
1043 }
1044 m_titles.RemoveAt(nPos);
1045 return pMenu;
1046 } // end of wxMenuBar::Remove
1047
1048 #if wxUSE_ACCEL
1049
1050 void wxMenuBar::RebuildAccelTable()
1051 {
1052 //
1053 // Merge the accelerators of all menus into one accel table
1054 //
1055 size_t nAccelCount = 0;
1056 size_t i;
1057 size_t nCount = GetMenuCount();
1058 wxMenuList::iterator it;
1059 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
1060 {
1061 nAccelCount += (*it)->GetAccelCount();
1062 }
1063
1064 if (nAccelCount)
1065 {
1066 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
1067
1068 nAccelCount = 0;
1069 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
1070 {
1071 nAccelCount += (*it)->CopyAccels(&pAccelEntries[nAccelCount]);
1072 }
1073 m_vAccelTable = wxAcceleratorTable( nAccelCount
1074 ,pAccelEntries
1075 );
1076 delete [] pAccelEntries;
1077 }
1078 } // end of wxMenuBar::RebuildAccelTable
1079
1080 #endif // wxUSE_ACCEL
1081
1082 void wxMenuBar::Attach(
1083 wxFrame* pFrame
1084 )
1085 {
1086 wxMenuBarBase::Attach(pFrame);
1087
1088 #if wxUSE_ACCEL
1089 RebuildAccelTable();
1090 //
1091 // Ensure the accelerator table is set to the frame (not the client!)
1092 //
1093 if (!::WinSetAccelTable( vHabmain
1094 ,m_vAccelTable.GetHACCEL()
1095 ,(HWND)pFrame->GetFrame()
1096 ))
1097 {
1098 wxLogLastError(wxT("WinSetAccelTable"));
1099 }
1100 #endif // wxUSE_ACCEL
1101 } // end of wxMenuBar::Attach
1102
1103 void wxMenuBar::Detach()
1104 {
1105 ::WinDestroyWindow((HWND)m_hMenu);
1106 m_hMenu = (WXHMENU)NULL;
1107 m_menuBarFrame = NULL;
1108 } // end of wxMenuBar::Detach
1109
1110 // ---------------------------------------------------------------------------
1111 // wxMenuBar searching for menu items
1112 // ---------------------------------------------------------------------------
1113
1114 //
1115 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
1116 //
1117 int wxMenuBar::FindMenuItem(
1118 const wxString& rMenuString
1119 , const wxString& rItemString
1120 ) const
1121 {
1122 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
1123 size_t nCount = GetMenuCount(), i;
1124 wxMenuList::const_iterator it;
1125 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
1126 {
1127 wxString sTitle = wxStripMenuCodes(m_titles[i]);
1128
1129 if (rMenuString == sTitle)
1130 return (*it)->FindItem(rItemString);
1131 }
1132 return wxNOT_FOUND;
1133 } // end of wxMenuBar::FindMenuItem
1134
1135 wxMenuItem* wxMenuBar::FindItem(
1136 int nId
1137 , wxMenu** ppItemMenu
1138 ) const
1139 {
1140 if (ppItemMenu)
1141 *ppItemMenu = NULL;
1142
1143 wxMenuItem* pItem = NULL;
1144 size_t nCount = GetMenuCount(), i;
1145 wxMenuList::const_iterator it;
1146 for (i = 0, it = m_menus.begin(); !pItem && (i < nCount); i++, it++)
1147 {
1148 pItem = (*it)->FindItem( nId
1149 ,ppItemMenu
1150 );
1151 }
1152 return pItem;
1153 } // end of wxMenuBar::FindItem
1154
1155 wxMenuItem* wxMenuBar::FindItem(
1156 int nId
1157 , ULONG hItem
1158 , wxMenu** ppItemMenu
1159 ) const
1160 {
1161 if (ppItemMenu)
1162 *ppItemMenu = NULL;
1163
1164 wxMenuItem* pItem = NULL;
1165 size_t nCount = GetMenuCount(), i;
1166 wxMenuList::const_iterator it;
1167 for (i = 0, it = m_menus.begin(); !pItem && (i < nCount); i++, it++)
1168 {
1169 pItem = (*it)->FindItem( nId
1170 ,hItem
1171 ,ppItemMenu
1172 );
1173 }
1174 return pItem;
1175 } // end of wxMenuBar::FindItem