]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/menu.cpp
Dtor for wxHtmlCell
[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// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifndef WX_PRECOMP
16 #include "wx/app.h"
17 #include "wx/frame.h"
18 #include "wx/menu.h"
19 #include "wx/utils.h"
20 #include "wx/intl.h"
21 #include "wx/log.h"
22#endif
23
24#if wxUSE_OWNER_DRAWN
25 #include "wx/ownerdrw.h"
26#endif
27
28#include "wx/os2/private.h"
29
30// other standard headers
31#include <string.h>
32
33// ----------------------------------------------------------------------------
34// global variables
35// ----------------------------------------------------------------------------
36
37extern wxMenu* wxCurrentPopupMenu;
38
39// ----------------------------------------------------------------------------
40// constants
41// ----------------------------------------------------------------------------
42
43//
44// The (popup) menu title has this special id
45//
46static const int idMenuTitle = -3;
47
48//
49// The unique ID for Menus
50//
51USHORT wxMenu::m_nextMenuId = 0;
52
53// ----------------------------------------------------------------------------
54// macros
55// ----------------------------------------------------------------------------
56
57 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
58 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
59
60// ============================================================================
61// implementation
62// ============================================================================
63
64// ---------------------------------------------------------------------------
65// wxMenu construction, adding and removing menu items
66// ---------------------------------------------------------------------------
67
68//
69// Construct a menu with optional title (then use append)
70//
71void wxMenu::Init()
72{
73 m_bDoBreak = FALSE;
74 m_nStartRadioGroup = -1;
75
76 //
77 // Create the menu (to be used as a submenu or a popup)
78 //
79 if ((m_hMenu = ::WinCreateWindow( HWND_DESKTOP
80 ,WC_MENU
81 ,"Menu"
82 ,0L
83 ,0L
84 ,0L
85 ,0L
86 ,0L
87 ,NULLHANDLE
88 ,HWND_TOP
89 ,0L
90 ,NULL
91 ,NULL
92 )) == 0)
93 {
94 wxLogLastError(wxT("WinLoadMenu"));
95 }
96 m_vMenuData.iPosition = 0;
97 m_vMenuData.afStyle = MIS_SUBMENU | MIS_TEXT;
98 m_vMenuData.afAttribute = (USHORT)0;
99 m_vMenuData.id = m_nextMenuId++;
100 m_vMenuData.hwndSubMenu = m_hMenu;
101 m_vMenuData.hItem = NULLHANDLE;
102
103 //
104 // If we have a title, insert it in the beginning of the menu
105 //
106 if (!m_title.empty())
107 {
108 Append( idMenuTitle
109 ,m_title
110 ,wxEmptyString
111 ,wxITEM_NORMAL
112 );
113 AppendSeparator();
114 }
115} // end of wxMenu::Init
116
117//
118// The wxWindow destructor will take care of deleting the submenus.
119//
120wxMenu::~wxMenu()
121{
122 //
123 // We should free PM resources only if PM doesn't do it for us
124 // which happens if we're attached to a menubar or a submenu of another
125 // menu
126 if (!IsAttached() && !GetParent())
127 {
128 if (!::WinDestroyWindow((HWND)GetHmenu()) )
129 {
130 wxLogLastError(wxT("WinDestroyWindow"));
131 }
132 }
133
134#if wxUSE_ACCEL
135 //
136 // Delete accels
137 //
138 WX_CLEAR_ARRAY(m_vAccels);
139#endif // wxUSE_ACCEL
140} // end of wxMenu::~wxMenu
141
142void wxMenu::Break()
143{
144 // this will take effect during the next call to Append()
145 m_bDoBreak = true;
146} // end of wxMenu::Break
147
148void wxMenu::Attach(
149 wxMenuBarBase* pMenubar
150)
151{
152 wxMenuBase::Attach(pMenubar);
153 EndRadioGroup();
154} // end of wxMenu::Break;
155
156#if wxUSE_ACCEL
157
158int wxMenu::FindAccel(
159 int nId
160) const
161{
162 size_t n;
163 size_t nCount = m_vAccels.GetCount();
164
165 for (n = 0; n < nCount; n++)
166 if (m_vAccels[n]->m_command == nId)
167 return n;
168 return wxNOT_FOUND;
169} // end of wxMenu::FindAccel
170
171void wxMenu::UpdateAccel(
172 wxMenuItem* pItem
173)
174{
175 if (pItem->IsSubMenu())
176 {
177 wxMenu* pSubmenu = pItem->GetSubMenu();
178 wxMenuItemList::compatibility_iterator node = pSubmenu->GetMenuItems().GetFirst();
179
180 while (node)
181 {
182 UpdateAccel(node->GetData());
183 node = node->GetNext();
184 }
185 }
186 else if (!pItem->IsSeparator())
187 {
188 //
189 // Recurse upwards: we should only modify m_accels of the top level
190 // menus, not of the submenus as wxMenuBar doesn't look at them
191 // (alternative and arguable cleaner solution would be to recurse
192 // downwards in GetAccelCount() and CopyAccels())
193 //
194 if (GetParent())
195 {
196 GetParent()->UpdateAccel(pItem);
197 return;
198 }
199
200 //
201 // Find the (new) accel for this item
202 //
203 wxAcceleratorEntry* pAccel = wxGetAccelFromString(pItem->GetText());
204
205 if (pAccel)
206 pAccel->m_command = pItem->GetId();
207
208 //
209 // Find the old one
210 //
211 size_t n = FindAccel(pItem->GetId());
212
213 if (n == (size_t)wxNOT_FOUND)
214 {
215 //
216 // No old, add new if any
217 //
218 if (pAccel)
219 m_vAccels.Add(pAccel);
220 else
221 return;
222 }
223 else
224 {
225 //
226 // Replace old with new or just remove the old one if no new
227 //
228 delete m_vAccels[n];
229 if (pAccel)
230 m_vAccels[n] = pAccel;
231 else
232 m_vAccels.RemoveAt(n);
233 }
234
235 if (IsAttached())
236 {
237 GetMenuBar()->RebuildAccelTable();
238 }
239 }
240} // wxMenu::UpdateAccel
241
242#endif // wxUSE_ACCEL
243
244//
245// Append a new item or submenu to the menu
246//
247bool wxMenu::DoInsertOrAppend( wxMenuItem* pItem,
248 size_t nPos )
249{
250 wxMenu* pSubmenu = pItem->GetSubMenu();
251 MENUITEM& rItem = (pSubmenu != NULL)?pSubmenu->m_vMenuData:
252 pItem->m_vMenuData;
253
254 ERRORID vError;
255 wxString sError;
256
257#if wxUSE_ACCEL
258 UpdateAccel(pItem);
259#endif // wxUSE_ACCEL
260
261 //
262 // If "Break" has just been called, insert a menu break before this item
263 // (and don't forget to reset the flag)
264 //
265 if (m_bDoBreak)
266 {
267 rItem.afStyle |= MIS_BREAK;
268 m_bDoBreak = FALSE;
269 }
270
271 //
272 // Id is the numeric id for normal menu items and HMENU for submenus as
273 // required by ::MM_INSERTITEM message API
274 //
275 if (pSubmenu != NULL)
276 {
277 wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
278 pSubmenu->SetParent(this);
279
280 rItem.iPosition = 0; // submenus have a 0 position
281 rItem.id = (USHORT)pSubmenu->GetHMenu();
282 rItem.afStyle |= MIS_SUBMENU | MIS_TEXT;
283 }
284 else
285 {
286 rItem.id = (USHORT)pItem->GetId();
287 }
288
289 BYTE* pData=NULL;
290
291#if wxUSE_OWNER_DRAWN
292 if (pItem->IsOwnerDrawn())
293 {
294 //
295 // Want to get {Measure|Draw}Item messages?
296 // item draws itself, passing pointer to data doesn't work in OS/2
297 // Will eventually need to set the image handle somewhere into vItem.hItem
298 //
299 rItem.afStyle |= MIS_OWNERDRAW;
300 pData = (BYTE*)NULL;
301 rItem.hItem = (HBITMAP)pItem->GetBitmap().GetHBITMAP();
302 pItem->m_vMenuData.afStyle = rItem.afStyle;
303 pItem->m_vMenuData.hItem = rItem.hItem;
304 }
305 else
306#endif
307 if (pItem->IsSeparator())
308 {
309 rItem.afStyle = MIS_SEPARATOR;
310 }
311 else
312 {
313 if (pItem->GetId() == idMenuTitle)
314 {
315 // Item is an unselectable title to be passed via pData
316 rItem.afStyle = MIS_STATIC;
317 }
318 else
319 {
320 //
321 // Menu is just a normal string (passed in data parameter)
322 //
323 rItem.afStyle |= MIS_TEXT;
324 }
325 pData = (char*)pItem->GetText().c_str();
326 }
327
328 if (nPos == (size_t)-1)
329 {
330 rItem.iPosition = MIT_END;
331 }
332 else
333 {
334 rItem.iPosition = (SHORT)nPos;
335 }
336
337 APIRET rc;
338
339 rc = (APIRET)::WinSendMsg( GetHmenu()
340 ,MM_INSERTITEM
341 ,(MPARAM)&rItem
342 ,(MPARAM)pData
343 );
344#if wxUSE_OWNER_DRAWN
345 if (pItem->IsOwnerDrawn())
346 {
347 MENUITEM vMenuItem;
348
349 ::WinSendMsg( GetHmenu()
350 ,MM_QUERYITEM
351 ,MPFROM2SHORT( (USHORT)pItem->GetId()
352 ,(USHORT)(FALSE)
353 )
354 ,&vMenuItem
355 );
356 }
357#endif
358
359 if (rc == (APIRET)MIT_MEMERROR || rc == (APIRET)MIT_ERROR)
360 {
361 vError = ::WinGetLastError(vHabmain);
362 sError = wxPMErrorToStr(vError);
363 wxLogError(wxT("Error inserting or appending a menuitem. Error: %s\n"), sError.c_str());
364 wxLogLastError(wxT("Insert or AppendMenu"));
365 return false;
366 }
367
368 //
369 // If we're already attached to the menubar, we must update it
370 //
371 if (IsAttached() && GetMenuBar()->IsAttached())
372 {
373 GetMenuBar()->Refresh();
374 }
375
376 return true;
377} // end of wxMenu::DoInsertOrAppend
378
379void wxMenu::EndRadioGroup()
380{
381 //
382 // We're not inside a radio group any longer
383 //
384 m_nStartRadioGroup = -1;
385} // end of wxMenu::EndRadioGroup
386
387wxMenuItem* wxMenu::DoAppend( wxMenuItem* pItem )
388{
389 wxCHECK_MSG( pItem, NULL, _T("NULL item in wxMenu::DoAppend") );
390
391 bool bCheck = false;
392
393 if (pItem->GetKind() == wxITEM_RADIO)
394 {
395 int nCount = GetMenuItemCount();
396
397 if (m_nStartRadioGroup == -1)
398 {
399 //
400 // Start a new radio group
401 //
402 m_nStartRadioGroup = nCount;
403
404 //
405 // For now it has just one element
406 //
407 pItem->SetAsRadioGroupStart();
408 pItem->SetRadioGroupEnd(m_nStartRadioGroup);
409
410 //
411 // Ensure that we have a checked item in the radio group
412 //
413 bCheck = true;
414 }
415 else // extend the current radio group
416 {
417 //
418 // We need to update its end item
419 //
420 pItem->SetRadioGroupStart(m_nStartRadioGroup);
421
422 wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_nStartRadioGroup);
423
424 if (node)
425 {
426 node->GetData()->SetRadioGroupEnd(nCount);
427 }
428 else
429 {
430 wxFAIL_MSG( _T("where is the radio group start item?") );
431 }
432 }
433 }
434 else // not a radio item
435 {
436 EndRadioGroup();
437 }
438
439 if (!wxMenuBase::DoAppend(pItem) || !DoInsertOrAppend(pItem))
440 {
441 return NULL;
442 }
443 if (bCheck)
444 {
445 //
446 // Check the item initially
447 //
448 pItem->Check(true);
449 }
450 return pItem;
451} // end of wxMenu::DoAppend
452
453wxMenuItem* wxMenu::DoInsert(
454 size_t nPos
455, wxMenuItem* pItem
456)
457{
458 if ( wxMenuBase::DoInsert( nPos
459 ,pItem) &&
460 DoInsertOrAppend( pItem
461 ,nPos
462 ))
463 return pItem;
464 else
465 return NULL;
466} // end of wxMenu::DoInsert
467
468wxMenuItem* wxMenu::DoRemove(
469 wxMenuItem* pItem
470)
471{
472 //
473 // We need to find the items position in the child list
474 //
475 size_t nPos;
476 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
477
478 for (nPos = 0; node; nPos++)
479 {
480 if (node->GetData() == pItem)
481 break;
482 node = node->GetNext();
483 }
484
485 //
486 // DoRemove() (unlike Remove) can only be called for existing item!
487 //
488 wxCHECK_MSG(node, NULL, wxT("bug in wxMenu::Remove logic"));
489
490#if wxUSE_ACCEL
491 //
492 // Remove the corresponding accel from the accel table
493 //
494 int n = FindAccel(pItem->GetId());
495
496 if (n != wxNOT_FOUND)
497 {
498 delete m_vAccels[n];
499 m_vAccels.RemoveAt(n);
500 }
501
502#endif // wxUSE_ACCEL
503 //
504 // Remove the item from the menu
505 //
506 ::WinSendMsg( GetHmenu()
507 ,MM_REMOVEITEM
508 ,MPFROM2SHORT(pItem->GetId(), TRUE)
509 ,(MPARAM)0
510 );
511 if (IsAttached() && GetMenuBar()->IsAttached())
512 {
513 //
514 // Otherwise, the chane won't be visible
515 //
516 GetMenuBar()->Refresh();
517 }
518
519 //
520 // And from internal data structures
521 //
522 return wxMenuBase::DoRemove(pItem);
523} // end of wxMenu::DoRemove
524
525// ---------------------------------------------------------------------------
526// accelerator helpers
527// ---------------------------------------------------------------------------
528
529#if wxUSE_ACCEL
530
531//
532// Create the wxAcceleratorEntries for our accels and put them into provided
533// array - return the number of accels we have
534//
535size_t wxMenu::CopyAccels(
536 wxAcceleratorEntry* pAccels
537) const
538{
539 size_t nCount = GetAccelCount();
540
541 for (size_t n = 0; n < nCount; n++)
542 {
543 *pAccels++ = *m_vAccels[n];
544 }
545 return nCount;
546} // end of wxMenu::CopyAccels
547
548#endif // wxUSE_ACCEL
549
550// ---------------------------------------------------------------------------
551// set wxMenu title
552// ---------------------------------------------------------------------------
553
554void wxMenu::SetTitle( const wxString& rLabel )
555{
556 bool bHasNoTitle = m_title.empty();
557 HWND hMenu = GetHmenu();
558
559 m_title = rLabel;
560 if (bHasNoTitle)
561 {
562 if (!rLabel.empty())
563 {
564 if (!::WinSetWindowText(hMenu, (PSZ)rLabel.c_str()))
565 {
566 wxLogLastError(wxT("SetMenuTitle"));
567 }
568 }
569 }
570 else
571 {
572 if (rLabel.empty() )
573 {
574 ::WinSendMsg( GetHmenu()
575 ,MM_REMOVEITEM
576 ,MPFROM2SHORT(hMenu, TRUE)
577 ,(MPARAM)0
578 );
579 }
580 else
581 {
582 //
583 // Modify the title
584 //
585 if (!::WinSetWindowText(hMenu, (PSZ)rLabel.c_str()))
586 {
587 wxLogLastError(wxT("SetMenuTitle"));
588 }
589 }
590 }
591} // end of wxMenu::SetTitle
592
593// ---------------------------------------------------------------------------
594// event processing
595// ---------------------------------------------------------------------------
596
597bool wxMenu::OS2Command(
598 WXUINT WXUNUSED(uParam)
599, WXWORD vId
600)
601{
602 //
603 // Ignore commands from the menu title
604 //
605
606 if (vId != (WXWORD)idMenuTitle)
607 {
608 SendEvent( vId
609 ,(int)::WinSendMsg( GetHmenu()
610 ,MM_QUERYITEMATTR
611 ,MPFROMSHORT(vId)
612 ,(MPARAM)MIA_CHECKED
613 )
614 );
615 }
616 return TRUE;
617} // end of wxMenu::OS2Command
618
619// ---------------------------------------------------------------------------
620// other
621// ---------------------------------------------------------------------------
622
623wxWindow* wxMenu::GetWindow() const
624{
625 if (m_invokingWindow != NULL)
626 return m_invokingWindow;
627 else if ( GetMenuBar() != NULL)
628 return GetMenuBar()->GetFrame();
629
630 return NULL;
631} // end of wxMenu::GetWindow
632
633// recursive search for item by id
634wxMenuItem* wxMenu::FindItem(
635 int nItemId
636, ULONG hItem
637, wxMenu** ppItemMenu
638) const
639{
640 if ( ppItemMenu )
641 *ppItemMenu = NULL;
642
643 wxMenuItem* pItem = NULL;
644
645 for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
646 node && !pItem;
647 node = node->GetNext() )
648 {
649 pItem = node->GetData();
650
651 if ( pItem->GetId() == nItemId && pItem->m_vMenuData.hItem == hItem)
652 {
653 if ( ppItemMenu )
654 *ppItemMenu = (wxMenu *)this;
655 }
656 else if ( pItem->IsSubMenu() )
657 {
658 pItem = pItem->GetSubMenu()->FindItem( nItemId
659 ,hItem
660 ,ppItemMenu
661 );
662 if (pItem)
663 break;
664 }
665 else
666 {
667 // don't exit the loop
668 pItem = NULL;
669 }
670 }
671 return pItem;
672} // end of wxMenu::FindItem
673
674// ---------------------------------------------------------------------------
675// Menu Bar
676// ---------------------------------------------------------------------------
677
678void wxMenuBar::Init()
679{
680 m_eventHandler = this;
681 m_menuBarFrame = NULL;
682 m_hMenu = 0;
683} // end of wxMenuBar::Init
684
685wxMenuBar::wxMenuBar()
686{
687 Init();
688} // end of wxMenuBar::wxMenuBar
689
690wxMenuBar::wxMenuBar(
691 long WXUNUSED(lStyle)
692)
693{
694 Init();
695} // end of wxMenuBar::wxMenuBar
696
697wxMenuBar::wxMenuBar(
698 int nCount
699, wxMenu* vMenus[]
700, const wxString sTitles[]
701, long WXUNUSED(lStyle)
702)
703{
704 Init();
705
706 m_titles.Alloc(nCount);
707 for ( int i = 0; i < nCount; i++ )
708 {
709 m_menus.Append(vMenus[i]);
710 m_titles.Add(sTitles[i]);
711 vMenus[i]->Attach(this);
712 }
713} // end of wxMenuBar::wxMenuBar
714
715wxMenuBar::~wxMenuBar()
716{
717 //
718 // We should free PM's resources only if PM doesn't do it for us
719 // which happens if we're attached to a frame
720 //
721 if (m_hMenu && !IsAttached())
722 {
723 ::WinDestroyWindow((HMENU)m_hMenu);
724 m_hMenu = (WXHMENU)NULL;
725 }
726} // end of wxMenuBar::~wxMenuBar
727
728// ---------------------------------------------------------------------------
729// wxMenuBar helpers
730// ---------------------------------------------------------------------------
731
732void wxMenuBar::Refresh()
733{
734 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
735
736 WinSendMsg(GetWinHwnd(m_menuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
737} // end of wxMenuBar::Refresh
738
739WXHMENU wxMenuBar::Create()
740{
741 HWND hFrame;
742
743 if (m_hMenu != 0 )
744 return m_hMenu;
745
746 wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
747
748 //
749 // Menubars should be associated with a frame otherwise they are popups
750 //
751 if (m_menuBarFrame != NULL)
752 hFrame = GetWinHwnd(m_menuBarFrame);
753 else
754 hFrame = HWND_DESKTOP;
755 //
756 // Create an empty menu and then fill it with insertions
757 //
758 if ((m_hMenu = ::WinCreateWindow( hFrame
759 ,WC_MENU
760 ,(PSZ)NULL
761 ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
762 ,0L
763 ,0L
764 ,0L
765 ,0L
766 ,hFrame
767 ,HWND_TOP
768 ,FID_MENU
769 ,NULL
770 ,NULL
771 )) == 0)
772 {
773 wxLogLastError(wxT("WinLoadMenu"));
774 }
775 else
776 {
777 size_t nCount = GetMenuCount(), i;
778 wxMenuList::iterator it;
779 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
780 {
781 APIRET rc;
782 ERRORID vError;
783 wxString sError;
784 HWND hSubMenu;
785
786 //
787 // Set the parent and owner of the submenues to be the menubar, not the desktop
788 //
789 hSubMenu = (*it)->m_vMenuData.hwndSubMenu;
790 if (!::WinSetParent((*it)->m_vMenuData.hwndSubMenu, m_hMenu, FALSE))
791 {
792 vError = ::WinGetLastError(vHabmain);
793 sError = wxPMErrorToStr(vError);
794 wxLogError(wxT("Error setting parent for submenu. Error: %s\n"), sError.c_str());
795 return NULLHANDLE;
796 }
797
798 if (!::WinSetOwner((*it)->m_vMenuData.hwndSubMenu, m_hMenu))
799 {
800 vError = ::WinGetLastError(vHabmain);
801 sError = wxPMErrorToStr(vError);
802 wxLogError(wxT("Error setting parent for submenu. Error: %s\n"), sError.c_str());
803 return NULLHANDLE;
804 }
805
806 (*it)->m_vMenuData.iPosition = (SHORT)i;
807
808 rc = (APIRET)::WinSendMsg(m_hMenu, MM_INSERTITEM, (MPARAM)&(*it)->m_vMenuData, (MPARAM)m_titles[i].c_str());
809 if (rc == (APIRET)MIT_MEMERROR || rc == (APIRET)MIT_ERROR)
810 {
811 vError = ::WinGetLastError(vHabmain);
812 sError = wxPMErrorToStr(vError);
813 wxLogError(wxT("Error inserting or appending a menuitem. Error: %s\n"), sError.c_str());
814 return NULLHANDLE;
815 }
816 }
817 }
818 return m_hMenu;
819} // end of wxMenuBar::Create
820
821// ---------------------------------------------------------------------------
822// wxMenuBar functions to work with the top level submenus
823// ---------------------------------------------------------------------------
824
825//
826// NB: we don't support owner drawn top level items for now, if we do these
827// functions would have to be changed to use wxMenuItem as well
828//
829void wxMenuBar::EnableTop(
830 size_t nPos
831, bool bEnable
832)
833{
834 wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
835 USHORT uFlag = 0;
836 SHORT nId;
837
838 if(!bEnable)
839 uFlag = MIA_DISABLED;
840
841 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
842 if (nId == MIT_ERROR)
843 {
844 wxLogLastError(wxT("LogLastError"));
845 return;
846 }
847 ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(MIA_DISABLED, uFlag));
848 Refresh();
849} // end of wxMenuBar::EnableTop
850
851void wxMenuBar::SetLabelTop(
852 size_t nPos
853, const wxString& rLabel
854)
855{
856 SHORT nId;
857 MENUITEM vItem;
858
859 wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
860 m_titles[nPos] = rLabel;
861
862 if (!IsAttached())
863 {
864 return;
865 }
866
867 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
868 if (nId == MIT_ERROR)
869 {
870 wxLogLastError(wxT("LogLastError"));
871 return;
872 }
873 if(!::WinSendMsg( (HWND)m_hMenu
874 ,MM_QUERYITEM
875 ,MPFROM2SHORT(nId, TRUE)
876 ,MPARAM(&vItem)
877 ))
878 {
879 wxLogLastError(wxT("QueryItem"));
880 }
881 nId = vItem.id;
882
883 if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
884 {
885 wxLogLastError(wxT("ModifyMenu"));
886 }
887 Refresh();
888} // end of wxMenuBar::SetLabelTop
889
890wxString wxMenuBar::GetLabelTop(
891 size_t nPos
892) const
893{
894 wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
895 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
896 return m_titles[nPos];
897} // end of wxMenuBar::GetLabelTop
898
899// ---------------------------------------------------------------------------
900// wxMenuBar construction
901// ---------------------------------------------------------------------------
902
903wxMenu* wxMenuBar::Replace(
904 size_t nPos
905, wxMenu* pMenu
906, const wxString& rTitle
907)
908{
909 SHORT nId;
910 wxString sTitle = wxPMTextToLabel(rTitle);
911 wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
912 ,pMenu
913 ,sTitle
914 );
915
916
917 nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
918 if (nId == MIT_ERROR)
919 {
920 wxLogLastError(wxT("LogLastError"));
921 return NULL;
922 }
923 if (!pMenuOld)
924 return NULL;
925 m_titles[nPos] = sTitle;
926 if (IsAttached())
927 {
928 ::WinSendMsg((HWND)m_hMenu, MM_REMOVEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
929 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
930
931#if wxUSE_ACCEL
932 if (pMenuOld->HasAccels() || pMenu->HasAccels())
933 {
934 //
935 // Need to rebuild accell table
936 //
937 RebuildAccelTable();
938 }
939#endif // wxUSE_ACCEL
940 Refresh();
941 }
942 return pMenuOld;
943} // end of wxMenuBar::Replace
944
945bool wxMenuBar::Insert( size_t nPos,
946 wxMenu* pMenu,
947 const wxString& rTitle )
948{
949 wxString sTitle = wxPMTextToLabel(rTitle);
950
951 if (!wxMenuBarBase::Insert( nPos, pMenu, sTitle ))
952 return false;
953
954 m_titles.Insert( sTitle, nPos );
955
956 if (IsAttached())
957 {
958 pMenu->m_vMenuData.iPosition = (SHORT)nPos;
959 ::WinSendMsg( (HWND)m_hMenu
960 ,MM_INSERTITEM
961 ,(MPARAM)&pMenu->m_vMenuData
962 ,(MPARAM)sTitle.c_str()
963 );
964#if wxUSE_ACCEL
965 if (pMenu->HasAccels())
966 {
967 // need to rebuild accell table
968 RebuildAccelTable();
969 }
970#endif // wxUSE_ACCEL
971 Refresh();
972 }
973
974 return true;
975} // end of wxMenuBar::Insert
976
977bool wxMenuBar::Append(
978 wxMenu* pMenu
979, const wxString& rsTitle
980)
981{
982 WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
983
984 wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
985
986 wxString sTitle = wxPMTextToLabel(rsTitle);
987
988 if (!wxMenuBarBase::Append(pMenu, sTitle))
989 return FALSE;
990
991 m_titles.Add(sTitle);
992
993 if ( IsAttached() )
994 {
995 pMenu->m_vMenuData.iPosition = MIT_END;
996 ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
997#if wxUSE_ACCEL
998 if (pMenu->HasAccels())
999 {
1000 //
1001 // Need to rebuild accell table
1002 //
1003 RebuildAccelTable();
1004 }
1005#endif // wxUSE_ACCEL
1006 Refresh();
1007 }
1008 return TRUE;
1009} // end of wxMenuBar::Append
1010
1011wxMenu* wxMenuBar::Remove(
1012 size_t nPos
1013)
1014{
1015 wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
1016 SHORT nId;
1017
1018 if (!pMenu)
1019 return NULL;
1020
1021 nId = SHORT1FROMMR(::WinSendMsg( (HWND)GetHmenu()
1022 ,MM_ITEMIDFROMPOSITION
1023 ,MPFROMSHORT(nPos)
1024 ,(MPARAM)0)
1025 );
1026 if (nId == MIT_ERROR)
1027 {
1028 wxLogLastError(wxT("LogLastError"));
1029 return NULL;
1030 }
1031 if (IsAttached())
1032 {
1033 ::WinSendMsg( (HWND)GetHmenu()
1034 ,MM_REMOVEITEM
1035 ,MPFROM2SHORT(nId, TRUE)
1036 ,(MPARAM)0
1037 );
1038
1039#if wxUSE_ACCEL
1040 if (pMenu->HasAccels())
1041 {
1042 //
1043 // Need to rebuild accell table
1044 //
1045 RebuildAccelTable();
1046 }
1047#endif // wxUSE_ACCEL
1048 Refresh();
1049 }
1050 m_titles.RemoveAt(nPos);
1051 return pMenu;
1052} // end of wxMenuBar::Remove
1053
1054#if wxUSE_ACCEL
1055
1056void wxMenuBar::RebuildAccelTable()
1057{
1058 //
1059 // Merge the accelerators of all menus into one accel table
1060 //
1061 size_t nAccelCount = 0;
1062 size_t i;
1063 size_t nCount = GetMenuCount();
1064 wxMenuList::iterator it;
1065 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
1066 {
1067 nAccelCount += (*it)->GetAccelCount();
1068 }
1069
1070 if (nAccelCount)
1071 {
1072 wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
1073
1074 nAccelCount = 0;
1075 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
1076 {
1077 nAccelCount += (*it)->CopyAccels(&pAccelEntries[nAccelCount]);
1078 }
1079 m_vAccelTable = wxAcceleratorTable( nAccelCount
1080 ,pAccelEntries
1081 );
1082 delete [] pAccelEntries;
1083 }
1084} // end of wxMenuBar::RebuildAccelTable
1085
1086#endif // wxUSE_ACCEL
1087
1088void wxMenuBar::Attach(
1089 wxFrame* pFrame
1090)
1091{
1092 wxMenuBarBase::Attach(pFrame);
1093
1094#if wxUSE_ACCEL
1095 RebuildAccelTable();
1096 //
1097 // Ensure the accelerator table is set to the frame (not the client!)
1098 //
1099 if (!::WinSetAccelTable( vHabmain
1100 ,m_vAccelTable.GetHACCEL()
1101 ,(HWND)pFrame->GetFrame()
1102 ))
1103 wxLogLastError(wxT("WinSetAccelTable"));
1104#endif // wxUSE_ACCEL
1105} // end of wxMenuBar::Attach
1106
1107void wxMenuBar::Detach()
1108{
1109 ::WinDestroyWindow((HWND)m_hMenu);
1110 m_hMenu = (WXHMENU)NULL;
1111 m_menuBarFrame = NULL;
1112} // end of wxMenuBar::Detach
1113
1114// ---------------------------------------------------------------------------
1115// wxMenuBar searching for menu items
1116// ---------------------------------------------------------------------------
1117
1118//
1119// Find the itemString in menuString, and return the item id or wxNOT_FOUND
1120//
1121int wxMenuBar::FindMenuItem(
1122 const wxString& rMenuString
1123, const wxString& rItemString
1124) const
1125{
1126 wxString sMenuLabel = wxStripMenuCodes(rMenuString);
1127 size_t nCount = GetMenuCount(), i;
1128 wxMenuList::const_iterator it;
1129 for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
1130 {
1131 wxString sTitle = wxStripMenuCodes(m_titles[i]);
1132
1133 if (rMenuString == sTitle)
1134 return (*it)->FindItem(rItemString);
1135 }
1136 return wxNOT_FOUND;
1137} // end of wxMenuBar::FindMenuItem
1138
1139wxMenuItem* wxMenuBar::FindItem(
1140 int nId
1141, wxMenu** ppItemMenu
1142) const
1143{
1144 if (ppItemMenu)
1145 *ppItemMenu = NULL;
1146
1147 wxMenuItem* pItem = NULL;
1148 size_t nCount = GetMenuCount(), i;
1149 wxMenuList::const_iterator it;
1150 for (i = 0, it = m_menus.begin(); !pItem && (i < nCount); i++, it++)
1151 {
1152 pItem = (*it)->FindItem( nId
1153 ,ppItemMenu
1154 );
1155 }
1156 return pItem;
1157} // end of wxMenuBar::FindItem
1158
1159wxMenuItem* wxMenuBar::FindItem(
1160 int nId
1161, ULONG hItem
1162, wxMenu** ppItemMenu
1163) const
1164{
1165 if (ppItemMenu)
1166 *ppItemMenu = NULL;
1167
1168 wxMenuItem* pItem = NULL;
1169 size_t nCount = GetMenuCount(), i;
1170 wxMenuList::const_iterator it;
1171 for (i = 0, it = m_menus.begin(); !pItem && (i < nCount); i++, it++)
1172 {
1173 pItem = (*it)->FindItem( nId
1174 ,hItem
1175 ,ppItemMenu
1176 );
1177 }
1178 return pItem;
1179} // end of wxMenuBar::FindItem