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