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