Auto-convert numeric values in fields when referencing them in expressions.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21723
This commit is contained in:
Jeff Young 2025-09-12 20:34:54 +01:00
parent aa4de22ef4
commit 2c102a62e0
3 changed files with 123 additions and 17 deletions

View File

@ -708,6 +708,104 @@ double EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale,
} }
bool EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale, const wxString& aTextValue,
double& aDoubleValue )
{
double dtmp = 0;
// Acquire the 'right' decimal point separator
const struct lconv* lc = localeconv();
wxChar decimal_point = lc->decimal_point[0];
wxString buf( aTextValue.Strip( wxString::both ) );
// Convert any entered decimal point separators to the 'right' one
buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
// Find the end of the numeric part
unsigned brk_point = 0;
while( brk_point < buf.Len() )
{
wxChar ch = buf[brk_point];
if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
break;
++brk_point;
}
if( brk_point == 0 )
return false;
// Extract the numeric part
buf.Left( brk_point ).ToDouble( &dtmp );
// Check the unit designator
wxString unit( buf.Mid( brk_point ).Strip( wxString::both ).Lower() );
EDA_UNITS units;
//check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
{
units = EDA_UNITS::UM;
}
else if( unit == wxT( "mm" ) )
{
units = EDA_UNITS::MM;
}
else if( unit == wxT( "cm" ) )
{
units = EDA_UNITS::CM;
}
else if( unit == wxT( "mil" ) || unit == wxT( "mils" ) || unit == wxT( "thou" ) )
{
units = EDA_UNITS::MILS;
}
else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
{
units = EDA_UNITS::INCH;
}
else if( unit == wxT( "oz" ) ) // 1 oz = 1.37 mils
{
units = EDA_UNITS::MILS;
dtmp *= 1.37;
}
else if( unit == wxT( "ra" ) ) // Radians
{
dtmp *= 180.0f / M_PI;
}
else if( unit == wxT( "fs" ) )
{
units = EDA_UNITS::FS;
}
else if( unit == wxT( "ps" ) )
{
units = EDA_UNITS::PS;
}
else if( unit == wxT( "ps/in" ) )
{
units = EDA_UNITS::PS_PER_INCH;
}
else if( unit == wxT( "ps/cm" ) )
{
units = EDA_UNITS::PS_PER_CM;
}
else if( unit == wxT( "ps/mm" ) )
{
units = EDA_UNITS::PS_PER_MM;
}
else
{
return false;
}
aDoubleValue = FromUserUnit( aIuScale, units, dtmp );
return true;
}
long long int EDA_UNIT_UTILS::UI::ValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits, long long int EDA_UNIT_UTILS::UI::ValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
const wxString& aTextValue, EDA_DATA_TYPE aType ) const wxString& aTextValue, EDA_DATA_TYPE aType )
{ {

View File

@ -256,6 +256,9 @@ namespace EDA_UNIT_UTILS
KICOMMON_API double DoubleValueFromString( const wxString& aTextValue ); KICOMMON_API double DoubleValueFromString( const wxString& aTextValue );
KICOMMON_API bool DoubleValueFromString( const EDA_IU_SCALE& aIuScale, const wxString& aTextValue,
double& aDoubleValue );
/** /**
* Convert \a aTextValue in \a aUnits to internal units used by the application. * Convert \a aTextValue in \a aUnits to internal units used by the application.
* *

View File

@ -447,28 +447,33 @@ LIBEVAL::VALUE* PCBEXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
if( it->second->Name() == wxT( "Pin Type" ) ) if( it->second->Name() == wxT( "Pin Type" ) )
return new PCBEXPR_PINTYPE_VALUE( str ); return new PCBEXPR_PINTYPE_VALUE( str );
else
return new LIBEVAL::VALUE( str ); // If it quacks like a duck, it is a duck
double doubleVal;
if( EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, str, doubleVal ) )
return new LIBEVAL::VALUE( doubleVal );
return new LIBEVAL::VALUE( str );
} }
else else if( it->second->Name() == wxT( "Layer" )
|| it->second->Name() == wxT( "Layer Top" )
|| it->second->Name() == wxT( "Layer Bottom" ) )
{ {
const wxAny& any = item->Get( it->second ); const wxAny& any = item->Get( it->second );
PCB_LAYER_ID layer; PCB_LAYER_ID layer;
if( it->second->Name() == wxT( "Layer" ) if( any.GetAs<PCB_LAYER_ID>( &layer ) )
|| it->second->Name() == wxT( "Layer Top" ) return new PCBEXPR_LAYER_VALUE( layer );
|| it->second->Name() == wxT( "Layer Bottom" ) ) else if( any.GetAs<wxString>( &str ) )
{ return new PCBEXPR_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) );
if( any.GetAs<PCB_LAYER_ID>( &layer ) ) }
return new PCBEXPR_LAYER_VALUE( layer ); else
else if( any.GetAs<wxString>( &str ) ) {
return new PCBEXPR_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) ); const wxAny& any = item->Get( it->second );
}
else if( any.GetAs<wxString>( &str ) )
{ return new LIBEVAL::VALUE( str );
if( any.GetAs<wxString>( &str ) )
return new LIBEVAL::VALUE( str );
}
} }
return new LIBEVAL::VALUE(); return new LIBEVAL::VALUE();