diff --git a/common/base_units.cpp b/common/base_units.cpp index cfecad0877..af5d545bc1 100644 --- a/common/base_units.cpp +++ b/common/base_units.cpp @@ -397,10 +397,10 @@ int ValueFromTextCtrl( const wxTextCtrl& aTextCtr ) { int value; wxString msg = aTextCtr.GetValue(); - NumericEvaluator eval; + NUMERIC_EVALUATOR eval( g_UserUnit ); - if( eval.process( msg.mb_str() ) ) - msg = wxString::FromUTF8( eval.result() ); + if( eval.Process( msg ) ) + msg = eval.Result(); value = ValueFromString( g_UserUnit, msg ); diff --git a/common/libeval/grammar.c b/common/libeval/grammar.c index cc9eb22186..4551f2d38f 100644 --- a/common/libeval/grammar.c +++ b/common/libeval/grammar.c @@ -98,9 +98,9 @@ typedef union { #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 #endif -#define ParseARG_SDECL NumericEvaluator* pEval ; -#define ParseARG_PDECL , NumericEvaluator* pEval -#define ParseARG_FETCH NumericEvaluator* pEval = yypParser->pEval +#define ParseARG_SDECL NUMERIC_EVALUATOR* pEval ; +#define ParseARG_PDECL , NUMERIC_EVALUATOR* pEval +#define ParseARG_FETCH NUMERIC_EVALUATOR* pEval = yypParser->pEval #define ParseARG_STORE yypParser->pEval = pEval #define YYNSTATE 16 #define YYNRULE 16 @@ -757,12 +757,12 @@ static void yy_reduce( break; case 9: /* expr ::= VAR */ #line 55 "grammar.lemon" -{ yygotominor.yy0.dValue = pEval->getVar(yymsp[0].minor.yy0.text); yygotominor.yy0.valid=true; } +{ yygotominor.yy0.dValue = pEval->GetVar(yymsp[0].minor.yy0.text); yygotominor.yy0.valid=true; } #line 762 "grammar.c" break; case 10: /* expr ::= VAR ASSIGN expr */ #line 56 "grammar.lemon" -{ pEval->setVar(yymsp[-2].minor.yy0.text, yymsp[0].minor.yy0.dValue); yygotominor.yy0.dValue = yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=false; } +{ pEval->SetVar(yymsp[-2].minor.yy0.text, yymsp[0].minor.yy0.dValue); yygotominor.yy0.dValue = yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=false; } #line 767 "grammar.c" break; case 11: /* expr ::= expr PLUS expr */ diff --git a/common/libeval/grammar.lemon b/common/libeval/grammar.lemon index d172fd9189..ffe627e9f4 100644 --- a/common/libeval/grammar.lemon +++ b/common/libeval/grammar.lemon @@ -52,8 +52,8 @@ stmt ::= expr SEMCOL. { pEval->parseSetResult(NAN); } expr(A) ::= VALUE(B). { A.dValue = B.dValue; A.valid=true; } expr(A) ::= expr(B) UNIT(C). { A.dValue = B.dValue * C.dValue; A.valid=B.valid; } expr(A) ::= MINUS expr(B). { A.dValue = -B.dValue; A.valid=B.valid; } -expr(A) ::= VAR(B). { A.dValue = pEval->getVar(B.text); A.valid=true; } -expr(A) ::= VAR(B) ASSIGN expr(C). { pEval->setVar(B.text, C.dValue); A.dValue = C.dValue; A.valid=false; } +expr(A) ::= VAR(B). { A.dValue = pEval->GetVar(B.text); A.valid=true; } +expr(A) ::= VAR(B) ASSIGN expr(C). { pEval->SetVar(B.text, C.dValue); A.dValue = C.dValue; A.valid=false; } expr(A) ::= expr(B) PLUS expr(C). { A.dValue = B.dValue + C.dValue; A.valid=C.valid; } expr(A) ::= expr(B) MINUS expr(C). { A.dValue = B.dValue - C.dValue; A.valid=C.valid; } expr(A) ::= expr(B) MULT expr(C). { A.dValue = B.dValue * C.dValue; A.valid=C.valid; } diff --git a/common/libeval/numeric_evaluator.cpp b/common/libeval/numeric_evaluator.cpp index 7da81f9ef8..7efb7054bc 100644 --- a/common/libeval/numeric_evaluator.cpp +++ b/common/libeval/numeric_evaluator.cpp @@ -17,24 +17,9 @@ along with this program. If not, see . */ -#define TESTMODE 0 #include -#if !TESTMODE -#include -#else -#include -#endif - - -#include -#include -#include -#include -#include - - /* The (generated) lemon parser is written in C. * In order to keep its symbol from the global namespace include the parser code with * a C++ namespace. @@ -49,335 +34,330 @@ namespace numEval #endif #include "grammar.c" + #ifdef __GNUC__ #pragma GCC diagnostic pop #endif } /* namespace numEval */ -// JEY TODO: remove this version; -NumericEvaluator :: NumericEvaluator() : - pClParser( 0 ) +NUMERIC_EVALUATOR::NUMERIC_EVALUATOR( EDA_UNITS_T aUnits, bool aUseMils ) { - struct lconv* lc = localeconv(); - cClDecSep = *lc->decimal_point; + struct lconv* lc = localeconv(); + m_localeDecimalSeparator = *lc->decimal_point; - bClTextInputStorage = true; + m_parseError = false; + m_parseFinished = false; - bClError = false; - bClParseFinished = false; + m_parser = numEval::ParseAlloc( malloc ); - if( pClParser == nullptr ) - pClParser = numEval::ParseAlloc(malloc); - - switch( g_UserUnit ) - { - case INCHES: - eClUnitDefault = Unit::Inch; - break; - case MILLIMETRES: - eClUnitDefault = Unit::Metric; - break; - default: - eClUnitDefault = Unit::Metric; - break; - } + switch( aUnits ) + { + case INCHES: + if( aUseMils ) + m_defaultUnits = Unit::Mil; + else + m_defaultUnits = Unit::Inch; + break; + case MILLIMETRES:m_defaultUnits = Unit::Metric; + break; + default:m_defaultUnits = Unit::Metric; + break; + } } -NumericEvaluator::NumericEvaluator( EDA_UNITS_T aUnits, bool aUseMils ) : - pClParser( 0 ) + +NUMERIC_EVALUATOR::~NUMERIC_EVALUATOR() { - struct lconv* lc = localeconv(); - cClDecSep = *lc->decimal_point; + numEval::ParseFree( m_parser, free ); - bClTextInputStorage = true; - pClParser = numEval::ParseAlloc(malloc); + // Allow explicit call to destructor + m_parser = nullptr; - switch( aUnits ) - { - case INCHES: - if( aUseMils ) - eClUnitDefault = Unit::Mil; - else - eClUnitDefault = Unit::Inch; - break; - case MILLIMETRES: - eClUnitDefault = Unit::Metric; - break; - default: - eClUnitDefault = Unit::Metric; - break; - } + Clear(); } -NumericEvaluator :: ~NumericEvaluator() + +void NUMERIC_EVALUATOR::Clear() { - numEval::ParseFree(pClParser, free); - - // Allow explicit call to destructor - pClParser = nullptr; - - clear(); + free( m_token.token ); + m_token.token = nullptr; + m_token.input = nullptr; + m_parseError = true; + m_originalText = wxEmptyString; } -void -NumericEvaluator :: clear(const void* pObj) -{ - free(clToken.token); - clToken.token = nullptr; - clToken.input = nullptr; - bClError = true; - if (bClTextInputStorage) - clObjMap.clear(); +void NUMERIC_EVALUATOR::parseError( const char* s ) +{ + m_parseError = true; } -void -NumericEvaluator :: parse(int token, numEval::TokenType value) + +void NUMERIC_EVALUATOR::parseOk() { - numEval::Parse(pClParser, token, value, this); + m_parseFinished = true; } -void -NumericEvaluator :: parseError(const char* s) + +void NUMERIC_EVALUATOR::parseSetResult( double val ) { - bClError = true; + snprintf( m_token.token, m_token.OutLen, "%.10g", val ); } -void -NumericEvaluator :: parseOk() + +wxString NUMERIC_EVALUATOR::OriginalText() const { - bClParseFinished = true; + return m_originalText; } -void -NumericEvaluator :: parseSetResult(double val) + +bool NUMERIC_EVALUATOR::Process( const wxString& aString ) { - snprintf(clToken.token, clToken.OutLen, "%.10g", val); + m_originalText = aString; + + // Feed parser token after token until end of input. + + newString( aString ); + m_parseError = false; + m_parseFinished = false; + Token tok; + + do + { + tok = getToken(); + numEval::Parse( m_parser, tok.token, tok.value, this ); + + if( m_parseFinished || tok.token == ENDS ) + { + // Reset parser by passing zero as token ID, value is ignored. + numEval::Parse( m_parser, 0, tok.value, this ); + break; + } + } while( tok.token ); + + return !m_parseError; } -const char* -NumericEvaluator :: textInput(const void* pObj) const -{ - auto it = clObjMap.find(pObj); - if (it != clObjMap.end()) return it->second.c_str(); - return nullptr; +void NUMERIC_EVALUATOR::newString( const wxString& aString ) +{ + Clear(); + auto len = aString.length(); + m_token.token = reinterpret_cast( malloc( TokenStat::OutLen + 1 )); + strcpy( m_token.token, "0" ); + m_token.inputLen = len; + m_token.pos = 0; + m_token.input = aString.mb_str(); + m_parseFinished = false; } -bool -NumericEvaluator :: process(const char* s) + +NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken() { - /* Process new string. - * Feed parser token after token until end of input. - */ + Token retval; + size_t idx; - newString(s); + retval.token = ENDS; + retval.value.dValue = 0; - if (pClParser == nullptr) - pClParser = numEval::ParseAlloc(malloc); + if( m_token.token == nullptr ) + return retval; - bClError = false; - bClParseFinished = false; + if( m_token.input == nullptr ) + return retval; - Token tok; - do { - tok = getToken(); - parse(tok.token, tok.value); - if (bClParseFinished || tok.token == ENDS) { - // Reset parser by passing zero as token ID, value is ignored. - numEval::Parse(pClParser, 0, tok.value, this); - break; - } - //usleep(200000); - } while (tok.token); + if( m_token.pos >= m_token.inputLen ) + return retval; - return !bClError; + auto isDecimalSeparator = [ & ]( char ch ) -> bool { + return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' ); + }; + + // Lambda: get value as string, store into clToken.token and update current index. + auto extractNumber = [ & ]() { + bool haveSeparator = false; + idx = 0; + auto ch = m_token.input[ m_token.pos ]; + + do + { + if( isDecimalSeparator( ch ) && haveSeparator ) + break; + + m_token.token[ idx++ ] = ch; + + if( isDecimalSeparator( ch )) + haveSeparator = true; + + ch = m_token.input[ ++m_token.pos ]; + } while( isdigit( ch ) || isDecimalSeparator( ch )); + + m_token.token[ idx ] = 0; + + // Ensure that the systems decimal separator is used + for( int i = strlen( m_token.token ); i; i-- ) + if( isDecimalSeparator( m_token.token[ i - 1 ] )) + m_token.token[ i - 1 ] = m_localeDecimalSeparator; + }; + + // Lamda: Get unit for current token. + // Valid units are ", in, mm, mil and thou. Returns Unit::Invalid otherwise. + auto checkUnit = [ this ]() -> Unit { + char ch = m_token.input[ m_token.pos ]; + + if( ch == '"' ) + { + m_token.pos++; + return Unit::Inch; + } + + // Do not use strcasecmp() as it is not available on all platforms + const char* cptr = &m_token.input[ m_token.pos ]; + const auto sizeLeft = m_token.inputLen - m_token.pos; + + if( sizeLeft >= 2 && ch == 'm' && cptr[ 1 ] == 'm' && !isalnum( cptr[ 2 ] )) + { + m_token.pos += 2; + return Unit::Metric; + } + + if( sizeLeft >= 2 && ch == 'i' && cptr[ 1 ] == 'n' && !isalnum( cptr[ 2 ] )) + { + m_token.pos += 2; + return Unit::Inch; + } + + if( sizeLeft >= 3 && ch == 'm' && cptr[ 1 ] == 'i' && cptr[ 2 ] == 'l' && !isalnum( cptr[ 3 ] )) + { + m_token.pos += 3; + return Unit::Mil; + } + + if( sizeLeft >= 4 && ch == 't' && cptr[ 1 ] == 'h' && cptr[ 2 ] == 'o' && cptr[ 2 ] == 'u' && !isalnum( cptr[ 3 ] )) + { + m_token.pos += 4; + return Unit::Mil; + } + + return Unit::Invalid; + }; + + char ch; + + // Start processing of first/next token: Remove whitespace + for( ;; ) + { + ch = m_token.input[ m_token.pos ]; + + if( ch == ' ' ) + m_token.pos++; + else + break; + } + + Unit convertFrom; + + if( ch == 0 ) + { + /* End of input */ + } + else if( isdigit( ch ) || isDecimalSeparator( ch )) + { + // VALUE + extractNumber(); + retval.token = VALUE; + retval.value.dValue = atof( m_token.token ); + } + else if(( convertFrom = checkUnit()) != Unit::Invalid ) + { + // UNIT + // Units are appended to a VALUE. + // Determine factor to default unit if unit for value is given. + // Example: Default is mm, unit is inch: factor is 25.4 + // The factor is assigned to the terminal UNIT. The actual + // conversion is done within a parser action. + retval.token = UNIT; + if( m_defaultUnits == Unit::Metric ) + { + switch( convertFrom ) + { + case Unit::Inch :retval.value.dValue = 25.4; break; + case Unit::Mil :retval.value.dValue = 25.4 / 1000.0; break; + case Unit::Metric :retval.value.dValue = 1.0; break; + case Unit::Invalid :break; + } + } + else if( m_defaultUnits == Unit::Inch ) + { + switch( convertFrom ) + { + case Unit::Inch :retval.value.dValue = 1.0; break; + case Unit::Mil :retval.value.dValue = 1.0 / 1000.0; break; + case Unit::Metric :retval.value.dValue = 1.0 / 25.4; break; + case Unit::Invalid :break; + } + } + else if( m_defaultUnits == Unit::Mil ) + { + switch( convertFrom ) + { + case Unit::Inch :retval.value.dValue = 1.0 * 1000.0; break; + case Unit::Mil :retval.value.dValue = 1.0; break; + case Unit::Metric :retval.value.dValue = 1000.0 / 25.4; break; + case Unit::Invalid :break; + } + } + } + else if( isalpha( ch )) + { + // VAR + const char* cptr = &m_token.input[ m_token.pos ]; + cptr++; + + while( isalnum( *cptr )) + cptr++; + + retval.token = VAR; + size_t bytesToCopy = cptr - &m_token.input[ m_token.pos ]; + + if( bytesToCopy >= sizeof( retval.value.text )) + bytesToCopy = sizeof( retval.value.text ) - 1; + + strncpy( retval.value.text, &m_token.input[ m_token.pos ], bytesToCopy ); + retval.value.text[ bytesToCopy ] = 0; + m_token.pos += cptr - &m_token.input[ m_token.pos ]; + } + else + { + // Single char tokens + switch( ch ) + { + case '+' :retval.token = PLUS; break; + case '-' :retval.token = MINUS; break; + case '*' :retval.token = MULT; break; + case '/' :retval.token = DIVIDE; break; + case '(' :retval.token = PARENL; break; + case ')' :retval.token = PARENR; break; + case '=' :retval.token = ASSIGN; break; + case ';' :retval.token = SEMCOL; break; + default :m_parseError = true; break; /* invalid character */ + } + m_token.pos++; + } + + return retval; } -bool -NumericEvaluator :: process(const char* s, const void* pObj) +void NUMERIC_EVALUATOR::SetVar( const wxString& aString, double aValue ) { - if (bClTextInputStorage) // Store input string for (text entry) pObj. - clObjMap[pObj] = s; - return process(s); + m_varMap[ aString ] = aValue; } -void -NumericEvaluator :: newString(const char* s) +double NUMERIC_EVALUATOR::GetVar( const wxString& aString ) { - clear(); - auto len = strlen(s); - clToken.token = reinterpret_cast(malloc(TokenStat::OutLen+1)); - strcpy(clToken.token, "0"); - clToken.inputLen = len; - clToken.pos = 0; - clToken.input = s; - bClParseFinished = false; -} - -NumericEvaluator::Token NumericEvaluator::getToken() -{ - Token retval; - size_t idx; - - retval.token = ENDS; - retval.value.dValue = 0; - - if (clToken.token == nullptr) return retval; - if (clToken.input == nullptr) return retval; - if (clToken.pos >= clToken.inputLen) return retval; - - auto isDecSep = [&](char ch) -> bool { - if (ch == cClDecSep) return true; - if (cClDecSep == ',' && ch == '.') return true; - return false; - }; - - // Lambda: get value as string, store into clToken.token and update current index. - auto extractNumber = [&]() { - short sepCount = 0; - idx = 0; - auto ch = clToken.input[clToken.pos]; - do { - if (ch == isDecSep(ch) && sepCount) break; - clToken.token[idx++] = ch; - if (isDecSep(ch)) sepCount++; - ch = clToken.input[++clToken.pos]; - } while (isdigit(ch) || isDecSep(ch)); - clToken.token[idx] = 0; - - // Ensure that the systems decimal separator is used - for (int i = strlen(clToken.token); i; i--) if (isDecSep(clToken.token[i-1])) clToken.token[i-1] = cClDecSep; - }; - - // Lamda: Get unit for current token. - // Valid units are ", in, mm, mil and thou. Returns Unit::Invalid otherwise. - auto checkUnit = [this]() -> Unit { - char ch = clToken.input[clToken.pos]; - if (ch == '"') { - clToken.pos++; - return Unit::Inch; - } - // Do not use strcasecmp() as it is not available on all platforms - const char* cptr = &clToken.input[clToken.pos]; - const auto sizeLeft = clToken.inputLen - clToken.pos; - if (sizeLeft >= 2 && ch == 'm' && tolower(cptr[1]) == 'm' && !isalnum(cptr[2])) { - clToken.pos += 2; - return Unit::Metric; - } - if (sizeLeft >= 2 && ch == 'i' && tolower(cptr[1]) == 'n' && !isalnum(cptr[2])) { - clToken.pos += 2; - return Unit::Inch; - } - if (sizeLeft >= 3 && ch == 'm' && tolower(cptr[1]) == 'i' && tolower(cptr[2]) == 'l' && !isalnum(cptr[3])) { - clToken.pos += 3; - return Unit::Mil; - } - if (sizeLeft >= 4 && ch == 't' && tolower(cptr[1]) == 'h' && tolower(cptr[2]) == 'o' && tolower(cptr[2]) == 'u' && !isalnum(cptr[3])) { - clToken.pos += 4; - return Unit::Mil; - } - - return Unit::Invalid; - }; - - // Start processing of first/next token: Remove whitespace - char ch; - for (;;) { - ch = clToken.input[clToken.pos]; - if (ch == ' ') { - clToken.pos++; - } - else break; - } - - Unit convertFrom; - - if (ch == 0) { - /* End of input */ - } - else if (isdigit(ch) || isDecSep(ch)) { // VALUE - extractNumber(); - retval.token = VALUE; - retval.value.dValue = atof(clToken.token); - } - else if ((convertFrom = checkUnit()) != Unit::Invalid) { // UNIT - /* Units are appended to a VALUE. - * Determine factor to default unit if unit for value is given. - * Example: Default is mm, unit is inch: factor is 25.4 - * The factor is assigned to the terminal UNIT. The actual - * conversion is done within a parser action. - */ - retval.token = UNIT; - if (eClUnitDefault == Unit::Metric) - { - switch (convertFrom) { - case Unit::Inch : retval.value.dValue = 25.4; break; - case Unit::Mil : retval.value.dValue = 25.4/1000.0; break; - case Unit::Metric : retval.value.dValue = 1.0; break; - case Unit::Invalid : break; - } - } - else if (eClUnitDefault == Unit::Inch) - { - switch (convertFrom) { - case Unit::Inch : retval.value.dValue = 1.0; break; - case Unit::Mil : retval.value.dValue = 1.0/1000.0; break; - case Unit::Metric : retval.value.dValue = 1.0/25.4; break; - case Unit::Invalid : break; - } - } - else if (eClUnitDefault == Unit::Mil) - { - switch (convertFrom) - { - case Unit::Inch : retval.value.dValue = 1.0*1000.0; break; - case Unit::Mil : retval.value.dValue = 1.0; break; - case Unit::Metric : retval.value.dValue = 1000.0/25.4; break; - case Unit::Invalid : break; - } - } - } - else if (isalpha(ch)) { // VAR - const char* cptr = &clToken.input[clToken.pos]; - cptr++; - while (isalnum(*cptr)) cptr++; - retval.token = VAR; - size_t bytesToCopy = cptr - &clToken.input[clToken.pos]; - if (bytesToCopy >= sizeof(retval.value.text)) bytesToCopy = sizeof(retval.value.text)-1; - strncpy(retval.value.text, &clToken.input[clToken.pos], bytesToCopy); - retval.value.text[bytesToCopy] = 0; - clToken.pos += cptr - &clToken.input[clToken.pos]; - } - else { // Single char tokens - switch (ch) { - case '+' : retval.token = PLUS; break; - case '-' : retval.token = MINUS; break; - case '*' : retval.token = MULT; break; - case '/' : retval.token = DIVIDE; break; - case '(' : retval.token = PARENL; break; - case ')' : retval.token = PARENR; break; - case '=' : retval.token = ASSIGN; break; - case ';' : retval.token = SEMCOL; break; - default: bClError = true; break; /* invalid character */ - } - clToken.pos++; - } - - return retval; -} - -void -NumericEvaluator :: setVar(const std::string& s, double value) -{ - clVarMap[s] = value; -} - -double -NumericEvaluator :: getVar(const std::string& s) -{ - auto result = clVarMap.find(s); - if (result != clVarMap.end()) return result->second; - return 0.0; + if( m_varMap[ aString ] ) + return m_varMap[ aString ]; + else + return 0.0; } diff --git a/common/widgets/text_ctrl_eval.cpp b/common/widgets/text_ctrl_eval.cpp index 6ebba2575b..73a660935f 100644 --- a/common/widgets/text_ctrl_eval.cpp +++ b/common/widgets/text_ctrl_eval.cpp @@ -27,7 +27,8 @@ TEXT_CTRL_EVAL::TEXT_CTRL_EVAL( wxWindow* aParent, wxWindowID aId, const wxString& aValue, const wxPoint& aPos, const wxSize& aSize, long aStyle, const wxValidator& aValidator, const wxString& aName ) - : wxTextCtrl( aParent, aId, aValue, aPos, aSize, aStyle | wxTE_PROCESS_ENTER, aValidator, aName ) + : wxTextCtrl( aParent, aId, aValue, aPos, aSize, aStyle | wxTE_PROCESS_ENTER, aValidator, aName ), + m_eval( g_UserUnit ) { Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusGet ), NULL, this ); @@ -38,19 +39,19 @@ TEXT_CTRL_EVAL::TEXT_CTRL_EVAL( wxWindow* aParent, wxWindowID aId, const } -void TEXT_CTRL_EVAL::SetValue( const wxString& aValue ) -{ - wxTextCtrl::SetValue( aValue ); - m_eval.clear( this ); -} - - +void TEXT_CTRL_EVAL::SetValue( const wxString& aValue ) +{ + wxTextCtrl::SetValue( aValue ); + m_eval.Clear(); +} + + void TEXT_CTRL_EVAL::onTextFocusGet( wxFocusEvent& aEvent ) { - auto oldStr = m_eval.textInput( this ); + wxString oldStr = m_eval.OriginalText(); - if( oldStr ) - wxTextCtrl::SetValue( wxString::FromUTF8( oldStr ) ); + if( oldStr.length() ) + SetValue( oldStr ); aEvent.Skip(); } @@ -76,8 +77,8 @@ void TEXT_CTRL_EVAL::onTextEnter( wxCommandEvent& aEvent ) void TEXT_CTRL_EVAL::evaluate() { if( GetValue().IsEmpty() ) - wxTextCtrl::SetValue( "0" ); + wxTextCtrl::SetValue( "0" ); - if( m_eval.process( GetValue().mb_str(), this ) ) - wxTextCtrl::SetValue( wxString::FromUTF8( m_eval.result() ) ); + if( m_eval.Process( GetValue() ) ) + SetValue( m_eval.Result() ); } diff --git a/common/widgets/unit_binder.cpp b/common/widgets/unit_binder.cpp index 3d134e85eb..eabaab88e3 100644 --- a/common/widgets/unit_binder.cpp +++ b/common/widgets/unit_binder.cpp @@ -65,10 +65,10 @@ void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent ) { if( m_allowEval ) { - auto oldStr = m_eval.textInput( this ); + wxString oldStr = m_eval.OriginalText(); - if( oldStr ) - m_textEntry->SetValue( wxString::FromUTF8( oldStr ) ); + if( oldStr.length() ) + m_textEntry->SetValue( oldStr ); } aEvent.Skip(); @@ -104,10 +104,10 @@ void UNIT_BINDER::onTextEnter( wxCommandEvent& aEvent ) void UNIT_BINDER::evaluate() { if( m_textEntry->GetValue().IsEmpty() ) - m_textEntry->SetValue( "0" ); + m_textEntry->ChangeValue( "0" ); - if( m_eval.process( m_textEntry->GetValue().mb_str(), this ) ) - m_textEntry->SetValue( wxString::FromUTF8( m_eval.result() ) ); + if( m_eval.Process( m_textEntry->GetValue() ) ) + m_textEntry->ChangeValue( m_eval.Result() ); } @@ -137,7 +137,7 @@ bool UNIT_BINDER::Validate( bool setFocusOnError ) { wxString msg = wxString::Format( _( "%s must be larger than %s." ), valueDescriptionFromLabel( m_label ), - StringFromValue( EDA_UNITS_T::MILLIMETRES, m_min, true ) ); + StringFromValue( m_units, m_min, true ) ); DisplayError( textInput->GetParent(), msg ); if( setFocusOnError ) @@ -154,7 +154,7 @@ bool UNIT_BINDER::Validate( bool setFocusOnError ) { wxString msg = wxString::Format( _( "%s must be smaller than %s." ), valueDescriptionFromLabel( m_label ), - StringFromValue( EDA_UNITS_T::MILLIMETRES, m_max, true ) ); + StringFromValue( m_units, m_max, true ) ); DisplayError( textInput->GetParent(), msg ); if( setFocusOnError ) @@ -182,7 +182,7 @@ void UNIT_BINDER::SetValue( wxString aValue ) m_textEntry->SetValue( aValue ); if( m_allowEval ) - m_eval.clear(); + m_eval.Clear(); m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_useMils ) ); } diff --git a/include/libeval/numeric_evaluator.h b/include/libeval/numeric_evaluator.h index e2ffbdf5b6..4de591fca1 100644 --- a/include/libeval/numeric_evaluator.h +++ b/include/libeval/numeric_evaluator.h @@ -80,39 +80,32 @@ Supported units are millimeters (mm), Mil (mil) and inch (") namespace numEval { -struct TokenType -{ - union { - double dValue; - int iValue; - }; + struct TokenType + { + union + { + double dValue; + int iValue; + }; - bool valid; - char text[32]; -}; + bool valid; + char text[32]; + }; } // namespace numEval -class NumericEvaluator { - enum class Unit { Invalid, Metric, Inch, Mil }; +class NUMERIC_EVALUATOR +{ + enum class Unit { Invalid, Metric, Inch, Mil }; public: - NumericEvaluator(); - NumericEvaluator( EDA_UNITS_T aUnits, bool aUseMils ); - ~NumericEvaluator(); + NUMERIC_EVALUATOR( EDA_UNITS_T aUnits, bool aUseMils = false ); + ~NUMERIC_EVALUATOR(); /* clear() should be invoked by the client if a new input string is to be processed. It * will reset the parser. User defined variables are retained. */ - void clear(const void* pObj = nullptr); - - /* Set the decimal separator for the input string. Defaults to '.' */ - void setDecimalSeparator(char sep); - - /* Enable or disable support for input string storage. - * If enabled the input string is saved if process(const char*, const void*) is used. - */ - void enableTextInputStorage(bool w) { bClTextInputStorage = w; } + void Clear(); /* Used by the lemon parser */ void parseError(const char* s); @@ -120,83 +113,76 @@ public: void parseSetResult(double); /* Check if previous invokation of process() was successful */ - inline bool isValid() const { return !bClError; } + inline bool IsValid() const { return !m_parseError; } /* Result of string processing. Undefined if !isValid() */ - inline const char* result() const { return clToken.token; } - - /* Numeric result of string processing, in default units. */ - inline const double value() const { return resultValue; } + inline wxString Result() const { return wxString::FromUTF8( m_token.token ); } /* Evaluate input string. * Result can be retrieved by result(). * Returns true if input string could be evaluated, otherwise false. */ - bool process(const char* s); + bool Process( const wxString& aString ); - /* Like process(const char*) but also stores input string in a std:map with key pObj. */ - bool process(const char* s, const void* pObj); - - /* Retrieve old input string with key pObj. */ - const char* textInput(const void* pObj) const; + /* Retrieve the original text before evaluation. */ + wxString OriginalText() const; /* Add/set variable with value */ - void setVar(const std::string&, double value); + void SetVar( const wxString& aString, double aValue ); /* Get value of variable. Returns 0.0 if not defined. */ - double getVar(const std::string&); + double GetVar( const wxString& aString ); /* Remove single variable */ - void removeVar(const std::string& s) { clVarMap.erase(s); } + void RemoveVar( const wxString& aString ) { m_varMap.erase( aString ); } /* Remove all variables */ - void clearVar() { clVarMap.clear(); } + void ClearVar() { m_varMap.clear(); } protected: - /* Token type used by the tokenizer */ - struct Token { + /* Token type used by the tokenizer */ + struct Token + { int token; numEval::TokenType value; }; /* Begin processing of a new input string */ - void newString(const char* s); + void newString( const wxString& aString ); /* Tokenizer: Next token/value taken from input string. */ Token getToken(); /* Used by processing loop */ - void parse(int token, numEval::TokenType value); + void parse( int token, numEval::TokenType value ); private: - void* pClParser; // the current lemon parser state machine + void* m_parser; // the current lemon parser state machine /* Token state for input string. */ - struct TokenStat { - enum { OutLen=32 }; - TokenStat() : input(0), token(0), inputLen(0), pos(0) { /* empty */ } - const char* input; // current input string ("var=4") - char* token; // output token ("var", type:VAR; "4", type:VALUE) - size_t inputLen; // strlen(input) - size_t pos; // current index - } clToken; + struct TokenStat + { + enum { OutLen = 32 }; + TokenStat() : input( 0 ), token( 0 ), inputLen( 0 ), pos( 0 ) { /* empty */ } + const char* input; // current input string ("var=4") + char* token; // output token ("var", type:VAR; "4", type:VALUE) + size_t inputLen; // strlen(input) + size_t pos; // current index + } + m_token; - char cClDecSep; // decimal separator ('.') + char m_localeDecimalSeparator; /* Parse progress. Set by parser actions. */ - bool bClError; - bool bClParseFinished; + bool m_parseError; + bool m_parseFinished; - /* The result (in eClUnitDefault units) */ - int resultValue; + Unit m_defaultUnits; // Default unit for values - bool bClTextInputStorage; // Enable input string storage used by process(const char*, const void*) + wxString m_originalText; - Unit eClUnitDefault; // Default unit for values - - std::map clObjMap; // Map pointer to text entry -> (original) input string - std::map clVarMap; + std::map m_varMap; }; -#endif /* NUMERIC_EVALUATOR_H_ */ +#endif /* NUMERIC_EVALUATOR_H_ */ \ No newline at end of file diff --git a/include/widgets/text_ctrl_eval.h b/include/widgets/text_ctrl_eval.h index 0ad727198f..9a46b066b9 100644 --- a/include/widgets/text_ctrl_eval.h +++ b/include/widgets/text_ctrl_eval.h @@ -57,7 +57,7 @@ public: protected: ///> Numeric expression evaluator - NumericEvaluator m_eval; + NUMERIC_EVALUATOR m_eval; void onTextFocusGet( wxFocusEvent& aEvent ); void onTextFocusLost( wxFocusEvent& aEvent ); diff --git a/include/widgets/unit_binder.h b/include/widgets/unit_binder.h index f0c97e962b..bd65c426dc 100644 --- a/include/widgets/unit_binder.h +++ b/include/widgets/unit_binder.h @@ -121,7 +121,7 @@ protected: int m_max; ///> Evaluator - NumericEvaluator m_eval; + NUMERIC_EVALUATOR m_eval; bool m_allowEval; }; diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index eaa46517ae..02d844d747 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -1022,7 +1022,6 @@ const BOX2I MODULE::ViewBBox() const area.Inflate( biggest_clearance ); } - return area; }