FIX: Intercept IDLE event in DropDown to fix various problems on MacOS

Change-Id: Ia9aa96c90f1b7c3f6c33b7325dc28a4f780969c3
This commit is contained in:
chunmao.guo 2022-08-05 15:35:43 +08:00 committed by Yifan Wu
parent ace72ecdbc
commit 646934953c
5 changed files with 59 additions and 40 deletions

View File

@ -317,25 +317,14 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR
c_editor->SetSelection(atoi(data.GetText().c_str()) - 1); c_editor->SetSelection(atoi(data.GetText().c_str()) - 1);
#ifndef _WIN32 #ifdef __linux__
c_editor->Bind(wxEVT_COMBOBOX, [this, c_editor](wxCommandEvent& evt) { c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
// to avoid event propagation to other sidebar items // to avoid event propagation to other sidebar items
evt.StopPropagation(); evt.StopPropagation();
// FinishEditing grabs new selection and triggers config update. We better call // FinishEditing grabs new selection and triggers config update. We better call
// it explicitly, automatic update on KILL_FOCUS didn't work on Linux. // it explicitly, automatic update on KILL_FOCUS didn't work on Linux.
c_editor->SetClientData(this);
this->FinishEditing(); 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 #else
// to avoid event propagation to other sidebar items // to avoid event propagation to other sidebar items
c_editor->Bind(wxEVT_COMBOBOX, [](wxCommandEvent& evt) { evt.StopPropagation(); }); c_editor->Bind(wxEVT_COMBOBOX, [](wxCommandEvent& evt) { evt.StopPropagation(); });

View File

@ -4741,9 +4741,7 @@ void ObjectList::OnEditingStarted(wxDataViewEvent &event)
auto item = event.GetItem(); auto item = event.GetItem();
if (!renderer->GetEditorCtrl()) { if (!renderer->GetEditorCtrl()) {
renderer->StartEditing(item, GetItemRect(item, column)); renderer->StartEditing(item, GetItemRect(item, column));
if (col == colFilament) // TODO: not handle KILL_FOCUS from ComboBox if (col == colName) // TODO: for colName editing, disable shortcuts
renderer->GetEditorCtrl()->PopEventHandler();
else if (col == colName) // TODO: for colName editing, disable shortcuts
SetAcceleratorTable(wxNullAcceleratorTable); SetAcceleratorTable(wxNullAcceleratorTable);
} }
#endif //__WXMSW__ #endif //__WXMSW__

View File

@ -26,13 +26,14 @@ ComboBox::ComboBox(wxWindow * parent,
int n, int n,
const wxString choices[], const wxString choices[],
long style) long style)
: drop(this, texts, icons, style & DD_STYLE_MASK) : drop(texts, icons)
{ {
if (style & wxCB_READONLY) if (style & wxCB_READONLY)
style |= wxRIGHT; style |= wxRIGHT;
text_off = style & CB_NO_TEXT; text_off = style & CB_NO_TEXT;
TextInput::Create(parent, "", value, (style & CB_NO_DROP_ICON) ? "" : "drop_down", pos, size, TextInput::Create(parent, "", value, (style & CB_NO_DROP_ICON) ? "" : "drop_down", pos, size,
style | wxTE_PROCESS_ENTER); style | wxTE_PROCESS_ENTER);
drop.Create(this, style & DD_STYLE_MASK);
if (style & wxCB_READONLY) { if (style & wxCB_READONLY) {
GetTextCtrl()->Hide(); GetTextCtrl()->Hide();
@ -52,16 +53,12 @@ ComboBox::ComboBox(wxWindow * parent,
SetSelection(e.GetInt()); SetSelection(e.GetInt());
e.SetEventObject(this); e.SetEventObject(this);
e.SetId(GetId()); e.SetId(GetId());
wxMouseEvent e1;
mouseDown(e1);
GetEventHandler()->ProcessEvent(e); GetEventHandler()->ProcessEvent(e);
}); });
drop.Bind(wxEVT_SHOW, [this](auto &e) { drop.Bind(EVT_DISMISS, [this](auto &) {
if (!e.IsShown()) { drop_down = false;
drop_down = false; wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP);
wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP); GetEventHandler()->ProcessEvent(e);
GetEventHandler()->ProcessEvent(e);
}
}); });
for (int i = 0; i < n; ++i) Append(choices[i]); 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) void ComboBox::mouseDown(wxMouseEvent &event)
{ {
SetFocus(); //SetFocus();
if (drop_down) { if (drop_down) {
drop.Hide(); drop.Hide();
} else if (drop.HasDismissLongTime()) { } else if (drop.HasDismissLongTime()) {

View File

@ -3,6 +3,8 @@
#include <wx/dcgraph.h> #include <wx/dcgraph.h>
wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent);
BEGIN_EVENT_TABLE(DropDown, wxPopupTransientWindow) BEGIN_EVENT_TABLE(DropDown, wxPopupTransientWindow)
EVT_LEFT_DOWN(DropDown::mouseDown) EVT_LEFT_DOWN(DropDown::mouseDown)
@ -21,12 +23,9 @@ END_EVENT_TABLE()
* calling Refresh()/Update(). * calling Refresh()/Update().
*/ */
DropDown::DropDown(wxWindow * parent, DropDown::DropDown(std::vector<wxString> &texts,
std::vector<wxString> &texts, std::vector<wxBitmap> &icons)
std::vector<wxBitmap> &icons, : texts(texts)
long style)
: wxPopupTransientWindow(parent)
, texts(texts)
, icons(icons) , icons(icons)
, state_handler(this) , state_handler(this)
, border_color(0xDBDBDB) , border_color(0xDBDBDB)
@ -36,6 +35,21 @@ DropDown::DropDown(wxWindow * parent,
, selector_background_color(std::make_pair(0xEDFAF2, (int) StateColor::Checked), , selector_background_color(std::make_pair(0xEDFAF2, (int) StateColor::Checked),
std::make_pair(*wxWHITE, (int) StateColor::Normal)) std::make_pair(*wxWHITE, (int) StateColor::Normal))
{ {
}
DropDown::DropDown(wxWindow * parent,
std::vector<wxString> &texts,
std::vector<wxBitmap> &icons,
long style)
: DropDown(texts, icons)
{
Create(parent, style);
}
void DropDown::Create(wxWindow * parent,
long style)
{
wxPopupTransientWindow::Create(parent);
SetBackgroundStyle(wxBG_STYLE_PAINT); SetBackgroundStyle(wxBG_STYLE_PAINT);
SetBackgroundColour(*wxWHITE); SetBackgroundColour(*wxWHITE);
state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color}); 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 // BBS set default font
SetFont(Label::Body_14); 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) void DropDown::Invalidate(bool clear)
@ -352,27 +371,31 @@ void DropDown::autoPosition()
void DropDown::mouseDown(wxMouseEvent& event) 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; pressedDown = true;
CaptureMouse();
dragStart = event.GetPosition(); dragStart = event.GetPosition();
} }
void DropDown::mouseReleased(wxMouseEvent& event) void DropDown::mouseReleased(wxMouseEvent& event)
{ {
if (pressedDown) { if (pressedDown) {
ReleaseMouse();
dragStart = wxPoint(); dragStart = wxPoint();
pressedDown = false; pressedDown = false;
if (hover_item >= 0) // not moved if (hover_item >= 0) { // not moved
sendDropDownEvent(); sendDropDownEvent();
DismissAndNotify(); DismissAndNotify();
}
} }
} }
void DropDown::mouseMove(wxMouseEvent &event) void DropDown::mouseMove(wxMouseEvent &event)
{ {
wxPoint pt = event.GetPosition();
if (pressedDown) { if (pressedDown) {
wxPoint pt = event.GetPosition();
wxPoint pt2 = offset + pt - dragStart; wxPoint pt2 = offset + pt - dragStart;
dragStart = pt; dragStart = pt;
if (pt2.y > 0) if (pt2.y > 0)
@ -387,7 +410,7 @@ void DropDown::mouseMove(wxMouseEvent &event)
} }
} }
if (!pressedDown || hover_item >= 0) { 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 >= (int) texts.size()) hover = -1;
if (hover == hover_item) return; if (hover == hover_item) return;
hover_item = hover; hover_item = hover;
@ -434,4 +457,6 @@ void DropDown::OnDismiss()
{ {
dismissTime = boost::posix_time::microsec_clock::universal_time(); dismissTime = boost::posix_time::microsec_clock::universal_time();
hover_item = -1; hover_item = -1;
wxCommandEvent e(EVT_DISMISS);
GetEventHandler()->ProcessEvent(e);
} }

