From dfec7aa0c08617ed61fc1ee04551aea19dc6abd0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Dec 2018 01:01:49 +0100 Subject: [PATCH 1/4] Make disabling the window before creating it actually work Disabling a window before actually creating it ought to work, similarly to hiding a window before creating it which can be used to avoid showing the window on screen at all, even briefly. However it didn't under MSW where the window was disabled from wxWidgets point of view, but not at the MSW level. Fix this by accounting for the enabled state in MSWGetStyle(). Closes #16385. --- docs/changes.txt | 8 ++++++++ src/msw/window.cpp | 3 +++ tests/controls/buttontest.cpp | 17 +++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index ea37991c44..5ce2c6c4c2 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -102,6 +102,14 @@ Changes in behaviour which may result in build errors removing its name. +3.1.?: (released 2012-??-??) +---------------------------- + +All (GUI): + +- Make disabling the window before creating it actually work. + + 3.1.2: (released 2018-12-10) ---------------------------- diff --git a/src/msw/window.cpp b/src/msw/window.cpp index e17b851b59..609f6e8c19 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1518,6 +1518,9 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle() WXDWORD style = WS_CHILD; + if ( !IsThisEnabled() ) + style |= WS_DISABLED; + // using this flag results in very significant reduction in flicker, // especially with controls inside the static boxes (as the interior of the // box is not redrawn twice), but sometimes results in redraw problems, so diff --git a/tests/controls/buttontest.cpp b/tests/controls/buttontest.cpp index 764de5b28e..4f84523828 100644 --- a/tests/controls/buttontest.cpp +++ b/tests/controls/buttontest.cpp @@ -102,8 +102,21 @@ void ButtonTestCase::Disabled() wxUIActionSimulator sim; - //In this test we disable the button and check events are not sent - m_button->Disable(); + // In this test we disable the button and check events are not sent and we + // do it once by disabling the previously enabled button and once by + // creating the button in the disabled state. + SECTION("Disable after creation") + { + m_button->Disable(); + } + + SECTION("Create disabled") + { + delete m_button; + m_button = new wxButton(); + m_button->Disable(); + m_button->Create(wxTheApp->GetTopWindow(), wxID_ANY, "wxButton"); + } sim.MouseMove(m_button->GetScreenPosition() + wxPoint(10, 10)); wxYield(); From 5ba1ba1162b51a838f4fe2cbfae6b7bdff583ce6 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Dec 2018 01:15:08 +0100 Subject: [PATCH 2/4] Fix creating disabled windows in wxGTK too Don't forbid calling Enable() before creating the window and just do nothing in this case and do disable the window when it's actually created if it's supposed to be disabled. Note that this doesn't work for classes overriding Enable() directly, such as wxButton or wxCheckBox, currently. --- src/gtk/window.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index e440422ab7..32340aaa62 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -2913,6 +2913,11 @@ void wxWindowGTK::PostCreation() SetLayoutDirection(wxLayout_Default); + // if the window had been disabled before being created, it should be + // created in the initially disabled state + if ( !m_isEnabled ) + DoEnable(false); + // unless the window was created initially hidden (i.e. Hide() had been // called before Create()), we should show it at GTK+ level as well if (m_isShown) @@ -4196,7 +4201,12 @@ bool wxWindowGTK::IsShown() const void wxWindowGTK::DoEnable( bool enable ) { - wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); + if ( !m_widget ) + { + // The window can be disabled before being created, so just don't do + // anything in this case and, in particular, don't assert. + return; + } gtk_widget_set_sensitive( m_widget, enable ); if (m_wxwindow && (m_wxwindow != m_widget)) From 96f3832d52e3c6bfd1fd351d2fdbabc6c48a19e8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Dec 2018 01:31:43 +0100 Subject: [PATCH 3/4] Override DoEnable() instead of Enable() in wxGTK controls This is slightly simpler, as it doesn't require checking whether the control state really changes or not (it always does if DoEnable() is called) and allows disabling the controls before creating them, e.g. code like wxButton* const b = new wxButton(); b->Disable(); b->Create(this, wxID_OK); works as expected now instead of spewing GTK+ errors. --- include/wx/gtk/anybutton.h | 4 ++-- include/wx/gtk/checkbox.h | 3 ++- include/wx/gtk/radiobox.h | 2 ++ include/wx/gtk/radiobut.h | 3 ++- include/wx/gtk/spinbutt.h | 4 ++-- include/wx/gtk/textctrl.h | 3 ++- src/gtk/anybutton.cpp | 11 ++++++----- src/gtk/checkbox.cpp | 10 +++++----- src/gtk/radiobox.cpp | 16 ++++++++++++---- src/gtk/radiobut.cpp | 10 +++++----- src/gtk/spinbutt.cpp | 10 +++++----- src/gtk/textctrl.cpp | 13 +++++-------- 12 files changed, 50 insertions(+), 39 deletions(-) diff --git a/include/wx/gtk/anybutton.h b/include/wx/gtk/anybutton.h index ad0357a659..0b149ec085 100644 --- a/include/wx/gtk/anybutton.h +++ b/include/wx/gtk/anybutton.h @@ -23,8 +23,6 @@ public: m_isPressed = false; } - virtual bool Enable( bool enable = true ) wxOVERRIDE; - // implementation // -------------- @@ -41,6 +39,8 @@ public: protected: virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const wxOVERRIDE; + virtual void DoEnable(bool enable) wxOVERRIDE; + virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE; virtual void DoSetBitmap(const wxBitmap& bitmap, State which) wxOVERRIDE; virtual void DoSetBitmapPosition(wxDirection dir) wxOVERRIDE; diff --git a/include/wx/gtk/checkbox.h b/include/wx/gtk/checkbox.h index 8068f0b556..e16bc4f3ff 100644 --- a/include/wx/gtk/checkbox.h +++ b/include/wx/gtk/checkbox.h @@ -39,7 +39,6 @@ public: bool GetValue() const wxOVERRIDE; virtual void SetLabel( const wxString& label ) wxOVERRIDE; - virtual bool Enable( bool enable = true ) wxOVERRIDE; static wxVisualAttributes GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); @@ -52,6 +51,8 @@ protected: virtual void DoApplyWidgetStyle(GtkRcStyle *style) wxOVERRIDE; virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const wxOVERRIDE; + virtual void DoEnable(bool enable) wxOVERRIDE; + void DoSet3StateValue(wxCheckBoxState state) wxOVERRIDE; wxCheckBoxState DoGet3StateValue() const wxOVERRIDE; diff --git a/include/wx/gtk/radiobox.h b/include/wx/gtk/radiobox.h index 9e7df61a93..f38f82a599 100644 --- a/include/wx/gtk/radiobox.h +++ b/include/wx/gtk/radiobox.h @@ -141,6 +141,8 @@ protected: virtual void DoApplyWidgetStyle(GtkRcStyle *style) wxOVERRIDE; virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const wxOVERRIDE; + virtual void DoEnable(bool enable) wxOVERRIDE; + virtual bool GTKNeedsToFilterSameWindowFocus() const wxOVERRIDE { return true; } virtual bool GTKWidgetNeedsMnemonic() const wxOVERRIDE; diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index 340c671c1e..7ef6a6a162 100644 --- a/include/wx/gtk/radiobut.h +++ b/include/wx/gtk/radiobut.h @@ -41,7 +41,6 @@ public: virtual void SetLabel(const wxString& label) wxOVERRIDE; virtual void SetValue(bool val); virtual bool GetValue() const; - virtual bool Enable( bool enable = true ) wxOVERRIDE; static wxVisualAttributes GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); @@ -52,6 +51,8 @@ protected: virtual void DoApplyWidgetStyle(GtkRcStyle *style) wxOVERRIDE; virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const wxOVERRIDE; + virtual void DoEnable(bool enable) wxOVERRIDE; + private: typedef wxControl base_type; diff --git a/include/wx/gtk/spinbutt.h b/include/wx/gtk/spinbutt.h index ae974200b7..437198173c 100644 --- a/include/wx/gtk/spinbutt.h +++ b/include/wx/gtk/spinbutt.h @@ -44,8 +44,6 @@ public: static wxVisualAttributes GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); - virtual bool Enable( bool enable = true ) wxOVERRIDE; - // implementation int m_pos; @@ -56,6 +54,8 @@ protected: virtual wxSize DoGetBestSize() const wxOVERRIDE; virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const wxOVERRIDE; + virtual void DoEnable(bool enable) wxOVERRIDE; + private: typedef wxSpinButtonBase base_type; diff --git a/include/wx/gtk/textctrl.h b/include/wx/gtk/textctrl.h index f27d38cfa7..d411188a66 100644 --- a/include/wx/gtk/textctrl.h +++ b/include/wx/gtk/textctrl.h @@ -95,7 +95,6 @@ public: // Overridden wxWindow methods virtual void SetWindowStyleFlag( long style ) wxOVERRIDE; - virtual bool Enable( bool enable = true ) wxOVERRIDE; // Implementation from now on void OnDropFiles( wxDropFilesEvent &event ); @@ -178,6 +177,8 @@ protected: private: void Init(); + virtual void DoEnable(bool enable) wxOVERRIDE; + // overridden wxTextEntry virtual methods virtual GtkEditable *GetEditable() const wxOVERRIDE; virtual GtkEntry *GetEntry() const wxOVERRIDE; diff --git a/src/gtk/anybutton.cpp b/src/gtk/anybutton.cpp index 0742eed15f..9859016a37 100644 --- a/src/gtk/anybutton.cpp +++ b/src/gtk/anybutton.cpp @@ -69,10 +69,13 @@ wxgtk_button_released_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button) // wxAnyButton //----------------------------------------------------------------------------- -bool wxAnyButton::Enable( bool enable ) +void wxAnyButton::DoEnable(bool enable) { - if (!base_type::Enable(enable)) - return false; + // See wxWindow::DoEnable() + if ( !m_widget ) + return; + + base_type::DoEnable(enable); gtk_widget_set_sensitive(gtk_bin_get_child(GTK_BIN(m_widget)), enable); @@ -80,8 +83,6 @@ bool wxAnyButton::Enable( bool enable ) GTKFixSensitivity(); GTKUpdateBitmap(); - - return true; } GdkWindow *wxAnyButton::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const diff --git a/src/gtk/checkbox.cpp b/src/gtk/checkbox.cpp index 401f94358d..d11c7ef205 100644 --- a/src/gtk/checkbox.cpp +++ b/src/gtk/checkbox.cpp @@ -222,17 +222,17 @@ void wxCheckBox::SetLabel( const wxString& label ) GTKSetLabelForLabel(GTK_LABEL(m_widgetLabel), label); } -bool wxCheckBox::Enable( bool enable ) +void wxCheckBox::DoEnable(bool enable) { - if (!base_type::Enable(enable)) - return false; + if ( !m_widgetLabel ) + return; + + base_type::DoEnable(enable); gtk_widget_set_sensitive( m_widgetLabel, enable ); if (enable) GTKFixSensitivity(); - - return true; } void wxCheckBox::DoApplyWidgetStyle(GtkRcStyle *style) diff --git a/src/gtk/radiobox.cpp b/src/gtk/radiobox.cpp index b75e127ecd..c93fde74d2 100644 --- a/src/gtk/radiobox.cpp +++ b/src/gtk/radiobox.cpp @@ -487,8 +487,18 @@ void wxRadioBox::SetString(unsigned int item, const wxString& label) bool wxRadioBox::Enable( bool enable ) { - if ( !wxControl::Enable( enable ) ) - return false; + // Explicitly forward to the base class just because we need to override + // this function to prevent it from being hidden by Enable(int, bool) + // overload. + return wxControl::Enable(enable); +} + +void wxRadioBox::DoEnable(bool enable) +{ + if ( !m_widget ) + return; + + wxControl::DoEnable(enable); wxRadioBoxButtonsInfoList::compatibility_iterator node = m_buttonsInfo.GetFirst(); while (node) @@ -503,8 +513,6 @@ bool wxRadioBox::Enable( bool enable ) if (enable) GTKFixSensitivity(); - - return true; } bool wxRadioBox::Enable(unsigned int item, bool enable) diff --git a/src/gtk/radiobut.cpp b/src/gtk/radiobut.cpp index 9b87a178ad..b77a52cdd6 100644 --- a/src/gtk/radiobut.cpp +++ b/src/gtk/radiobut.cpp @@ -149,17 +149,17 @@ bool wxRadioButton::GetValue() const return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_widget)) != 0; } -bool wxRadioButton::Enable( bool enable ) +void wxRadioButton::DoEnable(bool enable) { - if (!base_type::Enable(enable)) - return false; + if ( !m_widget ) + return; + + base_type::DoEnable(enable); gtk_widget_set_sensitive(gtk_bin_get_child(GTK_BIN(m_widget)), enable); if (enable) GTKFixSensitivity(); - - return true; } void wxRadioButton::DoApplyWidgetStyle(GtkRcStyle *style) diff --git a/src/gtk/spinbutt.cpp b/src/gtk/spinbutt.cpp index a0a3ebef55..56f86fb1f0 100644 --- a/src/gtk/spinbutt.cpp +++ b/src/gtk/spinbutt.cpp @@ -173,16 +173,16 @@ void wxSpinButton::SetRange(int minVal, int maxVal) GtkEnableEvents(); } -bool wxSpinButton::Enable( bool enable ) +void wxSpinButton::DoEnable(bool enable) { - if (!base_type::Enable(enable)) - return false; + if ( !m_widget ) + return; + + base_type::DoEnable(enable); // Work around lack of visual update when enabling if (enable) GTKFixSensitivity(false /* fix even if not under mouse */); - - return true; } void wxSpinButton::GtkDisableEvents() const diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index b8551d37c7..fe47602ac6 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -1350,17 +1350,14 @@ void wxTextCtrl::SetEditable( bool editable ) } } -bool wxTextCtrl::Enable( bool enable ) +void wxTextCtrl::DoEnable(bool enable) { - if (!wxWindowBase::Enable(enable)) - { - // nothing to do - return false; - } + if ( !m_text ) + return; + + wxTextCtrlBase::DoEnable(enable); gtk_widget_set_sensitive( m_text, enable ); - - return true; } void wxTextCtrl::MarkDirty() From 0de31f03a1ad63f8b779c8a85a8ffc08ee57714f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Dec 2018 01:48:49 +0100 Subject: [PATCH 4/4] Document that Enable() can be called before creating the window Explicitly mention that calling Enable() for a window which hasn't been created yet is allowed. --- interface/wx/window.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/wx/window.h b/interface/wx/window.h index 97184e1c28..64b3c1d58d 100644 --- a/interface/wx/window.h +++ b/interface/wx/window.h @@ -2834,6 +2834,14 @@ public: disabled, all of its children are disabled as well and they are reenabled again when the parent is. + A window can be created initially disabled by calling this method on it + @e before calling Create() to create the actual underlying window, e.g. + @code + wxWindow* w = new MyWindow(); // Note: default ctor is used here. + w->Enable(false); + w->Create(parent, ... all the usual non-default ctor arguments ...); + @endcode + @param enable If @true, enables the window for input. If @false, disables the window.