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