KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_fields_grid_table.cpp
Go to the documentation of this file.
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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <board.h>
21#include <footprint.h>
23#include <kiway.h>
24#include <kiway_player.h>
26#include <pcb_base_frame.h>
27#include <pcb_edit_frame.h>
28#include <project.h>
29#include <trigo.h>
31
35
36enum
37{
38 MYID_SELECT_FOOTPRINT = 991, // must be within GRID_TRICKS' enum range
40};
41
42
43wxArrayString g_menuOrientations;
44
45
47 std::vector<EMBEDDED_FILES*> aFilesStack ) :
48 m_frame( aFrame ),
49 m_dialog( aDialog ),
55{
56 // Build the column attributes.
57
58 m_readOnlyAttr = new wxGridCellAttr;
59 m_readOnlyAttr->SetReadOnly( true );
60
61 m_fieldNameAttr = new wxGridCellAttr;
64 m_fieldNameAttr->SetEditor( nameEditor );
65
66 m_boolColAttr = new wxGridCellAttr;
67 m_boolColAttr->SetRenderer( new wxGridCellBoolRenderer() );
68 m_boolColAttr->SetEditor( new wxGridCellBoolEditor() );
69 m_boolColAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
70
71 if( g_menuOrientations.IsEmpty() )
72 {
77 }
78
79 m_orientationColAttr = new wxGridCellAttr;
81
82 m_layerColAttr = new wxGridCellAttr;
83 m_layerColAttr->SetRenderer( new GRID_CELL_LAYER_RENDERER( m_frame ) );
84 m_layerColAttr->SetEditor( new GRID_CELL_LAYER_SELECTOR( m_frame, {} ) );
85
86 m_referenceAttr = new wxGridCellAttr;
87 GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR();
88 referenceEditor->SetValidator( m_referenceValidator );
89 m_referenceAttr->SetEditor( referenceEditor );
90
91 m_valueAttr = new wxGridCellAttr;
93 valueEditor->SetValidator( m_valueValidator );
94 m_valueAttr->SetEditor( valueEditor );
95
96 m_urlAttr = new wxGridCellAttr;
97 GRID_CELL_URL_EDITOR* urlEditor = new GRID_CELL_URL_EDITOR( m_dialog, nullptr, aFilesStack );
98 urlEditor->SetValidator( m_urlValidator );
99 m_urlAttr->SetEditor( urlEditor );
100
101 m_eval = std::make_unique<NUMERIC_EVALUATOR>( m_frame->GetUserUnits() );
102
103 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &PCB_FIELDS_GRID_TABLE::onUnitsChanged, this );
104}
105
106
108{
109 m_readOnlyAttr->DecRef();
110 m_fieldNameAttr->DecRef();
111 m_boolColAttr->DecRef();
112 m_orientationColAttr->DecRef();
113 m_layerColAttr->DecRef();
114 m_referenceAttr->DecRef();
115 m_valueAttr->DecRef();
116 m_urlAttr->DecRef();
117
118 m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &PCB_FIELDS_GRID_TABLE::onUnitsChanged, this );
119}
120
121
123{
124 int mandatoryRows = 0;
125
126 for( const PCB_FIELD& field : *this )
127 {
128 if( field.IsMandatory() )
129 mandatoryRows++;
130 }
131
132 return mandatoryRows;
133}
134
135
136void PCB_FIELDS_GRID_TABLE::onUnitsChanged( wxCommandEvent& aEvent )
137{
138 if( GetView() )
139 GetView()->ForceRefresh();
140
141 aEvent.Skip();
142}
143
144
146{
147 switch( aCol )
148 {
149 case PFC_NAME: return _( "Name" );
150 case PFC_VALUE: return _( "Value" );
151 case PFC_SHOWN: return _( "Show" );
152 case PFC_WIDTH: return _( "Width" );
153 case PFC_HEIGHT: return _( "Height" );
154 case PFC_THICKNESS: return _( "Thickness" );
155 case PFC_ITALIC: return _( "Italic" );
156 case PFC_LAYER: return _( "Layer" );
157 case PFC_ORIENTATION: return _( "Orientation" );
158 case PFC_UPRIGHT: return _( "Keep Upright" );
159 case PFC_XOFFSET: return _( "X Offset" );
160 case PFC_YOFFSET: return _( "Y Offset" );
161 case PFC_KNOCKOUT: return _( "Knockout" );
162 case PFC_MIRRORED: return _( "Mirrored" );
163 default: wxFAIL; return wxEmptyString;
164 }
165}
166
167
168bool PCB_FIELDS_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
169{
170 switch( aCol )
171 {
172 case PFC_NAME:
173 case PFC_VALUE:
174 case PFC_WIDTH:
175 case PFC_HEIGHT:
176 case PFC_THICKNESS:
177 case PFC_ORIENTATION:
178 case PFC_XOFFSET:
179 case PFC_YOFFSET:
180 return aTypeName == wxGRID_VALUE_STRING;
181
182 case PFC_SHOWN:
183 case PFC_ITALIC:
184 case PFC_UPRIGHT:
185 case PFC_KNOCKOUT:
186 case PFC_MIRRORED:
187 return aTypeName == wxGRID_VALUE_BOOL;
188
189 case PFC_LAYER:
190 return aTypeName == wxGRID_VALUE_NUMBER;
191
192 default:
193 wxFAIL;
194 return false;
195 }
196}
197
198
199bool PCB_FIELDS_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
200{
201 return CanGetValueAs( aRow, aCol, aTypeName );
202}
203
204
205wxGridCellAttr* PCB_FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol,
206 wxGridCellAttr::wxAttrKind aKind )
207{
208 const PCB_FIELD& field = this->at( (size_t) aRow );
209
210 switch( aCol )
211 {
212 case PFC_NAME:
213 if( field.IsMandatory() )
214 {
215 m_readOnlyAttr->IncRef();
216 return enhanceAttr( m_readOnlyAttr, aRow, aCol, aKind );
217 }
218
219 m_fieldNameAttr->IncRef();
220 return enhanceAttr( m_fieldNameAttr, aRow, aCol, aKind );
221
222 case PFC_VALUE:
223 if( field.GetId() == FIELD_T::REFERENCE )
224 {
225 m_referenceAttr->IncRef();
226 return enhanceAttr( m_referenceAttr, aRow, aCol, aKind );
227 }
228 else if( field.GetId() == FIELD_T::VALUE )
229 {
230 m_valueAttr->IncRef();
231 return enhanceAttr( m_valueAttr, aRow, aCol, aKind );
232 }
233 else if( field.GetId() == FIELD_T::DATASHEET || field.HasHypertext() )
234 {
235 m_urlAttr->IncRef();
236 return enhanceAttr( m_urlAttr, aRow, aCol, aKind );
237 }
238
239 return enhanceAttr( nullptr, aRow, aCol, aKind );
240
241 case PFC_WIDTH:
242 case PFC_HEIGHT:
243 case PFC_THICKNESS:
244 case PFC_XOFFSET:
245 case PFC_YOFFSET:
246 return enhanceAttr( nullptr, aRow, aCol, aKind );
247
248 case PFC_SHOWN:
249 case PFC_ITALIC:
250 case PFC_UPRIGHT:
251 case PFC_KNOCKOUT:
252 case PFC_MIRRORED:
253 m_boolColAttr->IncRef();
254 return enhanceAttr( m_boolColAttr, aRow, aCol, aKind );
255
256 case PFC_LAYER:
257 m_layerColAttr->IncRef();
258 return enhanceAttr( m_layerColAttr, aRow, aCol, aKind );
259
260 case PFC_ORIENTATION:
261 m_orientationColAttr->IncRef();
262 return enhanceAttr( m_orientationColAttr, aRow, aCol, aKind );
263
264 default:
265 wxFAIL;
266 return enhanceAttr( nullptr, aRow, aCol, aKind );
267 }
268}
269
270
271wxString PCB_FIELDS_GRID_TABLE::GetValue( int aRow, int aCol )
272{
273 wxGrid* grid = GetView();
274 const PCB_FIELD& field = this->at( (size_t) aRow );
275
276 if( grid->GetGridCursorRow() == aRow && grid->GetGridCursorCol() == aCol
277 && grid->IsCellEditControlShown() )
278 {
279 auto it = m_evalOriginal.find( { aRow, aCol } );
280
281 if( it != m_evalOriginal.end() )
282 return it->second;
283 }
284
285 switch( aCol )
286 {
287 case PFC_NAME: return field.GetName();
288 case PFC_VALUE: return field.GetText();
289 case PFC_WIDTH: return m_frame->StringFromValue( field.GetTextWidth(), true );
290 case PFC_HEIGHT: return m_frame->StringFromValue( field.GetTextHeight(), true );
291 case PFC_THICKNESS: return m_frame->StringFromValue( field.GetTextThickness(), true );
292 case PFC_LAYER: return field.GetLayerName();
293
294 case PFC_ORIENTATION:
295 {
296 EDA_ANGLE angle = field.GetTextAngle() - field.GetParentFootprint()->GetOrientation();
297 return m_frame->StringFromValue( angle, true );
298 }
299
300 case PFC_XOFFSET: return m_frame->StringFromValue( field.GetFPRelativePosition().x, true );
301 case PFC_YOFFSET: return m_frame->StringFromValue( field.GetFPRelativePosition().y, true );
302
303 default:
304 // we can't assert here because wxWidgets sometimes calls this without checking
305 // the column type when trying to see if there's an overflow
306 return wxT( "bad wxWidgets!" );
307 }
308}
309
310
312{
313 PCB_FIELD& field = this->at( (size_t) aRow );
314
315 switch( aCol )
316 {
317 case PFC_SHOWN: return field.IsVisible();
318 case PFC_ITALIC: return field.IsItalic();
319 case PFC_UPRIGHT: return field.IsKeepUpright();
320 case PFC_KNOCKOUT: return field.IsKnockout();
321 case PFC_MIRRORED: return field.IsMirrored();
322
323 default:
324 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
325 return false;
326 }
327}
328
329
331{
332 PCB_FIELD& field = this->at( (size_t) aRow );
333
334 switch( aCol )
335 {
336 case PFC_LAYER: return field.GetLayer();
337
338 default:
339 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a long value" ), aCol ) );
340 return 0;
341 }
342}
343
344
345void PCB_FIELDS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
346{
347 PCB_FIELD& field = this->at( (size_t) aRow );
348 VECTOR2I pos;
349 wxString value = aValue;
350
351 if( aCol != PFC_VALUE )
352 value.Trim( true ).Trim( false );
353
354 if( aCol == PFC_WIDTH
355 || aCol == PFC_HEIGHT
356 || aCol == PFC_THICKNESS
357 || aCol == PFC_XOFFSET
358 || aCol == PFC_YOFFSET )
359 {
360 m_eval->SetDefaultUnits( m_frame->GetUserUnits() );
361
362 if( m_eval->Process( value ) )
363 {
364 m_evalOriginal[ { aRow, aCol } ] = value;
365 value = m_eval->Result();
366 }
367 }
368
369 switch( aCol )
370 {
371 case PFC_NAME: field.SetName( value ); break;
372 case PFC_VALUE: field.SetText( value ); break;
373 case PFC_WIDTH: field.SetTextWidth( m_frame->ValueFromString( value ) ); break;
374 case PFC_HEIGHT: field.SetTextHeight( m_frame->ValueFromString( value ) ); break;
375 case PFC_THICKNESS: field.SetTextThickness( m_frame->ValueFromString( value ) ); break;
376
377 case PFC_ORIENTATION:
378 field.SetTextAngle( m_frame->AngleValueFromString( value )
379 + field.GetParentFootprint()->GetOrientation() );
380 break;
381
382 case PFC_XOFFSET:
383 case PFC_YOFFSET:
384 pos = field.GetFPRelativePosition();
385
386 if( aCol == PFC_XOFFSET )
387 pos.x = m_frame->ValueFromString( value );
388 else
389 pos.y = m_frame->ValueFromString( value );
390
391 field.SetFPRelativePosition( pos );
392 break;
393
394 default:
395 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
396 break;
397 }
398
399 GetView()->Refresh();
400 m_dialog->OnModify();
401}
402
403
404void PCB_FIELDS_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue )
405{
406 PCB_FIELD& field = this->at( (size_t) aRow );
407
408 switch( aCol )
409 {
410 case PFC_SHOWN: field.SetVisible( aValue ); break;
411 case PFC_ITALIC: field.SetItalic( aValue ); break;
412 case PFC_UPRIGHT: field.SetKeepUpright( aValue ); break;
413 case PFC_KNOCKOUT: field.SetIsKnockout( aValue ); break;
414 case PFC_MIRRORED: field.SetMirrored( aValue ); break;
415
416 default:
417 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
418 break;
419 }
420
421 m_dialog->OnModify();
422}
423
424
425void PCB_FIELDS_GRID_TABLE::SetValueAsLong( int aRow, int aCol, long aValue )
426{
427 PCB_FIELD& field = this->at( (size_t) aRow );
428
429 switch( aCol )
430 {
431 case PFC_LAYER:
432 field.SetLayer( ToLAYER_ID( (int) aValue ) );
433
434 if( BOARD* board = field.GetBoard() )
435 field.SetMirrored( board->IsBackLayer( field.GetLayer() ) );
436 else
437 field.SetMirrored( IsBackLayer( field.GetLayer() ) );
438
439 break;
440
441 default:
442 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a long value" ), aCol ) );
443 break;
444 }
445
446 m_dialog->OnModify();
447}
448
449
450// Keep the row deletion, and the cached expression evaluation in sync
451bool PCB_FIELDS_GRID_TABLE::DeleteRows( size_t aPos, size_t aNumRows )
452{
453 if( aPos >= size() || aNumRows > size() - aPos )
454 return false;
455
456 std::map<std::pair<int, int>, wxString> rebasedEvalOriginal;
457
458 for( const auto& [cell, expression] : m_evalOriginal )
459 {
460 // Just keep anything from before our deletion
461 if( cell.first < static_cast<int>( aPos ) )
462 {
463 rebasedEvalOriginal[cell] = expression;
464 }
465 // Move expressions after the deletion up by the number of deleted rows
466 else if( cell.first >= static_cast<int>( aPos + aNumRows ) )
467 {
468 rebasedEvalOriginal[{ cell.first - static_cast<int>( aNumRows ), cell.second }] = expression;
469 }
470 // No else because that is the deleted range, and those go away
471 }
472
473 // Replace cache with new cache with correct number of rows
474 m_evalOriginal.swap( rebasedEvalOriginal );
475 // Delete actual rows from grid
476 erase( begin() + aPos, begin() + aPos + aNumRows );
477
478 if( GetView() )
479 {
480 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aPos, aNumRows );
481 GetView()->ProcessTableMessage( msg );
482 }
483
484 return true;
485}
virtual bool IsKnockout() const
Definition board_item.h:414
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetIsKnockout(bool aKnockout)
Definition board_item.h:415
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:374
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
VECTOR2I GetFPRelativePosition() const
void SetFPRelativePosition(const VECTOR2I &aPos)
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:410
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:80
bool IsItalic() const
Definition eda_text.h:200
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
bool IsKeepUpright() const
Definition eda_text.h:245
virtual bool IsVisible() const
Definition eda_text.h:226
virtual int GetTextHeight() const
Definition eda_text.h:307
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:354
virtual int GetTextWidth() const
Definition eda_text.h:304
virtual void SetTextWidth(int aWidth)
Definition eda_text.cpp:534
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
virtual void SetTextHeight(int aHeight)
Definition eda_text.cpp:545
bool IsMirrored() const
Definition eda_text.h:229
void SetKeepUpright(bool aKeepUpright)
Definition eda_text.cpp:386
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:290
EDA_ANGLE GetOrientation() const
Definition footprint.h:439
This class works around a bug in wxGrid where the first keystroke doesn't get sent through the valida...
virtual void SetValidator(const wxValidator &validator) override
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
void onUnitsChanged(wxCommandEvent &aEvent)
void SetValue(int aRow, int aCol, const wxString &aValue) override
bool GetValueAsBool(int aRow, int aCol) override
wxString GetColLabelValue(int aCol) override
bool CanGetValueAs(int aRow, int aCol, const wxString &aTypeName) override
std::map< std::pair< int, int >, wxString > m_evalOriginal
FIELD_VALIDATOR m_nonUrlValidator
PCB_FIELDS_GRID_TABLE(PCB_BASE_FRAME *aFrame, DIALOG_SHIM *aDialog, std::vector< EMBEDDED_FILES * > aFilesStack)
long GetValueAsLong(int aRow, int aCol) override
wxGridCellAttr * m_readOnlyAttr
wxString GetValue(int aRow, int aCol) override
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
std::unique_ptr< NUMERIC_EVALUATOR > m_eval
void SetValueAsBool(int aRow, int aCol, bool aValue) override
FIELD_VALIDATOR m_referenceValidator
bool CanSetValueAs(int aRow, int aCol, const wxString &aTypeName) override
FIELD_VALIDATOR m_fieldNameValidator
bool DeleteRows(size_t aPos=0, size_t aNumRows=1) override
wxGridCellAttr * m_orientationColAttr
void SetValueAsLong(int aRow, int aCol, long aValue) override
bool IsMandatory() const
FIELD_T GetId() const
Definition pcb_field.h:123
bool HasHypertext() const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetName(const wxString &aName)
Definition pcb_field.h:121
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
Definition pcb_text.cpp:512
EDA_ANGLE GetTextAngle() const override
Definition pcb_text.cpp:560
int GetTextThickness() const override
Definition pcb_text.cpp:497
void SetTextAngle(const EDA_ANGLE &aAngle) override
Definition pcb_text.cpp:572
wxGridCellAttr * enhanceAttr(wxGridCellAttr *aInputAttr, int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind)
Definition wx_grid.cpp:43
#define _(s)
@ USER
The main config directory (e.g. ~/.config/kicad/)
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:829
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
KICOMMON_API wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
wxArrayString g_menuOrientations
@ PFC_THICKNESS
@ PFC_ORIENTATION
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708