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