More updates to wxWindow, wxMenu, GdiImage to get minimal to work
[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
75 //
76 m_hMenu = ::WinCreateWindow( HWND_DESKTOP // parent
77 ,WC_MENU // type
78 ,"Menu" // a generic name
79 ,0L // no style flag
80 ,0L,0L,0L,0L // no position
81 ,NULLHANDLE // no owner
82 ,NULLHANDLE // no insertion position
83 ,0L // no ID needed for dynamic creation
84 ,NULL // no control data
85 ,NULL // no presentation params
86 );
87 if (!m_hMenu)
88 {
89 wxLogLastError("WinLoadMenu");
90 }
91
92 //
93 // If we have a title, insert it in the beginning of the menu
94 //
95 if (!!m_title)
96 {
97 Append( idMenuTitle
98 ,m_title
99 );
100 AppendSeparator();
101 }
102 } // end of wxMenu::Init
103
104 //
105 // The wxWindow destructor will take care of deleting the submenus.
106 //
107 wxMenu::~wxMenu()
108 {
109 //
110 // We should free PM resources only if PM doesn't do it for us
111 // which happens if we're attached to a menubar or a submenu of another
112 // menu
113 if (!IsAttached() && !GetParent())
114 {
115 if (!::WinDestroyWindow((HWND)GetHmenu()) )
116 {
117 wxLogLastError("WinDestroyWindow");
118 }
119 }
120
121 #if wxUSE_ACCEL
122 //
123 // Delete accels
124 //
125 WX_CLEAR_ARRAY(m_vAccels);
126 #endif // wxUSE_ACCEL
127 } // end of wxMenu::~wxMenu
128
129 void wxMenu::Break()
130 {
131 // this will take effect during the next call to Append()
132 m_bDoBreak = TRUE;
133 } // end of wxMenu::Break
134
135 #if wxUSE_ACCEL
136
137 int wxMenu::FindAccel(
138 int nId
139 ) const
140 {
141 size_t n;
142 size_t nCount = m_vAccels.GetCount();
143
144 for (n = 0; n < nCount; n++)
145 {
146 if (m_vAccels[n]->m_command == nId)
147 return n;
148 }
149 return wxNOT_FOUND;
150 } // end of wxMenu::FindAccel
151
152 void wxMenu::UpdateAccel(
153 wxMenuItem* pItem
154 )
155 {
156 //
157 // Find the (new) accel for this item
158 //
159 wxAcceleratorEntry* pAccel = wxGetAccelFromString(pItem->GetText());
160
161 if (pAccel)
162 pAccel->m_command = pItem->GetId();
163
164 //
165 // Find the old one
166 //
167 int n = FindAccel(pItem->GetId());
168
169 if (n == wxNOT_FOUND)
170 {
171 //
172 // No old, add new if any
173 //
174 if (pAccel)
175 m_vAccels.Add(pAccel);
176 else
177 return; // skipping RebuildAccelTable() below
178 }
179 else
180 {
181 //
182 // Replace old with new or just remove the old one if no new
183 //
184 delete m_vAccels[n];
185
186 if (pAccel)
187 m_vAccels[n] = pAccel;
188 else
189 m_vAccels.Remove(n);
190 }
191
192 if (IsAttached())
193 {
194 m_menuBar->RebuildAccelTable();
195 }
196 } // wxMenu::UpdateAccel
197
198 #endif // wxUSE_ACCEL
199
200 //
201 // Append a new item or submenu to the menu
202 //
203 bool wxMenu::DoInsertOrAppend(
204 wxMenuItem* pItem
205 , size_t nPos
206 )
207 {
208 #if wxUSE_ACCEL
209 UpdateAccel(pItem);
210 #endif // wxUSE_ACCEL
211
212 //
213 // If "Break" has just been called, insert a menu break before this item
214 // (and don't forget to reset the flag)
215 //
216 if (m_bDoBreak)
217 {
218 m_vMenuData.afStyle |= MIS_BREAK;
219 m_bDoBreak = FALSE;
220 }
221
222 if (pItem->IsSeparator())
223 {
224 m_vMenuData.afStyle |= MIS_SEPARATOR;
225 }
226
227 //
228 // Id is the numeric id for normal menu items and HMENU for submenus as
229 // required by ::WinInsertMenu() API
230 //
231
232 wxMenu* pSubmenu = pItem->GetSubMenu();
233 MENUITEM vItem;
234
235 if (pSubmenu != NULL )
236 {
237 wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
238 pSubmenu->SetParent(this);
239
240 m_vMenuData.id = (USHORT)pSubmenu->GetHMenu();
241 m_vMenuData.afStyle |= MIS_SUBMENU;
242 }
243 else
244 {
245 m_vMenuData.id = pItem->GetId();
246 }
247
248 BYTE* pData;
249
250 #if wxUSE_OWNER_DRAWN
251 if (pItem->IsOwnerDrawn())
252 {
253 //
254 // Want to get {Measure|Draw}Item messages?
255 // item draws itself, pass pointer to it in data parameter
256 //
257 m_vMenuData.afStyle |= MIS_OWNERDRAW;
258 pData = (BYTE*)pItem;
259 }
260 else
261 #endif
262 {
263 //
264 // Menu is just a normal string (passed in data parameter)
265 //
266 m_vMenuData.afStyle |= MIS_TEXT;
267 pData = (char*)pItem->GetText().c_str();
268 }
269
270 BOOL bOk;
271
272 //
273 // -1 means this is a sub menu not a menuitem
274 //
275 if (nPos == (size_t)-1)
276 {
277 HWND hSubMenu = ::WinCreateWindow( HWND_DESKTOP // parent
278 ,WC_MENU // type
279 ,"Menu" // a generic name
280 ,0L // no style flag
281 ,0L,0L,0L,0L // no position
282 ,NULLHANDLE // no owner
283 ,NULLHANDLE // no insertion position
284 ,0L // no ID needed for dynamic creation
285 ,NULL // no control data
286 ,NULL // no presentation params
287 );
288
289 m_vMenuData.iPosition = 0;
290 m_vMenuData.hwndSubMenu = hSubMenu;
291 m_vMenuData.hItem = NULLHANDLE;
292
293 bOk = (bool)::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&vItem, (MPARAM)NULL);
294 }
295 else
296 {
297 m_vMenuData.iPosition = nPos;
298 m_vMenuData.hwndSubMenu = NULLHANDLE;
299 m_vMenuData.hItem = NULLHANDLE;
300 bOk = (bool)::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&vItem, (MPARAM)pData);
301 }
302
303 if (!bOk)
304 {
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 // DrawMenuBar(GetHwndOf(m_menuBarFrame));
613 }
614
615 WXHMENU wxMenuBar::Create()
616 {
617 MENUITEM vItem;
618
619 if (m_hMenu != 0 )
620 return m_hMenu;
621
622 wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
623
624 //
625 // Create an empty menu and then fill it with insertions
626 //
627 m_hMenu = ::WinCreateWindow( HWND_DESKTOP // parent
628 ,WC_MENU // type
629 ,"Menu" // a generic name
630 ,0L // no style flag
631 ,0L,0L,0L,0L // no position
632 ,NULLHANDLE // no owner
633 ,NULLHANDLE // no insertion position
634 ,0L // no ID needed for dynamic creation
635 ,NULL // no control data
636 ,NULL // no presentation params
637 );
638 if (!m_hMenu)
639 {
640 wxLogLastError("CreateMenu");
641 }
642 else
643 {
644 size_t nCount = GetMenuCount();
645
646 for (size_t i = 0; i < nCount; i++)
647 {
648 vItem.iPosition = 0;
649 vItem.afStyle = MIS_SUBMENU | MIS_TEXT;
650 vItem.afAttribute = (USHORT)0;
651 vItem.id = (USHORT)0;
652 vItem.hwndSubMenu = m_menus[i]->GetHMenu();
653 vItem.hItem = NULLHANDLE;
654
655 ::WinSendMsg(GetHmenu(), MM_INSERTITEM, (MPARAM)&vItem, (MPARAM)m_titles[i].c_str());
656 }
657 }
658 return m_hMenu;
659 } // end of wxMenuBar::Create
660
661 // ---------------------------------------------------------------------------
662 // wxMenuBar functions to work with the top level submenus
663 // ---------------------------------------------------------------------------
664
665 //
666 // NB: we don't support owner drawn top level items for now, if we do these
667 // functions would have to be changed to use wxMenuItem as well
668 //
669 void wxMenuBar::EnableTop(
670 size_t nPos
671 , bool bEnable
672 )
673 {
674 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
675 USHORT uFlag = 0;
676 SHORT nId;
677
678 if(!bEnable)
679 uFlag = MIA_DISABLED;
680
681 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
682 if (nId == MIT_ERROR)
683 {
684 wxLogLastError("LogLastError");
685 return;
686 }
687 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(uFlag, uFlag));
688 Refresh();
689 } // end of wxMenuBar::EnableTop
690
691 void wxMenuBar::SetLabelTop(
692 size_t nPos
693 , const wxString& rLabel
694 )
695 {
696 SHORT nId;
697 MENUITEM vItem;
698
699 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
700 m_titles[nPos] = rLabel;
701
702 if (!IsAttached())
703 {
704 return;
705 }
706
707 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
708 if (nId == MIT_ERROR)
709 {
710 wxLogLastError("LogLastError");
711 return;
712 }
713 if(!::WinSendMsg( (HWND)m_hMenu
714 ,MM_QUERYITEM
715 ,MPFROM2SHORT(nId, TRUE)
716 ,MPARAM(&vItem)
717 ))
718 {
719 wxLogLastError("QueryItem");
720 }
721 nId = vItem.id;
722
723 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
724 {
725 wxLogLastError("ModifyMenu");
726 }
727 Refresh();
728 } // end of wxMenuBar::SetLabelTop
729
730 wxString wxMenuBar::GetLabelTop(
731 size_t nPos
732 ) const
733 {
734 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
735 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
736 return m_titles[nPos];
737 } // end of wxMenuBar::GetLabelTop
738
739 // ---------------------------------------------------------------------------
740 // wxMenuBar construction
741 // ---------------------------------------------------------------------------
742
743 wxMenu* wxMenuBar::Replace(
744 size_t nPos
745 , wxMenu* pMenu
746 , const wxString& rTitle
747 )
748 {
749 SHORT nId;
750 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
751 ,pMenu
752 ,rTitle
753 );
754
755
756 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
757 if (nId == MIT_ERROR)
758 {
759 wxLogLastError("LogLastError");
760 return NULL;
761 }
762 if (!pMenuOld)
763 return FALSE;
764 m_titles[nPos] = rTitle;
765 if (IsAttached())
766 {
767 ::WinSendMsg((HWND)m_hMenu, MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
768 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
769
770 #if wxUSE_ACCEL
771 if (pMenuOld->HasAccels() || pMenu->HasAccels())
772 {
773 //
774 // Need to rebuild accell table
775 //
776 RebuildAccelTable();
777 }
778 #endif // wxUSE_ACCEL
779 Refresh();
780 }
781 return pMenuOld;
782 } // end of wxMenuBar::Replace
783
784 bool wxMenuBar::Insert(
785 size_t nPos
786 , wxMenu* pMenu
787 , const wxString& rTitle
788 )
789 {
790 if (!wxMenuBarBase::Insert( nPos
791 ,pMenu
792 ,rTitle
793 ))
794 return FALSE;
795
796 m_titles.Insert( rTitle
797 ,nPos
798 );
799
800 pMenu->Attach(this);
801
802 if (IsAttached())
803 {
804 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
805 #if wxUSE_ACCEL
806 if (pMenu->HasAccels())
807 {
808 // need to rebuild accell table
809 RebuildAccelTable();
810 }
811 #endif // wxUSE_ACCEL
812 Refresh();
813 }
814 return TRUE;
815 } // end of wxMenuBar::Insert
816
817 bool wxMenuBar::Append(
818 wxMenu* pMenu
819 , const wxString& rTitle
820 )
821 {
822 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
823
824 wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
825
826 if (!wxMenuBarBase::Append(pMenu, rTitle))
827 return FALSE;
828
829 pMenu->Attach(this);
830 m_titles.Add(rTitle);
831
832 if ( IsAttached() )
833 {
834 pMenu->m_vMenuData.iPosition = MIT_END;
835 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)rTitle.c_str());
836 #if wxUSE_ACCEL
837 if (pMenu->HasAccels())
838 {
839 //
840 // Need to rebuild accell table
841 //
842 RebuildAccelTable();
843 }
844 #endif // wxUSE_ACCEL
845 Refresh();
846 }
847 return TRUE;
848 } // end of wxMenuBar::Append
849
850 wxMenu* wxMenuBar::Remove(
851 size_t nPos
852 )
853 {
854 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
855 SHORT nId;
856
857 if (!pMenu)
858 return NULL;
859
860 nId = SHORT1FROMMR(::WinSendMsg((HWND)GetHmenu(), MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
861 if (nId == MIT_ERROR)
862 {
863 wxLogLastError("LogLastError");
864 return NULL;
865 }
866 if (IsAttached())
867 {
868 ::WinSendMsg((HWND)GetHmenu(), MM_DELETEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
869 pMenu->Detach();
870
871 #if wxUSE_ACCEL
872 if (pMenu->HasAccels())
873 {
874 //
875 // Need to rebuild accell table
876 //
877 RebuildAccelTable();
878 }
879 #endif // wxUSE_ACCEL
880 Refresh();
881 }
882 m_titles.Remove(nPos);
883 return pMenu;
884 } // end of wxMenuBar::Remove
885
886 #if wxUSE_ACCEL
887
888 void wxMenuBar::RebuildAccelTable()
889 {
890 //
891 // Merge the accelerators of all menus into one accel table
892 //
893 size_t nAccelCount = 0;
894 size_t i;
895 size_t nCount = GetMenuCount();
896
897 for (i = 0; i < nCount; i++)
898 {
899 nAccelCount += m_menus[i]->GetAccelCount();
900 }
901
902 if (nAccelCount)
903 {
904 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
905
906 nAccelCount = 0;
907 for (i = 0; i < nCount; i++)
908 {
909 nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
910 }
911 m_vAccelTable = wxAcceleratorTable( nAccelCount
912 ,pAccelEntries
913 );
914 delete [] pAccelEntries;
915 }
916 } // end of wxMenuBar::RebuildAccelTable
917
918 #endif // wxUSE_ACCEL
919
920 void wxMenuBar::Attach(
921 wxFrame* pFrame
922 )
923 {
924 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
925 m_pMenuBarFrame = pFrame;
926
927 #if wxUSE_ACCEL
928 RebuildAccelTable();
929 #endif // wxUSE_ACCEL
930 } // end of wxMenuBar::Attach
931
932 void wxMenuBar::Detach()
933 {
934 ::WinDestroyWindow((HWND)m_hMenu);
935 m_hMenu = (WXHMENU)NULL;
936 m_pMenuBarFrame = NULL;
937 } // end of wxMenuBar::Detach
938
939 // ---------------------------------------------------------------------------
940 // wxMenuBar searching for menu items
941 // ---------------------------------------------------------------------------
942
943 //
944 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
945 //
946 int wxMenuBar::FindMenuItem(
947 const wxString& rMenuString
948 , const wxString& rItemString
949 ) const
950 {
951 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
952 size_t nCount = GetMenuCount();
953
954 for (size_t i = 0; i < nCount; i++)
955 {
956 wxString sTitle = wxStripMenuCodes(m_titles[i]);
957
958 if (rMenuString == sTitle)
959 return m_menus[i]->FindItem(rItemString);
960 }
961 return wxNOT_FOUND;
962 } // end of wxMenuBar::FindMenuItem
963
964 wxMenuItem* wxMenuBar::FindItem(
965 int nId
966 , wxMenu** ppItemMenu
967 ) const
968 {
969 if (ppItemMenu)
970 *ppItemMenu = NULL;
971
972 wxMenuItem* pItem = NULL;
973 size_t nCount = GetMenuCount();
974
975 for (size_t i = 0; !pItem && (i < nCount); i++)
976 {
977 pItem = m_menus[i]->FindItem( nId
978 ,ppItemMenu
979 );
980 }
981 return pItem;
982 } // end of wxMenuBar::FindItem
983