You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
7.5 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2022 Mikolaj Wielgus
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * https://www.gnu.org/licenses/gpl-3.0.html
  20. * or you may search the http://www.gnu.org website for the version 3 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <wx/combo.h>
  25. // Include simulator headers after wxWidgets headers to avoid conflicts with Windows headers
  26. // (especially on msys2 + wxWidgets 3.0.x)
  27. #include <sim/sim_property.h>
  28. #include <sim/sim_value.h>
  29. #include <ki_exception.h>
  30. /**
  31. *
  32. * wxPropertyGrid property specializations for simulator.
  33. *
  34. */
  35. SIM_PROPERTY::SIM_PROPERTY( SIM_MODEL& aModel, int aParamIndex ) :
  36. m_model( aModel ),
  37. m_paramIndex( aParamIndex ),
  38. m_needsEval( false ),
  39. m_eval( EDA_UNITS::UNSCALED ),
  40. m_disabled( false )
  41. {
  42. }
  43. void SIM_PROPERTY::Disable()
  44. {
  45. m_disabled = true;
  46. }
  47. SIM_BOOL_PROPERTY::SIM_BOOL_PROPERTY( const wxString& aLabel, const wxString& aName,
  48. SIM_MODEL& aModel, int aParamIndex ) :
  49. wxBoolProperty( aLabel, aName ),
  50. SIM_PROPERTY( aModel, aParamIndex )
  51. {
  52. std::string value = m_model.GetParam( m_paramIndex ).value;
  53. SetValue( value == "1" );
  54. }
  55. wxValidator* SIM_BOOL_PROPERTY::DoGetValidator() const
  56. {
  57. return new SIM_VALIDATOR();
  58. }
  59. void SIM_BOOL_PROPERTY::OnSetValue()
  60. {
  61. wxPGProperty::OnSetValue();
  62. if( m_disabled )
  63. return;
  64. m_model.SetParamValue( m_paramIndex, m_value.GetBool() ? "1" : "0" );
  65. }
  66. SIM_STRING_PROPERTY::SIM_STRING_PROPERTY( const wxString& aLabel, const wxString& aName,
  67. SIM_MODEL& aModel, int aParamIndex,
  68. SIM_VALUE::TYPE aValueType,
  69. SIM_VALUE_GRAMMAR::NOTATION aNotation ) :
  70. wxStringProperty( aLabel, aName ),
  71. SIM_PROPERTY( aModel, aParamIndex ),
  72. m_valueType( aValueType )
  73. {
  74. SetValueFromString( GetParam().value );
  75. }
  76. bool SIM_STRING_PROPERTY::OnEvent( wxPropertyGrid* propgrid, wxWindow* wnd_primary, wxEvent& event )
  77. {
  78. if( event.GetEventType() == wxEVT_SET_FOCUS && allowEval() )
  79. {
  80. if( wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary ) )
  81. {
  82. wxString oldStr = m_eval.OriginalText();
  83. if( oldStr.length() && oldStr != textEntry->GetValue() )
  84. {
  85. SetValueInEvent( oldStr );
  86. textEntry->SetValue( oldStr );
  87. }
  88. m_needsEval = true;
  89. return true;
  90. }
  91. }
  92. else if( event.GetEventType() == wxEVT_KILL_FOCUS && allowEval() )
  93. {
  94. if( wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary ) )
  95. {
  96. wxString strValue = textEntry->GetValue();
  97. if( !strValue.IsEmpty() && m_eval.Process( strValue ) )
  98. {
  99. double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
  100. if( std::isnan( value ) || SIM_VALUE::Equal( value, strValue.ToStdString() ) )
  101. {
  102. // Don't mess up user formatting if eval'ing didn't actually change the value.
  103. }
  104. else
  105. {
  106. SetValueInEvent( m_eval.Result() );
  107. }
  108. }
  109. m_needsEval = false;
  110. return true;
  111. }
  112. }
  113. else if( event.GetEventType() == wxEVT_KEY_DOWN )
  114. {
  115. wxKeyEvent& keyEvent = dynamic_cast<wxKeyEvent&>( event );
  116. if( wxPropertyGrid* propGrid = dynamic_cast<wxPropertyGrid*>( wnd_primary->GetParent() ) )
  117. {
  118. if( keyEvent.GetKeyCode() == WXK_TAB )
  119. {
  120. propGrid->CommitChangesFromEditor();
  121. keyEvent.m_keyCode = keyEvent.ShiftDown() ? WXK_UP : WXK_DOWN;
  122. keyEvent.m_shiftDown = false;
  123. }
  124. #ifdef __WXMAC__
  125. // This shouldn't be required, as wxPGTextCtrlEditor::OnTextCtrlEvent() should be
  126. // setting the value to modified. But it doesn't on Mac (or the modified flag is
  127. // cleared at some point later), and even if it is set, the changes don't get
  128. // committed.
  129. // (We used to have code in DIALOG_SIM_MODEL to commit things on *some* actions, but
  130. // it wasn't complete and this appears to have at least a better hit rate.)
  131. propGrid->CallAfter(
  132. [propGrid]()
  133. {
  134. propGrid->EditorsValueWasModified();
  135. propGrid->CommitChangesFromEditor();
  136. } );
  137. #endif
  138. }
  139. }
  140. return false;
  141. }
  142. wxValidator* SIM_STRING_PROPERTY::DoGetValidator() const
  143. {
  144. return new SIM_VALIDATOR();
  145. }
  146. bool SIM_STRING_PROPERTY::allowEval() const
  147. {
  148. return m_valueType == SIM_VALUE::TYPE_INT
  149. || m_valueType == SIM_VALUE::TYPE_FLOAT;
  150. }
  151. bool SIM_STRING_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aText,
  152. int aArgFlags ) const
  153. {
  154. if( m_disabled )
  155. return false;
  156. wxString text = aText;
  157. if( allowEval() && m_needsEval && m_eval.Process( aText ) )
  158. {
  159. if( !aText.IsEmpty() )
  160. {
  161. double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
  162. if( std::isnan( value ) || SIM_VALUE::Equal( value, aText.ToStdString() ) )
  163. {
  164. // Don't mess up user formatting if eval'ing didn't actually change the value.
  165. }
  166. else
  167. {
  168. text = SIM_VALUE::Normalize( value );
  169. }
  170. }
  171. }
  172. m_model.SetParamValue( m_paramIndex, text.ToStdString() );
  173. aVariant = text.ToStdString();
  174. return true;
  175. }
  176. SIM_ENUM_PROPERTY::SIM_ENUM_PROPERTY( const wxString& aLabel, const wxString& aName,
  177. SIM_MODEL& aModel, int aParamIndex,
  178. const wxArrayString& aValues ) :
  179. wxEnumProperty( aLabel, aName, aValues ),
  180. SIM_PROPERTY( aModel, aParamIndex )
  181. {
  182. for( int ii = 0; ii < (int) GetParam().info.enumValues.size(); ++ii )
  183. {
  184. if( GetParam().info.enumValues[ii] == GetParam().value )
  185. {
  186. SetValue( ii );
  187. return;
  188. }
  189. }
  190. SetValue( -1 );
  191. }
  192. #if wxCHECK_VERSION( 3, 3, 0 )
  193. bool SIM_ENUM_PROPERTY::IntToValue( wxVariant& aVariant, int aNumber,
  194. wxPGPropValFormatFlags aArgFlags ) const
  195. #else
  196. bool SIM_ENUM_PROPERTY::IntToValue( wxVariant& aVariant, int aNumber, int aArgFlags ) const
  197. #endif
  198. {
  199. if( m_disabled )
  200. return false;
  201. m_model.SetParamValue( m_paramIndex, m_choices.GetLabel( aNumber ).ToStdString() );
  202. return wxEnumProperty::IntToValue( aVariant, aNumber, aArgFlags );
  203. }