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