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