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.

1086 lines
32 KiB

2 years ago
2 years ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
2 years ago
2 years ago
3 years ago
2 years ago
2 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The 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 <embedded_files.h>
  24. #include <kiway.h>
  25. #include <kiway_player.h>
  26. #include <dialog_shim.h>
  27. #include <fields_grid_table.h>
  28. #include <sch_base_frame.h>
  29. #include <sch_field.h>
  30. #include <sch_label.h>
  31. #include <sch_validators.h>
  32. #include <validators.h>
  33. #include <sch_edit_frame.h>
  34. #include <symbol_library.h>
  35. #include <schematic.h>
  36. #include <template_fieldnames.h>
  37. #include <widgets/grid_text_button_helpers.h>
  38. #include <wildcards_and_files_ext.h>
  39. #include <project/project_file.h>
  40. #include <project/net_settings.h>
  41. #include "eda_doc.h"
  42. #include "widgets/grid_color_swatch_helpers.h"
  43. #include "font/fontconfig.h"
  44. #include "font/kicad_font_name.h"
  45. #include "widgets/grid_text_helpers.h"
  46. #include <wx/settings.h>
  47. #include <string_utils.h>
  48. #include <widgets/grid_combobox.h>
  49. #include <pgm_base.h>
  50. #include <project_sch.h>
  51. enum
  52. {
  53. MYID_SELECT_FOOTPRINT = GRIDTRICKS_FIRST_CLIENT_ID,
  54. MYID_SHOW_DATASHEET
  55. };
  56. #define DEFAULT_FONT_NAME _( "Default Font" )
  57. static wxString netList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH& aSheetPath )
  58. {
  59. wxCHECK( aSymbol && aSymbol->GetLibSymbolRef(), wxEmptyString );
  60. /*
  61. * Symbol netlist format:
  62. * pinNumber pinName <tab> pinNumber pinName...
  63. * fpFilter fpFilter...
  64. */
  65. wxString netlist;
  66. // We need the list of pins of the lib symbol, not just the pins of the current
  67. // sch symbol, that can be just an unit of a multi-unit symbol, to be able to
  68. // select/filter right footprints
  69. wxArrayString pins;
  70. const std::unique_ptr< LIB_SYMBOL >& lib_symbol = aSymbol->GetLibSymbolRef();
  71. if( lib_symbol )
  72. {
  73. for( SCH_PIN* pin : lib_symbol->GetPins( 0 /* all units */, 1 /* single bodyStyle */ ) )
  74. pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() );
  75. }
  76. if( !pins.IsEmpty() )
  77. netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE );
  78. netlist << wxS( "\r" );
  79. wxArrayString fpFilters = aSymbol->GetLibSymbolRef()->GetFPFilters();
  80. if( !fpFilters.IsEmpty() )
  81. netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
  82. netlist << wxS( "\r" );
  83. return netlist;
  84. }
  85. static wxString netList( LIB_SYMBOL* aSymbol )
  86. {
  87. /*
  88. * Symbol netlist format:
  89. * pinNumber pinName <tab> pinNumber pinName...
  90. * fpFilter fpFilter...
  91. */
  92. wxString netlist;
  93. wxArrayString pins;
  94. for( SCH_PIN* pin : aSymbol->GetPins( 0 /* all units */, 1 /* single bodyStyle */ ) )
  95. pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() );
  96. if( !pins.IsEmpty() )
  97. netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE );
  98. netlist << wxS( "\r" );
  99. wxArrayString fpFilters = aSymbol->GetFPFilters();
  100. if( !fpFilters.IsEmpty() )
  101. netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
  102. netlist << wxS( "\r" );
  103. return netlist;
  104. }
  105. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame, WX_GRID* aGrid,
  106. LIB_SYMBOL* aSymbol ) :
  107. m_frame( aFrame ),
  108. m_dialog( aDialog ),
  109. m_parentType( SCH_SYMBOL_T ),
  110. m_mandatoryFieldCount( MANDATORY_FIELDS ),
  111. m_part( aSymbol ),
  112. m_symbolNetlist( netList( aSymbol ) ),
  113. m_fieldNameValidator( FIELD_NAME ),
  114. m_referenceValidator( REFERENCE_FIELD ),
  115. m_valueValidator( VALUE_FIELD ),
  116. m_urlValidator( FIELD_VALUE ),
  117. m_nonUrlValidator( FIELD_VALUE ),
  118. m_filepathValidator( SHEETFILENAME )
  119. {
  120. initGrid( aGrid );
  121. }
  122. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid,
  123. SCH_SYMBOL* aSymbol ) :
  124. m_frame( aFrame ),
  125. m_dialog( aDialog ),
  126. m_parentType( SCH_SYMBOL_T ),
  127. m_mandatoryFieldCount( MANDATORY_FIELDS ),
  128. m_part( aSymbol->GetLibSymbolRef().get() ),
  129. m_symbolNetlist( netList( aSymbol, aFrame->GetCurrentSheet() ) ),
  130. m_fieldNameValidator( FIELD_NAME ),
  131. m_referenceValidator( REFERENCE_FIELD ),
  132. m_valueValidator( VALUE_FIELD ),
  133. m_urlValidator( FIELD_VALUE ),
  134. m_nonUrlValidator( FIELD_VALUE ),
  135. m_filepathValidator( SHEETFILENAME )
  136. {
  137. initGrid( aGrid );
  138. }
  139. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid,
  140. SCH_SHEET* aSheet ) :
  141. m_frame( aFrame ),
  142. m_dialog( aDialog ),
  143. m_parentType( SCH_SHEET_T ),
  144. m_mandatoryFieldCount( SHEET_MANDATORY_FIELDS ),
  145. m_part( nullptr ),
  146. m_fieldNameValidator( FIELD_NAME ),
  147. m_referenceValidator( SHEETNAME_V ),
  148. m_valueValidator( VALUE_FIELD ),
  149. m_urlValidator( FIELD_VALUE ),
  150. m_nonUrlValidator( FIELD_VALUE ),
  151. m_filepathValidator( SHEETFILENAME_V )
  152. {
  153. initGrid( aGrid );
  154. }
  155. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid,
  156. SCH_LABEL_BASE* aLabel ) :
  157. m_frame( aFrame ),
  158. m_dialog( aDialog ),
  159. m_parentType( SCH_LABEL_LOCATE_ANY_T ),
  160. m_mandatoryFieldCount( aLabel->GetMandatoryFieldCount() ),
  161. m_part( nullptr ),
  162. m_fieldNameValidator( FIELD_NAME ),
  163. m_referenceValidator( 0 ),
  164. m_valueValidator( 0 ),
  165. m_urlValidator( FIELD_VALUE ),
  166. m_nonUrlValidator( FIELD_VALUE ),
  167. m_filepathValidator( 0 )
  168. {
  169. initGrid( aGrid );
  170. }
  171. void FIELDS_GRID_TABLE::initGrid( WX_GRID* aGrid )
  172. {
  173. // Build the various grid cell attributes.
  174. // NOTE: validators and cellAttrs are member variables to get the destruction order
  175. // right. wxGrid is VERY cranky about this.
  176. m_readOnlyAttr = new wxGridCellAttr;
  177. m_readOnlyAttr->SetReadOnly( true );
  178. m_fieldNameAttr = new wxGridCellAttr;
  179. GRID_CELL_TEXT_EDITOR* nameEditor = new GRID_CELL_TEXT_EDITOR();
  180. nameEditor->SetValidator( m_fieldNameValidator );
  181. m_fieldNameAttr->SetEditor( nameEditor );
  182. m_referenceAttr = new wxGridCellAttr;
  183. GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR();
  184. referenceEditor->SetValidator( m_referenceValidator );
  185. m_referenceAttr->SetEditor( referenceEditor );
  186. m_valueAttr = new wxGridCellAttr;
  187. if( m_parentType == LIB_SYMBOL_T )
  188. {
  189. GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
  190. valueEditor->SetValidator( m_valueValidator );
  191. m_valueAttr->SetEditor( valueEditor );
  192. }
  193. else
  194. {
  195. GRID_CELL_STC_EDITOR* valueEditor = new GRID_CELL_STC_EDITOR( true,
  196. [this]( wxStyledTextEvent& aEvent, SCINTILLA_TRICKS* aScintillaTricks )
  197. {
  198. SCH_FIELD& valueField = static_cast<SCH_FIELD&>( this->at( VALUE_FIELD ) );
  199. valueField.OnScintillaCharAdded( aScintillaTricks, aEvent );
  200. } );
  201. m_valueAttr->SetEditor( valueEditor );
  202. }
  203. m_footprintAttr = new wxGridCellAttr;
  204. GRID_CELL_FPID_EDITOR* fpIdEditor = new GRID_CELL_FPID_EDITOR( m_dialog, m_symbolNetlist );
  205. fpIdEditor->SetValidator( m_nonUrlValidator );
  206. m_footprintAttr->SetEditor( fpIdEditor );
  207. EMBEDDED_FILES* files = nullptr;
  208. if( m_frame->GetFrameType() == FRAME_SCH )
  209. {
  210. files = m_frame->GetScreen()->Schematic();
  211. }
  212. else if( m_frame->GetFrameType() == FRAME_SCH_SYMBOL_EDITOR
  213. || m_frame->GetFrameType() == FRAME_SCH_VIEWER )
  214. {
  215. files = m_part;
  216. }
  217. m_urlAttr = new wxGridCellAttr;
  218. SEARCH_STACK* prjSearchStack = PROJECT_SCH::SchSearchS( &m_frame->Prj() );
  219. GRID_CELL_URL_EDITOR* urlEditor = new GRID_CELL_URL_EDITOR( m_dialog, prjSearchStack, files );
  220. urlEditor->SetValidator( m_urlValidator );
  221. m_urlAttr->SetEditor( urlEditor );
  222. m_nonUrlAttr = new wxGridCellAttr;
  223. GRID_CELL_TEXT_EDITOR* nonUrlEditor = new GRID_CELL_TEXT_EDITOR();
  224. nonUrlEditor->SetValidator( m_nonUrlValidator );
  225. m_nonUrlAttr->SetEditor( nonUrlEditor );
  226. m_curdir = m_frame->Prj().GetProjectPath();
  227. m_filepathAttr = new wxGridCellAttr;
  228. // Create a wild card using wxFileDialog syntax.
  229. wxString wildCard( _( "Schematic Files" ) );
  230. std::vector<std::string> exts;
  231. exts.push_back( FILEEXT::KiCadSchematicFileExtension );
  232. wildCard += AddFileExtListToFilter( exts );
  233. auto filepathEditor = new GRID_CELL_PATH_EDITOR( m_dialog, aGrid, &m_curdir, wildCard );
  234. filepathEditor->SetValidator( m_filepathValidator );
  235. m_filepathAttr->SetEditor( filepathEditor );
  236. m_boolAttr = new wxGridCellAttr;
  237. m_boolAttr->SetRenderer( new wxGridCellBoolRenderer() );
  238. m_boolAttr->SetEditor( new wxGridCellBoolEditor() );
  239. m_boolAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  240. wxArrayString vAlignNames;
  241. vAlignNames.Add( _( "Top" ) );
  242. vAlignNames.Add( _( "Center" ) );
  243. vAlignNames.Add( _( "Bottom" ) );
  244. m_vAlignAttr = new wxGridCellAttr;
  245. m_vAlignAttr->SetEditor( new wxGridCellChoiceEditor( vAlignNames ) );
  246. m_vAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  247. wxArrayString hAlignNames;
  248. hAlignNames.Add( _( "Left" ) );
  249. hAlignNames.Add(_( "Center" ) );
  250. hAlignNames.Add(_( "Right" ) );
  251. m_hAlignAttr = new wxGridCellAttr;
  252. m_hAlignAttr->SetEditor( new wxGridCellChoiceEditor( hAlignNames ) );
  253. m_hAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  254. wxArrayString orientationNames;
  255. orientationNames.Add( _( "Horizontal" ) );
  256. orientationNames.Add(_( "Vertical" ) );
  257. m_orientationAttr = new wxGridCellAttr;
  258. m_orientationAttr->SetEditor( new wxGridCellChoiceEditor( orientationNames ) );
  259. m_orientationAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  260. SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
  261. wxArrayString existingNetclasses;
  262. wxArrayString fonts;
  263. std::vector<std::string> fontNames;
  264. if( editFrame )
  265. {
  266. // Load the combobox with existing existingNetclassNames
  267. PROJECT_FILE& projectFile = editFrame->Prj().GetProjectFile();
  268. const std::shared_ptr<NET_SETTINGS>& settings = projectFile.NetSettings();
  269. existingNetclasses.push_back( settings->GetDefaultNetclass()->GetName() );
  270. for( const auto& [name, netclass] : settings->GetNetclasses() )
  271. existingNetclasses.push_back( name );
  272. // We don't need to re-cache the embedded fonts when looking at symbols in the schematic
  273. // editor because the fonts are all available in the schematic.
  274. const std::vector<wxString>* fontFiles = nullptr;
  275. if( m_frame->GetScreen() && m_frame->GetScreen()->Schematic() )
  276. fontFiles = m_frame->GetScreen()->Schematic()->GetEmbeddedFiles()->GetFontFiles();
  277. Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ),
  278. fontFiles, false );
  279. }
  280. else
  281. {
  282. const std::vector<wxString>* fontFiles = m_part->GetEmbeddedFiles()->UpdateFontFiles();
  283. // If there are font files embedded, we want to re-cache our fonts for each symbol that
  284. // we are looking at in the symbol editor.
  285. Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ),
  286. fontFiles, !fontFiles->empty() );
  287. }
  288. m_netclassAttr = new wxGridCellAttr;
  289. m_netclassAttr->SetEditor( new GRID_CELL_COMBOBOX( existingNetclasses ) );
  290. for( const std::string& name : fontNames )
  291. fonts.Add( wxString( name ) );
  292. fonts.Sort();
  293. fonts.Insert( KICAD_FONT_NAME, 0 );
  294. fonts.Insert( DEFAULT_FONT_NAME, 0 );
  295. m_fontAttr = new wxGridCellAttr;
  296. m_fontAttr->SetEditor( new GRID_CELL_COMBOBOX( fonts ) );
  297. m_colorAttr = new wxGridCellAttr;
  298. m_colorAttr->SetRenderer( new GRID_CELL_COLOR_RENDERER( m_dialog ) );
  299. m_colorAttr->SetEditor( new GRID_CELL_COLOR_SELECTOR( m_dialog, aGrid ) );
  300. m_eval = std::make_unique<NUMERIC_EVALUATOR>( m_frame->GetUserUnits() );
  301. m_frame->Bind( EDA_EVT_UNITS_CHANGED, &FIELDS_GRID_TABLE::onUnitsChanged, this );
  302. }
  303. FIELDS_GRID_TABLE::~FIELDS_GRID_TABLE()
  304. {
  305. m_readOnlyAttr->DecRef();
  306. m_fieldNameAttr->DecRef();
  307. m_boolAttr->DecRef();
  308. m_referenceAttr->DecRef();
  309. m_valueAttr->DecRef();
  310. m_footprintAttr->DecRef();
  311. m_urlAttr->DecRef();
  312. m_nonUrlAttr->DecRef();
  313. m_filepathAttr->DecRef();
  314. m_vAlignAttr->DecRef();
  315. m_hAlignAttr->DecRef();
  316. m_orientationAttr->DecRef();
  317. m_netclassAttr->DecRef();
  318. m_fontAttr->DecRef();
  319. m_colorAttr->DecRef();
  320. m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &FIELDS_GRID_TABLE::onUnitsChanged, this );
  321. }
  322. void FIELDS_GRID_TABLE::onUnitsChanged( wxCommandEvent& aEvent )
  323. {
  324. if( GetView() )
  325. GetView()->ForceRefresh();
  326. aEvent.Skip();
  327. }
  328. int FIELDS_GRID_TABLE::getColumnCount() const
  329. {
  330. if( m_frame->GetFrameType() == FRAME_SCH
  331. || m_frame->GetFrameType() == FRAME_SCH_VIEWER )
  332. {
  333. return FDC_SCH_EDIT_COUNT;
  334. }
  335. else
  336. {
  337. return FDC_SYMBOL_EDITOR_COUNT;
  338. }
  339. }
  340. int FIELDS_GRID_TABLE::getVisibleRowCount() const
  341. {
  342. if( m_frame->GetFrameType() == FRAME_SCH
  343. || m_frame->GetFrameType() == FRAME_SCH_VIEWER )
  344. {
  345. int visibleRows = 0;
  346. for( const SCH_FIELD& field : *this )
  347. {
  348. if( !field.IsPrivate() )
  349. visibleRows++;
  350. }
  351. return visibleRows;
  352. }
  353. return (int) this->size();
  354. }
  355. SCH_FIELD& FIELDS_GRID_TABLE::getField( int aRow )
  356. {
  357. if( m_frame->GetFrameType() == FRAME_SCH
  358. || m_frame->GetFrameType() == FRAME_SCH_VIEWER )
  359. {
  360. int visibleRow = 0;
  361. for( SCH_FIELD& field : *this )
  362. {
  363. if( field.IsPrivate() )
  364. continue;
  365. if( visibleRow == aRow )
  366. return field;
  367. ++visibleRow;
  368. }
  369. wxFAIL_MSG( wxT( "Row index off end of visible row count" ) );
  370. }
  371. return this->at( aRow );
  372. }
  373. wxString FIELDS_GRID_TABLE::GetColLabelValue( int aCol )
  374. {
  375. switch( aCol )
  376. {
  377. case FDC_NAME: return _( "Name" );
  378. case FDC_VALUE: return _( "Value" );
  379. case FDC_SHOWN: return _( "Show" );
  380. case FDC_SHOW_NAME: return _( "Show Name" );
  381. case FDC_H_ALIGN: return _( "H Align" );
  382. case FDC_V_ALIGN: return _( "V Align" );
  383. case FDC_ITALIC: return _( "Italic" );
  384. case FDC_BOLD: return _( "Bold" );
  385. case FDC_TEXT_SIZE: return _( "Text Size" );
  386. case FDC_ORIENTATION: return _( "Orientation" );
  387. case FDC_POSX: return _( "X Position" );
  388. case FDC_POSY: return _( "Y Position" );
  389. case FDC_FONT: return _( "Font" );
  390. case FDC_COLOR: return _( "Color" );
  391. case FDC_ALLOW_AUTOPLACE: return _( "Allow Autoplacement" );
  392. case FDC_PRIVATE: return _( "Private" );
  393. default: wxFAIL; return wxEmptyString;
  394. }
  395. }
  396. bool FIELDS_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
  397. {
  398. switch( aCol )
  399. {
  400. case FDC_NAME:
  401. case FDC_VALUE:
  402. case FDC_H_ALIGN:
  403. case FDC_V_ALIGN:
  404. case FDC_TEXT_SIZE:
  405. case FDC_ORIENTATION:
  406. case FDC_POSX:
  407. case FDC_POSY:
  408. case FDC_FONT:
  409. case FDC_COLOR:
  410. return aTypeName == wxGRID_VALUE_STRING;
  411. case FDC_SHOWN:
  412. case FDC_SHOW_NAME:
  413. case FDC_ITALIC:
  414. case FDC_BOLD:
  415. case FDC_ALLOW_AUTOPLACE:
  416. case FDC_PRIVATE:
  417. return aTypeName == wxGRID_VALUE_BOOL;
  418. default:
  419. wxFAIL;
  420. return false;
  421. }
  422. }
  423. bool FIELDS_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
  424. {
  425. return CanGetValueAs( aRow, aCol, aTypeName );
  426. }
  427. wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
  428. {
  429. wxGridCellAttr* tmp;
  430. switch( aCol )
  431. {
  432. case FDC_NAME:
  433. if( aRow < m_mandatoryFieldCount )
  434. {
  435. tmp = m_fieldNameAttr->Clone();
  436. tmp->SetReadOnly( true );
  437. return enhanceAttr( tmp, aRow, aCol, aKind );
  438. }
  439. else
  440. {
  441. m_fieldNameAttr->IncRef();
  442. return enhanceAttr( m_fieldNameAttr, aRow, aCol, aKind );
  443. }
  444. case FDC_VALUE:
  445. if( m_parentType == SCH_SYMBOL_T && aRow == REFERENCE_FIELD )
  446. {
  447. m_referenceAttr->IncRef();
  448. return enhanceAttr( m_referenceAttr, aRow, aCol, aKind );
  449. }
  450. else if( m_parentType == SCH_SYMBOL_T && aRow == VALUE_FIELD )
  451. {
  452. m_valueAttr->IncRef();
  453. return enhanceAttr( m_valueAttr, aRow, aCol, aKind );
  454. }
  455. else if( m_parentType == SCH_SYMBOL_T && aRow == FOOTPRINT_FIELD )
  456. {
  457. // Power symbols have do not appear in the board, so don't allow
  458. // a footprint (m_part can be nullptr when loading a old schematic
  459. // (for instance Kicad 4) with libraries missing)
  460. if( m_part && m_part->IsPower() )
  461. {
  462. m_readOnlyAttr->IncRef();
  463. return enhanceAttr( m_readOnlyAttr, aRow, aCol, aKind );
  464. }
  465. else
  466. {
  467. m_footprintAttr->IncRef();
  468. return enhanceAttr( m_footprintAttr, aRow, aCol, aKind );
  469. }
  470. }
  471. else if( m_parentType == SCH_SYMBOL_T && aRow == DATASHEET_FIELD )
  472. {
  473. m_urlAttr->IncRef();
  474. return enhanceAttr( m_urlAttr, aRow, aCol, aKind );
  475. }
  476. else if( m_parentType == SCH_SHEET_T && aRow == SHEETNAME )
  477. {
  478. m_referenceAttr->IncRef();
  479. return enhanceAttr( m_referenceAttr, aRow, aCol, aKind );
  480. }
  481. else if( m_parentType == SCH_SHEET_T && aRow == SHEETFILENAME )
  482. {
  483. m_filepathAttr->IncRef();
  484. return enhanceAttr( m_filepathAttr, aRow, aCol, aKind );
  485. }
  486. else if( ( m_parentType == SCH_LABEL_LOCATE_ANY_T )
  487. && this->at( (size_t) aRow ).GetCanonicalName() == wxT( "Netclass" ) )
  488. {
  489. m_netclassAttr->IncRef();
  490. return enhanceAttr( m_netclassAttr, aRow, aCol, aKind );
  491. }
  492. else
  493. {
  494. wxString fn = GetValue( aRow, FDC_NAME );
  495. SCHEMATIC_SETTINGS* settings = m_frame->Prj().GetProjectFile().m_SchematicSettings;
  496. const TEMPLATE_FIELDNAME* templateFn =
  497. settings ? settings->m_TemplateFieldNames.GetFieldName( fn ) : nullptr;
  498. if( templateFn && templateFn->m_URL )
  499. {
  500. m_urlAttr->IncRef();
  501. return enhanceAttr( m_urlAttr, aRow, aCol, aKind );
  502. }
  503. else
  504. {
  505. m_nonUrlAttr->IncRef();
  506. return enhanceAttr( m_nonUrlAttr, aRow, aCol, aKind );
  507. }
  508. }
  509. case FDC_TEXT_SIZE:
  510. case FDC_POSX:
  511. case FDC_POSY:
  512. return enhanceAttr( nullptr, aRow, aCol, aKind );
  513. case FDC_H_ALIGN:
  514. m_hAlignAttr->IncRef();
  515. return enhanceAttr( m_hAlignAttr, aRow, aCol, aKind );
  516. case FDC_V_ALIGN:
  517. m_vAlignAttr->IncRef();
  518. return enhanceAttr( m_vAlignAttr, aRow, aCol, aKind );
  519. case FDC_ORIENTATION:
  520. m_orientationAttr->IncRef();
  521. return enhanceAttr( m_orientationAttr, aRow, aCol, aKind );
  522. case FDC_SHOWN:
  523. case FDC_SHOW_NAME:
  524. case FDC_ITALIC:
  525. case FDC_BOLD:
  526. case FDC_ALLOW_AUTOPLACE:
  527. case FDC_PRIVATE:
  528. m_boolAttr->IncRef();
  529. return enhanceAttr( m_boolAttr, aRow, aCol, aKind );
  530. case FDC_FONT:
  531. m_fontAttr->IncRef();
  532. return enhanceAttr( m_fontAttr, aRow, aCol, aKind );
  533. case FDC_COLOR:
  534. m_colorAttr->IncRef();
  535. return enhanceAttr( m_colorAttr, aRow, aCol, aKind );
  536. default:
  537. wxFAIL;
  538. return enhanceAttr( nullptr, aRow, aCol, aKind );
  539. }
  540. }
  541. wxString FIELDS_GRID_TABLE::GetValue( int aRow, int aCol )
  542. {
  543. wxCHECK( aRow < GetNumberRows(), wxEmptyString );
  544. wxGrid* grid = GetView();
  545. const SCH_FIELD& field = getField( aRow );
  546. if( grid->GetGridCursorRow() == aRow && grid->GetGridCursorCol() == aCol
  547. && grid->IsCellEditControlShown() )
  548. {
  549. auto it = m_evalOriginal.find( { aRow, aCol } );
  550. if( it != m_evalOriginal.end() )
  551. return it->second;
  552. }
  553. switch( aCol )
  554. {
  555. case FDC_NAME:
  556. // Use default field names for mandatory and system fields because they are translated
  557. // according to the current locale
  558. if( m_parentType == SCH_SYMBOL_T )
  559. {
  560. if( aRow < m_mandatoryFieldCount )
  561. return TEMPLATE_FIELDNAME::GetDefaultFieldName( aRow, DO_TRANSLATE );
  562. else
  563. return field.GetName( false );
  564. }
  565. else if( m_parentType == SCH_SHEET_T )
  566. {
  567. if( aRow < m_mandatoryFieldCount )
  568. return SCH_SHEET::GetDefaultFieldName( aRow );
  569. else
  570. return field.GetName( false );
  571. }
  572. else if( m_parentType == SCH_LABEL_LOCATE_ANY_T )
  573. {
  574. return SCH_LABEL_BASE::GetDefaultFieldName( field.GetCanonicalName(), false );
  575. }
  576. else
  577. {
  578. wxFAIL_MSG( wxS( "Unhandled field owner type." ) );
  579. return field.GetName( false );
  580. }
  581. case FDC_VALUE:
  582. return EscapeString( UnescapeString( field.GetText() ), CTX_LINE );
  583. case FDC_SHOWN:
  584. return StringFromBool( field.IsVisible() );
  585. case FDC_SHOW_NAME:
  586. return StringFromBool( field.IsNameShown() );
  587. case FDC_H_ALIGN:
  588. switch ( field.GetEffectiveHorizJustify() )
  589. {
  590. case GR_TEXT_H_ALIGN_LEFT: return _( "Left" );
  591. case GR_TEXT_H_ALIGN_CENTER: return _( "Center" );
  592. case GR_TEXT_H_ALIGN_RIGHT: return _( "Right" );
  593. case GR_TEXT_H_ALIGN_INDETERMINATE: return INDETERMINATE_STATE;
  594. }
  595. break;
  596. case FDC_V_ALIGN:
  597. switch ( field.GetEffectiveVertJustify() )
  598. {
  599. case GR_TEXT_V_ALIGN_TOP: return _( "Top" );
  600. case GR_TEXT_V_ALIGN_CENTER: return _( "Center" );
  601. case GR_TEXT_V_ALIGN_BOTTOM: return _( "Bottom" );
  602. case GR_TEXT_V_ALIGN_INDETERMINATE: return INDETERMINATE_STATE;
  603. }
  604. break;
  605. case FDC_ITALIC:
  606. return StringFromBool( field.IsItalic() );
  607. case FDC_BOLD:
  608. return StringFromBool( field.IsBold() );
  609. case FDC_TEXT_SIZE:
  610. return m_frame->StringFromValue( field.GetTextHeight(), true );
  611. case FDC_ORIENTATION:
  612. if( field.GetTextAngle().IsHorizontal() )
  613. return _( "Horizontal" );
  614. else
  615. return _( "Vertical" );
  616. case FDC_POSX:
  617. return m_frame->StringFromValue( field.GetTextPos().x, true );
  618. case FDC_POSY:
  619. return m_frame->StringFromValue( field.GetTextPos().y, true );
  620. case FDC_FONT:
  621. if( field.GetFont() )
  622. return field.GetFont()->GetName();
  623. else
  624. return DEFAULT_FONT_NAME;
  625. case FDC_COLOR:
  626. return field.GetTextColor().ToCSSString();
  627. case FDC_ALLOW_AUTOPLACE:
  628. return StringFromBool( field.CanAutoplace() );
  629. case FDC_PRIVATE:
  630. return StringFromBool( field.IsPrivate() );
  631. default:
  632. // we can't assert here because wxWidgets sometimes calls this without checking
  633. // the column type when trying to see if there's an overflow
  634. break;
  635. }
  636. return wxT( "bad wxWidgets!" );
  637. }
  638. bool FIELDS_GRID_TABLE::GetValueAsBool( int aRow, int aCol )
  639. {
  640. wxCHECK( aRow < GetNumberRows(), false );
  641. const SCH_FIELD& field = getField( aRow );
  642. switch( aCol )
  643. {
  644. case FDC_SHOWN: return field.IsVisible();
  645. case FDC_SHOW_NAME: return field.IsNameShown();
  646. case FDC_ITALIC: return field.IsItalic();
  647. case FDC_BOLD: return field.IsBold();
  648. case FDC_ALLOW_AUTOPLACE: return field.CanAutoplace();
  649. case FDC_PRIVATE: return field.IsPrivate();
  650. default:
  651. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  652. return false;
  653. }
  654. }
  655. void FIELDS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
  656. {
  657. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  658. SCH_FIELD& field = getField( aRow );
  659. VECTOR2I pos;
  660. wxString value = aValue;
  661. switch( aCol )
  662. {
  663. case FDC_TEXT_SIZE:
  664. case FDC_POSX:
  665. case FDC_POSY:
  666. m_eval->SetDefaultUnits( m_frame->GetUserUnits() );
  667. if( m_eval->Process( value ) )
  668. {
  669. m_evalOriginal[ { aRow, aCol } ] = value;
  670. value = m_eval->Result();
  671. }
  672. break;
  673. default:
  674. break;
  675. }
  676. switch( aCol )
  677. {
  678. case FDC_NAME:
  679. field.SetName( value );
  680. break;
  681. case FDC_VALUE:
  682. {
  683. if( m_parentType == SCH_SHEET_T && aRow == SHEETFILENAME )
  684. {
  685. value = EnsureFileExtension( value, FILEEXT::KiCadSchematicFileExtension );
  686. }
  687. else if( m_parentType == LIB_SYMBOL_T && aRow == VALUE_FIELD )
  688. {
  689. value = EscapeString( value, CTX_LIBID );
  690. }
  691. field.SetText( UnescapeString( value ) );
  692. break;
  693. }
  694. case FDC_SHOWN:
  695. field.SetVisible( BoolFromString( value ) );
  696. break;
  697. case FDC_SHOW_NAME:
  698. field.SetNameShown( BoolFromString( value ) );
  699. break;
  700. case FDC_H_ALIGN:
  701. {
  702. GR_TEXT_H_ALIGN_T horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
  703. if( value == _( "Left" ) )
  704. horizontalJustification = GR_TEXT_H_ALIGN_LEFT;
  705. else if( value == _( "Center" ) )
  706. horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
  707. else if( value == _( "Right" ) )
  708. horizontalJustification = GR_TEXT_H_ALIGN_RIGHT;
  709. else
  710. wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + value );
  711. // Note that we must set justifications before we can ask if they're flipped. If the old
  712. // justification is center then it won't know (whereas if the new justification is center
  713. // the we don't care).
  714. field.SetHorizJustify( horizontalJustification );
  715. if( field.IsHorizJustifyFlipped() )
  716. field.SetHorizJustify( EDA_TEXT::MapHorizJustify( - horizontalJustification ) );
  717. break;
  718. }
  719. case FDC_V_ALIGN:
  720. {
  721. GR_TEXT_V_ALIGN_T verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
  722. if( value == _( "Top" ) )
  723. verticalJustification = GR_TEXT_V_ALIGN_TOP;
  724. else if( value == _( "Center" ) )
  725. verticalJustification = GR_TEXT_V_ALIGN_CENTER;
  726. else if( value == _( "Bottom" ) )
  727. verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
  728. else
  729. wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + value);
  730. // Note that we must set justifications before we can ask if they're flipped. If the old
  731. // justification is center then it won't know (whereas if the new justification is center
  732. // the we don't care).
  733. field.SetVertJustify( verticalJustification );
  734. if( field.IsVertJustifyFlipped() )
  735. field.SetVertJustify( EDA_TEXT::MapVertJustify( -verticalJustification ) );
  736. break;
  737. }
  738. case FDC_ITALIC:
  739. field.SetItalic( BoolFromString( value ) );
  740. break;
  741. case FDC_BOLD:
  742. field.SetBold( BoolFromString( value ) );
  743. break;
  744. case FDC_TEXT_SIZE:
  745. field.SetTextSize( VECTOR2I( m_frame->ValueFromString( value ),
  746. m_frame->ValueFromString( value ) ) );
  747. break;
  748. case FDC_ORIENTATION:
  749. if( value == _( "Horizontal" ) )
  750. field.SetTextAngle( ANGLE_HORIZONTAL );
  751. else if( value == _( "Vertical" ) )
  752. field.SetTextAngle( ANGLE_VERTICAL );
  753. else
  754. wxFAIL_MSG( wxT( "unknown orientation: " ) + value );
  755. break;
  756. case FDC_POSX:
  757. case FDC_POSY:
  758. pos = field.GetTextPos();
  759. if( aCol == FDC_POSX )
  760. pos.x = m_frame->ValueFromString( value );
  761. else
  762. pos.y = m_frame->ValueFromString( value );
  763. field.SetTextPos( pos );
  764. break;
  765. case FDC_FONT:
  766. if( value == DEFAULT_FONT_NAME )
  767. field.SetFont( nullptr );
  768. else if( value == KICAD_FONT_NAME )
  769. field.SetFont( KIFONT::FONT::GetFont( wxEmptyString, field.IsBold(),
  770. field.IsItalic() ) );
  771. else
  772. field.SetFont( KIFONT::FONT::GetFont( aValue, field.IsBold(), field.IsItalic() ) );
  773. break;
  774. case FDC_COLOR:
  775. field.SetTextColor( wxColor( value ) );
  776. break;
  777. case FDC_ALLOW_AUTOPLACE:
  778. field.SetCanAutoplace( BoolFromString( value ) );
  779. break;
  780. case FDC_PRIVATE:
  781. field.SetPrivate( BoolFromString( value ) );
  782. break;
  783. default:
  784. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
  785. break;
  786. }
  787. m_dialog->OnModify();
  788. GetView()->Refresh();
  789. }
  790. void FIELDS_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue )
  791. {
  792. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  793. SCH_FIELD& field = getField( aRow );
  794. switch( aCol )
  795. {
  796. case FDC_SHOWN:
  797. field.SetVisible( aValue );
  798. break;
  799. case FDC_SHOW_NAME:
  800. field.SetNameShown( aValue );
  801. break;
  802. case FDC_ITALIC:
  803. field.SetItalic( aValue );
  804. break;
  805. case FDC_BOLD:
  806. field.SetBold( aValue );
  807. break;
  808. case FDC_ALLOW_AUTOPLACE:
  809. field.SetCanAutoplace( aValue );
  810. break;
  811. case FDC_PRIVATE:
  812. field.SetPrivate( aValue );
  813. break;
  814. default:
  815. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  816. break;
  817. }
  818. m_dialog->OnModify();
  819. }
  820. wxString FIELDS_GRID_TABLE::StringFromBool( bool aValue ) const
  821. {
  822. if( aValue )
  823. return wxT( "1" );
  824. else
  825. return wxT( "0" );
  826. }
  827. bool FIELDS_GRID_TABLE::BoolFromString( const wxString& aValue ) const
  828. {
  829. if( aValue == wxS( "1" ) )
  830. {
  831. return true;
  832. }
  833. else if( aValue == wxS( "0" ) )
  834. {
  835. return false;
  836. }
  837. else
  838. {
  839. wxFAIL_MSG( wxString::Format( "string '%s' can't be converted to boolean correctly and "
  840. "will be perceived as FALSE", aValue ) );
  841. return false;
  842. }
  843. }
  844. void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
  845. {
  846. if( m_grid->GetGridCursorRow() == FOOTPRINT_FIELD && m_grid->GetGridCursorCol() == FDC_VALUE
  847. && !m_grid->IsReadOnly( FOOTPRINT_FIELD, FDC_VALUE ) )
  848. {
  849. menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
  850. _( "Browse for footprint" ) );
  851. menu.AppendSeparator();
  852. }
  853. else if( m_grid->GetGridCursorRow() == DATASHEET_FIELD
  854. && m_grid->GetGridCursorCol() == FDC_VALUE )
  855. {
  856. menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
  857. _( "Show datasheet in browser" ) );
  858. menu.AppendSeparator();
  859. }
  860. GRID_TRICKS::showPopupMenu( menu, aEvent );
  861. }
  862. void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
  863. {
  864. if( event.GetId() == MYID_SELECT_FOOTPRINT )
  865. {
  866. // pick a footprint using the footprint picker.
  867. wxString fpid = m_grid->GetCellValue( FOOTPRINT_FIELD, FDC_VALUE );
  868. if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ) )
  869. {
  870. if( frame->ShowModal( &fpid, m_dlg ) )
  871. m_grid->SetCellValue( FOOTPRINT_FIELD, FDC_VALUE, fpid );
  872. frame->Destroy();
  873. }
  874. }
  875. else if (event.GetId() == MYID_SHOW_DATASHEET )
  876. {
  877. wxString datasheet_uri = m_grid->GetCellValue( DATASHEET_FIELD, FDC_VALUE );
  878. GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj(),
  879. PROJECT_SCH::SchSearchS( &m_dlg->Prj() ), m_files );
  880. }
  881. else
  882. {
  883. GRID_TRICKS::doPopupSelection( event );
  884. }
  885. }