more minimal stuff
[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/frame.h"
21 #include "wx/menu.h"
22 #include "wx/utils.h"
23 #include "wx/intl.h"
24 #include "wx/log.h"
25 #endif
26
27 #if wxUSE_OWNER_DRAWN
28 #include "wx/ownerdrw.h"
29 #endif
30
31 #include "wx/os2/private.h"
32
33 // other standard headers
34 #include <string.h>
35
36 // ----------------------------------------------------------------------------
37 // global variables
38 // ----------------------------------------------------------------------------
39
40 extern wxMenu* wxCurrentPopupMenu;
41
42 // ----------------------------------------------------------------------------
43 // constants
44 // ----------------------------------------------------------------------------
45
46 //
47 // The (popup) menu title has this special id
48 //
49 static const int idMenuTitle = -2;
50
51 // ----------------------------------------------------------------------------
52 // macros
53 // ----------------------------------------------------------------------------
54
55 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
56 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
57
58 // ============================================================================
59 // implementation
60 // ============================================================================
61
62 // ---------------------------------------------------------------------------
63 // wxMenu construction, adding and removing menu items
64 // ---------------------------------------------------------------------------
65
66 //
67 // Construct a menu with optional title (then use append)
68 //
69 void wxMenu::Init()
70 {
71 m_bDoBreak = FALSE;
72
73 //
74 // Create the menu (to be used as a submenu or a popup)
75 //
76 if ((m_hMenu = ::WinCreateWindow( HWND_DESKTOP
77 ,(const wxChar*)WC_MENU
78 ,"Menu"
79 ,0L
80 ,0L
81 ,0L
82 ,0L
83 ,0L
84 ,NULLHANDLE
85 ,HWND_TOP
86 ,0L
87 ,NULL
88 ,NULL
89 )) != 0)
90 {
91 wxLogLastError("WinLoadMenu");
92 }
93
94 //
95 // If we have a title, insert it in the beginning of the menu
96 //
97 if (!m_title.IsEmpty())
98 {
99 Append( idMenuTitle
100 ,m_title
101 );
102 AppendSeparator();
103 }
104 } // end of wxMenu::Init
105
106 //
107 // The wxWindow destructor will take care of deleting the submenus.
108 //
109 wxMenu::~wxMenu()
110 {
111 //
112 // We should free PM resources only if PM doesn't do it for us
113 // which happens if we're attached to a menubar or a submenu of another
114 // menu
115 if (!IsAttached() && !GetParent())
116 {
117 if (!::WinDestroyWindow((HWND)GetHmenu()) )
118 {
119 wxLogLastError("WinDestroyWindow");
120 }
121 }
122
123 #if wxUSE_ACCEL
124 //
125 // Delete accels
126 //
127 WX_CLEAR_ARRAY(m_vAccels);
128 #endif // wxUSE_ACCEL
129 } // end of wxMenu::~wxMenu
130
131 void wxMenu::Break()
132 {
133 // this will take effect during the next call to Append()
134 m_bDoBreak = TRUE;
135 } // end of wxMenu::Break
136
137 #if wxUSE_ACCEL
138
139 int wxMenu::FindAccel(
140 int nId
141 ) const
142 {
143 size_t n;
144 size_t nCount = m_vAccels.GetCount();
145
146 for (n = 0; n < nCount; n++)
147 {
148 if (m_vAccels[n]->m_command == nId)
149 return n;
150 }
151 return wxNOT_FOUND;
152 } // end of wxMenu::FindAccel
153
154 void wxMenu::UpdateAccel(
155 wxMenuItem* pItem
156 )
157 {
158 //
159 // Find the (new) accel for this item
160 //
161 wxAcceleratorEntry* pAccel = wxGetAccelFromString(pItem->GetText());
162
163 if (pAccel)
164 pAccel->m_command = pItem->GetId();
165
166 //
167 // Find the old one
168 //
169 int n = FindAccel(pItem->GetId());
170
171 if (n == wxNOT_FOUND)
172 {
173 //
174 // No old, add new if any
175 //
176 if (pAccel)
177 m_vAccels.Add(pAccel);
178 else
179 return; // skipping RebuildAccelTable() below
180 }
181 else
182 {
183 //
184 // Replace old with new or just remove the old one if no new
185 //
186 delete m_vAccels[n];
187
188 if (pAccel)
189 m_vAccels[n] = pAccel;
190 else
191 m_vAccels.Remove(n);
192 }
193
194 if (IsAttached())
195 {
196 m_menuBar->RebuildAccelTable();
197 }
198 } // wxMenu::UpdateAccel
199
200 #endif // wxUSE_ACCEL
201
202 //
203 // Append a new item or submenu to the menu
204 //
205 bool wxMenu::DoInsertOrAppend(
206 wxMenuItem* pItem
207 , size_t nPos
208 )
209 {
210 #if wxUSE_ACCEL
211 UpdateAccel(pItem);
212 #endif // wxUSE_ACCEL
213
214 //
215 // If "Break" has just been called, insert a menu break before this item
216 // (and don't forget to reset the flag)
217 //
218 if (m_bDoBreak)
219 {
220 m_vMenuData.afStyle |= MIS_BREAK;
221 m_bDoBreak = FALSE;
222 }
223
224 if (pItem->IsSeparator())
225 {
226 m_vMenuData.afStyle |= MIS_SEPARATOR;
227 }
228
229 //
230 // Id is the numeric id for normal menu items and HMENU for submenus as
231 // required by ::WinInsertMenu() API
232 //
233
234 wxMenu* pSubmenu = pItem->GetSubMenu();
235
236 if (pSubmenu != NULL)
237 {
238 wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
239 pSubmenu->SetParent(this);
240
241 m_vMenuData.iPosition = 0; // submenus have a 0 position
242 m_vMenuData.id = (USHORT)pSubmenu->GetHMenu();
243 m_vMenuData.afStyle |= MIS_SUBMENU;
244 }
245 else
246 {
247 m_vMenuData.id = pItem->GetId();
248 }
249
250 BYTE* pData;
251
252 #if wxUSE_OWNER_DRAWN
253 if (pItem->IsOwnerDrawn())
254 {
255 //
256 // Want to get {Measure|Draw}Item messages?
257 // item draws itself, pass pointer to it in data parameter
258 // Will eventually need to set the image handle somewhere into m_vMenuData.hItem
259 //
260 m_vMenuData.afStyle |= MIS_OWNERDRAW;
261 pData = (BYTE*)pItem;
262 }
263 else
264 #endif
265 {
266 //
267 // Menu is just a normal string (passed in data parameter)
268 //
269 m_vMenuData.afStyle |= MIS_TEXT;
270 pData = (char*)pItem->GetText().c_str();
271 }
272
273 BOOL bOk;
274
275 //
276 // -1 means this is a sub menu not a menuitem. We must create a window for it.
277 // Submenus are also attached to a menubar so its parent and owner should be the handle of the menubar.
278 //
279 if (nPos == (size_t)-1)
280 {
281 HWND hSubMenu = ::WinCreateWindow( GetWinHwnd(m_menuBar) // parent
282 ,WC_MENU // type
283 ,"Menu" // a generic name
284 ,0L // no style flag
285 ,0L,0L,0L,0L // no position
286 ,GetWinHwnd(m_menuBar) // no owner
287 ,HWND_TOP // always on top
288 ,0L // no ID needed for dynamic creation
289 ,NULL // no control data
290 ,NULL // no presentation params
291 );
292
293 m_vMenuData.iPosition = 0;
294 m_vMenuData.hwndSubMenu = hSubMenu;
295 m_vMenuData.hItem = NULLHANDLE;
296
297 bOk = (bool)::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&m_vMenuData, (MPARAM)pItem->GetText().c_str());
298 }
299 else
300 {
301 m_vMenuData.iPosition = nPos;
302 m_vMenuData.hwndSubMenu = NULLHANDLE;
303 m_vMenuData.hItem = NULLHANDLE;
304 bOk = (bool)::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&m_vMenuData, (MPARAM)pItem->GetText().c_str());
305 }
306
307 if (!bOk)
308 {
309 wxLogLastError("Insert or AppendMenu");
310 return FALSE;
311 }
312 else
313 {
314 //
315 // If we're already attached to the menubar, we must update it
316 //
317 if (IsAttached())
318 {
319 m_menuBar->Refresh();
320 }
321 return TRUE;
322 }
323 return FALSE;
324 } // end of wxMenu::DoInsertOrAppend
325
326 bool wxMenu::DoAppend(
327 wxMenuItem* pItem
328 )
329 {
330 return wxMenuBase::DoAppend(pItem) && DoInsertOrAppend(pItem);
331 }
332
333 bool wxMenu::DoInsert(
334 size_t nPos
335 , wxMenuItem* pItem
336 )
337 {
338 return ( wxMenuBase::DoInsert( nPos
339 ,pItem) &&
340 DoInsertOrAppend( pItem
341 ,nPos
342 ));
343 } // end of wxMenu::DoInsert
344
345 wxMenuItem* wxMenu::DoRemove(
346 wxMenuItem* pItem
347 )
348 {
349 //
350 // We need to find the items position in the child list
351 //
352 size_t nPos;
353 wxMenuItemList::Node* pNode = GetMenuItems().GetFirst();
354
355 for (nPos = 0; pNode; nPos++)
356 {
357 if (pNode->GetData() == pItem)
358 break;
359 pNode = pNode->GetNext();
360 }
361
362 //
363 // DoRemove() (unlike Remove) can only be called for existing item!
364 //
365 wxCHECK_MSG(pNode, NULL, wxT("bug in wxMenu::Remove logic"));
366
367 #if wxUSE_ACCEL
368 //
369 // Remove the corresponding accel from the accel table
370 //
371 int n = FindAccel(pItem->GetId());
372
373 if (n != wxNOT_FOUND)
374 {
375 delete m_vAccels[n];
376 m_vAccels.Remove(n);
377 }
378
379 #endif // wxUSE_ACCEL
380 //
381 // Remove the item from the menu
382 //
383 ::WinSendMsg( GetHmenu()
384 ,MM_REMOVEITEM
385 ,MPFROM2SHORT(pItem->GetId(), TRUE)
386 ,(MPARAM)0
387 );
388 if (IsAttached())
389 {
390 //
391 // Otherwise, the chane won't be visible
392 //
393 m_menuBar->Refresh();
394 }
395
396 //
397 // And from internal data structures
398 //
399 return wxMenuBase::DoRemove(pItem);
400 } // end of wxMenu::DoRemove
401
402 // ---------------------------------------------------------------------------
403 // accelerator helpers
404 // ---------------------------------------------------------------------------
405
406 #if wxUSE_ACCEL
407
408 //
409 // Create the wxAcceleratorEntries for our accels and put them into provided
410 // array - return the number of accels we have
411 //
412 size_t wxMenu::CopyAccels(
413 wxAcceleratorEntry* pAccels
414 ) const
415 {
416 size_t nCount = GetAccelCount();
417
418 for (size_t n = 0; n < nCount; n++)
419 {
420 *pAccels++ = *m_vAccels[n];
421 }
422 return nCount;
423 } // end of wxMenu::CopyAccels
424
425 #endif // wxUSE_ACCEL
426
427 // ---------------------------------------------------------------------------
428 // set wxMenu title
429 // ---------------------------------------------------------------------------
430
431 void wxMenu::SetTitle(
432 const wxString& rLabel
433 )
434 {
435 bool bHasNoTitle = m_title.IsEmpty();
436 HWND hMenu = GetHmenu();
437
438 m_title = rLabel;
439 if (bHasNoTitle)
440 {
441 if (!rLabel.IsEmpty())
442 {
443 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
444 {
445 wxLogLastError("SetMenuTitle");
446 }
447 }
448 }
449 else
450 {
451 if (rLabel.IsEmpty() )
452 {
453 ::WinSendMsg( GetHmenu()
454 ,MM_REMOVEITEM
455 ,MPFROM2SHORT(hMenu, TRUE)
456 ,(MPARAM)0
457 );
458 }
459 else
460 {
461 //
462 // Modify the title
463 //
464 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
465 {
466 wxLogLastError("SetMenuTitle");
467 }
468 }
469 }
470 } // end of wxMenu::SetTitle
471
472 // ---------------------------------------------------------------------------
473 // event processing
474 // ---------------------------------------------------------------------------
475
476 bool wxMenu::OS2Command(
477 WXUINT WXUNUSED(uParam)
478 , WXWORD vId
479 )
480 {
481 //
482 // Ignore commands from the menu title
483 //
484
485 if (vId != (WXWORD)idMenuTitle)
486 {
487 wxCommandEvent vEvent(wxEVT_COMMAND_MENU_SELECTED);
488
489 vEvent.SetEventObject(this);
490 vEvent.SetId(vId);
491 vEvent.SetInt(vId);
492 ProcessCommand(vEvent);
493 }
494 return TRUE;
495 } // end of wxMenu::OS2Command
496
497 bool wxMenu::ProcessCommand(
498 wxCommandEvent& rEvent
499 )
500 {
501 bool bProcessed = FALSE;
502
503 #if wxUSE_MENU_CALLBACK
504 //
505 // Try a callback
506 //
507 if (m_callback)
508 {
509 (void)(*(m_callback))(*this, rEvent);
510 bProcessed = TRUE;
511 }
512 #endif // wxUSE_MENU_CALLBACK
513
514 //
515 // Try the menu's event handler
516 //
517 if (!bProcessed && GetEventHandler())
518 {
519 bProcessed = GetEventHandler()->ProcessEvent(rEvent);
520 }
521
522 //
523 // Try the window the menu was popped up from (and up through the
524 // hierarchy)
525 wxWindow* pWin = GetInvokingWindow();
526
527 if (!bProcessed && pWin)
528 bProcessed = pWin->GetEventHandler()->ProcessEvent(rEvent);
529 return bProcessed;
530 } // end of wxMenu::ProcessCommand
531
532 // ---------------------------------------------------------------------------
533 // other
534 // ---------------------------------------------------------------------------
535
536 void wxMenu::Attach(
537 wxMenuBar* pMenubar
538 )
539 {
540 //
541 // Menu can be in at most one menubar because otherwise they would both
542 // delete the menu pointer
543 //
544 wxASSERT_MSG(!m_menuBar, wxT("menu belongs to 2 menubars, expect a crash"));
545 m_menuBar = pMenubar;
546 } // end of
547
548 void wxMenu::Detach()
549 {
550 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
551 m_menuBar = NULL;
552 } // end of wxMenu::Detach
553
554 wxWindow* wxMenu::GetWindow() const
555 {
556 if (m_invokingWindow != NULL)
557 return m_invokingWindow;
558 else if ( m_menuBar != NULL)
559 return m_menuBar->GetFrame();
560
561 return NULL;
562 } // end of wxMenu::GetWindow
563
564 // ---------------------------------------------------------------------------
565 // Menu Bar
566 // ---------------------------------------------------------------------------
567
568 void wxMenuBar::Init()
569 {
570 m_eventHandler = this;
571 m_pMenuBarFrame = NULL;
572 m_hMenu = 0;
573 } // end of wxMenuBar::Init
574
575 wxMenuBar::wxMenuBar()
576 {
577 Init();
578 } // end of wxMenuBar::wxMenuBar
579
580 wxMenuBar::wxMenuBar(
581 long WXUNUSED(lStyle)
582 )
583 {
584 Init();
585 } // end of wxMenuBar::wxMenuBar
586
587 wxMenuBar::wxMenuBar(
588 int nCount
589 , wxMenu* vMenus[]
590 , const wxString sTitles[]
591 )
592 {
593 Init();
594
595 m_titles.Alloc(nCount);
596 for ( int i = 0; i < nCount; i++ )
597 {
598 m_menus.Append(vMenus[i]);
599 m_titles.Add(sTitles[i]);
600 vMenus[i]->Attach(this);
601 }
602 } // end of wxMenuBar::wxMenuBar
603
604 wxMenuBar::~wxMenuBar()
605 {
606 } // end of wxMenuBar::~wxMenuBar
607
608 // ---------------------------------------------------------------------------
609 // wxMenuBar helpers
610 // ---------------------------------------------------------------------------
611
612 void wxMenuBar::Refresh()
613 {
614 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
615
616 WinSendMsg(GetWinHwnd(m_pMenuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
617 } // end of wxMenuBar::Refresh
618
619 WXHMENU wxMenuBar::Create()
620 {
621 MENUITEM vItem;
622 HWND hFrame;
623
624 if (m_hMenu != 0 )
625 return m_hMenu;
626
627 wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
628
629 //
630 // Menubars should be associated with a frame otherwise they are popups
631 //
632 if (m_pMenuBarFrame != NULL)
633 hFrame = GetWinHwnd(m_pMenuBarFrame);
634 else
635 hFrame = HWND_DESKTOP;
636 //
637 // Create an empty menu and then fill it with insertions
638 //
639 if (!wxWindow::OS2Create( hFrame
640 ,WC_MENU
641 ,"Menu"
642 ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
643 ,0L
644 ,0L
645 ,0L
646 ,0L
647 ,hFrame
648 ,HWND_TOP
649 ,FID_MENU
650 ,(PVOID)NULL
651 ,(PVOID)NULL
652 ))
653 {
654 wxLogLastError("CreateMenu");
655 }
656 else
657 {
658 size_t nCount = GetMenuCount();
659
660 for (size_t i = 0; i < nCount; i++)
661 {
662 vItem.iPosition = 0;
663 vItem.afStyle = MIS_SUBMENU | MIS_TEXT;
664 vItem.afAttribute = (USHORT)0;
665 vItem.id = (USHORT)0;
666 vItem.hwndSubMenu = m_menus[i]->GetHMenu();
667 vItem.hItem = NULLHANDLE;
668
669 ::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&vItem, (MPARAM)m_titles[i].c_str());
670 }
671 }
672 return m_hMenu;
673 } // end of wxMenuBar::Create
674
675 // ---------------------------------------------------------------------------
676 // wxMenuBar functions to work with the top level submenus
677 // ---------------------------------------------------------------------------
678
679 //
680 // NB: we don't support owner drawn top level items for now, if we do these
681 // functions would have to be changed to use wxMenuItem as well
682 //
683 void wxMenuBar::EnableTop(
684 size_t nPos
685 , bool bEnable
686 )
687 {
688 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
689 USHORT uFlag = 0;
690 SHORT nId;
691
692 if(!bEnable)
693 uFlag = MIA_DISABLED;
694
695 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
696 if (nId == MIT_ERROR)
697 {
698 wxLogLastError("LogLastError");
699 return;
700 }
701 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(uFlag, uFlag));
702 Refresh();
703 } // end of wxMenuBar::EnableTop
704
705 void wxMenuBar::SetLabelTop(
706 size_t nPos
707 , const wxString& rLabel
708 )
709 {
710 SHORT nId;
711 MENUITEM vItem;
712
713 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
714 m_titles[nPos] = rLabel;
715
716 if (!IsAttached())
717 {
718 return;
719 }
720
721 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
722 if (nId == MIT_ERROR)
723 {
724 wxLogLastError("LogLastError");
725 return;
726 }
727 if(!::WinSendMsg( (HWND)m_hMenu
728 ,MM_QUERYITEM
729 ,MPFROM2SHORT(nId, TRUE)
730 ,MPARAM(&vItem)
731 ))
732 {
733 wxLogLastError("QueryItem");
734 }
735 nId = vItem.id;
736
737 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
738 {
739 wxLogLastError("ModifyMenu");
740 }
741 Refresh();
742 } // end of wxMenuBar::SetLabelTop
743
744 wxString wxMenuBar::GetLabelTop(
745 size_t nPos
746 ) const
747 {
748 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
749 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
750 return m_titles[nPos];
751 } // end of wxMenuBar::GetLabelTop
752
753 // ---------------------------------------------------------------------------
754 // wxMenuBar construction
755 // ---------------------------------------------------------------------------
756
757 wxMenu* wxMenuBar::Replace(
758 size_t nPos
759 , wxMenu* pMenu
760 , const wxString& rTitle
761 )
762 {
763 SHORT nId;
764 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
765 ,pMenu
766 ,rTitle
767 );
768
769
770 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
771 if (nId == MIT_ERROR)
772 {
773 wxLogLastError("LogLastError");
774 return NULL;
775 }
776 if (!pMenuOld)
777 return FALSE;
778 m_titles[nPos] = rTitle;
779 if (IsAttached())
780 {
781 ::WinSendMsg((HWND)m_hMenu, MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
782 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
783
784 #if wxUSE_ACCEL
785 if (pMenuOld->HasAccels() || pMenu->HasAccels())
786 {
787 //
788 // Need to rebuild accell table
789 //
790 RebuildAccelTable();
791 }
792 #endif // wxUSE_ACCEL
793 Refresh();
794 }
795 return pMenuOld;
796 } // end of wxMenuBar::Replace
797
798 bool wxMenuBar::Insert(
799 size_t nPos
800 , wxMenu* pMenu
801 , const wxString& rTitle
802 )
803 {
804 if (!wxMenuBarBase::Insert( nPos
805 ,pMenu
806 ,rTitle
807 ))
808 return FALSE;
809
810 m_titles.Insert( rTitle
811 ,nPos
812 );
813
814 pMenu->Attach(this);
815
816 if (IsAttached())
817 {
818 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
819 #if wxUSE_ACCEL
820 if (pMenu->HasAccels())
821 {
822 // need to rebuild accell table
823 RebuildAccelTable();
824 }
825 #endif // wxUSE_ACCEL
826 Refresh();
827 }
828 return TRUE;
829 } // end of wxMenuBar::Insert
830
831 bool wxMenuBar::Append(
832 wxMenu* pMenu
833 , const wxString& rTitle
834 )
835 {
836 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
837
838 wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
839
840 if (!wxMenuBarBase::Append(pMenu, rTitle))
841 return FALSE;
842
843 pMenu->Attach(this);
844 m_titles.Add(rTitle);
845
846 if ( IsAttached() )
847 {
848 pMenu->m_vMenuData.iPosition = MIT_END;
849 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
850 #if wxUSE_ACCEL
851 if (pMenu->HasAccels())
852 {
853 //
854 // Need to rebuild accell table
855 //
856 RebuildAccelTable();
857 }
858 #endif // wxUSE_ACCEL
859 Refresh();
860 }
861 return TRUE;
862 } // end of wxMenuBar::Append
863
864 wxMenu* wxMenuBar::Remove(
865 size_t nPos
866 )
867 {
868 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
869 SHORT nId;
870
871 if (!pMenu)
872 return NULL;
873
874 nId = SHORT1FROMMR(::WinSendMsg((HWND)GetHmenu(), MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
875 if (nId == MIT_ERROR)
876 {
877 wxLogLastError("LogLastError");
878 return NULL;
879 }
880 if (IsAttached())
881 {
882 ::WinSendMsg((HWND)GetHmenu(), MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
883 pMenu->Detach();
884
885 #if wxUSE_ACCEL
886 if (pMenu->HasAccels())
887 {
888 //
889 // Need to rebuild accell table
890 //
891 RebuildAccelTable();
892 }
893 #endif // wxUSE_ACCEL
894 Refresh();
895 }
896 m_titles.Remove(nPos);
897 return pMenu;
898 } // end of wxMenuBar::Remove
899
900 #if wxUSE_ACCEL
901
902 void wxMenuBar::RebuildAccelTable()
903 {
904 //
905 // Merge the accelerators of all menus into one accel table
906 //
907 size_t nAccelCount = 0;
908 size_t i;
909 size_t nCount = GetMenuCount();
910
911 for (i = 0; i < nCount; i++)
912 {
913 nAccelCount += m_menus[i]->GetAccelCount();
914 }
915
916 if (nAccelCount)
917 {
918 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
919
920 nAccelCount = 0;
921 for (i = 0; i < nCount; i++)
922 {
923 nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
924 }
925 m_vAccelTable = wxAcceleratorTable( nAccelCount
926 ,pAccelEntries
927 );
928 delete [] pAccelEntries;
929 }
930 } // end of wxMenuBar::RebuildAccelTable
931
932 #endif // wxUSE_ACCEL
933
934 void wxMenuBar::Attach(
935 wxFrame* pFrame
936 )
937 {
938 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
939 m_pMenuBarFrame = pFrame;
940
941 #if wxUSE_ACCEL
942 RebuildAccelTable();
943 #endif // wxUSE_ACCEL
944 } // end of wxMenuBar::Attach
945
946 void wxMenuBar::Detach()
947 {
948 ::WinDestroyWindow((HWND)m_hMenu);
949 m_hMenu = (WXHMENU)NULL;
950 m_pMenuBarFrame = NULL;
951 } // end of wxMenuBar::Detach
952
953 // ---------------------------------------------------------------------------
954 // wxMenuBar searching for menu items
955 // ---------------------------------------------------------------------------
956
957 //
958 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
959 //
960 int wxMenuBar::FindMenuItem(
961 const wxString& rMenuString
962 , const wxString& rItemString
963 ) const
964 {
965 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
966 size_t nCount = GetMenuCount();
967
968 for (size_t i = 0; i < nCount; i++)
969 {
970 wxString sTitle = wxStripMenuCodes(m_titles[i]);
971
972 if (rMenuString == sTitle)
973 return m_menus[i]->FindItem(rItemString);
974 }
975 return wxNOT_FOUND;
976 } // end of wxMenuBar::FindMenuItem
977
978 wxMenuItem* wxMenuBar::FindItem(
979 int nId
980 , wxMenu** ppItemMenu
981 ) const
982 {
983 if (ppItemMenu)
984 *ppItemMenu = NULL;
985
986 wxMenuItem* pItem = NULL;
987 size_t nCount = GetMenuCount();
988
989 for (size_t i = 0; !pItem && (i < nCount); i++)
990 {
991 pItem = m_menus[i]->FindItem( nId
992 ,ppItemMenu
993 );
994 }
995 return pItem;
996 } // end of wxMenuBar::FindItem
997