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