]>
git.saurik.com Git - wxWidgets.git/blob - src/univ/menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxMenuItem, wxMenu and wxMenuBar implementation
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2000 Vadim Zeitlin
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "univmenuitem.h"
22 #pragma implementation "univmenu.h"
25 #include "wx/wxprec.h"
32 #include "wx/dynarray.h"
33 #include "wx/control.h" // for FindAccelIndex()
35 #include "wx/settings.h"
42 #include "wx/popupwin.h"
43 #include "wx/evtloop.h"
45 #include "wx/univ/renderer.h"
48 #include "wx/msw/private.h"
51 // ----------------------------------------------------------------------------
52 // wxMenuInfo contains all extra information about top level menus we need
53 // ----------------------------------------------------------------------------
55 class WXDLLEXPORT wxMenuInfo
59 wxMenuInfo(const wxString
& text
)
67 void SetLabel(const wxString
& text
)
69 // remember the accel char (may be -1 if none)
70 m_indexAccel
= wxControl::FindAccelIndex(text
, &m_label
);
72 // calculate the width later, after the menu bar is created
76 void SetEnabled(bool enabled
= TRUE
) { m_isEnabled
= enabled
; }
80 const wxString
& GetLabel() const { return m_label
; }
81 bool IsEnabled() const { return m_isEnabled
; }
82 wxCoord
GetWidth(wxMenuBar
*menubar
) const
86 wxConstCast(this, wxMenuInfo
)->CalcWidth(menubar
);
92 int GetAccelIndex() const { return m_indexAccel
; }
95 void CalcWidth(wxMenuBar
*menubar
)
98 wxClientDC
dc(menubar
);
99 dc
.SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
100 dc
.GetTextExtent(m_label
, &size
.x
, &size
.y
);
102 // adjust for the renderer we use and store the width
103 m_width
= menubar
->GetRenderer()->GetMenuBarItemSize(size
).x
;
112 #include "wx/arrimpl.cpp"
114 WX_DEFINE_OBJARRAY(wxMenuInfoArray
);
116 // ----------------------------------------------------------------------------
117 // wxPopupMenuWindow: a popup window showing a menu
118 // ----------------------------------------------------------------------------
120 class wxPopupMenuWindow
: public wxPopupTransientWindow
123 wxPopupMenuWindow(wxWindow
*parent
, wxMenu
*menu
);
125 // override the base class version to select the first item initially
126 virtual void Popup(wxWindow
*focus
= NULL
);
128 // override the base class version to dismiss any open submenus
129 virtual void Dismiss();
131 // notify the menu when the window disappears from screen
132 virtual void OnDismiss();
134 // called when a submenu is dismissed
135 void OnSubmenuDismiss() { m_hasOpenSubMenu
= FALSE
; }
137 // get the currently selected item (may be NULL)
138 wxMenuItem
*GetCurrentItem() const
140 return m_nodeCurrent
? m_nodeCurrent
->GetData() : NULL
;
143 // find the menu item at given position
144 wxMenuItemList::Node
*GetMenuItemFromPoint(const wxPoint
& pt
) const;
146 // refresh the given item
147 void RefreshItem(wxMenuItem
*item
);
149 // preselect the first item
150 void SelectFirst() { SetCurrent(m_menu
->GetMenuItems().GetFirst()); }
152 // process the key event, return TRUE if done
153 bool ProcessKeyDown(int key
);
155 // process mouse move event
156 void ProcessMouseMove(const wxPoint
& pt
);
158 // don't dismiss the popup window if the parent menu was clicked
159 virtual bool ProcessLeftDown(wxMouseEvent
& event
);
162 // how did we perform this operation?
169 // draw the menu inside this window
170 virtual void DoDraw(wxControlRenderer
*renderer
);
173 void OnLeftUp(wxMouseEvent
& event
);
174 void OnMouseMove(wxMouseEvent
& event
);
175 void OnMouseLeave(wxMouseEvent
& event
);
176 void OnKeyDown(wxKeyEvent
& event
);
178 // reset the current item and node
181 // set the current node and item withotu refreshing anything
182 void SetCurrent(wxMenuItemList::Node
*node
);
184 // change the current item refreshing the old and new items
185 void ChangeCurrent(wxMenuItemList::Node
*node
);
187 // activate item, i.e. call either ClickItem() or OpenSubmenu() depending
188 // on what it is, return TRUE if something was done (i.e. it's not a
190 bool ActivateItem(wxMenuItem
*item
, InputMethod how
= WithKeyboard
);
192 // send the event about the item click
193 void ClickItem(wxMenuItem
*item
);
195 // show the submenu for this item
196 void OpenSubmenu(wxMenuItem
*item
, InputMethod how
= WithKeyboard
);
198 // can this tiem be opened?
199 bool CanOpen(wxMenuItem
*item
)
201 return item
&& item
->IsEnabled() && item
->IsSubMenu();
204 // dismiss the menu and all parent menus too
205 void DismissAndNotify();
207 // react to dimissing this menu and also dismiss the parent if
209 void HandleDismiss(bool dismissParent
);
211 // do we have an open submenu?
212 bool HasOpenSubmenu() const { return m_hasOpenSubMenu
; }
214 // get previous node after the current one
215 wxMenuItemList::Node
*GetPrevNode() const;
217 // get previous node before the given one, wrapping if it's the first one
218 wxMenuItemList::Node
*GetPrevNode(wxMenuItemList::Node
*node
) const;
220 // get next node after the current one
221 wxMenuItemList::Node
*GetNextNode() const;
223 // get next node after the given one, wrapping if it's the last one
224 wxMenuItemList::Node
*GetNextNode(wxMenuItemList::Node
*node
) const;
230 // the menu node corresponding to the current item
231 wxMenuItemList::Node
*m_nodeCurrent
;
233 // do we currently have an opened submenu?
234 bool m_hasOpenSubMenu
;
236 DECLARE_EVENT_TABLE()
239 // ----------------------------------------------------------------------------
240 // wxMenuKbdRedirector: an event handler which redirects kbd input to wxMenu
241 // ----------------------------------------------------------------------------
243 class wxMenuKbdRedirector
: public wxEvtHandler
246 wxMenuKbdRedirector(wxMenu
*menu
) { m_menu
= menu
; }
248 virtual bool ProcessEvent(wxEvent
& event
)
250 if ( event
.GetEventType() == wxEVT_KEY_DOWN
)
252 return m_menu
->ProcessKeyDown(((wxKeyEvent
&)event
).GetKeyCode());
256 return wxEvtHandler::ProcessEvent(event
);
264 // ----------------------------------------------------------------------------
266 // ----------------------------------------------------------------------------
268 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
269 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxWindow
)
270 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
)
272 BEGIN_EVENT_TABLE(wxPopupMenuWindow
, wxPopupTransientWindow
)
273 EVT_KEY_DOWN(wxPopupMenuWindow::OnKeyDown
)
275 EVT_LEFT_UP(wxPopupMenuWindow::OnLeftUp
)
276 EVT_MOTION(wxPopupMenuWindow::OnMouseMove
)
277 EVT_LEAVE_WINDOW(wxPopupMenuWindow::OnMouseLeave
)
280 BEGIN_EVENT_TABLE(wxMenuBar
, wxMenuBarBase
)
281 EVT_KILL_FOCUS(wxMenuBar::OnKillFocus
)
283 EVT_KEY_DOWN(wxMenuBar::OnKeyDown
)
285 EVT_LEFT_DOWN(wxMenuBar::OnLeftDown
)
286 EVT_MOTION(wxMenuBar::OnMouseMove
)
289 // ============================================================================
291 // ============================================================================
293 // ----------------------------------------------------------------------------
295 // ----------------------------------------------------------------------------
297 wxPopupMenuWindow::wxPopupMenuWindow(wxWindow
*parent
, wxMenu
*menu
)
300 m_hasOpenSubMenu
= FALSE
;
304 (void)Create(parent
, wxBORDER_RAISED
);
306 SetCursor(wxCURSOR_ARROW
);
309 // ----------------------------------------------------------------------------
310 // wxPopupMenuWindow current item/node handling
311 // ----------------------------------------------------------------------------
313 void wxPopupMenuWindow::ResetCurrent()
318 void wxPopupMenuWindow::SetCurrent(wxMenuItemList::Node
*node
)
320 m_nodeCurrent
= node
;
323 void wxPopupMenuWindow::ChangeCurrent(wxMenuItemList::Node
*node
)
325 if ( node
!= m_nodeCurrent
)
329 wxMenuItem
*item
= m_nodeCurrent
->GetData();
330 wxCHECK_RET( item
, _T("no current item?") );
332 // if it was the currently opened menu, close it
333 if ( item
->IsSubMenu() && item
->GetSubMenu()->IsShown() )
335 item
->GetSubMenu()->Dismiss();
342 m_nodeCurrent
= node
;
345 RefreshItem(m_nodeCurrent
->GetData());
349 wxMenuItemList::Node
*wxPopupMenuWindow::GetPrevNode() const
351 wxMenuItemList::Node
*node
= m_nodeCurrent
;
354 // start from the end if no current item
355 node
= m_menu
->GetMenuItems().GetLast();
358 return GetPrevNode(node
);
361 wxMenuItemList::Node
*
362 wxPopupMenuWindow::GetPrevNode(wxMenuItemList::Node
*node
) const
366 node
= node
->GetPrevious();
369 node
= m_menu
->GetMenuItems().GetLast();
372 //else: the menu is empty
377 wxMenuItemList::Node
*wxPopupMenuWindow::GetNextNode() const
379 wxMenuItemList::Node
*node
= m_nodeCurrent
;
382 // start from the beginning if no current item
383 node
= m_menu
->GetMenuItems().GetFirst();
386 return GetNextNode(node
);
389 wxMenuItemList::Node
*
390 wxPopupMenuWindow::GetNextNode(wxMenuItemList::Node
*node
) const
394 node
= node
->GetNext();
397 node
= m_menu
->GetMenuItems().GetFirst();
400 //else: the menu is empty
405 // ----------------------------------------------------------------------------
406 // wxPopupMenuWindow popup/dismiss
407 // ----------------------------------------------------------------------------
409 void wxPopupMenuWindow::Popup(wxWindow
*focus
)
411 // check that the current item had been properly reset before
412 wxASSERT_MSG( !m_nodeCurrent
||
413 m_nodeCurrent
== m_menu
->GetMenuItems().GetFirst(),
414 _T("menu current item preselected incorrectly") );
416 wxPopupTransientWindow::Popup(focus
);
419 // ensure that this window is really on top of everything: without using
420 // SetWindowPos() it can be covered by its parent menu which is not
421 // really what we want
422 wxMenu
*menuParent
= m_menu
->GetParent();
425 wxPopupMenuWindow
*win
= menuParent
->m_popupMenu
;
427 // if we're shown, the parent menu must be also shown
428 wxCHECK_RET( win
, _T("parent menu is not shown?") );
430 if ( !::SetWindowPos(GetHwndOf(win
), GetHwnd(),
432 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOREDRAW
) )
434 wxLogLastError(_T("SetWindowPos(HWND_TOP)"));
442 void wxPopupMenuWindow::Dismiss()
444 if ( HasOpenSubmenu() )
446 wxMenuItem
*item
= GetCurrentItem();
447 wxCHECK_RET( item
&& item
->IsSubMenu(), _T("where is our open submenu?") );
449 wxPopupMenuWindow
*win
= item
->GetSubMenu()->m_popupMenu
;
450 wxCHECK_RET( win
, _T("opened submenu is not opened?") );
456 wxPopupTransientWindow::Dismiss();
459 void wxPopupMenuWindow::OnDismiss()
461 // when we are dismissed because the user clicked elsewhere or we lost
462 // focus in any other way, hide the parent menu as well
466 void wxPopupMenuWindow::HandleDismiss(bool dismissParent
)
470 m_menu
->OnDismiss(dismissParent
);
473 void wxPopupMenuWindow::DismissAndNotify()
479 // ----------------------------------------------------------------------------
480 // wxPopupMenuWindow geometry
481 // ----------------------------------------------------------------------------
483 wxMenuItemList::Node
*
484 wxPopupMenuWindow::GetMenuItemFromPoint(const wxPoint
& pt
) const
486 // we only use the y coord normally, but still check x in case the point is
487 // outside the window completely
488 if ( wxWindow::HitTest(pt
) == wxHT_WINDOW_INSIDE
)
491 for ( wxMenuItemList::Node
*node
= m_menu
->GetMenuItems().GetFirst();
493 node
= node
->GetNext() )
495 wxMenuItem
*item
= node
->GetData();
496 y
+= item
->GetHeight();
508 // ----------------------------------------------------------------------------
509 // wxPopupMenuWindow drawing
510 // ----------------------------------------------------------------------------
512 void wxPopupMenuWindow::RefreshItem(wxMenuItem
*item
)
514 wxCHECK_RET( item
, _T("can't refresh NULL item") );
516 wxASSERT_MSG( IsShown(), _T("can't refresh menu which is not shown") );
518 // FIXME: -1 here because of SetLogicalOrigin(1, 1) in DoDraw()
519 RefreshRect(wxRect(0, item
->GetPosition() - 1,
520 m_menu
->GetGeometryInfo().GetSize().x
, item
->GetHeight()));
523 void wxPopupMenuWindow::DoDraw(wxControlRenderer
*renderer
)
525 // no clipping so far - do we need it? I don't think so as the menu is
526 // never partially covered as it is always on top of everything
528 wxDC
& dc
= renderer
->GetDC();
529 dc
.SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
531 // FIXME: this should be done in the renderer, however when it is fixed
532 // wxPopupMenuWindow::RefreshItem() should be changed too!
533 dc
.SetLogicalOrigin(1, 1);
535 wxRenderer
*rend
= renderer
->GetRenderer();
538 const wxMenuGeometryInfo
& gi
= m_menu
->GetGeometryInfo();
539 for ( wxMenuItemList::Node
*node
= m_menu
->GetMenuItems().GetFirst();
541 node
= node
->GetNext() )
543 wxMenuItem
*item
= node
->GetData();
545 if ( item
->IsSeparator() )
547 rend
->DrawMenuSeparator(dc
, y
, gi
);
549 else // not a separator
552 if ( item
->IsCheckable() )
554 flags
|= wxCONTROL_CHECKABLE
;
556 if ( item
->IsChecked() )
558 flags
|= wxCONTROL_CHECKED
;
562 if ( !item
->IsEnabled() )
563 flags
|= wxCONTROL_DISABLED
;
565 if ( item
->IsSubMenu() )
566 flags
|= wxCONTROL_ISSUBMENU
;
568 if ( item
== GetCurrentItem() )
569 flags
|= wxCONTROL_SELECTED
;
577 item
->GetAccelString(),
578 // strangely enough, for unchecked item we use the
579 // "checked" bitmap because this is the default one - this
580 // explains this strange boolean expression
581 item
->GetBitmap(!item
->IsCheckable() || item
->IsChecked()),
583 item
->GetAccelIndex()
587 y
+= item
->GetHeight();
591 // ----------------------------------------------------------------------------
592 // wxPopupMenuWindow actions
593 // ----------------------------------------------------------------------------
595 void wxPopupMenuWindow::ClickItem(wxMenuItem
*item
)
597 wxCHECK_RET( item
, _T("can't click NULL item") );
599 wxASSERT_MSG( !item
->IsSeparator() && !item
->IsSubMenu(),
600 _T("can't click this item") );
602 m_menu
->ClickItem(item
);
608 void wxPopupMenuWindow::OpenSubmenu(wxMenuItem
*item
, InputMethod how
)
610 wxCHECK_RET( item
, _T("can't open NULL submenu") );
612 wxMenu
*submenu
= item
->GetSubMenu();
613 wxCHECK_RET( submenu
, _T("can only open submenus!") );
615 // FIXME: should take into account the border width
616 submenu
->Popup(ClientToScreen(wxPoint(0, item
->GetPosition())),
617 wxSize(m_menu
->GetGeometryInfo().GetSize().x
, 0),
618 how
== WithKeyboard
/* preselect first item then */);
620 m_hasOpenSubMenu
= TRUE
;
623 bool wxPopupMenuWindow::ActivateItem(wxMenuItem
*item
, InputMethod how
)
625 // don't activate disabled items
626 if ( !item
|| !item
->IsEnabled() )
631 // normal menu items generate commands, submenus can be opened and
632 // the separators don't do anything
633 if ( item
->IsSubMenu() )
635 OpenSubmenu(item
, how
);
637 else if ( !item
->IsSeparator() )
641 else // separator, can't activate
649 // ----------------------------------------------------------------------------
650 // wxPopupMenuWindow input handling
651 // ----------------------------------------------------------------------------
653 bool wxPopupMenuWindow::ProcessLeftDown(wxMouseEvent
& event
)
655 // wxPopupWindowHandler dismisses the window when the mouse is clicked
656 // outside it which is usually just fine, but there is one case when we
657 // don't want to do it: if the mouse was clicked on the parent submenu item
658 // which opens this menu, so check for it
660 wxPoint pos
= event
.GetPosition();
661 if ( HitTest(pos
.x
, pos
.y
) == wxHT_WINDOW_OUTSIDE
)
663 wxMenu
*menu
= m_menu
->GetParent();
666 wxPopupMenuWindow
*win
= menu
->m_popupMenu
;
668 wxCHECK_MSG( win
, FALSE
, _T("parent menu not shown?") );
670 pos
= ClientToScreen(pos
);
671 if ( win
->GetMenuItemFromPoint(win
->ScreenToClient(pos
)) )
676 //else: it is outside the parent menu as well, do dismiss this one
683 void wxPopupMenuWindow::OnLeftUp(wxMouseEvent
& event
)
685 wxMenuItemList::Node
*node
= GetMenuItemFromPoint(event
.GetPosition());
688 ActivateItem(node
->GetData(), WithMouse
);
692 void wxPopupMenuWindow::OnMouseMove(wxMouseEvent
& event
)
694 const wxPoint pt
= event
.GetPosition();
696 // we need to ignore extra mouse events: example when this happens is when
697 // the mouse is on the menu and we open a submenu from keyboard - Windows
698 // then sends us a dummy mouse move event, we (correctly) determine that it
699 // happens in the parent menu and so immediately close the just opened
702 static wxPoint s_ptLast
;
703 wxPoint ptCur
= ClientToScreen(pt
);
704 if ( ptCur
== s_ptLast
)
712 ProcessMouseMove(pt
);
717 void wxPopupMenuWindow::ProcessMouseMove(const wxPoint
& pt
)
719 wxMenuItemList::Node
*node
= GetMenuItemFromPoint(pt
);
721 // don't reset current to NULL here, we only do it when the mouse leaves
722 // the window (see below)
725 if ( node
!= m_nodeCurrent
)
729 wxMenuItem
*item
= GetCurrentItem();
732 OpenSubmenu(item
, WithMouse
);
735 //else: same item, nothing to do
737 else // not on an item
739 // the last open submenu forwards the mouse move messages to its
740 // parent, so if the mouse moves to another item of the parent menu,
741 // this menu is closed and this other item is selected - in the similar
742 // manner, the top menu forwards the mouse moves to the menubar which
743 // allows to select another top level menu by just moving the mouse
745 // we need to translate our client coords to the client coords of the
746 // window we forward this event to
747 wxPoint ptScreen
= ClientToScreen(pt
);
749 // if the mouse is outside this menu, let the parent one to
751 wxMenu
*menuParent
= m_menu
->GetParent();
754 wxPopupMenuWindow
*win
= menuParent
->m_popupMenu
;
756 // if we're shown, the parent menu must be also shown
757 wxCHECK_RET( win
, _T("parent menu is not shown?") );
759 win
->ProcessMouseMove(win
->ScreenToClient(ptScreen
));
761 else // no parent menu
763 wxMenuBar
*menubar
= m_menu
->GetMenuBar();
766 if ( menubar
->ProcessMouseEvent(
767 menubar
->ScreenToClient(ptScreen
)) )
769 // menubar has closed this menu and opened another one, probably
774 //else: top level popup menu, no other processing to do
778 void wxPopupMenuWindow::OnMouseLeave(wxMouseEvent
& event
)
780 // due to the artefact of mouse events generation under MSW, we actually
781 // may get the mouse leave event after the menu had been already dismissed
782 // and calling ChangeCurrent() would then assert, so don't do it
785 // we shouldn't change the current them if our submenu is opened and
786 // mouse moved there, in this case the submenu is responsable for
789 if ( HasOpenSubmenu() )
791 wxMenuItem
*item
= GetCurrentItem();
792 wxCHECK_RET( CanOpen(item
), _T("where is our open submenu?") );
794 wxPopupMenuWindow
*win
= item
->GetSubMenu()->m_popupMenu
;
795 wxCHECK_RET( win
, _T("submenu is opened but not shown?") );
797 // only handle this event if the mouse is not inside the submenu
798 wxPoint pt
= ClientToScreen(event
.GetPosition());
800 win
->HitTest(win
->ScreenToClient(pt
)) == wxHT_WINDOW_OUTSIDE
;
804 // this menu is the last opened
817 void wxPopupMenuWindow::OnKeyDown(wxKeyEvent
& event
)
819 if ( !ProcessKeyDown(event
.GetKeyCode()) )
825 bool wxPopupMenuWindow::ProcessKeyDown(int key
)
827 wxMenuItem
*item
= GetCurrentItem();
829 // first let the opened submenu to have it (no test for IsEnabled() here,
830 // the keys navigate even in a disabled submenu if we had somehow managed
831 // to open it inspit of this)
832 if ( HasOpenSubmenu() )
834 wxCHECK_MSG( CanOpen(item
), FALSE
,
835 _T("has open submenu but another item selected?") );
837 if ( item
->GetSubMenu()->ProcessKeyDown(key
) )
841 bool processed
= TRUE
;
843 // handle the up/down arrows, home, end, esc and return here, pass the
844 // left/right arrows to the menu bar except when the right arrow can be
845 // used to open a submenu
849 // if we're not a top level menu, close us, else leave this to the
851 if ( !m_menu
->GetParent() )
860 // close just this menu
862 HandleDismiss(FALSE
);
866 processed
= ActivateItem(item
);
870 ChangeCurrent(m_menu
->GetMenuItems().GetFirst());
874 ChangeCurrent(m_menu
->GetMenuItems().GetLast());
880 bool up
= key
== WXK_UP
;
882 wxMenuItemList::Node
*nodeStart
= up
? GetPrevNode()
885 while ( node
&& node
->GetData()->IsSeparator() )
887 node
= up
? GetPrevNode(node
) : GetNextNode(node
);
889 if ( node
== nodeStart
)
891 // nothing but separators and disabled items in this
909 // don't try to reopen an already opened menu
910 if ( !HasOpenSubmenu() && CanOpen(item
) )
921 // look for the menu item starting with this letter
922 if ( wxIsalnum(key
) )
924 // we want to start from the item after this one because
925 // if we're already on the item with the given accel we want to
926 // go to the next one, not to stay in place
927 wxMenuItemList::Node
*nodeStart
= GetNextNode();
929 // do we have more than one item with this accel?
930 bool notUnique
= FALSE
;
932 // translate everything to lower case before comparing
933 wxChar chAccel
= wxTolower(key
);
935 // loop through all items searching for the item with this
937 wxMenuItemList::Node
*node
= nodeStart
,
941 item
= node
->GetData();
943 int idxAccel
= item
->GetAccelIndex();
944 if ( idxAccel
!= -1 &&
945 wxTolower(item
->GetLabel()[(size_t)idxAccel
])
948 // ok, found an item with this accel
951 // store it but continue searching as we need to
952 // know if it's the only item with this accel or if
956 else // we already had found such item
960 // no need to continue further, we won't find
961 // anything we don't already know
966 // we want to iterate over all items wrapping around if
968 node
= GetNextNode(node
);
969 if ( node
== nodeStart
)
971 // we've seen all nodes
978 item
= nodeFound
->GetData();
980 // go to this item anyhow
981 ChangeCurrent(nodeFound
);
983 if ( !notUnique
&& item
->IsEnabled() )
985 // unique item with this accel - activate it
986 processed
= ActivateItem(item
);
988 //else: just select it but don't activate as the user might
989 // have wanted to activate another item
991 // skip "processed = FALSE" below
1002 // ----------------------------------------------------------------------------
1004 // ----------------------------------------------------------------------------
1019 // ----------------------------------------------------------------------------
1020 // wxMenu and wxMenuGeometryInfo
1021 // ----------------------------------------------------------------------------
1023 wxMenuGeometryInfo::~wxMenuGeometryInfo()
1027 const wxMenuGeometryInfo
& wxMenu::GetGeometryInfo() const
1033 wxConstCast(this, wxMenu
)->m_geometry
=
1034 m_popupMenu
->GetRenderer()->GetMenuGeometry(m_popupMenu
, *this);
1038 wxFAIL_MSG( _T("can't get geometry without window") );
1045 void wxMenu::InvalidateGeometryInfo()
1054 // ----------------------------------------------------------------------------
1055 // wxMenu adding/removing items
1056 // ----------------------------------------------------------------------------
1058 void wxMenu::OnItemAdded(wxMenuItem
*item
)
1060 InvalidateGeometryInfo();
1064 #endif // wxUSE_ACCEL
1066 // the submenus of a popup menu should have the same invoking window as it
1068 if ( m_invokingWindow
&& item
->IsSubMenu() )
1070 item
->GetSubMenu()->SetInvokingWindow(m_invokingWindow
);
1074 bool wxMenu::DoAppend(wxMenuItem
*item
)
1076 if ( !wxMenuBase::DoAppend(item
) )
1084 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
1086 if ( !wxMenuBase::DoInsert(pos
, item
) )
1094 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
1096 wxMenuItem
*itemOld
= wxMenuBase::DoRemove(item
);
1100 InvalidateGeometryInfo();
1103 RemoveAccelFor(item
);
1104 #endif // wxUSE_ACCEL
1110 // ----------------------------------------------------------------------------
1111 // wxMenu attaching/detaching
1112 // ----------------------------------------------------------------------------
1114 void wxMenu::Attach(wxMenuBarBase
*menubar
)
1116 wxMenuBase::Attach(menubar
);
1118 wxCHECK_RET( m_menuBar
, _T("menubar can't be NULL after attaching") );
1120 // unfortunately, we can't use m_menuBar->GetEventHandler() here because,
1121 // if the menubar is currently showing a menu, its event handler is a
1122 // temporary one installed by wxPopupWindow and so will disappear soon any
1123 // any attempts to use it from the newly attached menu would result in a
1126 // so we use the menubar itself, even if it's a pity as it means we can't
1127 // redirect all menu events by changing the menubar handler (FIXME)
1128 SetNextHandler(m_menuBar
);
1131 void wxMenu::Detach()
1133 wxMenuBase::Detach();
1136 // ----------------------------------------------------------------------------
1137 // wxMenu misc functions
1138 // ----------------------------------------------------------------------------
1140 wxWindow
*wxMenu::GetRootWindow() const
1144 // simple case - a normal menu attached to the menubar
1148 // we're a popup menu but the trouble is that only the top level popup menu
1149 // has a pointer to the invoking window, so we must walk up the menu chain
1151 wxWindow
*win
= GetInvokingWindow();
1154 // we already have it
1158 wxMenu
*menu
= GetParent();
1161 win
= menu
->GetInvokingWindow();
1165 menu
= menu
->GetParent();
1168 // we're probably going to crash in the caller anyhow, but try to detect
1169 // this error as soon as possible
1170 wxASSERT_MSG( win
, _T("menu without any associated window?") );
1172 // also remember it in this menu so that we don't have to search for it the
1174 wxConstCast(this, wxMenu
)->m_invokingWindow
= win
;
1179 wxRenderer
*wxMenu::GetRenderer() const
1181 // we're going to crash without renderer!
1182 wxCHECK_MSG( m_popupMenu
, NULL
, _T("neither popup nor menubar menu?") );
1184 return m_popupMenu
->GetRenderer();
1187 void wxMenu::RefreshItem(wxMenuItem
*item
)
1189 // the item geometry changed, so our might have changed as well
1190 InvalidateGeometryInfo();
1194 // this would be a bug in IsShown()
1195 wxCHECK_RET( m_popupMenu
, _T("must have popup window if shown!") );
1197 // recalc geometry to update the item height and such
1198 (void)GetGeometryInfo();
1200 m_popupMenu
->RefreshItem(item
);
1204 // ----------------------------------------------------------------------------
1205 // wxMenu showing and hiding
1206 // ----------------------------------------------------------------------------
1208 bool wxMenu::IsShown() const
1210 return m_popupMenu
&& m_popupMenu
->IsShown();
1213 void wxMenu::OnDismiss(bool dismissParent
)
1217 // always notify the parent about submenu disappearance
1218 wxPopupMenuWindow
*win
= m_menuParent
->m_popupMenu
;
1221 win
->OnSubmenuDismiss();
1225 wxFAIL_MSG( _T("parent menu not shown?") );
1228 // and if we dismiss everything, propagate to parent
1229 if ( dismissParent
)
1231 // dismissParent is recursive
1232 m_menuParent
->Dismiss();
1233 m_menuParent
->OnDismiss(TRUE
);
1236 else // no parent menu
1238 // notify the menu bar if we're a top level menu
1241 m_menuBar
->OnDismissMenu(dismissParent
);
1245 wxCHECK_RET( m_invokingWindow
, _T("what kind of menu is this?") );
1247 m_invokingWindow
->DismissPopupMenu();
1248 SetInvokingWindow(NULL
);
1253 void wxMenu::Popup(const wxPoint
& pos
, const wxSize
& size
, bool selectFirst
)
1255 // create the popup window if not done yet
1258 m_popupMenu
= new wxPopupMenuWindow(GetRootWindow(), this);
1261 // select the first item unless disabled
1264 m_popupMenu
->SelectFirst();
1267 // the geometry might have changed since the last time we were shown, so
1269 m_popupMenu
->SetClientSize(GetGeometryInfo().GetSize());
1271 // position it as specified
1272 m_popupMenu
->Position(pos
, size
);
1274 // the menu can't have the focus itself (it is a Windows limitation), so
1275 // always keep the focus at the originating window
1276 wxWindow
*focus
= GetRootWindow();
1278 wxASSERT_MSG( focus
, _T("no window to keep focus on?") );
1281 m_popupMenu
->Popup(focus
);
1284 void wxMenu::Dismiss()
1286 wxCHECK_RET( IsShown(), _T("can't dismiss hidden menu") );
1288 m_popupMenu
->Dismiss();
1291 // ----------------------------------------------------------------------------
1292 // wxMenu event processing
1293 // ----------------------------------------------------------------------------
1295 bool wxMenu::ProcessKeyDown(int key
)
1297 wxCHECK_MSG( m_popupMenu
, FALSE
,
1298 _T("can't process key events if not shown") );
1300 return m_popupMenu
->ProcessKeyDown(key
);
1303 bool wxMenu::ClickItem(wxMenuItem
*item
)
1306 if ( item
->IsCheckable() )
1308 // update the item state
1309 isChecked
= !item
->IsChecked();
1311 item
->Check(isChecked
!= 0);
1319 return SendEvent(item
->GetId(), isChecked
);
1322 // ----------------------------------------------------------------------------
1323 // wxMenu accel support
1324 // ----------------------------------------------------------------------------
1328 bool wxMenu::ProcessAccelEvent(const wxKeyEvent
& event
)
1330 // do we have an item for this accel?
1331 wxMenuItem
*item
= m_accelTable
.GetMenuItem(event
);
1332 if ( item
&& item
->IsEnabled() )
1334 return ClickItem(item
);
1338 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
1340 node
= node
->GetNext() )
1342 const wxMenuItem
*item
= node
->GetData();
1343 if ( item
->IsSubMenu() && item
->IsEnabled() )
1346 if ( item
->GetSubMenu()->ProcessAccelEvent(event
) )
1356 void wxMenu::AddAccelFor(wxMenuItem
*item
)
1358 wxAcceleratorEntry
*accel
= item
->GetAccel();
1361 accel
->SetMenuItem(item
);
1363 m_accelTable
.Add(*accel
);
1369 void wxMenu::RemoveAccelFor(wxMenuItem
*item
)
1371 wxAcceleratorEntry
*accel
= item
->GetAccel();
1374 m_accelTable
.Remove(*accel
);
1380 #endif // wxUSE_ACCEL
1382 // ----------------------------------------------------------------------------
1383 // wxMenuItem construction
1384 // ----------------------------------------------------------------------------
1386 wxMenuItem::wxMenuItem(wxMenu
*parentMenu
,
1388 const wxString
& text
,
1389 const wxString
& help
,
1394 m_parentMenu
= parentMenu
;
1395 m_subMenu
= subMenu
;
1400 m_isCheckable
= isCheckable
;
1402 m_isChecked
= FALSE
;
1410 wxMenuItem::~wxMenuItem()
1414 // ----------------------------------------------------------------------------
1415 // wxMenuItemBase methods implemented here
1416 // ----------------------------------------------------------------------------
1419 wxMenuItem
*wxMenuItemBase::New(wxMenu
*parentMenu
,
1421 const wxString
& name
,
1422 const wxString
& help
,
1426 return new wxMenuItem(parentMenu
, id
, name
, help
, isCheckable
, subMenu
);
1430 wxString
wxMenuItemBase::GetLabelFromText(const wxString
& text
)
1432 return wxStripMenuCodes(text
);
1435 // ----------------------------------------------------------------------------
1436 // wxMenuItem operations
1437 // ----------------------------------------------------------------------------
1439 void wxMenuItem::NotifyMenu()
1441 m_parentMenu
->RefreshItem(this);
1444 void wxMenuItem::UpdateAccelInfo()
1446 m_indexAccel
= wxControl::FindAccelIndex(m_text
);
1448 // will be empty if the text contains no TABs - ok
1449 m_strAccel
= m_text
.AfterFirst(_T('\t'));
1452 void wxMenuItem::SetText(const wxString
& text
)
1454 if ( text
!= m_text
)
1456 // first call the base class version to change m_text
1457 wxMenuItemBase::SetText(text
);
1465 void wxMenuItem::SetCheckable(bool checkable
)
1467 if ( checkable
!= m_isCheckable
)
1469 wxMenuItemBase::SetCheckable(checkable
);
1475 void wxMenuItem::SetBitmaps(const wxBitmap
& bmpChecked
,
1476 const wxBitmap
& bmpUnchecked
)
1478 m_bmpChecked
= bmpChecked
;
1479 m_bmpUnchecked
= bmpUnchecked
;
1484 void wxMenuItem::Enable(bool enable
)
1486 if ( enable
!= m_isEnabled
)
1488 wxMenuItemBase::Enable(enable
);
1494 void wxMenuItem::Check(bool check
)
1496 if ( check
!= m_isChecked
)
1498 wxMenuItemBase::Check(check
);
1504 // ----------------------------------------------------------------------------
1505 // wxMenuBar creation
1506 // ----------------------------------------------------------------------------
1508 void wxMenuBar::Init()
1516 m_shouldShowMenu
= FALSE
;
1519 void wxMenuBar::Attach(wxFrame
*frame
)
1521 // maybe you really wanted to call Detach()?
1522 wxCHECK_RET( frame
, _T("wxMenuBar::Attach(NULL) called") );
1524 wxMenuBarBase::Attach(frame
);
1528 // reparent if necessary
1529 if ( m_frameLast
!= frame
)
1534 // show it back - was hidden by Detach()
1537 else // not created yet, do it now
1539 // we have no way to return the error from here anyhow :-(
1540 (void)Create(frame
, -1);
1542 SetCursor(wxCURSOR_ARROW
);
1544 SetFont(wxSystemSettings::GetSystemFont(wxSYS_SYSTEM_FONT
));
1547 // remember the last frame which had us to avoid unnecessarily reparenting
1549 m_frameLast
= frame
;
1552 void wxMenuBar::Detach()
1554 // don't delete the window because we may be reattached later, just hide it
1560 wxMenuBarBase::Detach();
1563 wxMenuBar::~wxMenuBar()
1567 // ----------------------------------------------------------------------------
1568 // wxMenuBar adding/removing items
1569 // ----------------------------------------------------------------------------
1571 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
1573 return Insert(GetCount(), menu
, title
);
1576 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
1578 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
1581 wxMenuInfo
*info
= new wxMenuInfo(title
);
1582 m_menuInfos
.Insert(info
, pos
);
1584 RefreshAllItemsAfter(pos
);
1589 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
1591 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
1595 wxMenuInfo
& info
= m_menuInfos
[pos
];
1597 info
.SetLabel(title
);
1599 // even if the old menu was disabled, the new one is not any more
1602 // even if we change only this one, the new label has different width,
1603 // so we need to refresh everything beyond this item as well
1604 RefreshAllItemsAfter(pos
);
1610 wxMenu
*wxMenuBar::Remove(size_t pos
)
1612 wxMenu
*menuOld
= wxMenuBarBase::Remove(pos
);
1616 m_menuInfos
.RemoveAt(pos
);
1618 // this doesn't happen too often, so don't try to be too smart - just
1619 // refresh everything
1626 // ----------------------------------------------------------------------------
1627 // wxMenuBar top level menus access
1628 // ----------------------------------------------------------------------------
1630 wxCoord
wxMenuBar::GetItemWidth(size_t pos
) const
1632 return m_menuInfos
[pos
].GetWidth(wxConstCast(this, wxMenuBar
));
1635 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
1637 wxCHECK_RET( pos
< GetCount(), _T("invalid index in EnableTop") );
1639 if ( enable
!= m_menuInfos
[pos
].IsEnabled() )
1641 m_menuInfos
[pos
].SetEnabled(enable
);
1645 //else: nothing to do
1648 bool wxMenuBar::IsEnabledTop(size_t pos
) const
1650 wxCHECK_MSG( pos
< GetCount(), FALSE
, _T("invalid index in IsEnabledTop") );
1652 return m_menuInfos
[pos
].IsEnabled();
1655 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
1657 wxCHECK_RET( pos
< GetCount(), _T("invalid index in EnableTop") );
1659 if ( label
!= m_menuInfos
[pos
].GetLabel() )
1661 m_menuInfos
[pos
].SetLabel(label
);
1665 //else: nothing to do
1668 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
1670 wxCHECK_MSG( pos
< GetCount(), _T(""), _T("invalid index in GetLabelTop") );
1672 return m_menuInfos
[pos
].GetLabel();
1675 // ----------------------------------------------------------------------------
1676 // wxMenuBar drawing
1677 // ----------------------------------------------------------------------------
1679 void wxMenuBar::RefreshAllItemsAfter(size_t pos
)
1681 wxRect rect
= GetItemRect(pos
);
1682 rect
.width
= GetClientSize().x
- rect
.x
;
1686 void wxMenuBar::RefreshItem(size_t pos
)
1688 wxCHECK_RET( pos
!= (size_t)-1,
1689 _T("invalid item in wxMenuBar::RefreshItem") );
1691 RefreshRect(GetItemRect(pos
));
1694 void wxMenuBar::DoDraw(wxControlRenderer
*renderer
)
1696 wxDC
& dc
= renderer
->GetDC();
1697 dc
.SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
1699 // redraw only the items which must be redrawn
1701 // we don't have to use GetUpdateClientRect() here because our client rect
1702 // is the same as total one
1703 wxRect rectUpdate
= GetUpdateRegion().GetBox();
1705 int flagsMenubar
= GetStateFlags();
1709 rect
.height
= GetClientSize().y
;
1712 size_t count
= GetCount();
1713 for ( size_t n
= 0; n
< count
; n
++ )
1715 if ( x
> rectUpdate
.GetRight() )
1717 // all remaining items are to the right of rectUpdate
1722 rect
.width
= GetItemWidth(n
);
1724 if ( x
< rectUpdate
.x
)
1726 // this item is still to the left of rectUpdate
1730 int flags
= flagsMenubar
;
1731 if ( m_current
!= -1 && n
== (size_t)m_current
)
1733 flags
|= wxCONTROL_SELECTED
;
1736 if ( !IsEnabledTop(n
) )
1738 flags
|= wxCONTROL_DISABLED
;
1741 GetRenderer()->DrawMenuBarItem
1745 m_menuInfos
[n
].GetLabel(),
1747 m_menuInfos
[n
].GetAccelIndex()
1752 // ----------------------------------------------------------------------------
1753 // wxMenuBar geometry
1754 // ----------------------------------------------------------------------------
1756 wxRect
wxMenuBar::GetItemRect(size_t pos
) const
1758 wxASSERT_MSG( pos
< GetCount(), _T("invalid menu bar item index") );
1763 rect
.height
= GetClientSize().y
;
1765 for ( size_t n
= 0; n
< pos
; n
++ )
1767 rect
.x
+= GetItemWidth(n
);
1770 rect
.width
= GetItemWidth(pos
);
1775 wxSize
wxMenuBar::DoGetBestClientSize() const
1778 if ( GetMenuCount() > 0 )
1780 wxClientDC
dc(wxConstCast(this, wxMenuBar
));
1781 dc
.SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
1782 dc
.GetTextExtent(GetLabelTop(0), &size
.x
, &size
.y
);
1784 // adjust for the renderer we use
1785 size
= GetRenderer()->GetMenuBarItemSize(size
);
1787 else // empty menubar
1793 // the width is arbitrary, of course, for horizontal menubar
1799 int wxMenuBar::GetMenuFromPoint(const wxPoint
& pos
) const
1801 if ( pos
.x
< 0 || pos
.y
< 0 || pos
.y
> GetClientSize().y
)
1806 size_t count
= GetCount();
1807 for ( size_t item
= 0; item
< count
; item
++ )
1809 x
+= GetItemWidth(item
);
1817 // to the right of the last menu item
1821 // ----------------------------------------------------------------------------
1822 // wxMenuBar menu operations
1823 // ----------------------------------------------------------------------------
1825 void wxMenuBar::SelectMenu(size_t pos
)
1833 void wxMenuBar::DoSelectMenu(size_t pos
)
1835 wxCHECK_RET( pos
< GetCount(), _T("invalid menu index in DoSelectMenu") );
1837 if ( m_current
!= -1 )
1839 // close the previous menu
1840 if ( IsShowingMenu() )
1842 // restore m_shouldShowMenu flag after DismissMenu() which resets
1844 bool old
= m_shouldShowMenu
;
1848 m_shouldShowMenu
= old
;
1851 RefreshItem((size_t)m_current
);
1859 void wxMenuBar::PopupMenu(size_t pos
)
1861 wxCHECK_RET( pos
< GetCount(), _T("invalid menu index in PopupCurrentMenu") );
1868 // ----------------------------------------------------------------------------
1869 // wxMenuBar input handing
1870 // ----------------------------------------------------------------------------
1873 Note that wxMenuBar doesn't use wxInputHandler but handles keyboard and
1874 mouse in the same way under all platforms. This is because it doesn't derive
1875 from wxControl (which works with input handlers) but directly from wxWindow.
1877 Also, menu bar input handling is rather simple, so maybe it's not really
1878 worth making it themeable - at least I've decided against doing it now as it
1879 would merging the changes back into trunk more difficult. But it still could
1880 be done later if really needed.
1883 void wxMenuBar::OnKillFocus(wxFocusEvent
& event
)
1885 if ( m_current
!= -1 )
1887 RefreshItem((size_t)m_current
);
1895 void wxMenuBar::OnLeftDown(wxMouseEvent
& event
)
1903 else // we didn't have mouse capture, capture it now
1905 m_current
= GetMenuFromPoint(event
.GetPosition());
1906 if ( m_current
== -1 )
1908 // unfortunately, we can't prevent wxMSW from giving us the focus,
1909 // so we can only give it back
1916 // show it as selected
1917 RefreshItem((size_t)m_current
);
1920 PopupCurrentMenu(FALSE
/* don't select first item - as Windows does */);
1925 void wxMenuBar::OnMouseMove(wxMouseEvent
& event
)
1929 (void)ProcessMouseEvent(event
.GetPosition());
1937 bool wxMenuBar::ProcessMouseEvent(const wxPoint
& pt
)
1939 // a hack to ignore the extra mouse events MSW sends us: this is similar to
1940 // wxUSE_MOUSEEVENT_HACK in wxWin itself but it isn't enough for us here as
1941 // we get the messages from different windows (old and new popup menus for
1944 static wxPoint s_ptLast
;
1945 if ( pt
== s_ptLast
)
1953 int currentNew
= GetMenuFromPoint(pt
);
1954 if ( (currentNew
== -1) || (currentNew
== m_current
) )
1959 // select the new active item
1960 DoSelectMenu(currentNew
);
1962 // show the menu if we know that we should, even if we hadn't been showing
1963 // it before (this may happen if the previous menu was disabled)
1964 if ( m_shouldShowMenu
)
1966 // open the new menu if the old one we closed had been opened
1967 PopupCurrentMenu(FALSE
/* don't select first item - as Windows does */);
1973 void wxMenuBar::OnKeyDown(wxKeyEvent
& event
)
1975 // the current item must have been set before
1976 wxCHECK_RET( m_current
!= -1, _T("where is current item?") );
1978 int key
= event
.GetKeyCode();
1980 // first let the menu have it
1981 if ( IsShowingMenu() && m_menuShown
->ProcessKeyDown(key
) )
1986 // cycle through the menu items when left/right arrows are pressed and open
1987 // the menu when up/down one is
1991 // Alt must be processed at wxWindow level too
1996 // remove the selection and give the focus away
1997 if ( m_current
!= -1 )
1999 if ( IsShowingMenu() )
2011 size_t count
= GetCount();
2014 // the item won't change anyhow
2017 //else: otherwise, it will
2019 // remember if we were showing a menu - if we did, we should
2020 // show the new menu after changing the item
2021 bool wasMenuOpened
= IsShowingMenu();
2022 if ( wasMenuOpened
)
2027 // cast is safe as we tested for -1 above
2028 size_t currentNew
= (size_t)m_current
;
2030 if ( key
== WXK_LEFT
)
2032 if ( currentNew
-- == 0 )
2033 currentNew
= count
- 1;
2037 if ( ++currentNew
== (int)count
)
2041 DoSelectMenu(currentNew
);
2043 if ( wasMenuOpened
)
2058 // letters open the corresponding menu
2061 int idxFound
= FindNextItemForAccel(m_current
, key
, &unique
);
2063 if ( idxFound
!= -1 )
2065 if ( IsShowingMenu() )
2070 DoSelectMenu((size_t)idxFound
);
2072 // if the item is not unique, just select it but don't
2073 // activate as the user might have wanted to activate
2076 // also, don't try to open a disabled menu
2077 if ( unique
&& IsEnabledTop((size_t)idxFound
) )
2083 // skip the "event.Skip()" below
2092 // ----------------------------------------------------------------------------
2093 // wxMenuBar accel handling
2094 // ----------------------------------------------------------------------------
2096 int wxMenuBar::FindNextItemForAccel(int idxStart
, int key
, bool *unique
) const
2098 if ( !wxIsalnum(key
) )
2100 // we only support letters/digits as accels
2104 // do we have more than one item with this accel?
2108 // translate everything to lower case before comparing
2109 wxChar chAccel
= wxTolower(key
);
2111 // the index of the item with this accel
2114 // loop through all items searching for the item with this
2115 // accel starting at the item after the current one
2116 int count
= GetCount();
2117 int n
= idxStart
== -1 ? 0 : idxStart
+ 1;
2128 const wxMenuInfo
& info
= m_menuInfos
[n
];
2130 int idxAccel
= info
.GetAccelIndex();
2131 if ( idxAccel
!= -1 &&
2132 wxTolower(info
.GetLabel()[(size_t)idxAccel
])
2135 // ok, found an item with this accel
2136 if ( idxFound
== -1 )
2138 // store it but continue searching as we need to
2139 // know if it's the only item with this accel or if
2143 else // we already had found such item
2148 // no need to continue further, we won't find
2149 // anything we don't already know
2154 // we want to iterate over all items wrapping around if
2162 if ( n
== idxStart
)
2164 // we've seen all items
2174 bool wxMenuBar::ProcessAccelEvent(const wxKeyEvent
& event
)
2177 for ( wxMenuList::Node
*node
= m_menus
.GetFirst();
2179 node
= node
->GetNext(), n
++ )
2181 // accels of the items in the disabled menus shouldn't work
2182 if ( m_menuInfos
[n
].IsEnabled() )
2184 if ( node
->GetData()->ProcessAccelEvent(event
) )
2186 // menu processed it
2196 #endif // wxUSE_ACCEL
2198 // ----------------------------------------------------------------------------
2199 // wxMenuBar menus showing
2200 // ----------------------------------------------------------------------------
2202 void wxMenuBar::PopupCurrentMenu(bool selectFirst
)
2204 wxCHECK_RET( m_current
!= -1, _T("no menu to popup") );
2206 // forgot to call DismissMenu()?
2207 wxASSERT_MSG( !m_menuShown
, _T("shouldn't show two menu at once!") );
2209 // in any case, we should show it - even if we won't
2210 m_shouldShowMenu
= TRUE
;
2212 if ( IsEnabledTop(m_current
) )
2214 // remember the menu we show
2215 m_menuShown
= GetMenu(m_current
);
2217 // we don't show the menu at all if it has no items
2218 if ( !m_menuShown
->IsEmpty() )
2220 // position it correctly: note that we must use screen coords and
2221 // that we pass 0 as width to position the menu exactly below the
2222 // item, not to the right of it
2223 wxRect rectItem
= GetItemRect(m_current
);
2224 m_menuShown
->Popup(ClientToScreen(rectItem
.GetPosition()),
2225 wxSize(0, rectItem
.GetHeight()),
2230 // reset it back as no menu is shown
2234 //else: don't show disabled menu
2237 void wxMenuBar::DismissMenu()
2239 wxCHECK_RET( m_menuShown
, _T("can't dismiss menu if none is shown") );
2241 m_menuShown
->Dismiss();
2245 void wxMenuBar::OnDismissMenu(bool dismissMenuBar
)
2247 m_shouldShowMenu
= FALSE
;
2249 if ( dismissMenuBar
)
2255 void wxMenuBar::OnDismiss()
2259 if ( m_current
!= -1 )
2261 RefreshItem((size_t)m_current
);
2269 void wxMenuBar::GiveAwayFocus()
2271 GetFrame()->SetFocus();
2274 // ----------------------------------------------------------------------------
2275 // popup menu support
2276 // ----------------------------------------------------------------------------
2278 wxEventLoop
*wxWindow::ms_evtLoopPopup
= NULL
;
2280 bool wxWindow::DoPopupMenu(wxMenu
*menu
, int x
, int y
)
2282 wxCHECK_MSG( !ms_evtLoopPopup
, FALSE
,
2283 _T("can't show more than one popup menu at a time") );
2286 // we need to change the cursor before showing the menu as, apparently, no
2287 // cursor changes took place while the mouse is captured
2288 wxCursor cursorOld
= GetCursor();
2289 SetCursor(wxCURSOR_ARROW
);
2293 // flash any delayed log messages before showing the menu, otherwise it
2294 // could be dismissed (because it would lose focus) immediately after being
2296 wxLog::FlushActive();
2298 // some controls update themselves from OnIdle() call - let them do it
2300 wxTheApp
->ProcessEvent(event
);
2302 // if the window hadn't been refreshed yet, the menu can adversely affect
2303 // its next OnPaint() handler execution - i.e. scrolled window refresh
2304 // logic breaks then as it scrolls part of the menu which hadn't been there
2305 // when the update event was generated into view
2309 menu
->SetInvokingWindow(this);
2310 menu
->Popup(ClientToScreen(wxPoint(x
, y
)), wxSize(0, 0));
2312 // this is not very useful if the menu was popped up because of the mouse
2313 // click but I think it is nice to do when it appears because of a key
2314 // press (i.e. Windows menu key)
2316 // Windows itself doesn't do it, but IMHO this is nice
2319 // we have to redirect all keyboard input to the menu temporarily
2320 PushEventHandler(new wxMenuKbdRedirector(menu
));
2322 // enter the local modal loop
2323 ms_evtLoopPopup
= new wxEventLoop
;
2324 ms_evtLoopPopup
->Run();
2326 delete ms_evtLoopPopup
;
2327 ms_evtLoopPopup
= NULL
;
2329 // remove the handler
2330 PopEventHandler(TRUE
/* delete it */);
2332 menu
->SetInvokingWindow(NULL
);
2335 SetCursor(cursorOld
);
2341 void wxWindow::DismissPopupMenu()
2343 wxCHECK_RET( ms_evtLoopPopup
, _T("no popup menu shown") );
2345 ms_evtLoopPopup
->Exit();
2348 #endif // wxUSE_MENUS