From b6f8a8cf5be0702770cb78067dd8b459c06126ae Mon Sep 17 00:00:00 2001 From: Dummy Date: Sun, 18 Apr 2021 01:27:37 +0100 Subject: [PATCH 01/16] Add wxSpinCtrl::GetTextValue() This allows to retrieve the current contents of the text entry part of wxSpinCtrl. For now provide a stub in the base class, will be made pure virtual later. Co-Authored-By: Vadim Zeitlin --- include/wx/generic/spinctlg.h | 1 + include/wx/gtk/spinctrl.h | 1 + include/wx/msw/spinctrl.h | 1 + include/wx/spinctrl.h | 1 + interface/wx/spinctrl.h | 14 ++++++++++++++ src/generic/spinctlg.cpp | 5 +++++ src/gtk/spinctrl.cpp | 7 +++++++ src/msw/spinctrl.cpp | 5 +++++ 8 files changed, 35 insertions(+) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index bcb589ef15..8f3e5ecc92 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -60,6 +60,7 @@ public: virtual ~wxSpinCtrlGenericBase(); // accessors + virtual wxString GetTextValue() const wxOVERRIDE; // T GetValue() const // T GetMin() const // T GetMax() const diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index 0db4cb0b39..b3db6befcd 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -35,6 +35,7 @@ public: // wxSpinCtrl(Double) methods call DoXXX functions of the same name // accessors + virtual wxString GetTextValue() const wxOVERRIDE; // T GetValue() const // T GetMin() const // T GetMax() const diff --git a/include/wx/msw/spinctrl.h b/include/wx/msw/spinctrl.h index 491d9d99bd..b222089165 100644 --- a/include/wx/msw/spinctrl.h +++ b/include/wx/msw/spinctrl.h @@ -62,6 +62,7 @@ public: void SetSelection(long from, long to); // wxSpinCtrlBase methods + virtual wxString GetTextValue() const; virtual int GetBase() const; virtual bool SetBase(int base); diff --git a/include/wx/spinctrl.h b/include/wx/spinctrl.h index 775672f97b..3c49cb6f31 100644 --- a/include/wx/spinctrl.h +++ b/include/wx/spinctrl.h @@ -35,6 +35,7 @@ public: wxSpinCtrlBase() {} // accessor functions that derived classes are expected to have + virtual wxString GetTextValue() const { return wxString(); } // T GetValue() const // T GetMin() const // T GetMax() const diff --git a/interface/wx/spinctrl.h b/interface/wx/spinctrl.h index 98cc2bd189..a92b458e02 100644 --- a/interface/wx/spinctrl.h +++ b/interface/wx/spinctrl.h @@ -133,6 +133,13 @@ public: */ int GetMin() const; + /** + Returns the text in the text entry part of the control. + + @since 3.1.6 + */ + wxString GetTextValue() const; + /** Gets the value of the spin control. */ @@ -315,6 +322,13 @@ public: */ double GetMin() const; + /** + Returns the text in the text entry part of the control. + + @since 3.1.6 + */ + wxString GetTextValue() const; + /** Gets the value of the spin control. */ diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index 28393d38fa..aa99410c35 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -506,6 +506,11 @@ bool wxSpinCtrlGenericBase::SyncSpinToText(SendEvent sendEvent) // changing value and range // ---------------------------------------------------------------------------- +wxString wxSpinCtrlGenericBase::GetTextValue() const +{ + return m_textCtrl ? m_textCtrl->GetValue() : wxString(); +} + void wxSpinCtrlGenericBase::SetValue(const wxString& text) { wxCHECK_RET( m_textCtrl, wxT("invalid call to wxSpinCtrl::SetValue") ); diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index 14793ec74c..2d8914caff 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -214,6 +214,13 @@ double wxSpinCtrlGTKBase::DoGetIncrement() const return inc; } +wxString wxSpinCtrlGTKBase::GetTextValue() const +{ + wxCHECK_MSG(m_widget, wxEmptyString, "invalid spin button"); + + return gtk_entry_get_text( GTK_ENTRY(m_widget) ); +} + bool wxSpinCtrlGTKBase::GetSnapToTicks() const { wxCHECK_MSG(m_widget, false, "invalid spin button"); diff --git a/src/msw/spinctrl.cpp b/src/msw/spinctrl.cpp index f4c60ba158..9cad282bcc 100644 --- a/src/msw/spinctrl.cpp +++ b/src/msw/spinctrl.cpp @@ -442,6 +442,11 @@ bool wxSpinCtrl::SetBase(int base) // wxTextCtrl-like methods // ---------------------------------------------------------------------------- +wxString wxSpinCtrl::GetTextValue() const +{ + return wxGetWindowText(m_hwndBuddy); +} + void wxSpinCtrl::SetValue(const wxString& text) { if ( !::SetWindowText(GetBuddyHwnd(), text.c_str()) ) From f2d3589d887073b54f3dbc7580b122de16d4e5cd Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 18 Apr 2021 13:04:47 +0200 Subject: [PATCH 02/16] Also implement wxSpinCtrl::GetTextValue() for wxGTK1 --- include/wx/gtk1/spinctrl.h | 1 + src/gtk1/spinctrl.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/wx/gtk1/spinctrl.h b/include/wx/gtk1/spinctrl.h index 45a7473ca0..f037be2ebe 100644 --- a/include/wx/gtk1/spinctrl.h +++ b/include/wx/gtk1/spinctrl.h @@ -48,6 +48,7 @@ public: void SetValue(const wxString& text); void SetSelection(long from, long to); + virtual wxString GetTextValue() const; virtual int GetValue() const; virtual void SetValue( int value ); virtual void SetRange( int minVal, int maxVal ); diff --git a/src/gtk1/spinctrl.cpp b/src/gtk1/spinctrl.cpp index 98934ec791..0483b21d33 100644 --- a/src/gtk1/spinctrl.cpp +++ b/src/gtk1/spinctrl.cpp @@ -203,6 +203,13 @@ int wxSpinCtrl::GetMax() const return (int)ceil(m_adjust->upper); } +wxString wxSpinCtrl::GetTextValue() const +{ + wxCHECK_MSG(m_widget, wxEmptyString, "invalid spin button"); + + return gtk_entry_get_text( GTK_ENTRY(m_widget) ); +} + int wxSpinCtrl::GetValue() const { wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") ); From e5042a6a539f7ddabe73a8cc2e979baffb1aa710 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 18 Apr 2021 13:05:09 +0200 Subject: [PATCH 03/16] Implement wxSpinCtrl::GetTextValue() for wxQt too --- include/wx/qt/spinctrl.h | 1 + src/qt/spinctrl.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/wx/qt/spinctrl.h b/include/wx/qt/spinctrl.h index 9355ff9fc6..c6f0ca5954 100644 --- a/include/wx/qt/spinctrl.h +++ b/include/wx/qt/spinctrl.h @@ -29,6 +29,7 @@ public: T min, T max, T initial, T inc, const wxString& name ); + virtual wxString GetTextValue() const wxOVERRIDE; virtual void SetValue(const wxString&) wxOVERRIDE {} virtual void SetSnapToTicks(bool snap_to_ticks) wxOVERRIDE; diff --git a/src/qt/spinctrl.cpp b/src/qt/spinctrl.cpp index 1e67adc6af..d1c4b628f4 100644 --- a/src/qt/spinctrl.cpp +++ b/src/qt/spinctrl.cpp @@ -58,6 +58,12 @@ bool wxSpinCtrlQt< T, Widget >::Create( wxWindow *parent, wxWindowID id, return QtCreateControl( parent, id, pos, size, style, wxDefaultValidator, name ); } +template< typename T, typename Widget > +wxString wxSpinCtrlQt< T, Widget >::GetTextValue() const +{ + return wxQtConvertString(m_qtSpinBox->text()); +} + template< typename T, typename Widget > void wxSpinCtrlQt< T, Widget >::SetValue( T val ) { From 11967af49f58027d51977b3f5793deba0a660d2f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 18 Apr 2021 13:09:51 +0200 Subject: [PATCH 04/16] Make wxSpinCtrl::GetTextValue() pure virtual It is now implemented in all ports. --- include/wx/spinctrl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wx/spinctrl.h b/include/wx/spinctrl.h index 3c49cb6f31..42d2af59c4 100644 --- a/include/wx/spinctrl.h +++ b/include/wx/spinctrl.h @@ -35,7 +35,7 @@ public: wxSpinCtrlBase() {} // accessor functions that derived classes are expected to have - virtual wxString GetTextValue() const { return wxString(); } + virtual wxString GetTextValue() const = 0; // T GetValue() const // T GetMin() const // T GetMax() const From 34ab87ce4d0980119535837ddbea6d288d464983 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 19 Apr 2021 21:57:17 +0200 Subject: [PATCH 05/16] Get rid of CppUnit boilerplate in wxSpinCtrlDouble unit test This was already done for wxSpinCtrl unit tests in a4928c0fde (Use Catch in wxSpinCtrl unit tests, 2020-07-12), do it for wxSpinCtrlDouble too now. --- tests/controls/spinctrldbltest.cpp | 155 +++++++++++++---------------- 1 file changed, 69 insertions(+), 86 deletions(-) diff --git a/tests/controls/spinctrldbltest.cpp b/tests/controls/spinctrldbltest.cpp index 77668b75ed..b491b5e48a 100644 --- a/tests/controls/spinctrldbltest.cpp +++ b/tests/controls/spinctrldbltest.cpp @@ -19,76 +19,59 @@ #include "wx/uiaction.h" #include "wx/spinctrl.h" -class SpinCtrlDoubleTestCase : public CppUnit::TestCase +class SpinCtrlDoubleTestCase { public: - SpinCtrlDoubleTestCase() { } + SpinCtrlDoubleTestCase(int style = wxSP_ARROW_KEYS) + : m_spin(new wxSpinCtrlDouble(wxTheApp->GetTopWindow(), wxID_ANY, "", + wxDefaultPosition, wxDefaultSize, + style)) + { + } - void setUp() wxOVERRIDE; - void tearDown() wxOVERRIDE; + ~SpinCtrlDoubleTestCase() + { + delete m_spin; + } -private: - CPPUNIT_TEST_SUITE( SpinCtrlDoubleTestCase ); - CPPUNIT_TEST( NoEventsInCtor ); - WXUISIM_TEST( Arrows ); - WXUISIM_TEST( Wrap ); - CPPUNIT_TEST( Range ); - CPPUNIT_TEST( Value ); - WXUISIM_TEST( Increment ); - CPPUNIT_TEST( Digits ); - CPPUNIT_TEST_SUITE_END(); - - void NoEventsInCtor(); - void Arrows(); - void Wrap(); - void Range(); - void Value(); - void Increment(); - void Digits(); - - wxSpinCtrlDouble* m_spin; +protected: + wxSpinCtrlDouble* const m_spin; wxDECLARE_NO_COPY_CLASS(SpinCtrlDoubleTestCase); }; -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( SpinCtrlDoubleTestCase ); - -// also include in its own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( SpinCtrlDoubleTestCase, "SpinCtrlDoubleTestCase" ); - -void SpinCtrlDoubleTestCase::setUp() +class SpinCtrlDoubleTestCaseWrap : public SpinCtrlDoubleTestCase { - m_spin = new wxSpinCtrlDouble(wxTheApp->GetTopWindow()); -} +public: + SpinCtrlDoubleTestCaseWrap() + : SpinCtrlDoubleTestCase(wxSP_ARROW_KEYS | wxSP_WRAP) + { + } +}; -void SpinCtrlDoubleTestCase::tearDown() -{ - wxDELETE(m_spin); -} -void SpinCtrlDoubleTestCase::NoEventsInCtor() +TEST_CASE("SpinCtrlDouble::NoEventsInCtor", "[spinctrl][spinctrldouble]") { // Verify that creating the control does not generate any events. This is // unexpected and shouldn't happen. - wxWindow* const parent = m_spin->GetParent(); - delete m_spin; - m_spin = new wxSpinCtrlDouble; + wxSpinCtrlDouble *m_spin = new wxSpinCtrlDouble; EventCounter updatedSpin(m_spin, wxEVT_SPINCTRLDOUBLE); EventCounter updatedText(m_spin, wxEVT_TEXT); - m_spin->Create(parent, wxID_ANY, "", + m_spin->Create(wxTheApp->GetTopWindow(), wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0, 0., 100., 17.); - CPPUNIT_ASSERT_EQUAL(0, updatedSpin.GetCount()); - CPPUNIT_ASSERT_EQUAL(0, updatedText.GetCount()); + CHECK( updatedSpin.GetCount() == 0 ); + CHECK( updatedText.GetCount() == 0 ); } -void SpinCtrlDoubleTestCase::Arrows() -{ #if wxUSE_UIACTIONSIMULATOR + +TEST_CASE_METHOD(SpinCtrlDoubleTestCase, + "SpinCtrlDouble::Arrows", "[spinctrl][spinctrldouble]") +{ EventCounter updated(m_spin, wxEVT_SPINCTRLDOUBLE); wxUIActionSimulator sim; @@ -99,26 +82,20 @@ void SpinCtrlDoubleTestCase::Arrows() sim.Char(WXK_UP); wxYield(); - CPPUNIT_ASSERT_EQUAL(1, updated.GetCount()); - CPPUNIT_ASSERT_EQUAL(1.0, m_spin->GetValue()); + CHECK( updated.GetCount() == 1 ); + CHECK( m_spin->GetValue() == 1.0 ); updated.Clear(); sim.Char(WXK_DOWN); wxYield(); - CPPUNIT_ASSERT_EQUAL(1, updated.GetCount()); - CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetValue()); -#endif + CHECK( updated.GetCount() == 1 ); + CHECK( m_spin->GetValue() == 0.0 ); } -void SpinCtrlDoubleTestCase::Wrap() +TEST_CASE_METHOD(SpinCtrlDoubleTestCaseWrap, + "SpinCtrlDouble::Wrap", "[spinctrl][spinctrldouble]") { -#if wxUSE_UIACTIONSIMULATOR - wxDELETE(m_spin); - m_spin = new wxSpinCtrlDouble(wxTheApp->GetTopWindow(), wxID_ANY, "", - wxDefaultPosition, wxDefaultSize, - wxSP_ARROW_KEYS | wxSP_WRAP); - wxUIActionSimulator sim; m_spin->SetFocus(); @@ -128,20 +105,21 @@ void SpinCtrlDoubleTestCase::Wrap() wxYield(); - CPPUNIT_ASSERT_EQUAL(100.0, m_spin->GetValue()); + CHECK( m_spin->GetValue() == 100.0 ); sim.Char(WXK_UP); wxYield(); - CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetValue()); -#endif + CHECK( m_spin->GetValue() == 0.0 ); } +#endif // wxUSE_UIACTIONSIMULATOR -void SpinCtrlDoubleTestCase::Range() +TEST_CASE_METHOD(SpinCtrlDoubleTestCase, + "SpinCtrlDouble::Range", "[spinctrl][spinctrldouble]") { - CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetMin()); - CPPUNIT_ASSERT_EQUAL(100.0, m_spin->GetMax()); + CHECK( m_spin->GetMin() == 0.0 ); + CHECK( m_spin->GetMax() == 100.0 ); // Test that the value is adjusted to be inside the new valid range but // that this doesn't result in any events (as this is not something done by @@ -151,26 +129,27 @@ void SpinCtrlDoubleTestCase::Range() EventCounter updatedText(m_spin, wxEVT_TEXT); m_spin->SetRange(1., 10.); - CPPUNIT_ASSERT_EQUAL(1., m_spin->GetValue()); + CHECK( m_spin->GetValue() == 1. ); - CPPUNIT_ASSERT_EQUAL(0, updatedSpin.GetCount()); - CPPUNIT_ASSERT_EQUAL(0, updatedText.GetCount()); + CHECK( updatedSpin.GetCount() == 0 ); + CHECK( updatedText.GetCount() == 0 ); } //Test negative ranges m_spin->SetRange(-10.0, 10.0); - CPPUNIT_ASSERT_EQUAL(-10.0, m_spin->GetMin()); - CPPUNIT_ASSERT_EQUAL(10.0, m_spin->GetMax()); + CHECK( m_spin->GetMin() == -10.0 ); + CHECK( m_spin->GetMax() == 10.0 ); //Test backwards ranges m_spin->SetRange(75.0, 50.0); - CPPUNIT_ASSERT_EQUAL(75.0, m_spin->GetMin()); - CPPUNIT_ASSERT_EQUAL(50.0, m_spin->GetMax()); + CHECK( m_spin->GetMin() == 75.0 ); + CHECK( m_spin->GetMax() == 50.0 ); } -void SpinCtrlDoubleTestCase::Value() +TEST_CASE_METHOD(SpinCtrlDoubleTestCase, + "SpinCtrlDouble::Value", "[spinctrl][spinctrldouble]") { EventCounter updatedSpin(m_spin, wxEVT_SPINCTRLDOUBLE); EventCounter updatedText(m_spin, wxEVT_TEXT); @@ -178,28 +157,30 @@ void SpinCtrlDoubleTestCase::Value() m_spin->SetDigits(2); m_spin->SetIncrement(0.1); - CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetValue()); + CHECK( m_spin->GetValue() == 0.0 ); m_spin->SetValue(50.0); - CPPUNIT_ASSERT_EQUAL(50.0, m_spin->GetValue()); + CHECK( m_spin->GetValue() == 50.0 ); m_spin->SetValue(49.1); - CPPUNIT_ASSERT_EQUAL(49.1, m_spin->GetValue()); + CHECK( m_spin->GetValue() == 49.1 ); // Calling SetValue() shouldn't have generated any events. - CPPUNIT_ASSERT_EQUAL(0, updatedSpin.GetCount()); - CPPUNIT_ASSERT_EQUAL(0, updatedText.GetCount()); + CHECK( updatedSpin.GetCount() == 0 ); + CHECK( updatedText.GetCount() == 0 ); } -void SpinCtrlDoubleTestCase::Increment() -{ #if wxUSE_UIACTIONSIMULATOR - CPPUNIT_ASSERT_EQUAL(1.0, m_spin->GetIncrement()); + +TEST_CASE_METHOD(SpinCtrlDoubleTestCase, + "SpinCtrlDouble::Increment", "[spinctrl][spinctrldouble]") +{ + CHECK( m_spin->GetIncrement() == 1.0 ); m_spin->SetDigits(1); m_spin->SetIncrement(0.1); - CPPUNIT_ASSERT_EQUAL(0.1, m_spin->GetIncrement()); + CHECK( m_spin->GetIncrement() == 0.1 ); wxUIActionSimulator sim; @@ -210,15 +191,17 @@ void SpinCtrlDoubleTestCase::Increment() wxYield(); - CPPUNIT_ASSERT_EQUAL(0.1, m_spin->GetValue()); -#endif + CHECK( m_spin->GetValue() == 0.1 ); } -void SpinCtrlDoubleTestCase::Digits() +#endif // wxUSE_UIACTIONSIMULATOR + +TEST_CASE_METHOD(SpinCtrlDoubleTestCase, + "SpinCtrlDouble::Digits", "[spinctrl][spinctrldouble]") { m_spin->SetDigits(5); - CPPUNIT_ASSERT_EQUAL(5, m_spin->GetDigits()); + CHECK( m_spin->GetDigits() == 5 ); } static inline unsigned int GetInitialDigits(double inc) @@ -230,7 +213,7 @@ static inline unsigned int GetInitialDigits(double inc) return digits; } -TEST_CASE("SpinCtrlDoubleTestCase::InitialDigits", "[spinctrldouble][initialdigits]") +TEST_CASE("SpinCtrlDouble::InitialDigits", "[spinctrldouble][initialdigits]") { REQUIRE(GetInitialDigits(15) == 0); REQUIRE(GetInitialDigits(10) == 0); From f64da1eb3679ca076bfb7c6ba379e9d62a6a8a8b Mon Sep 17 00:00:00 2001 From: Dummy Date: Mon, 19 Apr 2021 23:38:03 +0200 Subject: [PATCH 06/16] Allow clearing spin controls in the widgets sample Calling wxSpinCtrl::SetValue("") is always valid. See #19140. --- samples/widgets/spinbtn.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/samples/widgets/spinbtn.cpp b/samples/widgets/spinbtn.cpp index 70006a3a21..609fc36ada 100644 --- a/samples/widgets/spinbtn.cpp +++ b/samples/widgets/spinbtn.cpp @@ -483,6 +483,14 @@ void SpinBtnWidgetsPage::OnButtonSetBase(wxCommandEvent& WXUNUSED(event)) void SpinBtnWidgetsPage::OnButtonSetValue(wxCommandEvent& WXUNUSED(event)) { + if ( m_textValue->IsEmpty() ) + { + m_spinctrl->SetValue( wxEmptyString ); + m_spinctrldbl->SetValue( wxEmptyString ); + + return; + } + long val; if ( !m_textValue->GetValue().ToLong(&val) || !IsValidValue(val) ) { @@ -499,7 +507,8 @@ void SpinBtnWidgetsPage::OnButtonSetValue(wxCommandEvent& WXUNUSED(event)) void SpinBtnWidgetsPage::OnUpdateUIValueButton(wxUpdateUIEvent& event) { long val; - event.Enable( m_textValue->GetValue().ToLong(&val) && IsValidValue(val) ); + event.Enable( m_textValue->IsEmpty() || + ( m_textValue->GetValue().ToLong(&val) && IsValidValue(val) ) ); } void SpinBtnWidgetsPage::OnUpdateUIMinMaxButton(wxUpdateUIEvent& event) From 4b263ff10aac0f26d2e897ed1d3d4fb7b0caef26 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 20 Apr 2021 01:02:16 +0200 Subject: [PATCH 07/16] Explicitly convert from UTF-8 in wxSpinCtrl::GetTextValue() Use UTF-8 encoding explicitly rather than relying on it being the default. --- src/gtk/spinctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index 2d8914caff..bd293c8a68 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -218,7 +218,7 @@ wxString wxSpinCtrlGTKBase::GetTextValue() const { wxCHECK_MSG(m_widget, wxEmptyString, "invalid spin button"); - return gtk_entry_get_text( GTK_ENTRY(m_widget) ); + return wxGTK_CONV_BACK(gtk_entry_get_text( GTK_ENTRY(m_widget) )); } bool wxSpinCtrlGTKBase::GetSnapToTicks() const From 8194f0555396e368fd13404517f8cda73c34fb78 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 20 Apr 2021 01:04:37 +0200 Subject: [PATCH 08/16] Simplify event sending code by using GetTextValue() Just use this function now that it's available rather than calling gtk_entry_get_text() (and sometimes forgetting to specify UTF-8 encoding explicitly). --- src/gtk/spinctrl.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index bd293c8a68..5f5dce9bd9 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -67,11 +67,11 @@ gtk_value_changed(GtkSpinButton* spinbutton, wxSpinCtrlGTKBase* win) extern "C" { static void -gtk_changed(GtkSpinButton* spinbutton, wxSpinCtrl* win) +gtk_changed(GtkSpinButton*, wxSpinCtrl* win) { wxCommandEvent event( wxEVT_TEXT, win->GetId() ); event.SetEventObject( win ); - event.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton))); + event.SetString(win->GetTextValue()); event.SetInt(win->GetValue()); win->HandleWindowEvent( event ); } @@ -343,9 +343,7 @@ void wxSpinCtrlGTKBase::OnChar( wxKeyEvent &event ) { wxCommandEvent evt( wxEVT_TEXT_ENTER, m_windowId ); evt.SetEventObject(this); - GtkSpinButton *gsb = GTK_SPIN_BUTTON(m_widget); - wxString val = wxGTK_CONV_BACK( gtk_entry_get_text( &gsb->entry ) ); - evt.SetString( val ); + evt.SetString(GetTextValue()); if (HandleWindowEvent(evt)) return; } From 3ac3763705bdbe01b1ffbacc44803d7b6340c5d4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 19 Apr 2021 21:33:28 +0200 Subject: [PATCH 09/16] Always handle "input" and "output" signals in wxGTK wxSpinCtrl No real changes yet, just refactor the code to always connect these signals handlers and not just when using non-decimal base. Add wxSpinCtrl::GTKInput() and GTKOutput() virtual methods to handle these signals appropriately depending on the type of the control. This will allow further customizing conversion to/from string in the upcoming commit and will also make it possible to handle UI locale different from the C locale in the future. --- include/wx/gtk/spinctrl.h | 19 +++++ src/gtk/spinctrl.cpp | 146 ++++++++++++++++++++++++-------------- 2 files changed, 112 insertions(+), 53 deletions(-) diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index b3db6befcd..900a1f2dc1 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -58,6 +58,19 @@ public: // implementation void OnChar( wxKeyEvent &event ); + + // These values map to the possible return values of "input" GTK signal but + // are more readable and type-safe. + enum GTKInputResult + { + GTKInput_Error = -1, + GTKInput_Default, + GTKInput_Converted + }; + + virtual GTKInputResult GTKInput(double* value) const = 0; + virtual bool GTKOutput(wxString* text) const = 0; + protected: double DoGetValue() const; double DoGetMin() const; @@ -138,6 +151,9 @@ public: virtual int GetBase() const wxOVERRIDE { return m_base; } virtual bool SetBase(int base) wxOVERRIDE; + virtual GTKInputResult GTKInput(double* value) const wxOVERRIDE; + virtual bool GTKOutput(wxString* text) const wxOVERRIDE; + protected: virtual void GtkSetEntryWidth() wxOVERRIDE; @@ -206,6 +222,9 @@ public: virtual int GetBase() const wxOVERRIDE { return 10; } virtual bool SetBase(int WXUNUSED(base)) wxOVERRIDE { return false; } + virtual GTKInputResult GTKInput(double* value) const wxOVERRIDE; + virtual bool GTKOutput(wxString* text) const wxOVERRIDE; + protected: virtual void GtkSetEntryWidth() wxOVERRIDE; diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index 5f5dce9bd9..fe64c3a906 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -77,6 +77,47 @@ gtk_changed(GtkSpinButton*, wxSpinCtrl* win) } } +//----------------------------------------------------------------------------- +// "input" and "output" +//----------------------------------------------------------------------------- + +extern "C" +{ + +static gint +wx_gtk_spin_input(GtkSpinButton*, gdouble* val, wxSpinCtrlGTKBase* win) +{ + switch ( win->GTKInput(val) ) + { + case wxSpinCtrl::GTKInput_Error: + return GTK_INPUT_ERROR; + + case wxSpinCtrl::GTKInput_Default: + return FALSE; + + case wxSpinCtrl::GTKInput_Converted: + return TRUE; + } + + wxFAIL_MSG("unreachable"); + return FALSE; +} + +static gint +wx_gtk_spin_output(GtkSpinButton* spin, wxSpinCtrlGTKBase* win) +{ + wxString text; + if ( !win->GTKOutput(&text) ) + return FALSE; + + if ( text != win->GetTextValue() ) + gtk_entry_set_text(GTK_ENTRY(spin), text.utf8_str()); + + return TRUE; +} + +} // extern "C" + // ---------------------------------------------------------------------------- // wxSpinCtrlEventDisabler: helper to temporarily disable GTK+ events // ---------------------------------------------------------------------------- @@ -146,6 +187,9 @@ bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id, g_signal_connect_after(m_widget, "value_changed", G_CALLBACK(gtk_value_changed), this); g_signal_connect_after(m_widget, "changed", G_CALLBACK(gtk_changed), this); + g_signal_connect(m_widget, "input", G_CALLBACK(wx_gtk_spin_input), this); + g_signal_connect(m_widget, "output", G_CALLBACK(wx_gtk_spin_output), this); + m_parent->DoAddChild( this ); PostCreation(size); @@ -399,42 +443,6 @@ wxSpinCtrlGTKBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) // wxSpinCtrl //----------------------------------------------------------------------------- -extern "C" -{ - -static gboolean -wx_gtk_spin_input(GtkSpinButton* spin, gdouble* val, wxSpinCtrl* win) -{ - // We might use g_ascii_strtoll() here but it's 2.12+ only, so use our own - // wxString function even if this requires an extra conversion. - const wxString - text(wxString::FromUTF8(gtk_entry_get_text(GTK_ENTRY(spin)))); - - long lval; - if ( !text.ToLong(&lval, win->GetBase()) ) - return FALSE; - - *val = lval; - - return TRUE; -} - -static gint -wx_gtk_spin_output(GtkSpinButton* spin, wxSpinCtrl* win) -{ - const gint val = gtk_spin_button_get_value_as_int(spin); - - gtk_entry_set_text - ( - GTK_ENTRY(spin), - wxSpinCtrlImpl::FormatAsHex(val, win->GetMax()).utf8_str() - ); - - return TRUE; -} - -} // extern "C" - void wxSpinCtrl::GtkSetEntryWidth() { const int minVal = static_cast(DoGetMin()); @@ -467,23 +475,6 @@ bool wxSpinCtrl::SetBase(int base) // We need to be able to enter letters for any base greater than 10. gtk_spin_button_set_numeric( GTK_SPIN_BUTTON(m_widget), m_base <= 10 ); - if ( m_base != 10 ) - { - g_signal_connect( m_widget, "input", - G_CALLBACK(wx_gtk_spin_input), this); - g_signal_connect( m_widget, "output", - G_CALLBACK(wx_gtk_spin_output), this); - } - else - { - g_signal_handlers_disconnect_by_func(m_widget, - (gpointer)wx_gtk_spin_input, - this); - g_signal_handlers_disconnect_by_func(m_widget, - (gpointer)wx_gtk_spin_output, - this); - } - InvalidateBestSize(); GtkSetEntryWidth(); @@ -494,6 +485,44 @@ bool wxSpinCtrl::SetBase(int base) return true; } +wxSpinCtrl::GTKInputResult +wxSpinCtrl::GTKInput(double* value) const +{ + // Don't override the default logic unless really needed. + if ( GetBase() == 10 ) + return GTKInput_Default; + + long lval; + if ( !GetTextValue().ToLong(&lval, GetBase()) ) + return GTKInput_Error; + + *value = lval; + + return GTKInput_Converted; +} + +bool wxSpinCtrl::GTKOutput(wxString* text) const +{ + switch ( GetBase() ) + { + default: + wxFAIL_MSG("unsupported base"); + wxFALLTHROUGH; + + case 10: + // Don't override the default output format unless really needed. + return false; + + case 16: + const gint val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(m_widget)); + + *text = wxSpinCtrlImpl::FormatAsHex(val, GetMax()); + break; + } + + return true; +} + //----------------------------------------------------------------------------- // wxSpinCtrlDouble //----------------------------------------------------------------------------- @@ -528,4 +557,15 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits) GtkSetEntryWidth(); } +wxSpinCtrl::GTKInputResult +wxSpinCtrlDouble::GTKInput(double* WXUNUSED(value)) const +{ + return GTKInput_Default; +} + +bool wxSpinCtrlDouble::GTKOutput(wxString* WXUNUSED(text)) const +{ + return false; +} + #endif // wxUSE_SPINCTRL From e73a0c23ef9829fc953ebacda8d8deab19bf3a90 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 20 Apr 2021 00:53:50 +0200 Subject: [PATCH 10/16] Replace dynamic cast with a virtual GTKValueChanged() function No real changes, but using a virtual function is simpler and safer than using wxIsKindOf(). --- include/wx/gtk/spinctrl.h | 4 ++++ src/gtk/spinctrl.cpp | 37 ++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index 900a1f2dc1..72de31d7ed 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -71,6 +71,8 @@ public: virtual GTKInputResult GTKInput(double* value) const = 0; virtual bool GTKOutput(wxString* text) const = 0; + virtual void GTKValueChanged() = 0; + protected: double DoGetValue() const; double DoGetMin() const; @@ -153,6 +155,7 @@ public: virtual GTKInputResult GTKInput(double* value) const wxOVERRIDE; virtual bool GTKOutput(wxString* text) const wxOVERRIDE; + virtual void GTKValueChanged() wxOVERRIDE; protected: virtual void GtkSetEntryWidth() wxOVERRIDE; @@ -224,6 +227,7 @@ public: virtual GTKInputResult GTKInput(double* value) const wxOVERRIDE; virtual bool GTKOutput(wxString* text) const wxOVERRIDE; + virtual void GTKValueChanged() wxOVERRIDE; protected: virtual void GtkSetEntryWidth() wxOVERRIDE; diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index fe64c3a906..c25be9a517 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -37,27 +37,12 @@ extern bool g_blockEventsOnDrag; extern "C" { static void -gtk_value_changed(GtkSpinButton* spinbutton, wxSpinCtrlGTKBase* win) +gtk_value_changed(GtkSpinButton*, wxSpinCtrlGTKBase* win) { if (g_blockEventsOnDrag) return; - if (wxIsKindOf(win, wxSpinCtrl)) - { - wxSpinEvent event(wxEVT_SPINCTRL, win->GetId()); - event.SetEventObject( win ); - event.SetPosition(static_cast(win)->GetValue()); - event.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton))); - win->HandleWindowEvent( event ); - } - else // wxIsKindOf(win, wxSpinCtrlDouble) - { - wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, win->GetId()); - event.SetEventObject( win ); - event.SetValue(static_cast(win)->GetValue()); - event.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton))); - win->HandleWindowEvent( event ); - } + win->GTKValueChanged(); } } @@ -523,6 +508,15 @@ bool wxSpinCtrl::GTKOutput(wxString* text) const return true; } +void wxSpinCtrl::GTKValueChanged() +{ + wxSpinEvent event(wxEVT_SPINCTRL, GetId()); + event.SetEventObject( this ); + event.SetPosition(GetValue()); + event.SetString(GetTextValue()); + HandleWindowEvent( event ); +} + //----------------------------------------------------------------------------- // wxSpinCtrlDouble //----------------------------------------------------------------------------- @@ -568,4 +562,13 @@ bool wxSpinCtrlDouble::GTKOutput(wxString* WXUNUSED(text)) const return false; } +void wxSpinCtrlDouble::GTKValueChanged() +{ + wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, GetId()); + event.SetEventObject( this ); + event.SetValue(GetValue()); + event.SetString(GetTextValue()); + HandleWindowEvent( event ); +} + #endif // wxUSE_SPINCTRL From ca0cf3ea5923c18e5c6c2229a2e2cb5c0640aba7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 20 Apr 2021 00:55:02 +0200 Subject: [PATCH 11/16] Allow using a different text value in wxGTK wxSpinCtrl Make it possible to use a string value different from the numeric value, as wxMSW version allows this and some existing code depends on it. Closes #19140. --- include/wx/gtk/spinctrl.h | 16 ++++ src/gtk/spinctrl.cpp | 128 +++++++++++++++++++++++++++-- tests/controls/spinctrldbltest.cpp | 11 +++ tests/controls/spinctrltest.cpp | 11 +++ 4 files changed, 159 insertions(+), 7 deletions(-) diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index 72de31d7ed..b5bfa96c72 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -74,6 +74,9 @@ public: virtual void GTKValueChanged() = 0; protected: + wxSpinCtrlGTKBase(); + ~wxSpinCtrlGTKBase(); + double DoGetValue() const; double DoGetMin() const; double DoGetMax() const; @@ -98,6 +101,19 @@ protected: // override this and return true. virtual bool UseGTKStyleBase() const wxOVERRIDE { return true; } + // Set or reset m_textOverride. + void GTKSetTextOverride(const wxString& text); + void GTKResetTextOverride(); + +private: + // This function does _not_ take into account m_textOverride, so it is + // private and normally shouldn't be used -- use DoGetValue() instead. + double GTKGetValue() const; + + // Non-null when the text value is different from the numeric value. + class wxSpinCtrlGTKTextOverride* m_textOverride; + + friend class wxSpinCtrlEventDisabler; wxDECLARE_EVENT_TABLE(); diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index c25be9a517..a48917547d 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -127,6 +127,22 @@ private: wxDECLARE_NO_COPY_CLASS(wxSpinCtrlEventDisabler); }; +// ---------------------------------------------------------------------------- +// wxSpinCtrlGTKTextOverride: extra data for using a separate string value +// ---------------------------------------------------------------------------- + +class wxSpinCtrlGTKTextOverride +{ +public: + wxSpinCtrlGTKTextOverride() + : m_value(0.0) + { + } + + wxString m_text; + double m_value; +}; + //----------------------------------------------------------------------------- // wxSpinCtrlGTKBase //----------------------------------------------------------------------------- @@ -135,6 +151,54 @@ wxBEGIN_EVENT_TABLE(wxSpinCtrlGTKBase, wxSpinCtrlBase) EVT_CHAR(wxSpinCtrlGTKBase::OnChar) wxEND_EVENT_TABLE() +wxSpinCtrlGTKBase::wxSpinCtrlGTKBase() + : m_textOverride(NULL) +{ +} + +wxSpinCtrlGTKBase::~wxSpinCtrlGTKBase() +{ + delete m_textOverride; +} + +void wxSpinCtrlGTKBase::GTKSetTextOverride(const wxString& text) +{ + if ( !m_textOverride ) + { + // Remember the original numeric value, that we're going to keep using + // it while this override is valid, and do it before initializing + // m_textOverride as our own "input" handler called from GTKGetValue() + // would use it if it were non-null. + const double value = GTKGetValue(); + + m_textOverride = new wxSpinCtrlGTKTextOverride(); + m_textOverride->m_value = value; + } + //else: No need to change the value, it stays the same anyhow. + + // Update the text in any case. + m_textOverride->m_text = text; +} + +void wxSpinCtrlGTKBase::GTKResetTextOverride() +{ + if ( !m_textOverride ) + return; + + delete m_textOverride; + m_textOverride = NULL; + + // Update the text part to reflect the numeric value now that we don't + // override it any longer, otherwise we'd keep showing the old one because + // the text is updated by GTK before "value" is generated. + wxSpinCtrlEventDisabler disable(this); + gtk_spin_button_set_value + ( + GTK_SPIN_BUTTON(m_widget), + gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget)) + ); +} + bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, @@ -188,6 +252,15 @@ bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id, } double wxSpinCtrlGTKBase::DoGetValue() const +{ + // While using a text override, the text value is fixed by the program and + // shouldn't be used, just return the numeric value we had had before, as + // the text override is reset whenever it changes, so it must not have + // changed yet. + return m_textOverride ? m_textOverride->m_value : GTKGetValue(); +} + +double wxSpinCtrlGTKBase::GTKGetValue() const { wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") ); @@ -269,7 +342,12 @@ void wxSpinCtrlGTKBase::SetValue( const wxString& value ) return; } - // invalid number - set text as is (wxMSW compatible) + // invalid number - set text as is (wxMSW compatible) and remember that it + // is set to avoid overwriting it later, which is notably important when + // we're called before the window is realized as the default "realize" + // handler will call our "output" handler + GTKSetTextOverride(value); + wxSpinCtrlEventDisabler disable(this); gtk_entry_set_text( GTK_ENTRY(m_widget), wxGTK_CONV( value ) ); } @@ -278,6 +356,8 @@ void wxSpinCtrlGTKBase::DoSetValue( double value ) { wxCHECK_RET( (m_widget != NULL), wxT("invalid spin button") ); + GTKResetTextOverride(); + wxSpinCtrlEventDisabler disable(this); gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget), value); } @@ -424,6 +504,28 @@ wxSpinCtrlGTKBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) return GetDefaultAttributesFromGTKWidget(gtk_spin_button_new_with_range(0, 100, 1), true); } +wxSpinCtrlGTKBase::GTKInputResult wxSpinCtrlGTKBase::GTKInput(double* value) const +{ + if ( m_textOverride ) + { + *value = m_textOverride->m_value; + return GTKInput_Converted; + } + + return GTKInput_Default; +} + +bool wxSpinCtrlGTKBase::GTKOutput(wxString* text) const +{ + if ( m_textOverride ) + { + *text = m_textOverride->m_text; + return true; + } + + return false; +} + //----------------------------------------------------------------------------- // wxSpinCtrl //----------------------------------------------------------------------------- @@ -470,9 +572,12 @@ bool wxSpinCtrl::SetBase(int base) return true; } -wxSpinCtrl::GTKInputResult -wxSpinCtrl::GTKInput(double* value) const +wxSpinCtrl::GTKInputResult wxSpinCtrl::GTKInput(double* value) const { + GTKInputResult res = wxSpinCtrlGTKBase::GTKInput(value); + if ( res != GTKInput_Default ) + return res; + // Don't override the default logic unless really needed. if ( GetBase() == 10 ) return GTKInput_Default; @@ -488,6 +593,9 @@ wxSpinCtrl::GTKInput(double* value) const bool wxSpinCtrl::GTKOutput(wxString* text) const { + if ( wxSpinCtrlGTKBase::GTKOutput(text) ) + return true; + switch ( GetBase() ) { default: @@ -510,6 +618,8 @@ bool wxSpinCtrl::GTKOutput(wxString* text) const void wxSpinCtrl::GTKValueChanged() { + GTKResetTextOverride(); + wxSpinEvent event(wxEVT_SPINCTRL, GetId()); event.SetEventObject( this ); event.SetPosition(GetValue()); @@ -551,19 +661,23 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits) GtkSetEntryWidth(); } -wxSpinCtrl::GTKInputResult -wxSpinCtrlDouble::GTKInput(double* WXUNUSED(value)) const +wxSpinCtrl::GTKInputResult wxSpinCtrlDouble::GTKInput(double* value) const { - return GTKInput_Default; + return wxSpinCtrlGTKBase::GTKInput(value); } -bool wxSpinCtrlDouble::GTKOutput(wxString* WXUNUSED(text)) const +bool wxSpinCtrlDouble::GTKOutput(wxString* text) const { + if ( wxSpinCtrlGTKBase::GTKOutput(text) ) + return true; + return false; } void wxSpinCtrlDouble::GTKValueChanged() { + GTKResetTextOverride(); + wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, GetId()); event.SetEventObject( this ); event.SetValue(GetValue()); diff --git a/tests/controls/spinctrldbltest.cpp b/tests/controls/spinctrldbltest.cpp index b491b5e48a..890659b298 100644 --- a/tests/controls/spinctrldbltest.cpp +++ b/tests/controls/spinctrldbltest.cpp @@ -168,6 +168,17 @@ TEST_CASE_METHOD(SpinCtrlDoubleTestCase, // Calling SetValue() shouldn't have generated any events. CHECK( updatedSpin.GetCount() == 0 ); CHECK( updatedText.GetCount() == 0 ); + + // Also test that setting the text value works. + CHECK( m_spin->GetTextValue() == "49.10" ); + + m_spin->SetValue("57.30"); + CHECK( m_spin->GetTextValue() == "57.30" ); + CHECK( m_spin->GetValue() == 57.3 ); + + m_spin->SetValue(""); + CHECK( m_spin->GetTextValue() == "" ); + CHECK( m_spin->GetValue() == 57.3 ); } #if wxUSE_UIACTIONSIMULATOR diff --git a/tests/controls/spinctrltest.cpp b/tests/controls/spinctrltest.cpp index 1fcc8a1788..7591857281 100644 --- a/tests/controls/spinctrltest.cpp +++ b/tests/controls/spinctrltest.cpp @@ -268,6 +268,17 @@ TEST_CASE_METHOD(SpinCtrlTestCase2, "SpinCtrl::Value", "[spinctrl]") // Calling SetValue() shouldn't have generated any events. CHECK(updatedSpin.GetCount() == 0); CHECK(updatedText.GetCount() == 0); + + // Also test that setting the text value works. + CHECK( m_spin->GetTextValue() == "100" ); + + m_spin->SetValue("57"); + CHECK( m_spin->GetTextValue() == "57" ); + CHECK( m_spin->GetValue() == 57 ); + + m_spin->SetValue(""); + CHECK( m_spin->GetTextValue() == "" ); + CHECK( m_spin->GetValue() == 57 ); } TEST_CASE_METHOD(SpinCtrlTestCase2, "SpinCtrl::Base", "[spinctrl]") From 496aefbf88043f4176bea4c4c34784f2497f2bdd Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 20 Apr 2021 01:17:42 +0200 Subject: [PATCH 12/16] Document wxSpinCtrl::SetValue("") behaviour Mention that this is explicitly allowed now that it works. Co-Authored-By: Dummy --- interface/wx/spinctrl.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/interface/wx/spinctrl.h b/interface/wx/spinctrl.h index a92b458e02..55353ef86d 100644 --- a/interface/wx/spinctrl.h +++ b/interface/wx/spinctrl.h @@ -197,6 +197,10 @@ public: Sets the value of the spin control. It is recommended to use the overload taking an integer value instead. + The behaviour of this function when @a text doesn't represent a valid + number currently differs between the platforms, however passing an + empty string does clear the text part contents, without affecting the + value returned by GetValue(), under all of them. Notice that, unlike wxTextCtrl::SetValue(), but like most of the other setter methods in wxWidgets, calling this method does not generate any @@ -250,6 +254,14 @@ public: /** Constructor, creating and showing a spin control. + If @a value is non-empty, it will be shown in the text entry part of + the control and if it has numeric value, the initial numeric value of + the control, as returned by GetValue() will also be determined by it + instead of by @a initial. Hence, it only makes sense to specify @a + initial if @a value is an empty string or is not convertible to a + number, otherwise @a initial is simply ignored and the number specified + by @a value is used. + @param parent Parent window. Must not be @NULL. @param value @@ -356,6 +368,10 @@ public: Sets the value of the spin control. It is recommended to use the overload taking a double value instead. + The behaviour of this function when @a text doesn't represent a valid + number currently differs between the platforms, however + passing an empty string does clear the text part contents, without + affecting the value returned by GetValue(), under all of them. Notice that, unlike wxTextCtrl::SetValue(), but like most of the other setter methods in wxWidgets, calling this method does not generate any From e7c9bd32fd072fe0fd12100614ab3f393b2f9a18 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 21 Apr 2021 08:32:37 +0200 Subject: [PATCH 13/16] Fix return type of GtkSpinButton "output" signal handler This doesn't seem to change anything in practice, but still use the correct return type. Co-Authored-By: Paul Cornett --- src/gtk/spinctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index a48917547d..2c665ae55e 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -88,7 +88,7 @@ wx_gtk_spin_input(GtkSpinButton*, gdouble* val, wxSpinCtrlGTKBase* win) return FALSE; } -static gint +static gboolean wx_gtk_spin_output(GtkSpinButton* spin, wxSpinCtrlGTKBase* win) { wxString text; From 32258bd10ad71186bf8f60fc9296e8b3218ac2d9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 21 Apr 2021 09:00:14 +0200 Subject: [PATCH 14/16] Move wxEVT_TEXT generation to wxSpinCtrlGTKBase::GTKTextChanged() This is more consistent with GTKValueChanged() and allows making the change in the upcoming commit. No real changes yet, this is just a refactoring. --- include/wx/gtk/spinctrl.h | 1 + src/gtk/spinctrl.cpp | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index b5bfa96c72..611f859382 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -72,6 +72,7 @@ public: virtual bool GTKOutput(wxString* text) const = 0; virtual void GTKValueChanged() = 0; + void GTKTextChanged(); protected: wxSpinCtrlGTKBase(); diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index 2c665ae55e..4639674234 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -54,11 +54,7 @@ extern "C" { static void gtk_changed(GtkSpinButton*, wxSpinCtrl* win) { - wxCommandEvent event( wxEVT_TEXT, win->GetId() ); - event.SetEventObject( win ); - event.SetString(win->GetTextValue()); - event.SetInt(win->GetValue()); - win->HandleWindowEvent( event ); + win->GTKTextChanged(); } } @@ -526,6 +522,15 @@ bool wxSpinCtrlGTKBase::GTKOutput(wxString* text) const return false; } +void wxSpinCtrlGTKBase::GTKTextChanged() +{ + wxCommandEvent event( wxEVT_TEXT, GetId() ); + event.SetEventObject( this ); + event.SetString(GetTextValue()); + event.SetInt(static_cast(DoGetValue())); + HandleWindowEvent( event ); +} + //----------------------------------------------------------------------------- // wxSpinCtrl //----------------------------------------------------------------------------- From 86c0394383dc50328b0da55bf6b10b3f8ad2dd75 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 21 Apr 2021 09:02:59 +0200 Subject: [PATCH 15/16] Reset text override if the text is manually modified Otherwise the newly entered text wouldn't be taken into account, as it would still be overridden. --- src/gtk/spinctrl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index 4639674234..6e709e7e17 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -524,6 +524,8 @@ bool wxSpinCtrlGTKBase::GTKOutput(wxString* text) const void wxSpinCtrlGTKBase::GTKTextChanged() { + GTKResetTextOverride(); + wxCommandEvent event( wxEVT_TEXT, GetId() ); event.SetEventObject( this ); event.SetString(GetTextValue()); From c356f83da2583663e2abae18ebbc798e4bd2f761 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 21 Apr 2021 09:24:02 +0200 Subject: [PATCH 16/16] Fix resetting text override when manually entering the text The entered text wasn't taken into account, as the override was still used when its numeric value was retrieved by GtkSpinButton using our "input" handler, so reset the override now as soon as we get "changed" signal. --- include/wx/gtk/spinctrl.h | 9 ++++++++- src/gtk/spinctrl.cpp | 17 ++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index 611f859382..267bd94de5 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -102,10 +102,17 @@ protected: // override this and return true. virtual bool UseGTKStyleBase() const wxOVERRIDE { return true; } - // Set or reset m_textOverride. + // Set m_textOverride to use the given text instead of the numeric value. void GTKSetTextOverride(const wxString& text); + + // Reset the override and changing the value to correspond to the + // previously overridden numeric value. void GTKResetTextOverride(); + // Just reset the override, without touching the value, returning true if + // we did it. In most cases, the function above should be used instead. + bool GTKResetTextOverrideOnly(); + private: // This function does _not_ take into account m_textOverride, so it is // private and normally shouldn't be used -- use DoGetValue() instead. diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index 6e709e7e17..b9f72eda28 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -176,14 +176,22 @@ void wxSpinCtrlGTKBase::GTKSetTextOverride(const wxString& text) m_textOverride->m_text = text; } -void wxSpinCtrlGTKBase::GTKResetTextOverride() +bool wxSpinCtrlGTKBase::GTKResetTextOverrideOnly() { if ( !m_textOverride ) - return; + return false; delete m_textOverride; m_textOverride = NULL; + return true; +} + +void wxSpinCtrlGTKBase::GTKResetTextOverride() +{ + if ( !GTKResetTextOverrideOnly() ) + return; + // Update the text part to reflect the numeric value now that we don't // override it any longer, otherwise we'd keep showing the old one because // the text is updated by GTK before "value" is generated. @@ -524,7 +532,10 @@ bool wxSpinCtrlGTKBase::GTKOutput(wxString* text) const void wxSpinCtrlGTKBase::GTKTextChanged() { - GTKResetTextOverride(); + // We can't use GTKResetTextOverride() itself here because it would also + // reset the value and we do not want this to happen -- the value is being + // changed to correspond to the new text. + GTKResetTextOverrideOnly(); wxCommandEvent event( wxEVT_TEXT, GetId() ); event.SetEventObject( this );