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