]> git.saurik.com Git - wxWidgets.git/blob - src/os2/menu.cpp
Do not allow events to fire after socket is closed (fixes crash on GTK with GDK_Input...
[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 // 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
37 extern wxMenu* wxCurrentPopupMenu;
38
39 // ----------------------------------------------------------------------------
40 // constants
41 // ----------------------------------------------------------------------------
42
43 //
44 // The (popup) menu title has this special id
45 //
46 static const int idMenuTitle = -3;
47
48 //
49 // The unique ID for Menus
50 //
51 USHORT 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 //
71 void 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 //
120 wxMenu::~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
142 void wxMenu::Break()
143 {
144 // this will take effect during the next call to Append()
145 m_bDoBreak = true;
146 } // end of wxMenu::Break
147
148 void wxMenu::Attach(
149 wxMenuBarBase* pMenubar
150 )
151 {
152 wxMenuBase::Attach(pMenubar);
153 EndRadioGroup();
154 } // end of wxMenu::Break;
155
156 #if wxUSE_ACCEL
157
158 int 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
171 void 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 //
247 bool 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
379 void 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
387 wxMenuItem* 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
453 wxMenuItem* 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
468 wxMenuItem* 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 //
535 size_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
554 void 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
597 bool 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
623 wxWindow* 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
634 wxMenuItem* 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
678 void wxMenuBar::Init()
679 {
680 m_eventHandler = this;
681 m_menuBarFrame = NULL;
682 m_hMenu = 0;
683 } // end of wxMenuBar::Init
684
685 wxMenuBar::wxMenuBar()
686 {
687 Init();
688 } // end of wxMenuBar::wxMenuBar
689
690 wxMenuBar::wxMenuBar(
691 long WXUNUSED(lStyle)
692 )
693 {
694 Init();
695 } // end of wxMenuBar::wxMenuBar
696
697 wxMenuBar::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
715 wxMenuBar::~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
732 void 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
739 WXHMENU 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 //
829 void 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
851 void 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
890 wxString 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
903 wxMenu* 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
945 bool 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
977 bool 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
1011 wxMenu* 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
1056 void 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
1088 void 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
1107 void 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 //
1121 int 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
1139 wxMenuItem* 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
1159 wxMenuItem* 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