diff --git a/common/base_units.cpp b/common/base_units.cpp index c21bc5768e..02f143f2ee 100644 --- a/common/base_units.cpp +++ b/common/base_units.cpp @@ -187,7 +187,8 @@ wxString MessageTextFromValue( EDA_UNITS aUnits, double aValue, bool aAddUnitLab break; case EDA_UNITS::DEGREES: - format = wxT( "%.1f" ); + // 3 digits in mantissa should be good for rotation in degree + format = wxT( "%.3f" ); break; case EDA_UNITS::UNSCALED: diff --git a/common/widgets/unit_binder.cpp b/common/widgets/unit_binder.cpp index 1ca4b8ced8..cd1d42d5f3 100644 --- a/common/widgets/unit_binder.cpp +++ b/common/widgets/unit_binder.cpp @@ -35,11 +35,11 @@ wxDEFINE_EVENT( DELAY_FOCUS, wxCommandEvent ); -UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent, wxStaticText* aLabel, wxWindow* aValue, +UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent, wxStaticText* aLabel, wxWindow* aValueCtrl, wxStaticText* aUnitLabel, bool allowEval ) : m_frame( aParent ), m_label( aLabel ), - m_value( aValue ), + m_valueCtrl( aValueCtrl ), m_unitLabel( aUnitLabel ), m_eval( aParent->GetUserUnits() ), m_originTransforms( aParent->GetOriginTransforms() ), @@ -47,12 +47,13 @@ UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent, wxStaticText* aLabel, wxWindo { m_units = aParent->GetUserUnits(); m_dataType = EDA_DATA_TYPE::DISTANCE; - m_allowEval = allowEval && dynamic_cast( m_value ); + m_precision = 0; + m_allowEval = allowEval && dynamic_cast( m_valueCtrl ); m_needsEval = false; m_selStart = 0; m_selEnd = 0; - wxTextEntry* textEntry = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); if( textEntry ) { @@ -60,10 +61,11 @@ UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent, wxStaticText* aLabel, wxWindo textEntry->ChangeValue( wxT( "0" ) ); } - m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); + if( m_unitLabel ) + m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); - m_value->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), NULL, this ); - m_value->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), NULL, this ); + m_valueCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), NULL, this ); + m_valueCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), NULL, this ); Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), NULL, this ); m_frame->Connect( UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ), nullptr, this ); @@ -79,14 +81,24 @@ UNIT_BINDER::~UNIT_BINDER() void UNIT_BINDER::SetUnits( EDA_UNITS aUnits ) { m_units = aUnits; - m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); + + if( m_unitLabel ) + m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); +} + + +void UNIT_BINDER::SetPrecision( int aLength ) +{ + m_precision = std::min( aLength, 6 ); } void UNIT_BINDER::SetDataType( EDA_DATA_TYPE aDataType ) { m_dataType = aDataType; - m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); + + if( m_unitLabel ) + m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); } @@ -104,7 +116,7 @@ void UNIT_BINDER::onUnitsChanged( wxCommandEvent& aEvent ) void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent ) { - wxTextEntry* textEntry = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); if( m_allowEval && textEntry ) { @@ -125,7 +137,7 @@ void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent ) void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent ) { - wxTextEntry* textEntry = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); if( m_allowEval && textEntry ) { @@ -168,16 +180,16 @@ wxString valueDescriptionFromLabel( wxStaticText* aLabel ) void UNIT_BINDER::delayedFocusHandler( wxCommandEvent& ) { if( !m_errorMessage.IsEmpty() ) - DisplayError( m_value->GetParent(), m_errorMessage ); + DisplayError( m_valueCtrl->GetParent(), m_errorMessage ); m_errorMessage = wxEmptyString; - m_value->SetFocus(); + m_valueCtrl->SetFocus(); } bool UNIT_BINDER::Validate( double aMin, double aMax, EDA_UNITS aUnits ) { - wxTextEntry* textEntry = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); if( !textEntry || textEntry->GetValue() == INDETERMINATE_ACTION @@ -231,14 +243,15 @@ void UNIT_BINDER::SetValue( int aValue ) void UNIT_BINDER::SetDoubleValue( double aValue ) { double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType ); + displayValue = setPrecision( displayValue, false ); SetValue( StringFromValue( m_units, displayValue, false, m_dataType ) ); } void UNIT_BINDER::SetValue( wxString aValue ) { - wxTextEntry* textEntry = dynamic_cast( m_value ); - wxStaticText* staticText = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); + wxStaticText* staticText = dynamic_cast( m_valueCtrl ); if( textEntry ) textEntry->SetValue( aValue ); @@ -248,7 +261,8 @@ void UNIT_BINDER::SetValue( wxString aValue ) if( m_allowEval ) m_eval.Clear(); - m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); + if( m_unitLabel ) + m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); } @@ -262,8 +276,8 @@ void UNIT_BINDER::ChangeValue( int aValue ) void UNIT_BINDER::ChangeValue( const wxString& aValue ) { - wxTextEntry* textEntry = dynamic_cast( m_value ); - wxStaticText* staticText = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); + wxStaticText* staticText = dynamic_cast( m_valueCtrl ); if( textEntry ) textEntry->ChangeValue( aValue ); @@ -273,14 +287,15 @@ void UNIT_BINDER::ChangeValue( const wxString& aValue ) if( m_allowEval ) m_eval.Clear(); - m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); + if( m_unitLabel ) + m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_dataType ) ); } long long int UNIT_BINDER::GetValue() { - wxTextEntry* textEntry = dynamic_cast( m_value ); - wxStaticText* staticText = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); + wxStaticText* staticText = dynamic_cast( m_valueCtrl ); wxString value; if( textEntry ) @@ -300,10 +315,26 @@ long long int UNIT_BINDER::GetValue() } +double UNIT_BINDER::setPrecision( double aValue, bool aValueUsesUserUnits ) +{ + if( m_precision > 1 ) + { + int scale = pow( 10, m_precision ); + long long tmp = aValueUsesUserUnits ? aValue : To_User_Unit( m_units, aValue ) * scale; + aValue = static_cast( tmp ) / scale; + + if( !aValueUsesUserUnits ) + aValue = From_User_Unit( m_units, aValue ); + } + + return aValue; +} + + double UNIT_BINDER::GetDoubleValue() { - wxTextEntry* textEntry = dynamic_cast( m_value ); - wxStaticText* staticText = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); + wxStaticText* staticText = dynamic_cast( m_valueCtrl ); wxString value; if( textEntry ) @@ -323,13 +354,15 @@ double UNIT_BINDER::GetDoubleValue() } double displayValue = DoubleValueFromString( m_units, value, m_dataType ); + displayValue = setPrecision( displayValue, false ); + return m_originTransforms.FromDisplay( displayValue, m_coordType ); } bool UNIT_BINDER::IsIndeterminate() const { - wxTextEntry* te = dynamic_cast( m_value ); + wxTextEntry* te = dynamic_cast( m_valueCtrl ); if( te ) return te->GetValue() == INDETERMINATE_STATE || te->GetValue() == INDETERMINATE_ACTION; @@ -340,8 +373,8 @@ bool UNIT_BINDER::IsIndeterminate() const wxString UNIT_BINDER::GetOriginalText() const { - wxTextEntry* textEntry = dynamic_cast( m_value ); - wxStaticText* staticText = dynamic_cast( m_value ); + wxTextEntry* textEntry = dynamic_cast( m_valueCtrl ); + wxStaticText* staticText = dynamic_cast( m_valueCtrl ); if( m_allowEval ) return m_eval.OriginalText(); @@ -363,30 +396,38 @@ void UNIT_BINDER::SetLabel( const wxString& aLabel ) void UNIT_BINDER::Enable( bool aEnable ) { m_label->Enable( aEnable ); - m_value->Enable( aEnable ); - m_unitLabel->Enable( aEnable ); + m_valueCtrl->Enable( aEnable ); + + if( m_unitLabel ) + m_unitLabel->Enable( aEnable ); } void UNIT_BINDER::Show( bool aShow, bool aResize ) { m_label->Show( aShow ); - m_value->Show( aShow ); - m_unitLabel->Show( aShow ); + m_valueCtrl->Show( aShow ); + + if( m_unitLabel ) + m_unitLabel->Show( aShow ); if( aResize ) { if( aShow ) { m_label->SetSize( -1, -1 ); - m_value->SetSize( -1, -1 ); - m_unitLabel->SetSize( -1, -1 ); + m_valueCtrl->SetSize( -1, -1 ); + + if( m_unitLabel ) + m_unitLabel->SetSize( -1, -1 ); } else { m_label->SetSize( 0, 0 ); - m_value->SetSize( 0, 0 ); - m_unitLabel->SetSize( 0, 0 ); + m_valueCtrl->SetSize( 0, 0 ); + + if( m_unitLabel ) + m_unitLabel->SetSize( 0, 0 ); } } } diff --git a/include/widgets/unit_binder.h b/include/widgets/unit_binder.h index dee26ce95f..c99449a9dd 100644 --- a/include/widgets/unit_binder.h +++ b/include/widgets/unit_binder.h @@ -47,24 +47,33 @@ public: * @param aParent is the parent EDA_DRAW_FRAME. * @param aLabel is the static text used to label the text input widget (note: the label * text, trimmed of its colon, will also be used in error messages) - * @param aValue is the control used to edit or display the given value (wxTextCtrl, + * @param aValueCtrl is the control used to edit or display the given value (wxTextCtrl, * wxComboBox, wxStaticText, etc.). * @param aUnitLabel is the units label displayed after the text input widget + * Can be nullptr. * @param aAllowEval indicates \a aTextInput's content should be eval'ed before storing */ UNIT_BINDER( EDA_DRAW_FRAME* aParent, - wxStaticText* aLabel, wxWindow* aValue, wxStaticText* aUnitLabel, + wxStaticText* aLabel, wxWindow* aValueCtrl, wxStaticText* aUnitLabel, bool aAllowEval = true ); ~UNIT_BINDER() override; /** - * Function SetUnits * Normally not needed (as the UNIT_BINDER inherits from the parent frame), but can be * used to set to DEGREES for angular controls. */ virtual void SetUnits( EDA_UNITS aUnits ); + /** + * Normally not needed, but can be used to set the precision when using + * internal units that are floats (not integers) like DEGREES or PERCENT. + * Not used for integer values in IU + * @param aLength is the number of digits for mantissa (0 = no truncation) + * must be <= 6 + */ + virtual void SetPrecision( int aLength ); + /** * Used to override the datatype of the displayed property (default is DISTANCE) * @param aDataType is the datatype to use for the units text display @@ -84,6 +93,8 @@ public: * Function SetDoubleValue * Sets new value (in Internal Units) for the text field, taking care of units conversion. * @param aValue is the new value. + * the initialized value will be truncated according to the precision set by SetPrecision() + * (if not <= 0) */ virtual void SetDoubleValue( double aValue ); @@ -106,6 +117,8 @@ public: /** * Function GetValue * Returns the current value in Internal Units. + * the returned value will be truncated according to the precision set by + * SetPrecision() (if not <= 0) */ virtual double GetDoubleValue(); @@ -178,16 +191,28 @@ protected: void onUnitsChanged( wxCommandEvent& aEvent ); + /** When m_precision > 0 truncate the value aValue to show only + * m_precision digits in mantissa. + * used in GetDoubleValue to return a rounded value. + * Mainly for units set to DEGREES. + * @param aValue is the value to modify. + * @param aValueUsesUserUnits must be set to true if aValue is a user value, + * and set to false if aValue is a internal unit value. + * @return the "rounded" value. + */ + double setPrecision( double aValue, bool aValueUsesUserUnits ); + EDA_DRAW_FRAME* m_frame; ///> The bound widgets wxStaticText* m_label; - wxWindow* m_value; - wxStaticText* m_unitLabel; + wxWindow* m_valueCtrl; + wxStaticText* m_unitLabel; // Can be nullptr ///> Currently used units. EDA_UNITS m_units; EDA_DATA_TYPE m_dataType; + int m_precision; // 0 to 6 ///> Validation support. wxString m_errorMessage;