From 9a150ba4866e35302790def1ce5cbd9dba95b833 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 23 May 2021 14:03:38 +0100 Subject: [PATCH 1/4] Add wxEventObjectOriginSetter helper class This RAII helper can be used to temporarily change the event object and ID of a wxEvent and will be used when redirecting events to make events from one object to appear as coming from another one. --- include/wx/event.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/wx/event.h b/include/wx/event.h index f5c32a3d77..c654264798 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -1197,6 +1197,35 @@ private: wxDECLARE_NO_COPY_CLASS(wxPropagateOnce); }; +// Helper class changing the event object to make the event appear as coming +// from a different source: this is somewhat of a hack, but avoids copying the +// events just to change their event object field. +class wxEventObjectOriginSetter +{ +public: + wxEventObjectOriginSetter(wxEvent& event, wxObject* source, int winid = 0) + : m_event(event), + m_sourceOrig(event.GetEventObject()), + m_idOrig(event.GetId()) + { + m_event.SetEventObject(source); + m_event.SetId(winid); + } + + ~wxEventObjectOriginSetter() + { + m_event.SetId(m_idOrig); + m_event.SetEventObject(m_sourceOrig); + } + +private: + wxEvent& m_event; + wxObject* const m_sourceOrig; + const int m_idOrig; + + wxDECLARE_NO_COPY_CLASS(wxEventObjectOriginSetter); +}; + // A helper object used to temporarily make wxEvent::ShouldProcessOnlyIn() // return true for the handler passed to its ctor. class wxEventProcessInHandlerOnly From fa00fd24f0f3f1226d5a26127867e88aaffb833f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 23 May 2021 14:05:03 +0100 Subject: [PATCH 2/4] Fix event origin for wxEVT_CHAR from wxCompositeWindow children Use the just added wxEventObjectOriginSetter to set the event object and ID to that of wxCompositeWindow itself, rather than that of the child window where the event had actually occurred. --- include/wx/compositewin.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/wx/compositewin.h b/include/wx/compositewin.h index 23ee6f738b..a5d93b02bf 100644 --- a/include/wx/compositewin.h +++ b/include/wx/compositewin.h @@ -223,6 +223,8 @@ private: void OnChar(wxKeyEvent& event) { + wxEventObjectOriginSetter setThis(event, this, this->GetId()); + if ( !this->ProcessWindowEvent(event) ) event.Skip(); } From 3ed930c7366c876a7ea927d3035fdbd9dc93e9fb Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 23 May 2021 14:14:29 +0100 Subject: [PATCH 3/4] Use wxCompositeWindow for generic wxDataViewCtrl implementation This makes several methods that didn't have any effect before work correctly, including SetToolTip(), whose effect is now shown in the sample, but also SetCursor() and SetLayoutDirection(). Some methods would now actually work too well: SetForegroundColour() and SetBackgroundColour() implementations in wxCompositeWindow apply to all sub-windows, but in wxDataViewCtrl they are only supposed to affect the items, but not the header, so we need to override them to prevent the base class version from being used. It is still preferable to explicitly disable these two methods and inherit all the other ones (including any possibly added in the future) from wxCompositeWindow to implementing all the methods manually in wxDataViewCtrl itself. --- include/wx/generic/dataview.h | 13 +++++++++-- samples/dataview/dataview.cpp | 5 ++-- src/generic/datavgen.cpp | 43 +++++++++++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index b773882488..262d318696 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -12,6 +12,7 @@ #include "wx/defs.h" #include "wx/object.h" +#include "wx/compositewin.h" #include "wx/control.h" #include "wx/scrolwin.h" #include "wx/icon.h" @@ -180,8 +181,9 @@ private: // wxDataViewCtrl // --------------------------------------------------------- -class WXDLLIMPEXP_CORE wxDataViewCtrl : public wxDataViewCtrlBase, - public wxScrollHelper +class WXDLLIMPEXP_CORE wxDataViewCtrl + : public wxCompositeWindow, + public wxScrollHelper { friend class wxDataViewMainWindow; friend class wxDataViewHeaderWindowBase; @@ -192,6 +194,8 @@ class WXDLLIMPEXP_CORE wxDataViewCtrl : public wxDataViewCtrlBase, friend class wxDataViewCtrlAccessible; #endif // wxUSE_ACCESSIBILITY + typedef wxCompositeWindow BaseType; + public: wxDataViewCtrl() : wxScrollHelper(this) { @@ -264,6 +268,8 @@ public: virtual void SetFocus() wxOVERRIDE; virtual bool SetFont(const wxFont & font) wxOVERRIDE; + virtual bool SetForegroundColour(const wxColour& colour) wxOVERRIDE; + virtual bool SetBackgroundColour(const wxColour& colour) wxOVERRIDE; #if wxUSE_ACCESSIBILITY virtual bool Show(bool show = true) wxOVERRIDE; @@ -361,6 +367,9 @@ public: // utility functions not part of the API #endif // wxUSE_ACCESSIBILITY private: + // Implement pure virtual method inherited from wxCompositeWindow. + virtual wxWindowList GetCompositeWindowParts() const wxOVERRIDE; + virtual wxDataViewItem DoGetCurrentItem() const wxOVERRIDE; virtual void DoSetCurrentItem(const wxDataViewItem& item) wxOVERRIDE; diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 41e821cb83..742002aab2 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -617,9 +617,6 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int wxSizer *firstPanelSz = new wxBoxSizer( wxVERTICAL ); m_ctrl[Page_Music]->SetMinSize(wxSize(-1, 200)); firstPanelSz->Add(m_ctrl[Page_Music], 1, wxGROW|wxALL, 5); - firstPanelSz->Add( - new wxStaticText(firstPanel, wxID_ANY, "Most of the cells above are editable!"), - 0, wxGROW|wxALL, 5); firstPanelSz->Add(button_sizer); firstPanelSz->Add(sizerCurrent); firstPanel->SetSizerAndFit(firstPanelSz); @@ -837,6 +834,8 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l // select initially the ninth symphony: m_ctrl[Page_Music]->Select(m_music_model->GetNinthItem()); + + m_ctrl[Page_Music]->SetToolTip("You may edit most of the cells here!"); } break; diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 164e2a6b0d..449f355668 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -5584,6 +5584,14 @@ bool wxDataViewCtrl::Create(wxWindow *parent, return true; } +wxWindowList wxDataViewCtrl::GetCompositeWindowParts() const +{ + wxWindowList parts; + parts.push_back(m_headerArea); // It's ok to add it even if it's null. + parts.push_back(m_clientArea); + return parts; +} + wxBorder wxDataViewCtrl::GetDefaultBorder() const { return wxBORDER_THEME; @@ -5679,15 +5687,11 @@ void wxDataViewCtrl::SetFocus() bool wxDataViewCtrl::SetFont(const wxFont & font) { - if (!wxControl::SetFont(font)) + if (!BaseType::SetFont(font)) return false; - if (m_headerArea) - m_headerArea->SetFont(font); - if (m_clientArea) { - m_clientArea->SetFont(font); m_clientArea->SetRowHeight(m_clientArea->GetDefaultRowHeight()); } @@ -5700,6 +5704,35 @@ bool wxDataViewCtrl::SetFont(const wxFont & font) return true; } +bool wxDataViewCtrl::SetForegroundColour(const wxColour& colour) +{ + // Previous versions of this class, not using wxCompositeWindow, as well as + // the native versions of this control, don't change the header foreground + // when this method is called and this could be more desirable in practice, + // as well we being more compatible, so skip calling the base class version + // that would change it as well and change only the main items area colour + // here too. + if ( !wxDataViewCtrlBase::SetForegroundColour(colour) ) + return false; + + if ( m_clientArea ) + m_clientArea->SetForegroundColour(colour); + + return true; +} + +bool wxDataViewCtrl::SetBackgroundColour(const wxColour& colour) +{ + // See SetForegroundColour() above. + if ( !wxDataViewCtrlBase::SetBackgroundColour(colour) ) + return false; + + if ( m_clientArea ) + m_clientArea->SetBackgroundColour(colour); + + return true; +} + #if wxUSE_ACCESSIBILITY bool wxDataViewCtrl::Show(bool show) { From f16b502f66d0466fa5d1921bb24fcac8add92891 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 23 May 2021 14:32:39 +0100 Subject: [PATCH 4/4] Forward key down/up events from wxCompositeWindow children too There doesn't seem to be any reason to only forward CHAR events, but not KEY_{DOWN,UP} ones, so do the same thing for the latter ones too. This allows to get rid of GetMainWindow() call in wxDataViewCtrl unit tests, as wxEVT_KEY_DOWN are now correctly received in the control itself and not just its main window. --- include/wx/compositewin.h | 8 ++++++-- tests/controls/dataviewctrltest.cpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/wx/compositewin.h b/include/wx/compositewin.h index a5d93b02bf..32bfcdd9cf 100644 --- a/include/wx/compositewin.h +++ b/include/wx/compositewin.h @@ -218,10 +218,14 @@ private: win = win->GetParent(); } - child->Bind(wxEVT_CHAR, &wxCompositeWindow::OnChar, this); + // Make all keyboard events occurring in sub-windows appear as coming + // from the main window itself. + child->Bind(wxEVT_KEY_DOWN, &wxCompositeWindow::OnKeyEvent, this); + child->Bind(wxEVT_CHAR, &wxCompositeWindow::OnKeyEvent, this); + child->Bind(wxEVT_KEY_UP, &wxCompositeWindow::OnKeyEvent, this); } - void OnChar(wxKeyEvent& event) + void OnKeyEvent(wxKeyEvent& event) { wxEventObjectOriginSetter setThis(event, this, this->GetId()); diff --git a/tests/controls/dataviewctrltest.cpp b/tests/controls/dataviewctrltest.cpp index a22a5aad11..d1c7053af1 100644 --- a/tests/controls/dataviewctrltest.cpp +++ b/tests/controls/dataviewctrltest.cpp @@ -423,7 +423,7 @@ TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, if ( !EnableUITests() ) return; - EventCounter keyEvents(m_dvc->GetMainWindow(), wxEVT_KEY_DOWN); + EventCounter keyEvents(m_dvc, wxEVT_KEY_DOWN); m_dvc->SetFocus();