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