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.

265 lines
7.8 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <scintilla_tricks.h>
  24. #include <widgets/std_bitmap_button.h>
  25. #include <widgets/grid_text_helpers.h>
  26. #include <grid_tricks.h>
  27. #include <dialogs/html_message_box.h>
  28. #include <../sim/simulator_frame.h>
  29. #include <dialog_user_defined_signals.h>
  30. #include <string_utils.h>
  31. DIALOG_USER_DEFINED_SIGNALS::DIALOG_USER_DEFINED_SIGNALS( SIMULATOR_FRAME* aParent,
  32. std::map<int, wxString>* aSignals ) :
  33. DIALOG_USER_DEFINED_SIGNALS_BASE( aParent ),
  34. m_frame( aParent ),
  35. m_signals( aSignals ),
  36. m_helpWindow( nullptr )
  37. {
  38. m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
  39. wxGridCellAttr* attr = new wxGridCellAttr;
  40. attr->SetReadOnly();
  41. m_grid->SetColAttr( 1, attr );
  42. for( const auto& [ id, signal ] : *m_signals )
  43. addGridRow( signal, id );
  44. m_addButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
  45. m_deleteButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
  46. SetupStandardButtons();
  47. Layout();
  48. // Now all widgets have the size fixed, call FinishDialogSettings
  49. finishDialogSettings();
  50. }
  51. DIALOG_USER_DEFINED_SIGNALS::~DIALOG_USER_DEFINED_SIGNALS()
  52. {
  53. // Delete the GRID_TRICKS.
  54. m_grid->PopEventHandler( true );
  55. if( m_helpWindow )
  56. m_helpWindow->Destroy();
  57. }
  58. bool DIALOG_USER_DEFINED_SIGNALS::TransferDataToWindow()
  59. {
  60. if( !wxDialog::TransferDataToWindow() )
  61. return false;
  62. return true;
  63. }
  64. void DIALOG_USER_DEFINED_SIGNALS::addGridRow( const wxString& aText, int aId )
  65. {
  66. int row = m_grid->GetNumberRows();
  67. m_grid->AppendRows();
  68. m_grid->SetCellValue( row, 0, aText );
  69. m_grid->SetCellValue( row, 1, wxString::Format( wxS( "%d" ), aId ) );
  70. wxGridCellAttr* attr = new wxGridCellAttr;
  71. attr->SetEditor( new GRID_CELL_STC_EDITOR( true,
  72. [this]( wxStyledTextEvent& aEvent, SCINTILLA_TRICKS* aScintillaTricks )
  73. {
  74. onScintillaCharAdded( aEvent, aScintillaTricks );
  75. } ) );
  76. m_grid->SetAttr( row, 0, attr );
  77. }
  78. void DIALOG_USER_DEFINED_SIGNALS::onAddSignal( wxCommandEvent& event )
  79. {
  80. if( !m_grid->CommitPendingChanges() )
  81. return;
  82. long newId = 0;
  83. for( int ii = 0; ii < m_grid->GetNumberRows(); ++ii )
  84. {
  85. long usedId;
  86. m_grid->GetCellValue( ii, 1 ).ToLong( &usedId );
  87. if( usedId > newId )
  88. newId = usedId + 1;
  89. }
  90. addGridRow( wxEmptyString, (int) newId );
  91. m_grid->MakeCellVisible( m_grid->GetNumberRows() - 1, 0 );
  92. m_grid->SetGridCursor( m_grid->GetNumberRows() - 1, 0 );
  93. m_grid->EnableCellEditControl( true );
  94. m_grid->ShowCellEditControl();
  95. }
  96. void DIALOG_USER_DEFINED_SIGNALS::onDeleteSignal( wxCommandEvent& event )
  97. {
  98. int curRow = m_grid->GetGridCursorRow();
  99. if( curRow < 0 || m_grid->GetNumberRows() <= curRow )
  100. return;
  101. m_grid->CommitPendingChanges( true /* silent mode; we don't care if it's valid */ );
  102. m_grid->DeleteRows( curRow, 1 );
  103. m_grid->MakeCellVisible( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
  104. m_grid->SetGridCursor( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
  105. }
  106. void DIALOG_USER_DEFINED_SIGNALS::onScintillaCharAdded( wxStyledTextEvent &aEvent,
  107. SCINTILLA_TRICKS* aTricks )
  108. {
  109. wxStyledTextCtrl* textCtrl = aTricks->Scintilla();
  110. wxArrayString tokens;
  111. for( const wxString& signal : m_frame->SimPlotVectors() )
  112. tokens.push_back( signal );
  113. tokens.push_back( wxS( "sqrt(x)" ) );
  114. tokens.push_back( wxS( "sin(x)" ) );
  115. tokens.push_back( wxS( "cos(x)" ) );
  116. tokens.push_back( wxS( "tan(x)" ) );
  117. tokens.push_back( wxS( "sinh(x)" ) );
  118. tokens.push_back( wxS( "cosh(x)" ) );
  119. tokens.push_back( wxS( "tanh(x)" ) );
  120. tokens.push_back( wxS( "asin(x)" ) );
  121. tokens.push_back( wxS( "acos(x)" ) );
  122. tokens.push_back( wxS( "atan(x)" ) );
  123. tokens.push_back( wxS( "asinh(x)" ) );
  124. tokens.push_back( wxS( "acosh(x)" ) );
  125. tokens.push_back( wxS( "atanh(x)" ) );
  126. tokens.push_back( wxS( "arctan(x)" ) );
  127. tokens.push_back( wxS( "exp(x)" ) );
  128. tokens.push_back( wxS( "ln(x)" ) );
  129. tokens.push_back( wxS( "log(x)" ) );
  130. tokens.push_back( wxS( "abs(x)" ) );
  131. tokens.push_back( wxS( "nint(x)" ) );
  132. tokens.push_back( wxS( "int(x)" ) );
  133. tokens.push_back( wxS( "floor(x)" ) );
  134. tokens.push_back( wxS( "ceil(x)" ) );
  135. tokens.push_back( wxS( "pow(x,y)" ) );
  136. tokens.push_back( wxS( "pwr(x,y)" ) );
  137. tokens.push_back( wxS( "min(x,y)" ) );
  138. tokens.push_back( wxS( "max(x,y)" ) );
  139. tokens.push_back( wxS( "sgn(x)" ) );
  140. tokens.push_back( wxS( "ternary_fcn(x,y,z)" ) );
  141. tokens.push_back( wxS( "gauss(nom,rvar,sigma)" ) );
  142. tokens.push_back( wxS( "agauss(nom,avar,sigma)" ) );
  143. tokens.push_back( wxS( "unif(nom,rvar)" ) );
  144. tokens.push_back( wxS( "aunif(nom,avar)" ) );
  145. tokens.push_back( wxS( "limit(nom,avar)" ) );
  146. int text_pos = textCtrl->GetCurrentPos();
  147. int start = textCtrl->WordStartPosition( text_pos, true );
  148. int parenCount = 0;
  149. for( start = text_pos - 1; start > 0; start-- )
  150. {
  151. wxUniChar c = textCtrl->GetCharAt( start );
  152. if( c == '(' )
  153. {
  154. if( parenCount )
  155. {
  156. start += 1;
  157. break;
  158. }
  159. else
  160. {
  161. parenCount++;
  162. }
  163. }
  164. else if( wxIsalpha( c ) && parenCount )
  165. {
  166. break;
  167. }
  168. else if( !wxIsalnum( c ) && c != '/' )
  169. {
  170. start += 1;
  171. break;
  172. }
  173. }
  174. wxString partial = textCtrl->GetRange( start, text_pos );
  175. aTricks->DoAutocomplete( partial, tokens );
  176. textCtrl->SetFocus();
  177. }
  178. bool DIALOG_USER_DEFINED_SIGNALS::TransferDataFromWindow()
  179. {
  180. if( !wxDialog::TransferDataFromWindow() )
  181. return false;
  182. if( !m_grid->CommitPendingChanges() )
  183. return false;
  184. m_signals->clear();
  185. for( int ii = 0; ii < m_grid->GetNumberRows(); ++ii )
  186. {
  187. wxString signal = m_grid->GetCellValue( ii, 0 );
  188. if( !signal.IsEmpty() )
  189. {
  190. long id;
  191. m_grid->GetCellValue( ii, 1 ).ToLong( &id );
  192. (*m_signals)[ (int) id ] = signal;
  193. }
  194. }
  195. return true;
  196. }
  197. void DIALOG_USER_DEFINED_SIGNALS::OnFormattingHelp( wxHyperlinkEvent& aEvent )
  198. {
  199. wxString msg =
  200. #include "../sim/user_defined_signals_help_md.h"
  201. ;
  202. m_helpWindow = new HTML_MESSAGE_BOX( nullptr, _( "Syntax Help" ) );
  203. wxSize sz( 320, 320 );
  204. m_helpWindow->SetMinSize( m_helpWindow->ConvertDialogToPixels( sz ) );
  205. m_helpWindow->SetDialogSizeInDU( sz.x, sz.y );
  206. wxString html_txt;
  207. ConvertMarkdown2Html( wxGetTranslation( msg ), html_txt );
  208. m_helpWindow->AddHTML_Text( html_txt );
  209. m_helpWindow->ShowModeless();
  210. }