more framework fixes for menu displays
[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 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
332 bool wxMenu::DoAppend(
333 wxMenuItem* pItem
334 )
335 {
336 return wxMenuBase::DoAppend(pItem) && DoInsertOrAppend(pItem);
337 }
338
339 bool 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
351 wxMenuItem* 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 //
418 size_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
437 void 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
482 bool 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
503 bool 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
542 void 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
554 void 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
560 wxWindow* 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
574 void wxMenuBar::Init()
575 {
576 m_eventHandler = this;
577 m_pMenuBarFrame = NULL;
578 m_hMenu = 0;
579 } // end of wxMenuBar::Init
580
581 wxMenuBar::wxMenuBar()
582 {
583 Init();
584 } // end of wxMenuBar::wxMenuBar
585
586 wxMenuBar::wxMenuBar(
587 long WXUNUSED(lStyle)
588 )
589 {
590 Init();
591 } // end of wxMenuBar::wxMenuBar
592
593 wxMenuBar::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
610 wxMenuBar::~wxMenuBar()
611 {
612 } // end of wxMenuBar::~wxMenuBar
613
614 // ---------------------------------------------------------------------------
615 // wxMenuBar helpers
616 // ---------------------------------------------------------------------------
617
618 void 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
625 WXHMENU 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 //
715 void 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
737 void 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
776 wxString 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
789 wxMenu* 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
830 bool 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
863 bool 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
896 wxMenu* 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
934 void 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
966 void 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
978 void 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 //
992 int 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
1010 wxMenuItem* 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