KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_fp_edit_pad_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, 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
25
26#include <wx/button.h>
27#include <wx/sizer.h>
28#include <wx/dcclient.h>
29#include <pcb_shape.h>
30#include <widgets/wx_grid.h>
33#include <base_units.h>
34#include <units_provider.h>
35#include <board.h>
36#include <footprint.h>
38
39// Helper to map shape string to PAD_SHAPE
40static PAD_SHAPE ShapeFromString( const wxString& shape )
41{
42 if( shape == _( "Oval" ) ) return PAD_SHAPE::OVAL;
43 if( shape == _( "Rectangle" ) ) return PAD_SHAPE::RECTANGLE;
44 if( shape == _( "Trapezoid" ) ) return PAD_SHAPE::TRAPEZOID;
45 if( shape == _( "Rounded rectangle" ) ) return PAD_SHAPE::ROUNDRECT;
46 if( shape == _( "Chamfered rectangle" ) ) return PAD_SHAPE::CHAMFERED_RECT;
47 if( shape == _( "Custom shape" ) ) return PAD_SHAPE::CUSTOM;
48 return PAD_SHAPE::CIRCLE;
49}
50
52 DIALOG_SHIM( (wxWindow*)aParent, wxID_ANY, _( "Pad Table" ), wxDefaultPosition, wxDefaultSize,
53 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
54 m_grid( nullptr ),
55 m_footprint( aFootprint ),
57{
58 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
59
60 m_grid = new WX_GRID( this, wxID_ANY );
61 m_grid->CreateGrid( 0, 11 );
62 m_grid->SetColLabelValue( COL_NUMBER, _( "Number" ) );
63 m_grid->SetColLabelValue( COL_TYPE, _( "Type" ) );
64 m_grid->SetColLabelValue( COL_SHAPE, _( "Shape" ) );
65 m_grid->SetColLabelValue( COL_POS_X, _( "X Position" ) );
66 m_grid->SetColLabelValue( COL_POS_Y, _( "Y Position" ) );
67 m_grid->SetColLabelValue( COL_SIZE_X, _( "Size X" ) );
68 m_grid->SetColLabelValue( COL_SIZE_Y, _( "Size Y" ) );
69 m_grid->SetColLabelValue( COL_DRILL_X, _( "Drill X" ) );
70 m_grid->SetColLabelValue( COL_DRILL_Y, _( "Drill Y" ) );
71 m_grid->SetColLabelValue( COL_P2D_LENGTH, _( "Pad->Die Length" ) );
72 m_grid->SetColLabelValue( COL_P2D_DELAY, _( "Pad->Die Delay" ) );
73 m_grid->EnableEditing( true );
74
75 wxGridCellAttr* attr;
76
77 // Type column editor (attribute)
78 attr = new wxGridCellAttr;
79 {
80 wxArrayString typeNames;
81 typeNames.push_back( _( "Through-hole" ) ); // PTH
82 typeNames.push_back( _( "SMD" ) ); // SMD
83 typeNames.push_back( _( "Connector" ) ); // CONN SMD? (use CONN?)
84 typeNames.push_back( _( "NPTH" ) ); // NPTH
85 typeNames.push_back( _( "Aperture" ) ); // inferred copper-less
86 attr->SetEditor( new GRID_CELL_COMBOBOX( typeNames ) );
87 }
88 m_grid->SetColAttr( COL_TYPE, attr );
89
90 attr = new wxGridCellAttr;
91 wxArrayString shapeNames;
92 shapeNames.push_back( _( "Circle" ) );
93 shapeNames.push_back( _( "Oval" ) );
94 shapeNames.push_back( _( "Rectangle" ) );
95 shapeNames.push_back( _( "Trapezoid" ) );
96 shapeNames.push_back( _( "Rounded rectangle" ) );
97 shapeNames.push_back( _( "Chamfered rectangle" ) );
98 shapeNames.push_back( _( "Custom shape" ) );
99 attr->SetEditor( new GRID_CELL_COMBOBOX( shapeNames ) );
100 m_grid->SetColAttr( COL_SHAPE, attr );
101
102 attr = new wxGridCellAttr;
103 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
104 m_grid->SetColAttr( COL_POS_X, attr );
105
106 attr = new wxGridCellAttr;
107 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
108 m_grid->SetColAttr( COL_POS_Y, attr );
109
110 attr = new wxGridCellAttr;
111 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
112 m_grid->SetColAttr( COL_SIZE_X, attr );
113
114 attr = new wxGridCellAttr;
115 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
116 m_grid->SetColAttr( COL_SIZE_Y, attr );
117
118 // Drill X
119 attr = new wxGridCellAttr;
120 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
121 m_grid->SetColAttr( COL_DRILL_X, attr );
122
123 // Drill Y
124 attr = new wxGridCellAttr;
125 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
126 m_grid->SetColAttr( COL_DRILL_Y, attr );
127
128 // Pad->Die Length
129 attr = new wxGridCellAttr;
130 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
131 m_grid->SetColAttr( COL_P2D_LENGTH, attr );
132
133 // Pad->Die Delay
134 attr = new wxGridCellAttr;
135 attr->SetEditor( new GRID_CELL_TEXT_EDITOR() );
136 m_grid->SetColAttr( COL_P2D_DELAY, attr );
137
138 m_grid->SetUnitsProvider( m_unitsProvider.get(), COL_POS_X );
139 m_grid->SetUnitsProvider( m_unitsProvider.get(), COL_POS_Y );
140 m_grid->SetUnitsProvider( m_unitsProvider.get(), COL_SIZE_X );
141 m_grid->SetUnitsProvider( m_unitsProvider.get(), COL_SIZE_Y );
142 m_grid->SetUnitsProvider( m_unitsProvider.get(), COL_DRILL_X );
143 m_grid->SetUnitsProvider( m_unitsProvider.get(), COL_DRILL_Y );
145
146 topSizer->Add( m_grid, 1, wxEXPAND | wxALL, 5 );
147
148 wxStdDialogButtonSizer* buttons = new wxStdDialogButtonSizer();
149 buttons->AddButton( new wxButton( this, wxID_OK ) );
150 buttons->AddButton( new wxButton( this, wxID_CANCEL ) );
151 buttons->Realize();
152 topSizer->Add( buttons, 0, wxALIGN_RIGHT | wxALL, 5 );
153
154 SetSizerAndFit( topSizer );
155
157 Populate();
158
159 // Bind cell change handlers for real-time updates
160 m_grid->Bind( wxEVT_GRID_CELL_CHANGED, &DIALOG_FP_EDIT_PAD_TABLE::OnCellChanged, this );
161 m_grid->Bind( wxEVT_GRID_SELECT_CELL, &DIALOG_FP_EDIT_PAD_TABLE::OnSelectCell, this );
162
163 // Listen for cancel
164 Bind(
165 wxEVT_BUTTON,
166 [this]( wxCommandEvent& aEvt )
167 {
168 m_cancelled = true;
169 aEvt.Skip();
170 },
171 wxID_CANCEL );
172
174}
175
181
183{
184 if( !m_footprint )
185 return;
186
187 int row = 0;
188
189 for( PAD* pad : m_footprint->Pads() )
190 {
191 m_grid->AppendRows( 1 );
192 m_grid->SetCellValue( row, COL_NUMBER, pad->GetNumber() );
193
194 // Pad attribute to string
195 wxString attrStr;
196
197 switch( pad->GetAttribute() )
198 {
199 case PAD_ATTRIB::PTH: attrStr = _( "Through-hole" ); break;
200 case PAD_ATTRIB::SMD: attrStr = _( "SMD" ); break;
201 case PAD_ATTRIB::CONN: attrStr = _( "Connector" ); break;
202 case PAD_ATTRIB::NPTH: attrStr = _( "NPTH" ); break;
203 default: attrStr = _( "Through-hole" ); break;
204 }
205
206 VECTOR2I size = pad->GetSize( PADSTACK::ALL_LAYERS );
207
208 if( pad->IsAperturePad() )
209 attrStr = _( "Aperture" );
210
211 m_grid->SetCellValue( row, COL_TYPE, attrStr );
212 m_grid->SetCellValue( row, COL_SHAPE, pad->ShowPadShape( PADSTACK::ALL_LAYERS ) );
213 m_grid->SetCellValue( row, COL_POS_X, m_unitsProvider->StringFromValue( pad->GetPosition().x, true ) );
214 m_grid->SetCellValue( row, COL_POS_Y, m_unitsProvider->StringFromValue( pad->GetPosition().y, true ) );
215 m_grid->SetCellValue( row, COL_SIZE_X, m_unitsProvider->StringFromValue( size.x, true ) );
216 m_grid->SetCellValue( row, COL_SIZE_Y, m_unitsProvider->StringFromValue( size.y, true ) );
217
218 // Drill values (only meaningful for PTH or NPTH). Leave empty otherwise.
219 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
220 {
221 VECTOR2I drill = pad->GetDrillSize();
222
223 if( drill.x > 0 )
224 m_grid->SetCellValue( row, COL_DRILL_X, m_unitsProvider->StringFromValue( drill.x, true ) );
225 if( drill.y > 0 )
226 m_grid->SetCellValue( row, COL_DRILL_Y, m_unitsProvider->StringFromValue( drill.y, true ) );
227 }
228 else
229 {
230 // For non-PTH pads, drill columns are not applicable.
231 m_grid->SetReadOnly( row, COL_DRILL_X, true );
232 m_grid->SetReadOnly( row, COL_DRILL_Y, true );
233 }
234
235 // Pad to die metrics
236 if( pad->GetPadToDieLength() )
237 m_grid->SetCellValue( row, COL_P2D_LENGTH, m_unitsProvider->StringFromValue( pad->GetPadToDieLength(), true ) );
238 if( pad->GetPadToDieDelay() )
239 m_grid->SetCellValue( row, COL_P2D_DELAY, wxString::Format( "%d", pad->GetPadToDieDelay() ) );
240 row++;
241 }
242
243 // Hide row labels per requirements
244 m_grid->HideRowLabels();
245
246 // Auto size the data columns first to get reasonable initial widths
247 m_grid->AutoSizeColumns();
248
249 // Ensure the Shape column (index 1) is wide enough for the longest translated
250 // shape text plus the dropdown arrow / padding. We compute a max text width
251 // using a device context and add a platform neutral padding.
252 {
253 wxClientDC dc( m_grid );
254 dc.SetFont( m_grid->GetFont() );
255
256 wxArrayString shapeNames;
257 shapeNames.push_back( _( "Circle" ) );
258 shapeNames.push_back( _( "Oval" ) );
259 shapeNames.push_back( _( "Rectangle" ) );
260 shapeNames.push_back( _( "Trapezoid" ) );
261 shapeNames.push_back( _( "Rounded rectangle" ) );
262 shapeNames.push_back( _( "Chamfered rectangle" ) );
263 shapeNames.push_back( _( "Custom shape" ) );
264
265 int maxWidth = 0;
266 for( const wxString& str : shapeNames )
267 {
268 int w, h;
269 dc.GetTextExtent( str, &w, &h );
270 maxWidth = std::max( maxWidth, w );
271 }
272
273 // Add padding for internal cell margins + dropdown control.
274 int padding = FromDIP( 30 ); // heuristic: 2*margin + arrow button
275 m_grid->SetColSize( COL_SHAPE, maxWidth + padding );
276 }
277
278 // Record initial proportions for proportional resizing later.
280 Bind( wxEVT_SIZE, &DIALOG_FP_EDIT_PAD_TABLE::OnSize, this );
281
282 // Run an initial proportional resize using current client size so columns
283 // respect proportions immediately.
284 wxSizeEvent sizeEvt( GetSize(), GetId() );
285 CallAfter(
286 [this, sizeEvt]
287 {
288 wxSizeEvent evt( sizeEvt );
289 this->OnSize( evt );
290 } );
291
292 // If pads exist, select the first row to show initial highlight
293 if( m_grid->GetNumberRows() > 0 )
294 {
295 m_grid->SetGridCursor( 0, 0 );
296 // Construct event with required parameters (id, type, obj, row, col,...)
297 wxGridEvent ev( m_grid->GetId(), wxEVT_GRID_SELECT_CELL, m_grid, 0, 0, -1, -1, true );
298 OnSelectCell( ev );
299 }
300}
301
303{
304 m_originalPads.clear();
305 if( !m_footprint )
306 return;
307
308 for( PAD* pad : m_footprint->Pads() )
309 {
310 PAD_SNAPSHOT snap;
311 snap.number = pad->GetNumber();
312 snap.shape = pad->GetShape( PADSTACK::ALL_LAYERS );
313 snap.position = pad->GetPosition();
314 snap.size = pad->GetSize( PADSTACK::ALL_LAYERS );
315 snap.attribute = pad->GetAttribute();
316 snap.drillSize = pad->GetDrillSize();
317 snap.padToDieLength= pad->GetPadToDieLength();
318 snap.padToDieDelay = pad->GetPadToDieDelay();
319 m_originalPads.push_back( snap );
320 }
321}
322
324{
325 if( !m_footprint )
326 return;
327
328 size_t idx = 0;
329 PCB_BASE_FRAME* base = dynamic_cast<PCB_BASE_FRAME*>( GetParent() );
330 PCB_DRAW_PANEL_GAL* canvas = base ? base->GetCanvas() : nullptr;
331
332 for( PAD* pad : m_footprint->Pads() )
333 {
334 if( idx >= m_originalPads.size() )
335 break;
336
337 const PAD_SNAPSHOT& snap = m_originalPads[idx++];
338 pad->SetNumber( snap.number );
339 pad->SetShape( PADSTACK::ALL_LAYERS, snap.shape );
340 pad->SetAttribute( snap.attribute );
341 pad->SetPosition( snap.position );
342 pad->SetSize( PADSTACK::ALL_LAYERS, snap.size );
343 pad->SetDrillSize( snap.drillSize );
344 pad->SetPadToDieLength( snap.padToDieLength );
345 pad->SetPadToDieDelay( snap.padToDieDelay );
346 pad->ClearBrightened();
347
348 if( canvas )
349 canvas->GetView()->Update( pad, KIGFX::REPAINT );
350 }
351
352 if( canvas )
353 {
355 canvas->ForceRefresh();
356 }
357}
358
359
361{
362 if( !m_grid->CommitPendingChanges() )
363 return false;
364
365 if( !m_footprint )
366 return true;
367
368 int row = 0;
369
370 for( PAD* pad : m_footprint->Pads() )
371 {
372 pad->SetNumber( m_grid->GetCellValue( row, COL_NUMBER ) );
373
374 wxString typeStr = m_grid->GetCellValue( row, COL_TYPE );
375 if( typeStr == _( "Through-hole" ) )
376 pad->SetAttribute( PAD_ATTRIB::PTH );
377 else if( typeStr == _( "SMD" ) )
378 pad->SetAttribute( PAD_ATTRIB::SMD );
379 else if( typeStr == _( "Connector" ) )
380 pad->SetAttribute( PAD_ATTRIB::CONN );
381 else if( typeStr == _( "NPTH" ) )
382 pad->SetAttribute( PAD_ATTRIB::NPTH );
383 // Aperture derived by copper-less layers; do not overwrite attribute here.
384
385 wxString shape = m_grid->GetCellValue( row, COL_SHAPE );
386 PAD_SHAPE newShape = ShapeFromString( shape );
387
388 pad->SetShape( PADSTACK::ALL_LAYERS, newShape );
389
390 VECTOR2I pos;
391 pos.x = m_grid->GetUnitValue( row, COL_POS_X );
392 pos.y = m_grid->GetUnitValue( row, COL_POS_Y );
393 pad->SetPosition( pos );
394
395 VECTOR2I size;
396 size.x = m_grid->GetUnitValue( row, COL_SIZE_X );
397 size.y = m_grid->GetUnitValue( row, COL_SIZE_Y );
398 pad->SetSize( PADSTACK::ALL_LAYERS, size );
399
400 // Drill sizes (only if attribute allows)
401 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
402 {
403 int dx = m_grid->GetUnitValue( row, COL_DRILL_X );
404 int dy = m_grid->GetUnitValue( row, COL_DRILL_Y );
405 if( dx > 0 || dy > 0 )
406 {
407 if( dx <= 0 ) dx = dy;
408 if( dy <= 0 ) dy = dx;
409 pad->SetDrillSize( { dx, dy } );
410 }
411 }
412
413 // Pad->Die
414 wxString delayStr = m_grid->GetCellValue( row, COL_P2D_DELAY );
415 wxString lenStr = m_grid->GetCellValue( row, COL_P2D_LENGTH );
416
417 if( !lenStr.IsEmpty() )
418 pad->SetPadToDieLength( m_grid->GetUnitValue( row, COL_P2D_LENGTH ) );
419 else
420 pad->SetPadToDieLength( 0 );
421
422 if( !delayStr.IsEmpty() )
423 {
424 long delayVal;
425
426 if( delayStr.ToLong( &delayVal ) )
427 pad->SetPadToDieDelay( (int) delayVal );
428 else
429 pad->SetPadToDieDelay( 0 );
430 }
431 else
432 pad->SetPadToDieDelay( 0 );
433
434 row++;
435 }
436
437 return true;
438}
439
441{
442 m_colProportions.clear();
443 m_minColWidths.clear();
444
445 if( !m_grid )
446 return;
447
448 // Only consider the actual data columns (all of them since row labels are hidden)
449 int cols = m_grid->GetNumberCols();
450 int total = 0;
451 std::vector<int> widths;
452 widths.reserve( cols );
453
454 for( int c = 0; c < cols; ++c )
455 {
456 int w = m_grid->GetColSize( c );
457 widths.push_back( w );
458 total += w;
459 }
460
461 if( total <= 0 )
462 return;
463
464 for( int w : widths )
465 {
466 m_colProportions.push_back( (double) w / (double) total );
467 m_minColWidths.push_back( w );
468 }
469}
470
471void DIALOG_FP_EDIT_PAD_TABLE::OnSize( wxSizeEvent& aEvent )
472{
473 if( m_colProportions.empty() )
474 {
475 aEvent.Skip();
476 return;
477 }
478
479 // Compute available total width for columns and resize keeping proportions.
480 int cols = m_grid->GetNumberCols();
481 int available = 0;
482
483 for( int c = 0; c < cols; ++c )
484 available += m_grid->GetColSize( c );
485
486 // Use client size of grid minus scrollbar estimate to better distribute.
487 int clientW = m_grid->GetClientSize().x;
488
489 if( clientW > 0 )
490 available = clientW; // prefer actual client width
491
492 int used = 0;
493 for( int c = 0; c < cols; ++c )
494 {
495 int target = (int) std::round( m_colProportions[c] * available );
496 target = std::max( target, m_minColWidths[c] );
497
498 // Defer last column to absorb rounding diff.
499 if( c == cols - 1 )
500 target = std::max( available - used, m_minColWidths[c] );
501
502 m_grid->SetColSize( c, target );
503 used += target;
504 }
505
506 aEvent.Skip();
507}
508
510{
511 int row = aEvent.GetRow();
512 int col = aEvent.GetCol();
513
514 if( !m_footprint )
515 return;
516
517 // row -> pad mapping is current order of Pads() iteration; rebuild each time (pads count small)
518 int idx = 0;
519 PAD* target = nullptr;
520
521 for( PAD* pad : m_footprint->Pads() )
522 {
523 if( idx == row ) { target = pad; break; }
524 ++idx;
525 }
526
527 if( !target )
528 return;
529 bool needCanvasRefresh = false;
530
531 switch( col )
532 {
533 case COL_NUMBER:
534 target->SetNumber( m_grid->GetCellValue( row, col ) );
535 break;
536
537 case COL_TYPE:
538 {
539 wxString typeStr = m_grid->GetCellValue( row, col );
540 PAD_ATTRIB newAttr = target->GetAttribute();
541
542 if( typeStr == _( "Through-hole" ) )
543 newAttr = PAD_ATTRIB::PTH;
544 else if( typeStr == _( "SMD" ) )
545 newAttr = PAD_ATTRIB::SMD;
546 else if( typeStr == _( "Connector" ) )
547 newAttr = PAD_ATTRIB::CONN;
548 else if( typeStr == _( "NPTH" ) )
549 newAttr = PAD_ATTRIB::NPTH;
550
551 if( newAttr != target->GetAttribute() )
552 {
553 target->SetAttribute( newAttr );
554
555 // Toggle drill columns read-only state dynamically.
556 bool drillsEditable = ( newAttr == PAD_ATTRIB::PTH || newAttr == PAD_ATTRIB::NPTH );
557 m_grid->SetReadOnly( row, COL_DRILL_X, !drillsEditable );
558 m_grid->SetReadOnly( row, COL_DRILL_Y, !drillsEditable );
559 needCanvasRefresh = true;
560 }
561 break;
562 }
563
564 case COL_SHAPE:
565 target->SetShape( PADSTACK::ALL_LAYERS, ShapeFromString( m_grid->GetCellValue( row, col ) ) );
566 needCanvasRefresh = true;
567 break;
568
569 case COL_POS_X:
570 case COL_POS_Y:
571 {
572 VECTOR2I pos = target->GetPosition();
573
574 if( col == COL_POS_X )
575 pos.x = m_grid->GetUnitValue( row, col );
576 else
577 pos.y = m_grid->GetUnitValue( row, col );
578
579 target->SetPosition( pos );
580 needCanvasRefresh = true;
581 break;
582 }
583
584 case COL_SIZE_X:
585 case COL_SIZE_Y:
586 {
587 VECTOR2I size = target->GetSize( PADSTACK::ALL_LAYERS );
588
589 if( col == COL_SIZE_X )
590 size.x = m_grid->GetUnitValue( row, col );
591 else
592 size.y = m_grid->GetUnitValue( row, col );
593
594 target->SetSize( PADSTACK::ALL_LAYERS, size );
595 needCanvasRefresh = true;
596 break;
597 }
598
599 case COL_DRILL_X:
600 case COL_DRILL_Y:
601 {
602 if( target->GetAttribute() == PAD_ATTRIB::PTH || target->GetAttribute() == PAD_ATTRIB::NPTH )
603 {
604 int dx = m_grid->GetUnitValue( row, COL_DRILL_X );
605 int dy = m_grid->GetUnitValue( row, COL_DRILL_Y );
606 if( dx > 0 || dy > 0 )
607 {
608 if( dx <= 0 ) dx = dy;
609 if( dy <= 0 ) dy = dx;
610 target->SetDrillSize( { dx, dy } );
611 needCanvasRefresh = true;
612 }
613 }
614 break;
615 }
616
617 case COL_P2D_LENGTH:
618 if( !m_grid->GetCellValue( row, col ).IsEmpty() )
619 target->SetPadToDieLength( m_grid->GetUnitValue( row, col ) );
620 break;
621
622 case COL_P2D_DELAY:
623 {
624 wxString d = m_grid->GetCellValue( row, col );
625 long val;
626
627 if( d.ToLong( &val ) )
628 target->SetPadToDieDelay( (int) val );
629 break;
630 }
631
632 default:
633 break;
634 }
635
636 // Request redraw (simple approach)
637 target->SetDirty();
638
639 if( needCanvasRefresh )
640 {
641 if( PCB_BASE_FRAME* base = dynamic_cast<PCB_BASE_FRAME*>( GetParent() ) )
642 base->GetCanvas()->ForceRefresh();
643 }
644}
645
646void DIALOG_FP_EDIT_PAD_TABLE::OnSelectCell( wxGridEvent& aEvent )
647{
648 int row = aEvent.GetRow();
649
650 if( !m_footprint )
651 return;
652
653 PCB_BASE_FRAME* base = dynamic_cast<PCB_BASE_FRAME*>( GetParent() );
654 PCB_DRAW_PANEL_GAL* canvas = base ? base->GetCanvas() : nullptr;
655
656 // Clear existing pad selections
657 for( PAD* pad : m_footprint->Pads() )
658 {
659 if( pad->IsBrightened() )
660 {
661 pad->ClearBrightened();
662
663 if( canvas )
664 canvas->GetView()->Update( pad, KIGFX::REPAINT );
665 }
666 }
667
668 int idx = 0;
669
670 for( PAD* pad : m_footprint->Pads() )
671 {
672 if( idx == row )
673 {
674 pad->SetBrightened();
675
676 if( canvas )
677 {
678 canvas->GetView()->Update( pad, KIGFX::REPAINT );
679 canvas->ForceRefresh();
680 }
681
682 break;
683 }
684
685 ++idx;
686 }
687
688}
689
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
DIALOG_FP_EDIT_PAD_TABLE(PCB_BASE_FRAME *aParent, FOOTPRINT *aFootprint)
std::vector< PAD_SNAPSHOT > m_originalPads
void OnSize(wxSizeEvent &aEvent)
void OnCellChanged(wxGridEvent &aEvent)
std::vector< double > m_colProportions
std::unique_ptr< UNITS_PROVIDER > m_unitsProvider
void OnSelectCell(wxGridEvent &aEvent)
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
DIALOG_SHIM(wxWindow *aParent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, const wxString &name=wxDialogNameStr)
EDA_UNITS GetUserUnits() const
void ForceRefresh()
Force a redraw.
This class works around a bug in wxGrid where the first keystroke doesn't get sent through the valida...
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition pcb_view.cpp:91
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:639
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:145
Definition pad.h:54
void SetAttribute(PAD_ATTRIB aAttribute)
Definition pad.cpp:883
PAD_ATTRIB GetAttribute() const
Definition pad.h:440
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:186
VECTOR2I GetPosition() const override
Definition pad.h:208
void SetDirty()
Definition pad.h:429
void SetPadToDieDelay(int aDelay)
Definition pad.h:455
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition pad.h:135
void SetPosition(const VECTOR2I &aPos) override
Definition pad.h:202
void SetDrillSize(const VECTOR2I &aSize)
Definition pad.h:304
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.h:259
void SetPadToDieLength(int aLength)
Definition pad.h:452
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition pad.h:264
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
static PAD_SHAPE ShapeFromString(const wxString &shape)
#define _(s)
static std::map< int, wxString > shapeNames
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:58
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:39
STL namespace.
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition padstack.h:81
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:87
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:83
@ PTH
Plated through hole pad.
Definition padstack.h:82
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:84
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition padstack.h:52
@ CHAMFERED_RECT
Definition padstack.h:60
@ ROUNDRECT
Definition padstack.h:57
@ TRAPEZOID
Definition padstack.h:56
@ RECTANGLE
Definition padstack.h:54
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695