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 (C) 1992-2024 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, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <base_units.h>
28#include <bitmaps.h>
29#include <board_commit.h>
30#include <board.h>
32#include <footprint.h>
33#include <confirm.h>
34#include <core/arraydim.h>
35#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
40#include <macros.h>
41#include <pad.h>
42#include <pcb_base_frame.h>
44#include <pcb_painter.h>
45#include <pcbnew_settings.h>
47#include <view/view_controls.h>
49#include <tool/tool_manager.h>
50#include <tools/pad_tool.h>
51#include <advanced_config.h> // for pad property feature management
52#include <wx/choicdlg.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
76{
86};
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
112static bool PadHasMeaningfulRoundingRadius( const PAD& aPad )
113{
114 const PAD_SHAPE shape = aPad.GetShape();
115 return shape == PAD_SHAPE::ROUNDRECT || shape == PAD_SHAPE::CHAMFERED_RECT;
116}
117
118
124static double GetDefaultIpcRoundingRatio( const PAD& aPad )
125{
126 const double defaultProportion = 0.25;
127 const double minimumSizeIU = pcbIUScale.mmToIU( 0.25 );
128
129 const int padMinSizeIU = std::min( aPad.GetSizeX(), aPad.GetSizeY() );
130 const double defaultRadiusIU = std::min( minimumSizeIU, padMinSizeIU * defaultProportion );
131
132 // Convert back to a ratio
133 return defaultRadiusIU / padMinSizeIU;
134}
135
136
138{
139 DIALOG_PAD_PROPERTIES dlg( this, aPad );
140
141 // QuasiModal required for NET_SELECTOR
142 dlg.ShowQuasiModal();
143}
144
145
148 m_parent( aParent ),
149 m_canUpdate( false ),
150 m_posX( aParent, m_posXLabel, m_posXCtrl, m_posXUnits ),
151 m_posY( aParent, m_posYLabel, m_posYCtrl, m_posYUnits ),
152 m_sizeX( aParent, m_sizeXLabel, m_sizeXCtrl, m_sizeXUnits ),
153 m_sizeY( aParent, m_sizeYLabel, m_sizeYCtrl, m_sizeYUnits ),
154 m_offsetX( aParent, m_offsetXLabel, m_offsetXCtrl, m_offsetXUnits ),
155 m_offsetY( aParent, m_offsetYLabel, m_offsetYCtrl, m_offsetYUnits ),
156 m_padToDie( aParent, m_padToDieLabel, m_padToDieCtrl, m_padToDieUnits ),
157 m_trapDelta( aParent, m_trapDeltaLabel, m_trapDeltaCtrl, m_trapDeltaUnits ),
158 m_cornerRadius( aParent, m_cornerRadiusLabel, m_cornerRadiusCtrl, m_cornerRadiusUnits ),
159 m_cornerRatio( aParent, m_cornerRatioLabel, m_cornerRatioCtrl, m_cornerRatioUnits ),
160 m_chamferRatio( aParent, m_chamferRatioLabel, m_chamferRatioCtrl, m_chamferRatioUnits ),
161 m_mixedCornerRatio( aParent, m_mixedCornerRatioLabel, m_mixedCornerRatioCtrl,
162 m_mixedCornerRatioUnits ),
163 m_mixedChamferRatio( aParent, m_mixedChamferRatioLabel, m_mixedChamferRatioCtrl,
164 m_mixedChamferRatioUnits ),
165 m_holeX( aParent, m_holeXLabel, m_holeXCtrl, m_holeXUnits ),
166 m_holeY( aParent, m_holeYLabel, m_holeYCtrl, m_holeYUnits ),
167 m_clearance( aParent, m_clearanceLabel, m_clearanceCtrl, m_clearanceUnits ),
168 m_maskMargin( aParent, m_maskMarginLabel, m_maskMarginCtrl, m_maskMarginUnits ),
169 m_pasteMargin( aParent, m_pasteMarginLabel, m_pasteMarginCtrl, m_pasteMarginUnits ),
170 m_pasteMarginRatio( aParent, m_pasteMarginRatioLabel, m_pasteMarginRatioCtrl,
171 m_pasteMarginRatioUnits ),
172 m_thermalGap( aParent, m_thermalGapLabel, m_thermalGapCtrl, m_thermalGapUnits ),
173 m_spokeWidth( aParent, m_spokeWidthLabel, m_spokeWidthCtrl, m_spokeWidthUnits ),
174 m_spokeAngle( aParent, m_spokeAngleLabel, m_spokeAngleCtrl, m_spokeAngleUnits ),
175 m_pad_orientation( aParent, m_PadOrientText, m_cb_padrotation, m_orientationUnits ),
176 m_teardropMaxLenSetting( aParent, m_stMaxLen, m_tcTdMaxLen, m_stMaxLenUnits ),
177 m_teardropMaxHeightSetting( aParent, m_stTdMaxSize, m_tcMaxHeight, m_stMaxHeightUnits )
178{
179 SetName( PAD_PROPERTIES_DLG_NAME );
180 m_isFpEditor = dynamic_cast<FOOTPRINT_EDIT_FRAME*>( aParent ) != nullptr;
181
182 m_currentPad = aPad; // aPad can be NULL, if the dialog is called
183 // from the footprint editor to set default pad setup
184
186
187 // Configure display origin transforms
190
193
195
196 m_FlippedWarningIcon->SetBitmap( KiBitmapBundle( BITMAPS::dialog_warning ) );
197 m_nonCopperWarningIcon->SetBitmap( KiBitmapBundle( BITMAPS::dialog_warning ) );
198 m_legacyTeardropsIcon->SetBitmap( KiBitmapBundle( BITMAPS::dialog_warning ) );
199
201 m_previewPad = new PAD( (FOOTPRINT*) nullptr );
202
203 if( aPad )
204 {
205 SetTitle( _( "Pad Properties" ) );
206
207 *m_previewPad = *aPad;
210 }
211 else
212 {
213 SetTitle( _( "Default Pad Properties for Add Pad Tool" ) );
214
217 }
218
219 // Pads have a hardcoded internal rounding ratio which is 0.25 by default, even if
220 // they're not a rounded shape. This makes it hard to detect an intentional 0.25
221 // ratio, or one that's only there because it's the PAD default.
222 // Zero it out here to mark that we should recompute a better ratio if the user
223 // selects a pad shape which would need a default rounding ratio computed for it
226
227 if( m_isFpEditor )
228 {
229 m_padNetLabel->Show( false );
230 m_padNetSelector->Show( false );
231 }
232
233 m_FlippedWarningSizer->Show( false );
234
235 // Pad needs to have a parent for painting; use the parent board for its design settings
236 if( !m_previewPad->GetParent() )
238
239 m_cornerRatio.SetUnits( EDA_UNITS::PERCENT );
240 m_chamferRatio.SetUnits( EDA_UNITS::PERCENT );
241 m_mixedCornerRatio.SetUnits( EDA_UNITS::PERCENT );
242 m_mixedChamferRatio.SetUnits( EDA_UNITS::PERCENT );
243 m_pad_orientation.SetUnits( EDA_UNITS::DEGREES );
245
246 m_spokeAngle.SetUnits( EDA_UNITS::DEGREES );
248
250
251 m_pasteMarginRatio.SetUnits( EDA_UNITS::PERCENT );
253
254 initValues();
255
256 wxFont infoFont = KIUI::GetInfoFont( this );
257 m_copperLayersLabel->SetFont( infoFont );
258 m_techLayersLabel->SetFont( infoFont );
259 m_parentInfo->SetFont( infoFont );
260 m_teardropShapeLabel->SetFont( infoFont );
261
262 infoFont.SetStyle( wxFONTSTYLE_ITALIC );
263 m_nonCopperNote->SetFont( infoFont );
264 m_staticTextInfoPaste->SetFont( infoFont );
265
268
269 // Usually, TransferDataToWindow is called by OnInitDialog
270 // calling it here fixes all widget sizes so FinishDialogSettings can safely fix minsizes
272
273 // Initialize canvas to be able to display the dummy pad:
275
276 m_notebook->SetSelection( m_page );
277
278 switch( m_page )
279 {
280 case 0: SetInitialFocus( m_padNumCtrl ); break;
281 case 1: SetInitialFocus( m_thermalGapCtrl ); break;
282 case 2: SetInitialFocus( m_clearanceCtrl ); break;
283 }
284
287 m_canUpdate = true;
288
289 m_padNetSelector->Connect( NET_SELECTED,
290 wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ),
291 nullptr, this );
292
293 if( m_padType->GetSelection() != PTH_DLG_TYPE && m_padType->GetSelection() != NPTH_DLG_TYPE )
294 {
295 m_gbSizerHole->Show( false );
296 m_staticline6->Show( false );
297 }
298
299 // Now all widgets have the size fixed, call FinishDialogSettings
301
302 // Update widgets
303 wxUpdateUIEvent dummyUI;
304 OnUpdateUI( dummyUI );
305
306 // Post a dummy size event to force the pad preview panel to update the
307 // view: actual size, best zoom ... after the frame is shown
308 PostSizeEvent();
309}
310
311
313{
314 m_padNetSelector->Disconnect( NET_SELECTED,
315 wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ),
316 nullptr, this );
317
318 m_page = m_notebook->GetSelection();
319
320 // Remove the preview pad from the group of the actual pad before deletion
321 if( m_previewPad )
322 m_previewPad->SetParentGroup( nullptr );
323
324 delete m_previewPad;
325 delete m_axisOrigin;
326}
327
328
329// Store the pad draw option during a session.
331
332
333void DIALOG_PAD_PROPERTIES::OnInitDialog( wxInitDialogEvent& event )
334{
335 m_selectedColor = COLOR4D( 1.0, 1.0, 1.0, 0.7 );
336
337 // Needed on some WM to be sure the pad is redrawn according to the final size
338 // of the canvas, with the right zoom factor
339 redraw();
340}
341
342
343void DIALOG_PAD_PROPERTIES::OnCancel( wxCommandEvent& event )
344{
345 // Mandatory to avoid m_panelShowPadGal trying to draw something
346 // in a non valid context during closing process:
348
349 // Now call default handler for wxID_CANCEL command event
350 event.Skip();
351}
352
353
355{
357 COLOR_SETTINGS* colorSettings = m_parent->GetColorSettings();
358
359 opts.m_forceDisplayCursor = false;
360
361 // Initialize the canvas to display the pad
362 m_padPreviewGAL = new PCB_DRAW_PANEL_GAL( m_boardViewPanel, -1, wxDefaultPosition,
363 wxDefaultSize, opts,
365
366 m_padPreviewSizer->Add( m_padPreviewGAL, 12, wxEXPAND | wxALL, 5 );
367
368 // Show the X and Y axis. It is useful because pad shape can have an offset
369 // or be a complex shape.
374
377 m_padPreviewGAL->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
378
379 KIGFX::VIEW_CONTROLS* parentViewControls = m_parent->GetCanvas()->GetViewControls();
380 m_padPreviewGAL->GetViewControls()->ApplySettings( parentViewControls->GetSettings() );
381
382 m_padPreviewGAL->Show();
383
385
386 // fix the pad render mode (filled/not filled)
387 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
388
389 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
390 settings->SetHighContrast( false );
391 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
392
393 // gives a non null grid size (0.001mm) because GAL layer does not like a 0 size grid:
394 double gridsize = 0.001 * pcbIUScale.IU_PER_MM;
395 view->GetGAL()->SetGridSize( VECTOR2D( gridsize, gridsize ) );
396
397 // And do not show the grid:
398 view->GetGAL()->SetGridVisibility( false );
399 view->GetGAL()->SetAxesEnabled( false );
400 view->Add( m_previewPad );
401 view->Add( m_axisOrigin );
402
404 Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_PROPERTIES::OnResize ) );
405}
406
407
409{
410 // Note: use ChangeValue() to avoid generating a wxEVT_TEXT event
412
415
418}
419
420
422{
423 if( m_previewPad->GetShape() != PAD_SHAPE::ROUNDRECT
424 && m_previewPad->GetShape() != PAD_SHAPE::CHAMFERED_RECT )
425 {
426 return;
427 }
428
429 if( m_cornerRadius.GetValue() < 0 )
430 m_cornerRadiusCtrl->ChangeValue( "0" );
431
433 {
435
438
439 redraw();
440 }
441}
442
443
445{
446 if( m_previewPad->GetShape() != PAD_SHAPE::ROUNDRECT
447 && m_previewPad->GetShape() != PAD_SHAPE::CHAMFERED_RECT )
448 {
449 return;
450 }
451
452 wxObject* ctrl = event.GetEventObject();
453 wxString value = event.GetString();
454 bool changed = false;
455
456 if( ctrl == m_cornerRatioCtrl || ctrl == m_mixedCornerRatioCtrl )
457 {
458 double ratioPercent;
459
460 if( value.ToDouble( &ratioPercent ) )
461 {
462 // Clamp ratioPercent to acceptable value (0.0 to 50.0)
463 if( ratioPercent < 0.0 )
464 {
467 }
468 else if( ratioPercent > 50.0 )
469 {
472 }
473
474 if( ctrl == m_cornerRatioCtrl )
475 m_mixedCornerRatioCtrl->ChangeValue( value );
476 else
477 m_cornerRatioCtrl->ChangeValue( value );
478
479 changed = true;
480 }
481 }
482 else if( ctrl == m_chamferRatioCtrl || ctrl == m_mixedChamferRatioCtrl )
483 {
484 double ratioPercent;
485
486 if( value.ToDouble( &ratioPercent ) )
487 {
488 // Clamp ratioPercent to acceptable value (0.0 to 50.0)
489 if( ratioPercent < 0.0 )
490 {
493 }
494 else if( ratioPercent > 50.0 )
495 {
498 }
499
500 if( ctrl == m_chamferRatioCtrl )
501 m_mixedChamferRatioCtrl->ChangeValue( value );
502 else
503 m_chamferRatioCtrl->ChangeValue( value );
504
505 changed = true;
506 }
507 }
508
509 if( changed && transferDataToPad( m_previewPad ) )
511
512 redraw();
513}
514
515
517{
518 wxString msg;
519
520 // Disable pad net name wxTextCtrl if the caller is the footprint editor
521 // because nets are living only in the board managed by the board editor
523
532 m_layerECO1->SetLabel( m_board->GetLayerName( Eco1_User ) );
533 m_layerECO2->SetLabel( m_board->GetLayerName( Eco2_User ) );
535
536 if( m_currentPad )
537 {
538 if( FOOTPRINT* footprint = m_currentPad->GetParentFootprint() )
539 {
541
542 if( footprint->IsFlipped() )
543 {
544 // flip pad (up/down) around its position
546 relPos.y = - relPos.y;
547 }
548
549 m_previewPad->SetPosition( relPos );
551
552 // Display parent footprint info
553 msg.Printf( _("Footprint %s (%s), %s, rotated %g deg"),
554 footprint->Reference().GetShownText( false ),
555 footprint->Value().GetShownText( false ),
556 footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
557 footprint->GetOrientation().AsDegrees() );
558
559 m_FlippedWarningSizer->Show( footprint->IsFlipped() );
560 m_parentInfo->SetLabel( msg );
561 }
562
563 m_padNumCtrl->SetValue( m_previewPad->GetNumber() );
564 }
565 else
566 {
568 m_padNumCtrl->SetValue( padTool->GetLastPadNumber() );
569
570 if( m_isFpEditor )
571 {
572 switch( m_board->Footprints()[0]->GetAttributes() )
573 {
574 case FOOTPRINT_ATTR_T::FP_THROUGH_HOLE:
575 m_previewPad->SetAttribute( PAD_ATTRIB::PTH );
576
577 if( m_previewPad->GetDrillSizeX() == 0 )
579
580 break;
581
582 case FOOTPRINT_ATTR_T::FP_SMD:
583 m_previewPad->SetAttribute( PAD_ATTRIB::SMD );
584 break;
585 }
586 }
587 }
588
590
592
593 // Display current pad parameters units:
596
599
602
603 m_offsetShapeOpt->SetValue( m_previewPad->GetOffset() != VECTOR2I() );
606
607 if( m_previewPad->GetDelta().x )
608 {
610 m_trapAxisCtrl->SetSelection( 0 );
611 }
612 else
613 {
615 m_trapAxisCtrl->SetSelection( 1 );
616 }
617
618 // Store the initial thermal spoke angle to restore it, because some initializations
619 // can change this value (mainly after m_PadShapeSelector initializations)
620 EDA_ANGLE spokeInitialAngle = m_previewPad->GetThermalSpokeAngle();
621
622 m_padToDieOpt->SetValue( m_previewPad->GetPadToDieLength() != 0 );
624
625 if( m_previewPad->GetLocalClearance().has_value() )
627 else
628 m_clearance.ChangeValue( wxEmptyString );
629
630 if( m_previewPad->GetLocalSolderMaskMargin().has_value() )
632 else
633 m_maskMargin.ChangeValue( wxEmptyString );
634
635 if( m_previewPad->GetLocalSolderPasteMargin().has_value() )
637 else
638 m_pasteMargin.ChangeValue( wxEmptyString );
639
642 else
643 m_pasteMarginRatio.ChangeValue( wxEmptyString );
644
649
658
660
661 if( m_curvedEdges->GetValue() )
663 else
664 m_curvePointsCtrl->SetValue( 5 );
665
667 {
668 default:
669 case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
670 case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
671 case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
672 case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
673 }
674
676 m_ZoneCustomPadShape->SetSelection( 1 );
677 else
678 m_ZoneCustomPadShape->SetSelection( 0 );
679
680 switch( m_previewPad->GetShape() )
681 {
682 default:
683 case PAD_SHAPE::CIRCLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
684 case PAD_SHAPE::OVAL: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_OVAL ); break;
685 case PAD_SHAPE::RECTANGLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_RECT ); break;
686 case PAD_SHAPE::TRAPEZOID: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_TRAPEZOID ); break;
687 case PAD_SHAPE::ROUNDRECT: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_ROUNDRECT ); break;
688
689 case PAD_SHAPE::CHAMFERED_RECT:
692 else
694 break;
695
696 case PAD_SHAPE::CUSTOM:
697 if( m_previewPad->GetAnchorPadShape() == PAD_SHAPE::RECTANGLE )
699 else
701 break;
702 }
703
712
714
715 // Type of pad selection
716 bool aperture =
717 m_previewPad->GetAttribute() == PAD_ATTRIB::SMD && m_previewPad->IsAperturePad();
718
719 if( aperture )
720 {
721 m_padType->SetSelection( APERTURE_DLG_TYPE );
722 }
723 else
724 {
725 switch( m_previewPad->GetAttribute() )
726 {
727 case PAD_ATTRIB::PTH: m_padType->SetSelection( PTH_DLG_TYPE ); break;
728 case PAD_ATTRIB::SMD: m_padType->SetSelection( SMD_DLG_TYPE ); break;
729 case PAD_ATTRIB::CONN: m_padType->SetSelection( CONN_DLG_TYPE ); break;
730 case PAD_ATTRIB::NPTH: m_padType->SetSelection( NPTH_DLG_TYPE ); break;
731 }
732 }
733
734 switch( m_previewPad->GetProperty() )
735 {
736 case PAD_PROP::NONE: m_choiceFabProperty->SetSelection( 0 ); break;
737 case PAD_PROP::BGA: m_choiceFabProperty->SetSelection( 1 ); break;
738 case PAD_PROP::FIDUCIAL_LOCAL: m_choiceFabProperty->SetSelection( 2 ); break;
739 case PAD_PROP::FIDUCIAL_GLBL: m_choiceFabProperty->SetSelection( 3 ); break;
740 case PAD_PROP::TESTPOINT: m_choiceFabProperty->SetSelection( 4 ); break;
741 case PAD_PROP::HEATSINK: m_choiceFabProperty->SetSelection( 5 ); break;
742 case PAD_PROP::CASTELLATED: m_choiceFabProperty->SetSelection( 6 ); break;
743 }
744
745 // Ensure the pad property is compatible with the pad type
746 if( m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
747 {
748 m_choiceFabProperty->SetSelection( 0 );
749 m_choiceFabProperty->Enable( false );
750 }
751
753 m_holeShapeCtrl->SetSelection( 0 );
754 else
755 m_holeShapeCtrl->SetSelection( 1 );
756
759
760 // Update some dialog widgets state (Enable/disable options):
761 wxCommandEvent cmd_event;
762 OnPadShapeSelection( cmd_event );
763 OnOffsetCheckbox( cmd_event );
764
765 // Restore thermal spoke angle to its initial value, because it can be modified
766 // by the call to OnPadShapeSelection()
767 m_previewPad->SetThermalSpokeAngle( spokeInitialAngle );
769}
770
771
772void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
773{
774 redraw();
775 event.Skip();
776}
777
778
779void DIALOG_PAD_PROPERTIES::onChangePadMode( wxCommandEvent& event )
780{
782
784
785 // fix the pad render mode (filled/not filled)
786 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
787
788 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
789 settings->SetHighContrast( false );
790 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
791
792 redraw();
793}
794
795
797{
798 switch( m_PadShapeSelector->GetSelection() )
799 {
803 m_shapePropsBook->SetSelection( 0 );
804 break;
805
807 m_shapePropsBook->SetSelection( 1 );
808 break;
809
811 {
812 m_shapePropsBook->SetSelection( 2 );
813
814 // Reasonable defaults
817
818 break;
819 }
820
822 m_shapePropsBook->SetSelection( 3 );
823
824 // Reasonable default
825 if( m_previewPad->GetChamferRectRatio() == 0.0 )
827
828 // Ensure the displayed value is up to date:
830
831 // A reasonable default is one corner chamfered (usual for some SMD pads).
832 if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
833 && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
834 {
835 m_cbTopLeft->SetValue( true );
836 m_cbTopRight->SetValue( false );
837 m_cbBottomLeft->SetValue( false );
838 m_cbBottomRight->SetValue( false );
839 }
840
841 break;
842
844 m_shapePropsBook->SetSelection( 4 );
845
846 // Reasonable defaults
848 && m_previewPad->GetChamferRectRatio() == 0.0 )
849 {
853 }
854
855 // Ensure the displayed values are up to date:
858 break;
859
860 case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE::CUSTOM, circular anchor
861 case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE::CUSTOM, rect anchor
862 m_shapePropsBook->SetSelection( 0 );
863 break;
864 }
865
866 // Note: must do this before enabling/disabling m_sizeY as we're using that as a flag to see
867 // what the last shape was.
868 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE )
869 {
870 if( m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_90 )
872 }
873 else
874 {
875 if( !m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_45 )
877 }
878
879 // Readjust props book size
880 wxSize size = m_shapePropsBook->GetSize();
881 size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
882 m_shapePropsBook->SetMaxSize( size );
883
886
887 m_offsetShapeOpt->Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE );
888
889 if( !m_offsetShapeOpt->IsEnabled() )
890 m_offsetShapeOpt->SetValue( false );
891
892 // Show/hide controls depending on m_offsetShapeOpt being enabled
893 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
894 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
895
898
899 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
900 m_notebook->GetPage( i )->Layout();
901
902 // Resize the dialog if its height is too small to show all widgets:
903 if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
904 m_MainSizer->SetSizeHints( this );
905
907 redraw();
908}
909
910
912{
915 redraw();
916}
917
918
919void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
920{
922 redraw();
923}
924
925
927{
928 m_rbCopperLayersSel->Clear();
929
930 switch( m_padType->GetSelection() )
931 {
932 case PTH_DLG_TYPE:
933 m_rbCopperLayersSel->Append( _( "All copper layers" ) );
934 m_rbCopperLayersSel->Append( wxString::Format( _( "%s, %s and connected layers" ),
936 m_board->GetLayerName( B_Cu ) ) );
937 m_rbCopperLayersSel->Append( _( "Connected layers only" ) );
938 m_rbCopperLayersSel->Append( _( "None" ) );
939 break;
940
941 case NPTH_DLG_TYPE:
942 m_rbCopperLayersSel->Append( wxString::Format( _( "%s and %s" ),
944 m_board->GetLayerName( B_Cu ) ) );
947 m_rbCopperLayersSel->Append( _( "None" ) );
948 break;
949
950 case SMD_DLG_TYPE:
951 case CONN_DLG_TYPE:
954 break;
955
957 m_rbCopperLayersSel->Append( _( "None" ) );
958 break;
959 }
960}
961
962
963void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
964{
965 bool hasHole = true;
966 bool hasConnection = true;
967 bool hasProperty = true;
968
969 switch( m_padType->GetSelection() )
970 {
971 case PTH_DLG_TYPE: hasHole = true; hasConnection = true; hasProperty = true; break;
972 case SMD_DLG_TYPE: hasHole = false; hasConnection = true; hasProperty = true; break;
973 case CONN_DLG_TYPE: hasHole = false; hasConnection = true; hasProperty = true; break;
974 case NPTH_DLG_TYPE: hasHole = true; hasConnection = false; hasProperty = false; break;
975 case APERTURE_DLG_TYPE: hasHole = false; hasConnection = false; hasProperty = true; break;
976 }
977
978 // Update Layers dropdown list and selects the "best" layer set for the new pad type:
981
982 m_gbSizerHole->Show( hasHole );
983 m_staticline6->Show( hasHole );
984
985 if( !hasHole )
986 {
987 m_holeX.ChangeValue( 0 );
988 m_holeY.ChangeValue( 0 );
989 }
990 else if( m_holeX.GetValue() == 0 )
991 {
992 if( m_currentPad )
993 {
996 }
997 else
998 {
1000 }
1001 }
1002
1003 if( !hasConnection )
1004 {
1005 m_padNumCtrl->ChangeValue( wxEmptyString );
1007 m_padToDieOpt->SetValue( false );
1008 }
1009 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1010 {
1011 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1013 }
1014
1015 if( !hasProperty )
1016 m_choiceFabProperty->SetSelection( 0 );
1017
1018 m_choiceFabProperty->Enable( hasProperty );
1019
1021
1022 // Layout adjustment is needed if the hole details got shown/hidden
1023 m_LeftBoxSizer->Layout();
1024 redraw();
1025}
1026
1027
1028void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1029{
1030 bool hasHole = true;
1031 bool hasConnection = true;
1032
1033 switch( m_padType->GetSelection() )
1034 {
1035 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1036 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1037 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1038 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1039 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1040 }
1041
1042 // Enable/disable hole controls
1043 m_holeShapeLabel->Enable( hasHole );
1044 m_holeShapeCtrl->Enable( hasHole );
1045 m_holeX.Enable( hasHole );
1046 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1047
1048 // Enable/disable number and net
1049 m_padNumLabel->Enable( hasConnection );
1050 m_padNumCtrl->Enable( hasConnection );
1051
1052 if( m_padNetLabel->IsShown() )
1053 {
1054 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1055 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1056 }
1057
1058 // Enable/disable pad length-to-die
1059 m_padToDieOpt->Enable( hasConnection );
1060
1061 if( !m_padToDieOpt->IsEnabled() )
1062 m_padToDieOpt->SetValue( false );
1063
1064 // We can show/hide this here because it doesn't require the layout to be refreshed.
1065 // All the others have to be done in their event handlers because doing a layout here
1066 // causes infinite looping on MSW.
1067 m_padToDie.Show( m_padToDieOpt->GetValue() );
1068
1069 // Enable/disable Copper Layers control
1070 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1071
1073
1074 switch( m_padType->GetSelection() )
1075 {
1076 case PTH_DLG_TYPE:
1077 if( !cu_set.any() )
1078 m_stackupImagesBook->SetSelection( 3 );
1079 else if( !m_previewPad->GetRemoveUnconnected() )
1080 m_stackupImagesBook->SetSelection( 0 );
1081 else if( m_previewPad->GetKeepTopBottom() )
1082 m_stackupImagesBook->SetSelection( 1 );
1083 else
1084 m_stackupImagesBook->SetSelection( 2 );
1085
1086 break;
1087
1088 case NPTH_DLG_TYPE:
1089 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1090 m_stackupImagesBook->SetSelection( 4 );
1091 else if( cu_set.test( F_Cu ) )
1092 m_stackupImagesBook->SetSelection( 5 );
1093 else if( cu_set.test( B_Cu ) )
1094 m_stackupImagesBook->SetSelection( 6 );
1095 else
1096 m_stackupImagesBook->SetSelection( 7 );
1097
1098 break;
1099
1100 case SMD_DLG_TYPE:
1101 case CONN_DLG_TYPE:
1102 case APERTURE_DLG_TYPE:
1103 m_stackupImagesBook->ChangeSelection( 3 );
1104 break;
1105 }
1106
1108}
1109
1110
1112{
1113 event.Enable( !m_board->LegacyTeardrops() );
1114}
1115
1116
1118{
1119 event.Enable( !m_board->LegacyTeardrops() && m_curvedEdges->GetValue() );
1120}
1121
1122
1124{
1125 bool isOnCopperLayer = ( m_previewPad->GetLayerSet() & LSET::AllCuMask() ).any();
1126 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1127}
1128
1129
1130void DIALOG_PAD_PROPERTIES::updatePadLayersList( LSET layer_mask, bool remove_unconnected,
1131 bool keep_top_bottom )
1132{
1134
1135 switch( m_padType->GetSelection() )
1136 {
1137 case PTH_DLG_TYPE:
1138 if( !layer_mask.any() )
1139 layer_mask = PAD::PTHMask();
1140
1141 if( !( layer_mask & LSET::AllCuMask() ).any() )
1142 m_rbCopperLayersSel->SetSelection( 3 );
1143 else if( !remove_unconnected )
1144 m_rbCopperLayersSel->SetSelection( 0 );
1145 else if( keep_top_bottom )
1146 m_rbCopperLayersSel->SetSelection( 1 );
1147 else
1148 m_rbCopperLayersSel->SetSelection( 2 );
1149
1150 break;
1151
1152 case SMD_DLG_TYPE:
1153 if( !layer_mask.any() )
1154 layer_mask = PAD::SMDMask();
1155
1156 if( layer_mask.test( F_Cu ) )
1157 m_rbCopperLayersSel->SetSelection( 0 );
1158 else
1159 m_rbCopperLayersSel->SetSelection( 1 );
1160
1161 break;
1162
1163 case CONN_DLG_TYPE:
1164 if( !layer_mask.any() )
1165 layer_mask = PAD::ConnSMDMask();
1166
1167 if( layer_mask.test( F_Cu ) )
1168 m_rbCopperLayersSel->SetSelection( 0 );
1169 else
1170 m_rbCopperLayersSel->SetSelection( 1 );
1171
1172 break;
1173
1174 case NPTH_DLG_TYPE:
1175 if( !layer_mask.any() )
1176 layer_mask = PAD::UnplatedHoleMask();
1177
1178 if( layer_mask.test( F_Cu ) && layer_mask.test( B_Cu ) )
1179 m_rbCopperLayersSel->SetSelection( 0 );
1180 else if( layer_mask.test( F_Cu ) )
1181 m_rbCopperLayersSel->SetSelection( 1 );
1182 else if( layer_mask.test( B_Cu ) )
1183 m_rbCopperLayersSel->SetSelection( 2 );
1184 else
1185 m_rbCopperLayersSel->SetSelection( 3 );
1186
1187 break;
1188
1189 case APERTURE_DLG_TYPE:
1190 if( !layer_mask.any() )
1191 layer_mask = PAD::ApertureMask();
1192
1193 m_rbCopperLayersSel->SetSelection( 0 );
1194 break;
1195 }
1196
1197 m_layerFrontAdhesive->SetValue( layer_mask[F_Adhes] );
1198 m_layerBackAdhesive->SetValue( layer_mask[B_Adhes] );
1199
1200 m_layerFrontPaste->SetValue( layer_mask[F_Paste] );
1201 m_layerBackPaste->SetValue( layer_mask[B_Paste] );
1202
1203 m_layerFrontSilk->SetValue( layer_mask[F_SilkS] );
1204 m_layerBackSilk->SetValue( layer_mask[B_SilkS] );
1205
1206 m_layerFrontMask->SetValue( layer_mask[F_Mask] );
1207 m_layerBackMask->SetValue( layer_mask[B_Mask] );
1208
1209 m_layerECO1->SetValue( layer_mask[Eco1_User] );
1210 m_layerECO2->SetValue( layer_mask[Eco2_User] );
1211
1212 m_layerUserDwgs->SetValue( layer_mask[Dwgs_User] );
1213}
1214
1215
1217{
1218 bool retVal = DIALOG_SHIM::Show( aShow );
1219
1220 if( aShow )
1221 {
1222 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1223 // wxWidgets needs to have these set when the panel is visible for some reason.
1224 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1225 m_stackupImage0->SetBitmap( KiBitmapBundle( BITMAPS::pads_reset_unused ) );
1226 m_stackupImage1->SetBitmap( KiBitmapBundle( BITMAPS::pads_remove_unused_keep_bottom ) );
1227 m_stackupImage2->SetBitmap( KiBitmapBundle( BITMAPS::pads_remove_unused ) );
1228 m_stackupImage4->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth_top_bottom ) );
1229 m_stackupImage5->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth_top ) );
1230 m_stackupImage6->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth_bottom ) );
1231 m_stackupImage7->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth ) );
1232
1233 Layout();
1234 }
1235
1236 return retVal;
1237}
1238
1239
1240void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1241{
1243 redraw();
1244}
1245
1246
1247void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1248{
1250 redraw();
1251}
1252
1253
1255{
1256 bool error = !transferDataToPad( m_previewPad );
1257
1258 wxArrayString error_msgs;
1259 wxArrayString warning_msgs;
1260 VECTOR2I pad_size = m_previewPad->GetSize();
1261 VECTOR2I drill_size = m_previewPad->GetDrillSize();
1262
1263 if( m_previewPad->GetShape() == PAD_SHAPE::CUSTOM )
1264 {
1265 pad_size = m_previewPad->GetBoundingBox().GetSize();
1266 }
1267 else if( m_previewPad->GetShape() == PAD_SHAPE::CIRCLE )
1268 {
1269 if( pad_size.x <= 0 )
1270 error_msgs.Add( _( "Error: Pad must have a positive size." ) );
1271 }
1272 else
1273 {
1274 if( pad_size.x <= 0 || pad_size.y <= 0 )
1275 error_msgs.Add( _( "Error: Pad must have a positive size." ) );
1276 }
1277
1278 // Test hole against pad shape
1280 {
1281 int maxError = m_board->GetDesignSettings().m_MaxError;
1282 SHAPE_POLY_SET padOutline;
1283
1284 m_previewPad->TransformShapeToPolygon( padOutline, UNDEFINED_LAYER, 0, maxError,
1285 ERROR_INSIDE );
1286
1287 if( !padOutline.Collide( m_previewPad->GetPosition() ) )
1288 {
1289 warning_msgs.Add( _( "Warning: Pad hole not inside pad shape." ) );
1290 }
1291 else if( m_previewPad->GetAttribute() == PAD_ATTRIB::PTH )
1292 {
1293 std::shared_ptr<SHAPE_SEGMENT> slot = m_previewPad->GetEffectiveHoleShape();
1294 SHAPE_POLY_SET slotOutline;
1295
1296 TransformOvalToPolygon( slotOutline, slot->GetSeg().A, slot->GetSeg().B,
1297 slot->GetWidth(), maxError, ERROR_INSIDE );
1298
1299 padOutline.BooleanSubtract( slotOutline, SHAPE_POLY_SET::PM_FAST );
1300
1301 if( padOutline.IsEmpty() )
1302 warning_msgs.Add( _( "Warning: Pad hole will leave no copper." ) );
1303 }
1304 }
1305
1306 if( m_previewPad->GetLocalClearance().value_or( 0 ) < 0 )
1307 warning_msgs.Add( _( "Warning: Negative local clearance values will have no effect." ) );
1308
1309 // Some pads need a negative solder mask clearance (mainly for BGA with small pads)
1310 // However the negative solder mask clearance must not create negative mask size
1311 // Therefore test for minimal acceptable negative value
1312 std::optional<int> solderMaskMargin = m_previewPad->GetLocalSolderMaskMargin();
1313
1314 if( solderMaskMargin.has_value() && solderMaskMargin.value() < 0 )
1315 {
1316 int absMargin = abs( solderMaskMargin.value() );
1317
1318 if( m_previewPad->GetShape() == PAD_SHAPE::CUSTOM )
1319 {
1320 for( const std::shared_ptr<PCB_SHAPE>& shape : m_previewPad->GetPrimitives() )
1321 {
1322 BOX2I shapeBBox = shape->GetBoundingBox();
1323
1324 if( absMargin > shapeBBox.GetWidth() || absMargin > shapeBBox.GetHeight() )
1325 {
1326 warning_msgs.Add( _( "Warning: Negative solder mask clearances larger than "
1327 "some shape primitives. Results may be surprising." ) );
1328
1329 break;
1330 }
1331 }
1332 }
1333 else if( absMargin > pad_size.x || absMargin > pad_size.y )
1334 {
1335 warning_msgs.Add( _( "Warning: Negative solder mask clearance larger than pad. No "
1336 "solder mask will be generated." ) );
1337 }
1338 }
1339
1340 // Some pads need a positive solder paste clearance (mainly for BGA with small pads)
1341 // However, a positive value can create issues if the resulting shape is too big.
1342 // (like a solder paste creating a solder paste area on a neighbor pad or on the solder mask)
1343 // So we could ask for user to confirm the choice
1344 // For now we just check for disappearing paste
1345 wxSize paste_size;
1346 int paste_margin = m_previewPad->GetLocalSolderPasteMargin().value_or( 0 );
1347 double paste_ratio = m_previewPad->GetLocalSolderPasteMarginRatio().value_or( 0 );
1348
1349 paste_size.x = pad_size.x + paste_margin + KiROUND( pad_size.x * paste_ratio );
1350 paste_size.y = pad_size.y + paste_margin + KiROUND( pad_size.y * paste_ratio );
1351
1352 if( paste_size.x <= 0 || paste_size.y <= 0 )
1353 {
1354 warning_msgs.Add( _( "Warning: Negative solder paste margins larger than pad. No solder "
1355 "paste mask will be generated." ) );
1356 }
1357
1358 LSET padlayers_mask = m_previewPad->GetLayerSet();
1359
1360 if( padlayers_mask == 0 )
1361 error_msgs.Add( _( "Error: pad has no layer." ) );
1362
1363 if( !padlayers_mask[F_Cu] && !padlayers_mask[B_Cu] )
1364 {
1365 if( ( drill_size.x || drill_size.y ) && m_previewPad->GetAttribute() != PAD_ATTRIB::NPTH )
1366 {
1367 warning_msgs.Add( _( "Warning: Plated through holes should normally have a copper pad "
1368 "on at least one layer." ) );
1369 }
1370 }
1371
1372 if( error )
1373 error_msgs.Add( _( "Error: Trapazoid delta is too large." ) );
1374
1375 switch( m_previewPad->GetAttribute() )
1376 {
1377 case PAD_ATTRIB::NPTH: // Not plated, but through hole, a hole is expected
1378 case PAD_ATTRIB::PTH: // Pad through hole, a hole is also expected
1379 if( drill_size.x <= 0
1380 || ( drill_size.y <= 0 && m_previewPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ) )
1381 {
1382 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1383 }
1384 break;
1385
1386 case PAD_ATTRIB::CONN: // Connector pads are smd pads, just they do not have solder paste.
1387 if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
1388 {
1389 warning_msgs.Add( _( "Warning: Connector pads normally have no solder paste. Use a "
1390 "SMD pad instead." ) );
1391 }
1393
1394 case PAD_ATTRIB::SMD: // SMD and Connector pads (One external copper layer only)
1395 {
1396 if( drill_size.x > 0 || drill_size.y > 0 )
1397 {
1398 error_msgs.Add( _( "Error: SMD pad has a hole." ) );
1399 }
1400
1401 LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
1402
1403 if( ( padlayers_mask[F_Cu] && padlayers_mask[B_Cu] ) || innerlayers_mask.count() != 0 )
1404 warning_msgs.Add( _( "Warning: SMD pad has no outer layers." ) );
1405 }
1406 break;
1407 }
1408
1409 if( ( m_previewPad->GetProperty() == PAD_PROP::FIDUCIAL_GLBL || m_previewPad->GetProperty() == PAD_PROP::FIDUCIAL_LOCAL )
1410 && m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
1411 {
1412 warning_msgs.Add( _( "Warning: Fiducial property makes no sense on NPTH pads." ) );
1413 }
1414
1415 if( m_previewPad->GetProperty() == PAD_PROP::TESTPOINT
1416 && m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
1417 {
1418 warning_msgs.Add( _( "Warning: Testpoint property makes no sense on NPTH pads." ) );
1419 }
1420
1421 if( m_previewPad->GetProperty() == PAD_PROP::HEATSINK
1422 && m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
1423 {
1424 warning_msgs.Add( _( "Warning: Heatsink property makes no sense of NPTH pads." ) );
1425 }
1426
1427 if( m_previewPad->GetProperty() == PAD_PROP::CASTELLATED
1428 && m_previewPad->GetAttribute() != PAD_ATTRIB::PTH )
1429 {
1430 warning_msgs.Add( _( "Warning: Castellated property is for PTH pads." ) );
1431 }
1432
1433 if( m_previewPad->GetProperty() == PAD_PROP::BGA
1434 && m_previewPad->GetAttribute() != PAD_ATTRIB::SMD )
1435 {
1436 warning_msgs.Add( _( "Warning: BGA property is for SMD pads." ) );
1437 }
1438
1439 if( m_previewPad->GetShape() == PAD_SHAPE::ROUNDRECT
1440 || m_previewPad->GetShape() == PAD_SHAPE::CHAMFERED_RECT )
1441 {
1443
1444 if( m_cornerRatio.GetDoubleValue() < 0.0 )
1445 error_msgs.Add( _( "Error: Negative corner size." ) );
1446 else if( m_cornerRatio.GetDoubleValue() > 50.0 )
1447 warning_msgs.Add( _( "Warning: Corner size will make pad circular." ) );
1448 }
1449
1450 // PADSTACKS TODO: this will need to check each layer in the pad...
1451 if( m_previewPad->GetShape() == PAD_SHAPE::CUSTOM )
1452 {
1453 SHAPE_POLY_SET mergedPolygon;
1454 m_previewPad->MergePrimitivesAsPolygon( &mergedPolygon );
1455
1456 if( mergedPolygon.OutlineCount() > 1 )
1457 error_msgs.Add( _( "Error: Custom pad shape must resolve to a single polygon." ) );
1458 }
1459
1460
1461 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1462 {
1463 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1464 : _( "Pad Properties Warnings" );
1465 HTML_MESSAGE_BOX dlg( this, title );
1466
1467 wxArrayString msgs = error_msgs;
1468
1469 for( const wxString& msg : warning_msgs )
1470 msgs.Add( msg );
1471
1472 dlg.ListSet( msgs );
1473
1474 dlg.ShowModal();
1475 }
1476
1477 return error_msgs.GetCount() == 0;
1478}
1479
1480
1482{
1483 if( !m_canUpdate )
1484 return;
1485
1487 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view->GetPainter() );
1488 KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings();
1489
1491
1492 // The layer used to place primitive items selected when editing custom pad shapes
1493 // we use here a layer never used in a pad:
1494 #define SELECTED_ITEMS_LAYER Dwgs_User
1495
1498
1500
1501 view->Update( m_previewPad );
1502
1503 // delete previous items if highlight list
1504 while( m_highlight.size() )
1505 {
1506 delete m_highlight.back(); // the dtor also removes item from view
1507 m_highlight.pop_back();
1508 }
1509
1510 BOX2I bbox = m_previewPad->ViewBBox();
1511
1512 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1513 {
1514 // The origin always goes in the middle of the canvas; we want offsetting the pad
1515 // shape to move the pad, not the hole
1516 bbox.Move( -m_previewPad->GetPosition() );
1517 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1518 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1519
1520 // Don't blow up the GAL on too-large numbers
1521 if( maxXExtent > INT_MAX / 4 )
1522 maxXExtent = INT_MAX / 4;
1523
1524 if( maxYExtent > INT_MAX / 4 )
1525 maxYExtent = INT_MAX / 4;
1526
1527 BOX2D viewBox( m_previewPad->GetPosition(), {0, 0} );
1528 BOX2D canvasBox( m_previewPad->GetPosition(), {0, 0} );
1529 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1530 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1531
1532 view->SetBoundary( canvasBox );
1533
1534 // Autozoom
1535 view->SetViewport( viewBox );
1536
1539 }
1540}
1541
1542
1544{
1545 if( !wxDialog::TransferDataToWindow() )
1546 return false;
1547
1548 if( !m_panelGeneral->TransferDataToWindow() )
1549 return false;
1550
1551 if( !m_localSettingsPanel->TransferDataToWindow() )
1552 return false;
1553
1554 return true;
1555}
1556
1557
1559{
1560 BOARD_COMMIT commit( m_parent );
1561
1562 if( !wxDialog::TransferDataFromWindow() )
1563 return false;
1564
1565 if( !m_panelGeneral->TransferDataFromWindow() )
1566 return false;
1567
1568 if( !m_localSettingsPanel->TransferDataFromWindow() )
1569 return false;
1570
1571 if( !padValuesOK() )
1572 return false;
1573
1575 return false;
1576
1578 padTool->SetLastPadNumber( m_masterPad->GetNumber() );
1579
1580 // m_masterPad is a pattern: ensure there is no net for this pad:
1582
1583 if( !m_currentPad ) // Set current Pad parameters
1584 return true;
1585
1586 commit.Modify( m_currentPad );
1587
1588 // Update values
1592
1594
1595 VECTOR2I size = m_masterPad->GetDelta();
1596 m_currentPad->SetDelta( size );
1597
1600
1601 VECTOR2I offset = m_masterPad->GetOffset();
1602 m_currentPad->SetOffset( offset );
1603
1605
1606 if( m_masterPad->GetShape() != PAD_SHAPE::CUSTOM )
1608
1611
1615
1617
1618 int padNetcode = NETINFO_LIST::UNCONNECTED;
1619
1620 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1621 if( m_masterPad->GetAttribute() != PAD_ATTRIB::NPTH )
1622 padNetcode = m_padNetSelector->GetSelectedNetcode();
1623
1624 m_currentPad->SetNetCode( padNetcode );
1636
1638
1639 // rounded rect pads with radius ratio = 0 are in fact rect pads.
1640 // So set the right shape (and perhaps issues with a radius = 0)
1641 if( m_currentPad->GetShape() == PAD_SHAPE::ROUNDRECT &&
1643 {
1644 m_currentPad->SetShape( PAD_SHAPE::RECTANGLE );
1645 }
1646
1647 // Set the fabrication property:
1649
1650 // define the way the clearance area is defined in zones
1652
1653 VECTOR2I relPos = m_masterPad->GetPosition();
1654
1656 {
1657 // flip pad (up/down) around its position
1659 relPos.y = -relPos.y;
1660 }
1661
1662 // Must be done after flipping
1664
1666
1667 // redraw the area where the pad was
1669
1670 commit.Push( _( "Edit Pad Properties" ) );
1671
1672 return true;
1673}
1674
1675
1677{
1678 PAD_PROP prop = PAD_PROP::NONE;
1679
1680 switch( m_choiceFabProperty->GetSelection() )
1681 {
1682 case 0: prop = PAD_PROP::NONE; break;
1683 case 1: prop = PAD_PROP::BGA; break;
1684 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1685 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1686 case 4: prop = PAD_PROP::TESTPOINT; break;
1687 case 5: prop = PAD_PROP::HEATSINK; break;
1688 case 6: prop = PAD_PROP::CASTELLATED; break;
1689 }
1690
1691 return prop;
1692}
1693
1695{
1696 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1697 {
1698 m_holeXLabel->SetLabel( _( "Diameter:" ) );
1699 m_holeY.Show( false );
1700 }
1701 else
1702 {
1703 m_holeXLabel->SetLabel( _( "Hole size X:" ) );
1704 m_holeY.Show( true );
1705 }
1706
1707 m_holeXLabel->GetParent()->Layout();
1708}
1709
1711{
1712 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1714 {
1715 m_sizeXLabel->SetLabel( _( "Diameter:" ) );
1716 m_sizeY.Show( false );
1717 m_bitmapTeardrop->SetBitmap( KiBitmapBundle( BITMAPS::teardrop_sizes ) );
1718 m_minTrackWidthHint->SetLabel( _( "d" ) );
1719 m_stLenPercentHint->SetLabel( _( "d" ) );
1720 m_stWidthPercentHint->SetLabel( _( "d" ) );
1721 }
1722 else
1723 {
1724 m_sizeXLabel->SetLabel( _( "Pad size X:" ) );
1725 m_sizeY.Show( true );
1726 m_bitmapTeardrop->SetBitmap( KiBitmapBundle( BITMAPS::teardrop_rect_sizes ) );
1727 m_minTrackWidthHint->SetLabel( _( "w" ) );
1728 m_stLenPercentHint->SetLabel( _( "w" ) );
1729 m_stWidthPercentHint->SetLabel( _( "w" ) );
1730 }
1731
1732 m_sizeXLabel->GetParent()->Layout();
1733 resetSize();
1734 Layout();
1735 m_MainSizer->Fit( this );
1736}
1737
1738
1740{
1741 if( !Validate() )
1742 return false;
1743
1744 if( !m_panelGeneral->Validate() )
1745 return false;
1746
1747 if( !m_localSettingsPanel->Validate() )
1748 return false;
1749
1750 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1751 return false;
1752
1753 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1754 aPad->SetShape( code_shape[m_PadShapeSelector->GetSelection()] );
1755
1757 aPad->SetAnchorPadShape( PAD_SHAPE::RECTANGLE );
1758 else
1759 aPad->SetAnchorPadShape( PAD_SHAPE::CIRCLE );
1760
1761 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
1763
1764 aPad->GetTeardropParams().m_Enabled = m_cbTeardrops->GetValue();
1771
1772 if( m_curvedEdges->GetValue() )
1774 else
1776
1778
1779 // Read pad clearances values:
1780 if( m_clearance.IsNull() )
1781 aPad->SetLocalClearance( {} );
1782 else
1784
1785 if( m_maskMargin.IsNull() )
1786 aPad->SetLocalSolderMaskMargin( {} );
1787 else
1789
1790 if( m_pasteMargin.IsNull() )
1791 aPad->SetLocalSolderPasteMargin( {} );
1792 else
1794
1797 else
1799
1803
1804 // And rotation
1806
1807 switch( m_ZoneConnectionChoice->GetSelection() )
1808 {
1809 default:
1810 case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1811 case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
1812 case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1813 case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
1814 }
1815
1817
1818 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1819 {
1822 }
1823 else
1824 {
1827 }
1828
1829 if( aPad->GetShape() == PAD_SHAPE::CIRCLE )
1831 else
1833
1834 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
1835 // remember DeltaSize.x is the Y size variation
1836 bool error = false;
1837 VECTOR2I delta( 0, 0 );
1838
1839 if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
1840 {
1841 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
1842 if( m_trapAxisCtrl->GetSelection() == 0 )
1844 else
1846
1847 if( delta.x < 0 && delta.x < -aPad->GetSize().y )
1848 {
1849 delta.x = -aPad->GetSize().y + 2;
1850 error = true;
1851 }
1852
1853 if( delta.x > 0 && delta.x > aPad->GetSize().y )
1854 {
1855 delta.x = aPad->GetSize().y - 2;
1856 error = true;
1857 }
1858
1859 if( delta.y < 0 && delta.y < -aPad->GetSize().x )
1860 {
1861 delta.y = -aPad->GetSize().x + 2;
1862 error = true;
1863 }
1864
1865 if( delta.y > 0 && delta.y > aPad->GetSize().x )
1866 {
1867 delta.y = aPad->GetSize().x - 2;
1868 error = true;
1869 }
1870 }
1871
1872 aPad->SetDelta( delta );
1873
1874 if( m_offsetShapeOpt->GetValue() )
1876 else
1877 aPad->SetOffset( VECTOR2I() );
1878
1879 // Read pad length die
1880 if( m_padToDieOpt->GetValue() )
1882 else
1883 aPad->SetPadToDieLength( 0 );
1884
1885 aPad->SetNumber( m_padNumCtrl->GetValue() );
1887
1888 int chamfers = 0;
1889
1890 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
1891 {
1892 if( m_cbTopLeft->GetValue() )
1893 chamfers |= RECT_CHAMFER_TOP_LEFT;
1894
1895 if( m_cbTopRight->GetValue() )
1896 chamfers |= RECT_CHAMFER_TOP_RIGHT;
1897
1898 if( m_cbBottomLeft->GetValue() )
1899 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1900
1901 if( m_cbBottomRight->GetValue() )
1902 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1903 }
1904 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
1905 {
1906 if( m_cbTopLeft1->GetValue() )
1907 chamfers |= RECT_CHAMFER_TOP_LEFT;
1908
1909 if( m_cbTopRight1->GetValue() )
1910 chamfers |= RECT_CHAMFER_TOP_RIGHT;
1911
1912 if( m_cbBottomLeft1->GetValue() )
1913 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1914
1915 if( m_cbBottomRight1->GetValue() )
1916 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1917 }
1918 aPad->SetChamferPositions( chamfers );
1919
1920 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
1921 {
1922 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
1923 // that is the minimal area of this pad, and is useful to ensure a hole
1924 // diameter is acceptable, and is used in Gerber files as flashed area
1925 // reference
1926 if( aPad->GetAnchorPadShape() == PAD_SHAPE::CIRCLE )
1928 }
1929
1930 // Define the way the clearance area is defined in zones. Since all non-custom pad
1931 // shapes are convex to begin with, this really only makes any difference for custom
1932 // pad shapes.
1933 aPad->SetCustomShapeInZoneOpt( m_ZoneCustomPadShape->GetSelection() == 0 ?
1936
1937 switch( aPad->GetAttribute() )
1938 {
1939 case PAD_ATTRIB::PTH:
1940 break;
1941
1942 case PAD_ATTRIB::CONN:
1943 case PAD_ATTRIB::SMD:
1944 // SMD and PAD_ATTRIB::CONN has no hole.
1945 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
1946 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
1947 // and are intended to be used in virtual edge board connectors
1948 // However we can accept a non null offset,
1949 // mainly to allow complex pads build from a set of basic pad shapes
1950 aPad->SetDrillSize( VECTOR2I( 0, 0 ) );
1951 break;
1952
1953 case PAD_ATTRIB::NPTH:
1954 // Mechanical purpose only:
1955 // no net name, no pad name allowed
1956 aPad->SetNumber( wxEmptyString );
1958 break;
1959
1960 default:
1961 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
1962 break;
1963 }
1964
1965 if( aPad->GetShape() == PAD_SHAPE::ROUNDRECT )
1966 {
1968 }
1969 else if( aPad->GetShape() == PAD_SHAPE::CHAMFERED_RECT )
1970 {
1972 {
1975 }
1976 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
1977 {
1979 aPad->SetRoundRectRadiusRatio( 0 );
1980 }
1981 }
1982
1984
1985 LSET padLayerMask = LSET();
1986 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
1987
1988 aPad->SetRemoveUnconnected( false );
1989 aPad->SetKeepTopBottom( false );
1990
1991 switch( m_padType->GetSelection() )
1992 {
1993 case PTH_DLG_TYPE:
1994 switch( copperLayersChoice )
1995 {
1996 case 0:
1997 // All copper layers
1998 padLayerMask |= LSET::AllCuMask();
1999 break;
2000
2001 case 1:
2002 // Front, back and connected
2003 padLayerMask |= LSET::AllCuMask();
2004 aPad->SetRemoveUnconnected( true );
2005 aPad->SetKeepTopBottom( true );
2006 break;
2007
2008 case 2:
2009 // Connected only
2010 padLayerMask |= LSET::AllCuMask();
2011 aPad->SetRemoveUnconnected( true );
2012 break;
2013
2014 case 3:
2015 // No copper layers
2016 break;
2017 }
2018
2019 break;
2020
2021 case NPTH_DLG_TYPE:
2022 switch( copperLayersChoice )
2023 {
2024 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
2025 case 1: padLayerMask.set( F_Cu ); break;
2026 case 2: padLayerMask.set( B_Cu ); break;
2027 default: break;
2028 }
2029
2030 break;
2031
2032 case SMD_DLG_TYPE:
2033 case CONN_DLG_TYPE:
2034 switch( copperLayersChoice )
2035 {
2036 case 0: padLayerMask.set( F_Cu ); break;
2037 case 1: padLayerMask.set( B_Cu ); break;
2038 }
2039
2040 break;
2041
2042 case APERTURE_DLG_TYPE:
2043 // no copper layers
2044 break;
2045 }
2046
2047 if( m_layerFrontAdhesive->GetValue() )
2048 padLayerMask.set( F_Adhes );
2049
2050 if( m_layerBackAdhesive->GetValue() )
2051 padLayerMask.set( B_Adhes );
2052
2053 if( m_layerFrontPaste->GetValue() )
2054 padLayerMask.set( F_Paste );
2055
2056 if( m_layerBackPaste->GetValue() )
2057 padLayerMask.set( B_Paste );
2058
2059 if( m_layerFrontSilk->GetValue() )
2060 padLayerMask.set( F_SilkS );
2061
2062 if( m_layerBackSilk->GetValue() )
2063 padLayerMask.set( B_SilkS );
2064
2065 if( m_layerFrontMask->GetValue() )
2066 padLayerMask.set( F_Mask );
2067
2068 if( m_layerBackMask->GetValue() )
2069 padLayerMask.set( B_Mask );
2070
2071 if( m_layerECO1->GetValue() )
2072 padLayerMask.set( Eco1_User );
2073
2074 if( m_layerECO2->GetValue() )
2075 padLayerMask.set( Eco2_User );
2076
2077 if( m_layerUserDwgs->GetValue() )
2078 padLayerMask.set( Dwgs_User );
2079
2080 aPad->SetLayerSet( padLayerMask );
2081
2082 return !error;
2083}
2084
2085
2086void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2087{
2088 if( m_offsetShapeOpt->GetValue() )
2089 {
2092 }
2093
2094 // Show/hide controls depending on m_offsetShapeOpt being enabled
2095 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2096 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2097
2098 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2099 m_notebook->GetPage( i )->Layout();
2100
2101 OnValuesChanged( event );
2102}
2103
2104
2106{
2107 if( m_padToDieOpt->GetValue() && m_currentPad )
2109
2110 OnValuesChanged( event );
2111}
2112
2113
2114void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2115{
2116 if( m_canUpdate )
2117 {
2119 return;
2120
2121 // If the pad size has changed, update the displayed values for rounded rect pads.
2123
2124 redraw();
2125 }
2126}
2127
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
#define DEFAULT_PAD_DRILL_DIAMETER_MM
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
TEARDROP_PARAMETERS & GetTeardropParams()
std::unique_ptr< PAD > m_Pad_Master
void SetParentGroup(PCB_GROUP *aGroup)
Definition: board_item.h:90
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
VECTOR2I GetFPRelativePosition() const
Definition: board_item.cpp:262
void SetFPRelativePosition(const VECTOR2I &aPos)
Definition: board_item.cpp:276
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:204
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:832
FOOTPRINTS & Footprints()
Definition: board.h:318
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:576
bool LegacyTeardrops() const
Definition: board.h:1217
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:806
coord_type GetTop() const
Definition: box2.h:195
coord_type GetHeight() const
Definition: box2.h:189
coord_type GetWidth() const
Definition: box2.h:188
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:112
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:507
coord_type GetRight() const
Definition: box2.h:190
coord_type GetLeft() const
Definition: box2.h:194
const Vec & GetSize() const
Definition: box2.h:180
coord_type GetBottom() const
Definition: box2.h:191
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)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
Class DIALOG_PAD_PROPERTIES_BASE.
void OnUpdateUINonCopperWarning(wxUpdateUIEvent &event) override
void OnInitDialog(wxInitDialogEvent &event) override
void PadTypeSelected(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.
bool Show(bool aShow) 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 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 onTeardropsUpdateUi(wxUpdateUIEvent &event) override
void onChangePadMode(wxCommandEvent &event) override
std::vector< PCB_SHAPE * > m_highlight
KIGFX::ORIGIN_VIEWITEM * m_axisOrigin
void OnSetCopperLayers(wxCommandEvent &event) override
void OnCancel(wxCommandEvent &event) override
void onCornerRadiusChange(wxCommandEvent &event) override
void updatePadLayersList(LSET layer_mask, bool remove_unconnected, bool keep_top_bottom)
Updates the CheckBox states in pad layers list, based on the layer_mask (if non-empty) or the default...
PAD_PROP getSelectedProperty()
Return the pad property currently selected.
void OnSetLayers(wxCommandEvent &event) override
void onCornerSizePercentChange(wxCommandEvent &event) override
void OnPadToDieCheckbox(wxCommandEvent &event) override
void onTeardropCurvePointsUpdateUi(wxUpdateUIEvent &event) override
void OnDrillShapeSelected(wxCommandEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) 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:97
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowQuasiModal()
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...
bool IsType(FRAME_T aType) const
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
GAL_DISPLAY_OPTIONS_IMPL & GetGalDisplayOptions()
Return a reference to the gal rendering options used by GAL for rendering.
GAL_TYPE GetBackend() const
Return the type of backend currently used by GAL canvas.
void StopDrawing()
Prevent the GAL canvas from further drawing until it is recreated or StartDrawing() is called.
KIGFX::VIEW_CONTROLS * GetViewControls() const
Return a pointer to the #VIEW_CONTROLS instance used in the panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
void StartDrawing()
Begin drawing if it was stopped previously.
void SetStealsFocus(bool aStealsFocus)
Set whether focus is taken on certain events (mouseover, keys, etc).
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:125
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
bool IsFlipped() const
Definition: footprint.h:370
void ListSet(const wxString &aList)
Add a list of items.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
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.
void SetPosition(const VECTOR2I &aPosition) override
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Contains methods for drawing PCB-specific items.
Definition: pcb_painter.h:164
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
Definition: pcb_painter.h:169
PCB specific render settings.
Definition: pcb_painter.h:77
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,...
void ApplySettings(const VC_SETTINGS &aSettings)
Load new settings from program common settings.
const VC_SETTINGS & GetSettings() const
Apply VIEW_CONTROLS settings from an object.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition: view.cpp:524
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:315
void SetBoundary(const BOX2D &aBoundary)
Set limits for view area.
Definition: view.h:281
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:1636
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
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:827
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:573
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:823
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:375
void SetNetInfo(const NETINFO_LIST *aNetInfoList)
void SetBoard(BOARD *aBoard)
int GetSelectedNetcode()
void SetSelectedNetcode(int aNetcode)
Tool relating to pads and pad settings.
Definition: pad_tool.h:37
void SetLastPadNumber(const wxString &aPadNumber)
Definition: pad_tool.h:69
wxString GetLastPadNumber() const
Definition: pad_tool.h:68
Definition: pad.h:59
bool IsAperturePad() const
Definition: pad.h:381
void SetAttribute(PAD_ATTRIB aAttribute)
Definition: pad.cpp:646
void SetLayerSet(LSET aLayers) override
Definition: pad.h:370
PAD_PROP GetProperty() const
Definition: pad.h:377
bool GetRemoveUnconnected() const
Definition: pad.h:597
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: pad.h:356
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:371
int GetSizeX() const
Definition: pad.h:246
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition: pad.cpp:637
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: pad.h:398
const VECTOR2I & GetDrillSize() const
Definition: pad.h:254
PAD_ATTRIB GetAttribute() const
Definition: pad.h:374
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:190
void SetRemoveUnconnected(bool aSet)
Set the unconnected removal property.
Definition: pad.h:596
void SetThermalGap(int aGap)
Definition: pad.h:541
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition: pad.h:528
const wxString & GetNumber() const
Definition: pad.h:131
void MergePrimitivesAsPolygon(SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
int GetRoundRectCornerRadius() const
Definition: pad.cpp:324
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: pad.h:399
void DeletePrimitivesList()
Clear the basic shapes list.
void SetDrillShape(PAD_DRILL_SHAPE_T aShape)
Definition: pad.h:355
VECTOR2I GetPosition() const override
Definition: pad.h:198
void SetProperty(PAD_PROP aProperty)
Definition: pad.cpp:657
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:301
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:529
void SetOffset(const VECTOR2I &aOffset)
Definition: pad.h:260
void SetChamferRectRatio(double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition: pad.cpp:347
const VECTOR2I & GetOffset() const
Definition: pad.h:261
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pad.cpp:211
void SetRoundRectCornerRadius(double aRadius)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:330
int GetDrillSizeX() const
Definition: pad.h:256
void SetKeepTopBottom(bool aSet)
Set whether we keep the top and bottom connections even if they are not connected.
Definition: pad.h:602
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition: pad.cpp:1596
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition: pad.h:130
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: pad.h:393
bool GetKeepTopBottom() const
Definition: pad.h:603
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:401
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: pad.h:208
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.h:389
void SetDelta(const VECTOR2I &aSize)
Definition: pad.h:250
bool IsOnCopperLayer() const override
Definition: pad.cpp:772
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:192
const VECTOR2I & GetDelta() const
Definition: pad.h:251
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition: pad.cpp:204
void SetDrillSize(const VECTOR2I &aSize)
Definition: pad.h:253
PAD_SHAPE GetShape() const
Definition: pad.h:190
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:342
EDA_ANGLE GetFPRelativeOrientation()
Definition: pad.cpp:683
void Flip(const VECTOR2I &VECTOR2I, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: pad.cpp:692
static LSET ApertureMask()
layer set for an aperture pad
Definition: pad.cpp:218
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pad.cpp:1457
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:197
std::optional< int > GetLocalSolderPasteMargin() const
Definition: pad.h:395
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pad.h:392
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: pad.h:396
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:181
int GetSizeY() const
Definition: pad.h:248
int GetThermalSpokeWidth() const
Definition: pad.h:519
void SetFPRelativeOrientation(const EDA_ANGLE &aAngle)
Definition: pad.cpp:674
void SetCustomShapeInZoneOpt(CUST_PAD_SHAPE_IN_ZONE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones.
Definition: pad.h:218
void SetRoundRectRadiusRatio(double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:339
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:229
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition: pad.cpp:665
int GetChamferPositions() const
Definition: pad.h:582
void ReplacePrimitives(const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Clear the current custom shape primitives list and import a new list.
void SetLocalClearance(std::optional< int > aClearance)
Definition: pad.h:390
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: pad.h:402
void SetThermalSpokeWidth(int aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: pad.h:518
void SetSize(const VECTOR2I &aSize)
Definition: pad.h:243
double GetRoundRectRadiusRatio() const
Definition: pad.h:563
int GetThermalGap() const
Definition: pad.h:542
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:401
const VECTOR2I & GetSize() const
Definition: pad.h:244
void SetChamferPositions(int aPositions)
Has meaning only for chamfered rectangular pads.
Definition: pad.h:581
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:203
double GetChamferRectRatio() const
Definition: pad.h:572
void SetPadToDieLength(int aLength)
Definition: pad.h:386
int GetPadToDieLength() const
Definition: pad.h:387
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
void ShowPadPropertiesDialog(PAD *aPad)
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
virtual COLOR_SETTINGS * GetColorSettings(bool aForceRefresh=false) const override
Helper to retrieve the current color settings.
void UpdateColors()
Update the color settings in the painter and GAL.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
int OutlineCount() const
Return the number of outlines in the set.
int m_CurveSegCount
number of segments to build the curved sides of a teardrop area must be > 2.
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.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
int GetIntValue()
Definition: unit_binder.h:127
virtual void ChangeDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
virtual long long int GetValue()
Return the current value in Internal Units.
void Enable(bool aEnable)
Enable/disable the label, widget and units label.
virtual void SetPrecision(int aLength)
Normally not needed, but can be used to set the precision when using internal units that are floats (...
virtual void SetUnits(EDA_UNITS aUnits)
Normally not needed (as the UNIT_BINDER inherits from the parent frame), but can be used to set to DE...
virtual EDA_ANGLE GetAngleValue()
virtual void SetNegativeZero()
Definition: unit_binder.h:71
virtual double GetDoubleValue()
Return the current value in Internal Units.
virtual void SetAngleValue(const EDA_ANGLE &aValue)
virtual void ChangeAngleValue(const EDA_ANGLE &aValue)
virtual void SetDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED)
Validate the control against the given range, informing the user of any errors found.
virtual void ChangeValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void Show(bool aShow, bool aResize=false)
Show/hide the label, widget and units label.
void SetCoordType(ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType)
Set the current origin transform mode.
Definition: unit_binder.h:188
bool IsNull() const
Return true if the control holds no value (ie: empty string, not 0).
This file is part of the common library.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
#define APERTURE_DLG_TYPE
#define CONN_DLG_TYPE
static PAD_ATTRIB code_type[]
#define SELECTED_ITEMS_LAYER
static PAD_SHAPE code_shape[]
static bool PadHasMeaningfulRoundingRadius(const PAD &aPad)
Returns true if the pad's rounding ratio is valid (i.e.
#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
static double GetDefaultIpcRoundingRatio(const PAD &aPad)
Get a sensible default for a rounded rectangle pad's rounding ratio.
#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.
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:437
static constexpr EDA_ANGLE ANGLE_45
Definition: eda_angle.h:436
#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:42
@ ERROR_INSIDE
@ LAYER_GRID
Definition: layer_ids.h:208
@ B_Adhes
Definition: layer_ids.h:98
@ Dwgs_User
Definition: layer_ids.h:110
@ F_Paste
Definition: layer_ids.h:102
@ F_Adhes
Definition: layer_ids.h:99
@ B_Mask
Definition: layer_ids.h:107
@ B_Cu
Definition: layer_ids.h:96
@ Eco1_User
Definition: layer_ids.h:112
@ F_Mask
Definition: layer_ids.h:108
@ B_Paste
Definition: layer_ids.h:101
@ F_SilkS
Definition: layer_ids.h:105
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:113
@ B_SilkS
Definition: layer_ids.h:104
@ F_Cu
Definition: layer_ids.h:65
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:151
@ CUST_PAD_SHAPE_IN_ZONE_OUTLINE
Definition: pad.h:45
@ CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL
Definition: pad.h:46
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: pad_shapes.h:81
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
@ PAD_DRILL_SHAPE_CIRCLE
Definition: pad_shapes.h:70
@ PAD_DRILL_SHAPE_OBLONG
Definition: pad_shapes.h:71
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: pad_shapes.h:35
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition: pad_shapes.h:97
const double IU_PER_MM
Definition: base_units.h:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
constexpr int delta
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588