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