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