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