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.

461 lines
12 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_player.h>
  24. #include <project.h>
  25. #include <fp_text_grid_table.h>
  26. #include <widgets/grid_icon_text_helpers.h>
  27. #include <widgets/grid_combobox.h>
  28. #include <trigo.h>
  29. #include <pcb_base_frame.h>
  30. #include <footprint.h>
  31. #include "grid_layer_box_helpers.h"
  32. #include "widgets/grid_text_button_helpers.h"
  33. enum
  34. {
  35. MYID_SELECT_FOOTPRINT = 991, // must be within GRID_TRICKS' enum range
  36. MYID_SHOW_DATASHEET
  37. };
  38. wxArrayString g_menuOrientations;
  39. FP_TEXT_GRID_TABLE::FP_TEXT_GRID_TABLE( PCB_BASE_FRAME* aFrame, DIALOG_SHIM* aDialog ) :
  40. m_frame( aFrame ),
  41. m_dialog( aDialog ),
  42. m_fieldNameValidator( FIELD_NAME ),
  43. m_referenceValidator( REFERENCE_FIELD ),
  44. m_valueValidator( VALUE_FIELD ),
  45. m_urlValidator( FIELD_VALUE ),
  46. m_nonUrlValidator( FIELD_VALUE )
  47. {
  48. // Build the column attributes.
  49. m_readOnlyAttr = new wxGridCellAttr;
  50. m_readOnlyAttr->SetReadOnly( true );
  51. m_boolColAttr = new wxGridCellAttr;
  52. m_boolColAttr->SetRenderer( new wxGridCellBoolRenderer() );
  53. m_boolColAttr->SetEditor( new wxGridCellBoolEditor() );
  54. m_boolColAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  55. if( g_menuOrientations.IsEmpty() )
  56. {
  57. g_menuOrientations.push_back( "0" + EDA_UNIT_UTILS::GetText( EDA_UNITS::DEGREES ) );
  58. g_menuOrientations.push_back( "90" + EDA_UNIT_UTILS::GetText( EDA_UNITS::DEGREES ) );
  59. g_menuOrientations.push_back( "-90" + EDA_UNIT_UTILS::GetText( EDA_UNITS::DEGREES ) );
  60. g_menuOrientations.push_back( "180" + EDA_UNIT_UTILS::GetText( EDA_UNITS::DEGREES ) );
  61. }
  62. m_orientationColAttr = new wxGridCellAttr;
  63. m_orientationColAttr->SetEditor( new GRID_CELL_COMBOBOX( g_menuOrientations ) );
  64. m_layerColAttr = new wxGridCellAttr;
  65. m_layerColAttr->SetRenderer( new GRID_CELL_LAYER_RENDERER( m_frame ) );
  66. m_layerColAttr->SetEditor( new GRID_CELL_LAYER_SELECTOR( m_frame, {} ) );
  67. m_referenceAttr = new wxGridCellAttr;
  68. GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR();
  69. referenceEditor->SetValidator( m_referenceValidator );
  70. m_referenceAttr->SetEditor( referenceEditor );
  71. m_valueAttr = new wxGridCellAttr;
  72. GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
  73. valueEditor->SetValidator( m_valueValidator );
  74. m_valueAttr->SetEditor( valueEditor );
  75. m_footprintAttr = new wxGridCellAttr;
  76. m_footprintAttr->SetReadOnly( true );
  77. GRID_CELL_FPID_EDITOR* fpIdEditor = new GRID_CELL_FPID_EDITOR( m_dialog, "" );
  78. fpIdEditor->SetValidator( m_nonUrlValidator );
  79. m_footprintAttr->SetEditor( fpIdEditor );
  80. m_urlAttr = new wxGridCellAttr;
  81. GRID_CELL_URL_EDITOR* urlEditor = new GRID_CELL_URL_EDITOR( m_dialog );
  82. urlEditor->SetValidator( m_urlValidator );
  83. m_urlAttr->SetEditor( urlEditor );
  84. m_eval = std::make_unique<NUMERIC_EVALUATOR>( m_frame->GetUserUnits() );
  85. m_frame->Bind( EDA_EVT_UNITS_CHANGED, &FP_TEXT_GRID_TABLE::onUnitsChanged, this );
  86. }
  87. FP_TEXT_GRID_TABLE::~FP_TEXT_GRID_TABLE()
  88. {
  89. m_readOnlyAttr->DecRef();
  90. m_boolColAttr->DecRef();
  91. m_orientationColAttr->DecRef();
  92. m_layerColAttr->DecRef();
  93. m_referenceAttr->DecRef();
  94. m_valueAttr->DecRef();
  95. m_footprintAttr->DecRef();
  96. m_urlAttr->DecRef();
  97. m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &FP_TEXT_GRID_TABLE::onUnitsChanged, this );
  98. }
  99. void FP_TEXT_GRID_TABLE::onUnitsChanged( wxCommandEvent& aEvent )
  100. {
  101. if( GetView() )
  102. GetView()->ForceRefresh();
  103. aEvent.Skip();
  104. }
  105. wxString FP_TEXT_GRID_TABLE::GetColLabelValue( int aCol )
  106. {
  107. switch( aCol )
  108. {
  109. case FPT_NAME: return _( "Name" );
  110. case FPT_VALUE: return _( "Value" );
  111. case FPT_SHOWN: return _( "Show" );
  112. case FPT_WIDTH: return _( "Width" );
  113. case FPT_HEIGHT: return _( "Height" );
  114. case FPT_THICKNESS: return _( "Thickness" );
  115. case FPT_ITALIC: return _( "Italic" );
  116. case FPT_LAYER: return _( "Layer" );
  117. case FPT_ORIENTATION: return _( "Orientation" );
  118. case FPT_UPRIGHT: return _( "Keep Upright" );
  119. case FPT_XOFFSET: return _( "X Offset" );
  120. case FPT_YOFFSET: return _( "Y Offset" );
  121. case FPT_KNOCKOUT: return _( "Knockout" );
  122. default: wxFAIL; return wxEmptyString;
  123. }
  124. }
  125. bool FP_TEXT_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
  126. {
  127. switch( aCol )
  128. {
  129. case FPT_NAME:
  130. case FPT_VALUE:
  131. case FPT_WIDTH:
  132. case FPT_HEIGHT:
  133. case FPT_THICKNESS:
  134. case FPT_ORIENTATION:
  135. case FPT_XOFFSET:
  136. case FPT_YOFFSET:
  137. return aTypeName == wxGRID_VALUE_STRING;
  138. case FPT_SHOWN:
  139. case FPT_ITALIC:
  140. case FPT_UPRIGHT:
  141. case FPT_KNOCKOUT:
  142. return aTypeName == wxGRID_VALUE_BOOL;
  143. case FPT_LAYER:
  144. return aTypeName == wxGRID_VALUE_NUMBER;
  145. default:
  146. wxFAIL;
  147. return false;
  148. }
  149. }
  150. bool FP_TEXT_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
  151. {
  152. return CanGetValueAs( aRow, aCol, aTypeName );
  153. }
  154. wxGridCellAttr* FP_TEXT_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind )
  155. {
  156. switch( aCol )
  157. {
  158. case FPT_NAME:
  159. if( aRow < MANDATORY_FIELDS )
  160. {
  161. m_readOnlyAttr->IncRef();
  162. return m_readOnlyAttr;
  163. }
  164. return nullptr;
  165. case FPT_VALUE:
  166. if( aRow == REFERENCE_FIELD )
  167. {
  168. m_referenceAttr->IncRef();
  169. return m_referenceAttr;
  170. }
  171. else if( aRow == VALUE_FIELD )
  172. {
  173. m_valueAttr->IncRef();
  174. return m_valueAttr;
  175. }
  176. else if( aRow == FOOTPRINT_FIELD )
  177. {
  178. m_footprintAttr->IncRef();
  179. return m_footprintAttr;
  180. }
  181. else if( aRow == DATASHEET_FIELD )
  182. {
  183. m_urlAttr->IncRef();
  184. return m_urlAttr;
  185. }
  186. return nullptr;
  187. case FPT_WIDTH:
  188. case FPT_HEIGHT:
  189. case FPT_THICKNESS:
  190. case FPT_XOFFSET:
  191. case FPT_YOFFSET:
  192. return nullptr;
  193. case FPT_SHOWN:
  194. case FPT_ITALIC:
  195. case FPT_UPRIGHT:
  196. case FPT_KNOCKOUT:
  197. m_boolColAttr->IncRef();
  198. return m_boolColAttr;
  199. case FPT_LAYER:
  200. m_layerColAttr->IncRef();
  201. return m_layerColAttr;
  202. case FPT_ORIENTATION:
  203. m_orientationColAttr->IncRef();
  204. return m_orientationColAttr;
  205. default:
  206. wxFAIL;
  207. return nullptr;
  208. }
  209. }
  210. wxString FP_TEXT_GRID_TABLE::GetValue( int aRow, int aCol )
  211. {
  212. wxGrid* grid = GetView();
  213. const PCB_FIELD* field = this->at( (size_t) aRow );
  214. if( grid->GetGridCursorRow() == aRow && grid->GetGridCursorCol() == aCol
  215. && grid->IsCellEditControlShown() )
  216. {
  217. auto it = m_evalOriginal.find( { aRow, aCol } );
  218. if( it != m_evalOriginal.end() )
  219. return it->second;
  220. }
  221. switch( aCol )
  222. {
  223. case FPT_NAME:
  224. return field->GetName();
  225. case FPT_VALUE:
  226. return field->GetText();
  227. case FPT_WIDTH:
  228. return m_frame->StringFromValue( field->GetTextWidth(), true );
  229. case FPT_HEIGHT:
  230. return m_frame->StringFromValue( field->GetTextHeight(), true );
  231. case FPT_THICKNESS:
  232. return m_frame->StringFromValue( field->GetTextThickness(), true );
  233. case FPT_LAYER:
  234. return field->GetLayerName();
  235. case FPT_ORIENTATION:
  236. {
  237. EDA_ANGLE angle = field->GetTextAngle() - field->GetParentFootprint()->GetOrientation();
  238. return m_frame->StringFromValue( angle, true );
  239. }
  240. case FPT_XOFFSET:
  241. return m_frame->StringFromValue( field->GetFPRelativePosition().x, true );
  242. case FPT_YOFFSET:
  243. return m_frame->StringFromValue( field->GetFPRelativePosition().y, true );
  244. default:
  245. // we can't assert here because wxWidgets sometimes calls this without checking
  246. // the column type when trying to see if there's an overflow
  247. return wxT( "bad wxWidgets!" );
  248. }
  249. }
  250. bool FP_TEXT_GRID_TABLE::GetValueAsBool( int aRow, int aCol )
  251. {
  252. PCB_FIELD* field = this->at( (size_t) aRow );
  253. switch( aCol )
  254. {
  255. case FPT_SHOWN: return field->IsVisible();
  256. case FPT_ITALIC: return field->IsItalic();
  257. case FPT_UPRIGHT: return field->IsKeepUpright();
  258. case FPT_KNOCKOUT: return field->IsKnockout();
  259. default:
  260. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  261. return false;
  262. }
  263. }
  264. long FP_TEXT_GRID_TABLE::GetValueAsLong( int aRow, int aCol )
  265. {
  266. PCB_FIELD* field = this->at( (size_t) aRow );
  267. switch( aCol )
  268. {
  269. case FPT_LAYER: return field->GetLayer();
  270. default:
  271. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a long value" ), aCol ) );
  272. return 0;
  273. }
  274. }
  275. void FP_TEXT_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
  276. {
  277. PCB_FIELD* field = this->at( (size_t) aRow );
  278. VECTOR2I pos;
  279. wxString value = aValue;
  280. switch( aCol )
  281. {
  282. case FPT_WIDTH:
  283. case FPT_HEIGHT:
  284. case FPT_THICKNESS:
  285. case FPT_XOFFSET:
  286. case FPT_YOFFSET:
  287. m_eval->SetDefaultUnits( m_frame->GetUserUnits() );
  288. if( m_eval->Process( value ) )
  289. {
  290. m_evalOriginal[ { aRow, aCol } ] = value;
  291. value = m_eval->Result();
  292. }
  293. break;
  294. default:
  295. break;
  296. }
  297. switch( aCol )
  298. {
  299. case FPT_NAME:
  300. field->SetName( value );
  301. break;
  302. case FPT_VALUE:
  303. field->SetText( value );
  304. break;
  305. case FPT_WIDTH:
  306. field->SetTextWidth( m_frame->ValueFromString( value ) );
  307. break;
  308. case FPT_HEIGHT:
  309. field->SetTextHeight( m_frame->ValueFromString( value ) );
  310. break;
  311. case FPT_THICKNESS:
  312. field->SetTextThickness( m_frame->ValueFromString( value ) );
  313. break;
  314. case FPT_ORIENTATION:
  315. field->SetTextAngle( m_frame->AngleValueFromString( value )
  316. + field->GetParentFootprint()->GetOrientation() );
  317. break;
  318. case FPT_XOFFSET:
  319. case FPT_YOFFSET:
  320. pos = field->GetFPRelativePosition();
  321. if( aCol == FPT_XOFFSET )
  322. pos.x = m_frame->ValueFromString( value );
  323. else
  324. pos.y = m_frame->ValueFromString( value );
  325. field->SetFPRelativePosition( pos );
  326. break;
  327. default:
  328. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
  329. break;
  330. }
  331. GetView()->Refresh();
  332. }
  333. void FP_TEXT_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue )
  334. {
  335. PCB_FIELD* field = this->at( (size_t) aRow );
  336. switch( aCol )
  337. {
  338. case FPT_SHOWN:
  339. field->SetVisible( aValue );
  340. break;
  341. case FPT_ITALIC:
  342. field->SetItalic( aValue );
  343. break;
  344. case FPT_UPRIGHT:
  345. field->SetKeepUpright( aValue );
  346. break;
  347. case FPT_KNOCKOUT:
  348. field->SetIsKnockout( aValue );
  349. break;
  350. default:
  351. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  352. break;
  353. }
  354. }
  355. void FP_TEXT_GRID_TABLE::SetValueAsLong( int aRow, int aCol, long aValue )
  356. {
  357. PCB_FIELD* field = this->at( (size_t) aRow );
  358. switch( aCol )
  359. {
  360. case FPT_LAYER:
  361. field->SetLayer( ToLAYER_ID( (int) aValue ) );
  362. field->SetMirrored( IsBackLayer( field->GetLayer() ) );
  363. break;
  364. default:
  365. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a long value" ), aCol ) );
  366. break;
  367. }
  368. }