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