Loads of framework and dll fixes
[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 hMenuBar;
282 if (m_menuBar)
283 hMenuBar = GetWinHwnd(m_menuBar);
284 else
285 hMenuBar = HWND_DESKTOP;
286 HWND hSubMenu = ::WinCreateWindow( hMenuBar // parent
287 ,WC_MENU // type
288 ,"Menu" // a generic name
289 ,0L // no style flag
290 ,0L,0L,0L,0L // no position
291 ,hMenuBar // no owner
292 ,HWND_TOP // always on top
293 ,0L // no ID needed for dynamic creation
294 ,NULL // no control data
295 ,NULL // no presentation params
296 );
297
298 m_vMenuData.iPosition = 0;
299 m_vMenuData.hwndSubMenu = hSubMenu;
300 m_vMenuData.hItem = NULLHANDLE;
301
302 bOk = (bool)::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&m_vMenuData, (MPARAM)pItem->GetText().c_str());
303 }
304 else
305 {
306 m_vMenuData.iPosition = nPos;
307 m_vMenuData.hwndSubMenu = NULLHANDLE;
308 m_vMenuData.hItem = NULLHANDLE;
309 bOk = (bool)::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&m_vMenuData, (MPARAM)pItem->GetText().c_str());
310 }
311
312 if (!bOk)
313 {
314 wxLogLastError("Insert or AppendMenu");
315 return FALSE;
316 }
317 else
318 {
319 //
320 // If we're already attached to the menubar, we must update it
321 //
322 if (IsAttached())
323 {
324 m_menuBar->Refresh();
325 }
326 return TRUE;
327 }
328 return FALSE;
329 } // end of wxMenu::DoInsertOrAppend
330
331 bool wxMenu::DoAppend(
332 wxMenuItem* pItem
333 )
334 {
335 return wxMenuBase::DoAppend(pItem) && DoInsertOrAppend(pItem);
336 }
337
338 bool wxMenu::DoInsert(
339 size_t nPos
340 , wxMenuItem* pItem
341 )
342 {
343 return ( wxMenuBase::DoInsert( nPos
344 ,pItem) &&
345 DoInsertOrAppend( pItem
346 ,nPos
347 ));
348 } // end of wxMenu::DoInsert
349
350 wxMenuItem* wxMenu::DoRemove(
351 wxMenuItem* pItem
352 )
353 {
354 //
355 // We need to find the items position in the child list
356 //
357 size_t nPos;
358 wxMenuItemList::Node* pNode = GetMenuItems().GetFirst();
359
360 for (nPos = 0; pNode; nPos++)
361 {
362 if (pNode->GetData() == pItem)
363 break;
364 pNode = pNode->GetNext();
365 }
366
367 //
368 // DoRemove() (unlike Remove) can only be called for existing item!
369 //
370 wxCHECK_MSG(pNode, NULL, wxT("bug in wxMenu::Remove logic"));
371
372 #if wxUSE_ACCEL
373 //
374 // Remove the corresponding accel from the accel table
375 //
376 int n = FindAccel(pItem->GetId());
377
378 if (n != wxNOT_FOUND)
379 {
380 delete m_vAccels[n];
381 m_vAccels.Remove(n);
382 }
383
384 #endif // wxUSE_ACCEL
385 //
386 // Remove the item from the menu
387 //
388 ::WinSendMsg( GetHmenu()
389 ,MM_REMOVEITEM
390 ,MPFROM2SHORT(pItem->GetId(), TRUE)
391 ,(MPARAM)0
392 );
393 if (IsAttached())
394 {
395 //
396 // Otherwise, the chane won't be visible
397 //
398 m_menuBar->Refresh();
399 }
400
401 //
402 // And from internal data structures
403 //
404 return wxMenuBase::DoRemove(pItem);
405 } // end of wxMenu::DoRemove
406
407 // ---------------------------------------------------------------------------
408 // accelerator helpers
409 // ---------------------------------------------------------------------------
410
411 #if wxUSE_ACCEL
412
413 //
414 // Create the wxAcceleratorEntries for our accels and put them into provided
415 // array - return the number of accels we have
416 //
417 size_t wxMenu::CopyAccels(
418 wxAcceleratorEntry* pAccels
419 ) const
420 {
421 size_t nCount = GetAccelCount();
422
423 for (size_t n = 0; n < nCount; n++)
424 {
425 *pAccels++ = *m_vAccels[n];
426 }
427 return nCount;
428 } // end of wxMenu::CopyAccels
429
430 #endif // wxUSE_ACCEL
431
432 // ---------------------------------------------------------------------------
433 // set wxMenu title
434 // ---------------------------------------------------------------------------
435
436 void wxMenu::SetTitle(
437 const wxString& rLabel
438 )
439 {
440 bool bHasNoTitle = m_title.IsEmpty();
441 HWND hMenu = GetHmenu();
442
443 m_title = rLabel;
444 if (bHasNoTitle)
445 {
446 if (!rLabel.IsEmpty())
447 {
448 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
449 {
450 wxLogLastError("SetMenuTitle");
451 }
452 }
453 }
454 else
455 {
456 if (rLabel.IsEmpty() )
457 {
458 ::WinSendMsg( GetHmenu()
459 ,MM_REMOVEITEM
460 ,MPFROM2SHORT(hMenu, TRUE)
461 ,(MPARAM)0
462 );
463 }
464 else
465 {
466 //
467 // Modify the title
468 //
469 if (!::WinSetWindowText(hMenu, rLabel.c_str()))
470 {
471 wxLogLastError("SetMenuTitle");
472 }
473 }
474 }
475 } // end of wxMenu::SetTitle
476
477 // ---------------------------------------------------------------------------
478 // event processing
479 // ---------------------------------------------------------------------------
480
481 bool wxMenu::OS2Command(
482 WXUINT WXUNUSED(uParam)
483 , WXWORD vId
484 )
485 {
486 //
487 // Ignore commands from the menu title
488 //
489
490 if (vId != (WXWORD)idMenuTitle)
491 {
492 wxCommandEvent vEvent(wxEVT_COMMAND_MENU_SELECTED);
493
494 vEvent.SetEventObject(this);
495 vEvent.SetId(vId);
496 vEvent.SetInt(vId);
497 ProcessCommand(vEvent);
498 }
499 return TRUE;
500 } // end of wxMenu::OS2Command
501
502 bool wxMenu::ProcessCommand(
503 wxCommandEvent& rEvent
504 )
505 {
506 bool bProcessed = FALSE;
507
508 #if wxUSE_MENU_CALLBACK
509 //
510 // Try a callback
511 //
512 if (m_callback)
513 {
514 (void)(*(m_callback))(*this, rEvent);
515 bProcessed = TRUE;
516 }
517 #endif // wxUSE_MENU_CALLBACK
518
519 //
520 // Try the menu's event handler
521 //
522 if (!bProcessed && GetEventHandler())
523 {
524 bProcessed = GetEventHandler()->ProcessEvent(rEvent);
525 }
526
527 //
528 // Try the window the menu was popped up from (and up through the
529 // hierarchy)
530 wxWindow* pWin = GetInvokingWindow();
531
532 if (!bProcessed && pWin)
533 bProcessed = pWin->GetEventHandler()->ProcessEvent(rEvent);
534 return bProcessed;
535 } // end of wxMenu::ProcessCommand
536
537 // ---------------------------------------------------------------------------
538 // other
539 // ---------------------------------------------------------------------------
540
541 void wxMenu::Attach(
542 wxMenuBar* pMenubar
543 )
544 {
545 //
546 // Menu can be in at most one menubar because otherwise they would both
547 // delete the menu pointer
548 //
549 wxASSERT_MSG(!m_menuBar, wxT("menu belongs to 2 menubars, expect a crash"));
550 m_menuBar = pMenubar;
551 } // end of
552
553 void wxMenu::Detach()
554 {
555 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
556 m_menuBar = NULL;
557 } // end of wxMenu::Detach
558
559 wxWindow* wxMenu::GetWindow() const
560 {
561 if (m_invokingWindow != NULL)
562 return m_invokingWindow;
563 else if ( m_menuBar != NULL)
564 return m_menuBar->GetFrame();
565
566 return NULL;
567 } // end of wxMenu::GetWindow
568
569 // ---------------------------------------------------------------------------
570 // Menu Bar
571 // ---------------------------------------------------------------------------
572
573 void wxMenuBar::Init()
574 {
575 m_eventHandler = this;
576 m_pMenuBarFrame = NULL;
577 m_hMenu = 0;
578 } // end of wxMenuBar::Init
579
580 wxMenuBar::wxMenuBar()
581 {
582 Init();
583 } // end of wxMenuBar::wxMenuBar
584
585 wxMenuBar::wxMenuBar(
586 long WXUNUSED(lStyle)
587 )
588 {
589 Init();
590 } // end of wxMenuBar::wxMenuBar
591
592 wxMenuBar::wxMenuBar(
593 int nCount
594 , wxMenu* vMenus[]
595 , const wxString sTitles[]
596 )
597 {
598 Init();
599
600 m_titles.Alloc(nCount);
601 for ( int i = 0; i < nCount; i++ )
602 {
603 m_menus.Append(vMenus[i]);
604 m_titles.Add(sTitles[i]);
605 vMenus[i]->Attach(this);
606 }
607 } // end of wxMenuBar::wxMenuBar
608
609 wxMenuBar::~wxMenuBar()
610 {
611 } // end of wxMenuBar::~wxMenuBar
612
613 // ---------------------------------------------------------------------------
614 // wxMenuBar helpers
615 // ---------------------------------------------------------------------------
616
617 void wxMenuBar::Refresh()
618 {
619 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
620
621 WinSendMsg(GetWinHwnd(m_pMenuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
622 } // end of wxMenuBar::Refresh
623
624 WXHMENU wxMenuBar::Create()
625 {
626 MENUITEM vItem;
627 HWND hFrame;
628
629 if (m_hMenu != 0 )
630 return m_hMenu;
631
632 wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
633
634 //
635 // Menubars should be associated with a frame otherwise they are popups
636 //
637 if (m_pMenuBarFrame != NULL)
638 hFrame = GetWinHwnd(m_pMenuBarFrame);
639 else
640 hFrame = HWND_DESKTOP;
641 //
642 // Create an empty menu and then fill it with insertions
643 //
644 if (!wxWindow::OS2Create( hFrame
645 ,WC_MENU
646 ,"Menu"
647 ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
648 ,0L
649 ,0L
650 ,0L
651 ,0L
652 ,hFrame
653 ,HWND_TOP
654 ,FID_MENU
655 ,(PVOID)NULL
656 ,(PVOID)NULL
657 ))
658 {
659 wxLogLastError("CreateMenu");
660 }
661 else
662 {
663 size_t nCount = GetMenuCount();
664
665 for (size_t i = 0; i < nCount; i++)
666 {
667 vItem.iPosition = 0;
668 vItem.afStyle = MIS_SUBMENU | MIS_TEXT;
669 vItem.afAttribute = (USHORT)0;
670 vItem.id = (USHORT)0;
671 vItem.hwndSubMenu = m_menus[i]->GetHMenu();
672 vItem.hItem = NULLHANDLE;
673
674 ::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&vItem, (MPARAM)m_titles[i].c_str());
675 }
676 }
677 return m_hMenu;
678 } // end of wxMenuBar::Create
679
680 // ---------------------------------------------------------------------------
681 // wxMenuBar functions to work with the top level submenus
682 // ---------------------------------------------------------------------------
683
684 //
685 // NB: we don't support owner drawn top level items for now, if we do these
686 // functions would have to be changed to use wxMenuItem as well
687 //
688 void wxMenuBar::EnableTop(
689 size_t nPos
690 , bool bEnable
691 )
692 {
693 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
694 USHORT uFlag = 0;
695 SHORT nId;
696
697 if(!bEnable)
698 uFlag = MIA_DISABLED;
699
700 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
701 if (nId == MIT_ERROR)
702 {
703 wxLogLastError("LogLastError");
704 return;
705 }
706 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(uFlag, uFlag));
707 Refresh();
708 } // end of wxMenuBar::EnableTop
709
710 void wxMenuBar::SetLabelTop(
711 size_t nPos
712 , const wxString& rLabel
713 )
714 {
715 SHORT nId;
716 MENUITEM vItem;
717
718 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
719 m_titles[nPos] = rLabel;
720
721 if (!IsAttached())
722 {
723 return;
724 }
725
726 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
727 if (nId == MIT_ERROR)
728 {
729 wxLogLastError("LogLastError");
730 return;
731 }
732 if(!::WinSendMsg( (HWND)m_hMenu
733 ,MM_QUERYITEM
734 ,MPFROM2SHORT(nId, TRUE)
735 ,MPARAM(&vItem)
736 ))
737 {
738 wxLogLastError("QueryItem");
739 }
740 nId = vItem.id;
741
742 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
743 {
744 wxLogLastError("ModifyMenu");
745 }
746 Refresh();
747 } // end of wxMenuBar::SetLabelTop
748
749 wxString wxMenuBar::GetLabelTop(
750 size_t nPos
751 ) const
752 {
753 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
754 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
755 return m_titles[nPos];
756 } // end of wxMenuBar::GetLabelTop
757
758 // ---------------------------------------------------------------------------
759 // wxMenuBar construction
760 // ---------------------------------------------------------------------------
761
762 wxMenu* wxMenuBar::Replace(
763 size_t nPos
764 , wxMenu* pMenu
765 , const wxString& rTitle
766 )
767 {
768 SHORT nId;
769 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
770 ,pMenu
771 ,rTitle
772 );
773
774
775 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
776 if (nId == MIT_ERROR)
777 {
778 wxLogLastError("LogLastError");
779 return NULL;
780 }
781 if (!pMenuOld)
782 return FALSE;
783 m_titles[nPos] = rTitle;
784 if (IsAttached())
785 {
786 ::WinSendMsg((HWND)m_hMenu, MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
787 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
788
789 #if wxUSE_ACCEL
790 if (pMenuOld->HasAccels() || pMenu->HasAccels())
791 {
792 //
793 // Need to rebuild accell table
794 //
795 RebuildAccelTable();
796 }
797 #endif // wxUSE_ACCEL
798 Refresh();
799 }
800 return pMenuOld;
801 } // end of wxMenuBar::Replace
802
803 bool wxMenuBar::Insert(
804 size_t nPos
805 , wxMenu* pMenu
806 , const wxString& rTitle
807 )
808 {
809 if (!wxMenuBarBase::Insert( nPos
810 ,pMenu
811 ,rTitle
812 ))
813 return FALSE;
814
815 m_titles.Insert( rTitle
816 ,nPos
817 );
818
819 pMenu->Attach(this);
820
821 if (IsAttached())
822 {
823 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
824 #if wxUSE_ACCEL
825 if (pMenu->HasAccels())
826 {
827 // need to rebuild accell table
828 RebuildAccelTable();
829 }
830 #endif // wxUSE_ACCEL
831 Refresh();
832 }
833 return TRUE;
834 } // end of wxMenuBar::Insert
835
836 bool wxMenuBar::Append(
837 wxMenu* pMenu
838 , const wxString& rTitle
839 )
840 {
841 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
842
843 wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
844
845 if (!wxMenuBarBase::Append(pMenu, rTitle))
846 return FALSE;
847
848 pMenu->Attach(this);
849 m_titles.Add(rTitle);
850
851 if ( IsAttached() )
852 {
853 pMenu->m_vMenuData.iPosition = MIT_END;
854 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
855 #if wxUSE_ACCEL
856 if (pMenu->HasAccels())
857 {
858 //
859 // Need to rebuild accell table
860 //
861 RebuildAccelTable();
862 }
863 #endif // wxUSE_ACCEL
864 Refresh();
865 }
866 return TRUE;
867 } // end of wxMenuBar::Append
868
869 wxMenu* wxMenuBar::Remove(
870 size_t nPos
871 )
872 {
873 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
874 SHORT nId;
875
876 if (!pMenu)
877 return NULL;
878
879 nId = SHORT1FROMMR(::WinSendMsg((HWND)GetHmenu(), MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
880 if (nId == MIT_ERROR)
881 {
882 wxLogLastError("LogLastError");
883 return NULL;
884 }
885 if (IsAttached())
886 {
887 ::WinSendMsg((HWND)GetHmenu(), MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
888 pMenu->Detach();
889
890 #if wxUSE_ACCEL
891 if (pMenu->HasAccels())
892 {
893 //
894 // Need to rebuild accell table
895 //
896 RebuildAccelTable();
897 }
898 #endif // wxUSE_ACCEL
899 Refresh();
900 }
901 m_titles.Remove(nPos);
902 return pMenu;
903 } // end of wxMenuBar::Remove
904
905 #if wxUSE_ACCEL
906
907 void wxMenuBar::RebuildAccelTable()
908 {
909 //
910 // Merge the accelerators of all menus into one accel table
911 //
912 size_t nAccelCount = 0;
913 size_t i;
914 size_t nCount = GetMenuCount();
915
916 for (i = 0; i < nCount; i++)
917 {
918 nAccelCount += m_menus[i]->GetAccelCount();
919 }
920
921 if (nAccelCount)
922 {
923 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
924
925 nAccelCount = 0;
926 for (i = 0; i < nCount; i++)
927 {
928 nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
929 }
930 m_vAccelTable = wxAcceleratorTable( nAccelCount
931 ,pAccelEntries
932 );
933 delete [] pAccelEntries;
934 }
935 } // end of wxMenuBar::RebuildAccelTable
936
937 #endif // wxUSE_ACCEL
938
939 void wxMenuBar::Attach(
940 wxFrame* pFrame
941 )
942 {
943 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
944 m_pMenuBarFrame = pFrame;
945
946 #if wxUSE_ACCEL
947 RebuildAccelTable();
948 #endif // wxUSE_ACCEL
949 } // end of wxMenuBar::Attach
950
951 void wxMenuBar::Detach()
952 {
953 ::WinDestroyWindow((HWND)m_hMenu);
954 m_hMenu = (WXHMENU)NULL;
955 m_pMenuBarFrame = NULL;
956 } // end of wxMenuBar::Detach
957
958 // ---------------------------------------------------------------------------
959 // wxMenuBar searching for menu items
960 // ---------------------------------------------------------------------------
961
962 //
963 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
964 //
965 int wxMenuBar::FindMenuItem(
966 const wxString& rMenuString
967 , const wxString& rItemString
968 ) const
969 {
970 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
971 size_t nCount = GetMenuCount();
972
973 for (size_t i = 0; i < nCount; i++)
974 {
975 wxString sTitle = wxStripMenuCodes(m_titles[i]);
976
977 if (rMenuString == sTitle)
978 return m_menus[i]->FindItem(rItemString);
979 }
980 return wxNOT_FOUND;
981 } // end of wxMenuBar::FindMenuItem
982
983 wxMenuItem* wxMenuBar::FindItem(
984 int nId
985 , wxMenu** ppItemMenu
986 ) const
987 {
988 if (ppItemMenu)
989 *ppItemMenu = NULL;
990
991 wxMenuItem* pItem = NULL;
992 size_t nCount = GetMenuCount();
993
994 for (size_t i = 0; !pItem && (i < nCount); i++)
995 {
996 pItem = m_menus[i]->FindItem( nId
997 ,ppItemMenu
998 );
999 }
1000 return pItem;
1001 } // end of wxMenuBar::FindItem
1002