Merge branch 'spinctrl-digits'
Improve setting the number of digits in wxSpinCtrlDouble and make it consistent on all platforms. See https://github.com/wxWidgets/wxWidgets/pull/2348 Closes #17085.
This commit is contained in:
@@ -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"))
|
||||
{
|
||||
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(); }
|
||||
@@ -402,7 +396,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
|
||||
@@ -416,7 +410,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;
|
||||
|
||||
@@ -424,10 +417,16 @@ private:
|
||||
// Common part of all ctors.
|
||||
void Init()
|
||||
{
|
||||
m_digits = 0;
|
||||
m_format = wxASCII_STR("%0.0f");
|
||||
DoSetDigits(0);
|
||||
}
|
||||
|
||||
// Just set the number of digits and the format unconditionally.
|
||||
void DoSetDigits(unsigned digits);
|
||||
|
||||
// Call DoSetDigits() and update the appearance.
|
||||
void DoSetDigitsAndUpdate(unsigned digits);
|
||||
|
||||
|
||||
wxString m_format;
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS(wxSpinCtrlDouble);
|
||||
|
@@ -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; }
|
||||
|
@@ -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_
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -26,6 +26,8 @@
|
||||
|
||||
#include "wx/private/spinctrl.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
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<int>(inc);
|
||||
if ( inc > 0.0 )
|
||||
{
|
||||
return wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast<int>(floor(log10(inc))));
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_SPINCTRL
|
||||
|
@@ -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());
|
||||
@@ -746,16 +762,36 @@ wxString wxSpinCtrlDouble::DoValueToText(double val)
|
||||
return wxString::Format(m_format, val);
|
||||
}
|
||||
|
||||
void wxSpinCtrlDouble::SetIncrement(double inc)
|
||||
{
|
||||
if ( inc == m_increment )
|
||||
return;
|
||||
|
||||
DoSetIncrement(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
|
||||
// high enough to show the numbers without losing precision.
|
||||
if ( digits > m_digits )
|
||||
DoSetDigitsAndUpdate(digits);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
m_digits = digits;
|
||||
DoSetDigitsAndUpdate(digits);
|
||||
}
|
||||
|
||||
m_format.Printf(wxT("%%0.%ulf"), digits);
|
||||
void wxSpinCtrlDouble::DoSetDigitsAndUpdate(unsigned digits)
|
||||
{
|
||||
DoSetDigits(digits);
|
||||
|
||||
ResetTextValidator();
|
||||
m_textCtrl->InvalidateBestSize();
|
||||
@@ -763,6 +799,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
|
||||
@@ -772,16 +815,6 @@ void wxSpinCtrlDouble::ResetTextValidator()
|
||||
#endif // wxUSE_VALIDATORS
|
||||
}
|
||||
|
||||
void wxSpinCtrlDouble::DetermineDigits(double inc)
|
||||
{
|
||||
inc = fabs(inc);
|
||||
if ( inc > 0.0 && inc < 1.0 )
|
||||
{
|
||||
m_digits = wxMin(SPINCTRLDBL_MAX_DIGITS, -static_cast<int>(floor(log10(inc))));
|
||||
m_format.Printf("%%0.%ulf", m_digits);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_SPINBTN
|
||||
|
||||
#endif // !wxPort-with-native-spinctrl
|
||||
|
@@ -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" );
|
||||
|
@@ -217,18 +217,47 @@ 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" );
|
||||
|
||||
// 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" );
|
||||
|
||||
// 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)
|
||||
{
|
||||
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<wxSpinCtrlDouble> 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]")
|
||||
|
Reference in New Issue
Block a user