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