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