View File

@ -9,6 +9,8 @@
#define DD_NO_TEXT 0x2000000 #define DD_NO_TEXT 0x2000000
#define DD_STYLE_MASK 0x3000000 #define DD_STYLE_MASK 0x3000000
wxDECLARE_EVENT(EVT_DISMISS, wxCommandEvent);
class DropDown : public wxPopupTransientWindow class DropDown : public wxPopupTransientWindow
{ {
std::vector<wxString> & texts; std::vector<wxString> & texts;
@ -39,11 +41,17 @@ class DropDown : public wxPopupTransientWindow
wxPoint dragStart; wxPoint dragStart;
public: public:
DropDown(std::vector<wxString> &texts,
std::vector<wxBitmap> &icons);
DropDown(wxWindow * parent, DropDown(wxWindow * parent,
std::vector<wxString> &texts, std::vector<wxString> &texts,
std::vector<wxBitmap> &icons, std::vector<wxBitmap> &icons,
long style = 0); long style = 0);
void Create(wxWindow * parent,
long style = 0);
public: public:
void Invalidate(bool clear = false); void Invalidate(bool clear = false);
@ -73,6 +81,9 @@ public:
void Rescale(); void Rescale();
bool HasDismissLongTime(); bool HasDismissLongTime();
protected:
void OnDismiss() override;
private: private:
void paintEvent(wxPaintEvent& evt); void paintEvent(wxPaintEvent& evt);
@ -92,7 +103,6 @@ private:
void sendDropDownEvent(); void sendDropDownEvent();
void OnDismiss() override;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };