Improve robustness of numeric evaluation.

It would appear that some platforms process the KILL_FOCUS event
after running TransferDataFromWindow().  This change makes sure
that the evaluation is done no matter the order.

Fixes: lp:1793911
* https://bugs.launchpad.net/kicad/+bug/1793911
This commit is contained in:
Jeff Young 2018-10-08 12:58:10 +01:00
parent 90df7a8b22
commit 3024ded91e
4 changed files with 54 additions and 59 deletions

View File

@ -136,6 +136,12 @@ bool NUMERIC_EVALUATOR::Process( const wxString& aString )
m_parseFinished = false; m_parseFinished = false;
Token tok; Token tok;
if( aString.IsEmpty() )
{
m_parseFinished = true;
return true;
}
do do
{ {
tok = getToken(); tok = getToken();

View File

@ -76,9 +76,6 @@ void TEXT_CTRL_EVAL::onTextEnter( wxCommandEvent& aEvent )
void TEXT_CTRL_EVAL::evaluate() void TEXT_CTRL_EVAL::evaluate()
{ {
if( GetValue().IsEmpty() )
wxTextCtrl::SetValue( "0" );
if( m_eval.Process( GetValue() ) ) if( m_eval.Process( GetValue() ) )
SetValue( m_eval.Result() ); SetValue( m_eval.Result() );
} }

View File

@ -46,6 +46,7 @@ UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent,
m_min = aMin; m_min = aMin;
m_max = aMax; m_max = aMax;
m_allowEval = allowEval && dynamic_cast<wxTextEntry*>( m_value ); m_allowEval = allowEval && dynamic_cast<wxTextEntry*>( m_value );
m_needsEval = false;
auto textEntry = dynamic_cast<wxTextEntry*>( m_value ); auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
if( textEntry ) if( textEntry )
@ -58,13 +59,6 @@ UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent,
m_value->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), NULL, this ); 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_value->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), NULL, this );
// Connect wxEVT_TEXT_ENTER when (and *only when*) m_value has the wxTE_PROCESS_ENTER style
// because if this style does not exist:
// 1 - Connect wxEVT_TEXT_ENTER is useless
// 2 - it generates wxWidgets assert
if( m_value->HasFlag( wxTE_PROCESS_ENTER ) )
m_value->Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( UNIT_BINDER::onTextEnter ), NULL, this );
} }
@ -86,6 +80,8 @@ void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
if( oldStr.length() ) if( oldStr.length() )
textEntry->SetValue( oldStr ); textEntry->SetValue( oldStr );
m_needsEval = true;
} }
aEvent.Skip(); aEvent.Skip();
@ -94,8 +90,15 @@ void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent ) void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
{ {
if( m_allowEval ) auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
evaluate();
if( m_allowEval && textEntry )
{
if( m_eval.Process( textEntry->GetValue() ) )
textEntry->ChangeValue( m_eval.Result() );
m_needsEval = false;
}
Validate( true ); Validate( true );
@ -103,32 +106,6 @@ void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
} }
void UNIT_BINDER::onTextEnter( wxCommandEvent& aEvent )
{
if( m_allowEval )
evaluate();
// Send an OK event to the parent dialog
wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK );
wxPostEvent( m_value->GetParent(), event );
}
void UNIT_BINDER::evaluate()
{
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
if( !textEntry )
return;
if( textEntry->GetValue().IsEmpty() )
textEntry->ChangeValue( "0" );
if( m_eval.Process( textEntry->GetValue() ) )
textEntry->ChangeValue( m_eval.Result() );
}
wxString valueDescriptionFromLabel( wxStaticText* aLabel ) wxString valueDescriptionFromLabel( wxStaticText* aLabel )
{ {
wxString desc = aLabel->GetLabel(); wxString desc = aLabel->GetLabel();
@ -208,10 +185,13 @@ void UNIT_BINDER::SetValue( int aValue )
void UNIT_BINDER::SetValue( wxString aValue ) void UNIT_BINDER::SetValue( wxString aValue )
{ {
if( dynamic_cast<wxTextEntry*>( m_value ) ) auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
dynamic_cast<wxTextEntry*>( m_value )->SetValue( aValue ); auto staticText = dynamic_cast<wxStaticText*>( m_value );
else if( dynamic_cast<wxStaticText*>( m_value ) )
dynamic_cast<wxStaticText*>( m_value )->SetLabel( aValue ); if( textEntry )
textEntry->SetValue( aValue );
else if( staticText )
staticText->SetLabel( aValue );
if( m_allowEval ) if( m_allowEval )
m_eval.Clear(); m_eval.Clear();
@ -228,10 +208,13 @@ void UNIT_BINDER::ChangeValue( int aValue )
void UNIT_BINDER::ChangeValue( wxString aValue ) void UNIT_BINDER::ChangeValue( wxString aValue )
{ {
if( dynamic_cast<wxTextEntry*>( m_value ) ) auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
dynamic_cast<wxTextEntry*>( m_value )->ChangeValue( aValue ); auto staticText = dynamic_cast<wxStaticText*>( m_value );
else if( dynamic_cast<wxStaticText*>( m_value ) )
dynamic_cast<wxStaticText*>( m_value )->SetLabel( aValue ); if( textEntry )
textEntry->ChangeValue( aValue );
else if( staticText )
staticText->SetLabel( aValue );
if( m_allowEval ) if( m_allowEval )
m_eval.Clear(); m_eval.Clear();
@ -240,23 +223,34 @@ void UNIT_BINDER::ChangeValue( wxString aValue )
} }
int UNIT_BINDER::GetValue() const int UNIT_BINDER::GetValue()
{ {
wxString s; auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
auto staticText = dynamic_cast<wxStaticText*>( m_value );
if( dynamic_cast<wxTextEntry*>( m_value ) ) if( m_needsEval && textEntry )
s = dynamic_cast<wxTextEntry*>( m_value )->GetValue(); {
else if( dynamic_cast<wxStaticText*>( m_value ) ) if( m_eval.Process( textEntry->GetValue() ) )
s = dynamic_cast<wxStaticText*>( m_value )->GetLabel(); textEntry->ChangeValue( m_eval.Result() );
return ValueFromString( m_units, s, m_useMils ); m_needsEval = false;
}
if( textEntry )
return ValueFromString( m_units, textEntry->GetValue(), m_useMils );
else if( staticText )
return ValueFromString( m_units, staticText->GetLabel(), m_useMils );
else
return 0;
} }
bool UNIT_BINDER::IsIndeterminate() const bool UNIT_BINDER::IsIndeterminate() const
{ {
if( dynamic_cast<wxTextEntry*>( m_value ) ) auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
return dynamic_cast<wxTextEntry*>( m_value )->GetValue() == INDETERMINATE;
if( textEntry )
return textEntry->GetValue() == INDETERMINATE;
return false; return false;
} }

View File

@ -89,7 +89,7 @@ public:
* Function GetValue * Function GetValue
* Returns the current value in Internal Units. * Returns the current value in Internal Units.
*/ */
virtual int GetValue() const; virtual int GetValue();
/** /**
* Function IsIndeterminate * Function IsIndeterminate
@ -125,11 +125,8 @@ protected:
void onSetFocus( wxFocusEvent& aEvent ); void onSetFocus( wxFocusEvent& aEvent );
void onKillFocus( wxFocusEvent& aEvent ); void onKillFocus( wxFocusEvent& aEvent );
void onTextEnter( wxCommandEvent& aEvent );
void delayedFocusHandler( wxIdleEvent& aEvent ); void delayedFocusHandler( wxIdleEvent& aEvent );
void evaluate();
///> The bound widgets ///> The bound widgets
wxStaticText* m_label; wxStaticText* m_label;
wxWindow* m_value; wxWindow* m_value;
@ -147,6 +144,7 @@ protected:
///> Evaluator ///> Evaluator
NUMERIC_EVALUATOR m_eval; NUMERIC_EVALUATOR m_eval;
bool m_allowEval; bool m_allowEval;
bool m_needsEval;
}; };
#endif /* __UNIT_BINDER_H_ */ #endif /* __UNIT_BINDER_H_ */