From c177e006fc4a4cfb5e951f678ba8581f5fcb3df1 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 16:45:39 +0100 Subject: [PATCH 01/10] Use wxScopedPtr instead of manual delete in wxSpinCtrlDouble test No real changes. --- tests/controls/spinctrldbltest.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/controls/spinctrldbltest.cpp b/tests/controls/spinctrldbltest.cpp index 1e834b1915..0308f3e3ea 100644 --- a/tests/controls/spinctrldbltest.cpp +++ b/tests/controls/spinctrldbltest.cpp @@ -224,11 +224,18 @@ TEST_CASE_METHOD(SpinCtrlDoubleTestCase, static inline unsigned int GetInitialDigits(double inc) { - wxSpinCtrlDouble* sc = new wxSpinCtrlDouble(wxTheApp->GetTopWindow(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, - 0, 50, 0, inc); - unsigned int digits = sc->GetDigits(); - delete sc; - return digits; + wxScopedPtr sc(new wxSpinCtrlDouble + ( + wxTheApp->GetTopWindow(), + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxDefaultSize, + wxSP_ARROW_KEYS, + 0, 50, 0, + inc + )); + return sc->GetDigits(); } TEST_CASE("SpinCtrlDouble::InitialDigits", "[spinctrldouble][initialdigits]") From e748c2b56c35bb68fbe83234b155a9963cff1748 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 19:11:38 +0100 Subject: [PATCH 02/10] Make wxSpinCtrlDouble::DetermineDigits() private There is no need to allow calling this function from derived classes. No real changes. --- include/wx/generic/spinctlg.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index 8f3e5ecc92..4c64ade837 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -416,7 +416,6 @@ protected: virtual bool DoTextToValue(const wxString& text, double *val) wxOVERRIDE; virtual wxString DoValueToText(double val) wxOVERRIDE; virtual void ResetTextValidator() wxOVERRIDE; - void DetermineDigits(double inc); unsigned m_digits; @@ -428,6 +427,9 @@ private: m_format = wxASCII_STR("%0.0f"); } + // Update m_digits and m_format to correspond to the given increment. + void DetermineDigits(double inc); + wxString m_format; wxDECLARE_DYNAMIC_CLASS(wxSpinCtrlDouble); From e2d2b367af1da9d84c82812ecf47c7e06707e655 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 19:13:22 +0100 Subject: [PATCH 03/10] Always initialize m_format in DetermineDigits() It doesn't seem right to leave it unchanged when increment is outside of [0, 1] interval, we should still set it to something in this case. And doing this makes it unnecessary and redundant to initialize m_format in Init(), as it will be always done when DetermineDigits() is called from Create() anyhow. --- include/wx/generic/spinctlg.h | 1 - src/generic/spinctlg.cpp | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index 4c64ade837..c00ed843eb 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -424,7 +424,6 @@ private: void Init() { m_digits = 0; - m_format = wxASCII_STR("%0.0f"); } // Update m_digits and m_format to correspond to the given increment. diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index 7255045e24..8048e72682 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -778,8 +778,13 @@ void wxSpinCtrlDouble::DetermineDigits(double inc) if ( inc > 0.0 && inc < 1.0 ) { m_digits = wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); - m_format.Printf("%%0.%ulf", m_digits); } + else + { + m_digits = 0; + } + + m_format.Printf("%%0.%ulf", m_digits); } #endif // wxUSE_SPINBTN From eecc62ba6511797f8618eeabaf3c75a15e3b6201 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 19:31:38 +0100 Subject: [PATCH 04/10] Factor out wxSpinCtrlDouble::DoSetDigits() Make this part of SetDigits() reusable in order to be able to also use it in DetermineDigits() now and in SetIncrement() in the upcoming commit. No real changes yet. --- include/wx/generic/spinctlg.h | 6 +++++- src/generic/spinctlg.cpp | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index c00ed843eb..154beb3af9 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -423,12 +423,16 @@ private: // Common part of all ctors. void Init() { - m_digits = 0; + DoSetDigits(0); } // Update m_digits and m_format to correspond to the given increment. void DetermineDigits(double inc); + // Set the number of digits and the format unconditionally. + void DoSetDigits(unsigned digits); + + wxString m_format; wxDECLARE_DYNAMIC_CLASS(wxSpinCtrlDouble); diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index 8048e72682..1342acc478 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -753,9 +753,7 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits) if ( digits == m_digits ) return; - m_digits = digits; - - m_format.Printf(wxT("%%0.%ulf"), digits); + DoSetDigits(digits); ResetTextValidator(); m_textCtrl->InvalidateBestSize(); @@ -763,6 +761,13 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits) DoSetValue(m_value, SendEvent_None); } +void wxSpinCtrlDouble::DoSetDigits(unsigned digits) +{ + m_digits = digits; + + m_format.Printf(wxT("%%0.%ulf"), digits); +} + void wxSpinCtrlDouble::ResetTextValidator() { #if wxUSE_VALIDATORS @@ -774,17 +779,19 @@ void wxSpinCtrlDouble::ResetTextValidator() void wxSpinCtrlDouble::DetermineDigits(double inc) { + unsigned digits; + inc = fabs(inc); if ( inc > 0.0 && inc < 1.0 ) { - m_digits = wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); + digits = wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); } else { - m_digits = 0; + digits = 0; } - m_format.Printf("%%0.%ulf", m_digits); + DoSetDigits(digits); } #endif // wxUSE_SPINBTN From 6938d919429b65981b14cabe4e54473aaea73487 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 19:45:34 +0100 Subject: [PATCH 05/10] Update number of digits in wxSpinCtrlDouble::SetIncrement() This is consistent with using the value of the increment specified in the ctor for setting the initial number of digits, it was surprising that creating the control with some value of the increment (e.g. 0.1) and calling SetIncrement(0.1) later resulted in very different outcomes, as in the former case the value was shown with a digit after the period while in the latter case only the integer part was shown. This also makes the behaviour compatible with that of the previous versions of the generic wxSpinCtrlDouble, which used "%g" to format the number before the changes of edc553870f (Fix displaying wxSpinCtrlDouble values with default precision, 2020-05-18), as they did show the fractional part even in the latter case. Add a test checking that this works as expected: before this commit, the test failed with "1 == 1.2" and "1 == 1.23" errors. --- include/wx/generic/spinctlg.h | 5 ++++- src/generic/spinctlg.cpp | 17 +++++++++++++++++ tests/controls/spinctrldbltest.cpp | 13 ++++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index 154beb3af9..ced305ef97 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -402,7 +402,7 @@ public: { wxSpinCtrlGenericBase::SetValue(value); } void SetValue(double value) { DoSetValue(value, SendEvent_None); } void SetRange(double minVal, double maxVal) { DoSetRange(minVal, maxVal); } - void SetIncrement(double inc) { DoSetIncrement(inc); } + void SetIncrement(double inc); void SetDigits(unsigned digits); // We don't implement bases support for floating point numbers, this is not @@ -432,6 +432,9 @@ private: // Set the number of digits and the format unconditionally. void DoSetDigits(unsigned digits); + // Update the appearance after the number of digits has changed. + void UpdateAfterDigitsChange(); + wxString m_format; diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index 1342acc478..98feb4b5a3 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -746,6 +746,18 @@ wxString wxSpinCtrlDouble::DoValueToText(double val) return wxString::Format(m_format, val); } +void wxSpinCtrlDouble::SetIncrement(double inc) +{ + if ( inc == m_increment ) + return; + + DoSetIncrement(inc); + + DetermineDigits(inc); + + UpdateAfterDigitsChange(); +} + void wxSpinCtrlDouble::SetDigits(unsigned digits) { wxCHECK_RET( digits <= SPINCTRLDBL_MAX_DIGITS, "too many digits for wxSpinCtrlDouble" ); @@ -755,6 +767,11 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits) DoSetDigits(digits); + UpdateAfterDigitsChange(); +} + +void wxSpinCtrlDouble::UpdateAfterDigitsChange() +{ ResetTextValidator(); m_textCtrl->InvalidateBestSize(); diff --git a/tests/controls/spinctrldbltest.cpp b/tests/controls/spinctrldbltest.cpp index 0308f3e3ea..f4dcf380f2 100644 --- a/tests/controls/spinctrldbltest.cpp +++ b/tests/controls/spinctrldbltest.cpp @@ -217,9 +217,20 @@ TEST_CASE_METHOD(SpinCtrlDoubleTestCase, TEST_CASE_METHOD(SpinCtrlDoubleTestCase, "SpinCtrlDouble::Digits", "[spinctrl][spinctrldouble]") { - m_spin->SetDigits(5); + // Setting increment should adjust the number of digits shown to be big + // enough to show numbers with the corresponding granularity. + m_spin->SetIncrement(0.1); + m_spin->SetValue(1.23456789); + CHECK( m_spin->GetTextValue() == "1.2" ); + m_spin->SetIncrement(0.01); + m_spin->SetValue(1.23456789); + CHECK( m_spin->GetTextValue() == "1.23" ); + + m_spin->SetDigits(5); CHECK( m_spin->GetDigits() == 5 ); + m_spin->SetValue(1.23456789); + CHECK( m_spin->GetTextValue() == "1.23457" ); } static inline unsigned int GetInitialDigits(double inc) From 0153a6673e540d81b41b604397f0d951111ff21a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 19:54:27 +0100 Subject: [PATCH 06/10] Don't decrease the number of digits implicitly wxSpinCtrlDouble::SetIncrement() should increase the number of digits if necessary because not doing it would be inconsistent with the initial determination of the number of digits in the ctor and would actually lose the digits displayed, but it seems unnecessary to decrease the number of digits and it might be surprising, so don't do it. Add a test for this behaviour and document it. --- include/wx/generic/spinctlg.h | 7 ++++--- interface/wx/spinctrl.h | 11 +++++++++-- src/generic/spinctlg.cpp | 23 ++++++++++++++--------- tests/controls/spinctrldbltest.cpp | 5 +++++ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index ced305ef97..b931f3457c 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -384,7 +384,7 @@ public: double inc = 1, const wxString& name = wxT("wxSpinCtrlDouble")) { - DetermineDigits(inc); + DoSetDigits(DetermineDigits(inc)); return wxSpinCtrlGenericBase::Create(parent, id, value, pos, size, style, min, max, initial, inc, name); @@ -426,8 +426,9 @@ private: DoSetDigits(0); } - // Update m_digits and m_format to correspond to the given increment. - void DetermineDigits(double inc); + // Return the number of digits required to show the numbers using the + // specified increment without loss of precision. + static unsigned DetermineDigits(double inc); // Set the number of digits and the format unconditionally. void DoSetDigits(unsigned digits); diff --git a/interface/wx/spinctrl.h b/interface/wx/spinctrl.h index 6371aeec7c..dd213178d5 100644 --- a/interface/wx/spinctrl.h +++ b/interface/wx/spinctrl.h @@ -354,8 +354,15 @@ public: /** Sets the increment value. - @note You may also need to change the precision of the value - using SetDigits(). + + Using this method changes the number of digits used by the control to + at least match the value of @a inc, e.g. using the increment of @c 0.01 + sets the number of digits to 2 if it had been less than 2 before. + However it doesn't change the number of digits if it had been already + high enough. + + In any case, you may call SetDigits() explicitly to override the + automatic determination of the number of digits. */ void SetIncrement(double inc); diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index 98feb4b5a3..f9749f052b 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -753,9 +753,17 @@ void wxSpinCtrlDouble::SetIncrement(double inc) DoSetIncrement(inc); - DetermineDigits(inc); + const unsigned digits = DetermineDigits(inc); - UpdateAfterDigitsChange(); + // We don't decrease the number of digits here, as this is unnecessary and + // could be undesirable, but we do increase it if the current number is not + // high enough to show the numbers without losing precision. + if ( digits > m_digits ) + { + DoSetDigits(digits); + + UpdateAfterDigitsChange(); + } } void wxSpinCtrlDouble::SetDigits(unsigned digits) @@ -794,21 +802,18 @@ void wxSpinCtrlDouble::ResetTextValidator() #endif // wxUSE_VALIDATORS } -void wxSpinCtrlDouble::DetermineDigits(double inc) +/* static */ +unsigned wxSpinCtrlDouble::DetermineDigits(double inc) { - unsigned digits; - inc = fabs(inc); if ( inc > 0.0 && inc < 1.0 ) { - digits = wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); + return wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); } else { - digits = 0; + return 0; } - - DoSetDigits(digits); } #endif // wxUSE_SPINBTN diff --git a/tests/controls/spinctrldbltest.cpp b/tests/controls/spinctrldbltest.cpp index f4dcf380f2..e8a8f32459 100644 --- a/tests/controls/spinctrldbltest.cpp +++ b/tests/controls/spinctrldbltest.cpp @@ -231,6 +231,11 @@ TEST_CASE_METHOD(SpinCtrlDoubleTestCase, CHECK( m_spin->GetDigits() == 5 ); m_spin->SetValue(1.23456789); CHECK( m_spin->GetTextValue() == "1.23457" ); + + // The number of digits shouldn't (implicitly) decrease however. + m_spin->SetIncrement(0.001); + m_spin->SetValue(1.23456789); + CHECK( m_spin->GetTextValue() == "1.23457" ); } static inline unsigned int GetInitialDigits(double inc) From 6c9c0ba02b61192fa27032112c61d309733a2256 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 20:00:31 +0100 Subject: [PATCH 07/10] Determine number of digits correctly when increment > 1 Using increment greater than 1 but with a fractional part should still work, i.e. should use enough digits to fully show the fractional part of the numbers that can be obtained by using this increment. --- src/generic/spinctlg.cpp | 4 +++- tests/controls/spinctrldbltest.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index f9749f052b..830f64f6f0 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -805,8 +805,10 @@ void wxSpinCtrlDouble::ResetTextValidator() /* static */ unsigned wxSpinCtrlDouble::DetermineDigits(double inc) { + // TODO-C++11: Use std::modf() to get the fractional part. inc = fabs(inc); - if ( inc > 0.0 && inc < 1.0 ) + inc -= static_cast(inc); + if ( inc > 0.0 ) { return wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); } diff --git a/tests/controls/spinctrldbltest.cpp b/tests/controls/spinctrldbltest.cpp index e8a8f32459..c31e83aa84 100644 --- a/tests/controls/spinctrldbltest.cpp +++ b/tests/controls/spinctrldbltest.cpp @@ -236,6 +236,12 @@ TEST_CASE_METHOD(SpinCtrlDoubleTestCase, m_spin->SetIncrement(0.001); m_spin->SetValue(1.23456789); CHECK( m_spin->GetTextValue() == "1.23457" ); + + // Check that using increment greater than 1 also works. + m_spin->SetDigits(0); + m_spin->SetIncrement(2.5); + m_spin->SetValue(7.5); + CHECK( m_spin->GetTextValue() == "7.5" ); } static inline unsigned int GetInitialDigits(double inc) From c16f85bd4d2769a4c406de3cc8fca6aba1212769 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 20:08:05 +0100 Subject: [PATCH 08/10] Simplify after recent changes by adding DoSetDigitsAndUpdate() There is no need for a separate UpdateAfterDigitsChange(), it is always called together with DoSetDigits(). --- include/wx/generic/spinctlg.h | 6 +++--- src/generic/spinctlg.cpp | 14 +++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index b931f3457c..b25f8108c8 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -430,11 +430,11 @@ private: // specified increment without loss of precision. static unsigned DetermineDigits(double inc); - // Set the number of digits and the format unconditionally. + // Just set the number of digits and the format unconditionally. void DoSetDigits(unsigned digits); - // Update the appearance after the number of digits has changed. - void UpdateAfterDigitsChange(); + // Call DoSetDigits() and update the appearance. + void DoSetDigitsAndUpdate(unsigned digits); wxString m_format; diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index 830f64f6f0..da85d8fdae 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -759,11 +759,7 @@ void wxSpinCtrlDouble::SetIncrement(double inc) // could be undesirable, but we do increase it if the current number is not // high enough to show the numbers without losing precision. if ( digits > m_digits ) - { - DoSetDigits(digits); - - UpdateAfterDigitsChange(); - } + DoSetDigitsAndUpdate(digits); } void wxSpinCtrlDouble::SetDigits(unsigned digits) @@ -773,13 +769,13 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits) if ( digits == m_digits ) return; - DoSetDigits(digits); - - UpdateAfterDigitsChange(); + DoSetDigitsAndUpdate(digits); } -void wxSpinCtrlDouble::UpdateAfterDigitsChange() +void wxSpinCtrlDouble::DoSetDigitsAndUpdate(unsigned digits) { + DoSetDigits(digits); + ResetTextValidator(); m_textCtrl->InvalidateBestSize(); From a44bb13a0c4ec5c86f1423555f45d34134b49e32 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 20:14:46 +0100 Subject: [PATCH 09/10] Make DetermineDigits() reusable in other ports Move this function, and the associated constant, to common code. This required moving wxSpinCtrlDouble::Create() implementation to the source file, but there are no real changes. --- include/wx/generic/spinctlg.h | 12 +--------- include/wx/private/spinctrl.h | 8 +++++++ src/common/spinctrlcmn.cpp | 17 +++++++++++++++ src/generic/spinctlg.cpp | 41 ++++++++++++++++++----------------- 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index b25f8108c8..64d9cb95c5 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -382,13 +382,7 @@ public: long style = wxSP_ARROW_KEYS, double min = 0, double max = 100, double initial = 0, double inc = 1, - const wxString& name = wxT("wxSpinCtrlDouble")) - { - DoSetDigits(DetermineDigits(inc)); - return wxSpinCtrlGenericBase::Create(parent, id, value, pos, size, - style, min, max, initial, - inc, name); - } + const wxString& name = wxT("wxSpinCtrlDouble")); // accessors double GetValue(wxSPINCTRL_GETVALUE_FIX) const { return DoGetValue(); } @@ -426,10 +420,6 @@ private: DoSetDigits(0); } - // Return the number of digits required to show the numbers using the - // specified increment without loss of precision. - static unsigned DetermineDigits(double inc); - // Just set the number of digits and the format unconditionally. void DoSetDigits(unsigned digits); diff --git a/include/wx/private/spinctrl.h b/include/wx/private/spinctrl.h index e0a59db1cc..66fdfb6e8e 100644 --- a/include/wx/private/spinctrl.h +++ b/include/wx/private/spinctrl.h @@ -28,6 +28,14 @@ extern wxSize GetBestSize(const wxControl* spin, int minVal, int maxVal, int bas // Helper function to check if given combination of range and base is valid. extern bool IsBaseCompatibleWithRange(int minVal, int maxVal, int base); + +// Maximum number of digits returned by DetermineDigits(). +const unsigned SPINCTRLDBL_MAX_DIGITS = 20; + +// Return the number of digits required to show the numbers using the +// specified increment without loss of precision. +extern unsigned DetermineDigits(double inc); + } // namespace wxSpinCtrlImpl #endif // _WX_PRIVATE_SPINCTRL_H_ diff --git a/src/common/spinctrlcmn.cpp b/src/common/spinctrlcmn.cpp index ac3c562843..956fcbf212 100644 --- a/src/common/spinctrlcmn.cpp +++ b/src/common/spinctrlcmn.cpp @@ -26,6 +26,8 @@ #include "wx/private/spinctrl.h" +#include + wxDEFINE_EVENT(wxEVT_SPINCTRL, wxSpinEvent); wxDEFINE_EVENT(wxEVT_SPINCTRLDOUBLE, wxSpinDoubleEvent); @@ -140,4 +142,19 @@ bool wxSpinCtrlImpl::IsBaseCompatibleWithRange(int minVal, int maxVal, int base) return base == 10 || (minVal >= 0 && maxVal >= 0); } +unsigned wxSpinCtrlImpl::DetermineDigits(double inc) +{ + // TODO-C++11: Use std::modf() to get the fractional part. + inc = fabs(inc); + inc -= static_cast(inc); + if ( inc > 0.0 ) + { + return wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); + } + else + { + return 0; + } +} + #endif // wxUSE_SPINCTRL diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index da85d8fdae..ae47212210 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -723,10 +723,26 @@ void wxSpinCtrl::ResetTextValidator() // wxSpinCtrlDouble //----------------------------------------------------------------------------- -#define SPINCTRLDBL_MAX_DIGITS 20 - wxIMPLEMENT_DYNAMIC_CLASS(wxSpinCtrlDouble, wxSpinCtrlGenericBase); +bool +wxSpinCtrlDouble::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + double min, double max, double initial, + double inc, + const wxString& name) +{ + DoSetDigits(wxSpinCtrlImpl::DetermineDigits(inc)); + + return wxSpinCtrlGenericBase::Create(parent, id, value, pos, size, + style, min, max, initial, + inc, name); +} + void wxSpinCtrlDouble::DoSendEvent() { wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, GetId()); @@ -753,7 +769,7 @@ void wxSpinCtrlDouble::SetIncrement(double inc) DoSetIncrement(inc); - const unsigned digits = DetermineDigits(inc); + const unsigned digits = wxSpinCtrlImpl::DetermineDigits(inc); // We don't decrease the number of digits here, as this is unnecessary and // could be undesirable, but we do increase it if the current number is not @@ -764,7 +780,8 @@ void wxSpinCtrlDouble::SetIncrement(double inc) void wxSpinCtrlDouble::SetDigits(unsigned digits) { - wxCHECK_RET( digits <= SPINCTRLDBL_MAX_DIGITS, "too many digits for wxSpinCtrlDouble" ); + wxCHECK_RET( digits <= wxSpinCtrlImpl::SPINCTRLDBL_MAX_DIGITS, + "too many digits for wxSpinCtrlDouble" ); if ( digits == m_digits ) return; @@ -798,22 +815,6 @@ void wxSpinCtrlDouble::ResetTextValidator() #endif // wxUSE_VALIDATORS } -/* static */ -unsigned wxSpinCtrlDouble::DetermineDigits(double inc) -{ - // TODO-C++11: Use std::modf() to get the fractional part. - inc = fabs(inc); - inc -= static_cast(inc); - if ( inc > 0.0 ) - { - return wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast(floor(log10(inc)))); - } - else - { - return 0; - } -} - #endif // wxUSE_SPINBTN #endif // !wxPort-with-native-spinctrl From 3481598cc6a2cd74652dea00eb57d1ea8ea57c4a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 25 Apr 2021 21:17:31 +0200 Subject: [PATCH 10/10] Make wxSpinCtrlDouble::SetIncrement() update digits in wxGTK too Follow the generic version and increase the number of digits if necessary. --- include/wx/gtk/spinctrl.h | 2 +- src/gtk/spinctrl.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index 267bd94de5..5fb19b4162 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -243,7 +243,7 @@ public: void SetValue(const wxString& value) wxOVERRIDE { wxSpinCtrlGTKBase::SetValue(value); } // visibility problem w/ gcc void SetValue(double value) { DoSetValue(value); } void SetRange(double minVal, double maxVal) { DoSetRange(minVal, maxVal); } - void SetIncrement(double inc) { DoSetIncrement(inc); } + void SetIncrement(double inc); void SetDigits(unsigned digits); virtual int GetBase() const wxOVERRIDE { return 10; } diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index 637fb60592..c327734e8a 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -643,6 +643,18 @@ void wxSpinCtrlDouble::GtkSetEntryWidth() gtk_entry_set_width_chars(GTK_ENTRY(m_widget), wxMax(lenMin, lenMax)); } +void wxSpinCtrlDouble::SetIncrement(double inc) +{ + DoSetIncrement(inc); + + const unsigned digits = wxSpinCtrlImpl::DetermineDigits(inc); + + // Increase the number of digits, if necessary, to show all numbers that + // can be obtained by using the new increment without loss of precision. + if ( digits > GetDigits() ) + SetDigits(digits); +} + unsigned wxSpinCtrlDouble::GetDigits() const { wxCHECK_MSG( m_widget, 0, "invalid spin button" );