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