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.

745 lines
23 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018-2022 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 <kiway.h>
  24. #include <kiway_player.h>
  25. #include <dialog_shim.h>
  26. #include <fields_grid_table.h>
  27. #include <sch_base_frame.h>
  28. #include <sch_field.h>
  29. #include <sch_label.h>
  30. #include <sch_validators.h>
  31. #include <validators.h>
  32. #include <sch_edit_frame.h>
  33. #include <netclass.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 <wx/settings.h>
  43. #include <string_utils.h>
  44. #include <widgets/grid_combobox.h>
  45. enum
  46. {
  47. MYID_SELECT_FOOTPRINT = GRIDTRICKS_FIRST_SHOWHIDE - 2, // must be within GRID_TRICKS' enum range
  48. MYID_SHOW_DATASHEET
  49. };
  50. template <class T>
  51. FIELDS_GRID_TABLE<T>::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame,
  52. WX_GRID* aGrid, LIB_SYMBOL* aSymbol ) :
  53. m_frame( aFrame ),
  54. m_dialog( aDialog ),
  55. m_grid( aGrid ),
  56. m_parentType( SCH_SYMBOL_T ),
  57. m_mandatoryFieldCount( MANDATORY_FIELDS ),
  58. m_part( aSymbol ),
  59. m_fieldNameValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_NAME ),
  60. m_referenceValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), REFERENCE_FIELD ),
  61. m_valueValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), VALUE_FIELD ),
  62. m_libIdValidator(),
  63. m_urlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  64. m_nonUrlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  65. m_filepathValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), SHEETFILENAME )
  66. {
  67. initGrid( aGrid );
  68. }
  69. template <class T>
  70. FIELDS_GRID_TABLE<T>::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame,
  71. WX_GRID* aGrid, SCH_SHEET* aSheet ) :
  72. m_frame( aFrame ),
  73. m_dialog( aDialog ),
  74. m_grid( aGrid ),
  75. m_parentType( SCH_SHEET_T ),
  76. m_mandatoryFieldCount( SHEET_MANDATORY_FIELDS ),
  77. m_part( nullptr ),
  78. m_fieldNameValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_NAME ),
  79. m_referenceValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), SHEETNAME_V ),
  80. m_valueValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), VALUE_FIELD ),
  81. m_libIdValidator(),
  82. m_urlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  83. m_nonUrlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  84. m_filepathValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), SHEETFILENAME_V )
  85. {
  86. initGrid( aGrid );
  87. }
  88. template <class T>
  89. FIELDS_GRID_TABLE<T>::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame,
  90. WX_GRID* aGrid, SCH_LABEL_BASE* aLabel ) :
  91. m_frame( aFrame ),
  92. m_dialog( aDialog ),
  93. m_grid( aGrid ),
  94. m_parentType( SCH_LABEL_LOCATE_ANY_T ),
  95. m_mandatoryFieldCount( aLabel->GetMandatoryFieldCount() ),
  96. m_part( nullptr ),
  97. m_fieldNameValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_NAME ),
  98. m_referenceValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), 0 ),
  99. m_valueValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), 0 ),
  100. m_libIdValidator(),
  101. m_urlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  102. m_nonUrlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  103. m_filepathValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), 0 )
  104. {
  105. initGrid( aGrid );
  106. }
  107. template <class T>
  108. void FIELDS_GRID_TABLE<T>::initGrid( WX_GRID* aGrid )
  109. {
  110. // Build the various grid cell attributes.
  111. // NOTE: validators and cellAttrs are member variables to get the destruction order
  112. // right. wxGrid is VERY cranky about this.
  113. m_readOnlyAttr = new wxGridCellAttr;
  114. m_readOnlyAttr->SetReadOnly( true );
  115. m_fieldNameAttr = new wxGridCellAttr;
  116. GRID_CELL_TEXT_EDITOR* nameEditor = new GRID_CELL_TEXT_EDITOR();
  117. nameEditor->SetValidator( m_fieldNameValidator );
  118. m_fieldNameAttr->SetEditor( nameEditor );
  119. m_referenceAttr = new wxGridCellAttr;
  120. GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR();
  121. referenceEditor->SetValidator( m_referenceValidator );
  122. m_referenceAttr->SetEditor( referenceEditor );
  123. m_valueAttr = new wxGridCellAttr;
  124. GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
  125. valueEditor->SetValidator( m_valueValidator );
  126. m_valueAttr->SetEditor( valueEditor );
  127. m_footprintAttr = new wxGridCellAttr;
  128. GRID_CELL_FOOTPRINT_ID_EDITOR* fpIdEditor = new GRID_CELL_FOOTPRINT_ID_EDITOR( m_dialog );
  129. fpIdEditor->SetValidator( m_libIdValidator );
  130. m_footprintAttr->SetEditor( fpIdEditor );
  131. m_urlAttr = new wxGridCellAttr;
  132. GRID_CELL_URL_EDITOR* urlEditor = new GRID_CELL_URL_EDITOR( m_dialog );
  133. urlEditor->SetValidator( m_urlValidator );
  134. m_urlAttr->SetEditor( urlEditor );
  135. m_nonUrlAttr = new wxGridCellAttr;
  136. GRID_CELL_TEXT_EDITOR* nonUrlEditor = new GRID_CELL_TEXT_EDITOR();
  137. nonUrlEditor->SetValidator( m_nonUrlValidator );
  138. m_nonUrlAttr->SetEditor( nonUrlEditor );
  139. m_curdir = m_frame->Prj().GetProjectPath();
  140. m_filepathAttr = new wxGridCellAttr;
  141. // Create a wild card using wxFileDialog syntax.
  142. wxString wildCard( _( "Schematic Files" ) );
  143. std::vector<std::string> exts;
  144. exts.push_back( KiCadSchematicFileExtension );
  145. wildCard += AddFileExtListToFilter( exts );
  146. auto filepathEditor = new GRID_CELL_PATH_EDITOR( m_dialog, aGrid, &m_curdir, wildCard );
  147. filepathEditor->SetValidator( m_filepathValidator );
  148. m_filepathAttr->SetEditor( filepathEditor );
  149. m_boolAttr = new wxGridCellAttr;
  150. m_boolAttr->SetRenderer( new wxGridCellBoolRenderer() );
  151. m_boolAttr->SetEditor( new wxGridCellBoolEditor() );
  152. m_boolAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  153. wxArrayString vAlignNames;
  154. vAlignNames.Add( _( "Top" ) );
  155. vAlignNames.Add( _( "Center" ) );
  156. vAlignNames.Add( _( "Bottom" ) );
  157. m_vAlignAttr = new wxGridCellAttr;
  158. m_vAlignAttr->SetEditor( new wxGridCellChoiceEditor( vAlignNames ) );
  159. m_vAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  160. wxArrayString hAlignNames;
  161. hAlignNames.Add( _( "Left" ) );
  162. hAlignNames.Add(_( "Center" ) );
  163. hAlignNames.Add(_( "Right" ) );
  164. m_hAlignAttr = new wxGridCellAttr;
  165. m_hAlignAttr->SetEditor( new wxGridCellChoiceEditor( hAlignNames ) );
  166. m_hAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  167. wxArrayString orientationNames;
  168. orientationNames.Add( _( "Horizontal" ) );
  169. orientationNames.Add(_( "Vertical" ) );
  170. m_orientationAttr = new wxGridCellAttr;
  171. m_orientationAttr->SetEditor( new wxGridCellChoiceEditor( orientationNames ) );
  172. m_orientationAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  173. SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
  174. wxArrayString existingNetclasses;
  175. if( editFrame )
  176. {
  177. // Load the combobox with existing existingNetclassNames
  178. NET_SETTINGS& netSettings = editFrame->Schematic().Prj().GetProjectFile().NetSettings();
  179. existingNetclasses.push_back( netSettings.m_NetClasses.GetDefault()->GetName() );
  180. for( const std::pair<const wxString, NETCLASSPTR>& pair : netSettings.m_NetClasses )
  181. existingNetclasses.push_back( pair.second->GetName() );
  182. }
  183. m_netclassAttr = new wxGridCellAttr;
  184. m_netclassAttr->SetEditor( new GRID_CELL_COMBOBOX( existingNetclasses ) );
  185. m_frame->Bind( UNITS_CHANGED, &FIELDS_GRID_TABLE<T>::onUnitsChanged, this );
  186. }
  187. template <class T>
  188. FIELDS_GRID_TABLE<T>::~FIELDS_GRID_TABLE()
  189. {
  190. m_readOnlyAttr->DecRef();
  191. m_fieldNameAttr->DecRef();
  192. m_boolAttr->DecRef();
  193. m_referenceAttr->DecRef();
  194. m_valueAttr->DecRef();
  195. m_footprintAttr->DecRef();
  196. m_urlAttr->DecRef();
  197. m_nonUrlAttr->DecRef();
  198. m_filepathAttr->DecRef();
  199. m_vAlignAttr->DecRef();
  200. m_hAlignAttr->DecRef();
  201. m_orientationAttr->DecRef();
  202. m_netclassAttr->DecRef();
  203. m_frame->Unbind( UNITS_CHANGED, &FIELDS_GRID_TABLE<T>::onUnitsChanged, this );
  204. }
  205. template <class T>
  206. void FIELDS_GRID_TABLE<T>::onUnitsChanged( wxCommandEvent& aEvent )
  207. {
  208. if( GetView() )
  209. GetView()->ForceRefresh();
  210. aEvent.Skip();
  211. }
  212. template <class T>
  213. wxString FIELDS_GRID_TABLE<T>::GetColLabelValue( int aCol )
  214. {
  215. switch( aCol )
  216. {
  217. case FDC_NAME: return _( "Name" );
  218. case FDC_VALUE: return _( "Value" );
  219. case FDC_SHOWN: return _( "Show" );
  220. case FDC_H_ALIGN: return _( "H Align" );
  221. case FDC_V_ALIGN: return _( "V Align" );
  222. case FDC_ITALIC: return _( "Italic" );
  223. case FDC_BOLD: return _( "Bold" );
  224. case FDC_TEXT_SIZE: return _( "Text Size" );
  225. case FDC_ORIENTATION: return _( "Orientation" );
  226. case FDC_POSX: return _( "X Position" );
  227. case FDC_POSY: return _( "Y Position" );
  228. default: wxFAIL; return wxEmptyString;
  229. }
  230. }
  231. template <class T>
  232. bool FIELDS_GRID_TABLE<T>::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
  233. {
  234. switch( aCol )
  235. {
  236. case FDC_NAME:
  237. case FDC_VALUE:
  238. case FDC_H_ALIGN:
  239. case FDC_V_ALIGN:
  240. case FDC_TEXT_SIZE:
  241. case FDC_ORIENTATION:
  242. case FDC_POSX:
  243. case FDC_POSY:
  244. return aTypeName == wxGRID_VALUE_STRING;
  245. case FDC_SHOWN:
  246. case FDC_ITALIC:
  247. case FDC_BOLD:
  248. return aTypeName == wxGRID_VALUE_BOOL;
  249. default:
  250. wxFAIL;
  251. return false;
  252. }
  253. }
  254. template <class T>
  255. bool FIELDS_GRID_TABLE<T>::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
  256. {
  257. return CanGetValueAs( aRow, aCol, aTypeName );
  258. }
  259. template <class T>
  260. wxGridCellAttr* FIELDS_GRID_TABLE<T>::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind )
  261. {
  262. wxGridCellAttr* tmp;
  263. switch( aCol )
  264. {
  265. case FDC_NAME:
  266. if( aRow < m_mandatoryFieldCount )
  267. {
  268. tmp = m_fieldNameAttr->Clone();
  269. tmp->SetReadOnly( true );
  270. return tmp;
  271. }
  272. else
  273. {
  274. m_fieldNameAttr->IncRef();
  275. return m_fieldNameAttr;
  276. }
  277. case FDC_VALUE:
  278. if( m_parentType == SCH_SYMBOL_T && aRow == REFERENCE_FIELD )
  279. {
  280. m_referenceAttr->IncRef();
  281. return m_referenceAttr;
  282. }
  283. else if( m_parentType == SCH_SYMBOL_T && aRow == VALUE_FIELD )
  284. {
  285. // For power symbols, the value is not editable, because value and pin name must
  286. // be the same and can be edited only in library editor.
  287. if( ( m_part && m_part->IsPower() && !m_frame->IsType( FRAME_SCH_SYMBOL_EDITOR ) ) )
  288. {
  289. tmp = m_readOnlyAttr->Clone();
  290. tmp->SetReadOnly( true );
  291. tmp->SetTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
  292. return tmp;
  293. }
  294. else
  295. {
  296. m_valueAttr->IncRef();
  297. return m_valueAttr;
  298. }
  299. }
  300. else if( m_parentType == SCH_SYMBOL_T && aRow == FOOTPRINT_FIELD )
  301. {
  302. m_footprintAttr->IncRef();
  303. return m_footprintAttr;
  304. }
  305. else if( m_parentType == SCH_SYMBOL_T && aRow == DATASHEET_FIELD )
  306. {
  307. m_urlAttr->IncRef();
  308. return m_urlAttr;
  309. }
  310. else if( m_parentType == SCH_SHEET_T && aRow == SHEETNAME )
  311. {
  312. m_referenceAttr->IncRef();
  313. return m_referenceAttr;
  314. }
  315. else if( m_parentType == SCH_SHEET_T && aRow == SHEETFILENAME )
  316. {
  317. m_filepathAttr->IncRef();
  318. return m_filepathAttr;
  319. }
  320. else if( ( m_parentType == SCH_LABEL_LOCATE_ANY_T )
  321. && this->at( (size_t) aRow ).GetCanonicalName() == wxT( "Netclass" ) )
  322. {
  323. m_netclassAttr->IncRef();
  324. return m_netclassAttr;
  325. }
  326. else
  327. {
  328. wxString fn = GetValue( aRow, FDC_NAME );
  329. SCHEMATIC_SETTINGS* settings = m_frame->Prj().GetProjectFile().m_SchematicSettings;
  330. const TEMPLATE_FIELDNAME* templateFn =
  331. settings ? settings->m_TemplateFieldNames.GetFieldName( fn ) : nullptr;
  332. if( templateFn && templateFn->m_URL )
  333. {
  334. m_urlAttr->IncRef();
  335. return m_urlAttr;
  336. }
  337. else
  338. {
  339. m_nonUrlAttr->IncRef();
  340. return m_nonUrlAttr;
  341. }
  342. }
  343. case FDC_TEXT_SIZE:
  344. case FDC_POSX:
  345. case FDC_POSY:
  346. return nullptr;
  347. case FDC_H_ALIGN:
  348. m_hAlignAttr->IncRef();
  349. return m_hAlignAttr;
  350. case FDC_V_ALIGN:
  351. m_vAlignAttr->IncRef();
  352. return m_vAlignAttr;
  353. case FDC_ORIENTATION:
  354. m_orientationAttr->IncRef();
  355. return m_orientationAttr;
  356. case FDC_SHOWN:
  357. case FDC_ITALIC:
  358. case FDC_BOLD:
  359. m_boolAttr->IncRef();
  360. return m_boolAttr;
  361. default:
  362. wxFAIL;
  363. return nullptr;
  364. }
  365. }
  366. template <class T>
  367. wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
  368. {
  369. wxCHECK( aRow < GetNumberRows(), wxEmptyString );
  370. const T& field = this->at( (size_t) aRow );
  371. switch( aCol )
  372. {
  373. case FDC_NAME:
  374. // Use default field names for mandatory and system fields because they are translated
  375. // according to the current locale
  376. if( m_parentType == SCH_SYMBOL_T )
  377. {
  378. if( aRow < m_mandatoryFieldCount )
  379. return TEMPLATE_FIELDNAME::GetDefaultFieldName( aRow );
  380. else
  381. return field.GetName( false );
  382. }
  383. else if( m_parentType == SCH_SHEET_T )
  384. {
  385. if( aRow < m_mandatoryFieldCount )
  386. return SCH_SHEET::GetDefaultFieldName( aRow );
  387. else
  388. return field.GetName( false );
  389. }
  390. else if( m_parentType == SCH_LABEL_LOCATE_ANY_T )
  391. {
  392. return SCH_LABEL_BASE::GetDefaultFieldName( field.GetCanonicalName(), false );
  393. }
  394. else
  395. {
  396. wxFAIL_MSG( "Unhandled field owner type." );
  397. return field.GetName( false );
  398. }
  399. case FDC_VALUE:
  400. return UnescapeString( field.GetText() );
  401. case FDC_SHOWN:
  402. return StringFromBool( field.IsVisible() );
  403. case FDC_H_ALIGN:
  404. switch ( field.GetHorizJustify() )
  405. {
  406. case GR_TEXT_H_ALIGN_LEFT: return _( "Left" );
  407. case GR_TEXT_H_ALIGN_CENTER: return _( "Center" );
  408. case GR_TEXT_H_ALIGN_RIGHT: return _( "Right" );
  409. }
  410. break;
  411. case FDC_V_ALIGN:
  412. switch ( field.GetVertJustify() )
  413. {
  414. case GR_TEXT_V_ALIGN_TOP: return _( "Top" );
  415. case GR_TEXT_V_ALIGN_CENTER: return _( "Center" );
  416. case GR_TEXT_V_ALIGN_BOTTOM: return _( "Bottom" );
  417. }
  418. break;
  419. case FDC_ITALIC:
  420. return StringFromBool( field.IsItalic() );
  421. case FDC_BOLD:
  422. return StringFromBool( field.IsBold() );
  423. case FDC_TEXT_SIZE:
  424. return StringFromValue( m_frame->GetUserUnits(), field.GetTextSize().GetHeight(), true );
  425. case FDC_ORIENTATION:
  426. if( field.GetTextAngle().IsHorizontal() )
  427. return _( "Horizontal" );
  428. else
  429. return _( "Vertical" );
  430. case FDC_POSX:
  431. return StringFromValue( m_frame->GetUserUnits(), field.GetTextPos().x, true );
  432. case FDC_POSY:
  433. return StringFromValue( m_frame->GetUserUnits(), field.GetTextPos().y, true );
  434. default:
  435. // we can't assert here because wxWidgets sometimes calls this without checking
  436. // the column type when trying to see if there's an overflow
  437. break;
  438. }
  439. return wxT( "bad wxWidgets!" );
  440. }
  441. template <class T>
  442. bool FIELDS_GRID_TABLE<T>::GetValueAsBool( int aRow, int aCol )
  443. {
  444. wxCHECK( aRow < GetNumberRows(), false );
  445. const T& field = this->at( (size_t) aRow );
  446. switch( aCol )
  447. {
  448. case FDC_SHOWN: return field.IsVisible();
  449. case FDC_ITALIC: return field.IsItalic();
  450. case FDC_BOLD: return field.IsBold();
  451. default:
  452. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  453. return false;
  454. }
  455. }
  456. template <class T>
  457. void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue )
  458. {
  459. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  460. T& field = this->at( (size_t) aRow );
  461. VECTOR2I pos;
  462. switch( aCol )
  463. {
  464. case FDC_NAME:
  465. field.SetName( aValue );
  466. break;
  467. case FDC_VALUE:
  468. {
  469. wxString value( aValue );
  470. if( m_parentType == SCH_SHEET_T && aRow == SHEETFILENAME )
  471. {
  472. wxFileName fn( value );
  473. // It's annoying to throw up nag dialogs when the extension isn't right. Just
  474. // fix it.
  475. if( fn.GetExt().CmpNoCase( KiCadSchematicFileExtension ) != 0 )
  476. {
  477. fn.SetExt( KiCadSchematicFileExtension );
  478. value = fn.GetFullPath();
  479. }
  480. }
  481. else if( m_frame->IsType( FRAME_SCH_SYMBOL_EDITOR ) && aRow == VALUE_FIELD )
  482. {
  483. value = EscapeString( value, CTX_LIBID );
  484. }
  485. field.SetText( value );
  486. }
  487. break;
  488. case FDC_SHOWN:
  489. field.SetVisible( BoolFromString( aValue ) );
  490. break;
  491. case FDC_H_ALIGN:
  492. if( aValue == _( "Left" ) )
  493. field.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  494. else if( aValue == _( "Center" ) )
  495. field.SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
  496. else if( aValue == _( "Right" ) )
  497. field.SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  498. else
  499. wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + aValue );
  500. break;
  501. case FDC_V_ALIGN:
  502. if( aValue == _( "Top" ) )
  503. field.SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  504. else if( aValue == _( "Center" ) )
  505. field.SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
  506. else if( aValue == _( "Bottom" ) )
  507. field.SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  508. else
  509. wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + aValue);
  510. break;
  511. case FDC_ITALIC:
  512. field.SetItalic( BoolFromString( aValue ) );
  513. break;
  514. case FDC_BOLD:
  515. field.SetBold( BoolFromString( aValue ) );
  516. break;
  517. case FDC_TEXT_SIZE:
  518. field.SetTextSize( wxSize( ValueFromString( m_frame->GetUserUnits(), aValue ),
  519. ValueFromString( m_frame->GetUserUnits(), aValue ) ) );
  520. break;
  521. case FDC_ORIENTATION:
  522. if( aValue == _( "Horizontal" ) )
  523. field.SetTextAngle( ANGLE_HORIZONTAL );
  524. else if( aValue == _( "Vertical" ) )
  525. field.SetTextAngle( ANGLE_VERTICAL );
  526. else
  527. wxFAIL_MSG( wxT( "unknown orientation: " ) + aValue );
  528. break;
  529. case FDC_POSX:
  530. case FDC_POSY:
  531. pos = field.GetTextPos();
  532. if( aCol == FDC_POSX )
  533. pos.x = ValueFromString( m_frame->GetUserUnits(), aValue );
  534. else
  535. pos.y = ValueFromString( m_frame->GetUserUnits(), aValue );
  536. field.SetTextPos( pos );
  537. break;
  538. default:
  539. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
  540. break;
  541. }
  542. m_dialog->OnModify();
  543. GetView()->Refresh();
  544. }
  545. template <class T>
  546. void FIELDS_GRID_TABLE<T>::SetValueAsBool( int aRow, int aCol, bool aValue )
  547. {
  548. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  549. T& field = this->at( (size_t) aRow );
  550. switch( aCol )
  551. {
  552. case FDC_SHOWN:
  553. field.SetVisible( aValue );
  554. break;
  555. case FDC_ITALIC:
  556. field.SetItalic( aValue );
  557. break;
  558. case FDC_BOLD:
  559. field.SetBold( aValue );
  560. break;
  561. default:
  562. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  563. break;
  564. }
  565. m_dialog->OnModify();
  566. }
  567. // Explicit Instantiations
  568. template class FIELDS_GRID_TABLE<SCH_FIELD>;
  569. template class FIELDS_GRID_TABLE<LIB_FIELD>;
  570. void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu )
  571. {
  572. if( m_grid->GetGridCursorRow() == FOOTPRINT_FIELD && m_grid->GetGridCursorCol() == FDC_VALUE )
  573. {
  574. menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
  575. _( "Browse for footprint" ) );
  576. menu.AppendSeparator();
  577. }
  578. else if( m_grid->GetGridCursorRow() == DATASHEET_FIELD && m_grid->GetGridCursorCol() == FDC_VALUE )
  579. {
  580. menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
  581. _( "Show datasheet in browser" ) );
  582. menu.AppendSeparator();
  583. }
  584. GRID_TRICKS::showPopupMenu( menu );
  585. }
  586. void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
  587. {
  588. if( event.GetId() == MYID_SELECT_FOOTPRINT )
  589. {
  590. // pick a footprint using the footprint picker.
  591. wxString fpid = m_grid->GetCellValue( FOOTPRINT_FIELD, FDC_VALUE );
  592. KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true, m_dlg );
  593. if( frame->ShowModal( &fpid, m_dlg ) )
  594. m_grid->SetCellValue( FOOTPRINT_FIELD, FDC_VALUE, fpid );
  595. frame->Destroy();
  596. }
  597. else if (event.GetId() == MYID_SHOW_DATASHEET )
  598. {
  599. wxString datasheet_uri = m_grid->GetCellValue( DATASHEET_FIELD, FDC_VALUE );
  600. GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj() );
  601. }
  602. else
  603. {
  604. GRID_TRICKS::doPopupSelection( event );
  605. }
  606. }
  607. template <class T>
  608. wxString FIELDS_GRID_TABLE<T>::StringFromBool( bool aValue ) const
  609. {
  610. if( aValue )
  611. return wxT( "1" );
  612. else
  613. return wxT( "0" );
  614. }
  615. template <class T>
  616. bool FIELDS_GRID_TABLE<T>::BoolFromString( wxString aValue ) const
  617. {
  618. if( aValue == "1" )
  619. {
  620. return true;
  621. }
  622. else if( aValue == "0" )
  623. {
  624. return false;
  625. }
  626. else
  627. {
  628. wxFAIL_MSG( wxString::Format( "string '%s' can't be converted to boolean correctly and "
  629. "will be perceived as FALSE", aValue ) );
  630. return false;
  631. }
  632. }