From a87eab540b29545a8a8beb0e65bf8dc6d5ae86e2 Mon Sep 17 00:00:00 2001 From: twanvl Date: Fri, 31 Dec 2010 19:38:52 +0000 Subject: [PATCH] Reverted DropDownList back to wxPopupWindow from wxPopupTransientWindow. The latter is not going to work, because it tries to be too smart. In particular, it thinks the mouse clicks outside the dialog when the scrollbar is clicked, and dismisses the popup. It also requires a mouse capture, which gives problems when submenus are used. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1574 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/gui/control/card_editor.cpp | 1 - src/gui/drop_down_list.cpp | 85 +++++++++++++++++++++++---------- src/gui/drop_down_list.hpp | 9 ++-- 3 files changed, 66 insertions(+), 29 deletions(-) diff --git a/src/gui/control/card_editor.cpp b/src/gui/control/card_editor.cpp index ade225d9..4964a5ef 100644 --- a/src/gui/control/card_editor.cpp +++ b/src/gui/control/card_editor.cpp @@ -213,7 +213,6 @@ void DataEditor::insert(const String& text, const String& action_name) { void DataEditor::onLeftDown(wxMouseEvent& ev) { ev.Skip(); // for focus - SetFocus(); // set focus now, otherwise this happens after the editor handles the event, which dismisses transient popup dialogs CaptureMouse(); // change selection? selectField(ev, &ValueEditor::onLeftDown); diff --git a/src/gui/drop_down_list.cpp b/src/gui/drop_down_list.cpp index c994f50b..6a04bed9 100644 --- a/src/gui/drop_down_list.cpp +++ b/src/gui/drop_down_list.cpp @@ -16,10 +16,47 @@ #include #include +// ----------------------------------------------------------------------------- : DropDownHider + +// Class that intercepts all events not directed to a DropDownList, and closes the list +class DropDownHider : public wxEvtHandler { + public: + DropDownHider(DropDownList& list) : list(list) {} + + private: + DropDownList& list; + + virtual bool ProcessEvent(wxEvent& ev) { + int t = ev.GetEventType(); + if ( t == wxEVT_LEFT_DOWN || t == wxEVT_RIGHT_DOWN + || t == wxEVT_MOVE || t == wxEVT_SIZE + || t == wxEVT_MENU_HIGHLIGHT || t == wxEVT_MENU_OPEN || t == wxEVT_MENU_OPEN + || t == wxEVT_ACTIVATE || t == wxEVT_CLOSE_WINDOW || t == wxEVT_KILL_FOCUS + || t == wxEVT_COMMAND_TOOL_CLICKED) + { + // close the list, and pass on the event + // don't just use ev.Skip(), because this event handler will be removed by hiding, + // so there will be no next handler to skip to + wxEvtHandler* nh = GetNextHandler(); + if (nh) nh->ProcessEvent(ev); + list.hide(false); + return false; + } else { +// if (t !=10093 && t !=10098 && t !=10097 && t !=10099 && t !=10004 && t !=10062 +// && t !=10025 && t !=10035 && t !=10034 && t !=10036 && t !=10042 && t !=10119) +// { +// t=t;//DEBUG +// } + return wxEvtHandler::ProcessEvent(ev); + } + } +}; + + // ----------------------------------------------------------------------------- : DropDownList : Show/Hide DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer) - : wxPopupTransientWindow(parent, wxSIMPLE_BORDER)//wxPopupWindow(parent, wxSIMPLE_BORDER) + : wxPopupWindow(parent, wxSIMPLE_BORDER) , text_offset(1) , item_size(100,1) , icon_size(0,0) @@ -28,6 +65,8 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer) , open_sub_menu(nullptr) , parent_menu(nullptr) , viewer(viewer) + , hider (is_submenu ? nullptr : new DropDownHider(*this)) + , hider2(is_submenu ? nullptr : new DropDownHider(*this)) , close_on_mouse_out(false) { if (is_submenu) { @@ -43,6 +82,8 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer) DropDownList::~DropDownList() { realHide(); // restore event handler before deleting it + delete hider; + delete hider2; } void DropDownList::show(bool in_place, wxPoint pos, RealRect* rect) { @@ -109,16 +150,21 @@ void DropDownList::show(bool in_place, wxPoint pos, RealRect* rect) { // visible item visible_start = 0; ensureSelectedItemVisible(); - // show - if (GetParent()->HasCapture()) { - // release capture on parent - // do this before showing the popup, because that might change who has the capture - GetParent()->ReleaseMouse(); + // set event handler + if (hider) { + assert(hider2); + wxGetTopLevelParent(GetParent())->PushEventHandler(hider); + GetParent() ->PushEventHandler(hider2); } + // show if (selected_item == NO_SELECTION && itemCount() > 0) selected_item = 0; // select first item by default mouse_down = false; close_on_mouse_out = false; - Popup(); + Window::Show(); + if (isRoot() && GetParent()->HasCapture()) { + // release capture on parent + GetParent()->ReleaseMouse(); + } // fix drop down arrow redrawArrowOnParent(); } @@ -144,15 +190,17 @@ void DropDownList::hide(bool event, bool allow_veto) { } void DropDownList::realHide() { - if (IsShown()) Dismiss(); -} - -void DropDownList::OnDismiss() { + if (!IsShown()) return; + Window::Hide(); + onHide(); hideSubMenu(); if (parent_menu) { parent_menu->open_sub_menu = nullptr; } else { redrawArrowOnParent(); + // disconnect event handler + GetParent() ->RemoveEventHandler(hider2); + wxGetTopLevelParent(GetParent())->RemoveEventHandler(hider); } } @@ -386,12 +434,8 @@ void DropDownList::onScroll(wxScrollWinEvent& ev) { // ----------------------------------------------------------------------------- : DropDownList : Parent events bool DropDownList::onMouseInParent(wxMouseEvent& ev, bool open_in_place) { - if (IsShown()) { - hide(false); - } else { - show(open_in_place, wxPoint(ev.GetX(), ev.GetY())); - ev.Skip(false); // Don't set the focus to the parent afterwards - } + if (IsShown()) hide(false); + else show(open_in_place, wxPoint(ev.GetX(), ev.GetY())); return true; } @@ -457,12 +501,6 @@ bool DropDownList::onCharInParent(wxKeyEvent& ev) { return false; } -void DropDownList::onKeyDown(wxKeyEvent& ev) { - // If we don't handle this event, then wxPopupTransientWindow desides to dismiss itself - // we can't wait for onChar - onCharInParent(ev); -} - // ----------------------------------------------------------------------------- : DropDownList : Event table // Note: some DropDownList events get sent to the parent which in turn should send them to the DropDownList @@ -474,5 +512,4 @@ BEGIN_EVENT_TABLE(DropDownList,wxPopupWindow) EVT_LEAVE_WINDOW (DropDownList::onMouseLeave) EVT_MOUSEWHEEL (DropDownList::onMouseWheel) EVT_SCROLLWIN (DropDownList::onScroll) - EVT_KEY_DOWN (DropDownList::onKeyDown) END_EVENT_TABLE () diff --git a/src/gui/drop_down_list.hpp b/src/gui/drop_down_list.hpp index 407ea960..5bccdbfe 100644 --- a/src/gui/drop_down_list.hpp +++ b/src/gui/drop_down_list.hpp @@ -14,12 +14,13 @@ #include // undocumented: wxPopupWindow class ValueViewer; +class DropDownHider; // ----------------------------------------------------------------------------- : DropDownList /// A popup/drop down window displaying a list of items /** This class is an abstract base for various drop down lists */ -class DropDownList : public wxPopupTransientWindow { +class DropDownList : public wxPopupWindow { public: ~DropDownList(); /// Create a drop down list, possibly a sub menu @@ -45,7 +46,7 @@ class DropDownList : public wxPopupTransientWindow { /// Prepare for showing the list virtual void onShow() {} /// Do something after hiding the list - virtual void OnDismiss(); + virtual void onHide() {} inline bool isRoot() { return parent_menu == nullptr; } @@ -93,6 +94,7 @@ class DropDownList : public wxPopupTransientWindow { DropDownList* open_sub_menu; ///< The sub menu that is currently shown, if any DropDownList* parent_menu; ///< The parent menu, only applies to sub menus ValueViewer* viewer; ///< The parent viewer object (optional) + DropDownHider* hider, *hider2; ///< Class to hide this window when we lose focus bool close_on_mouse_out; ///< Was the list kept open after selecting a choice, if so, be eager to close it int visible_start; ///< First visible pixel @@ -101,12 +103,11 @@ class DropDownList : public wxPopupTransientWindow { void onPaint(wxPaintEvent&); void onLeftDown(wxMouseEvent&); - void onLeftUp (wxMouseEvent&); + void onLeftUp(wxMouseEvent&); void onMotion(wxMouseEvent&); void onMouseLeave(wxMouseEvent&); void onMouseWheel(wxMouseEvent& ev); void onScroll(wxScrollWinEvent&); - void onKeyDown(wxKeyEvent&); // --------------------------------------------------- : Privates