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
398
399
400void DIALOG_PAD_PROPERTIES::OnEditLayerChanged( wxCommandEvent& aEvent )
401{
402 // Save data from the previous layer
404
405 switch( m_previewPad->Padstack().Mode() )
406 {
407 default:
410 break;
411
413 switch( m_cbEditLayer->GetSelection() )
414 {
415 default:
416 case 0: m_editLayer = F_Cu; break;
417 case 1: m_editLayer = PADSTACK::INNER_LAYERS; break;
418 case 2: m_editLayer = B_Cu; break;
419 }
420 break;
421
423 {
424 int layer = m_cbEditLayer->GetSelection();
425
426 if( layer < 0 )
427 layer = 0;
428
429 if( m_editLayerCtrlMap.contains( layer ) )
430 m_editLayer = m_editLayerCtrlMap.at( layer );
431 else
433 }
434 }
435
436 // Load controls with the current layer
438
439 wxCommandEvent cmd_event;
440 onPadShapeSelection( false );
441 OnOffsetCheckbox( cmd_event );
442
443 redraw();
444}
445
446
448{
449 // Note: use ChangeValue() to avoid generating a wxEVT_TEXT event
450 m_cornerRadius.ChangeValue( m_previewPad->GetRoundRectCornerRadius( m_editLayer ) );
451
452 m_cornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
453 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
454
455 m_chamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
456 m_mixedChamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
457}
458
459
461{
464 {
465 return;
466 }
467
468 if( m_cornerRadius.GetValue() < 0 )
469 m_cornerRadiusCtrl->ChangeValue( "0" );
470
472 {
473 m_previewPad->SetRoundRectCornerRadius( m_editLayer, m_cornerRadius.GetValue() );
474
475 m_cornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
476 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
477
478 redraw();
479 }
480
481 if( m_initialized )
482 OnModify();
483}
484
485
487{
488 // The maximum chamfer ratio is 50% of the smallest pad side if adjacent sides
489 // are selected, or 100% of the smallest pad side if only one side is selected.
490 double baseline = 1.0;
491
492 auto considerCheckboxes = [&]( const std::vector<wxCheckBox*>& checkBoxes )
493 {
494 for( size_t ii : { 0, 1, 2, 3 } )
495 {
496 if( !checkBoxes[ii]->IsChecked() )
497 continue;
498
499 if( checkBoxes[( ii + 1 ) % 4]->IsChecked() || checkBoxes[( ii - 1 ) % 4]->IsChecked() )
500 {
501 // If two adjacent corners are selected, the maximum chamfer ratio is 50%
502 baseline = std::max( baseline, 0.5 );
503 break;
504 }
505 }
506 };
507
508
509 baseline = 1.0 - m_previewPad->GetRoundRectRadiusRatio( m_editLayer );
510 considerCheckboxes( { m_cbTopLeft1, m_cbTopRight1, m_cbBottomRight1, m_cbBottomLeft1 } );
511 considerCheckboxes( { m_cbTopLeft, m_cbTopRight, m_cbBottomRight, m_cbBottomLeft } );
512
513 // If only one corner is selected, the maximum chamfer ratio is 100%
514 return baseline;
515}
516
517
519{
520 return 1.0 - m_previewPad->GetChamferRectRatio( m_editLayer );
521}
522
523
525{
526 auto updateCheckBoxes = []( const std::vector<wxCheckBox*>& aCheckBoxes )
527 {
528 for( size_t ii : { 0, 1, 2, 3 } )
529 {
530 bool disable = aCheckBoxes[( ii + 1 ) % 4]->IsChecked()
531 || aCheckBoxes[( ii + 3 ) % 4]->IsChecked();
532
533 aCheckBoxes[ii]->Enable( !disable );
534
535 if( disable )
536 aCheckBoxes[ii]->SetValue( false );
537 }
538 };
539
540 if( m_mixedChamferRatio.GetDoubleValue() > 50.0 )
541 {
543 }
544
545 if( m_chamferRatio.GetDoubleValue() > 50.0 )
546 {
547 updateCheckBoxes( { m_cbTopLeft, m_cbTopRight, m_cbBottomRight, m_cbBottomLeft } );
548 }
549}
550
551
553{
556 {
557 return;
558 }
559
560 wxObject* ctrl = event.GetEventObject();
561 wxString value = event.GetString();
562 bool changed = false;
563
564 if( ctrl == m_cornerRatioCtrl || ctrl == m_mixedCornerRatioCtrl )
565 {
566 double ratioPercent;
567
568 if( value.ToDouble( &ratioPercent ) )
569 {
570 // Clamp ratioPercent to acceptable value (0.0 to 50.0)
571 double maxRatio = getMaxCornerRadius();
572
573 if( ratioPercent < 0.0 )
574 {
575 m_cornerRatio.SetDoubleValue( 0.0 );
576 m_mixedCornerRatio.SetDoubleValue( 0.0 );
577 }
578 else if( ratioPercent > maxRatio * 100.0 )
579 {
580 m_cornerRatio.SetDoubleValue( maxRatio * 100.0 );
581 m_mixedCornerRatio.SetDoubleValue( maxRatio * 100.0 );
582 }
583
584 if( ctrl == m_cornerRatioCtrl )
585 m_mixedCornerRatioCtrl->ChangeValue( value );
586 else
587 m_cornerRatioCtrl->ChangeValue( value );
588
589 changed = true;
590 }
591 }
592 else if( ctrl == m_chamferRatioCtrl || ctrl == m_mixedChamferRatioCtrl )
593 {
594 double ratioPercent;
595
596 if( value.ToDouble( &ratioPercent ) )
597 {
598 double maxRatio = getMaxChamferRatio();
599 // Clamp ratioPercent to acceptable value (0.0 to maxRatio)
600 if( ratioPercent < 0.0 )
601 {
602 m_chamferRatio.SetDoubleValue( 0.0 );
603 m_mixedChamferRatio.SetDoubleValue( 0.0 );
604 }
605 else if( ratioPercent > maxRatio * 100.0 )
606 {
607 m_chamferRatio.SetDoubleValue( maxRatio * 100.0 );
608 m_mixedChamferRatio.SetDoubleValue( maxRatio * 100.0 );
609 }
610
611 if( ctrl == m_chamferRatioCtrl )
612 m_mixedChamferRatioCtrl->ChangeValue( value );
613 else
614 m_chamferRatioCtrl->ChangeValue( value );
615
617
618 changed = true;
619 }
620 }
621
622 if( changed && transferDataToPad( m_previewPad ) )
623 m_cornerRadius.ChangeValue( m_previewPad->GetRoundRectCornerRadius( m_editLayer ) );
624
625 redraw();
626
627 if( m_initialized )
628 OnModify();
629}
630
631
633{
634 wxString msg;
635
636 // Disable pad net name wxTextCtrl if the caller is the footprint editor
637 // because nets are living only in the board managed by the board editor
639
640 m_layerFrontAdhesive->SetLabel( m_board->GetLayerName( F_Adhes ) );
641 m_layerBackAdhesive->SetLabel( m_board->GetLayerName( B_Adhes ) );
642 m_layerFrontPaste->SetLabel( m_board->GetLayerName( F_Paste ) );
643 m_layerBackPaste->SetLabel( m_board->GetLayerName( B_Paste ) );
644 m_layerFrontSilk->SetLabel( m_board->GetLayerName( F_SilkS ) );
645 m_layerBackSilk->SetLabel( m_board->GetLayerName( B_SilkS ) );
646 m_layerFrontMask->SetLabel( m_board->GetLayerName( F_Mask ) );
647 m_layerBackMask->SetLabel( m_board->GetLayerName( B_Mask ) );
648 m_layerECO1->SetLabel( m_board->GetLayerName( Eco1_User ) );
649 m_layerECO2->SetLabel( m_board->GetLayerName( Eco2_User ) );
650 m_layerUserDwgs->SetLabel( m_board->GetLayerName( Dwgs_User ) );
651
652 VECTOR2I absPos;
653
654 if( m_currentPad )
655 {
656 absPos = m_currentPad->GetPosition();
657
658 if( FOOTPRINT* footprint = m_currentPad->GetParentFootprint() )
659 {
660 VECTOR2I relPos = m_currentPad->GetFPRelativePosition();
661
662 if( footprint->IsFlipped() )
663 {
664 // flip pad (up/down) around its position
666 relPos.y = - relPos.y;
667 }
668
669 m_previewPad->SetPosition( relPos );
670 m_previewPad->SetOrientation( m_currentPad->GetFPRelativeOrientation() );
671
672 // Display parent footprint info
673 msg.Printf( _("Footprint %s (%s), %s, rotated %g deg"),
674 footprint->Reference().GetShownText( false ),
675 footprint->Value().GetShownText( false ),
676 footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
677 footprint->GetOrientation().AsDegrees() );
678
679 m_FlippedWarningSizer->Show( footprint->IsFlipped() );
680 m_parentInfo->SetLabel( msg );
681 }
682
683 m_padNumCtrl->SetValue( m_previewPad->GetNumber() );
684 }
685 else
686 {
687 PAD_TOOL* padTool = m_parent->GetToolManager()->GetTool<PAD_TOOL>();
688 m_padNumCtrl->SetValue( padTool->GetLastPadNumber() );
689 }
690
692
693 m_padNetSelector->SetSelectedNetcode( m_previewPad->GetNetCode() );
694
695 // Display current pad parameters units:
696 m_posX.ChangeValue( absPos.x );
697 m_posY.ChangeValue( absPos.y );
698
699 m_holeX.ChangeValue( m_previewPad->GetDrillSize().x );
700 m_holeY.ChangeValue( m_previewPad->GetDrillSize().y );
701
703
704 m_padToDieOpt->SetValue( m_previewPad->GetPadToDieLength() != 0 );
705 m_padToDie.ChangeValue( m_previewPad->GetPadToDieLength() );
706
707 m_padToDieDelayOpt->SetValue( m_previewPad->GetPadToDieDelay() != 0 );
708 m_padToDieDelay.ChangeValue( m_previewPad->GetPadToDieDelay() );
709
710 if( m_previewPad->GetLocalClearance().has_value() )
711 m_clearance.ChangeValue( m_previewPad->GetLocalClearance().value() );
712 else
713 m_clearance.ChangeValue( wxEmptyString );
714
715 if( m_previewPad->GetLocalSolderMaskMargin().has_value() )
716 m_maskMargin.ChangeValue( m_previewPad->GetLocalSolderMaskMargin().value() );
717 else
718 m_maskMargin.ChangeValue( wxEmptyString );
719
720 m_pasteMargin.SetOffsetValue( m_previewPad->GetLocalSolderPasteMargin() );
721 m_pasteMargin.SetRatioValue( m_previewPad->GetLocalSolderPasteMarginRatio() );
722
723 if( m_previewPad->GetLocalThermalSpokeWidthOverride().has_value() )
724 m_spokeWidth.ChangeValue( m_previewPad->GetLocalThermalSpokeWidthOverride().value() );
725 else
726 m_spokeWidth.SetNull();
727
728 if( m_previewPad->GetLocalThermalGapOverride().has_value() )
729 m_thermalGap.ChangeValue( m_previewPad->GetLocalThermalGapOverride().value() );
730 else
731 m_thermalGap.SetNull();
732
733 m_spokeAngle.ChangeAngleValue( m_previewPad->GetThermalSpokeAngle() );
734 m_pad_orientation.ChangeAngleValue( m_previewPad->GetOrientation() );
735
736 m_cbTeardrops->SetValue( m_previewPad->GetTeardropParams().m_Enabled );
737 m_cbTeardropsUseNextTrack->SetValue( m_previewPad->GetTeardropParams().m_AllowUseTwoTracks );
738 m_cbPreferZoneConnection->SetValue( !m_previewPad->GetTeardropParams().m_TdOnPadsInZones );
739 m_teardropMaxLenSetting.SetValue( m_previewPad->GetTeardropParams().m_TdMaxLen );
740 m_teardropMaxHeightSetting.SetValue( m_previewPad->GetTeardropParams().m_TdMaxWidth );
741 m_spTeardropLenPercent->SetValue( m_previewPad->GetTeardropParams().m_BestLengthRatio *100 );
742 m_spTeardropSizePercent->SetValue( m_previewPad->GetTeardropParams().m_BestWidthRatio *100 );
743 m_spTeardropHDPercent->SetValue( m_previewPad->GetTeardropParams().m_WidthtoSizeFilterRatio*100 );
744 m_curvedEdges->SetValue( m_previewPad->GetTeardropParams().m_CurvedEdges );
745
746 switch( m_previewPad->GetLocalZoneConnection() )
747 {
748 default:
749 case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
750 case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
751 case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
752 case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
753 }
754
755 if( m_previewPad->GetCustomShapeInZoneOpt() == CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL )
756 m_ZoneCustomPadShape->SetSelection( 1 );
757 else
758 m_ZoneCustomPadShape->SetSelection( 0 );
759
760 // Type of pad selection
761 bool aperture =
762 m_previewPad->GetAttribute() == PAD_ATTRIB::SMD && m_previewPad->IsAperturePad();
763
764 if( aperture )
765 {
766 m_padType->SetSelection( APERTURE_DLG_TYPE );
767 }
768 else
769 {
770 switch( m_previewPad->GetAttribute() )
771 {
772 case PAD_ATTRIB::PTH: m_padType->SetSelection( PTH_DLG_TYPE ); break;
773 case PAD_ATTRIB::SMD: m_padType->SetSelection( SMD_DLG_TYPE ); break;
774 case PAD_ATTRIB::CONN: m_padType->SetSelection( CONN_DLG_TYPE ); break;
775 case PAD_ATTRIB::NPTH: m_padType->SetSelection( NPTH_DLG_TYPE ); break;
776 }
777 }
778
779 switch( m_previewPad->GetProperty() )
780 {
781 case PAD_PROP::NONE: m_choiceFabProperty->SetSelection( 0 ); break;
782 case PAD_PROP::BGA: m_choiceFabProperty->SetSelection( 1 ); break;
783 case PAD_PROP::FIDUCIAL_LOCAL: m_choiceFabProperty->SetSelection( 2 ); break;
784 case PAD_PROP::FIDUCIAL_GLBL: m_choiceFabProperty->SetSelection( 3 ); break;
785 case PAD_PROP::TESTPOINT: m_choiceFabProperty->SetSelection( 4 ); break;
786 case PAD_PROP::HEATSINK: m_choiceFabProperty->SetSelection( 5 ); break;
787 case PAD_PROP::MECHANICAL: m_choiceFabProperty->SetSelection( 6 ); break;
788 case PAD_PROP::CASTELLATED: m_choiceFabProperty->SetSelection( 7 ); break;
789 case PAD_PROP::PRESSFIT: m_choiceFabProperty->SetSelection( 8 ); break;
790 }
791
792 if( m_previewPad->GetDrillShape() != PAD_DRILL_SHAPE::OBLONG )
793 m_holeShapeCtrl->SetSelection( 0 );
794 else
795 m_holeShapeCtrl->SetSelection( 1 );
796
797 // Backdrill properties
798 const PADSTACK::DRILL_PROPS& secondaryDrill = m_previewPad->Padstack().SecondaryDrill();
799 const PADSTACK::DRILL_PROPS& tertiaryDrill = m_previewPad->Padstack().TertiaryDrill();
800 bool hasBackdrill = secondaryDrill.start != UNDEFINED_LAYER;
801 bool hasTertiaryDrill = tertiaryDrill.start != UNDEFINED_LAYER;
802
803 m_backDrillChoice->SetSelection( hasBackdrill ? ( hasTertiaryDrill ? 3 : 1 )
804 : ( hasTertiaryDrill ? 2 : 0 ) );
805
806 if( !hasBackdrill )
807 {
808 m_backDrillBottomSizeBinder.SetValue( 0 );
809 }
810 else
811 {
812 m_backDrillBottomSizeBinder.SetValue( secondaryDrill.size.x );
813
814 for( unsigned int i = 0; i < m_backDrillBottomLayer->GetCount(); ++i )
815 {
816 if( ToLAYER_ID( (intptr_t)m_backDrillBottomLayer->GetClientData( i ) ) == secondaryDrill.end )
817 {
818 m_backDrillBottomLayer->SetSelection( i );
819 break;
820 }
821 }
822 }
823
824 if( !hasTertiaryDrill )
825 {
826 m_backDrillTopSizeBinder.SetValue( 0 );
827 }
828 else
829 {
830 m_backDrillTopSizeBinder.SetValue( tertiaryDrill.size.x );
831
832 for( unsigned int i = 0; i < m_backDrillTopLayer->GetCount(); ++i )
833 {
834 if( ToLAYER_ID( (intptr_t)m_backDrillTopLayer->GetClientData( i ) ) == tertiaryDrill.end )
835 {
836 m_backDrillTopLayer->SetSelection( i );
837 break;
838 }
839 }
840 }
841
842 // Post machining
843 const PADSTACK::POST_MACHINING_PROPS& frontPostMachining = m_previewPad->Padstack().FrontPostMachining();
844
845 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
846 m_topPostMachining->SetSelection( 2 );
847 else if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
848 m_topPostMachining->SetSelection( 1 );
849 else
850 m_topPostMachining->SetSelection( 0 );
851
852 m_topPostMachineSize1Binder.SetValue( frontPostMachining.size );
853
854 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
855 {
857 m_topPostMachineSize2Binder.SetDoubleValue( frontPostMachining.angle / 10.0 );
858 }
859 else
860 {
861 m_topPostMachineSize2Binder.SetValue( frontPostMachining.depth );
862 }
863
864 const PADSTACK::POST_MACHINING_PROPS& backPostMachining = m_previewPad->Padstack().BackPostMachining();
865
866 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
867 m_bottomPostMachining->SetSelection( 2 );
868 else if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
869 m_bottomPostMachining->SetSelection( 1 );
870 else
871 m_bottomPostMachining->SetSelection( 0 );
872
873 m_bottomPostMachineSize1Binder.SetValue( backPostMachining.size );
874
875 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
876 {
878 m_bottomPostMachineSize2Binder.SetDoubleValue( backPostMachining.angle / 10.0 );
879 }
880 else
881 {
882 m_bottomPostMachineSize2Binder.SetValue( backPostMachining.depth );
883 }
884
885
886 updatePadLayersList( m_previewPad->GetLayerSet(), m_previewPad->GetRemoveUnconnected(),
887 m_previewPad->GetKeepTopBottom() );
888
889 // Update some dialog widgets state (Enable/disable options):
890 wxCommandEvent cmd_event;
891 onPadShapeSelection( false );
892 OnOffsetCheckbox( cmd_event );
894}
895
896
898{
899 m_primitives = m_previewPad->GetPrimitives( m_editLayer );
900
901 m_sizeX.ChangeValue( m_previewPad->GetSize( m_editLayer ).x );
902 m_sizeY.ChangeValue( m_previewPad->GetSize( m_editLayer ).y );
903
904 m_offsetShapeOpt->SetValue( m_previewPad->GetOffset( m_editLayer ) != VECTOR2I() );
905 m_offsetX.ChangeValue( m_previewPad->GetOffset( m_editLayer ).x );
906 m_offsetY.ChangeValue( m_previewPad->GetOffset( m_editLayer ).y );
907
908 if( m_previewPad->GetDelta( m_editLayer ).x )
909 {
910 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).x );
911 m_trapAxisCtrl->SetSelection( 0 );
912 }
913 else
914 {
915 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).y );
916 m_trapAxisCtrl->SetSelection( 1 );
917 }
918
919 switch( m_previewPad->GetShape( m_editLayer ) )
920 {
921 default:
922 case PAD_SHAPE::CIRCLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
923 case PAD_SHAPE::OVAL: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_OVAL ); break;
924 case PAD_SHAPE::RECTANGLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_RECT ); break;
927
929 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) > 0.0 )
931 else
933 break;
934
936 if( m_previewPad->GetAnchorPadShape( m_editLayer ) == PAD_SHAPE::RECTANGLE )
938 else
940 break;
941 }
942
943 int chamferPositions = m_previewPad->GetChamferPositions( m_editLayer );
944
945 m_cbTopLeft->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
946 m_cbTopLeft1->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
947 m_cbTopRight->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
948 m_cbTopRight1->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
949 m_cbBottomLeft->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
950 m_cbBottomLeft1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
951 m_cbBottomRight->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
952 m_cbBottomRight1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
953
955}
956
957
959{
960 // NOTE: synchronize changes here with DIALOG_TRACK_VIA_PROPERTIES::afterPadstackModeChanged
961
962 wxCHECK_MSG( m_board, /* void */, "Expected valid board in afterPadstackModeChanged" );
963 m_cbEditLayer->Clear();
964
965 switch( m_previewPad->Padstack().Mode() )
966 {
968 m_cbPadstackMode->SetSelection( 0 );
969 m_cbEditLayer->Append( m_board->GetLayerName( F_Cu ) );
970 m_cbEditLayer->Disable();
972 m_editLayerCtrlMap = { { 0, F_Cu } };
973 break;
974
976 {
977 m_cbPadstackMode->SetSelection( 1 );
978 m_cbEditLayer->Enable();
979
980 std::vector choices = {
981 m_board->GetLayerName( F_Cu ),
982 _( "Inner Layers" ),
983 m_board->GetLayerName( B_Cu )
984 };
985
986 m_cbEditLayer->Append( choices );
987
989 { 0, F_Cu },
991 { 2, B_Cu }
992 };
993
994 if( m_editLayer != F_Cu && m_editLayer != B_Cu )
996
997 break;
998 }
999
1001 {
1002 m_cbPadstackMode->SetSelection( 2 );
1003 m_cbEditLayer->Enable();
1004 LSET layers = LSET::AllCuMask() & m_board->GetEnabledLayers();
1005
1006 for( PCB_LAYER_ID layer : layers.UIOrder() )
1007 {
1008 int idx = m_cbEditLayer->Append( m_board->GetLayerName( layer ) );
1009 m_editLayerCtrlMap[idx] = layer;
1010 }
1011
1012 break;
1013 }
1014 }
1015
1016 for( const auto& [idx, layer] : m_editLayerCtrlMap )
1017 {
1018 if( layer == m_editLayer )
1019 {
1020 m_cbEditLayer->SetSelection( idx );
1021 break;
1022 }
1023 }
1024}
1025
1026
1027void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
1028{
1029 redraw();
1030 event.Skip();
1031}
1032
1033
1035{
1036 m_sketchPreview = m_cbShowPadOutline->GetValue();
1037
1038 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1039
1040 // fix the pad render mode (filled/not filled)
1041 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
1042
1043 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
1044 settings->SetHighContrast( false );
1045 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
1046
1047 redraw();
1048}
1049
1050
1052{
1053 onPadShapeSelection( true );
1054}
1055
1056
1058{
1059 switch( m_PadShapeSelector->GetSelection() )
1060 {
1062 case CHOICE_SHAPE_OVAL:
1063 case CHOICE_SHAPE_RECT:
1064 m_shapePropsBook->SetSelection( 0 );
1065 break;
1066
1068 m_shapePropsBook->SetSelection( 1 );
1069 break;
1070
1072 {
1073 m_shapePropsBook->SetSelection( 2 );
1074
1075 // Reasonable defaults
1076 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0 )
1077 {
1078 const double ipcRadiusRatio =
1080 m_cornerRatio.ChangeDoubleValue( ipcRadiusRatio * 100 );
1081 }
1082
1083 break;
1084 }
1085
1087 m_shapePropsBook->SetSelection( 3 );
1088
1089 // Reasonable default
1090 if( m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1091 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1092
1093 // Ensure the displayed value is up to date:
1094 m_chamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1095
1096 // A reasonable default is one corner chamfered (usual for some SMD pads).
1097 if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
1098 && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
1099 {
1100 m_cbTopLeft->SetValue( true );
1101 m_cbTopRight->SetValue( false );
1102 m_cbBottomLeft->SetValue( false );
1103 m_cbBottomRight->SetValue( false );
1104 }
1105
1106 break;
1107
1109 m_shapePropsBook->SetSelection( 4 );
1110
1111 // Reasonable defaults
1112 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0
1113 && m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1114 {
1115 const double ipcRadiusRatio =
1117 m_previewPad->SetRoundRectRadiusRatio( m_editLayer, ipcRadiusRatio );
1118 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1119 }
1120
1121 // Ensure the displayed values are up to date:
1122 m_mixedChamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1123 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
1124 break;
1125
1126 case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE::CUSTOM, circular anchor
1127 case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE::CUSTOM, rect anchor
1128 m_shapePropsBook->SetSelection( 0 );
1129 break;
1130 }
1131
1132 if( aUpdateSpokeAngle )
1133 {
1134 // Note: must do this before enabling/disabling m_sizeY as we're using that as a flag to see
1135 // what the last shape was.
1136 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE )
1137 {
1138 if( m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_90 )
1139 m_spokeAngle.SetAngleValue( ANGLE_45 );
1140 }
1141 else
1142 {
1143 if( !m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_45 )
1144 m_spokeAngle.SetAngleValue( ANGLE_90 );
1145 }
1146 }
1147
1148 // Readjust props book size
1149 wxSize size = m_shapePropsBook->GetSize();
1150 size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
1151 m_shapePropsBook->SetMaxSize( size );
1152
1153 m_sizeY.Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE
1155
1156 m_offsetShapeOpt->Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE );
1157
1158 if( !m_offsetShapeOpt->IsEnabled() )
1159 m_offsetShapeOpt->SetValue( false );
1160
1161 // Show/hide controls depending on m_offsetShapeOpt being enabled
1162 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
1163 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
1164
1167
1168 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
1169 m_notebook->GetPage( i )->Layout();
1170
1171 // Resize the dialog if its height is too small to show all widgets:
1172 if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
1173 m_MainSizer->SetSizeHints( this );
1174
1176 redraw();
1177
1178 if( m_initialized )
1179 OnModify();
1180}
1181
1182
1184{
1185 if( m_holeShapeCtrl->GetSelection() != CHOICE_SHAPE_CIRCLE )
1186 {
1187 bool hasBackdrill = ( m_backDrillChoice->GetSelection() != 0 );
1188 bool hasTopPost = ( m_topPostMachining->GetSelection() != 0 );
1189 bool hasBottomPost = ( m_bottomPostMachining->GetSelection() != 0 );
1190
1191 if( hasBackdrill || hasTopPost || hasBottomPost )
1192 {
1193 if( wxMessageBox( _( "Switching to non-circular hole will disable backdrills and post-machining. Continue?" ),
1194 _( "Warning" ), wxOK | wxCANCEL | wxICON_WARNING, this ) != wxOK )
1195 {
1196 m_holeShapeCtrl->SetSelection( CHOICE_SHAPE_CIRCLE );
1197 return;
1198 }
1199 }
1200 }
1201
1204 redraw();
1205
1206 if( m_initialized )
1207 OnModify();
1208}
1209
1210
1211void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
1212{
1214 redraw();
1215
1216 if( m_initialized )
1217 OnModify();
1218}
1219
1220
1222{
1223 m_rbCopperLayersSel->Clear();
1224
1225 switch( m_padType->GetSelection() )
1226 {
1227 case PTH_DLG_TYPE:
1228 m_rbCopperLayersSel->Append( _( "All copper layers" ) );
1229 m_rbCopperLayersSel->Append( wxString::Format( _( "%s, %s and connected layers" ),
1230 m_board->GetLayerName( F_Cu ),
1231 m_board->GetLayerName( B_Cu ) ) );
1232 m_rbCopperLayersSel->Append( _( "Connected layers only" ) );
1233 m_rbCopperLayersSel->Append( _( "None" ) );
1234 break;
1235
1236 case NPTH_DLG_TYPE:
1237 m_rbCopperLayersSel->Append( wxString::Format( _( "%s and %s" ),
1238 m_board->GetLayerName( F_Cu ),
1239 m_board->GetLayerName( B_Cu ) ) );
1240 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1241 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1242 m_rbCopperLayersSel->Append( _( "None" ) );
1243 break;
1244
1245 case SMD_DLG_TYPE:
1246 case CONN_DLG_TYPE:
1247 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1248 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1249 break;
1250
1251 case APERTURE_DLG_TYPE:
1252 m_rbCopperLayersSel->Append( _( "None" ) );
1253 break;
1254 }
1255
1256 m_backDrillTopLayer->Clear();
1257 m_backDrillBottomLayer->Clear();
1258
1259 for( PCB_LAYER_ID layerId : m_board->GetEnabledLayers().UIOrder() )
1260 {
1261 if( IsCopperLayer( layerId ) )
1262 {
1263 wxString layerName = m_board->GetLayerName( layerId );
1264 m_backDrillTopLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1265 m_backDrillBottomLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1266 }
1267 }
1268}
1269
1270
1271void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
1272{
1273 bool hasHole = true;
1274 bool hasConnection = true;
1275
1276 switch( m_padType->GetSelection() )
1277 {
1278 case PTH_DLG_TYPE: hasHole = true; hasConnection = true; break;
1279 case SMD_DLG_TYPE: hasHole = false; hasConnection = true; break;
1280 case CONN_DLG_TYPE: hasHole = false; hasConnection = true; break;
1281 case NPTH_DLG_TYPE: hasHole = true; hasConnection = false; break;
1282 case APERTURE_DLG_TYPE: hasHole = false; hasConnection = false; break;
1283 }
1284
1285 // Pad type just changed, so the old pad's layer set is no longer meaningful. Pass nullopt
1286 // to populate the defaults for the new type.
1287 updatePadLayersList( std::nullopt, m_previewPad->GetRemoveUnconnected(),
1288 m_previewPad->GetKeepTopBottom() );
1289
1290 m_gbSizerHole->Show( hasHole );
1291 m_staticline71->Show( hasHole );
1292
1293 if( !hasHole )
1294 {
1295 m_holeX.ChangeValue( 0 );
1296 m_holeY.ChangeValue( 0 );
1297 }
1298 else if( m_holeX.GetValue() == 0 )
1299 {
1300 if( m_currentPad )
1301 {
1302 m_holeX.ChangeValue( m_currentPad->GetDrillSize().x );
1303 m_holeY.ChangeValue( m_currentPad->GetDrillSize().y );
1304 }
1305 else
1306 {
1307 m_holeX.ChangeValue( pcbIUScale.mmToIU( DEFAULT_PAD_DRILL_DIAMETER_MM ) );
1308 }
1309 }
1310
1311 if( !hasConnection )
1312 {
1313 m_padNumCtrl->ChangeValue( wxEmptyString );
1314 m_padNetSelector->SetSelectedNetcode( 0 );
1315 m_padToDieOpt->SetValue( false );
1316 m_padToDieDelayOpt->SetValue( false );
1317 }
1318 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1319 {
1320 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1321 m_padNetSelector->SetSelectedNetcode( m_currentPad->GetNetCode() );
1322 }
1323
1325
1326 // For now, padstack controls only enabled for PTH pads
1327 bool enablePadstack = m_padType->GetSelection() == PTH_DLG_TYPE;
1328 m_padstackControls->Show( enablePadstack );
1329
1330 if( !enablePadstack )
1331 {
1332 m_editLayer = F_Cu;
1334 }
1335
1336 // Layout adjustment is needed if the hole details got shown/hidden
1337 m_LeftBoxSizer->Layout();
1338 redraw();
1339
1340 if( m_initialized )
1341 OnModify();
1342}
1343
1344
1345void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1346{
1347 bool hasHole = true;
1348 bool hasConnection = true;
1349
1350 switch( m_padType->GetSelection() )
1351 {
1352 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1353 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1354 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1355 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1356 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1357 }
1358
1359 // Enable/disable hole controls
1360 m_holeShapeLabel->Enable( hasHole );
1361 m_holeShapeCtrl->Enable( hasHole );
1362 m_holeX.Enable( hasHole );
1363 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1364
1365 // Enable/disable number and net
1366 m_padNumLabel->Enable( hasConnection );
1367 m_padNumCtrl->Enable( hasConnection );
1368
1369 if( m_padNetLabel->IsShown() )
1370 {
1371 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1372 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1373 }
1374
1375 // Enable/disable pad length-to-die
1376 m_padToDieOpt->Enable( hasConnection );
1377 m_padToDieDelayOpt->Enable( hasConnection );
1378
1379 if( !m_padToDieOpt->IsEnabled() )
1380 m_padToDieOpt->SetValue( false );
1381
1382 if( !m_padToDieDelayOpt->IsEnabled() )
1383 m_padToDieDelayOpt->SetValue( false );
1384
1385 // We can show/hide this here because it doesn't require the layout to be refreshed.
1386 // All the others have to be done in their event handlers because doing a layout here
1387 // causes infinite looping on MSW.
1388 m_padToDie.Show( m_padToDieOpt->GetValue() );
1389 m_padToDieDelay.Show( m_padToDieDelayOpt->GetValue() );
1390
1391 // Enable/disable Copper Layers control
1392 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1393
1394 LSET cu_set = m_previewPad->GetLayerSet() & LSET::AllCuMask();
1395
1396 switch( m_padType->GetSelection() )
1397 {
1398 case PTH_DLG_TYPE:
1399 if( !cu_set.any() )
1400 m_stackupImagesBook->SetSelection( 3 );
1401 else if( !m_previewPad->GetRemoveUnconnected() )
1402 m_stackupImagesBook->SetSelection( 0 );
1403 else if( m_previewPad->GetKeepTopBottom() )
1404 m_stackupImagesBook->SetSelection( 1 );
1405 else
1406 m_stackupImagesBook->SetSelection( 2 );
1407
1408 break;
1409
1410 case NPTH_DLG_TYPE:
1411 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1412 m_stackupImagesBook->SetSelection( 4 );
1413 else if( cu_set.test( F_Cu ) )
1414 m_stackupImagesBook->SetSelection( 5 );
1415 else if( cu_set.test( B_Cu ) )
1416 m_stackupImagesBook->SetSelection( 6 );
1417 else
1418 m_stackupImagesBook->SetSelection( 7 );
1419
1420 break;
1421
1422 case SMD_DLG_TYPE:
1423 case CONN_DLG_TYPE:
1424 case APERTURE_DLG_TYPE:
1425 m_stackupImagesBook->ChangeSelection( 3 );
1426 break;
1427 }
1428
1429 m_legacyTeardropsWarning->Show( m_board->LegacyTeardrops() );
1430}
1431
1432
1434{
1435 event.Enable( !m_board->LegacyTeardrops() );
1436}
1437
1438
1440{
1441 bool isOnCopperLayer = ( m_previewPad->GetLayerSet() & LSET::AllCuMask() ).any();
1442 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1443}
1444
1445
1446void DIALOG_PAD_PROPERTIES::updatePadLayersList( std::optional<LSET> layer_mask,
1447 bool remove_unconnected, bool keep_top_bottom )
1448{
1450
1451 // An empty LSET supplied by the caller is a valid user choice (a pad with no layers);
1452 // std::nullopt is the signal that defaults for the current pad type should be used instead.
1453 LSET effective_mask;
1454
1455 switch( m_padType->GetSelection() )
1456 {
1457 case PTH_DLG_TYPE:
1458 effective_mask = layer_mask.value_or( PAD::PTHMask() );
1459
1460 if( !( effective_mask & LSET::AllCuMask() ).any() )
1461 m_rbCopperLayersSel->SetSelection( 3 );
1462 else if( !remove_unconnected )
1463 m_rbCopperLayersSel->SetSelection( 0 );
1464 else if( keep_top_bottom )
1465 m_rbCopperLayersSel->SetSelection( 1 );
1466 else
1467 m_rbCopperLayersSel->SetSelection( 2 );
1468
1469 break;
1470
1471 case SMD_DLG_TYPE:
1472 // The SMD/CONN UI has no "no copper" radio choice, so fall back to defaults if the
1473 // stored mask has no copper layers. Otherwise saving would silently force B_Cu.
1474 effective_mask = layer_mask.value_or( PAD::SMDMask() );
1475
1476 if( !( effective_mask & LSET::AllCuMask() ).any() )
1477 effective_mask = PAD::SMDMask();
1478
1479 if( effective_mask.test( F_Cu ) )
1480 m_rbCopperLayersSel->SetSelection( 0 );
1481 else
1482 m_rbCopperLayersSel->SetSelection( 1 );
1483
1484 break;
1485
1486 case CONN_DLG_TYPE:
1487 effective_mask = layer_mask.value_or( PAD::ConnSMDMask() );
1488
1489 if( !( effective_mask & LSET::AllCuMask() ).any() )
1490 effective_mask = PAD::ConnSMDMask();
1491
1492 if( effective_mask.test( F_Cu ) )
1493 m_rbCopperLayersSel->SetSelection( 0 );
1494 else
1495 m_rbCopperLayersSel->SetSelection( 1 );
1496
1497 break;
1498
1499 case NPTH_DLG_TYPE:
1500 effective_mask = layer_mask.value_or( PAD::UnplatedHoleMask() );
1501
1502 if( effective_mask.test( F_Cu ) && effective_mask.test( B_Cu ) )
1503 m_rbCopperLayersSel->SetSelection( 0 );
1504 else if( effective_mask.test( F_Cu ) )
1505 m_rbCopperLayersSel->SetSelection( 1 );
1506 else if( effective_mask.test( B_Cu ) )
1507 m_rbCopperLayersSel->SetSelection( 2 );
1508 else
1509 m_rbCopperLayersSel->SetSelection( 3 );
1510
1511 break;
1512
1513 case APERTURE_DLG_TYPE:
1514 effective_mask = layer_mask.value_or( PAD::ApertureMask() );
1515
1516 m_rbCopperLayersSel->SetSelection( 0 );
1517 break;
1518 }
1519
1520 m_layerFrontAdhesive->SetValue( effective_mask[F_Adhes] );
1521 m_layerBackAdhesive->SetValue( effective_mask[B_Adhes] );
1522
1523 m_layerFrontPaste->SetValue( effective_mask[F_Paste] );
1524 m_layerBackPaste->SetValue( effective_mask[B_Paste] );
1525
1526 m_layerFrontSilk->SetValue( effective_mask[F_SilkS] );
1527 m_layerBackSilk->SetValue( effective_mask[B_SilkS] );
1528
1529 m_layerFrontMask->SetValue( effective_mask[F_Mask] );
1530 m_layerBackMask->SetValue( effective_mask[B_Mask] );
1531
1532 m_layerECO1->SetValue( effective_mask[Eco1_User] );
1533 m_layerECO2->SetValue( effective_mask[Eco2_User] );
1534
1535 m_layerUserDwgs->SetValue( effective_mask[Dwgs_User] );
1536}
1537
1538
1540{
1541 bool retVal = DIALOG_SHIM::Show( aShow );
1542
1543 if( aShow )
1544 {
1545 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1546 // wxWidgets needs to have these set when the panel is visible for some reason.
1547 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1555
1556 Layout();
1557 }
1558
1559 return retVal;
1560}
1561
1562
1563void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1564{
1566 redraw();
1567
1568 if( m_initialized )
1569 OnModify();
1570}
1571
1572
1573void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1574{
1576 redraw();
1577
1578 if( m_initialized )
1579 OnModify();
1580}
1581
1582
1584{
1586
1587 wxArrayString error_msgs;
1588 wxArrayString warning_msgs;
1589
1590 m_previewPad->CheckPad( m_parentFrame, true,
1591 [&]( int errorCode, const wxString& msg )
1592 {
1593 if( errorCode == DRCE_PADSTACK_INVALID )
1594 error_msgs.Add( _( "Error: " ) + msg );
1595 else if( errorCode == DRCE_PADSTACK )
1596 warning_msgs.Add( _( "Warning: " ) + msg );
1597 else if( errorCode == DRCE_PAD_TH_WITH_NO_HOLE )
1598 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1599 } );
1600
1601 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1602 {
1603 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1604 : _( "Pad Properties Warnings" );
1605 HTML_MESSAGE_BOX dlg( this, title );
1606
1607 wxArrayString msgs = error_msgs;
1608
1609 for( const wxString& msg : warning_msgs )
1610 msgs.Add( msg );
1611
1612 dlg.ListSet( msgs );
1613
1614 dlg.ShowModal();
1615 }
1616
1617 return error_msgs.GetCount() == 0;
1618}
1619
1620
1622{
1623 if( !m_initialized )
1624 return;
1625
1626 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1627 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view->GetPainter() );
1628 KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings();
1629
1630 m_padPreviewGAL->StopDrawing();
1631
1632 // The layer used to place primitive items selected when editing custom pad shapes
1633 // we use here a layer never used in a pad:
1634 #define SELECTED_ITEMS_LAYER Dwgs_User
1635
1636 view->ClearTopLayers();
1638 view->SetTopLayer( m_editLayer );
1640
1641 static const std::vector<int> topLayers = {
1646 };
1647
1648 for( int layer : topLayers )
1649 view->SetTopLayer( layer );
1650
1651 m_axisOrigin->SetPosition( m_previewPad->GetPosition() );
1652
1653 view->Update( m_previewPad );
1654
1655 // delete previous items if highlight list
1656 while( m_highlight.size() )
1657 {
1658 delete m_highlight.back(); // the dtor also removes item from view
1659 m_highlight.pop_back();
1660 }
1661
1662 BOX2I bbox = m_previewPad->ViewBBox();
1663
1664 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1665 {
1666 // The origin always goes in the middle of the canvas; we want offsetting the pad
1667 // shape to move the pad, not the hole
1668 bbox.Move( -m_previewPad->GetPosition() );
1669 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1670 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1671
1672 // Don't blow up the GAL on too-large numbers
1673 if( maxXExtent > INT_MAX / 4 )
1674 maxXExtent = INT_MAX / 4;
1675
1676 if( maxYExtent > INT_MAX / 4 )
1677 maxYExtent = INT_MAX / 4;
1678
1679 BOX2D viewBox( m_previewPad->GetPosition(), {0, 0} );
1680 BOX2D canvasBox( m_previewPad->GetPosition(), {0, 0} );
1681 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1682 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1683
1684 view->SetBoundary( canvasBox );
1685
1686 // Autozoom
1687 view->SetViewport( viewBox );
1688
1689 m_padPreviewGAL->StartDrawing();
1690 m_padPreviewGAL->Refresh();
1691 }
1692}
1693
1694
1696{
1697 if( !wxDialog::TransferDataToWindow() )
1698 return false;
1699
1700 if( !m_panelGeneral->TransferDataToWindow() )
1701 return false;
1702
1703 if( !m_localSettingsPanel->TransferDataToWindow() )
1704 return false;
1705
1706 return true;
1707}
1708
1709
1711{
1712 BOARD_COMMIT commit( m_parent );
1713
1714 if( !wxDialog::TransferDataFromWindow() )
1715 return false;
1716
1717 if( !m_panelGeneral->TransferDataFromWindow() )
1718 return false;
1719
1720 if( !m_localSettingsPanel->TransferDataFromWindow() )
1721 return false;
1722
1723 if( !padValuesOK() )
1724 return false;
1725
1727 return false;
1728
1729 m_padPreviewGAL->StopDrawing();
1730
1731 PAD_TOOL* padTool = m_parent->GetToolManager()->GetTool<PAD_TOOL>();
1732 padTool->SetLastPadNumber( m_masterPad->GetNumber() );
1733
1734 // m_masterPad is a pattern: ensure there is no net for this pad:
1736
1737 if( !m_currentPad ) // Set current Pad parameters
1738 return true;
1739
1740 commit.Modify( m_currentPad );
1741
1742 // Update values
1743
1744 // transferDataToPad only handles the current edit layer, so m_masterPad isn't accurate
1745 // TODO(JE) this could be cleaner
1746 m_currentPad->SetPadstack( m_previewPad->Padstack() );
1747
1748 m_currentPad->SetAttribute( m_masterPad->GetAttribute() );
1749 m_currentPad->SetFPRelativeOrientation( m_masterPad->GetOrientation() );
1750 m_currentPad->SetPadToDieLength( m_masterPad->GetPadToDieLength() );
1751 m_currentPad->SetPadToDieDelay( m_masterPad->GetPadToDieDelay() );
1752 m_currentPad->SetLayerSet( m_masterPad->GetLayerSet() );
1753 m_currentPad->SetNumber( m_masterPad->GetNumber() );
1754
1755 int padNetcode = NETINFO_LIST::UNCONNECTED;
1756
1757 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1758 if( m_masterPad->GetAttribute() != PAD_ATTRIB::NPTH )
1759 padNetcode = m_padNetSelector->GetSelectedNetcode();
1760
1761 m_currentPad->SetNetCode( padNetcode );
1762
1763 m_currentPad->GetTeardropParams() = m_masterPad->GetTeardropParams();
1764
1765 // Set the fabrication property:
1766 m_currentPad->SetProperty( getSelectedProperty() );
1767
1768 // define the way the clearance area is defined in zones
1769 m_currentPad->SetCustomShapeInZoneOpt( m_masterPad->GetCustomShapeInZoneOpt() );
1770
1771 if( m_currentPad->GetParentFootprint() && m_currentPad->GetParentFootprint()->IsFlipped() )
1772 {
1773 // flip pad (up/down) around its position
1774 m_currentPad->Flip( m_currentPad->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1775 }
1776
1777 m_currentPad->SetPosition( m_masterPad->GetPosition() );
1778
1779 m_parent->SetMsgPanel( m_currentPad );
1780
1781 // redraw the area where the pad was
1782 m_parent->GetCanvas()->Refresh();
1783
1784 commit.Push( _( "Edit Pad Properties" ) );
1785
1786 return true;
1787}
1788
1789
1791{
1792 PAD_PROP prop = PAD_PROP::NONE;
1793
1794 switch( m_choiceFabProperty->GetSelection() )
1795 {
1796 case 0: prop = PAD_PROP::NONE; break;
1797 case 1: prop = PAD_PROP::BGA; break;
1798 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1799 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1800 case 4: prop = PAD_PROP::TESTPOINT; break;
1801 case 5: prop = PAD_PROP::HEATSINK; break;
1802 case 6: prop = PAD_PROP::MECHANICAL; break;
1803 case 7: prop = PAD_PROP::CASTELLATED; break;
1804 case 8: prop = PAD_PROP::PRESSFIT; break;
1805 }
1806
1807 return prop;
1808}
1809
1810
1812{
1813 bool isRound = ( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE );
1814
1815 if( isRound )
1816 {
1817 m_holeXLabel->SetLabel( _( "Diameter:" ) );
1818 m_holeY.Show( false );
1819 }
1820 else
1821 {
1822 m_holeXLabel->SetLabel( _( "Hole size X:" ) );
1823 m_holeY.Show( true );
1824 }
1825
1826 m_holeXLabel->GetParent()->Layout();
1827
1828 if( !isRound )
1829 {
1830 // Disable all
1831 m_backDrillChoice->Enable( false );
1832 m_backDrillTopLayer->Enable( false );
1833 m_backDrillTopLayerLabel->Enable( false );
1834 m_backDrillBottomLayer->Enable( false );
1835 m_backDrillBottomLayerLabel->Enable( false );
1836
1837 m_topPostMachining->Enable( false );
1838 m_topPostMachineSize1Binder.Enable( false );
1839 m_topPostMachineSize2Binder.Enable( false );
1840 m_topPostMachineSize1Label->Enable( false );
1841 m_topPostMachineSize2Label->Enable( false );
1842
1843 m_bottomPostMachining->Enable( false );
1844 m_bottomPostMachineSize1Binder.Enable( false );
1845 m_bottomPostMachineSize2Binder.Enable( false );
1846 m_bottomPostMachineSize1Label->Enable( false );
1847 m_bottomPostMachineSize2Label->Enable( false );
1848 }
1849 else
1850 {
1851 // Enable main choices
1852 m_backDrillChoice->Enable( true );
1853 m_topPostMachining->Enable( true );
1854 m_bottomPostMachining->Enable( true );
1855
1856 // Update sub-controls based on selection
1857 wxCommandEvent dummy;
1861 }
1862}
1863
1864
1866{
1867 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1869 {
1870 m_sizeXLabel->SetLabel( _( "Diameter:" ) );
1871 m_sizeY.Show( false );
1873 m_minTrackWidthHint->SetLabel( _( "d" ) );
1874 m_stLenPercentHint->SetLabel( _( "d" ) );
1875 m_stWidthPercentHint->SetLabel( _( "d" ) );
1876 }
1877 else
1878 {
1879 m_sizeXLabel->SetLabel( _( "Pad size X:" ) );
1880 m_sizeY.Show( true );
1882 m_minTrackWidthHint->SetLabel( _( "w" ) );
1883 m_stLenPercentHint->SetLabel( _( "w" ) );
1884 m_stWidthPercentHint->SetLabel( _( "w" ) );
1885 }
1886
1887 m_sizeXLabel->GetParent()->Layout();
1888 resetSize();
1889 Layout();
1890 m_MainSizer->Fit( this );
1891}
1892
1893
1895{
1896 std::map<PCB_LAYER_ID, PCB_LAYER_ID> newLayerMap; // Map of new-layerss to init-from-layers
1897
1898 auto setMode =
1899 [&]( PADSTACK::MODE mode )
1900 {
1901 PADSTACK oldStack = aPad->Padstack();
1902
1903 aPad->Padstack().SetMode( mode );
1904
1906 [&]( PCB_LAYER_ID layer )
1907 {
1908 if( !oldStack.HasExplicitDefinitionForLayer( layer ) )
1909 {
1910 if( IsInnerCopperLayer( layer ) && layer != PADSTACK::INNER_LAYERS )
1911 newLayerMap[layer] = PADSTACK::INNER_LAYERS;
1912 else
1913 newLayerMap[layer] = F_Cu;
1914 }
1915 } );
1916 };
1917
1918 if( !Validate() )
1919 return false;
1920
1921 if( !m_panelGeneral->Validate() )
1922 return false;
1923
1924 if( !m_localSettingsPanel->Validate() )
1925 return false;
1926
1927 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1928 return false;
1929
1930 switch( m_cbPadstackMode->GetSelection() )
1931 {
1932 default:
1933 case 0: setMode( PADSTACK::MODE::NORMAL ); break;
1934 case 1: setMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1935 case 2: setMode( PADSTACK::MODE::CUSTOM ); break;
1936 }
1937
1938 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1939 aPad->SetShape( m_editLayer, code_shape[m_PadShapeSelector->GetSelection()] );
1940
1943 else
1945
1946 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
1948
1949 aPad->GetTeardropParams().m_Enabled = m_cbTeardrops->GetValue();
1956 aPad->GetTeardropParams().m_CurvedEdges = m_curvedEdges->GetValue();
1958
1959 // Read pad clearances values:
1960 if( m_clearance.IsNull() )
1961 aPad->SetLocalClearance( {} );
1962 else
1963 aPad->SetLocalClearance( m_clearance.GetIntValue() );
1964
1965 if( m_maskMargin.IsNull() )
1966 aPad->SetLocalSolderMaskMargin( {} );
1967 else
1968 aPad->SetLocalSolderMaskMargin( m_maskMargin.GetIntValue() );
1969
1970 aPad->SetLocalSolderPasteMargin( m_pasteMargin.GetOffsetValue() );
1971 aPad->SetLocalSolderPasteMarginRatio( m_pasteMargin.GetRatioValue() );
1972
1973 if( m_spokeWidth.IsNull() )
1975 else
1976 aPad->SetLocalThermalSpokeWidthOverride( m_spokeWidth.GetIntValue() );
1977
1978 if( m_thermalGap.IsNull() )
1979 aPad->SetLocalThermalGapOverride( {} );
1980 else
1981 aPad->SetLocalThermalGapOverride( m_thermalGap.GetIntValue() );
1982
1983 aPad->SetThermalSpokeAngle( m_spokeAngle.GetAngleValue() );
1984
1985 // And rotation
1986 aPad->SetOrientation( m_pad_orientation.GetAngleValue() );
1987
1988 switch( m_ZoneConnectionChoice->GetSelection() )
1989 {
1990 default:
1991 case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1992 case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
1993 case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1994 case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
1995 }
1996
1997 VECTOR2I pos( m_posX.GetIntValue(), m_posY.GetIntValue() );
1998
1999 if( FOOTPRINT* fp = aPad->GetParentFootprint() )
2000 {
2001 pos -= fp->GetPosition();
2002 RotatePoint( pos, -fp->GetOrientation() );
2003 }
2004
2005 aPad->SetPosition( pos );
2006
2007 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
2008 {
2010 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeX.GetIntValue() ) );
2011 }
2012 else
2013 {
2015 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeY.GetIntValue() ) );
2016 }
2017
2018 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CIRCLE )
2019 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2020 else
2021 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeY.GetIntValue() ) );
2022
2023 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
2024 // remember DeltaSize.x is the Y size variation
2025 bool error = false;
2026 VECTOR2I delta( 0, 0 );
2027
2028 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::TRAPEZOID )
2029 {
2030 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
2031 if( m_trapAxisCtrl->GetSelection() == 0 )
2032 delta.x = m_trapDelta.GetIntValue();
2033 else
2034 delta.y = m_trapDelta.GetIntValue();
2035
2036 if( delta.x < 0 && delta.x < -aPad->GetSize( m_editLayer ).y )
2037 {
2038 delta.x = -aPad->GetSize( m_editLayer ).y + 2;
2039 error = true;
2040 }
2041
2042 if( delta.x > 0 && delta.x > aPad->GetSize( m_editLayer ).y )
2043 {
2044 delta.x = aPad->GetSize( m_editLayer ).y - 2;
2045 error = true;
2046 }
2047
2048 if( delta.y < 0 && delta.y < -aPad->GetSize( m_editLayer ).x )
2049 {
2050 delta.y = -aPad->GetSize( m_editLayer ).x + 2;
2051 error = true;
2052 }
2053
2054 if( delta.y > 0 && delta.y > aPad->GetSize( m_editLayer ).x )
2055 {
2056 delta.y = aPad->GetSize( m_editLayer ).x - 2;
2057 error = true;
2058 }
2059 }
2060
2061 aPad->SetDelta( m_editLayer, delta );
2062
2063 if( m_offsetShapeOpt->GetValue() )
2064 aPad->SetOffset( m_editLayer, VECTOR2I( m_offsetX.GetIntValue(), m_offsetY.GetIntValue() ) );
2065 else
2066 aPad->SetOffset( m_editLayer, VECTOR2I() );
2067
2068 // Read pad length die
2069 if( m_padToDieOpt->GetValue() )
2070 aPad->SetPadToDieLength( m_padToDie.GetIntValue() );
2071 else
2072 aPad->SetPadToDieLength( 0 );
2073
2074 if( m_padToDieDelayOpt->GetValue() )
2075 aPad->SetPadToDieDelay( m_padToDieDelay.GetIntValue() );
2076 else
2077 aPad->SetPadToDieDelay( 0 );
2078
2079 aPad->SetNumber( m_padNumCtrl->GetValue() );
2080 aPad->SetNetCode( m_padNetSelector->GetSelectedNetcode() );
2081
2082 int chamfers = 0;
2083
2084 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
2085 {
2086 if( m_cbTopLeft->GetValue() )
2087 chamfers |= RECT_CHAMFER_TOP_LEFT;
2088
2089 if( m_cbTopRight->GetValue() )
2090 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2091
2092 if( m_cbBottomLeft->GetValue() )
2093 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2094
2095 if( m_cbBottomRight->GetValue() )
2096 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2097 }
2098 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
2099 {
2100 if( m_cbTopLeft1->GetValue() )
2101 chamfers |= RECT_CHAMFER_TOP_LEFT;
2102
2103 if( m_cbTopRight1->GetValue() )
2104 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2105
2106 if( m_cbBottomLeft1->GetValue() )
2107 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2108
2109 if( m_cbBottomRight1->GetValue() )
2110 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2111 }
2112
2113 aPad->SetChamferPositions( m_editLayer, chamfers );
2114
2115 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
2116 {
2117 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
2118 // that is the minimal area of this pad, and is useful to ensure a hole
2119 // diameter is acceptable, and is used in Gerber files as flashed area
2120 // reference
2122 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2123 }
2124
2125 // Define the way the clearance area is defined in zones. Since all non-custom pad
2126 // shapes are convex to begin with, this really only makes any difference for custom
2127 // pad shapes.
2130
2131 switch( aPad->GetAttribute() )
2132 {
2133 case PAD_ATTRIB::PTH:
2134 break;
2135
2136 case PAD_ATTRIB::CONN:
2137 case PAD_ATTRIB::SMD:
2138 // SMD and PAD_ATTRIB::CONN has no hole.
2139 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
2140 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
2141 // and are intended to be used in virtual edge board connectors
2142 // However we can accept a non null offset,
2143 // mainly to allow complex pads build from a set of basic pad shapes
2144 aPad->SetDrillSize( VECTOR2I( 0, 0 ) );
2145 break;
2146
2147 case PAD_ATTRIB::NPTH:
2148 // Mechanical purpose only:
2149 // no net name, no pad name allowed
2150 aPad->SetNumber( wxEmptyString );
2152 break;
2153
2154 default:
2155 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
2156 break;
2157 }
2158
2159 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::ROUNDRECT )
2160 {
2161 aPad->SetRoundRectRadiusRatio( m_editLayer, m_cornerRatio.GetDoubleValue() / 100.0 );
2162 }
2163 else if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CHAMFERED_RECT )
2164 {
2166 {
2167 aPad->SetChamferRectRatio( m_editLayer, m_mixedChamferRatio.GetDoubleValue() / 100.0 );
2168 aPad->SetRoundRectRadiusRatio( m_editLayer, m_mixedCornerRatio.GetDoubleValue() / 100.0 );
2169 }
2170 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
2171 {
2172 aPad->SetChamferRectRatio( m_editLayer, m_chamferRatio.GetDoubleValue() / 100.0 );
2174 }
2175 }
2176
2178
2179 LSET padLayerMask = LSET();
2180 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
2181
2183
2184 switch( m_padType->GetSelection() )
2185 {
2186 case PTH_DLG_TYPE:
2187 switch( copperLayersChoice )
2188 {
2189 case 0:
2190 // All copper layers
2191 padLayerMask |= LSET::AllCuMask();
2192 break;
2193
2194 case 1:
2195 // Front, back and connected
2196 padLayerMask |= LSET::AllCuMask();
2198 break;
2199
2200 case 2:
2201 // Connected only
2202 padLayerMask |= LSET::AllCuMask();
2204 break;
2205
2206 case 3:
2207 // No copper layers
2208 break;
2209 }
2210
2211 break;
2212
2213 case NPTH_DLG_TYPE:
2214 switch( copperLayersChoice )
2215 {
2216 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
2217 case 1: padLayerMask.set( F_Cu ); break;
2218 case 2: padLayerMask.set( B_Cu ); break;
2219 default: break;
2220 }
2221
2222 break;
2223
2224 case SMD_DLG_TYPE:
2225 case CONN_DLG_TYPE:
2226 switch( copperLayersChoice )
2227 {
2228 case 0: padLayerMask.set( F_Cu ); break;
2229 case 1: padLayerMask.set( B_Cu ); break;
2230 }
2231
2232 break;
2233
2234 case APERTURE_DLG_TYPE:
2235 // no copper layers
2236 break;
2237 }
2238
2239 if( m_layerFrontAdhesive->GetValue() )
2240 padLayerMask.set( F_Adhes );
2241
2242 if( m_layerBackAdhesive->GetValue() )
2243 padLayerMask.set( B_Adhes );
2244
2245 if( m_layerFrontPaste->GetValue() )
2246 padLayerMask.set( F_Paste );
2247
2248 if( m_layerBackPaste->GetValue() )
2249 padLayerMask.set( B_Paste );
2250
2251 if( m_layerFrontSilk->GetValue() )
2252 padLayerMask.set( F_SilkS );
2253
2254 if( m_layerBackSilk->GetValue() )
2255 padLayerMask.set( B_SilkS );
2256
2257 if( m_layerFrontMask->GetValue() )
2258 padLayerMask.set( F_Mask );
2259
2260 if( m_layerBackMask->GetValue() )
2261 padLayerMask.set( B_Mask );
2262
2263 if( m_layerECO1->GetValue() )
2264 padLayerMask.set( Eco1_User );
2265
2266 if( m_layerECO2->GetValue() )
2267 padLayerMask.set( Eco2_User );
2268
2269 if( m_layerUserDwgs->GetValue() )
2270 padLayerMask.set( Dwgs_User );
2271
2272 aPad->SetLayerSet( padLayerMask );
2273
2274 // Save backdrill properties
2275 PADSTACK::DRILL_PROPS secondaryDrill;
2276 secondaryDrill.size = VECTOR2I( m_backDrillBottomSizeBinder.GetIntValue(),
2277 m_backDrillBottomSizeBinder.GetIntValue() );
2278 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2279
2280 PADSTACK::DRILL_PROPS tertiaryDrill;
2281 tertiaryDrill.size = VECTOR2I( m_backDrillTopSizeBinder.GetIntValue(),
2282 m_backDrillTopSizeBinder.GetIntValue() );
2283 tertiaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2284
2285 if( !m_backDrillChoice->GetSelection() )
2286 {
2287 secondaryDrill.start = UNDEFINED_LAYER;
2288 secondaryDrill.end = UNDEFINED_LAYER;
2289 }
2290
2291 if( m_backDrillChoice->GetSelection() == 1 || m_backDrillChoice->GetSelection() == 3 ) // Front
2292 {
2293 tertiaryDrill.start = F_Cu;
2294
2295 if( m_backDrillTopLayer->GetSelection() != wxNOT_FOUND )
2296 tertiaryDrill.end = ToLAYER_ID( (intptr_t)m_backDrillTopLayer->GetClientData( m_backDrillTopLayer->GetSelection() ) );
2297 else
2298 tertiaryDrill.end = UNDEFINED_LAYER;
2299 }
2300
2301 if( m_backDrillChoice->GetSelection() == 2 || m_backDrillChoice->GetSelection() == 3 ) // Back
2302 {
2303 secondaryDrill.start = B_Cu;
2304
2305 if( m_backDrillBottomLayer->GetSelection() != wxNOT_FOUND )
2306 secondaryDrill.end = ToLAYER_ID( (intptr_t)m_backDrillBottomLayer->GetClientData( m_backDrillBottomLayer->GetSelection() ) );
2307 else
2308 secondaryDrill.end = UNDEFINED_LAYER;
2309 }
2310
2311 aPad->Padstack().SecondaryDrill() = secondaryDrill;
2312 aPad->Padstack().TertiaryDrill() = tertiaryDrill;
2313
2314 // Front Post Machining
2315 PADSTACK::POST_MACHINING_PROPS frontPostMachining;
2316
2317 switch( m_topPostMachining->GetSelection() )
2318 {
2319 case 1: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2320 case 2: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2321 default: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2322 }
2323
2324 frontPostMachining.size = m_topPostMachineSize1Binder.GetIntValue();
2325
2326 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2327 frontPostMachining.angle = KiROUND( m_topPostMachineSize2Binder.GetDoubleValue() * 10.0 );
2328 else
2329 frontPostMachining.depth = m_topPostMachineSize2Binder.GetIntValue();
2330
2331 aPad->Padstack().FrontPostMachining() = frontPostMachining;
2332
2333 // Back Post Machining
2334 PADSTACK::POST_MACHINING_PROPS backPostMachining;
2335
2336 switch( m_bottomPostMachining->GetSelection() )
2337 {
2338 case 1: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2339 case 2: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2340 default: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2341 }
2342
2343 backPostMachining.size = m_bottomPostMachineSize1Binder.GetIntValue();
2344
2345 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2346 backPostMachining.angle = KiROUND( m_bottomPostMachineSize2Binder.GetDoubleValue() * 10.0 );
2347 else
2348 backPostMachining.depth = m_bottomPostMachineSize2Binder.GetIntValue();
2349
2350 aPad->Padstack().BackPostMachining() = backPostMachining;
2351
2352 // If we created new layers, initialize them
2353 for( const auto& [newLayer, initFromLayer] : newLayerMap )
2354 {
2355 if( newLayer != m_editLayer && newLayer != initFromLayer )
2356 aPad->Padstack().CopperLayer( newLayer ) = aPad->Padstack().CopperLayer( initFromLayer );
2357 }
2358
2359 return !error;
2360}
2361
2362
2363
2364
2365void DIALOG_PAD_PROPERTIES::onBackDrillChoice( wxCommandEvent& event )
2366{
2367 int selection = m_backDrillChoice->GetSelection();
2368 // 0: None, 1: Top, 2: Bottom, 3: Both
2369
2370 bool enableTop = ( selection == 1 || selection == 3 );
2371 bool enableBottom = ( selection == 2 || selection == 3 );
2372
2373 m_backDrillTopSizeBinder.Enable( enableTop );
2374 m_backDrillTopLayer->Enable( enableTop );
2375 m_backDrillTopLayerLabel->Enable( enableTop );
2376
2377 m_backDrillBottomSizeBinder.Enable( enableBottom );
2378 m_backDrillBottomLayer->Enable( enableBottom );
2379 m_backDrillBottomLayerLabel->Enable( enableBottom );
2380
2381}
2382
2383
2385{
2386 int selection = m_topPostMachining->GetSelection();
2387 // 0: None, 1: Countersink, 2: Counterbore
2388
2389 bool enable = ( selection != 0 );
2390 m_topPostMachineSize1Binder.Enable( enable );
2391 m_topPostMachineSize2Binder.Enable( enable );
2392 m_topPostMachineSize1Label->Enable( enable );
2393 m_topPostMachineSize2Label->Enable( enable );
2394
2395 if( selection == 1 ) // Countersink
2396 {
2397 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2398 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
2400
2401 if( m_topPostMachineSize2Binder.IsIndeterminate() || m_topPostMachineSize2Binder.GetDoubleValue() == 0 )
2402 m_topPostMachineSize2Binder.SetDoubleValue( 82.0 );
2403 }
2404 else if( selection == 2 ) // Counterbore
2405 {
2406 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2407 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2408 m_topPostMachineSize2Binder.SetUnits( m_parent->GetUserUnits() );
2409 }
2410}
2411
2412
2414{
2415 int selection = m_bottomPostMachining->GetSelection();
2416 // 0: None, 1: Countersink, 2: Counterbore
2417
2418 bool enable = ( selection != 0 );
2419 m_bottomPostMachineSize1Binder.Enable( enable );
2420 m_bottomPostMachineSize2Binder.Enable( enable );
2421 m_bottomPostMachineSize1Label->Enable( enable );
2422 m_bottomPostMachineSize2Label->Enable( enable );
2423
2424 if( selection == 1 ) // Countersink
2425 {
2426 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2427 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
2429
2430 if( m_bottomPostMachineSize2Binder.IsIndeterminate() || m_bottomPostMachineSize2Binder.GetDoubleValue() == 0 )
2431 m_bottomPostMachineSize2Binder.SetDoubleValue( 82.0 );
2432 }
2433 else if( selection == 2 ) // Counterbore
2434 {
2435 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2436 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2437 m_bottomPostMachineSize2Binder.SetUnits( m_parent->GetUserUnits() );
2438 }
2439}
2440
2441
2442void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2443{
2444 if( m_offsetShapeOpt->GetValue() )
2445 {
2446 m_offsetX.SetValue( m_previewPad->GetOffset( m_editLayer ).x );
2447 m_offsetY.SetValue( m_previewPad->GetOffset( m_editLayer ).y );
2448 }
2449
2450 // Show/hide controls depending on m_offsetShapeOpt being enabled
2451 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2452 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2453
2454 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2455 m_notebook->GetPage( i )->Layout();
2456
2457 OnValuesChanged( event );
2458}
2459
2460
2462{
2463 if( m_padToDieOpt->GetValue() && m_currentPad )
2464 m_padToDie.SetValue( m_currentPad->GetPadToDieLength() );
2465
2466 OnValuesChanged( event );
2467}
2468
2469
2471{
2472 if( m_padToDieDelayOpt->GetValue() && m_currentPad )
2473 m_padToDieDelay.SetValue( m_currentPad->GetPadToDieDelay() );
2474
2475 OnValuesChanged( event );
2476}
2477
2478
2479void DIALOG_PAD_PROPERTIES::onModify( wxSpinDoubleEvent& aEvent )
2480{
2481 if( m_initialized )
2482 OnModify();
2483}
2484
2485
2486void DIALOG_PAD_PROPERTIES::onModify( wxCommandEvent& aEvent )
2487{
2488 if( m_initialized )
2489 OnModify();
2490}
2491
2492
2493void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2494{
2495 if( m_initialized )
2496 {
2498 return;
2499
2500 // If the pad size has changed, update the displayed values for rounded rect pads.
2503
2504 redraw();
2505 OnModify();
2506 }
2507}
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.
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(-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 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 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:82
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:610
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:301
void SetBoundary(const BOX2D &aBoundary)
Set limits for view area.
Definition view.h: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:1809
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:961
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:909
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:228
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:55
void SetAnchorPadShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition pad.h:243
void SetAttribute(PAD_ATTRIB aAttribute)
Definition pad.cpp:1370
void SetLocalThermalGapOverride(const std::optional< int > &aOverride)
Definition pad.h:774
PAD_ATTRIB GetAttribute() const
Definition pad.h:563
static LSET PTHMask()
layer set for a through hole pad
Definition pad.cpp:368
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition pad.h:746
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:730
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:187
void SetProperty(PAD_PROP aProperty)
Definition pad.cpp:1443
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition pad.cpp:389
void SetDelta(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.h:298
void SetPadToDieDelay(int aDelay)
Definition pad.h:580
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:196
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition pad.h:136
void SetDrillShape(PAD_DRILL_SHAPE aShape)
Definition pad.h:436
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pad.h:587
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition pad.h:323
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:232
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:940
void SetPosition(const VECTOR2I &aPos) override
Definition pad.h:203
const PADSTACK & Padstack() const
Definition pad.h:333
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition pad.cpp:382
void SetDrillSize(const VECTOR2I &aSize)
Definition pad.h:316
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.h:259
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:3205
static LSET ApertureMask()
layer set for an aperture pad
Definition pad.cpp:396
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition pad.cpp:375
void SetChamferPositions(PCB_LAYER_ID aLayer, int aPositions)
Has meaning only for chamfered rectangular pads.
Definition pad.h:840
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:1451
void SetLocalClearance(std::optional< int > aClearance)
Definition pad.h:584
void SetLayerSet(const LSET &aLayers) override
Definition pad.cpp:1659
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition pad.h:214
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition pad.cpp:902
void SetPadToDieLength(int aLength)
Definition pad.h:577
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition pad.h:264
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