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