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