From 646934953c6a76a3e8f79e1f8589689c1002602e Mon Sep 17 00:00:00 2001 From: "chunmao.guo" Date: Fri, 5 Aug 2022 15:35:43 +0800 Subject: [PATCH] FIX: Intercept IDLE event in DropDown to fix various problems on MacOS Change-Id: Ia9aa96c90f1b7c3f6c33b7325dc28a4f780969c3 --- src/slic3r/GUI/ExtraRenderers.cpp | 15 ++------- src/slic3r/GUI/GUI_ObjectList.cpp | 4 +-- src/slic3r/GUI/Widgets/ComboBox.cpp | 17 +++++----- src/slic3r/GUI/Widgets/DropDown.cpp | 49 ++++++++++++++++++++++------- src/slic3r/GUI/Widgets/DropDown.hpp | 14 +++++++-- 5 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/slic3r/GUI/ExtraRenderers.cpp b/src/slic3r/GUI/ExtraRenderers.cpp index e9a4849c1..70baf49ff 100644 --- a/src/slic3r/GUI/ExtraRenderers.cpp +++ b/src/slic3r/GUI/ExtraRenderers.cpp @@ -317,25 +317,14 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR c_editor->SetSelection(atoi(data.GetText().c_str()) - 1); -#ifndef _WIN32 - c_editor->Bind(wxEVT_COMBOBOX, [this, c_editor](wxCommandEvent& evt) { +#ifdef __linux__ + c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) { // to avoid event propagation to other sidebar items evt.StopPropagation(); // FinishEditing grabs new selection and triggers config update. We better call // it explicitly, automatic update on KILL_FOCUS didn't work on Linux. - c_editor->SetClientData(this); this->FinishEditing(); }); - c_editor->Bind(wxEVT_COMBOBOX_DROPDOWN, [this, c_editor](wxCommandEvent& evt) { - c_editor->SetClientData(this); - this->FinishEditing(); - }); - c_editor->Bind(wxEVT_KILL_FOCUS, [this, c_editor](wxFocusEvent& evt) { - if (!c_editor->GetDropDown().IsShown() && c_editor->GetClientData() == nullptr) { // TODO: Fix called twice - c_editor->SetClientData(this); - this->FinishEditing(); - } - }, c_editor->GetId()); #else // to avoid event propagation to other sidebar items c_editor->Bind(wxEVT_COMBOBOX, [](wxCommandEvent& evt) { evt.StopPropagation(); }); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 47cb0bcba..7cb6a6156 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -4741,9 +4741,7 @@ void ObjectList::OnEditingStarted(wxDataViewEvent &event) auto item = event.GetItem(); if (!renderer->GetEditorCtrl()) { renderer->StartEditing(item, GetItemRect(item, column)); - if (col == colFilament) // TODO: not handle KILL_FOCUS from ComboBox - renderer->GetEditorCtrl()->PopEventHandler(); - else if (col == colName) // TODO: for colName editing, disable shortcuts + if (col == colName) // TODO: for colName editing, disable shortcuts SetAcceleratorTable(wxNullAcceleratorTable); } #endif //__WXMSW__ diff --git a/src/slic3r/GUI/Widgets/ComboBox.cpp b/src/slic3r/GUI/Widgets/ComboBox.cpp index 8f2c685f3..ec416ea04 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.cpp +++ b/src/slic3r/GUI/Widgets/ComboBox.cpp @@ -26,13 +26,14 @@ ComboBox::ComboBox(wxWindow * parent, int n, const wxString choices[], long style) - : drop(this, texts, icons, style & DD_STYLE_MASK) + : drop(texts, icons) { if (style & wxCB_READONLY) style |= wxRIGHT; text_off = style & CB_NO_TEXT; TextInput::Create(parent, "", value, (style & CB_NO_DROP_ICON) ? "" : "drop_down", pos, size, style | wxTE_PROCESS_ENTER); + drop.Create(this, style & DD_STYLE_MASK); if (style & wxCB_READONLY) { GetTextCtrl()->Hide(); @@ -52,16 +53,12 @@ ComboBox::ComboBox(wxWindow * parent, SetSelection(e.GetInt()); e.SetEventObject(this); e.SetId(GetId()); - wxMouseEvent e1; - mouseDown(e1); GetEventHandler()->ProcessEvent(e); }); - drop.Bind(wxEVT_SHOW, [this](auto &e) { - if (!e.IsShown()) { - drop_down = false; - wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP); - GetEventHandler()->ProcessEvent(e); - } + drop.Bind(EVT_DISMISS, [this](auto &) { + drop_down = false; + wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP); + GetEventHandler()->ProcessEvent(e); }); for (int i = 0; i < n; ++i) Append(choices[i]); } @@ -209,7 +206,7 @@ void ComboBox::DoSetItemClientData(unsigned int n, void *data) void ComboBox::mouseDown(wxMouseEvent &event) { - SetFocus(); + //SetFocus(); if (drop_down) { drop.Hide(); } else if (drop.HasDismissLongTime()) { diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp index c328d0742..f588864c1 100644 --- a/src/slic3r/GUI/Widgets/DropDown.cpp +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -3,6 +3,8 @@ #include +wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent); + BEGIN_EVENT_TABLE(DropDown, wxPopupTransientWindow) EVT_LEFT_DOWN(DropDown::mouseDown) @@ -21,12 +23,9 @@ END_EVENT_TABLE() * calling Refresh()/Update(). */ -DropDown::DropDown(wxWindow * parent, - std::vector &texts, - std::vector &icons, - long style) - : wxPopupTransientWindow(parent) - , texts(texts) +DropDown::DropDown(std::vector &texts, + std::vector &icons) + : texts(texts) , icons(icons) , state_handler(this) , border_color(0xDBDBDB) @@ -36,6 +35,21 @@ DropDown::DropDown(wxWindow * parent, , selector_background_color(std::make_pair(0xEDFAF2, (int) StateColor::Checked), std::make_pair(*wxWHITE, (int) StateColor::Normal)) { +} + +DropDown::DropDown(wxWindow * parent, + std::vector &texts, + std::vector &icons, + long style) + : DropDown(texts, icons) +{ + Create(parent, style); +} + +void DropDown::Create(wxWindow * parent, + long style) +{ + wxPopupTransientWindow::Create(parent); SetBackgroundStyle(wxBG_STYLE_PAINT); SetBackgroundColour(*wxWHITE); state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color}); @@ -46,6 +60,11 @@ DropDown::DropDown(wxWindow * parent, // BBS set default font SetFont(Label::Body_14); +#ifdef __WXOSX__ + // wxPopupTransientWindow releases mouse on idle, which may cause various problems, + // such as losting mouse move, and dismissing soon on first LEFT_DOWN event. + Bind(wxEVT_IDLE, [] (wxIdleEvent & evt) {}); +#endif } void DropDown::Invalidate(bool clear) @@ -352,27 +371,31 @@ void DropDown::autoPosition() void DropDown::mouseDown(wxMouseEvent& event) { + // Receivce unexcepted LEFT_DOWN on Mac after OnDismiss + if (!IsShown()) + return; + // force calc hover item again + mouseMove(event); pressedDown = true; - CaptureMouse(); dragStart = event.GetPosition(); } void DropDown::mouseReleased(wxMouseEvent& event) { if (pressedDown) { - ReleaseMouse(); dragStart = wxPoint(); pressedDown = false; - if (hover_item >= 0) // not moved + if (hover_item >= 0) { // not moved sendDropDownEvent(); - DismissAndNotify(); + DismissAndNotify(); + } } } void DropDown::mouseMove(wxMouseEvent &event) { + wxPoint pt = event.GetPosition(); if (pressedDown) { - wxPoint pt = event.GetPosition(); wxPoint pt2 = offset + pt - dragStart; dragStart = pt; if (pt2.y > 0) @@ -387,7 +410,7 @@ void DropDown::mouseMove(wxMouseEvent &event) } } if (!pressedDown || hover_item >= 0) { - int hover = (event.GetPosition().y - offset.y) / rowSize.y; + int hover = (pt.y - offset.y) / rowSize.y; if (hover >= (int) texts.size()) hover = -1; if (hover == hover_item) return; hover_item = hover; @@ -434,4 +457,6 @@ void DropDown::OnDismiss() { dismissTime = boost::posix_time::microsec_clock::universal_time(); hover_item = -1; + wxCommandEvent e(EVT_DISMISS); + GetEventHandler()->ProcessEvent(e); } diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp index f4c4f2548..03f91a05a 100644 --- a/src/slic3r/GUI/Widgets/DropDown.hpp +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -9,6 +9,8 @@ #define DD_NO_TEXT 0x2000000 #define DD_STYLE_MASK 0x3000000 +wxDECLARE_EVENT(EVT_DISMISS, wxCommandEvent); + class DropDown : public wxPopupTransientWindow { std::vector & texts; @@ -39,11 +41,17 @@ class DropDown : public wxPopupTransientWindow wxPoint dragStart; public: + DropDown(std::vector &texts, + std::vector &icons); + DropDown(wxWindow * parent, std::vector &texts, std::vector &icons, long style = 0); - + + void Create(wxWindow * parent, + long style = 0); + public: void Invalidate(bool clear = false); @@ -73,6 +81,9 @@ public: void Rescale(); bool HasDismissLongTime(); + +protected: + void OnDismiss() override; private: void paintEvent(wxPaintEvent& evt); @@ -92,7 +103,6 @@ private: void sendDropDownEvent(); - void OnDismiss() override; DECLARE_EVENT_TABLE() };