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