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