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.

1285 lines
40 KiB

Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-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 "dialog_symbol_properties.h"
  24. #include <memory>
  25. #include <bitmaps.h>
  26. #include <wx/tooltip.h>
  27. #include <grid_tricks.h>
  28. #include <confirm.h>
  29. #include <kiface_base.h>
  30. #include <pin_numbers.h>
  31. #include <string_utils.h>
  32. #include <kiplatform/ui.h>
  33. #include <widgets/grid_icon_text_helpers.h>
  34. #include <widgets/grid_combobox.h>
  35. #include <widgets/std_bitmap_button.h>
  36. #include <settings/settings_manager.h>
  37. #include <ee_collectors.h>
  38. #include <symbol_library.h>
  39. #include <fields_grid_table.h>
  40. #include <sch_edit_frame.h>
  41. #include <sch_reference_list.h>
  42. #include <schematic.h>
  43. #include <sch_commit.h>
  44. #include <tool/tool_manager.h>
  45. #include <tool/actions.h>
  46. #include <dialog_sim_model.h>
  47. wxDEFINE_EVENT( SYMBOL_DELAY_FOCUS, wxCommandEvent );
  48. wxDEFINE_EVENT( SYMBOL_DELAY_SELECTION, wxCommandEvent );
  49. enum PIN_TABLE_COL_ORDER
  50. {
  51. COL_NUMBER,
  52. COL_BASE_NAME,
  53. COL_ALT_NAME,
  54. COL_TYPE,
  55. COL_SHAPE,
  56. COL_COUNT // keep as last
  57. };
  58. class SCH_PIN_TABLE_DATA_MODEL : public wxGridTableBase, public std::vector<SCH_PIN>
  59. {
  60. public:
  61. SCH_PIN_TABLE_DATA_MODEL() :
  62. m_readOnlyAttr( nullptr ),
  63. m_typeAttr( nullptr ),
  64. m_shapeAttr( nullptr )
  65. {
  66. }
  67. ~SCH_PIN_TABLE_DATA_MODEL()
  68. {
  69. for( wxGridCellAttr* attr : m_nameAttrs )
  70. attr->DecRef();
  71. m_readOnlyAttr->DecRef();
  72. m_typeAttr->DecRef();
  73. m_shapeAttr->DecRef();
  74. }
  75. void BuildAttrs()
  76. {
  77. for( wxGridCellAttr* attr : m_nameAttrs )
  78. attr->DecRef();
  79. m_nameAttrs.clear();
  80. if( m_readOnlyAttr )
  81. m_readOnlyAttr->DecRef();
  82. m_readOnlyAttr = new wxGridCellAttr;
  83. m_readOnlyAttr->SetReadOnly( true );
  84. for( const SCH_PIN& pin : *this )
  85. {
  86. LIB_PIN* lib_pin = pin.GetLibPin();
  87. wxGridCellAttr* attr = nullptr;
  88. if( lib_pin->GetAlternates().empty() )
  89. {
  90. attr = new wxGridCellAttr;
  91. attr->SetReadOnly( true );
  92. attr->SetBackgroundColour( KIPLATFORM::UI::GetDialogBGColour() );
  93. }
  94. else
  95. {
  96. wxArrayString choices;
  97. choices.push_back( lib_pin->GetName() );
  98. for( const std::pair<const wxString, LIB_PIN::ALT>& alt : lib_pin->GetAlternates() )
  99. choices.push_back( alt.first );
  100. attr = new wxGridCellAttr();
  101. attr->SetEditor( new GRID_CELL_COMBOBOX( choices ) );
  102. }
  103. m_nameAttrs.push_back( attr );
  104. }
  105. if( m_typeAttr )
  106. m_typeAttr->DecRef();
  107. m_typeAttr = new wxGridCellAttr;
  108. m_typeAttr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinTypeIcons(),
  109. PinTypeNames() ) );
  110. m_typeAttr->SetReadOnly( true );
  111. if( m_shapeAttr )
  112. m_shapeAttr->DecRef();
  113. m_shapeAttr = new wxGridCellAttr;
  114. m_shapeAttr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinShapeIcons(),
  115. PinShapeNames() ) );
  116. m_shapeAttr->SetReadOnly( true );
  117. }
  118. int GetNumberRows() override { return (int) size(); }
  119. int GetNumberCols() override { return COL_COUNT; }
  120. wxString GetColLabelValue( int aCol ) override
  121. {
  122. switch( aCol )
  123. {
  124. case COL_NUMBER: return _( "Number" );
  125. case COL_BASE_NAME: return _( "Base Name" );
  126. case COL_ALT_NAME: return _( "Alternate Assignment" );
  127. case COL_TYPE: return _( "Electrical Type" );
  128. case COL_SHAPE: return _( "Graphic Style" );
  129. default: wxFAIL; return wxEmptyString;
  130. }
  131. }
  132. bool IsEmptyCell( int row, int col ) override
  133. {
  134. return false; // don't allow adjacent cell overflow, even if we are actually empty
  135. }
  136. bool CanSetValueAs( int aRow, int aCol, const wxString& aTypeName ) override
  137. {
  138. // Don't accept random values; must use the popup to change to a known alternate
  139. return false;
  140. }
  141. wxString GetValue( int aRow, int aCol ) override
  142. {
  143. return GetValue( at( aRow ), aCol );
  144. }
  145. static wxString GetValue( const SCH_PIN& aPin, int aCol )
  146. {
  147. if( aCol == COL_ALT_NAME )
  148. {
  149. if( aPin.GetLibPin()->GetAlternates().empty() )
  150. return wxEmptyString;
  151. else if( aPin.GetAlt().IsEmpty() )
  152. return aPin.GetName();
  153. else
  154. return aPin.GetAlt();
  155. }
  156. switch( aCol )
  157. {
  158. case COL_NUMBER: return aPin.GetNumber();
  159. case COL_BASE_NAME: return aPin.GetLibPin()->GetName();
  160. case COL_TYPE: return PinTypeNames()[static_cast<int>( aPin.GetType() )];
  161. case COL_SHAPE: return PinShapeNames()[static_cast<int>( aPin.GetShape() )];
  162. default: wxFAIL; return wxEmptyString;
  163. }
  164. }
  165. wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind ) override
  166. {
  167. switch( aCol )
  168. {
  169. case COL_NUMBER:
  170. case COL_BASE_NAME:
  171. m_readOnlyAttr->IncRef();
  172. return m_readOnlyAttr;
  173. case COL_ALT_NAME:
  174. m_nameAttrs[ aRow ]->IncRef();
  175. return m_nameAttrs[ aRow ];
  176. case COL_TYPE:
  177. m_typeAttr->IncRef();
  178. return m_typeAttr;
  179. case COL_SHAPE:
  180. m_shapeAttr->IncRef();
  181. return m_shapeAttr;
  182. default:
  183. wxFAIL;
  184. return nullptr;
  185. }
  186. }
  187. void SetValue( int aRow, int aCol, const wxString &aValue ) override
  188. {
  189. switch( aCol )
  190. {
  191. case COL_ALT_NAME:
  192. if( aValue == at( aRow ).GetLibPin()->GetName() )
  193. at( aRow ).SetAlt( wxEmptyString );
  194. else
  195. at( aRow ).SetAlt( aValue );
  196. break;
  197. case COL_NUMBER:
  198. case COL_BASE_NAME:
  199. case COL_TYPE:
  200. case COL_SHAPE:
  201. // Read-only.
  202. break;
  203. default:
  204. wxFAIL;
  205. break;
  206. }
  207. }
  208. static bool compare( const SCH_PIN& lhs, const SCH_PIN& rhs, int sortCol, bool ascending )
  209. {
  210. wxString lhStr = GetValue( lhs, sortCol );
  211. wxString rhStr = GetValue( rhs, sortCol );
  212. if( lhStr == rhStr )
  213. {
  214. // Secondary sort key is always COL_NUMBER
  215. sortCol = COL_NUMBER;
  216. lhStr = GetValue( lhs, sortCol );
  217. rhStr = GetValue( rhs, sortCol );
  218. }
  219. bool res;
  220. // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
  221. // to get the opposite sort. i.e. ~(a<b) != (a>b)
  222. auto cmp = [ ascending ]( const auto a, const auto b )
  223. {
  224. if( ascending )
  225. return a < b;
  226. else
  227. return b < a;
  228. };
  229. switch( sortCol )
  230. {
  231. case COL_NUMBER:
  232. case COL_BASE_NAME:
  233. case COL_ALT_NAME:
  234. res = cmp( PIN_NUMBERS::Compare( lhStr, rhStr ), 0 );
  235. break;
  236. case COL_TYPE:
  237. case COL_SHAPE:
  238. res = cmp( lhStr.CmpNoCase( rhStr ), 0 );
  239. break;
  240. default:
  241. res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
  242. break;
  243. }
  244. return res;
  245. }
  246. void SortRows( int aSortCol, bool ascending )
  247. {
  248. std::sort( begin(), end(),
  249. [ aSortCol, ascending ]( const SCH_PIN& lhs, const SCH_PIN& rhs ) -> bool
  250. {
  251. return compare( lhs, rhs, aSortCol, ascending );
  252. } );
  253. }
  254. protected:
  255. std::vector<wxGridCellAttr*> m_nameAttrs;
  256. wxGridCellAttr* m_readOnlyAttr;
  257. wxGridCellAttr* m_typeAttr;
  258. wxGridCellAttr* m_shapeAttr;
  259. };
  260. DIALOG_SYMBOL_PROPERTIES::DIALOG_SYMBOL_PROPERTIES( SCH_EDIT_FRAME* aParent,
  261. SCH_SYMBOL* aSymbol ) :
  262. DIALOG_SYMBOL_PROPERTIES_BASE( aParent ),
  263. m_symbol( nullptr ),
  264. m_part( nullptr ),
  265. m_fieldsSize( 0, 0 ),
  266. m_lastRequestedSize( 0, 0 ),
  267. m_editorShown( false ),
  268. m_fields( nullptr ),
  269. m_dataModel( nullptr )
  270. {
  271. m_symbol = aSymbol;
  272. m_part = m_symbol->GetLibSymbolRef().get();
  273. // GetLibSymbolRef() now points to the cached part in the schematic, which should always be
  274. // there for usual cases, but can be null when opening old schematics not storing the part
  275. // so we need to handle m_part == nullptr
  276. // wxASSERT( m_part );
  277. m_fields = new FIELDS_GRID_TABLE<SCH_FIELD>( this, aParent, m_fieldsGrid, m_symbol );
  278. // Give a bit more room for combobox editors
  279. m_fieldsGrid->SetDefaultRowSize( m_fieldsGrid->GetDefaultRowSize() + 4 );
  280. m_pinGrid->SetDefaultRowSize( m_pinGrid->GetDefaultRowSize() + 4 );
  281. m_fieldsGrid->SetTable( m_fields );
  282. m_fieldsGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_fieldsGrid, this,
  283. [&]( wxCommandEvent& aEvent )
  284. {
  285. OnAddField( aEvent );
  286. } ) );
  287. m_fieldsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
  288. // Show/hide columns according to user's preference
  289. if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
  290. {
  291. m_fieldsGrid->ShowHideColumns( cfg->m_Appearance.edit_symbol_visible_columns );
  292. m_shownColumns = m_fieldsGrid->GetShownColumns();
  293. }
  294. if( m_part && m_part->HasConversion() )
  295. {
  296. // DeMorgan conversions are a subclass of alternate pin assignments, so don't allow
  297. // free-form alternate assignments as well. (We won't know how to map the alternates
  298. // back and forth when the conversion is changed.)
  299. m_pinTablePage->Disable();
  300. m_pinTablePage->SetToolTip( _( "Alternate pin assignments are not available for De Morgan "
  301. "symbols." ) );
  302. }
  303. else
  304. {
  305. m_dataModel = new SCH_PIN_TABLE_DATA_MODEL();
  306. // Make a copy of the pins for editing
  307. for( const std::unique_ptr<SCH_PIN>& pin : m_symbol->GetRawPins() )
  308. m_dataModel->push_back( *pin );
  309. m_dataModel->SortRows( COL_NUMBER, true );
  310. m_dataModel->BuildAttrs();
  311. m_pinGrid->SetTable( m_dataModel );
  312. }
  313. if( m_part && m_part->IsPower() )
  314. m_spiceFieldsButton->Hide();
  315. m_pinGrid->PushEventHandler( new GRID_TRICKS( m_pinGrid ) );
  316. m_pinGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
  317. m_tcLibraryID->SetBackgroundColour( KIPLATFORM::UI::GetDialogBGColour() );
  318. wxToolTip::Enable( true );
  319. SetupStandardButtons();
  320. // Configure button logos
  321. m_bpAdd->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
  322. m_bpDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
  323. m_bpMoveUp->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
  324. m_bpMoveDown->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
  325. // wxFormBuilder doesn't include this event...
  326. m_fieldsGrid->Bind( wxEVT_GRID_CELL_CHANGING, &DIALOG_SYMBOL_PROPERTIES::OnGridCellChanging,
  327. this );
  328. m_pinGrid->Bind( wxEVT_GRID_COL_SORT, &DIALOG_SYMBOL_PROPERTIES::OnPinTableColSort, this );
  329. Bind( SYMBOL_DELAY_FOCUS, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedFocus, this );
  330. Bind( SYMBOL_DELAY_SELECTION, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedSelection, this );
  331. QueueEvent( new wxCommandEvent( SYMBOL_DELAY_SELECTION ) );
  332. wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
  333. evt->SetClientData( new VECTOR2I( REFERENCE_FIELD, FDC_VALUE ) );
  334. QueueEvent( evt );
  335. finishDialogSettings();
  336. }
  337. DIALOG_SYMBOL_PROPERTIES::~DIALOG_SYMBOL_PROPERTIES()
  338. {
  339. if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
  340. {
  341. cfg->m_Appearance.edit_symbol_visible_columns = m_fieldsGrid->GetShownColumnsAsString();
  342. cfg->m_Appearance.edit_symbol_width = GetSize().x;
  343. cfg->m_Appearance.edit_symbol_height = GetSize().y;
  344. }
  345. // Prevents crash bug in wxGrid's d'tor
  346. m_fieldsGrid->DestroyTable( m_fields );
  347. if( m_dataModel )
  348. m_pinGrid->DestroyTable( m_dataModel );
  349. m_fieldsGrid->Unbind( wxEVT_GRID_CELL_CHANGING, &DIALOG_SYMBOL_PROPERTIES::OnGridCellChanging,
  350. this );
  351. m_pinGrid->Unbind( wxEVT_GRID_COL_SORT, &DIALOG_SYMBOL_PROPERTIES::OnPinTableColSort, this );
  352. Unbind( SYMBOL_DELAY_FOCUS, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedFocus, this );
  353. Unbind( SYMBOL_DELAY_SELECTION, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedSelection, this );
  354. // Delete the GRID_TRICKS.
  355. m_fieldsGrid->PopEventHandler( true );
  356. m_pinGrid->PopEventHandler( true );
  357. }
  358. SCH_EDIT_FRAME* DIALOG_SYMBOL_PROPERTIES::GetParent()
  359. {
  360. return dynamic_cast<SCH_EDIT_FRAME*>( wxDialog::GetParent() );
  361. }
  362. bool DIALOG_SYMBOL_PROPERTIES::TransferDataToWindow()
  363. {
  364. if( !wxDialog::TransferDataToWindow() )
  365. return false;
  366. std::set<wxString> defined;
  367. // Push a copy of each field into m_updateFields
  368. for( int i = 0; i < m_symbol->GetFieldCount(); ++i )
  369. {
  370. SCH_FIELD field( m_symbol->GetFields()[i] );
  371. // change offset to be symbol-relative
  372. field.Offset( -m_symbol->GetPosition() );
  373. defined.insert( field.GetName() );
  374. m_fields->push_back( field );
  375. }
  376. // Add in any template fieldnames not yet defined:
  377. for( const TEMPLATE_FIELDNAME& templateFieldname :
  378. GetParent()->Schematic().Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
  379. {
  380. if( defined.count( templateFieldname.m_Name ) <= 0 )
  381. {
  382. SCH_FIELD field( VECTOR2I( 0, 0 ), -1, m_symbol, templateFieldname.m_Name );
  383. field.SetVisible( templateFieldname.m_Visible );
  384. m_fields->push_back( field );
  385. }
  386. }
  387. // notify the grid
  388. wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->size() );
  389. m_fieldsGrid->ProcessTableMessage( msg );
  390. AdjustFieldsGridColumns();
  391. // If a multi-unit symbol, set up the unit selector and interchangeable checkbox.
  392. if( m_symbol->GetUnitCount() > 1 )
  393. {
  394. // Ensure symbol unit is the currently selected unit (mandatory in complex hierarchies)
  395. // from the current sheet path, because it can be modified by previous calculations
  396. m_symbol->UpdateUnit( m_symbol->GetUnitSelection( &GetParent()->GetCurrentSheet() ) );
  397. for( int ii = 1; ii <= m_symbol->GetUnitCount(); ii++ )
  398. {
  399. if( m_symbol->HasUnitDisplayName( ii ) )
  400. m_unitChoice->Append( m_symbol->GetUnitDisplayName( ii ) );
  401. else
  402. m_unitChoice->Append( m_symbol->SubReference( ii, false ) );
  403. }
  404. if( m_symbol->GetUnit() <= ( int )m_unitChoice->GetCount() )
  405. m_unitChoice->SetSelection( m_symbol->GetUnit() - 1 );
  406. }
  407. else
  408. {
  409. m_unitLabel->Enable( false );
  410. m_unitChoice->Enable( false );
  411. }
  412. if( m_part && m_part->HasConversion() )
  413. {
  414. if( m_symbol->GetConvert() > LIB_ITEM::LIB_CONVERT::BASE )
  415. m_cbAlternateSymbol->SetValue( true );
  416. }
  417. else
  418. {
  419. m_cbAlternateSymbol->Enable( false );
  420. }
  421. // Set the symbol orientation and mirroring.
  422. int orientation = m_symbol->GetOrientation() & ~( SYM_MIRROR_X | SYM_MIRROR_Y );
  423. switch( orientation )
  424. {
  425. default:
  426. case SYM_ORIENT_0: m_orientationCtrl->SetSelection( 0 ); break;
  427. case SYM_ORIENT_90: m_orientationCtrl->SetSelection( 1 ); break;
  428. case SYM_ORIENT_270: m_orientationCtrl->SetSelection( 2 ); break;
  429. case SYM_ORIENT_180: m_orientationCtrl->SetSelection( 3 ); break;
  430. }
  431. int mirror = m_symbol->GetOrientation() & ( SYM_MIRROR_X | SYM_MIRROR_Y );
  432. switch( mirror )
  433. {
  434. default: m_mirrorCtrl->SetSelection( 0 ) ; break;
  435. case SYM_MIRROR_X: m_mirrorCtrl->SetSelection( 1 ); break;
  436. case SYM_MIRROR_Y: m_mirrorCtrl->SetSelection( 2 ); break;
  437. }
  438. m_cbExcludeFromSim->SetValue( m_symbol->GetExcludedFromSim() );
  439. m_cbExcludeFromBom->SetValue( m_symbol->GetExcludedFromBOM() );
  440. m_cbExcludeFromBoard->SetValue( m_symbol->GetExcludedFromBoard() );
  441. m_cbDNP->SetValue( m_symbol->GetDNP() );
  442. if( m_part )
  443. {
  444. m_ShowPinNumButt->SetValue( m_part->ShowPinNumbers() );
  445. m_ShowPinNameButt->SetValue( m_part->ShowPinNames() );
  446. }
  447. // Set the symbol's library name.
  448. m_tcLibraryID->SetValue( UnescapeString( m_symbol->GetLibId().Format() ) );
  449. Layout();
  450. m_fieldsGrid->Layout();
  451. wxSafeYield();
  452. return true;
  453. }
  454. void DIALOG_SYMBOL_PROPERTIES::OnEditSpiceModel( wxCommandEvent& event )
  455. {
  456. if( !m_fieldsGrid->CommitPendingChanges() )
  457. return;
  458. std::vector<SCH_FIELD> fields;
  459. for( const SCH_FIELD& field : *m_fields )
  460. fields.emplace_back( field );
  461. DIALOG_SIM_MODEL dialog( this, *m_symbol, fields );
  462. if( dialog.ShowModal() != wxID_OK )
  463. return;
  464. // Add in any new fields
  465. for( const SCH_FIELD& editedField : fields )
  466. {
  467. bool found = false;
  468. for( SCH_FIELD& existingField : *m_fields )
  469. {
  470. if( existingField.GetName() == editedField.GetName() )
  471. {
  472. found = true;
  473. existingField.SetText( editedField.GetText() );
  474. break;
  475. }
  476. }
  477. if( !found )
  478. {
  479. m_fields->emplace_back( editedField );
  480. wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
  481. m_fieldsGrid->ProcessTableMessage( msg );
  482. }
  483. }
  484. // Remove any deleted fields
  485. for( int ii = (int) m_fields->size() - 1; ii >= 0; --ii )
  486. {
  487. SCH_FIELD& existingField = m_fields->at( ii );
  488. bool found = false;
  489. for( SCH_FIELD& editedField : fields )
  490. {
  491. if( editedField.GetName() == existingField.GetName() )
  492. {
  493. found = true;
  494. break;
  495. }
  496. }
  497. if( !found )
  498. {
  499. m_fields->erase( m_fields->begin() + ii );
  500. wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, ii, 1 );
  501. m_fieldsGrid->ClearSelection();
  502. m_fieldsGrid->ProcessTableMessage( msg );
  503. }
  504. }
  505. OnModify();
  506. m_fieldsGrid->ForceRefresh();
  507. }
  508. void DIALOG_SYMBOL_PROPERTIES::OnCancelButtonClick( wxCommandEvent& event )
  509. {
  510. // Running the Footprint Browser gums up the works and causes the automatic cancel
  511. // stuff to no longer work. So we do it here ourselves.
  512. EndQuasiModal( wxID_CANCEL );
  513. }
  514. bool DIALOG_SYMBOL_PROPERTIES::Validate()
  515. {
  516. LIB_ID id;
  517. if( !m_fieldsGrid->CommitPendingChanges() || !m_fieldsGrid->Validate() )
  518. return false;
  519. if( !SCH_SYMBOL::IsReferenceStringValid( m_fields->at( REFERENCE_FIELD ).GetText() ) )
  520. {
  521. DisplayErrorMessage( this, _( "References must start with a letter." ) );
  522. wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
  523. evt->SetClientData( new VECTOR2I( REFERENCE_FIELD, FDC_VALUE ) );
  524. QueueEvent( evt );
  525. return false;
  526. }
  527. // Check for missing field names.
  528. for( size_t i = MANDATORY_FIELDS; i < m_fields->size(); ++i )
  529. {
  530. SCH_FIELD& field = m_fields->at( i );
  531. wxString fieldName = field.GetName( false );
  532. if( fieldName.IsEmpty() )
  533. {
  534. DisplayErrorMessage( this, _( "Fields must have a name." ) );
  535. wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
  536. evt->SetClientData( new VECTOR2I( i, FDC_VALUE ) );
  537. QueueEvent( evt );
  538. return false;
  539. }
  540. }
  541. return true;
  542. }
  543. bool DIALOG_SYMBOL_PROPERTIES::TransferDataFromWindow()
  544. {
  545. if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
  546. return false;
  547. if( !m_fieldsGrid->CommitPendingChanges() )
  548. return false;
  549. if( !m_pinGrid->CommitPendingChanges() )
  550. return false;
  551. SCH_COMMIT commit( GetParent() );
  552. SCH_SCREEN* currentScreen = GetParent()->GetScreen();
  553. wxCHECK( currentScreen, false );
  554. // This needs to be done before the LIB_ID is changed to prevent stale library symbols in
  555. // the schematic file.
  556. currentScreen->Remove( m_symbol );
  557. // save old cmp in undo list if not already in edit, or moving ...
  558. if( m_symbol->GetEditFlags() == 0 )
  559. commit.Modify( m_symbol, currentScreen );
  560. // Save current flags which could be modified by next change settings
  561. EDA_ITEM_FLAGS flags = m_symbol->GetFlags();
  562. // For symbols with multiple shapes (De Morgan representation) Set the selected shape:
  563. if( m_cbAlternateSymbol->IsEnabled() && m_cbAlternateSymbol->GetValue() )
  564. m_symbol->SetConvert( LIB_ITEM::LIB_CONVERT::DEMORGAN );
  565. else
  566. m_symbol->SetConvert( LIB_ITEM::LIB_CONVERT::BASE );
  567. //Set the part selection in multiple part per package
  568. int unit_selection = m_unitChoice->IsEnabled() ? m_unitChoice->GetSelection() + 1 : 1;
  569. m_symbol->SetUnitSelection( &GetParent()->GetCurrentSheet(), unit_selection );
  570. m_symbol->SetUnit( unit_selection );
  571. switch( m_orientationCtrl->GetSelection() )
  572. {
  573. case 0: m_symbol->SetOrientation( SYM_ORIENT_0 ); break;
  574. case 1: m_symbol->SetOrientation( SYM_ORIENT_90 ); break;
  575. case 2: m_symbol->SetOrientation( SYM_ORIENT_270 ); break;
  576. case 3: m_symbol->SetOrientation( SYM_ORIENT_180 ); break;
  577. }
  578. switch( m_mirrorCtrl->GetSelection() )
  579. {
  580. case 0: break;
  581. case 1: m_symbol->SetOrientation( SYM_MIRROR_X ); break;
  582. case 2: m_symbol->SetOrientation( SYM_MIRROR_Y ); break;
  583. }
  584. if( m_part )
  585. {
  586. m_part->SetShowPinNames( m_ShowPinNameButt->GetValue() );
  587. m_part->SetShowPinNumbers( m_ShowPinNumButt->GetValue() );
  588. }
  589. // Restore m_Flag modified by SetUnit() and other change settings from the dialog
  590. m_symbol->ClearFlags();
  591. m_symbol->SetFlags( flags );
  592. // change all field positions from relative to absolute
  593. for( unsigned i = 0; i < m_fields->size(); ++i )
  594. m_fields->at( i ).Offset( m_symbol->GetPosition() );
  595. SCH_FIELDS& fields = m_symbol->GetFields();
  596. fields.clear();
  597. for( size_t ii = 0; ii < m_fields->size(); ++ii )
  598. {
  599. SCH_FIELD& field = m_fields->at( ii );
  600. const wxString& fieldName = field.GetCanonicalName();
  601. if( fieldName.IsEmpty() && field.GetText().IsEmpty() )
  602. continue;
  603. else if( fieldName.IsEmpty() )
  604. field.SetName( _( "untitled" ) );
  605. fields.push_back( field );
  606. }
  607. // Reference has a specific initialization, depending on the current active sheet
  608. // because for a given symbol, in a complex hierarchy, there are more than one
  609. // reference.
  610. m_symbol->SetRef( &GetParent()->GetCurrentSheet(), m_fields->at( REFERENCE_FIELD ).GetText() );
  611. // Similar for Value and Footprint, except that the GUI behavior is that they are kept
  612. // in sync between multiple instances.
  613. m_symbol->SetValueFieldText( m_fields->at( VALUE_FIELD ).GetText() );
  614. m_symbol->SetFootprintFieldText( m_fields->at( FOOTPRINT_FIELD ).GetText() );
  615. m_symbol->SetExcludedFromSim( m_cbExcludeFromSim->IsChecked() );
  616. m_symbol->SetExcludedFromBOM( m_cbExcludeFromBom->IsChecked() );
  617. m_symbol->SetExcludedFromBoard( m_cbExcludeFromBoard->IsChecked() );
  618. m_symbol->SetDNP( m_cbDNP->IsChecked() );
  619. // Update any assignments
  620. if( m_dataModel )
  621. {
  622. for( const SCH_PIN& model_pin : *m_dataModel )
  623. {
  624. // map from the edited copy back to the "real" pin in the symbol.
  625. SCH_PIN* src_pin = m_symbol->GetPin( model_pin.GetNumber() );
  626. if( src_pin )
  627. src_pin->SetAlt( model_pin.GetAlt() );
  628. }
  629. }
  630. // Keep fields other than the reference, include/exclude flags, and alternate pin assignements
  631. // in sync in multi-unit parts.
  632. if( m_symbol->GetUnitCount() > 1 && m_symbol->IsAnnotated( &GetParent()->GetCurrentSheet() ) )
  633. {
  634. wxString ref = m_symbol->GetRef( &GetParent()->GetCurrentSheet() );
  635. int unit = m_symbol->GetUnit();
  636. LIB_ID libId = m_symbol->GetLibId();
  637. for( SCH_SHEET_PATH& sheet : GetParent()->Schematic().GetSheets() )
  638. {
  639. SCH_SCREEN* screen = sheet.LastScreen();
  640. std::vector<SCH_SYMBOL*> otherUnits;
  641. CollectOtherUnits( ref, unit, libId, sheet, &otherUnits );
  642. for( SCH_SYMBOL* otherUnit : otherUnits )
  643. {
  644. commit.Modify( otherUnit, screen );
  645. otherUnit->SetValueFieldText( m_fields->at( VALUE_FIELD ).GetText() );
  646. otherUnit->SetFootprintFieldText( m_fields->at( FOOTPRINT_FIELD ).GetText() );
  647. for( size_t ii = DATASHEET_FIELD; ii < m_fields->size(); ++ii )
  648. {
  649. SCH_FIELD* otherField = otherUnit->FindField( m_fields->at( ii ).GetName() );
  650. if( otherField )
  651. {
  652. otherField->SetText( m_fields->at( ii ).GetText() );
  653. }
  654. else
  655. {
  656. SCH_FIELD newField( m_fields->at( ii ) );
  657. const_cast<KIID&>( newField.m_Uuid ) = KIID();
  658. newField.Offset( -m_symbol->GetPosition() );
  659. newField.Offset( otherUnit->GetPosition() );
  660. newField.SetParent( otherUnit );
  661. otherUnit->AddField( newField );
  662. }
  663. }
  664. for( size_t ii = otherUnit->GetFields().size() - 1; ii > DATASHEET_FIELD; ii-- )
  665. {
  666. SCH_FIELD& otherField = otherUnit->GetFields().at( ii );
  667. if( !m_symbol->FindField( otherField.GetName() ) )
  668. otherUnit->GetFields().erase( otherUnit->GetFields().begin() + ii );
  669. }
  670. otherUnit->SetExcludedFromSim( m_cbExcludeFromSim->IsChecked() );
  671. otherUnit->SetExcludedFromBOM( m_cbExcludeFromBom->IsChecked() );
  672. otherUnit->SetExcludedFromBoard( m_cbExcludeFromBoard->IsChecked() );
  673. otherUnit->SetDNP( m_cbDNP->IsChecked() );
  674. if( m_dataModel )
  675. {
  676. for( const SCH_PIN& model_pin : *m_dataModel )
  677. {
  678. SCH_PIN* src_pin = otherUnit->GetPin( model_pin.GetNumber() );
  679. if( src_pin )
  680. src_pin->SetAlt( model_pin.GetAlt() );
  681. }
  682. }
  683. }
  684. }
  685. }
  686. currentScreen->Append( m_symbol );
  687. if( !commit.Empty() )
  688. commit.Push( _( "Edit Symbol Properties" ) );
  689. return true;
  690. }
  691. void DIALOG_SYMBOL_PROPERTIES::OnGridCellChanging( wxGridEvent& event )
  692. {
  693. wxGridCellEditor* editor = m_fieldsGrid->GetCellEditor( event.GetRow(), event.GetCol() );
  694. wxControl* control = editor->GetControl();
  695. if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
  696. {
  697. event.Veto();
  698. wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
  699. evt->SetClientData( new VECTOR2I( event.GetRow(), event.GetCol() ) );
  700. QueueEvent( evt );
  701. }
  702. else if( event.GetCol() == FDC_NAME )
  703. {
  704. wxString newName = event.GetString();
  705. for( int i = 0; i < m_fieldsGrid->GetNumberRows(); ++i )
  706. {
  707. if( i == event.GetRow() )
  708. continue;
  709. if( newName.CmpNoCase( m_fieldsGrid->GetCellValue( i, FDC_NAME ) ) == 0 )
  710. {
  711. DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
  712. newName ) );
  713. event.Veto();
  714. wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
  715. evt->SetClientData( new VECTOR2I( event.GetRow(), event.GetCol() ) );
  716. QueueEvent( evt );
  717. }
  718. }
  719. }
  720. editor->DecRef();
  721. }
  722. void DIALOG_SYMBOL_PROPERTIES::OnGridEditorShown( wxGridEvent& aEvent )
  723. {
  724. if( aEvent.GetRow() == REFERENCE_FIELD && aEvent.GetCol() == FDC_VALUE )
  725. QueueEvent( new wxCommandEvent( SYMBOL_DELAY_SELECTION ) );
  726. m_editorShown = true;
  727. }
  728. void DIALOG_SYMBOL_PROPERTIES::OnGridEditorHidden( wxGridEvent& aEvent )
  729. {
  730. m_editorShown = false;
  731. }
  732. void DIALOG_SYMBOL_PROPERTIES::OnAddField( wxCommandEvent& event )
  733. {
  734. if( !m_fieldsGrid->CommitPendingChanges() )
  735. return;
  736. SCHEMATIC_SETTINGS& settings = m_symbol->Schematic()->Settings();
  737. int fieldID = (int) m_fields->size();
  738. SCH_FIELD newField( VECTOR2I( 0, 0 ), fieldID, m_symbol,
  739. TEMPLATE_FIELDNAME::GetDefaultFieldName( fieldID,
  740. DO_TRANSLATE ) );
  741. newField.SetTextAngle( m_fields->at( REFERENCE_FIELD ).GetTextAngle() );
  742. newField.SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
  743. m_fields->push_back( newField );
  744. // notify the grid
  745. wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
  746. m_fieldsGrid->ProcessTableMessage( msg );
  747. m_fieldsGrid->MakeCellVisible( (int) m_fields->size() - 1, 0 );
  748. m_fieldsGrid->SetGridCursor( (int) m_fields->size() - 1, 0 );
  749. m_fieldsGrid->EnableCellEditControl();
  750. m_fieldsGrid->ShowCellEditControl();
  751. OnModify();
  752. }
  753. void DIALOG_SYMBOL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
  754. {
  755. wxArrayInt selectedRows = m_fieldsGrid->GetSelectedRows();
  756. if( selectedRows.empty() && m_fieldsGrid->GetGridCursorRow() >= 0 )
  757. selectedRows.push_back( m_fieldsGrid->GetGridCursorRow() );
  758. if( selectedRows.empty() )
  759. return;
  760. for( int row : selectedRows )
  761. {
  762. if( row < MANDATORY_FIELDS )
  763. {
  764. DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
  765. MANDATORY_FIELDS ) );
  766. return;
  767. }
  768. }
  769. m_fieldsGrid->CommitPendingChanges( true /* quiet mode */ );
  770. m_fieldsGrid->ClearSelection();
  771. // Reverse sort so deleting a row doesn't change the indexes of the other rows.
  772. selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
  773. for( int row : selectedRows )
  774. {
  775. m_fields->erase( m_fields->begin() + row );
  776. // notify the grid
  777. wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
  778. m_fieldsGrid->ProcessTableMessage( msg );
  779. if( m_fieldsGrid->GetNumberRows() > 0 )
  780. {
  781. m_fieldsGrid->MakeCellVisible( std::max( 0, row-1 ), m_fieldsGrid->GetGridCursorCol() );
  782. m_fieldsGrid->SetGridCursor( std::max( 0, row-1 ), m_fieldsGrid->GetGridCursorCol() );
  783. }
  784. }
  785. OnModify();
  786. }
  787. void DIALOG_SYMBOL_PROPERTIES::OnMoveUp( wxCommandEvent& event )
  788. {
  789. if( !m_fieldsGrid->CommitPendingChanges() )
  790. return;
  791. int i = m_fieldsGrid->GetGridCursorRow();
  792. if( i > MANDATORY_FIELDS )
  793. {
  794. SCH_FIELD tmp = m_fields->at( (unsigned) i );
  795. m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
  796. m_fields->insert( m_fields->begin() + i - 1, tmp );
  797. m_fieldsGrid->ForceRefresh();
  798. m_fieldsGrid->SetGridCursor( i - 1, m_fieldsGrid->GetGridCursorCol() );
  799. m_fieldsGrid->MakeCellVisible( m_fieldsGrid->GetGridCursorRow(),
  800. m_fieldsGrid->GetGridCursorCol() );
  801. OnModify();
  802. }
  803. else
  804. {
  805. wxBell();
  806. }
  807. }
  808. void DIALOG_SYMBOL_PROPERTIES::OnMoveDown( wxCommandEvent& event )
  809. {
  810. if( !m_fieldsGrid->CommitPendingChanges() )
  811. return;
  812. int i = m_fieldsGrid->GetGridCursorRow();
  813. if( i >= MANDATORY_FIELDS && i < m_fieldsGrid->GetNumberRows() - 1 )
  814. {
  815. SCH_FIELD tmp = m_fields->at( (unsigned) i );
  816. m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
  817. m_fields->insert( m_fields->begin() + i + 1, tmp );
  818. m_fieldsGrid->ForceRefresh();
  819. m_fieldsGrid->SetGridCursor( i + 1, m_fieldsGrid->GetGridCursorCol() );
  820. m_fieldsGrid->MakeCellVisible( m_fieldsGrid->GetGridCursorRow(),
  821. m_fieldsGrid->GetGridCursorCol() );
  822. OnModify();
  823. }
  824. else
  825. {
  826. wxBell();
  827. }
  828. }
  829. void DIALOG_SYMBOL_PROPERTIES::OnEditSymbol( wxCommandEvent& )
  830. {
  831. if( TransferDataFromWindow() )
  832. EndQuasiModal( SYMBOL_PROPS_EDIT_SCHEMATIC_SYMBOL );
  833. }
  834. void DIALOG_SYMBOL_PROPERTIES::OnEditLibrarySymbol( wxCommandEvent& )
  835. {
  836. if( TransferDataFromWindow() )
  837. EndQuasiModal( SYMBOL_PROPS_EDIT_LIBRARY_SYMBOL );
  838. }
  839. void DIALOG_SYMBOL_PROPERTIES::OnUpdateSymbol( wxCommandEvent& )
  840. {
  841. if( TransferDataFromWindow() )
  842. EndQuasiModal( SYMBOL_PROPS_WANT_UPDATE_SYMBOL );
  843. }
  844. void DIALOG_SYMBOL_PROPERTIES::OnExchangeSymbol( wxCommandEvent& )
  845. {
  846. if( TransferDataFromWindow() )
  847. EndQuasiModal( SYMBOL_PROPS_WANT_EXCHANGE_SYMBOL );
  848. }
  849. void DIALOG_SYMBOL_PROPERTIES::OnPinTableCellEdited( wxGridEvent& aEvent )
  850. {
  851. int row = aEvent.GetRow();
  852. if( m_pinGrid->GetCellValue( row, COL_ALT_NAME )
  853. == m_dataModel->GetValue( row, COL_BASE_NAME ) )
  854. {
  855. m_dataModel->SetValue( row, COL_ALT_NAME, wxEmptyString );
  856. }
  857. // These are just to get the cells refreshed
  858. m_dataModel->SetValue( row, COL_TYPE, m_dataModel->GetValue( row, COL_TYPE ) );
  859. m_dataModel->SetValue( row, COL_SHAPE, m_dataModel->GetValue( row, COL_SHAPE ) );
  860. OnModify();
  861. }
  862. void DIALOG_SYMBOL_PROPERTIES::OnPinTableColSort( wxGridEvent& aEvent )
  863. {
  864. int sortCol = aEvent.GetCol();
  865. bool ascending;
  866. // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
  867. // event, and if we ask it will give us pre-event info.
  868. if( m_pinGrid->IsSortingBy( sortCol ) )
  869. // same column; invert ascending
  870. ascending = !m_pinGrid->IsSortOrderAscending();
  871. else
  872. // different column; start with ascending
  873. ascending = true;
  874. m_dataModel->SortRows( sortCol, ascending );
  875. m_dataModel->BuildAttrs();
  876. }
  877. void DIALOG_SYMBOL_PROPERTIES::AdjustFieldsGridColumns()
  878. {
  879. wxGridUpdateLocker deferRepaintsTillLeavingScope( m_fieldsGrid );
  880. // Account for scroll bars
  881. int fieldsWidth = KIPLATFORM::UI::GetUnobscuredSize( m_fieldsGrid ).x;
  882. m_fieldsGrid->AutoSizeColumn( 0 );
  883. m_fieldsGrid->SetColSize( 0, std::max( 72, m_fieldsGrid->GetColSize( 0 ) ) );
  884. int fixedColsWidth = m_fieldsGrid->GetColSize( 0 );
  885. for( int i = 2; i < m_fieldsGrid->GetNumberCols(); i++ )
  886. fixedColsWidth += m_fieldsGrid->GetColSize( i );
  887. m_fieldsGrid->SetColSize( 1, std::max( 120, fieldsWidth - fixedColsWidth ) );
  888. }
  889. void DIALOG_SYMBOL_PROPERTIES::AdjustPinsGridColumns()
  890. {
  891. wxGridUpdateLocker deferRepaintsTillLeavingScope( m_pinGrid );
  892. // Account for scroll bars
  893. int pinTblWidth = KIPLATFORM::UI::GetUnobscuredSize( m_pinGrid ).x;
  894. // Stretch the Base Name and Alternate Assignment columns to fit.
  895. for( int i = 0; i < COL_COUNT; ++i )
  896. {
  897. if( i != COL_BASE_NAME && i != COL_ALT_NAME )
  898. pinTblWidth -= m_pinGrid->GetColSize( i );
  899. }
  900. m_pinGrid->SetColSize( COL_BASE_NAME, pinTblWidth / 2 );
  901. m_pinGrid->SetColSize( COL_ALT_NAME, pinTblWidth / 2 );
  902. }
  903. void DIALOG_SYMBOL_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
  904. {
  905. std::bitset<64> shownColumns = m_fieldsGrid->GetShownColumns();
  906. if( shownColumns != m_shownColumns )
  907. {
  908. m_shownColumns = shownColumns;
  909. if( !m_fieldsGrid->IsCellEditControlShown() )
  910. AdjustFieldsGridColumns();
  911. }
  912. }
  913. void DIALOG_SYMBOL_PROPERTIES::HandleDelayedFocus( wxCommandEvent& event )
  914. {
  915. VECTOR2I *loc = static_cast<VECTOR2I*>( event.GetClientData() );
  916. wxCHECK_RET( loc, wxT( "Missing focus cell location" ) );
  917. // Handle a delayed focus
  918. m_fieldsGrid->SetFocus();
  919. m_fieldsGrid->MakeCellVisible( loc->x, loc->y );
  920. m_fieldsGrid->SetGridCursor( loc->x, loc->y );
  921. m_fieldsGrid->EnableCellEditControl( true );
  922. m_fieldsGrid->ShowCellEditControl();
  923. delete loc;
  924. }
  925. void DIALOG_SYMBOL_PROPERTIES::HandleDelayedSelection( wxCommandEvent& event )
  926. {
  927. // Handle a delayed selection
  928. wxGridCellEditor* cellEditor = m_fieldsGrid->GetCellEditor( REFERENCE_FIELD, FDC_VALUE );
  929. if( wxTextEntry* txt = dynamic_cast<wxTextEntry*>( cellEditor->GetControl() ) )
  930. KIUI::SelectReferenceNumber( txt );
  931. cellEditor->DecRef(); // we're done; must release
  932. }
  933. void DIALOG_SYMBOL_PROPERTIES::OnSizeFieldsGrid( wxSizeEvent& event )
  934. {
  935. wxSize new_size = event.GetSize();
  936. if( ( !m_editorShown || m_lastRequestedSize != new_size ) && m_fieldsSize != new_size )
  937. {
  938. m_fieldsSize = new_size;
  939. AdjustFieldsGridColumns();
  940. }
  941. // We store this value to check whether the dialog is changing size. This might indicate
  942. // that the user is scaling the dialog with an editor shown. Some editors do not close
  943. // (at least on GTK) when the user drags a dialog corner
  944. m_lastRequestedSize = new_size;
  945. // Always propagate for a grid repaint (needed if the height changes, as well as width)
  946. event.Skip();
  947. }
  948. void DIALOG_SYMBOL_PROPERTIES::OnSizePinsGrid( wxSizeEvent& event )
  949. {
  950. wxSize new_size = event.GetSize();
  951. if( m_pinsSize != new_size )
  952. {
  953. m_pinsSize = new_size;
  954. AdjustPinsGridColumns();
  955. }
  956. // Always propagate for a grid repaint (needed if the height changes, as well as width)
  957. event.Skip();
  958. }
  959. void DIALOG_SYMBOL_PROPERTIES::OnInitDlg( wxInitDialogEvent& event )
  960. {
  961. TransferDataToWindow();
  962. // Now all widgets have the size fixed, call FinishDialogSettings
  963. finishDialogSettings();
  964. EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
  965. if( cfg && cfg->m_Appearance.edit_symbol_width > 0 && cfg->m_Appearance.edit_symbol_height > 0 )
  966. SetSize( cfg->m_Appearance.edit_symbol_width, cfg->m_Appearance.edit_symbol_height );
  967. }
  968. void DIALOG_SYMBOL_PROPERTIES::OnCheckBox( wxCommandEvent& event )
  969. {
  970. OnModify();
  971. }
  972. void DIALOG_SYMBOL_PROPERTIES::OnUnitChoice( wxCommandEvent& event )
  973. {
  974. if( m_dataModel )
  975. {
  976. EDA_ITEM_FLAGS flags = m_symbol->GetFlags();
  977. int unit_selection = m_unitChoice->GetSelection() + 1;
  978. // We need to select a new unit to build the new unit pin list
  979. // but we should not change the symbol, so the initial unit will be selected
  980. // after rebuilding the pin list
  981. int old_unit = m_symbol->GetUnit();
  982. m_symbol->SetUnit( unit_selection );
  983. // Rebuild a copy of the pins of the new unit for editing
  984. m_dataModel->clear();
  985. for( const std::unique_ptr<SCH_PIN>& pin : m_symbol->GetRawPins() )
  986. m_dataModel->push_back( *pin );
  987. m_dataModel->SortRows( COL_NUMBER, true );
  988. m_dataModel->BuildAttrs();
  989. m_symbol->SetUnit( old_unit );
  990. // Restore m_Flag modified by SetUnit()
  991. m_symbol->ClearFlags();
  992. m_symbol->SetFlags( flags );
  993. }
  994. OnModify();
  995. }
  996. void DIALOG_SYMBOL_PROPERTIES::onUpdateEditSymbol( wxUpdateUIEvent& event )
  997. {
  998. event.Enable( m_symbol && m_symbol->GetLibSymbolRef() );
  999. }
  1000. void DIALOG_SYMBOL_PROPERTIES::onUpdateEditLibrarySymbol( wxUpdateUIEvent& event )
  1001. {
  1002. event.Enable( m_symbol && m_symbol->GetLibSymbolRef() );
  1003. }