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 VECTOR2I absPos;
537
538 if( m_currentPad )
539 {
540 absPos = m_currentPad->GetPosition();
541
542 if( FOOTPRINT* footprint = m_currentPad->GetParentFootprint() )
543 {
545
546 if( footprint->IsFlipped() )
547 {
548 // flip pad (up/down) around its position
550 relPos.y = - relPos.y;
551 }
552
553 m_previewPad->SetPosition( relPos );
555
556 // Display parent footprint info
557 msg.Printf( _("Footprint %s (%s), %s, rotated %g deg"),
558 footprint->Reference().GetShownText( false ),
559 footprint->Value().GetShownText( false ),
560 footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
561 footprint->GetOrientation().AsDegrees() );
562
563 m_FlippedWarningSizer->Show( footprint->IsFlipped() );
564 m_parentInfo->SetLabel( msg );
565 }
566
567 m_padNumCtrl->SetValue( m_previewPad->GetNumber() );
568 }
569 else
570 {
572 m_padNumCtrl->SetValue( padTool->GetLastPadNumber() );
573
574 if( m_isFpEditor )
575 {
576 switch( m_board->Footprints()[0]->GetAttributes() )
577 {
578 case FOOTPRINT_ATTR_T::FP_THROUGH_HOLE:
579 m_previewPad->SetAttribute( PAD_ATTRIB::PTH );
580
581 if( m_previewPad->GetDrillSizeX() == 0 )
583
584 break;
585
586 case FOOTPRINT_ATTR_T::FP_SMD:
587 m_previewPad->SetAttribute( PAD_ATTRIB::SMD );
588 break;
589 }
590 }
591 }
592
594
596
597 // Display current pad parameters units:
598 m_posX.ChangeValue( absPos.x );
599 m_posY.ChangeValue( absPos.y );
600
603
606
607 m_offsetShapeOpt->SetValue( m_previewPad->GetOffset() != VECTOR2I() );
610
611 if( m_previewPad->GetDelta().x )
612 {
614 m_trapAxisCtrl->SetSelection( 0 );
615 }
616 else
617 {
619 m_trapAxisCtrl->SetSelection( 1 );
620 }
621
622 // Store the initial thermal spoke angle to restore it, because some initializations
623 // can change this value (mainly after m_PadShapeSelector initializations)
624 EDA_ANGLE spokeInitialAngle = m_previewPad->GetThermalSpokeAngle();
625
626 m_padToDieOpt->SetValue( m_previewPad->GetPadToDieLength() != 0 );
628
629 if( m_previewPad->GetLocalClearance().has_value() )
631 else
632 m_clearance.ChangeValue( wxEmptyString );
633
634 if( m_previewPad->GetLocalSolderMaskMargin().has_value() )
636 else
637 m_maskMargin.ChangeValue( wxEmptyString );
638
639 if( m_previewPad->GetLocalSolderPasteMargin().has_value() )
641 else
642 m_pasteMargin.ChangeValue( wxEmptyString );
643
646 else
647 m_pasteMarginRatio.ChangeValue( wxEmptyString );
648
653
662
664
665 if( m_curvedEdges->GetValue() )
667 else
668 m_curvePointsCtrl->SetValue( 5 );
669
671 {
672 default:
673 case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
674 case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
675 case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
676 case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
677 }
678
680 m_ZoneCustomPadShape->SetSelection( 1 );
681 else
682 m_ZoneCustomPadShape->SetSelection( 0 );
683
684 switch( m_previewPad->GetShape() )
685 {
686 default:
687 case PAD_SHAPE::CIRCLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
688 case PAD_SHAPE::OVAL: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_OVAL ); break;
689 case PAD_SHAPE::RECTANGLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_RECT ); break;
690 case PAD_SHAPE::TRAPEZOID: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_TRAPEZOID ); break;
691 case PAD_SHAPE::ROUNDRECT: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_ROUNDRECT ); break;
692
693 case PAD_SHAPE::CHAMFERED_RECT:
696 else
698 break;
699
700 case PAD_SHAPE::CUSTOM:
701 if( m_previewPad->GetAnchorPadShape() == PAD_SHAPE::RECTANGLE )
703 else
705 break;
706 }
707
716
718
719 // Type of pad selection
720 bool aperture =
721 m_previewPad->GetAttribute() == PAD_ATTRIB::SMD && m_previewPad->IsAperturePad();
722
723 if( aperture )
724 {
725 m_padType->SetSelection( APERTURE_DLG_TYPE );
726 }
727 else
728 {
729 switch( m_previewPad->GetAttribute() )
730 {
731 case PAD_ATTRIB::PTH: m_padType->SetSelection( PTH_DLG_TYPE ); break;
732 case PAD_ATTRIB::SMD: m_padType->SetSelection( SMD_DLG_TYPE ); break;
733 case PAD_ATTRIB::CONN: m_padType->SetSelection( CONN_DLG_TYPE ); break;
734 case PAD_ATTRIB::NPTH: m_padType->SetSelection( NPTH_DLG_TYPE ); break;
735 }
736 }
737
738 switch( m_previewPad->GetProperty() )
739 {
740 case PAD_PROP::NONE: m_choiceFabProperty->SetSelection( 0 ); break;
741 case PAD_PROP::BGA: m_choiceFabProperty->SetSelection( 1 ); break;
742 case PAD_PROP::FIDUCIAL_LOCAL: m_choiceFabProperty->SetSelection( 2 ); break;
743 case PAD_PROP::FIDUCIAL_GLBL: m_choiceFabProperty->SetSelection( 3 ); break;
744 case PAD_PROP::TESTPOINT: m_choiceFabProperty->SetSelection( 4 ); break;
745 case PAD_PROP::HEATSINK: m_choiceFabProperty->SetSelection( 5 ); break;
746 case PAD_PROP::CASTELLATED: m_choiceFabProperty->SetSelection( 6 ); break;
747 case PAD_PROP::MECHANICAL: m_choiceFabProperty->SetSelection( 7 ); break;
748 }
749
750 // Ensure the pad property is compatible with the pad type
751 if( m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
752 {
753 m_choiceFabProperty->SetSelection( 0 );
754 m_choiceFabProperty->Enable( false );
755 }
756
757 if( m_previewPad->GetDrillShape() != PAD_DRILL_SHAPE::OBLONG )
758 m_holeShapeCtrl->SetSelection( 0 );
759 else
760 m_holeShapeCtrl->SetSelection( 1 );
761
764
765 // Update some dialog widgets state (Enable/disable options):
766 wxCommandEvent cmd_event;
767 OnPadShapeSelection( cmd_event );
768 OnOffsetCheckbox( cmd_event );
769
770 // Restore thermal spoke angle to its initial value, because it can be modified
771 // by the call to OnPadShapeSelection()
772 m_previewPad->SetThermalSpokeAngle( spokeInitialAngle );
774}
775
776
777void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
778{
779 redraw();
780 event.Skip();
781}
782
783
784void DIALOG_PAD_PROPERTIES::onChangePadMode( wxCommandEvent& event )
785{
787
789
790 // fix the pad render mode (filled/not filled)
791 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
792
793 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
794 settings->SetHighContrast( false );
795 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
796
797 redraw();
798}
799
800
802{
803 switch( m_PadShapeSelector->GetSelection() )
804 {
808 m_shapePropsBook->SetSelection( 0 );
809 break;
810
812 m_shapePropsBook->SetSelection( 1 );
813 break;
814
816 {
817 m_shapePropsBook->SetSelection( 2 );
818
819 // Reasonable defaults
822
823 break;
824 }
825
827 m_shapePropsBook->SetSelection( 3 );
828
829 // Reasonable default
830 if( m_previewPad->GetChamferRectRatio() == 0.0 )
832
833 // Ensure the displayed value is up to date:
835
836 // A reasonable default is one corner chamfered (usual for some SMD pads).
837 if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
838 && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
839 {
840 m_cbTopLeft->SetValue( true );
841 m_cbTopRight->SetValue( false );
842 m_cbBottomLeft->SetValue( false );
843 m_cbBottomRight->SetValue( false );
844 }
845
846 break;
847
849 m_shapePropsBook->SetSelection( 4 );
850
851 // Reasonable defaults
853 && m_previewPad->GetChamferRectRatio() == 0.0 )
854 {
858 }
859
860 // Ensure the displayed values are up to date:
863 break;
864
865 case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE::CUSTOM, circular anchor
866 case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE::CUSTOM, rect anchor
867 m_shapePropsBook->SetSelection( 0 );
868 break;
869 }
870
871 // Note: must do this before enabling/disabling m_sizeY as we're using that as a flag to see
872 // what the last shape was.
873 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE )
874 {
875 if( m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_90 )
877 }
878 else
879 {
880 if( !m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_45 )
882 }
883
884 // Readjust props book size
885 wxSize size = m_shapePropsBook->GetSize();
886 size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
887 m_shapePropsBook->SetMaxSize( size );
888
891
892 m_offsetShapeOpt->Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE );
893
894 if( !m_offsetShapeOpt->IsEnabled() )
895 m_offsetShapeOpt->SetValue( false );
896
897 // Show/hide controls depending on m_offsetShapeOpt being enabled
898 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
899 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
900
903
904 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
905 m_notebook->GetPage( i )->Layout();
906
907 // Resize the dialog if its height is too small to show all widgets:
908 if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
909 m_MainSizer->SetSizeHints( this );
910
912 redraw();
913}
914
915
917{
920 redraw();
921}
922
923
924void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
925{
927 redraw();
928}
929
930
932{
933 m_rbCopperLayersSel->Clear();
934
935 switch( m_padType->GetSelection() )
936 {
937 case PTH_DLG_TYPE:
938 m_rbCopperLayersSel->Append( _( "All copper layers" ) );
939 m_rbCopperLayersSel->Append( wxString::Format( _( "%s, %s and connected layers" ),
941 m_board->GetLayerName( B_Cu ) ) );
942 m_rbCopperLayersSel->Append( _( "Connected layers only" ) );
943 m_rbCopperLayersSel->Append( _( "None" ) );
944 break;
945
946 case NPTH_DLG_TYPE:
947 m_rbCopperLayersSel->Append( wxString::Format( _( "%s and %s" ),
949 m_board->GetLayerName( B_Cu ) ) );
952 m_rbCopperLayersSel->Append( _( "None" ) );
953 break;
954
955 case SMD_DLG_TYPE:
956 case CONN_DLG_TYPE:
959 break;
960
962 m_rbCopperLayersSel->Append( _( "None" ) );
963 break;
964 }
965}
966
967
968void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
969{
970 bool hasHole = true;
971 bool hasConnection = true;
972 bool hasProperty = true;
973
974 switch( m_padType->GetSelection() )
975 {
976 case PTH_DLG_TYPE: hasHole = true; hasConnection = true; hasProperty = true; break;
977 case SMD_DLG_TYPE: hasHole = false; hasConnection = true; hasProperty = true; break;
978 case CONN_DLG_TYPE: hasHole = false; hasConnection = true; hasProperty = true; break;
979 case NPTH_DLG_TYPE: hasHole = true; hasConnection = false; hasProperty = false; break;
980 case APERTURE_DLG_TYPE: hasHole = false; hasConnection = false; hasProperty = true; break;
981 }
982
983 // Update Layers dropdown list and selects the "best" layer set for the new pad type:
986
987 m_gbSizerHole->Show( hasHole );
988 m_staticline6->Show( hasHole );
989
990 if( !hasHole )
991 {
992 m_holeX.ChangeValue( 0 );
993 m_holeY.ChangeValue( 0 );
994 }
995 else if( m_holeX.GetValue() == 0 )
996 {
997 if( m_currentPad )
998 {
1001 }
1002 else
1003 {
1005 }
1006 }
1007
1008 if( !hasConnection )
1009 {
1010 m_padNumCtrl->ChangeValue( wxEmptyString );
1012 m_padToDieOpt->SetValue( false );
1013 }
1014 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1015 {
1016 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1018 }
1019
1020 if( !hasProperty )
1021 m_choiceFabProperty->SetSelection( 0 );
1022
1023 m_choiceFabProperty->Enable( hasProperty );
1024
1026
1027 // Layout adjustment is needed if the hole details got shown/hidden
1028 m_LeftBoxSizer->Layout();
1029 redraw();
1030}
1031
1032
1033void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1034{
1035 bool hasHole = true;
1036 bool hasConnection = true;
1037
1038 switch( m_padType->GetSelection() )
1039 {
1040 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1041 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1042 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1043 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1044 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1045 }
1046
1047 // Enable/disable hole controls
1048 m_holeShapeLabel->Enable( hasHole );
1049 m_holeShapeCtrl->Enable( hasHole );
1050 m_holeX.Enable( hasHole );
1051 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1052
1053 // Enable/disable number and net
1054 m_padNumLabel->Enable( hasConnection );
1055 m_padNumCtrl->Enable( hasConnection );
1056
1057 if( m_padNetLabel->IsShown() )
1058 {
1059 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1060 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1061 }
1062
1063 // Enable/disable pad length-to-die
1064 m_padToDieOpt->Enable( hasConnection );
1065
1066 if( !m_padToDieOpt->IsEnabled() )
1067 m_padToDieOpt->SetValue( false );
1068
1069 // We can show/hide this here because it doesn't require the layout to be refreshed.
1070 // All the others have to be done in their event handlers because doing a layout here
1071 // causes infinite looping on MSW.
1072 m_padToDie.Show( m_padToDieOpt->GetValue() );
1073
1074 // Enable/disable Copper Layers control
1075 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1076
1078
1079 switch( m_padType->GetSelection() )
1080 {
1081 case PTH_DLG_TYPE:
1082 if( !cu_set.any() )
1083 m_stackupImagesBook->SetSelection( 3 );
1084 else if( !m_previewPad->GetRemoveUnconnected() )
1085 m_stackupImagesBook->SetSelection( 0 );
1086 else if( m_previewPad->GetKeepTopBottom() )
1087 m_stackupImagesBook->SetSelection( 1 );
1088 else
1089 m_stackupImagesBook->SetSelection( 2 );
1090
1091 break;
1092
1093 case NPTH_DLG_TYPE:
1094 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1095 m_stackupImagesBook->SetSelection( 4 );
1096 else if( cu_set.test( F_Cu ) )
1097 m_stackupImagesBook->SetSelection( 5 );
1098 else if( cu_set.test( B_Cu ) )
1099 m_stackupImagesBook->SetSelection( 6 );
1100 else
1101 m_stackupImagesBook->SetSelection( 7 );
1102
1103 break;
1104
1105 case SMD_DLG_TYPE:
1106 case CONN_DLG_TYPE:
1107 case APERTURE_DLG_TYPE:
1108 m_stackupImagesBook->ChangeSelection( 3 );
1109 break;
1110 }
1111
1113}
1114
1115
1117{
1118 event.Enable( !m_board->LegacyTeardrops() );
1119}
1120
1121
1123{
1124 event.Enable( !m_board->LegacyTeardrops() && m_curvedEdges->GetValue() );
1125}
1126
1127
1129{
1130 bool isOnCopperLayer = ( m_previewPad->GetLayerSet() & LSET::AllCuMask() ).any();
1131 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1132}
1133
1134
1135void DIALOG_PAD_PROPERTIES::updatePadLayersList( LSET layer_mask, bool remove_unconnected,
1136 bool keep_top_bottom )
1137{
1139
1140 switch( m_padType->GetSelection() )
1141 {
1142 case PTH_DLG_TYPE:
1143 if( !layer_mask.any() )
1144 layer_mask = PAD::PTHMask();
1145
1146 if( !( layer_mask & LSET::AllCuMask() ).any() )
1147 m_rbCopperLayersSel->SetSelection( 3 );
1148 else if( !remove_unconnected )
1149 m_rbCopperLayersSel->SetSelection( 0 );
1150 else if( keep_top_bottom )
1151 m_rbCopperLayersSel->SetSelection( 1 );
1152 else
1153 m_rbCopperLayersSel->SetSelection( 2 );
1154
1155 break;
1156
1157 case SMD_DLG_TYPE:
1158 if( !layer_mask.any() )
1159 layer_mask = PAD::SMDMask();
1160
1161 if( layer_mask.test( F_Cu ) )
1162 m_rbCopperLayersSel->SetSelection( 0 );
1163 else
1164 m_rbCopperLayersSel->SetSelection( 1 );
1165
1166 break;
1167
1168 case CONN_DLG_TYPE:
1169 if( !layer_mask.any() )
1170 layer_mask = PAD::ConnSMDMask();
1171
1172 if( layer_mask.test( F_Cu ) )
1173 m_rbCopperLayersSel->SetSelection( 0 );
1174 else
1175 m_rbCopperLayersSel->SetSelection( 1 );
1176
1177 break;
1178
1179 case NPTH_DLG_TYPE:
1180 if( !layer_mask.any() )
1181 layer_mask = PAD::UnplatedHoleMask();
1182
1183 if( layer_mask.test( F_Cu ) && layer_mask.test( B_Cu ) )
1184 m_rbCopperLayersSel->SetSelection( 0 );
1185 else if( layer_mask.test( F_Cu ) )
1186 m_rbCopperLayersSel->SetSelection( 1 );
1187 else if( layer_mask.test( B_Cu ) )
1188 m_rbCopperLayersSel->SetSelection( 2 );
1189 else
1190 m_rbCopperLayersSel->SetSelection( 3 );
1191
1192 break;
1193
1194 case APERTURE_DLG_TYPE:
1195 if( !layer_mask.any() )
1196 layer_mask = PAD::ApertureMask();
1197
1198 m_rbCopperLayersSel->SetSelection( 0 );
1199 break;
1200 }
1201
1202 m_layerFrontAdhesive->SetValue( layer_mask[F_Adhes] );
1203 m_layerBackAdhesive->SetValue( layer_mask[B_Adhes] );
1204
1205 m_layerFrontPaste->SetValue( layer_mask[F_Paste] );
1206 m_layerBackPaste->SetValue( layer_mask[B_Paste] );
1207
1208 m_layerFrontSilk->SetValue( layer_mask[F_SilkS] );
1209 m_layerBackSilk->SetValue( layer_mask[B_SilkS] );
1210
1211 m_layerFrontMask->SetValue( layer_mask[F_Mask] );
1212 m_layerBackMask->SetValue( layer_mask[B_Mask] );
1213
1214 m_layerECO1->SetValue( layer_mask[Eco1_User] );
1215 m_layerECO2->SetValue( layer_mask[Eco2_User] );
1216
1217 m_layerUserDwgs->SetValue( layer_mask[Dwgs_User] );
1218}
1219
1220
1222{
1223 bool retVal = DIALOG_SHIM::Show( aShow );
1224
1225 if( aShow )
1226 {
1227 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1228 // wxWidgets needs to have these set when the panel is visible for some reason.
1229 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1230 m_stackupImage0->SetBitmap( KiBitmapBundle( BITMAPS::pads_reset_unused ) );
1231 m_stackupImage1->SetBitmap( KiBitmapBundle( BITMAPS::pads_remove_unused_keep_bottom ) );
1232 m_stackupImage2->SetBitmap( KiBitmapBundle( BITMAPS::pads_remove_unused ) );
1233 m_stackupImage4->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth_top_bottom ) );
1234 m_stackupImage5->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth_top ) );
1235 m_stackupImage6->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth_bottom ) );
1236 m_stackupImage7->SetBitmap( KiBitmapBundle( BITMAPS::pads_npth ) );
1237
1238 Layout();
1239 }
1240
1241 return retVal;
1242}
1243
1244
1245void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1246{
1248 redraw();
1249}
1250
1251
1252void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1253{
1255 redraw();
1256}
1257
1258
1260{
1261 bool error = !transferDataToPad( m_previewPad );
1262
1263 wxArrayString error_msgs;
1264 wxArrayString warning_msgs;
1265 VECTOR2I pad_size = m_previewPad->GetSize();
1266 VECTOR2I drill_size = m_previewPad->GetDrillSize();
1267
1268 if( m_previewPad->GetShape() == PAD_SHAPE::CUSTOM )
1269 {
1270 pad_size = m_previewPad->GetBoundingBox().GetSize();
1271 }
1272 else if( m_previewPad->GetShape() == PAD_SHAPE::CIRCLE )
1273 {
1274 if( pad_size.x <= 0 )
1275 error_msgs.Add( _( "Error: Pad must have a positive size." ) );
1276 }
1277 else
1278 {
1279 if( pad_size.x <= 0 || pad_size.y <= 0 )
1280 error_msgs.Add( _( "Error: Pad must have a positive size." ) );
1281 }
1282
1283 // Test hole against pad shape
1285 {
1286 int maxError = m_board->GetDesignSettings().m_MaxError;
1287 SHAPE_POLY_SET padOutline;
1288
1289 m_previewPad->TransformShapeToPolygon( padOutline, UNDEFINED_LAYER, 0, maxError,
1290 ERROR_INSIDE );
1291
1292 if( !padOutline.Collide( m_previewPad->GetPosition() ) )
1293 {
1294 warning_msgs.Add( _( "Warning: Pad hole not inside pad shape." ) );
1295 }
1296 else if( m_previewPad->GetAttribute() == PAD_ATTRIB::PTH )
1297 {
1298 std::shared_ptr<SHAPE_SEGMENT> slot = m_previewPad->GetEffectiveHoleShape();
1299 SHAPE_POLY_SET slotOutline;
1300
1301 TransformOvalToPolygon( slotOutline, slot->GetSeg().A, slot->GetSeg().B,
1302 slot->GetWidth(), maxError, ERROR_INSIDE );
1303
1304 padOutline.BooleanSubtract( slotOutline, SHAPE_POLY_SET::PM_FAST );
1305
1306 if( padOutline.IsEmpty() )
1307 warning_msgs.Add( _( "Warning: Pad hole will leave no copper." ) );
1308 }
1309 }
1310
1311 if( m_previewPad->GetLocalClearance().value_or( 0 ) < 0 )
1312 warning_msgs.Add( _( "Warning: Negative local clearance values will have no effect." ) );
1313
1314 // Some pads need a negative solder mask clearance (mainly for BGA with small pads)
1315 // However the negative solder mask clearance must not create negative mask size
1316 // Therefore test for minimal acceptable negative value
1317 std::optional<int> solderMaskMargin = m_previewPad->GetLocalSolderMaskMargin();
1318
1319 if( solderMaskMargin.has_value() && solderMaskMargin.value() < 0 )
1320 {
1321 int absMargin = abs( solderMaskMargin.value() );
1322
1323 if( m_previewPad->GetShape() == PAD_SHAPE::CUSTOM )
1324 {
1325 for( const std::shared_ptr<PCB_SHAPE>& shape : m_previewPad->GetPrimitives() )
1326 {
1327 BOX2I shapeBBox = shape->GetBoundingBox();
1328
1329 if( absMargin > shapeBBox.GetWidth() || absMargin > shapeBBox.GetHeight() )
1330 {
1331 warning_msgs.Add( _( "Warning: Negative solder mask clearances larger than "
1332 "some shape primitives. Results may be surprising." ) );
1333
1334 break;
1335 }
1336 }
1337 }
1338 else if( absMargin > pad_size.x || absMargin > pad_size.y )
1339 {
1340 warning_msgs.Add( _( "Warning: Negative solder mask clearance larger than pad. No "
1341 "solder mask will be generated." ) );
1342 }
1343 }
1344
1345 // Some pads need a positive solder paste clearance (mainly for BGA with small pads)
1346 // However, a positive value can create issues if the resulting shape is too big.
1347 // (like a solder paste creating a solder paste area on a neighbor pad or on the solder mask)
1348 // So we could ask for user to confirm the choice
1349 // For now we just check for disappearing paste
1350 wxSize paste_size;
1351 int paste_margin = m_previewPad->GetLocalSolderPasteMargin().value_or( 0 );
1352 double paste_ratio = m_previewPad->GetLocalSolderPasteMarginRatio().value_or( 0 );
1353
1354 paste_size.x = pad_size.x + paste_margin + KiROUND( pad_size.x * paste_ratio );
1355 paste_size.y = pad_size.y + paste_margin + KiROUND( pad_size.y * paste_ratio );
1356
1357 if( paste_size.x <= 0 || paste_size.y <= 0 )
1358 {
1359 warning_msgs.Add( _( "Warning: Negative solder paste margins larger than pad. No solder "
1360 "paste mask will be generated." ) );
1361 }
1362
1363 LSET padlayers_mask = m_previewPad->GetLayerSet();
1364
1365 if( padlayers_mask == 0 )
1366 error_msgs.Add( _( "Error: pad has no layer." ) );
1367
1368 if( !padlayers_mask[F_Cu] && !padlayers_mask[B_Cu] )
1369 {
1370 if( ( drill_size.x || drill_size.y ) && m_previewPad->GetAttribute() != PAD_ATTRIB::NPTH )
1371 {
1372 warning_msgs.Add( _( "Warning: Plated through holes should normally have a copper pad "
1373 "on at least one layer." ) );
1374 }
1375 }
1376
1377 if( error )
1378 error_msgs.Add( _( "Error: Trapazoid delta is too large." ) );
1379
1380 switch( m_previewPad->GetAttribute() )
1381 {
1382 case PAD_ATTRIB::NPTH: // Not plated, but through hole, a hole is expected
1383 case PAD_ATTRIB::PTH: // Pad through hole, a hole is also expected
1384 if( drill_size.x <= 0
1385 || ( drill_size.y <= 0 && m_previewPad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG ) )
1386 {
1387 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1388 }
1389 break;
1390
1391 case PAD_ATTRIB::CONN: // Connector pads are smd pads, just they do not have solder paste.
1392 if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
1393 {
1394 warning_msgs.Add( _( "Warning: Connector pads normally have no solder paste. Use a "
1395 "SMD pad instead." ) );
1396 }
1398
1399 case PAD_ATTRIB::SMD: // SMD and Connector pads (One external copper layer only)
1400 {
1401 if( drill_size.x > 0 || drill_size.y > 0 )
1402 {
1403 error_msgs.Add( _( "Error: SMD pad has a hole." ) );
1404 }
1405
1406 LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
1407
1408 if( ( padlayers_mask[F_Cu] && padlayers_mask[B_Cu] ) || innerlayers_mask.count() != 0 )
1409 warning_msgs.Add( _( "Warning: SMD pad has no outer layers." ) );
1410 }
1411 break;
1412 }
1413
1414 if( ( m_previewPad->GetProperty() == PAD_PROP::FIDUCIAL_GLBL || m_previewPad->GetProperty() == PAD_PROP::FIDUCIAL_LOCAL )
1415 && m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
1416 {
1417 warning_msgs.Add( _( "Warning: Fiducial property makes no sense on NPTH pads." ) );
1418 }
1419
1420 if( m_previewPad->GetProperty() == PAD_PROP::TESTPOINT
1421 && m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
1422 {
1423 warning_msgs.Add( _( "Warning: Testpoint property makes no sense on NPTH pads." ) );
1424 }
1425
1426 if( m_previewPad->GetProperty() == PAD_PROP::HEATSINK
1427 && m_previewPad->GetAttribute() == PAD_ATTRIB::NPTH )
1428 {
1429 warning_msgs.Add( _( "Warning: Heatsink property makes no sense of NPTH pads." ) );
1430 }
1431
1432 if( m_previewPad->GetProperty() == PAD_PROP::CASTELLATED
1433 && m_previewPad->GetAttribute() != PAD_ATTRIB::PTH )
1434 {
1435 warning_msgs.Add( _( "Warning: Castellated property is for PTH pads." ) );
1436 }
1437
1438 if( m_previewPad->GetProperty() == PAD_PROP::BGA
1439 && m_previewPad->GetAttribute() != PAD_ATTRIB::SMD )
1440 {
1441 warning_msgs.Add( _( "Warning: BGA property is for SMD pads." ) );
1442 }
1443
1444 if( m_previewPad->GetProperty() == PAD_PROP::MECHANICAL
1445 && m_previewPad->GetAttribute() != PAD_ATTRIB::PTH )
1446 {
1447 warning_msgs.Add( _( "Warning: Mechanical property is for PTH pads." ) );
1448 }
1449
1450 if( m_previewPad->GetShape() == PAD_SHAPE::ROUNDRECT
1451 || m_previewPad->GetShape() == PAD_SHAPE::CHAMFERED_RECT )
1452 {
1454
1455 if( m_cornerRatio.GetDoubleValue() < 0.0 )
1456 error_msgs.Add( _( "Error: Negative corner size." ) );
1457 else if( m_cornerRatio.GetDoubleValue() > 50.0 )
1458 warning_msgs.Add( _( "Warning: Corner size will make pad circular." ) );
1459 }
1460
1461 // PADSTACKS TODO: this will need to check each layer in the pad...
1462 if( m_previewPad->GetShape() == PAD_SHAPE::CUSTOM )
1463 {
1464 SHAPE_POLY_SET mergedPolygon;
1465 m_previewPad->MergePrimitivesAsPolygon( &mergedPolygon );
1466
1467 if( mergedPolygon.OutlineCount() > 1 )
1468 error_msgs.Add( _( "Error: Custom pad shape must resolve to a single polygon." ) );
1469 }
1470
1471
1472 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1473 {
1474 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1475 : _( "Pad Properties Warnings" );
1476 HTML_MESSAGE_BOX dlg( this, title );
1477
1478 wxArrayString msgs = error_msgs;
1479
1480 for( const wxString& msg : warning_msgs )
1481 msgs.Add( msg );
1482
1483 dlg.ListSet( msgs );
1484
1485 dlg.ShowModal();
1486 }
1487
1488 return error_msgs.GetCount() == 0;
1489}
1490
1491
1493{
1494 if( !m_canUpdate )
1495 return;
1496
1498 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view->GetPainter() );
1499 KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings();
1500
1502
1503 // The layer used to place primitive items selected when editing custom pad shapes
1504 // we use here a layer never used in a pad:
1505 #define SELECTED_ITEMS_LAYER Dwgs_User
1506
1509
1511
1512 view->Update( m_previewPad );
1513
1514 // delete previous items if highlight list
1515 while( m_highlight.size() )
1516 {
1517 delete m_highlight.back(); // the dtor also removes item from view
1518 m_highlight.pop_back();
1519 }
1520
1521 BOX2I bbox = m_previewPad->ViewBBox();
1522
1523 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1524 {
1525 // The origin always goes in the middle of the canvas; we want offsetting the pad
1526 // shape to move the pad, not the hole
1527 bbox.Move( -m_previewPad->GetPosition() );
1528 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1529 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1530
1531 // Don't blow up the GAL on too-large numbers
1532 if( maxXExtent > INT_MAX / 4 )
1533 maxXExtent = INT_MAX / 4;
1534
1535 if( maxYExtent > INT_MAX / 4 )
1536 maxYExtent = INT_MAX / 4;
1537
1538 BOX2D viewBox( m_previewPad->GetPosition(), {0, 0} );
1539 BOX2D canvasBox( m_previewPad->GetPosition(), {0, 0} );
1540 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1541 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1542
1543 view->SetBoundary( canvasBox );
1544
1545 // Autozoom
1546 view->SetViewport( viewBox );
1547
1550 }
1551}
1552
1553
1555{
1556 if( !wxDialog::TransferDataToWindow() )
1557 return false;
1558
1559 if( !m_panelGeneral->TransferDataToWindow() )
1560 return false;
1561
1562 if( !m_localSettingsPanel->TransferDataToWindow() )
1563 return false;
1564
1565 return true;
1566}
1567
1568
1570{
1571 BOARD_COMMIT commit( m_parent );
1572
1573 if( !wxDialog::TransferDataFromWindow() )
1574 return false;
1575
1576 if( !m_panelGeneral->TransferDataFromWindow() )
1577 return false;
1578
1579 if( !m_localSettingsPanel->TransferDataFromWindow() )
1580 return false;
1581
1582 if( !padValuesOK() )
1583 return false;
1584
1586 return false;
1587
1589 padTool->SetLastPadNumber( m_masterPad->GetNumber() );
1590
1591 // m_masterPad is a pattern: ensure there is no net for this pad:
1593
1594 if( !m_currentPad ) // Set current Pad parameters
1595 return true;
1596
1597 commit.Modify( m_currentPad );
1598
1599 // Update values
1603
1605
1606 VECTOR2I size = m_masterPad->GetDelta();
1607 m_currentPad->SetDelta( size );
1608
1611
1612 VECTOR2I offset = m_masterPad->GetOffset();
1613 m_currentPad->SetOffset( offset );
1614
1616
1617 if( m_masterPad->GetShape() != PAD_SHAPE::CUSTOM )
1619
1622
1625
1627
1628 int padNetcode = NETINFO_LIST::UNCONNECTED;
1629
1630 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1631 if( m_masterPad->GetAttribute() != PAD_ATTRIB::NPTH )
1632 padNetcode = m_padNetSelector->GetSelectedNetcode();
1633
1634 m_currentPad->SetNetCode( padNetcode );
1646
1648
1649 // rounded rect pads with radius ratio = 0 are in fact rect pads.
1650 // So set the right shape (and perhaps issues with a radius = 0)
1651 if( m_currentPad->GetShape() == PAD_SHAPE::ROUNDRECT &&
1653 {
1654 m_currentPad->SetShape( PAD_SHAPE::RECTANGLE );
1655 }
1656
1657 // Set the fabrication property:
1659
1660 // define the way the clearance area is defined in zones
1662
1664 {
1665 // flip pad (up/down) around its position
1667 }
1668
1670
1672
1673 // redraw the area where the pad was
1675
1676 commit.Push( _( "Edit Pad Properties" ) );
1677
1678 return true;
1679}
1680
1681
1683{
1684 PAD_PROP prop = PAD_PROP::NONE;
1685
1686 switch( m_choiceFabProperty->GetSelection() )
1687 {
1688 case 0: prop = PAD_PROP::NONE; break;
1689 case 1: prop = PAD_PROP::BGA; break;
1690 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1691 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1692 case 4: prop = PAD_PROP::TESTPOINT; break;
1693 case 5: prop = PAD_PROP::HEATSINK; break;
1694 case 6: prop = PAD_PROP::CASTELLATED; break;
1695 case 7: prop = PAD_PROP::MECHANICAL; break;
1696 }
1697
1698 return prop;
1699}
1700
1702{
1703 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1704 {
1705 m_holeXLabel->SetLabel( _( "Diameter:" ) );
1706 m_holeY.Show( false );
1707 }
1708 else
1709 {
1710 m_holeXLabel->SetLabel( _( "Hole size X:" ) );
1711 m_holeY.Show( true );
1712 }
1713
1714 m_holeXLabel->GetParent()->Layout();
1715}
1716
1718{
1719 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1721 {
1722 m_sizeXLabel->SetLabel( _( "Diameter:" ) );
1723 m_sizeY.Show( false );
1724 m_bitmapTeardrop->SetBitmap( KiBitmapBundle( BITMAPS::teardrop_sizes ) );
1725 m_minTrackWidthHint->SetLabel( _( "d" ) );
1726 m_stLenPercentHint->SetLabel( _( "d" ) );
1727 m_stWidthPercentHint->SetLabel( _( "d" ) );
1728 }
1729 else
1730 {
1731 m_sizeXLabel->SetLabel( _( "Pad size X:" ) );
1732 m_sizeY.Show( true );
1733 m_bitmapTeardrop->SetBitmap( KiBitmapBundle( BITMAPS::teardrop_rect_sizes ) );
1734 m_minTrackWidthHint->SetLabel( _( "w" ) );
1735 m_stLenPercentHint->SetLabel( _( "w" ) );
1736 m_stWidthPercentHint->SetLabel( _( "w" ) );
1737 }
1738
1739 m_sizeXLabel->GetParent()->Layout();
1740 resetSize();
1741 Layout();
1742 m_MainSizer->Fit( this );
1743}
1744
1745
1747{
1748 if( !Validate() )
1749 return false;
1750
1751 if( !m_panelGeneral->Validate() )
1752 return false;
1753
1754 if( !m_localSettingsPanel->Validate() )
1755 return false;
1756
1757 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1758 return false;
1759
1760 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1761 aPad->SetShape( code_shape[m_PadShapeSelector->GetSelection()] );
1762
1764 aPad->SetAnchorPadShape( PAD_SHAPE::RECTANGLE );
1765 else
1766 aPad->SetAnchorPadShape( PAD_SHAPE::CIRCLE );
1767
1768 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
1770
1771 aPad->GetTeardropParams().m_Enabled = m_cbTeardrops->GetValue();
1778
1779 if( m_curvedEdges->GetValue() )
1781 else
1783
1785
1786 // Read pad clearances values:
1787 if( m_clearance.IsNull() )
1788 aPad->SetLocalClearance( {} );
1789 else
1791
1792 if( m_maskMargin.IsNull() )
1793 aPad->SetLocalSolderMaskMargin( {} );
1794 else
1796
1797 if( m_pasteMargin.IsNull() )
1798 aPad->SetLocalSolderPasteMargin( {} );
1799 else
1801
1804 else
1806
1810
1811 // And rotation
1813
1814 switch( m_ZoneConnectionChoice->GetSelection() )
1815 {
1816 default:
1817 case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1818 case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
1819 case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1820 case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
1821 }
1822
1824
1825 if( FOOTPRINT* fp = aPad->GetParentFootprint() )
1826 {
1827 pos -= fp->GetPosition();
1828 RotatePoint( pos, -fp->GetOrientation() );
1829 }
1830
1831 aPad->SetPosition( pos );
1832
1833 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1834 {
1835 aPad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
1837 }
1838 else
1839 {
1840 aPad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
1842 }
1843
1844 if( aPad->GetShape() == PAD_SHAPE::CIRCLE )
1846 else
1848
1849 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
1850 // remember DeltaSize.x is the Y size variation
1851 bool error = false;
1852 VECTOR2I delta( 0, 0 );
1853
1854 if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
1855 {
1856 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
1857 if( m_trapAxisCtrl->GetSelection() == 0 )
1859 else
1861
1862 if( delta.x < 0 && delta.x < -aPad->GetSize().y )
1863 {
1864 delta.x = -aPad->GetSize().y + 2;
1865 error = true;
1866 }
1867
1868 if( delta.x > 0 && delta.x > aPad->GetSize().y )
1869 {
1870 delta.x = aPad->GetSize().y - 2;
1871 error = true;
1872 }
1873
1874 if( delta.y < 0 && delta.y < -aPad->GetSize().x )
1875 {
1876 delta.y = -aPad->GetSize().x + 2;
1877 error = true;
1878 }
1879
1880 if( delta.y > 0 && delta.y > aPad->GetSize().x )
1881 {
1882 delta.y = aPad->GetSize().x - 2;
1883 error = true;
1884 }
1885 }
1886
1887 aPad->SetDelta( delta );
1888
1889 if( m_offsetShapeOpt->GetValue() )
1891 else
1892 aPad->SetOffset( VECTOR2I() );
1893
1894 // Read pad length die
1895 if( m_padToDieOpt->GetValue() )
1897 else
1898 aPad->SetPadToDieLength( 0 );
1899
1900 aPad->SetNumber( m_padNumCtrl->GetValue() );
1902
1903 int chamfers = 0;
1904
1905 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
1906 {
1907 if( m_cbTopLeft->GetValue() )
1908 chamfers |= RECT_CHAMFER_TOP_LEFT;
1909
1910 if( m_cbTopRight->GetValue() )
1911 chamfers |= RECT_CHAMFER_TOP_RIGHT;
1912
1913 if( m_cbBottomLeft->GetValue() )
1914 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1915
1916 if( m_cbBottomRight->GetValue() )
1917 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1918 }
1919 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
1920 {
1921 if( m_cbTopLeft1->GetValue() )
1922 chamfers |= RECT_CHAMFER_TOP_LEFT;
1923
1924 if( m_cbTopRight1->GetValue() )
1925 chamfers |= RECT_CHAMFER_TOP_RIGHT;
1926
1927 if( m_cbBottomLeft1->GetValue() )
1928 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1929
1930 if( m_cbBottomRight1->GetValue() )
1931 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1932 }
1933 aPad->SetChamferPositions( chamfers );
1934
1935 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
1936 {
1937 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
1938 // that is the minimal area of this pad, and is useful to ensure a hole
1939 // diameter is acceptable, and is used in Gerber files as flashed area
1940 // reference
1941 if( aPad->GetAnchorPadShape() == PAD_SHAPE::CIRCLE )
1943 }
1944
1945 // Define the way the clearance area is defined in zones. Since all non-custom pad
1946 // shapes are convex to begin with, this really only makes any difference for custom
1947 // pad shapes.
1948 aPad->SetCustomShapeInZoneOpt( m_ZoneCustomPadShape->GetSelection() == 0 ?
1951
1952 switch( aPad->GetAttribute() )
1953 {
1954 case PAD_ATTRIB::PTH:
1955 break;
1956
1957 case PAD_ATTRIB::CONN:
1958 case PAD_ATTRIB::SMD:
1959 // SMD and PAD_ATTRIB::CONN has no hole.
1960 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
1961 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
1962 // and are intended to be used in virtual edge board connectors
1963 // However we can accept a non null offset,
1964 // mainly to allow complex pads build from a set of basic pad shapes
1965 aPad->SetDrillSize( VECTOR2I( 0, 0 ) );
1966 break;
1967
1968 case PAD_ATTRIB::NPTH:
1969 // Mechanical purpose only:
1970 // no net name, no pad name allowed
1971 aPad->SetNumber( wxEmptyString );
1973 break;
1974
1975 default:
1976 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
1977 break;
1978 }
1979
1980 if( aPad->GetShape() == PAD_SHAPE::ROUNDRECT )
1981 {
1983 }
1984 else if( aPad->GetShape() == PAD_SHAPE::CHAMFERED_RECT )
1985 {
1987 {
1990 }
1991 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
1992 {
1994 aPad->SetRoundRectRadiusRatio( 0 );
1995 }
1996 }
1997
1999
2000 LSET padLayerMask = LSET();
2001 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
2002
2004
2005 switch( m_padType->GetSelection() )
2006 {
2007 case PTH_DLG_TYPE:
2008 switch( copperLayersChoice )
2009 {
2010 case 0:
2011 // All copper layers
2012 padLayerMask |= LSET::AllCuMask();
2013 break;
2014
2015 case 1:
2016 // Front, back and connected
2017 padLayerMask |= LSET::AllCuMask();
2020 break;
2021
2022 case 2:
2023 // Connected only
2024 padLayerMask |= LSET::AllCuMask();
2026 break;
2027
2028 case 3:
2029 // No copper layers
2030 break;
2031 }
2032
2033 break;
2034
2035 case NPTH_DLG_TYPE:
2036 switch( copperLayersChoice )
2037 {
2038 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
2039 case 1: padLayerMask.set( F_Cu ); break;
2040 case 2: padLayerMask.set( B_Cu ); break;
2041 default: break;
2042 }
2043
2044 break;
2045
2046 case SMD_DLG_TYPE:
2047 case CONN_DLG_TYPE:
2048 switch( copperLayersChoice )
2049 {
2050 case 0: padLayerMask.set( F_Cu ); break;
2051 case 1: padLayerMask.set( B_Cu ); break;
2052 }
2053
2054 break;
2055
2056 case APERTURE_DLG_TYPE:
2057 // no copper layers
2058 break;
2059 }
2060
2061 if( m_layerFrontAdhesive->GetValue() )
2062 padLayerMask.set( F_Adhes );
2063
2064 if( m_layerBackAdhesive->GetValue() )
2065 padLayerMask.set( B_Adhes );
2066
2067 if( m_layerFrontPaste->GetValue() )
2068 padLayerMask.set( F_Paste );
2069
2070 if( m_layerBackPaste->GetValue() )
2071 padLayerMask.set( B_Paste );
2072
2073 if( m_layerFrontSilk->GetValue() )
2074 padLayerMask.set( F_SilkS );
2075
2076 if( m_layerBackSilk->GetValue() )
2077 padLayerMask.set( B_SilkS );
2078
2079 if( m_layerFrontMask->GetValue() )
2080 padLayerMask.set( F_Mask );
2081
2082 if( m_layerBackMask->GetValue() )
2083 padLayerMask.set( B_Mask );
2084
2085 if( m_layerECO1->GetValue() )
2086 padLayerMask.set( Eco1_User );
2087
2088 if( m_layerECO2->GetValue() )
2089 padLayerMask.set( Eco2_User );
2090
2091 if( m_layerUserDwgs->GetValue() )
2092 padLayerMask.set( Dwgs_User );
2093
2094 aPad->SetLayerSet( padLayerMask );
2095
2096 return !error;
2097}
2098
2099
2100void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2101{
2102 if( m_offsetShapeOpt->GetValue() )
2103 {
2106 }
2107
2108 // Show/hide controls depending on m_offsetShapeOpt being enabled
2109 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2110 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2111
2112 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2113 m_notebook->GetPage( i )->Layout();
2114
2115 OnValuesChanged( event );
2116}
2117
2118
2120{
2121 if( m_padToDieOpt->GetValue() && m_currentPad )
2123
2124 OnValuesChanged( event );
2125}
2126
2127
2128void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2129{
2130 if( m_canUpdate )
2131 {
2133 return;
2134
2135 // If the pad size has changed, update the displayed values for rounded rect pads.
2137
2138 redraw();
2139 }
2140}
2141
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
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
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:204
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:853
const FOOTPRINTS & Footprints() const
Definition: board.h:323
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:564
bool LegacyTeardrops() const
Definition: board.h:1243
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:794
const SizeVec & GetSize() const
Definition: box2.h:196
size_type GetHeight() const
Definition: box2.h:205
coord_type GetTop() const
Definition: box2.h:219
size_type GetWidth() const
Definition: box2.h:204
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:128
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
coord_type GetRight() const
Definition: box2.h:207
coord_type GetLeft() const
Definition: box2.h:218
coord_type GetBottom() const
Definition: box2.h:212
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:102
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:128
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:103
bool IsFlipped() const
Definition: footprint.h:377
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:165
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:170
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,...
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:1631
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:830
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:575
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)
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition: padstack.h:254
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:53
bool IsAperturePad() const
Definition: pad.h:396
void SetAttribute(PAD_ATTRIB aAttribute)
Definition: pad.cpp:771
void SetLayerSet(LSET aLayers) override
Definition: pad.h:385
PAD_PROP GetProperty() const
Definition: pad.h:392
bool GetRemoveUnconnected() const
Definition: pad.h:638
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:386
int GetSizeX() const
Definition: pad.h:253
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition: pad.cpp:762
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: pad.h:419
const VECTOR2I & GetDrillSize() const
Definition: pad.h:261
PAD_ATTRIB GetAttribute() const
Definition: pad.h:389
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:312
void SetThermalGap(int aGap)
Definition: pad.h:577
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition: pad.h:558
const wxString & GetNumber() const
Definition: pad.h:128
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:451
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: pad.h:423
void DeletePrimitivesList()
Clear the basic shapes list.
VECTOR2I GetPosition() const override
Definition: pad.h:195
void SetProperty(PAD_PROP aProperty)
Definition: pad.cpp:819
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:312
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:562
void SetOffset(const VECTOR2I &aOffset)
Definition: pad.h:267
void SetChamferRectRatio(double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition: pad.cpp:471
const VECTOR2I & GetOffset() const
Definition: pad.h:268
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pad.cpp:333
void SetRoundRectCornerRadius(double aRadius)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:457
int GetDrillSizeX() const
Definition: pad.h:263
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:1800
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition: pad.h:127
void SetDrillShape(PAD_DRILL_SHAPE aShape)
Definition: pad.h:366
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: pad.h:408
bool GetKeepTopBottom() const
Definition: pad.h:654
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:428
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.h:404
void SetDelta(const VECTOR2I &aSize)
Definition: pad.h:257
bool IsOnCopperLayer() const override
Definition: pad.cpp:938
void SetPadstack(const PADSTACK &aPadstack)
Definition: pad.h:274
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:189
const PADSTACK & Padstack() const
Definition: pad.h:272
const VECTOR2I & GetDelta() const
Definition: pad.h:258
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition: pad.cpp:326
void SetDrillSize(const VECTOR2I &aSize)
Definition: pad.h:260
PAD_SHAPE GetShape() const
Definition: pad.h:187
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:353
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition: pad.h:208
PAD_DRILL_SHAPE GetDrillShape() const
Definition: pad.h:371
void Flip(const VECTOR2I &VECTOR2I, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: pad.cpp:854
static LSET ApertureMask()
layer set for an aperture pad
Definition: pad.cpp:340
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pad.cpp:1659
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:319
std::optional< int > GetLocalSolderPasteMargin() const
Definition: pad.h:413
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pad.h:407
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: pad.h:414
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:178
int GetSizeY() const
Definition: pad.h:255
int GetThermalSpokeWidth() const
Definition: pad.h:549
EDA_ANGLE GetFPRelativeOrientation() const
Definition: pad.cpp:845
void SetFPRelativeOrientation(const EDA_ANGLE &aAngle)
Definition: pad.cpp:836
void SetCustomShapeInZoneOpt(PADSTACK::CUSTOM_SHAPE_ZONE_MODE 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:463
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:827
int GetChamferPositions() const
Definition: pad.h:618
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:405
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: pad.h:429
void SetThermalSpokeWidth(int aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: pad.h:548
void SetSize(const VECTOR2I &aSize)
Definition: pad.h:245
double GetRoundRectRadiusRatio() const
Definition: pad.h:599
int GetThermalGap() const
Definition: pad.h:578
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:525
const VECTOR2I & GetSize() const
Definition: pad.h:250
void SetChamferPositions(int aPositions)
Has meaning only for chamfered rectangular pads.
Definition: pad.h:617
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:200
double GetChamferRectRatio() const
Definition: pad.h:608
void SetPadToDieLength(int aLength)
Definition: pad.h:401
int GetPadToDieLength() const
Definition: pad.h:402
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:209
@ B_Adhes
Definition: layer_ids.h:97
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_SilkS
Definition: layer_ids.h:104
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:112
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
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
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:154
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: padstack.h:72
@ 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_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: padstack.h:44
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition: padstack.h:89
const double IU_PER_MM
Definition: base_units.h:76
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
constexpr 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:228
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:118
VECTOR2< double > VECTOR2D
Definition: vector2d.h:601
VECTOR2< int > VECTOR2I
Definition: vector2d.h:602