Fix several rounding problems with float values in wxPropertyGrid.
Loss of precision when converting floating point numbers to text and back could result in several problems, notably comparing a valid value with the minimum could fail after a round trip through wxSpinCtrl. Fix this by using a specialization of NumericValidation() handling floating point values specially and correctly. Closes #15625. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@75980 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -362,7 +362,14 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper
|
||||
// Min/Max check
|
||||
wxFloatProperty::DoValidation(property, v_d, NULL, mode);
|
||||
|
||||
s = wxNumberFormatter::ToString(v_d, -1, wxNumberFormatter::Style_None);
|
||||
int precision = -1;
|
||||
wxVariant v = property->GetAttribute(wxPG_FLOAT_PRECISION);
|
||||
if ( !v.IsNull() )
|
||||
{
|
||||
precision = v.GetInteger();
|
||||
}
|
||||
|
||||
s = wxNumberFormatter::ToString(v_d, precision, wxNumberFormatter::Style_NoTrailingZeroes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -1770,6 +1770,10 @@ wxVariant wxPGProperty::DoGetAttribute( const wxString& WXUNUSED(name) ) const
|
||||
|
||||
wxVariant wxPGProperty::GetAttribute( const wxString& name ) const
|
||||
{
|
||||
wxVariant value = DoGetAttribute(name);
|
||||
if ( !value.IsNull() )
|
||||
return value;
|
||||
|
||||
return m_attributes.FindValue(name);
|
||||
}
|
||||
|
||||
|
@@ -54,6 +54,8 @@
|
||||
#include "wx/propgrid/propgrid.h"
|
||||
#include "wx/numformatter.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#define wxPG_CUSTOM_IMAGE_WIDTH 20 // for wxColourProperty etc.
|
||||
|
||||
|
||||
@@ -342,7 +344,8 @@ bool wxIntProperty::IntToValue( wxVariant& variant, int value, int WXUNUSED(argF
|
||||
// implementations.
|
||||
//
|
||||
// Note that 'value' is reference on purpose, so we can write
|
||||
// back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE.
|
||||
// back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE or wxPG_PROPERTY_VALIDATION_WRAP.
|
||||
// For argument 'value' of type 'double' there is a specialized function (below).
|
||||
//
|
||||
template<typename T>
|
||||
bool NumericValidation( const wxPGProperty* property,
|
||||
@@ -427,6 +430,115 @@ bool NumericValidation( const wxPGProperty* property,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Template specialization for argument 'value' of type 'double'.
|
||||
// It takes into account required precision of the numbers
|
||||
// to avoid rounding and conversion errors.
|
||||
template<>
|
||||
bool NumericValidation( const wxPGProperty* property,
|
||||
double& value,
|
||||
wxPGValidationInfo* pValidationInfo,
|
||||
int mode,
|
||||
const wxString& strFmt )
|
||||
{
|
||||
double min = DBL_MIN;
|
||||
double max = DBL_MAX;
|
||||
wxVariant variant;
|
||||
bool minOk = false;
|
||||
bool maxOk = false;
|
||||
|
||||
variant = property->GetAttribute(wxPGGlobalVars->m_strMin);
|
||||
if ( !variant.IsNull() )
|
||||
{
|
||||
variant.Convert(&min);
|
||||
minOk = true;
|
||||
}
|
||||
|
||||
variant = property->GetAttribute(wxPGGlobalVars->m_strMax);
|
||||
if ( !variant.IsNull() )
|
||||
{
|
||||
variant.Convert(&max);
|
||||
maxOk = true;
|
||||
}
|
||||
|
||||
if ( minOk || maxOk )
|
||||
{
|
||||
// Get required precision.
|
||||
int precision = -1;
|
||||
variant = property->GetAttribute(wxPG_FLOAT_PRECISION);
|
||||
if ( !variant.IsNull() )
|
||||
{
|
||||
precision = variant.GetInteger();
|
||||
}
|
||||
|
||||
// Round current value to the required precision.
|
||||
wxString strVal = wxNumberFormatter::ToString(value, precision, wxNumberFormatter::Style_None);
|
||||
strVal.ToDouble(&value);
|
||||
|
||||
// Round minimal value to the required precision.
|
||||
strVal = wxNumberFormatter::ToString(min, precision, wxNumberFormatter::Style_None);
|
||||
strVal.ToDouble(&min);
|
||||
|
||||
// Round maximal value to the required precision.
|
||||
strVal = wxNumberFormatter::ToString(max, precision, wxNumberFormatter::Style_None);
|
||||
strVal.ToDouble(&max);
|
||||
}
|
||||
|
||||
if ( minOk )
|
||||
{
|
||||
if ( value < min )
|
||||
{
|
||||
if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
|
||||
{
|
||||
wxString msg;
|
||||
wxString smin = wxString::Format(strFmt, min);
|
||||
wxString smax = wxString::Format(strFmt, max);
|
||||
if ( !maxOk )
|
||||
msg = wxString::Format(
|
||||
_("Value must be %s or higher."),
|
||||
smin.c_str());
|
||||
else
|
||||
msg = wxString::Format(
|
||||
_("Value must be between %s and %s."),
|
||||
smin.c_str(), smax.c_str());
|
||||
pValidationInfo->SetFailureMessage(msg);
|
||||
}
|
||||
else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
|
||||
value = min;
|
||||
else
|
||||
value = max - (min - value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( maxOk )
|
||||
{
|
||||
if ( value > max )
|
||||
{
|
||||
if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
|
||||
{
|
||||
wxString msg;
|
||||
wxString smin = wxString::Format(strFmt, min);
|
||||
wxString smax = wxString::Format(strFmt, max);
|
||||
if ( !minOk )
|
||||
msg = wxString::Format(
|
||||
_("Value must be %s or less."),
|
||||
smax.c_str());
|
||||
else
|
||||
msg = wxString::Format(
|
||||
_("Value must be between %s and %s."),
|
||||
smin.c_str(), smax.c_str());
|
||||
pValidationInfo->SetFailureMessage(msg);
|
||||
}
|
||||
else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
|
||||
value = max;
|
||||
else
|
||||
value = min + (value - max);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxIntProperty::DoValidation( const wxPGProperty* property,
|
||||
wxLongLong_t& value,
|
||||
wxPGValidationInfo* pValidationInfo,
|
||||
|
Reference in New Issue
Block a user