KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_pad_properties.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 (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2013 Dick Hollenbeck, [email protected]
6 * Copyright (C) 2008-2013 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <drc/drc_item.h>
24#include <base_units.h>
25#include <bitmaps.h>
26#include <board_commit.h>
27#include <board.h>
29#include <footprint.h>
30#include <confirm.h>
31#include <core/arraydim.h>
32#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
37#include <macros.h>
38#include <pad.h>
39#include <pad_utils.h>
40#include <pcb_base_frame.h>
42#include <pcb_painter.h>
43#include <pcbnew_settings.h>
45#include <view/view_controls.h>
48#include <tool/tool_manager.h>
49#include <tools/pad_tool.h>
50#include <advanced_config.h> // for pad property feature management
51#include <wx/choicdlg.h>
52#include <wx/msgdlg.h>
53
54
55int DIALOG_PAD_PROPERTIES::m_page = 0; // remember the last open page during session
56
57
58// list of pad shapes, ordered like the pad shape wxChoice in dialog.
60{
67 PAD_SHAPE::CHAMFERED_RECT, // choice = CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT
68 PAD_SHAPE::CUSTOM, // choice = CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
69 PAD_SHAPE::CUSTOM // choice = PAD_SHAPE::CUSTOM_RECT_ANCHOR
70};
71
72
73// the ordered index of the pad shape wxChoice in dialog.
74// keep it consistent with code_shape[] and dialog strings
87
88
90{
95 PAD_ATTRIB::SMD // Aperture pad :type SMD with no copper layers,
96 // only on tech layers (usually only on paste layer
97};
98
99
100// These define have the same value as the m_PadType wxChoice GetSelected() return value
101#define PTH_DLG_TYPE 0
102#define SMD_DLG_TYPE 1
103#define CONN_DLG_TYPE 2
104#define NPTH_DLG_TYPE 3
105#define APERTURE_DLG_TYPE 4
106
107
109{
110 DIALOG_PAD_PROPERTIES dlg( this, aPad );
111
112 // QuasiModal required for NET_SELECTOR
113 dlg.ShowQuasiModal();
114}
115
116
119 m_parent( aParent ),
120 m_initialized( false ),
121 m_editLayer( F_Cu ),
153{
154 SetName( PAD_PROPERTIES_DLG_NAME );
156
157 m_currentPad = aPad; // aPad can be NULL, if the dialog is called
158 // from the footprint editor to set default pad setup
159
160 m_board = m_parent->GetBoard();
161
162 // Configure display origin transforms
165
166 m_padNetSelector->SetNetInfo( &m_board->GetNetInfo() );
167
169
173
174 m_masterPad = m_parent->GetDesignSettings().m_Pad_Master.get();
175 m_previewPad = new PAD( (FOOTPRINT*) nullptr );
176
177 if( aPad )
178 {
179 SetTitle( _( "Pad Properties" ) );
180
181 *m_previewPad = *aPad;
182 m_previewPad->GetTeardropParams() = aPad->GetTeardropParams();
183 m_previewPad->ClearFlags( SELECTED|BRIGHTENED );
184 }
185 else
186 {
187 SetTitle( _( "Default Pad Properties for Add Pad Tool" ) );
188
190 m_previewPad->GetTeardropParams() = m_masterPad->GetTeardropParams();
191 }
192
193 // Pads have a hardcoded internal rounding ratio which is 0.25 by default, even if
194 // they're not a rounded shape. This makes it hard to detect an intentional 0.25
195 // ratio, or one that's only there because it's the PAD default.
196 // Zero it out here to mark that we should recompute a better ratio if the user
197 // selects a pad shape which would need a default rounding ratio computed for it
198 m_previewPad->Padstack().ForEachUniqueLayer(
199 [&]( PCB_LAYER_ID aLayer )
200 {
202 m_previewPad->SetRoundRectRadiusRatio( aLayer, 0.0 );
203 } );
204
205 if( m_isFpEditor )
206 {
207 m_padNetLabel->Show( false );
208 m_padNetSelector->Show( false );
209 }
210
211 m_FlippedWarningSizer->Show( false );
212
213 // Pad needs to have a parent for painting; use the parent board for its design settings
214 if( !m_previewPad->GetParent() )
215 m_previewPad->SetParent( m_board );
216
222 m_pad_orientation.SetPrecision( 3 );
223
225 m_spokeAngle.SetPrecision( 3 );
226
227 // Update label text and tooltip for combined offset + ratio field
228 m_pasteMarginLabel->SetLabel( _( "Solder paste clearance:" ) );
229 m_pasteMarginLabel->SetToolTip( _( "Local solder paste clearance for this pad.\n"
230 "Enter an absolute value (e.g., -0.1mm), a percentage (e.g., -5%), "
231 "or both (e.g., -0.1mm - 5%).\n"
232 "If blank, the footprint or global value is used." ) );
233
234 m_padToDieDelay.SetUnits( EDA_UNITS::PS );
236
237 initValues();
238
239 m_techLayersLabel->SetFont( KIUI::GetStatusFont( this ) );
240 m_parentInfo->SetFont( KIUI::GetSmallInfoFont( this ) );
241 m_teardropShapeLabel->SetFont( KIUI::GetStatusFont( this ) );
242
243 wxFont infoFont = KIUI::GetSmallInfoFont( this ).Italic();
244 m_nonCopperNote->SetFont( infoFont );
245 m_staticTextInfoPaste->SetFont( infoFont );
246
249
250 // Usually, TransferDataToWindow is called by OnInitDialog
251 // calling it here fixes all widget sizes so FinishDialogSettings can safely fix minsizes
253
254 // Initialize canvas to be able to display the dummy pad:
256
257 m_notebook->SetSelection( m_page );
258
259 switch( m_page )
260 {
261 default:
262 case 0: SetInitialFocus( m_padNumCtrl ); break;
263 case 1: SetInitialFocus( m_thermalGapCtrl ); break;
264 case 2: SetInitialFocus( m_clearanceCtrl ); break;
265 }
266
268 m_initialized = true;
269
270 m_padNetSelector->Connect( FILTERED_ITEM_SELECTED,
271 wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ),
272 nullptr, this );
273
274 if( m_padType->GetSelection() != PTH_DLG_TYPE && m_padType->GetSelection() != NPTH_DLG_TYPE )
275 {
276 m_gbSizerHole->Show( false );
277 m_staticline71->Show( false );
278 }
279
280 // Now all widgets have the size fixed, call FinishDialogSettings
282
283 // Update widgets
284 wxUpdateUIEvent dummyUI;
285 OnUpdateUI( dummyUI );
286
287 // Post a dummy size event to force the pad preview panel to update the
288 // view: actual size, best zoom ... after the frame is shown
289 PostSizeEvent();
290}
291
292
294{
295 m_padNetSelector->Disconnect( FILTERED_ITEM_SELECTED,
296 wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ),
297 nullptr, this );
298
299 m_page = m_notebook->GetSelection();
300
301 delete m_previewPad;
302 delete m_axisOrigin;
303}
304
305
306// Store the pad draw option during a session.
308
309
310void DIALOG_PAD_PROPERTIES::OnInitDialog( wxInitDialogEvent& event )
311{
312 m_selectedColor = COLOR4D( 1.0, 1.0, 1.0, 0.7 );
313
314 // Needed on some WM to be sure the pad is redrawn according to the final size
315 // of the canvas, with the right zoom factor
316 redraw();
317}
318
319
320void DIALOG_PAD_PROPERTIES::OnCancel( wxCommandEvent& event )
321{
322 // Mandatory to avoid m_panelShowPadGal trying to draw something
323 // in a non valid context during closing process:
324 m_padPreviewGAL->StopDrawing();
325
326 // Now call default handler for wxID_CANCEL command event
327 event.Skip();
328}
329
330
332{
333 GAL_DISPLAY_OPTIONS_IMPL opts = m_parent->GetGalDisplayOptions();
334 COLOR_SETTINGS* colorSettings = m_parent->GetColorSettings();
335
336 opts.m_forceDisplayCursor = false;
337
338 // Initialize the canvas to display the pad
339 m_padPreviewGAL = new PCB_DRAW_PANEL_GAL( m_boardViewPanel, -1, wxDefaultPosition,
340 wxDefaultSize, opts,
341 m_parent->GetCanvas()->GetBackend() );
342
343 m_padPreviewSizer->Add( m_padPreviewGAL, 12, wxEXPAND | wxALL, 5 );
344
345 // Show the X and Y axis. It is useful because pad shape can have an offset
346 // or be a complex shape.
349 VECTOR2D( m_previewPad->GetPosition() ) );
350 m_axisOrigin->SetDrawAtZero( true );
351
352 m_padPreviewGAL->UpdateColors();
353 m_padPreviewGAL->SetStealsFocus( false );
354 m_padPreviewGAL->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
355
356 KIGFX::VIEW_CONTROLS* parentViewControls = m_parent->GetCanvas()->GetViewControls();
357 m_padPreviewGAL->GetViewControls()->ApplySettings( parentViewControls->GetSettings() );
358
359 m_padPreviewGAL->Show();
360
361 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
362
363 // fix the pad render mode (filled/not filled)
364 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
365
366 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
367 settings->SetHighContrast( false );
368 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
369
370 // don't show the locked item shadow in pad preview
372
373 // gives a non null grid size (0.001mm) because GAL layer does not like a 0 size grid:
374 double gridsize = 0.001 * pcbIUScale.IU_PER_MM;
375 view->GetGAL()->SetGridSize( VECTOR2D( gridsize, gridsize ) );
376
377 // And do not show the grid:
378 view->GetGAL()->SetGridVisibility( false );
379 view->GetGAL()->SetAxesEnabled( false );
380 view->Add( m_previewPad );
381 view->Add( m_axisOrigin );
382
383 m_padPreviewGAL->StartDrawing();
384 Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_PROPERTIES::OnResize ) );
385}
386
387
392
393
400
401
402void DIALOG_PAD_PROPERTIES::OnEditLayerChanged( wxCommandEvent& aEvent )
403{
404 // Save data from the previous layer
406
407 switch( m_previewPad->Padstack().Mode() )
408 {
409 default:
412 break;
413
415 switch( m_cbEditLayer->GetSelection() )
416 {
417 default:
418 case 0: m_editLayer = F_Cu; break;
419 case 1: m_editLayer = PADSTACK::INNER_LAYERS; break;
420 case 2: m_editLayer = B_Cu; break;
421 }
422 break;
423
425 {
426 int layer = m_cbEditLayer->GetSelection();
427
428 if( layer < 0 )
429 layer = 0;
430
431 if( m_editLayerCtrlMap.contains( layer ) )
432 m_editLayer = m_editLayerCtrlMap.at( layer );
433 else
435 }
436 }
437
438 // Load controls with the current layer
440
441 wxCommandEvent cmd_event;
442 onPadShapeSelection( false );
443 OnOffsetCheckbox( cmd_event );
444
445 redraw();
446}
447
448
450{
451 // Note: use ChangeValue() to avoid generating a wxEVT_TEXT event
452 m_cornerRadius.ChangeValue( m_previewPad->GetRoundRectCornerRadius( m_editLayer ) );
453
454 m_cornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
455 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
456
457 m_chamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
458 m_mixedChamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
459}
460
461
463{
466 {
467 return;
468 }
469
470 if( m_cornerRadius.GetValue() < 0 )
471 m_cornerRadiusCtrl->ChangeValue( "0" );
472
474 {
475 m_previewPad->SetRoundRectCornerRadius( m_editLayer, m_cornerRadius.GetValue() );
476
477 m_cornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
478 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
479
480 redraw();
481 }
482
483 if( m_initialized )
484 OnModify();
485}
486
487
489{
490 // The maximum chamfer ratio is 50% of the smallest pad side if adjacent sides
491 // are selected, or 100% of the smallest pad side if only one side is selected.
492 double baseline = 1.0;
493
494 auto considerCheckboxes = [&]( const std::vector<wxCheckBox*>& checkBoxes )
495 {
496 for( size_t ii : { 0, 1, 2, 3 } )
497 {
498 if( !checkBoxes[ii]->IsChecked() )
499 continue;
500
501 if( checkBoxes[( ii + 1 ) % 4]->IsChecked() || checkBoxes[( ii - 1 ) % 4]->IsChecked() )
502 {
503 // If two adjacent corners are selected, the maximum chamfer ratio is 50%
504 baseline = std::max( baseline, 0.5 );
505 break;
506 }
507 }
508 };
509
510
511 baseline = 1.0 - m_previewPad->GetRoundRectRadiusRatio( m_editLayer );
512 considerCheckboxes( { m_cbTopLeft1, m_cbTopRight1, m_cbBottomRight1, m_cbBottomLeft1 } );
513 considerCheckboxes( { m_cbTopLeft, m_cbTopRight, m_cbBottomRight, m_cbBottomLeft } );
514
515 // If only one corner is selected, the maximum chamfer ratio is 100%
516 return baseline;
517}
518
519
521{
522 return 1.0 - m_previewPad->GetChamferRectRatio( m_editLayer );
523}
524
525
527{
528 auto updateCheckBoxes = []( const std::vector<wxCheckBox*>& aCheckBoxes )
529 {
530 for( size_t ii : { 0, 1, 2, 3 } )
531 {
532 bool disable = aCheckBoxes[( ii + 1 ) % 4]->IsChecked()
533 || aCheckBoxes[( ii + 3 ) % 4]->IsChecked();
534
535 aCheckBoxes[ii]->Enable( !disable );
536
537 if( disable )
538 aCheckBoxes[ii]->SetValue( false );
539 }
540 };
541
542 if( m_mixedChamferRatio.GetDoubleValue() > 50.0 )
543 {
545 }
546
547 if( m_chamferRatio.GetDoubleValue() > 50.0 )
548 {
549 updateCheckBoxes( { m_cbTopLeft, m_cbTopRight, m_cbBottomRight, m_cbBottomLeft } );
550 }
551}
552
553
555{
558 {
559 return;
560 }
561
562 wxObject* ctrl = event.GetEventObject();
563 wxString value = event.GetString();
564 bool changed = false;
565
566 if( ctrl == m_cornerRatioCtrl || ctrl == m_mixedCornerRatioCtrl )
567 {
568 double ratioPercent;
569
570 if( value.ToDouble( &ratioPercent ) )
571 {
572 // Clamp ratioPercent to acceptable value (0.0 to 50.0)
573 double maxRatio = getMaxCornerRadius();
574
575 if( ratioPercent < 0.0 )
576 {
577 m_cornerRatio.SetDoubleValue( 0.0 );
578 m_mixedCornerRatio.SetDoubleValue( 0.0 );
579 }
580 else if( ratioPercent > maxRatio * 100.0 )
581 {
582 m_cornerRatio.SetDoubleValue( maxRatio * 100.0 );
583 m_mixedCornerRatio.SetDoubleValue( maxRatio * 100.0 );
584 }
585
586 if( ctrl == m_cornerRatioCtrl )
587 m_mixedCornerRatioCtrl->ChangeValue( value );
588 else
589 m_cornerRatioCtrl->ChangeValue( value );
590
591 changed = true;
592 }
593 }
594 else if( ctrl == m_chamferRatioCtrl || ctrl == m_mixedChamferRatioCtrl )
595 {
596 double ratioPercent;
597
598 if( value.ToDouble( &ratioPercent ) )
599 {
600 double maxRatio = getMaxChamferRatio();
601 // Clamp ratioPercent to acceptable value (0.0 to maxRatio)
602 if( ratioPercent < 0.0 )
603 {
604 m_chamferRatio.SetDoubleValue( 0.0 );
605 m_mixedChamferRatio.SetDoubleValue( 0.0 );
606 }
607 else if( ratioPercent > maxRatio * 100.0 )
608 {
609 m_chamferRatio.SetDoubleValue( maxRatio * 100.0 );
610 m_mixedChamferRatio.SetDoubleValue( maxRatio * 100.0 );
611 }
612
613 if( ctrl == m_chamferRatioCtrl )
614 m_mixedChamferRatioCtrl->ChangeValue( value );
615 else
616 m_chamferRatioCtrl->ChangeValue( value );
617
619
620 changed = true;
621 }
622 }
623
624 if( changed && transferDataToPad( m_previewPad ) )
625 m_cornerRadius.ChangeValue( m_previewPad->GetRoundRectCornerRadius( m_editLayer ) );
626
627 redraw();
628
629 if( m_initialized )
630 OnModify();
631}
632
633
635{
636 wxString msg;
637
638 // Disable pad net name wxTextCtrl if the caller is the footprint editor
639 // because nets are living only in the board managed by the board editor
641
642 m_layerFrontAdhesive->SetLabel( m_board->GetLayerName( F_Adhes ) );
643 m_layerBackAdhesive->SetLabel( m_board->GetLayerName( B_Adhes ) );
644 m_layerFrontPaste->SetLabel( m_board->GetLayerName( F_Paste ) );
645 m_layerBackPaste->SetLabel( m_board->GetLayerName( B_Paste ) );
646 m_layerFrontSilk->SetLabel( m_board->GetLayerName( F_SilkS ) );
647 m_layerBackSilk->SetLabel( m_board->GetLayerName( B_SilkS ) );
648 m_layerFrontMask->SetLabel( m_board->GetLayerName( F_Mask ) );
649 m_layerBackMask->SetLabel( m_board->GetLayerName( B_Mask ) );
650 m_layerECO1->SetLabel( m_board->GetLayerName( Eco1_User ) );
651 m_layerECO2->SetLabel( m_board->GetLayerName( Eco2_User ) );
652 m_layerUserDwgs->SetLabel( m_board->GetLayerName( Dwgs_User ) );
653
654 VECTOR2I absPos;
655
656 if( m_currentPad )
657 {
658 absPos = m_currentPad->GetPosition();
659
660 if( FOOTPRINT* footprint = m_currentPad->GetParentFootprint() )
661 {
662 VECTOR2I relPos = m_currentPad->GetFPRelativePosition();
663
664 if( footprint->IsFlipped() )
665 {
666 // flip pad (up/down) around its position
668 relPos.y = - relPos.y;
669 }
670
671 m_previewPad->SetPosition( relPos );
672 m_previewPad->SetOrientation( m_currentPad->GetFPRelativeOrientation() );
673
674 // Display parent footprint info
675 msg.Printf( _("Footprint %s (%s), %s, rotated %g deg"),
676 footprint->Reference().GetShownText( false ),
677 footprint->Value().GetShownText( false ),
678 footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
679 footprint->GetOrientation().AsDegrees() );
680
681 m_FlippedWarningSizer->Show( footprint->IsFlipped() );
682 m_parentInfo->SetLabel( msg );
683 }
684
685 m_padNumCtrl->SetValue( m_previewPad->GetNumber() );
686 }
687 else
688 {
689 PAD_TOOL* padTool = m_parent->GetToolManager()->GetTool<PAD_TOOL>();
690 m_padNumCtrl->SetValue( padTool->GetLastPadNumber() );
691 }
692
694
695 m_padNetSelector->SetSelectedNetcode( m_previewPad->GetNetCode() );
696
697 // Display current pad parameters units:
698 m_posX.ChangeValue( absPos.x );
699 m_posY.ChangeValue( absPos.y );
700
701 m_holeX.ChangeValue( m_previewPad->GetDrillSize().x );
702 m_holeY.ChangeValue( m_previewPad->GetDrillSize().y );
703
705
706 m_padToDieOpt->SetValue( m_previewPad->GetPadToDieLength() != 0 );
707 m_padToDie.ChangeValue( m_previewPad->GetPadToDieLength() );
708
709 m_padToDieDelayOpt->SetValue( m_previewPad->GetPadToDieDelay() != 0 );
710 m_padToDieDelay.ChangeValue( m_previewPad->GetPadToDieDelay() );
711
712 if( m_previewPad->GetLocalClearance().has_value() )
713 m_clearance.ChangeValue( m_previewPad->GetLocalClearance().value() );
714 else
715 m_clearance.ChangeValue( wxEmptyString );
716
717 if( m_previewPad->GetLocalSolderMaskMargin().has_value() )
718 m_maskMargin.ChangeValue( m_previewPad->GetLocalSolderMaskMargin().value() );
719 else
720 m_maskMargin.ChangeValue( wxEmptyString );
721
722 m_pasteMargin.SetOffsetValue( m_previewPad->GetLocalSolderPasteMargin() );
723 m_pasteMargin.SetRatioValue( m_previewPad->GetLocalSolderPasteMarginRatio() );
724
725 if( m_previewPad->GetLocalThermalSpokeWidthOverride().has_value() )
726 m_spokeWidth.ChangeValue( m_previewPad->GetLocalThermalSpokeWidthOverride().value() );
727 else
728 m_spokeWidth.SetNull();
729
730 if( m_previewPad->GetLocalThermalGapOverride().has_value() )
731 m_thermalGap.ChangeValue( m_previewPad->GetLocalThermalGapOverride().value() );
732 else
733 m_thermalGap.SetNull();
734
735 m_spokeAngle.ChangeAngleValue( m_previewPad->GetThermalSpokeAngle() );
736 m_pad_orientation.ChangeAngleValue( m_previewPad->GetOrientation() );
737
738 m_cbTeardrops->SetValue( m_previewPad->GetTeardropParams().m_Enabled );
739 m_cbTeardropsUseNextTrack->SetValue( m_previewPad->GetTeardropParams().m_AllowUseTwoTracks );
740 m_cbPreferZoneConnection->SetValue( !m_previewPad->GetTeardropParams().m_TdOnPadsInZones );
741 m_teardropMaxLenSetting.SetValue( m_previewPad->GetTeardropParams().m_TdMaxLen );
742 m_teardropMaxHeightSetting.SetValue( m_previewPad->GetTeardropParams().m_TdMaxWidth );
743 m_spTeardropLenPercent->SetValue( m_previewPad->GetTeardropParams().m_BestLengthRatio *100 );
744 m_spTeardropSizePercent->SetValue( m_previewPad->GetTeardropParams().m_BestWidthRatio *100 );
745 m_spTeardropHDPercent->SetValue( m_previewPad->GetTeardropParams().m_WidthtoSizeFilterRatio*100 );
746 m_curvedEdges->SetValue( m_previewPad->GetTeardropParams().m_CurvedEdges );
747
748 switch( m_previewPad->GetLocalZoneConnection() )
749 {
750 default:
751 case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
752 case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
753 case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
754 case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
755 }
756
757 if( m_previewPad->GetCustomShapeInZoneOpt() == CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL )
758 m_ZoneCustomPadShape->SetSelection( 1 );
759 else
760 m_ZoneCustomPadShape->SetSelection( 0 );
761
762 // Type of pad selection
763 bool aperture =
764 m_previewPad->GetAttribute() == PAD_ATTRIB::SMD && m_previewPad->IsAperturePad();
765
766 if( aperture )
767 {
768 m_padType->SetSelection( APERTURE_DLG_TYPE );
769 }
770 else
771 {
772 switch( m_previewPad->GetAttribute() )
773 {
774 case PAD_ATTRIB::PTH: m_padType->SetSelection( PTH_DLG_TYPE ); break;
775 case PAD_ATTRIB::SMD: m_padType->SetSelection( SMD_DLG_TYPE ); break;
776 case PAD_ATTRIB::CONN: m_padType->SetSelection( CONN_DLG_TYPE ); break;
777 case PAD_ATTRIB::NPTH: m_padType->SetSelection( NPTH_DLG_TYPE ); break;
778 }
779 }
780
781 switch( m_previewPad->GetProperty() )
782 {
783 case PAD_PROP::NONE: m_choiceFabProperty->SetSelection( 0 ); break;
784 case PAD_PROP::BGA: m_choiceFabProperty->SetSelection( 1 ); break;
785 case PAD_PROP::FIDUCIAL_LOCAL: m_choiceFabProperty->SetSelection( 2 ); break;
786 case PAD_PROP::FIDUCIAL_GLBL: m_choiceFabProperty->SetSelection( 3 ); break;
787 case PAD_PROP::TESTPOINT: m_choiceFabProperty->SetSelection( 4 ); break;
788 case PAD_PROP::HEATSINK: m_choiceFabProperty->SetSelection( 5 ); break;
789 case PAD_PROP::MECHANICAL: m_choiceFabProperty->SetSelection( 6 ); break;
790 case PAD_PROP::CASTELLATED: m_choiceFabProperty->SetSelection( 7 ); break;
791 case PAD_PROP::PRESSFIT: m_choiceFabProperty->SetSelection( 8 ); break;
792 }
793
794 if( m_previewPad->GetDrillShape() != PAD_DRILL_SHAPE::OBLONG )
795 m_holeShapeCtrl->SetSelection( 0 );
796 else
797 m_holeShapeCtrl->SetSelection( 1 );
798
799 // Backdrills are read through the PADSTACK accessors, which key the top/bottom side on the
800 // drill's start layer, so a pad written by KiCad 10.0 (top backdrill in the tertiary slot)
801 // loads correctly.
802 const PADSTACK& padstack = m_previewPad->Padstack();
803 std::optional<int> topBackdrillSize = padstack.GetBackdrillSize( true );
804 std::optional<int> bottomBackdrillSize = padstack.GetBackdrillSize( false );
805
806 m_backDrillChoice->SetSelection( topBackdrillSize ? ( bottomBackdrillSize ? 3 : 1 )
807 : ( bottomBackdrillSize ? 2 : 0 ) );
808
809 auto loadBackdrill = [&]( const std::optional<int>& aSize, PCB_LAYER_ID aEndLayer, UNIT_BINDER& aSizeBinder,
810 wxBitmapComboBox* aLayerCtrl )
811 {
812 if( !aSize )
813 {
814 aSizeBinder.SetValue( 0 );
815 return;
816 }
817
818 aSizeBinder.SetValue( *aSize );
819
820 for( unsigned int i = 0; i < aLayerCtrl->GetCount(); ++i )
821 {
822 if( ToLAYER_ID( (intptr_t) aLayerCtrl->GetClientData( i ) ) == aEndLayer )
823 {
824 aLayerCtrl->SetSelection( i );
825 break;
826 }
827 }
828 };
829
830 loadBackdrill( topBackdrillSize, padstack.GetBackdrillEndLayer( true ), m_backDrillTopSizeBinder,
832 loadBackdrill( bottomBackdrillSize, padstack.GetBackdrillEndLayer( false ), m_backDrillBottomSizeBinder,
834
835 // Post machining
836 const PADSTACK::POST_MACHINING_PROPS& frontPostMachining = m_previewPad->Padstack().FrontPostMachining();
837
838 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
839 m_topPostMachining->SetSelection( 2 );
840 else if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
841 m_topPostMachining->SetSelection( 1 );
842 else
843 m_topPostMachining->SetSelection( 0 );
844
845 m_topPostMachineSize1Binder.SetValue( frontPostMachining.size );
846
847 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
848 {
850 m_topPostMachineSize2Binder.SetDoubleValue( frontPostMachining.angle / 10.0 );
851 }
852 else
853 {
854 m_topPostMachineSize2Binder.SetValue( frontPostMachining.depth );
855 }
856
857 const PADSTACK::POST_MACHINING_PROPS& backPostMachining = m_previewPad->Padstack().BackPostMachining();
858
859 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
860 m_bottomPostMachining->SetSelection( 2 );
861 else if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
862 m_bottomPostMachining->SetSelection( 1 );
863 else
864 m_bottomPostMachining->SetSelection( 0 );
865
866 m_bottomPostMachineSize1Binder.SetValue( backPostMachining.size );
867
868 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
869 {
871 m_bottomPostMachineSize2Binder.SetDoubleValue( backPostMachining.angle / 10.0 );
872 }
873 else
874 {
875 m_bottomPostMachineSize2Binder.SetValue( backPostMachining.depth );
876 }
877
878 switch( m_previewPad->GetSimElectricalType() )
879 {
880 case PAD_SIM_ELECTRICAL_TYPE::NONE: m_simElectricalTypeCtrl->SetSelection( 0 ); break;
881 case PAD_SIM_ELECTRICAL_TYPE::SOURCE: m_simElectricalTypeCtrl->SetSelection( 1 ); break;
882 case PAD_SIM_ELECTRICAL_TYPE::SINK: m_simElectricalTypeCtrl->SetSelection( 2 ); break;
883 }
884
885 updatePadLayersList( m_previewPad->GetLayerSet(), m_previewPad->GetRemoveUnconnected(),
886 m_previewPad->GetKeepTopBottom() );
887
888 // Update some dialog widgets state (Enable/disable options):
889 wxCommandEvent cmd_event;
890 onPadShapeSelection( false );
891 OnOffsetCheckbox( cmd_event );
893}
894
895
897{
898 m_primitives = m_previewPad->GetPrimitives( m_editLayer );
899
900 m_sizeX.ChangeValue( m_previewPad->GetSize( m_editLayer ).x );
901 m_sizeY.ChangeValue( m_previewPad->GetSize( m_editLayer ).y );
902
903 m_offsetShapeOpt->SetValue( m_previewPad->GetOffset( m_editLayer ) != VECTOR2I() );
904 m_offsetX.ChangeValue( m_previewPad->GetOffset( m_editLayer ).x );
905 m_offsetY.ChangeValue( m_previewPad->GetOffset( m_editLayer ).y );
906
907 if( m_previewPad->GetDelta( m_editLayer ).x )
908 {
909 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).x );
910 m_trapAxisCtrl->SetSelection( 0 );
911 }
912 else
913 {
914 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).y );
915 m_trapAxisCtrl->SetSelection( 1 );
916 }
917
918 switch( m_previewPad->GetShape( m_editLayer ) )
919 {
920 default:
921 case PAD_SHAPE::CIRCLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
922 case PAD_SHAPE::OVAL: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_OVAL ); break;
923 case PAD_SHAPE::RECTANGLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_RECT ); break;
926
928 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) > 0.0 )
930 else
932 break;
933
935 if( m_previewPad->GetAnchorPadShape( m_editLayer ) == PAD_SHAPE::RECTANGLE )
937 else
939 break;
940 }
941
942 int chamferPositions = m_previewPad->GetChamferPositions( m_editLayer );
943
944 m_cbTopLeft->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
945 m_cbTopLeft1->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
946 m_cbTopRight->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
947 m_cbTopRight1->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
948 m_cbBottomLeft->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
949 m_cbBottomLeft1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
950 m_cbBottomRight->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
951 m_cbBottomRight1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
952
954}
955
956
958{
959 // NOTE: synchronize changes here with DIALOG_TRACK_VIA_PROPERTIES::afterPadstackModeChanged
960
961 wxCHECK_MSG( m_board, /* void */, "Expected valid board in afterPadstackModeChanged" );
962 m_cbEditLayer->Clear();
963
964 switch( m_previewPad->Padstack().Mode() )
965 {
967 m_cbPadstackMode->SetSelection( 0 );
968 m_cbEditLayer->Append( m_board->GetLayerName( F_Cu ) );
969 m_cbEditLayer->Disable();
971 m_editLayerCtrlMap = { { 0, F_Cu } };
972 break;
973
975 {
976 m_cbPadstackMode->SetSelection( 1 );
977 m_cbEditLayer->Enable();
978
979 std::vector choices = {
980 m_board->GetLayerName( F_Cu ),
981 _( "Inner Layers" ),
982 m_board->GetLayerName( B_Cu )
983 };
984
985 m_cbEditLayer->Append( choices );
986
988 { 0, F_Cu },
990 { 2, B_Cu }
991 };
992
993 if( m_editLayer != F_Cu && m_editLayer != B_Cu )
995
996 break;
997 }
998
1000 {
1001 m_cbPadstackMode->SetSelection( 2 );
1002 m_cbEditLayer->Enable();
1003 LSET layers = LSET::AllCuMask() & m_board->GetEnabledLayers();
1004
1005 for( PCB_LAYER_ID layer : layers.UIOrder() )
1006 {
1007 int idx = m_cbEditLayer->Append( m_board->GetLayerName( layer ) );
1008 m_editLayerCtrlMap[idx] = layer;
1009 }
1010
1011 break;
1012 }
1013 }
1014
1015 for( const auto& [idx, layer] : m_editLayerCtrlMap )
1016 {
1017 if( layer == m_editLayer )
1018 {
1019 m_cbEditLayer->SetSelection( idx );
1020 break;
1021 }
1022 }
1023}
1024
1025
1026void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
1027{
1028 redraw();
1029 event.Skip();
1030}
1031
1032
1034{
1035 m_sketchPreview = m_cbShowPadOutline->GetValue();
1036
1037 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1038
1039 // fix the pad render mode (filled/not filled)
1040 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
1041
1042 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
1043 settings->SetHighContrast( false );
1044 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
1045
1046 redraw();
1047}
1048
1049
1051{
1052 onPadShapeSelection( true );
1053}
1054
1055
1057{
1058 switch( m_PadShapeSelector->GetSelection() )
1059 {
1061 case CHOICE_SHAPE_OVAL:
1062 case CHOICE_SHAPE_RECT:
1063 m_shapePropsBook->SetSelection( 0 );
1064 break;
1065
1067 m_shapePropsBook->SetSelection( 1 );
1068 break;
1069
1071 {
1072 m_shapePropsBook->SetSelection( 2 );
1073
1074 // Reasonable defaults
1075 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0 )
1076 {
1077 const double ipcRadiusRatio =
1079 m_cornerRatio.ChangeDoubleValue( ipcRadiusRatio * 100 );
1080 }
1081
1082 break;
1083 }
1084
1086 m_shapePropsBook->SetSelection( 3 );
1087
1088 // Reasonable default
1089 if( m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1090 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1091
1092 // Ensure the displayed value is up to date:
1093 m_chamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1094
1095 // A reasonable default is one corner chamfered (usual for some SMD pads).
1096 if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
1097 && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
1098 {
1099 m_cbTopLeft->SetValue( true );
1100 m_cbTopRight->SetValue( false );
1101 m_cbBottomLeft->SetValue( false );
1102 m_cbBottomRight->SetValue( false );
1103 }
1104
1105 break;
1106
1108 m_shapePropsBook->SetSelection( 4 );
1109
1110 // Reasonable defaults
1111 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0
1112 && m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1113 {
1114 const double ipcRadiusRatio =
1116 m_previewPad->SetRoundRectRadiusRatio( m_editLayer, ipcRadiusRatio );
1117 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1118 }
1119
1120 // Ensure the displayed values are up to date:
1121 m_mixedChamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1122 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
1123 break;
1124
1125 case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE::CUSTOM, circular anchor
1126 case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE::CUSTOM, rect anchor
1127 m_shapePropsBook->SetSelection( 0 );
1128 break;
1129 }
1130
1131 if( aUpdateSpokeAngle )
1132 {
1133 // Note: must do this before enabling/disabling m_sizeY as we're using that as a flag to see
1134 // what the last shape was.
1135 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE )
1136 {
1137 if( m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_90 )
1138 m_spokeAngle.SetAngleValue( ANGLE_45 );
1139 }
1140 else
1141 {
1142 if( !m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_45 )
1143 m_spokeAngle.SetAngleValue( ANGLE_90 );
1144 }
1145 }
1146
1147 // Readjust props book size
1148 wxSize size = m_shapePropsBook->GetSize();
1149 size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
1150 m_shapePropsBook->SetMaxSize( size );
1151
1152 m_sizeY.Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE
1154
1155 m_offsetShapeOpt->Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE );
1156
1157 if( !m_offsetShapeOpt->IsEnabled() )
1158 m_offsetShapeOpt->SetValue( false );
1159
1160 // Show/hide controls depending on m_offsetShapeOpt being enabled
1161 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
1162 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
1163
1166
1167 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
1168 m_notebook->GetPage( i )->Layout();
1169
1170 // Resize the dialog if its height is too small to show all widgets:
1171 if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
1172 m_MainSizer->SetSizeHints( this );
1173
1175 redraw();
1176
1177 if( m_initialized )
1178 OnModify();
1179}
1180
1181
1183{
1184 if( m_holeShapeCtrl->GetSelection() != CHOICE_SHAPE_CIRCLE )
1185 {
1186 bool hasBackdrill = ( m_backDrillChoice->GetSelection() != 0 );
1187 bool hasTopPost = ( m_topPostMachining->GetSelection() != 0 );
1188 bool hasBottomPost = ( m_bottomPostMachining->GetSelection() != 0 );
1189
1190 if( hasBackdrill || hasTopPost || hasBottomPost )
1191 {
1192 if( wxMessageBox( _( "Switching to non-circular hole will disable backdrills and post-machining. Continue?" ),
1193 _( "Warning" ), wxOK | wxCANCEL | wxICON_WARNING, this ) != wxOK )
1194 {
1195 m_holeShapeCtrl->SetSelection( CHOICE_SHAPE_CIRCLE );
1196 return;
1197 }
1198 }
1199 }
1200
1203 redraw();
1204
1205 if( m_initialized )
1206 OnModify();
1207}
1208
1209
1210void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
1211{
1213 redraw();
1214
1215 if( m_initialized )
1216 OnModify();
1217}
1218
1219
1221{
1222 m_rbCopperLayersSel->Clear();
1223
1224 switch( m_padType->GetSelection() )
1225 {
1226 case PTH_DLG_TYPE:
1227 m_rbCopperLayersSel->Append( _( "All copper layers" ) );
1228 m_rbCopperLayersSel->Append( wxString::Format( _( "%s, %s and connected layers" ),
1229 m_board->GetLayerName( F_Cu ),
1230 m_board->GetLayerName( B_Cu ) ) );
1231 m_rbCopperLayersSel->Append( _( "Connected layers only" ) );
1232 m_rbCopperLayersSel->Append( _( "None" ) );
1233 break;
1234
1235 case NPTH_DLG_TYPE:
1236 m_rbCopperLayersSel->Append( wxString::Format( _( "%s and %s" ),
1237 m_board->GetLayerName( F_Cu ),
1238 m_board->GetLayerName( B_Cu ) ) );
1239 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1240 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1241 m_rbCopperLayersSel->Append( _( "None" ) );
1242 break;
1243
1244 case SMD_DLG_TYPE:
1245 case CONN_DLG_TYPE:
1246 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1247 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1248 break;
1249
1250 case APERTURE_DLG_TYPE:
1251 m_rbCopperLayersSel->Append( _( "None" ) );
1252 break;
1253 }
1254
1255 m_backDrillTopLayer->Clear();
1256 m_backDrillBottomLayer->Clear();
1257
1258 for( PCB_LAYER_ID layerId : m_board->GetEnabledLayers().UIOrder() )
1259 {
1260 if( IsCopperLayer( layerId ) )
1261 {
1262 wxString layerName = m_board->GetLayerName( layerId );
1263 m_backDrillTopLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1264 m_backDrillBottomLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1265 }
1266 }
1267}
1268
1269
1270void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
1271{
1272 bool hasHole = true;
1273 bool hasConnection = true;
1274
1275 switch( m_padType->GetSelection() )
1276 {
1277 case PTH_DLG_TYPE: hasHole = true; hasConnection = true; break;
1278 case SMD_DLG_TYPE: hasHole = false; hasConnection = true; break;
1279 case CONN_DLG_TYPE: hasHole = false; hasConnection = true; break;
1280 case NPTH_DLG_TYPE: hasHole = true; hasConnection = false; break;
1281 case APERTURE_DLG_TYPE: hasHole = false; hasConnection = false; break;
1282 }
1283
1284 // Pad type just changed, so the old pad's layer set is no longer meaningful. Pass nullopt
1285 // to populate the defaults for the new type.
1286 updatePadLayersList( std::nullopt, m_previewPad->GetRemoveUnconnected(),
1287 m_previewPad->GetKeepTopBottom() );
1288
1289 m_gbSizerHole->Show( hasHole );
1290 m_staticline71->Show( hasHole );
1291
1292 if( !hasHole )
1293 {
1294 m_holeX.ChangeValue( 0 );
1295 m_holeY.ChangeValue( 0 );
1296 }
1297 else if( m_holeX.GetValue() == 0 )
1298 {
1299 if( m_currentPad )
1300 {
1301 m_holeX.ChangeValue( m_currentPad->GetDrillSize().x );
1302 m_holeY.ChangeValue( m_currentPad->GetDrillSize().y );
1303 }
1304 else
1305 {
1306 m_holeX.ChangeValue( pcbIUScale.mmToIU( DEFAULT_PAD_DRILL_DIAMETER_MM ) );
1307 }
1308 }
1309
1310 if( !hasConnection )
1311 {
1312 m_padNumCtrl->ChangeValue( wxEmptyString );
1313 m_padNetSelector->SetSelectedNetcode( 0 );
1314 m_padToDieOpt->SetValue( false );
1315 m_padToDieDelayOpt->SetValue( false );
1316 }
1317 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1318 {
1319 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1320 m_padNetSelector->SetSelectedNetcode( m_currentPad->GetNetCode() );
1321 }
1322
1324
1325 // For now, padstack controls only enabled for PTH pads
1326 bool enablePadstack = m_padType->GetSelection() == PTH_DLG_TYPE;
1327 m_padstackControls->Show( enablePadstack );
1328
1329 if( !enablePadstack )
1330 {
1331 m_editLayer = F_Cu;
1333 }
1334
1335 // Layout adjustment is needed if the hole details got shown/hidden
1336 m_LeftBoxSizer->Layout();
1337 redraw();
1338
1339 if( m_initialized )
1340 OnModify();
1341}
1342
1343
1344void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1345{
1346 bool hasHole = true;
1347 bool hasConnection = true;
1348
1349 switch( m_padType->GetSelection() )
1350 {
1351 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1352 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1353 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1354 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1355 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1356 }
1357
1358 // Enable/disable hole controls
1359 m_holeShapeLabel->Enable( hasHole );
1360 m_holeShapeCtrl->Enable( hasHole );
1361 m_holeX.Enable( hasHole );
1362 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1363
1364 // Enable/disable number and net
1365 m_padNumLabel->Enable( hasConnection );
1366 m_padNumCtrl->Enable( hasConnection );
1367
1368 if( m_padNetLabel->IsShown() )
1369 {
1370 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1371 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1372 }
1373
1374 // Enable/disable pad length-to-die
1375 m_padToDieOpt->Enable( hasConnection );
1376 m_padToDieDelayOpt->Enable( hasConnection );
1377
1378 if( !m_padToDieOpt->IsEnabled() )
1379 m_padToDieOpt->SetValue( false );
1380
1381 if( !m_padToDieDelayOpt->IsEnabled() )
1382 m_padToDieDelayOpt->SetValue( false );
1383
1384 // We can show/hide this here because it doesn't require the layout to be refreshed.
1385 // All the others have to be done in their event handlers because doing a layout here
1386 // causes infinite looping on MSW.
1387 m_padToDie.Show( m_padToDieOpt->GetValue() );
1388 m_padToDieDelay.Show( m_padToDieDelayOpt->GetValue() );
1389
1390 // Enable/disable Copper Layers control
1391 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1392
1393 LSET cu_set = m_previewPad->GetLayerSet() & LSET::AllCuMask();
1394
1395 switch( m_padType->GetSelection() )
1396 {
1397 case PTH_DLG_TYPE:
1398 if( !cu_set.any() )
1399 m_stackupImagesBook->SetSelection( 3 );
1400 else if( !m_previewPad->GetRemoveUnconnected() )
1401 m_stackupImagesBook->SetSelection( 0 );
1402 else if( m_previewPad->GetKeepTopBottom() )
1403 m_stackupImagesBook->SetSelection( 1 );
1404 else
1405 m_stackupImagesBook->SetSelection( 2 );
1406
1407 break;
1408
1409 case NPTH_DLG_TYPE:
1410 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1411 m_stackupImagesBook->SetSelection( 4 );
1412 else if( cu_set.test( F_Cu ) )
1413 m_stackupImagesBook->SetSelection( 5 );
1414 else if( cu_set.test( B_Cu ) )
1415 m_stackupImagesBook->SetSelection( 6 );
1416 else
1417 m_stackupImagesBook->SetSelection( 7 );
1418
1419 break;
1420
1421 case SMD_DLG_TYPE:
1422 case CONN_DLG_TYPE:
1423 case APERTURE_DLG_TYPE:
1424 m_stackupImagesBook->ChangeSelection( 3 );
1425 break;
1426 }
1427
1428 m_legacyTeardropsWarning->Show( m_board->LegacyTeardrops() );
1429}
1430
1431
1433{
1434 event.Enable( !m_board->LegacyTeardrops() );
1435}
1436
1437
1439{
1440 bool isOnCopperLayer = ( m_previewPad->GetLayerSet() & LSET::AllCuMask() ).any();
1441 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1442}
1443
1444
1445void DIALOG_PAD_PROPERTIES::updatePadLayersList( std::optional<LSET> layer_mask,
1446 bool remove_unconnected, bool keep_top_bottom )
1447{
1449
1450 // An empty LSET supplied by the caller is a valid user choice (a pad with no layers);
1451 // std::nullopt is the signal that defaults for the current pad type should be used instead.
1452 LSET effective_mask;
1453
1454 switch( m_padType->GetSelection() )
1455 {
1456 case PTH_DLG_TYPE:
1457 effective_mask = layer_mask.value_or( PAD::PTHMask() );
1458
1459 if( !( effective_mask & LSET::AllCuMask() ).any() )
1460 m_rbCopperLayersSel->SetSelection( 3 );
1461 else if( !remove_unconnected )
1462 m_rbCopperLayersSel->SetSelection( 0 );
1463 else if( keep_top_bottom )
1464 m_rbCopperLayersSel->SetSelection( 1 );
1465 else
1466 m_rbCopperLayersSel->SetSelection( 2 );
1467
1468 break;
1469
1470 case SMD_DLG_TYPE:
1471 // The SMD/CONN UI has no "no copper" radio choice, so fall back to defaults if the
1472 // stored mask has no copper layers. Otherwise saving would silently force B_Cu.
1473 effective_mask = layer_mask.value_or( PAD::SMDMask() );
1474
1475 if( !( effective_mask & LSET::AllCuMask() ).any() )
1476 effective_mask = PAD::SMDMask();
1477
1478 if( effective_mask.test( F_Cu ) )
1479 m_rbCopperLayersSel->SetSelection( 0 );
1480 else
1481 m_rbCopperLayersSel->SetSelection( 1 );
1482
1483 break;
1484
1485 case CONN_DLG_TYPE:
1486 effective_mask = layer_mask.value_or( PAD::ConnSMDMask() );
1487
1488 if( !( effective_mask & LSET::AllCuMask() ).any() )
1489 effective_mask = PAD::ConnSMDMask();
1490
1491 if( effective_mask.test( F_Cu ) )
1492 m_rbCopperLayersSel->SetSelection( 0 );
1493 else
1494 m_rbCopperLayersSel->SetSelection( 1 );
1495
1496 break;
1497
1498 case NPTH_DLG_TYPE:
1499 effective_mask = layer_mask.value_or( PAD::UnplatedHoleMask() );
1500
1501 if( effective_mask.test( F_Cu ) && effective_mask.test( B_Cu ) )
1502 m_rbCopperLayersSel->SetSelection( 0 );
1503 else if( effective_mask.test( F_Cu ) )
1504 m_rbCopperLayersSel->SetSelection( 1 );
1505 else if( effective_mask.test( B_Cu ) )
1506 m_rbCopperLayersSel->SetSelection( 2 );
1507 else
1508 m_rbCopperLayersSel->SetSelection( 3 );
1509
1510 break;
1511
1512 case APERTURE_DLG_TYPE:
1513 effective_mask = layer_mask.value_or( PAD::ApertureMask() );
1514
1515 m_rbCopperLayersSel->SetSelection( 0 );
1516 break;
1517 }
1518
1519 m_layerFrontAdhesive->SetValue( effective_mask[F_Adhes] );
1520 m_layerBackAdhesive->SetValue( effective_mask[B_Adhes] );
1521
1522 m_layerFrontPaste->SetValue( effective_mask[F_Paste] );
1523 m_layerBackPaste->SetValue( effective_mask[B_Paste] );
1524
1525 m_layerFrontSilk->SetValue( effective_mask[F_SilkS] );
1526 m_layerBackSilk->SetValue( effective_mask[B_SilkS] );
1527
1528 m_layerFrontMask->SetValue( effective_mask[F_Mask] );
1529 m_layerBackMask->SetValue( effective_mask[B_Mask] );
1530
1531 m_layerECO1->SetValue( effective_mask[Eco1_User] );
1532 m_layerECO2->SetValue( effective_mask[Eco2_User] );
1533
1534 m_layerUserDwgs->SetValue( effective_mask[Dwgs_User] );
1535}
1536
1537
1539{
1540 bool retVal = DIALOG_SHIM::Show( aShow );
1541
1542 if( aShow )
1543 {
1544 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1545 // wxWidgets needs to have these set when the panel is visible for some reason.
1546 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1554
1555 Layout();
1556 }
1557
1558 return retVal;
1559}
1560
1561
1562void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1563{
1565 redraw();
1566
1567 if( m_initialized )
1568 OnModify();
1569}
1570
1571
1572void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1573{
1575 redraw();
1576
1577 if( m_initialized )
1578 OnModify();
1579}
1580
1581
1583{
1585
1586 wxArrayString error_msgs;
1587 wxArrayString warning_msgs;
1588
1589 m_previewPad->CheckPad( m_parentFrame, true,
1590 [&]( int errorCode, const wxString& msg )
1591 {
1592 if( errorCode == DRCE_PADSTACK_INVALID )
1593 error_msgs.Add( _( "Error: " ) + msg );
1594 else if( errorCode == DRCE_PADSTACK )
1595 warning_msgs.Add( _( "Warning: " ) + msg );
1596 else if( errorCode == DRCE_PAD_TH_WITH_NO_HOLE )
1597 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1598 } );
1599
1600 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1601 {
1602 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1603 : _( "Pad Properties Warnings" );
1604 HTML_MESSAGE_BOX dlg( this, title );
1605
1606 wxArrayString msgs = error_msgs;
1607
1608 for( const wxString& msg : warning_msgs )
1609 msgs.Add( msg );
1610
1611 dlg.ListSet( msgs );
1612
1613 dlg.ShowModal();
1614 }
1615
1616 return error_msgs.GetCount() == 0;
1617}
1618
1619
1621{
1622 if( !m_initialized )
1623 return;
1624
1625 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1626 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view->GetPainter() );
1627 KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings();
1628
1629 m_padPreviewGAL->StopDrawing();
1630
1631 // The layer used to place primitive items selected when editing custom pad shapes
1632 // we use here a layer never used in a pad:
1633 #define SELECTED_ITEMS_LAYER Dwgs_User
1634
1635 view->ClearTopLayers();
1637 view->SetTopLayer( m_editLayer );
1639
1640 static const std::vector<int> topLayers = {
1645 };
1646
1647 for( int layer : topLayers )
1648 view->SetTopLayer( layer );
1649
1650 m_axisOrigin->SetPosition( m_previewPad->GetPosition() );
1651
1652 view->Update( m_previewPad );
1653
1654 // delete previous items if highlight list
1655 while( m_highlight.size() )
1656 {
1657 delete m_highlight.back(); // the dtor also removes item from view
1658 m_highlight.pop_back();
1659 }
1660
1661 BOX2I bbox = m_previewPad->ViewBBox();
1662
1663 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1664 {
1665 // The origin always goes in the middle of the canvas; we want offsetting the pad
1666 // shape to move the pad, not the hole
1667 bbox.Move( -m_previewPad->GetPosition() );
1668 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1669 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1670
1671 // Don't blow up the GAL on too-large numbers
1672 if( maxXExtent > INT_MAX / 4 )
1673 maxXExtent = INT_MAX / 4;
1674
1675 if( maxYExtent > INT_MAX / 4 )
1676 maxYExtent = INT_MAX / 4;
1677
1678 BOX2D viewBox( m_previewPad->GetPosition(), {0, 0} );
1679 BOX2D canvasBox( m_previewPad->GetPosition(), {0, 0} );
1680 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1681 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1682
1683 view->SetBoundary( canvasBox );
1684
1685 // Autozoom
1686 view->SetViewport( viewBox );
1687
1688 m_padPreviewGAL->StartDrawing();
1689 m_padPreviewGAL->Refresh();
1690 }
1691}
1692
1693
1695{
1696 if( !wxDialog::TransferDataToWindow() )
1697 return false;
1698
1699 if( !m_panelGeneral->TransferDataToWindow() )
1700 return false;
1701
1702 if( !m_localSettingsPanel->TransferDataToWindow() )
1703 return false;
1704
1705 return true;
1706}
1707
1708
1710{
1711 BOARD_COMMIT commit( m_parent );
1712
1713 if( !wxDialog::TransferDataFromWindow() )
1714 return false;
1715
1716 if( !m_panelGeneral->TransferDataFromWindow() )
1717 return false;
1718
1719 if( !m_localSettingsPanel->TransferDataFromWindow() )
1720 return false;
1721
1722 if( !padValuesOK() )
1723 return false;
1724
1726 return false;
1727
1728 m_padPreviewGAL->StopDrawing();
1729
1730 PAD_TOOL* padTool = m_parent->GetToolManager()->GetTool<PAD_TOOL>();
1731 padTool->SetLastPadNumber( m_masterPad->GetNumber() );
1732
1733 // m_masterPad is a pattern: ensure there is no net for this pad:
1735
1736 if( !m_currentPad ) // Set current Pad parameters
1737 return true;
1738
1739 commit.Modify( m_currentPad );
1740
1741 // Update values
1742
1743 // transferDataToPad only handles the current edit layer, so m_masterPad isn't accurate
1744 // TODO(JE) this could be cleaner
1745 m_currentPad->SetPadstack( m_previewPad->Padstack() );
1746
1747 m_currentPad->SetAttribute( m_masterPad->GetAttribute() );
1748 m_currentPad->SetSimElectricalType( m_masterPad->GetSimElectricalType() );
1749 m_currentPad->SetFPRelativeOrientation( m_masterPad->GetOrientation() );
1750 m_currentPad->SetPadToDieLength( m_masterPad->GetPadToDieLength() );
1751 m_currentPad->SetPadToDieDelay( m_masterPad->GetPadToDieDelay() );
1752 m_currentPad->SetLayerSet( m_masterPad->GetLayerSet() );
1753 m_currentPad->SetNumber( m_masterPad->GetNumber() );
1754
1755 int padNetcode = NETINFO_LIST::UNCONNECTED;
1756
1757 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1758 if( m_masterPad->GetAttribute() != PAD_ATTRIB::NPTH )
1759 padNetcode = m_padNetSelector->GetSelectedNetcode();
1760
1761 m_currentPad->SetNetCode( padNetcode );
1762
1763 m_currentPad->GetTeardropParams() = m_masterPad->GetTeardropParams();
1764
1765 // Set the fabrication property:
1766 m_currentPad->SetProperty( getSelectedProperty() );
1767
1768 // define the way the clearance area is defined in zones
1769 m_currentPad->SetCustomShapeInZoneOpt( m_masterPad->GetCustomShapeInZoneOpt() );
1770
1771 if( m_currentPad->GetParentFootprint() && m_currentPad->GetParentFootprint()->IsFlipped() )
1772 {
1773 // flip pad (up/down) around its position
1774 m_currentPad->Flip( m_currentPad->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1775 }
1776
1777 m_currentPad->SetPosition( m_masterPad->GetPosition() );
1778
1779 m_parent->SetMsgPanel( m_currentPad );
1780
1781 // redraw the area where the pad was
1782 m_parent->GetCanvas()->Refresh();
1783
1784 commit.Push( _( "Edit Pad Properties" ) );
1785
1786 return true;
1787}
1788
1789
1791{
1792 PAD_PROP prop = PAD_PROP::NONE;
1793
1794 switch( m_choiceFabProperty->GetSelection() )
1795 {
1796 case 0: prop = PAD_PROP::NONE; break;
1797 case 1: prop = PAD_PROP::BGA; break;
1798 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1799 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1800 case 4: prop = PAD_PROP::TESTPOINT; break;
1801 case 5: prop = PAD_PROP::HEATSINK; break;
1802 case 6: prop = PAD_PROP::MECHANICAL; break;
1803 case 7: prop = PAD_PROP::CASTELLATED; break;
1804 case 8: prop = PAD_PROP::PRESSFIT; break;
1805 }
1806
1807 return prop;
1808}
1809
1810
1812{
1813 bool isRound = ( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE );
1814
1815 if( isRound )
1816 {
1817 m_holeXLabel->SetLabel( _( "Diameter:" ) );
1818 m_holeY.Show( false );
1819 }
1820 else
1821 {
1822 m_holeXLabel->SetLabel( _( "Hole size X:" ) );
1823 m_holeY.Show( true );
1824 }
1825
1826 m_holeXLabel->GetParent()->Layout();
1827
1828 if( !isRound )
1829 {
1830 // Disable all
1831 m_backDrillChoice->Enable( false );
1832 m_backDrillTopLayer->Enable( false );
1833 m_backDrillTopLayerLabel->Enable( false );
1834 m_backDrillBottomLayer->Enable( false );
1835 m_backDrillBottomLayerLabel->Enable( false );
1836
1837 m_topPostMachining->Enable( false );
1838 m_topPostMachineSize1Binder.Enable( false );
1839 m_topPostMachineSize2Binder.Enable( false );
1840 m_topPostMachineSize1Label->Enable( false );
1841 m_topPostMachineSize2Label->Enable( false );
1842
1843 m_bottomPostMachining->Enable( false );
1844 m_bottomPostMachineSize1Binder.Enable( false );
1845 m_bottomPostMachineSize2Binder.Enable( false );
1846 m_bottomPostMachineSize1Label->Enable( false );
1847 m_bottomPostMachineSize2Label->Enable( false );
1848 }
1849 else
1850 {
1851 // Enable main choices
1852 m_backDrillChoice->Enable( true );
1853 m_topPostMachining->Enable( true );
1854 m_bottomPostMachining->Enable( true );
1855
1856 // Update sub-controls based on selection
1857 wxCommandEvent dummy;
1861 }
1862}
1863
1864
1866{
1867 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1869 {
1870 m_sizeXLabel->SetLabel( _( "Diameter:" ) );
1871 m_sizeY.Show( false );
1873 m_minTrackWidthHint->SetLabel( _( "d" ) );
1874 m_stLenPercentHint->SetLabel( _( "d" ) );
1875 m_stWidthPercentHint->SetLabel( _( "d" ) );
1876 }
1877 else
1878 {
1879 m_sizeXLabel->SetLabel( _( "Pad size X:" ) );
1880 m_sizeY.Show( true );
1882 m_minTrackWidthHint->SetLabel( _( "w" ) );
1883 m_stLenPercentHint->SetLabel( _( "w" ) );
1884 m_stWidthPercentHint->SetLabel( _( "w" ) );
1885 }
1886
1887 m_sizeXLabel->GetParent()->Layout();
1888 resetSize();
1889 Layout();
1890 m_MainSizer->Fit( this );
1891}
1892
1893
1895{
1896 std::map<PCB_LAYER_ID, PCB_LAYER_ID> newLayerMap; // Map of new-layerss to init-from-layers
1897
1898 auto setMode =
1899 [&]( PADSTACK::MODE mode )
1900 {
1901 PADSTACK oldStack = aPad->Padstack();
1902
1903 aPad->Padstack().SetMode( mode );
1904
1906 [&]( PCB_LAYER_ID layer )
1907 {
1908 if( !oldStack.HasExplicitDefinitionForLayer( layer ) )
1909 {
1910 if( IsInnerCopperLayer( layer ) && layer != PADSTACK::INNER_LAYERS )
1911 newLayerMap[layer] = PADSTACK::INNER_LAYERS;
1912 else
1913 newLayerMap[layer] = F_Cu;
1914 }
1915 } );
1916 };
1917
1918 if( !Validate() )
1919 return false;
1920
1921 if( !m_panelGeneral->Validate() )
1922 return false;
1923
1924 if( !m_localSettingsPanel->Validate() )
1925 return false;
1926
1927 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1928 return false;
1929
1930 switch( m_cbPadstackMode->GetSelection() )
1931 {
1932 default:
1933 case 0: setMode( PADSTACK::MODE::NORMAL ); break;
1934 case 1: setMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1935 case 2: setMode( PADSTACK::MODE::CUSTOM ); break;
1936 }
1937
1938 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1939 aPad->SetShape( m_editLayer, code_shape[m_PadShapeSelector->GetSelection()] );
1940
1943 else
1945
1946 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
1948
1949 aPad->GetTeardropParams().m_Enabled = m_cbTeardrops->GetValue();
1956 aPad->GetTeardropParams().m_CurvedEdges = m_curvedEdges->GetValue();
1958
1959 // Read pad clearances values:
1960 if( m_clearance.IsNull() )
1961 aPad->SetLocalClearance( {} );
1962 else
1963 aPad->SetLocalClearance( m_clearance.GetIntValue() );
1964
1965 if( m_maskMargin.IsNull() )
1966 aPad->SetLocalSolderMaskMargin( {} );
1967 else
1968 aPad->SetLocalSolderMaskMargin( m_maskMargin.GetIntValue() );
1969
1970 aPad->SetLocalSolderPasteMargin( m_pasteMargin.GetOffsetValue() );
1971 aPad->SetLocalSolderPasteMarginRatio( m_pasteMargin.GetRatioValue() );
1972
1973 if( m_spokeWidth.IsNull() )
1975 else
1976 aPad->SetLocalThermalSpokeWidthOverride( m_spokeWidth.GetIntValue() );
1977
1978 if( m_thermalGap.IsNull() )
1979 aPad->SetLocalThermalGapOverride( {} );
1980 else
1981 aPad->SetLocalThermalGapOverride( m_thermalGap.GetIntValue() );
1982
1983 aPad->SetThermalSpokeAngle( m_spokeAngle.GetAngleValue() );
1984
1985 // And rotation
1986 aPad->SetOrientation( m_pad_orientation.GetAngleValue() );
1987
1988 switch( m_ZoneConnectionChoice->GetSelection() )
1989 {
1990 default:
1991 case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1992 case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
1993 case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1994 case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
1995 }
1996
1997 VECTOR2I pos( m_posX.GetIntValue(), m_posY.GetIntValue() );
1998
1999 if( FOOTPRINT* fp = aPad->GetParentFootprint() )
2000 {
2001 pos -= fp->GetPosition();
2002 RotatePoint( pos, -fp->GetOrientation() );
2003 }
2004
2005 aPad->SetPosition( pos );
2006
2007 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
2008 {
2010 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeX.GetIntValue() ) );
2011 }
2012 else
2013 {
2015 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeY.GetIntValue() ) );
2016 }
2017
2018 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CIRCLE )
2019 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2020 else
2021 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeY.GetIntValue() ) );
2022
2023 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
2024 // remember DeltaSize.x is the Y size variation
2025 bool error = false;
2026 VECTOR2I delta( 0, 0 );
2027
2028 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::TRAPEZOID )
2029 {
2030 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
2031 if( m_trapAxisCtrl->GetSelection() == 0 )
2032 delta.x = m_trapDelta.GetIntValue();
2033 else
2034 delta.y = m_trapDelta.GetIntValue();
2035
2036 if( delta.x < 0 && delta.x < -aPad->GetSize( m_editLayer ).y )
2037 {
2038 delta.x = -aPad->GetSize( m_editLayer ).y + 2;
2039 error = true;
2040 }
2041
2042 if( delta.x > 0 && delta.x > aPad->GetSize( m_editLayer ).y )
2043 {
2044 delta.x = aPad->GetSize( m_editLayer ).y - 2;
2045 error = true;
2046 }
2047
2048 if( delta.y < 0 && delta.y < -aPad->GetSize( m_editLayer ).x )
2049 {
2050 delta.y = -aPad->GetSize( m_editLayer ).x + 2;
2051 error = true;
2052 }
2053
2054 if( delta.y > 0 && delta.y > aPad->GetSize( m_editLayer ).x )
2055 {
2056 delta.y = aPad->GetSize( m_editLayer ).x - 2;
2057 error = true;
2058 }
2059 }
2060
2061 switch( m_simElectricalTypeCtrl->GetSelection() )
2062 {
2066 default: aPad->SetSimElectricalType( PAD_SIM_ELECTRICAL_TYPE::NONE ); break;
2067 }
2068
2069 aPad->SetDelta( m_editLayer, delta );
2070
2071 if( m_offsetShapeOpt->GetValue() )
2072 aPad->SetOffset( m_editLayer, VECTOR2I( m_offsetX.GetIntValue(), m_offsetY.GetIntValue() ) );
2073 else
2074 aPad->SetOffset( m_editLayer, VECTOR2I() );
2075
2076 // Read pad length die
2077 if( m_padToDieOpt->GetValue() )
2078 aPad->SetPadToDieLength( m_padToDie.GetIntValue() );
2079 else
2080 aPad->SetPadToDieLength( 0 );
2081
2082 if( m_padToDieDelayOpt->GetValue() )
2083 aPad->SetPadToDieDelay( m_padToDieDelay.GetIntValue() );
2084 else
2085 aPad->SetPadToDieDelay( 0 );
2086
2087 aPad->SetNumber( m_padNumCtrl->GetValue() );
2088 aPad->SetNetCode( m_padNetSelector->GetSelectedNetcode() );
2089
2090 int chamfers = 0;
2091
2092 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
2093 {
2094 if( m_cbTopLeft->GetValue() )
2095 chamfers |= RECT_CHAMFER_TOP_LEFT;
2096
2097 if( m_cbTopRight->GetValue() )
2098 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2099
2100 if( m_cbBottomLeft->GetValue() )
2101 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2102
2103 if( m_cbBottomRight->GetValue() )
2104 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2105 }
2106 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
2107 {
2108 if( m_cbTopLeft1->GetValue() )
2109 chamfers |= RECT_CHAMFER_TOP_LEFT;
2110
2111 if( m_cbTopRight1->GetValue() )
2112 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2113
2114 if( m_cbBottomLeft1->GetValue() )
2115 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2116
2117 if( m_cbBottomRight1->GetValue() )
2118 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2119 }
2120
2121 aPad->SetChamferPositions( m_editLayer, chamfers );
2122
2123 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
2124 {
2125 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
2126 // that is the minimal area of this pad, and is useful to ensure a hole
2127 // diameter is acceptable, and is used in Gerber files as flashed area
2128 // reference
2130 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2131 }
2132
2133 // Define the way the clearance area is defined in zones. Since all non-custom pad
2134 // shapes are convex to begin with, this really only makes any difference for custom
2135 // pad shapes.
2138
2139 switch( aPad->GetAttribute() )
2140 {
2141 case PAD_ATTRIB::PTH:
2142 break;
2143
2144 case PAD_ATTRIB::CONN:
2145 case PAD_ATTRIB::SMD:
2146 // SMD and PAD_ATTRIB::CONN has no hole.
2147 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
2148 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
2149 // and are intended to be used in virtual edge board connectors
2150 // However we can accept a non null offset,
2151 // mainly to allow complex pads build from a set of basic pad shapes
2152 aPad->SetDrillSize( VECTOR2I( 0, 0 ) );
2153 break;
2154
2155 case PAD_ATTRIB::NPTH:
2156 // Mechanical purpose only:
2157 // no net name, no pad name allowed
2158 aPad->SetNumber( wxEmptyString );
2160 break;
2161
2162 default:
2163 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
2164 break;
2165 }
2166
2167 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::ROUNDRECT )
2168 {
2169 aPad->SetRoundRectRadiusRatio( m_editLayer, m_cornerRatio.GetDoubleValue() / 100.0 );
2170 }
2171 else if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CHAMFERED_RECT )
2172 {
2174 {
2175 aPad->SetChamferRectRatio( m_editLayer, m_mixedChamferRatio.GetDoubleValue() / 100.0 );
2176 aPad->SetRoundRectRadiusRatio( m_editLayer, m_mixedCornerRatio.GetDoubleValue() / 100.0 );
2177 }
2178 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
2179 {
2180 aPad->SetChamferRectRatio( m_editLayer, m_chamferRatio.GetDoubleValue() / 100.0 );
2182 }
2183 }
2184
2186
2187 LSET padLayerMask = LSET();
2188 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
2189
2191
2192 switch( m_padType->GetSelection() )
2193 {
2194 case PTH_DLG_TYPE:
2195 switch( copperLayersChoice )
2196 {
2197 case 0:
2198 // All copper layers
2199 padLayerMask |= LSET::AllCuMask();
2200 break;
2201
2202 case 1:
2203 // Front, back and connected
2204 padLayerMask |= LSET::AllCuMask();
2206 break;
2207
2208 case 2:
2209 // Connected only
2210 padLayerMask |= LSET::AllCuMask();
2212 break;
2213
2214 case 3:
2215 // No copper layers
2216 break;
2217 }
2218
2219 break;
2220
2221 case NPTH_DLG_TYPE:
2222 switch( copperLayersChoice )
2223 {
2224 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
2225 case 1: padLayerMask.set( F_Cu ); break;
2226 case 2: padLayerMask.set( B_Cu ); break;
2227 default: break;
2228 }
2229
2230 break;
2231
2232 case SMD_DLG_TYPE:
2233 case CONN_DLG_TYPE:
2234 switch( copperLayersChoice )
2235 {
2236 case 0: padLayerMask.set( F_Cu ); break;
2237 case 1: padLayerMask.set( B_Cu ); break;
2238 }
2239
2240 break;
2241
2242 case APERTURE_DLG_TYPE:
2243 // no copper layers
2244 break;
2245 }
2246
2247 if( m_layerFrontAdhesive->GetValue() )
2248 padLayerMask.set( F_Adhes );
2249
2250 if( m_layerBackAdhesive->GetValue() )
2251 padLayerMask.set( B_Adhes );
2252
2253 if( m_layerFrontPaste->GetValue() )
2254 padLayerMask.set( F_Paste );
2255
2256 if( m_layerBackPaste->GetValue() )
2257 padLayerMask.set( B_Paste );
2258
2259 if( m_layerFrontSilk->GetValue() )
2260 padLayerMask.set( F_SilkS );
2261
2262 if( m_layerBackSilk->GetValue() )
2263 padLayerMask.set( B_SilkS );
2264
2265 if( m_layerFrontMask->GetValue() )
2266 padLayerMask.set( F_Mask );
2267
2268 if( m_layerBackMask->GetValue() )
2269 padLayerMask.set( B_Mask );
2270
2271 if( m_layerECO1->GetValue() )
2272 padLayerMask.set( Eco1_User );
2273
2274 if( m_layerECO2->GetValue() )
2275 padLayerMask.set( Eco2_User );
2276
2277 if( m_layerUserDwgs->GetValue() )
2278 padLayerMask.set( Dwgs_User );
2279
2280 aPad->SetLayerSet( padLayerMask );
2281
2282 // Backdrills are written through the PADSTACK accessors, which stamp each side's start layer
2283 // (top = F_Cu, bottom = B_Cu) so the result is read back correctly by older KiCad.
2284 int backDrillSel = m_backDrillChoice->GetSelection();
2285 bool wantTop = ( backDrillSel == 1 || backDrillSel == 3 ); // 1: Top, 3: Top & bottom
2286 bool wantBottom = ( backDrillSel == 2 || backDrillSel == 3 ); // 2: Bottom
2287
2288 PADSTACK& padstack = aPad->Padstack();
2289
2290 if( wantTop )
2291 {
2292 padstack.SetBackdrillSize( true, m_backDrillTopSizeBinder.GetIntValue() );
2293
2294 if( m_backDrillTopLayer->GetSelection() != wxNOT_FOUND )
2295 padstack.SetBackdrillEndLayer( true, ToLAYER_ID( (intptr_t) m_backDrillTopLayer->GetClientData(
2296 m_backDrillTopLayer->GetSelection() ) ) );
2297 }
2298 else
2299 {
2300 padstack.SetBackdrillSize( true, std::nullopt );
2301 }
2302
2303 if( wantBottom )
2304 {
2305 padstack.SetBackdrillSize( false, m_backDrillBottomSizeBinder.GetIntValue() );
2306
2307 if( m_backDrillBottomLayer->GetSelection() != wxNOT_FOUND )
2308 padstack.SetBackdrillEndLayer( false, ToLAYER_ID( (intptr_t) m_backDrillBottomLayer->GetClientData(
2309 m_backDrillBottomLayer->GetSelection() ) ) );
2310 }
2311 else
2312 {
2313 padstack.SetBackdrillSize( false, std::nullopt );
2314 }
2315
2316 // Front Post Machining
2317 PADSTACK::POST_MACHINING_PROPS frontPostMachining;
2318
2319 switch( m_topPostMachining->GetSelection() )
2320 {
2321 case 1: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2322 case 2: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2323 default: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2324 }
2325
2326 frontPostMachining.size = m_topPostMachineSize1Binder.GetIntValue();
2327
2328 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2329 frontPostMachining.angle = KiROUND( m_topPostMachineSize2Binder.GetDoubleValue() * 10.0 );
2330 else
2331 frontPostMachining.depth = m_topPostMachineSize2Binder.GetIntValue();
2332
2333 aPad->Padstack().FrontPostMachining() = frontPostMachining;
2334
2335 // Back Post Machining
2336 PADSTACK::POST_MACHINING_PROPS backPostMachining;
2337
2338 switch( m_bottomPostMachining->GetSelection() )
2339 {
2340 case 1: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2341 case 2: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2342 default: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2343 }
2344
2345 backPostMachining.size = m_bottomPostMachineSize1Binder.GetIntValue();
2346
2347 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2348 backPostMachining.angle = KiROUND( m_bottomPostMachineSize2Binder.GetDoubleValue() * 10.0 );
2349 else
2350 backPostMachining.depth = m_bottomPostMachineSize2Binder.GetIntValue();
2351
2352 aPad->Padstack().BackPostMachining() = backPostMachining;
2353
2354 // If we created new layers, initialize them
2355 for( const auto& [newLayer, initFromLayer] : newLayerMap )
2356 {
2357 if( newLayer != m_editLayer && newLayer != initFromLayer )
2358 aPad->Padstack().CopperLayer( newLayer ) = aPad->Padstack().CopperLayer( initFromLayer );
2359 }
2360
2361 return !error;
2362}
2363
2364
2365
2366
2367void DIALOG_PAD_PROPERTIES::onBackDrillChoice( wxCommandEvent& event )
2368{
2369 int selection = m_backDrillChoice->GetSelection();
2370 // 0: None, 1: Top, 2: Bottom, 3: Both
2371
2372 bool enableTop = ( selection == 1 || selection == 3 );
2373 bool enableBottom = ( selection == 2 || selection == 3 );
2374
2375 m_backDrillTopSizeBinder.Enable( enableTop );
2376 m_backDrillTopLayer->Enable( enableTop );
2377 m_backDrillTopLayerLabel->Enable( enableTop );
2378
2379 m_backDrillBottomSizeBinder.Enable( enableBottom );
2380 m_backDrillBottomLayer->Enable( enableBottom );
2381 m_backDrillBottomLayerLabel->Enable( enableBottom );
2382
2383}
2384
2385
2387{
2388 int selection = m_topPostMachining->GetSelection();
2389 // 0: None, 1: Countersink, 2: Counterbore
2390
2391 bool enable = ( selection != 0 );
2392 m_topPostMachineSize1Binder.Enable( enable );
2393 m_topPostMachineSize2Binder.Enable( enable );
2394 m_topPostMachineSize1Label->Enable( enable );
2395 m_topPostMachineSize2Label->Enable( enable );
2396
2397 if( selection == 1 ) // Countersink
2398 {
2399 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2400 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
2402
2403 if( m_topPostMachineSize2Binder.IsIndeterminate() || m_topPostMachineSize2Binder.GetDoubleValue() == 0 )
2404 m_topPostMachineSize2Binder.SetDoubleValue( 82.0 );
2405 }
2406 else if( selection == 2 ) // Counterbore
2407 {
2408 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2409 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2410 m_topPostMachineSize2Binder.SetUnits( m_parent->GetUserUnits() );
2411 }
2412}
2413
2414
2416{
2417 int selection = m_bottomPostMachining->GetSelection();
2418 // 0: None, 1: Countersink, 2: Counterbore
2419
2420 bool enable = ( selection != 0 );
2421 m_bottomPostMachineSize1Binder.Enable( enable );
2422 m_bottomPostMachineSize2Binder.Enable( enable );
2423 m_bottomPostMachineSize1Label->Enable( enable );
2424 m_bottomPostMachineSize2Label->Enable( enable );
2425
2426 if( selection == 1 ) // Countersink
2427 {
2428 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2429 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
2431
2432 if( m_bottomPostMachineSize2Binder.IsIndeterminate() || m_bottomPostMachineSize2Binder.GetDoubleValue() == 0 )
2433 m_bottomPostMachineSize2Binder.SetDoubleValue( 82.0 );
2434 }
2435 else if( selection == 2 ) // Counterbore
2436 {
2437 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2438 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2439 m_bottomPostMachineSize2Binder.SetUnits( m_parent->GetUserUnits() );
2440 }
2441}
2442
2443
2444void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2445{
2446 if( m_offsetShapeOpt->GetValue() )
2447 {
2448 m_offsetX.SetValue( m_previewPad->GetOffset( m_editLayer ).x );
2449 m_offsetY.SetValue( m_previewPad->GetOffset( m_editLayer ).y );
2450 }
2451
2452 // Show/hide controls depending on m_offsetShapeOpt being enabled
2453 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2454 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2455
2456 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2457 m_notebook->GetPage( i )->Layout();
2458
2459 OnValuesChanged( event );
2460}
2461
2462
2464{
2465 if( m_padToDieOpt->GetValue() && m_currentPad )
2466 m_padToDie.SetValue( m_currentPad->GetPadToDieLength() );
2467
2468 OnValuesChanged( event );
2469}
2470
2471
2473{
2474 if( m_padToDieDelayOpt->GetValue() && m_currentPad )
2475 m_padToDieDelay.SetValue( m_currentPad->GetPadToDieDelay() );
2476
2477 OnValuesChanged( event );
2478}
2479
2480
2481void DIALOG_PAD_PROPERTIES::onModify( wxSpinDoubleEvent& aEvent )
2482{
2483 if( m_initialized )
2484 OnModify();
2485}
2486
2487
2488void DIALOG_PAD_PROPERTIES::onModify( wxCommandEvent& aEvent )
2489{
2490 if( m_initialized )
2491 OnModify();
2492}
2493
2494
2495void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2496{
2497 if( m_initialized )
2498 {
2500 return;
2501
2502 // If the pad size has changed, update the displayed values for rounded rect pads.
2505
2506 redraw();
2507 OnModify();
2508 }
2509}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
@ teardrop_rect_sizes
@ pads_reset_unused
@ pads_remove_unused
@ pads_npth_bottom
@ pads_npth_top_bottom
@ pads_remove_unused_keep_bottom
#define DEFAULT_PAD_DRILL_DIAMETER_MM
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
BOX2< VECTOR2D > BOX2D
Definition box2.h:919
BASE_SET & set(size_t pos)
Definition base_set.h:116
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
TEARDROP_PARAMETERS & GetTeardropParams()
FOOTPRINT * GetParentFootprint() const
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition box2.h:134
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr const SizeVec & GetSize() const
Definition box2.h:202
constexpr coord_type GetTop() const
Definition box2.h:225
constexpr coord_type GetBottom() const
Definition box2.h:218
Color settings are a bit different than most of the settings objects in that there can be more than o...
COLOR4D GetColor(int aLayer) const
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
DIALOG_PAD_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_DIALOG_EDIT_PAD, const wxString &title=_("Pad Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(1004, 695), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void OnUpdateUINonCopperWarning(wxUpdateUIEvent &event) override
void OnInitDialog(wxInitDialogEvent &event) override
void PadTypeSelected(wxCommandEvent &event) override
void OnPadToDieDelayCheckbox(wxCommandEvent &event) override
void OnPadShapeSelection(wxCommandEvent &event) override
bool transferDataToPad(PAD *aPad)
Copy values from dialog field to aPad's members.
bool TransferDataFromWindow() override
Updates the different parameters for the component being edited.
std::map< int, PCB_LAYER_ID > m_editLayerCtrlMap
bool Show(bool aShow) override
void OnEditLayerChanged(wxCommandEvent &event) override
std::vector< std::shared_ptr< PCB_SHAPE > > m_primitives
bool padValuesOK()
test if all values are acceptable for the pad
void PadOrientEvent(wxCommandEvent &event) override
void OnResize(wxSizeEvent &event)
void OnElectricalTypeChaged(wxCommandEvent &event) override
void onPadShapeSelection(bool aUpdateSpokeAngle)
void OnOffsetCheckbox(wxCommandEvent &event) override
PCB_DRAW_PANEL_GAL * m_padPreviewGAL
void OnValuesChanged(wxCommandEvent &event) override
Called when a dimension has changed.
DIALOG_PAD_PROPERTIES(PCB_BASE_FRAME *aParent, PAD *aPad)
void updatePadLayersList(std::optional< LSET > layer_mask, bool remove_unconnected, bool keep_top_bottom)
Updates the CheckBox states in pad layers list.
void onBottomPostMachining(wxCommandEvent &event) override
void onTeardropsUpdateUi(wxUpdateUIEvent &event) override
std::vector< PCB_SHAPE * > m_highlight
void OnPadstackModeChanged(wxCommandEvent &event) override
void onChangePadDrawMode(wxCommandEvent &event) override
KIGFX::ORIGIN_VIEWITEM * m_axisOrigin
void OnSetCopperLayers(wxCommandEvent &event) override
void onBackDrillChoice(wxCommandEvent &event) override
void OnCancel(wxCommandEvent &event) override
void onCornerRadiusChange(wxCommandEvent &event) override
PAD_PROP getSelectedProperty()
Return the pad property currently selected.
void OnSetLayers(wxCommandEvent &event) override
void onCornerSizePercentChange(wxCommandEvent &event) override
MARGIN_OFFSET_BINDER m_pasteMargin
void OnPadToDieCheckbox(wxCommandEvent &event) override
void onTopPostMachining(wxCommandEvent &event) override
void OnDrillShapeSelected(wxCommandEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) override
void onModify(wxCommandEvent &aEvent) override
bool Show(bool show) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:79
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void resetSize()
Clear the existing dialog size and position.
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
EDA_BASE_FRAME * m_parentFrame
int ShowModal() override
FRAME_T GetFrameType() const
void ListSet(const wxString &aList)
Add a list of items.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
bool m_forceDisplayCursor
The pixel scale factor (>1 for hi-DPI scaled displays)
void SetAxesEnabled(bool aAxesEnabled)
Enable drawing the axes.
void SetGridSize(const VECTOR2D &aGridSize)
Set the grid size.
void SetGridVisibility(bool aVisibility)
Set the visibility setting of the grid.
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:78
void SetLayerColor(int aLayer, const COLOR4D &aColor)
Change the color used to draw a layer.
An interface for classes handling user events controlling the view behavior such as zooming,...
const VC_SETTINGS & GetSettings() const
Return the current VIEW_CONTROLS settings.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition view.cpp:609
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:300
void SetBoundary(const BOX2D &aBoundary)
Set limits for view area.
Definition view.h:291
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition view.cpp:1835
void SetLayerVisible(int aLayer, bool aVisible=true)
Control the visibility of a particular layer.
Definition view.h:405
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:207
void ClearTopLayers()
Remove all layers from the on-the-top set (they are no longer displayed over the rest of layers).
Definition view.cpp:960
virtual void SetTopLayer(int aLayer, bool aEnabled=true)
Set given layer to be displayed on the top or sets back the default order of layers.
Definition view.cpp:908
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:739
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:256
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:157
void SetBackdrillSize(bool aTop, std::optional< int > aSize)
Definition padstack.cpp:572
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition padstack.h:367
bool HasExplicitDefinitionForLayer(PCB_LAYER_ID aLayer) const
Check if the padstack has an explicit definition for the given layer.
void SetMode(MODE aMode)
COPPER_LAYER_PROPS & CopperLayer(PCB_LAYER_ID aLayer)
POST_MACHINING_PROPS & FrontPostMachining()
Definition padstack.h:360
void SetBackdrillEndLayer(bool aTop, PCB_LAYER_ID aLayer)
Definition padstack.cpp:597
std::optional< int > GetBackdrillSize(bool aTop) const
Definition padstack.cpp:563
MODE
! Copper geometry mode: controls how many unique copper layer shapes this padstack has
Definition padstack.h:170
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:171
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:173
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:172
PCB_LAYER_ID GetBackdrillEndLayer(bool aTop) const
Definition padstack.cpp:588
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:363
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:180
void SetLastPadNumber(const wxString &aPadNumber)
Definition pad_tool.h:63
wxString GetLastPadNumber() const
Definition pad_tool.h:62
Definition pad.h:61
void SetAnchorPadShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition pad.h:245
void SetAttribute(PAD_ATTRIB aAttribute)
Definition pad.cpp:1615
void SetLocalThermalGapOverride(const std::optional< int > &aOverride)
Definition pad.h:769
PAD_ATTRIB GetAttribute() const
Definition pad.h:555
static LSET PTHMask()
layer set for a through hole pad
Definition pad.cpp:579
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition pad.h:741
void SetSimElectricalType(PAD_SIM_ELECTRICAL_TYPE aType)
Definition pad.h:567
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition pad.h:599
void SetLocalThermalSpokeWidthOverride(std::optional< int > aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition pad.h:725
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:193
void SetProperty(PAD_PROP aProperty)
Definition pad.cpp:1688
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition pad.cpp:600
void SetDelta(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.h:296
void SetPadToDieDelay(int aDelay)
Definition pad.h:575
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:202
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition pad.h:142
void SetDrillShape(PAD_DRILL_SHAPE aShape)
Definition pad.h:428
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pad.h:582
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition pad.cpp:785
void SetCustomShapeInZoneOpt(CUSTOM_SHAPE_ZONE_MODE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones.
Definition pad.h:234
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition pad.h:605
void SetChamferRectRatio(PCB_LAYER_ID aLayer, double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition pad.cpp:1186
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:287
void SetPosition(const VECTOR2I &aPos) override
Definition pad.cpp:234
const PADSTACK & Padstack() const
Definition pad.h:326
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition pad.cpp:593
void SetDrillSize(const VECTOR2I &aSize)
Definition pad.h:314
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.cpp:254
void ReplacePrimitives(PCB_LAYER_ID aLayer, const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Clear the current custom shape primitives list and import a new list.
Definition pad.cpp:3558
static LSET ApertureMask()
layer set for an aperture pad
Definition pad.cpp:607
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition pad.cpp:586
void SetChamferPositions(PCB_LAYER_ID aLayer, int aPositions)
Has meaning only for chamfered rectangular pads.
Definition pad.h:835
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition pad.h:589
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition pad.cpp:1696
void SetLocalClearance(std::optional< int > aClearance)
Definition pad.h:579
void SetLayerSet(const LSET &aLayers) override
Definition pad.cpp:1931
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition pad.h:216
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition pad.cpp:1148
void SetPadToDieLength(int aLength)
Definition pad.h:572
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
void ShowPadPropertiesDialog(PAD *aPad)
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxLen
max allowed length for teardrops in IU. <= 0 to disable
bool m_AllowUseTwoTracks
True to create teardrops using 2 track segments if the first in too small.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_BestLengthRatio
The length of a teardrop as ratio between length and size of pad/via.
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_TdOnPadsInZones
A filter to exclude pads inside zone fills.
bool m_Enabled
Flag to enable teardrops.
bool m_CurvedEdges
True if the teardrop should be curved.
A type-safe container of any type.
Definition ki_any.h:92
This file is part of the common library.
#define APERTURE_DLG_TYPE
#define CONN_DLG_TYPE
static PAD_ATTRIB code_type[]
#define SELECTED_ITEMS_LAYER
static PAD_SHAPE code_shape[]
#define SMD_DLG_TYPE
@ CHOICE_SHAPE_CIRCLE
@ CHOICE_SHAPE_ROUNDRECT
@ CHOICE_SHAPE_CUSTOM_RECT_ANCHOR
@ CHOICE_SHAPE_CHAMFERED_RECT
@ CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
@ CHOICE_SHAPE_RECT
@ CHOICE_SHAPE_OVAL
@ CHOICE_SHAPE_TRAPEZOID
@ CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT
#define NPTH_DLG_TYPE
#define PTH_DLG_TYPE
#define PAD_PROPERTIES_DLG_NAME
DIALOG_PAD_PROPERTIES, derived from DIALOG_PAD_PROPERTIES_BASE, created by wxFormBuilder.
@ DRCE_PADSTACK
Definition drc_item.h:59
@ DRCE_PADSTACK_INVALID
Definition drc_item.h:60
@ DRCE_PAD_TH_WITH_NO_HOLE
Definition drc_item.h:81
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:412
#define BRIGHTENED
item is drawn with a bright contour
#define SELECTED
Item was manually selected by the user.
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
@ LAYER_PAD_NETNAMES
Definition layer_ids.h:198
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
@ LAYER_GRID
Definition layer_ids.h:250
@ LAYER_LOCKED_ITEM_SHADOW
Shadow layer for locked items.
Definition layer_ids.h:303
@ LAYER_NON_PLATEDHOLES
Draw usual through hole vias.
Definition layer_ids.h:235
@ LAYER_PAD_PLATEDHOLES
to draw pad holes (plated)
Definition layer_ids.h:267
@ LAYER_PAD_HOLEWALLS
Definition layer_ids.h:293
bool IsInnerCopperLayer(int aLayerId)
Test whether a layer is an inner (In1_Cu to In30_Cu) copper layer.
Definition layer_ids.h:697
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Adhes
Definition layer_ids.h:99
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_SilkS
Definition layer_ids.h:96
@ Eco2_User
Definition layer_ids.h:106
@ B_SilkS
Definition layer_ids.h:97
@ F_Cu
Definition layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
This file contains miscellaneous commonly used macros and functions.
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:25
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
KICOMMON_API wxFont GetSmallInfoFont(wxWindow *aWindow)
bool PadHasMeaningfulRoundingRadius(const PAD &aPad, PCB_LAYER_ID aLayer)
Returns true if the pad's rounding ratio is valid (i.e.
Definition pad_utils.cpp:42
double GetDefaultIpcRoundingRatio(const PAD &aPad, PCB_LAYER_ID aLayer)
Get a sensible default for a rounded rectangle pad's rounding ratio.
Definition pad_utils.cpp:25
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition padstack.h:97
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ PTH
Plated through hole pad.
Definition padstack.h:98
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:100
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
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition padstack.h:114
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
Definition padstack.h:118
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
Definition padstack.h:117
@ MECHANICAL
a pad used for mechanical support
Definition padstack.h:122
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:123
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
Definition padstack.h:120
@ NONE
no special fabrication property
Definition padstack.h:115
@ TESTPOINT
a test point pad
Definition padstack.h:119
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:121
@ BGA
Smd pad, used in BGA footprints.
Definition padstack.h:116
std::vector< FAB_LAYER_COLOR > dummy
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:281
int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46
@ NONE
Pads are not covered.
Definition zones.h:45
@ FULL
pads are covered by copper
Definition zones.h:47