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.

257 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 (C) 2022-2023 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. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary );
  81. wxCHECK( textEntry, false );
  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. else if( event.GetEventType() == wxEVT_KILL_FOCUS && allowEval() )
  92. {
  93. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wnd_primary );
  94. wxCHECK( textEntry, false );
  95. wxString strValue = textEntry->GetValue();
  96. if( !strValue.IsEmpty() && m_eval.Process( strValue ) )
  97. {
  98. double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
  99. if( std::isnan( value ) || SIM_VALUE::Equal( value, strValue.ToStdString() ) )
  100. {
  101. // Don't mess up user formatting if eval'ing didn't actually change the value.
  102. }
  103. else
  104. {
  105. SetValueInEvent( m_eval.Result() );
  106. }
  107. }
  108. m_needsEval = false;
  109. return true;
  110. }
  111. else if( event.GetEventType() == wxEVT_KEY_DOWN )
  112. {
  113. wxKeyEvent& keyEvent = dynamic_cast<wxKeyEvent&>( event );
  114. wxPropertyGrid* propGrid = dynamic_cast<wxPropertyGrid*>( wnd_primary->GetParent() );
  115. if( propGrid )
  116. {
  117. if( keyEvent.GetKeyCode() == WXK_TAB )
  118. {
  119. propGrid->CommitChangesFromEditor();
  120. keyEvent.m_keyCode = keyEvent.ShiftDown() ? WXK_UP : WXK_DOWN;
  121. keyEvent.m_shiftDown = false;
  122. }
  123. #ifdef __WXMAC__
  124. // This shouldn't be required, as wxPGTextCtrlEditor::OnTextCtrlEvent() should be
  125. // setting the value to modified. But it doesn't on Mac (or the modified flag is
  126. // cleared at some point later), and even if it is set, the changes don't get
  127. // committed.
  128. // (We used to have code in DIALOG_SIM_MODEL to commit things on *some* actions, but
  129. // it wasn't complete and this appears to have at least a better hit rate.)
  130. propGrid->CallAfter(
  131. [propGrid]()
  132. {
  133. propGrid->EditorsValueWasModified();
  134. propGrid->CommitChangesFromEditor();
  135. } );
  136. #endif
  137. }
  138. }
  139. return false;
  140. }
  141. wxValidator* SIM_STRING_PROPERTY::DoGetValidator() const
  142. {
  143. return new SIM_VALIDATOR();
  144. }
  145. bool SIM_STRING_PROPERTY::allowEval() const
  146. {
  147. return m_valueType == SIM_VALUE::TYPE_INT
  148. || m_valueType == SIM_VALUE::TYPE_FLOAT;
  149. }
  150. bool SIM_STRING_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aText,
  151. int aArgFlags ) const
  152. {
  153. if( m_disabled )
  154. return false;
  155. wxString text = aText;
  156. if( allowEval() && m_needsEval && m_eval.Process( aText ) )
  157. {
  158. if( !aText.IsEmpty() )
  159. {
  160. double value = SIM_VALUE::ToDouble( m_eval.Result().ToStdString() );
  161. if( std::isnan( value ) || SIM_VALUE::Equal( value, aText.ToStdString() ) )
  162. {
  163. // Don't mess up user formatting if eval'ing didn't actually change the value.
  164. }
  165. else
  166. {
  167. text = SIM_VALUE::Normalize( value );
  168. }
  169. }
  170. }
  171. m_model.SetParamValue( m_paramIndex, text.ToStdString() );
  172. aVariant = text.ToStdString();
  173. return true;
  174. }
  175. static wxArrayString convertStringsToWx( const std::vector<std::string>& aStrings )
  176. {
  177. wxArrayString result;
  178. for( const std::string& string : aStrings )
  179. result.Add( string );
  180. return result;
  181. }
  182. SIM_ENUM_PROPERTY::SIM_ENUM_PROPERTY( const wxString& aLabel, const wxString& aName,
  183. SIM_MODEL& aModel, int aParamIndex ) :
  184. wxEnumProperty( aLabel, aName,
  185. convertStringsToWx( aModel.GetParam( aParamIndex ).info.enumValues ) ),
  186. SIM_PROPERTY( aModel, aParamIndex )
  187. {
  188. for( int ii = 0; ii < (int) GetParam().info.enumValues.size(); ++ii )
  189. {
  190. if( GetParam().info.enumValues[ii] == GetParam().value )
  191. {
  192. SetValue( ii );
  193. return;
  194. }
  195. }
  196. SetValue( -1 );
  197. }
  198. bool SIM_ENUM_PROPERTY::IntToValue( wxVariant& aVariant, int aNumber, int aArgFlags ) const
  199. {
  200. if( m_disabled )
  201. return false;
  202. m_model.SetParamValue( m_paramIndex, GetParam().info.enumValues.at( aNumber ) );
  203. return wxEnumProperty::IntToValue( aVariant, aNumber, aArgFlags );
  204. }