]> git.saurik.com Git - wxWidgets.git/blob - src/os2/menu.cpp
dropTarget is now dynamically allocated.
[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 | MIS_TEXT;
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 APIRET rc;
661 ERRORID vError;
662 wxString sError;
663
664 rc = (APIRET)::WinSendMsg(hMenuBar, MM_INSERTITEM, (MPARAM)&m_menus[i]->m_vMenuData, (MPARAM)m_titles[i].c_str());
665 if (rc == MIT_MEMERROR || rc == MIT_ERROR)
666 {
667 vError = ::WinGetLastError(vHabmain);
668 sError = wxPMErrorToStr(vError);
669 wxLogError("Error inserting or appending a menuitem. Error: %s\n", sError);
670 return NULLHANDLE;
671 }
672 }
673 }
674 return hMenuBar;
675 } // end of wxMenuBar::Create
676
677 // ---------------------------------------------------------------------------
678 // wxMenuBar functions to work with the top level submenus
679 // ---------------------------------------------------------------------------
680
681 //
682 // NB: we don't support owner drawn top level items for now, if we do these
683 // functions would have to be changed to use wxMenuItem as well
684 //
685 void wxMenuBar::EnableTop(
686 size_t nPos
687 , bool bEnable
688 )
689 {
690 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
691 USHORT uFlag = 0;
692 SHORT nId;
693
694 if(!bEnable)
695 uFlag = MIA_DISABLED;
696
697 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
698 if (nId == MIT_ERROR)
699 {
700 wxLogLastError("LogLastError");
701 return;
702 }
703 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(uFlag, uFlag));
704 Refresh();
705 } // end of wxMenuBar::EnableTop
706
707 void wxMenuBar::SetLabelTop(
708 size_t nPos
709 , const wxString& rLabel
710 )
711 {
712 SHORT nId;
713 MENUITEM vItem;
714
715 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
716 m_titles[nPos] = rLabel;
717
718 if (!IsAttached())
719 {
720 return;
721 }
722
723 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
724 if (nId == MIT_ERROR)
725 {
726 wxLogLastError("LogLastError");
727 return;
728 }
729 if(!::WinSendMsg( (HWND)m_hMenu
730 ,MM_QUERYITEM
731 ,MPFROM2SHORT(nId, TRUE)
732 ,MPARAM(&vItem)
733 ))
734 {
735 wxLogLastError("QueryItem");
736 }
737 nId = vItem.id;
738
739 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
740 {
741 wxLogLastError("ModifyMenu");
742 }
743 Refresh();
744 } // end of wxMenuBar::SetLabelTop
745
746 wxString wxMenuBar::GetLabelTop(
747 size_t nPos
748 ) const
749 {
750 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
751 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
752 return m_titles[nPos];
753 } // end of wxMenuBar::GetLabelTop
754
755 // ---------------------------------------------------------------------------
756 // wxMenuBar construction
757 // ---------------------------------------------------------------------------
758
759 wxMenu* wxMenuBar::Replace(
760 size_t nPos
761 , wxMenu* pMenu
762 , const wxString& rTitle
763 )
764 {
765 SHORT nId;
766 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
767 ,pMenu
768 ,rTitle
769 );
770
771
772 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
773 if (nId == MIT_ERROR)
774 {
775 wxLogLastError("LogLastError");
776 return NULL;
777 }
778 if (!pMenuOld)
779 return FALSE;
780 m_titles[nPos] = rTitle;
781 if (IsAttached())
782 {
783 ::WinSendMsg((HWND)m_hMenu, MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
784 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
785
786 #if wxUSE_ACCEL
787 if (pMenuOld->HasAccels() || pMenu->HasAccels())
788 {
789 //
790 // Need to rebuild accell table
791 //
792 RebuildAccelTable();
793 }
794 #endif // wxUSE_ACCEL
795 Refresh();
796 }
797 return pMenuOld;
798 } // end of wxMenuBar::Replace
799
800 bool wxMenuBar::Insert(
801 size_t nPos
802 , wxMenu* pMenu
803 , const wxString& rTitle
804 )
805 {
806 if (!wxMenuBarBase::Insert( nPos
807 ,pMenu
808 ,rTitle
809 ))
810 return FALSE;
811
812 m_titles.Insert( rTitle
813 ,nPos
814 );
815
816 pMenu->Attach(this);
817
818 if (IsAttached())
819 {
820 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
821 #if wxUSE_ACCEL
822 if (pMenu->HasAccels())
823 {
824 // need to rebuild accell table
825 RebuildAccelTable();
826 }
827 #endif // wxUSE_ACCEL
828 Refresh();
829 }
830 return TRUE;
831 } // end of wxMenuBar::Insert
832
833 bool wxMenuBar::Append(
834 wxMenu* pMenu
835 , const wxString& rTitle
836 )
837 {
838 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
839
840 wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
841
842 if (!wxMenuBarBase::Append(pMenu, rTitle))
843 return FALSE;
844
845 pMenu->Attach(this);
846 m_titles.Add(rTitle);
847
848 if ( IsAttached() )
849 {
850 pMenu->m_vMenuData.iPosition = MIT_END;
851 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
852 #if wxUSE_ACCEL
853 if (pMenu->HasAccels())
854 {
855 //
856 // Need to rebuild accell table
857 //
858 RebuildAccelTable();
859 }
860 #endif // wxUSE_ACCEL
861 Refresh();
862 }
863 return TRUE;
864 } // end of wxMenuBar::Append
865
866 wxMenu* wxMenuBar::Remove(
867 size_t nPos
868 )
869 {
870 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
871 SHORT nId;
872
873 if (!pMenu)
874 return NULL;
875
876 nId = SHORT1FROMMR(::WinSendMsg((HWND)GetHmenu(), MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
877 if (nId == MIT_ERROR)
878 {
879 wxLogLastError("LogLastError");
880 return NULL;
881 }
882 if (IsAttached())
883 {
884 ::WinSendMsg((HWND)GetHmenu(), MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
885 pMenu->Detach();
886
887 #if wxUSE_ACCEL
888 if (pMenu->HasAccels())
889 {
890 //
891 // Need to rebuild accell table
892 //
893 RebuildAccelTable();
894 }
895 #endif // wxUSE_ACCEL
896 Refresh();
897 }
898 m_titles.Remove(nPos);
899 return pMenu;
900 } // end of wxMenuBar::Remove
901
902 #if wxUSE_ACCEL
903
904 void wxMenuBar::RebuildAccelTable()
905 {
906 //
907 // Merge the accelerators of all menus into one accel table
908 //
909 size_t nAccelCount = 0;
910 size_t i;
911 size_t nCount = GetMenuCount();
912
913 for (i = 0; i < nCount; i++)
914 {
915 nAccelCount += m_menus[i]->GetAccelCount();
916 }
917
918 if (nAccelCount)
919 {
920 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
921
922 nAccelCount = 0;
923 for (i = 0; i < nCount; i++)
924 {
925 nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
926 }
927 m_vAccelTable = wxAcceleratorTable( nAccelCount
928 ,pAccelEntries
929 );
930 delete [] pAccelEntries;
931 }
932 } // end of wxMenuBar::RebuildAccelTable
933
934 #endif // wxUSE_ACCEL
935
936 void wxMenuBar::Attach(
937 wxFrame* pFrame
938 )
939 {
940 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
941 m_pMenuBarFrame = pFrame;
942
943 #if wxUSE_ACCEL
944 RebuildAccelTable();
945 #endif // wxUSE_ACCEL
946 } // end of wxMenuBar::Attach
947
948 void wxMenuBar::Detach()
949 {
950 ::WinDestroyWindow((HWND)m_hMenu);
951 m_hMenu = (WXHMENU)NULL;
952 m_pMenuBarFrame = NULL;
953 } // end of wxMenuBar::Detach
954
955 // ---------------------------------------------------------------------------
956 // wxMenuBar searching for menu items
957 // ---------------------------------------------------------------------------
958
959 //
960 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
961 //
962 int wxMenuBar::FindMenuItem(
963 const wxString& rMenuString
964 , const wxString& rItemString
965 ) const
966 {
967 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
968 size_t nCount = GetMenuCount();
969
970 for (size_t i = 0; i < nCount; i++)
971 {
972 wxString sTitle = wxStripMenuCodes(m_titles[i]);
973
974 if (rMenuString == sTitle)
975 return m_menus[i]->FindItem(rItemString);
976 }
977 return wxNOT_FOUND;
978 } // end of wxMenuBar::FindMenuItem
979
980 wxMenuItem* wxMenuBar::FindItem(
981 int nId
982 , wxMenu** ppItemMenu
983 ) const
984 {
985 if (ppItemMenu)
986 *ppItemMenu = NULL;
987
988 wxMenuItem* pItem = NULL;
989 size_t nCount = GetMenuCount();
990
991 for (size_t i = 0; !pItem && (i < nCount); i++)
992 {
993 pItem = m_menus[i]->FindItem( nId
994 ,ppItemMenu
995 );
996 }
997 return pItem;
998 } // end of wxMenuBar::FindItem
999