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 // Update Layers dropdown list and selects the "best" layer set for the new pad type:
1286 updatePadLayersList( {}, m_previewPad->GetRemoveUnconnected(), m_previewPad->GetKeepTopBottom() );
1287
1288 m_gbSizerHole->Show( hasHole );
1289 m_staticline71->Show( hasHole );
1290
1291 if( !hasHole )
1292 {
1293 m_holeX.ChangeValue( 0 );
1294 m_holeY.ChangeValue( 0 );
1295 }
1296 else if( m_holeX.GetValue() == 0 )
1297 {
1298 if( m_currentPad )
1299 {
1300 m_holeX.ChangeValue( m_currentPad->GetDrillSize().x );
1301 m_holeY.ChangeValue( m_currentPad->GetDrillSize().y );
1302 }
1303 else
1304 {
1305 m_holeX.ChangeValue( pcbIUScale.mmToIU( DEFAULT_PAD_DRILL_DIAMETER_MM ) );
1306 }
1307 }
1308
1309 if( !hasConnection )
1310 {
1311 m_padNumCtrl->ChangeValue( wxEmptyString );
1312 m_padNetSelector->SetSelectedNetcode( 0 );
1313 m_padToDieOpt->SetValue( false );
1314 m_padToDieDelayOpt->SetValue( false );
1315 }
1316 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1317 {
1318 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1319 m_padNetSelector->SetSelectedNetcode( m_currentPad->GetNetCode() );
1320 }
1321
1323
1324 // For now, padstack controls only enabled for PTH pads
1325 bool enablePadstack = m_padType->GetSelection() == PTH_DLG_TYPE;
1326 m_padstackControls->Show( enablePadstack );
1327
1328 if( !enablePadstack )
1329 {
1330 m_editLayer = F_Cu;
1332 }
1333
1334 // Layout adjustment is needed if the hole details got shown/hidden
1335 m_LeftBoxSizer->Layout();
1336 redraw();
1337
1338 if( m_initialized )
1339 OnModify();
1340}
1341
1342
1343void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1344{
1345 bool hasHole = true;
1346 bool hasConnection = true;
1347
1348 switch( m_padType->GetSelection() )
1349 {
1350 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1351 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1352 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1353 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1354 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1355 }
1356
1357 // Enable/disable hole controls
1358 m_holeShapeLabel->Enable( hasHole );
1359 m_holeShapeCtrl->Enable( hasHole );
1360 m_holeX.Enable( hasHole );
1361 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1362
1363 // Enable/disable number and net
1364 m_padNumLabel->Enable( hasConnection );
1365 m_padNumCtrl->Enable( hasConnection );
1366
1367 if( m_padNetLabel->IsShown() )
1368 {
1369 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1370 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1371 }
1372
1373 // Enable/disable pad length-to-die
1374 m_padToDieOpt->Enable( hasConnection );
1375 m_padToDieDelayOpt->Enable( hasConnection );
1376
1377 if( !m_padToDieOpt->IsEnabled() )
1378 m_padToDieOpt->SetValue( false );
1379
1380 if( !m_padToDieDelayOpt->IsEnabled() )
1381 m_padToDieDelayOpt->SetValue( false );
1382
1383 // We can show/hide this here because it doesn't require the layout to be refreshed.
1384 // All the others have to be done in their event handlers because doing a layout here
1385 // causes infinite looping on MSW.
1386 m_padToDie.Show( m_padToDieOpt->GetValue() );
1387 m_padToDieDelay.Show( m_padToDieDelayOpt->GetValue() );
1388
1389 // Enable/disable Copper Layers control
1390 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1391
1392 LSET cu_set = m_previewPad->GetLayerSet() & LSET::AllCuMask();
1393
1394 switch( m_padType->GetSelection() )
1395 {
1396 case PTH_DLG_TYPE:
1397 if( !cu_set.any() )
1398 m_stackupImagesBook->SetSelection( 3 );
1399 else if( !m_previewPad->GetRemoveUnconnected() )
1400 m_stackupImagesBook->SetSelection( 0 );
1401 else if( m_previewPad->GetKeepTopBottom() )
1402 m_stackupImagesBook->SetSelection( 1 );
1403 else
1404 m_stackupImagesBook->SetSelection( 2 );
1405
1406 break;
1407
1408 case NPTH_DLG_TYPE:
1409 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1410 m_stackupImagesBook->SetSelection( 4 );
1411 else if( cu_set.test( F_Cu ) )
1412 m_stackupImagesBook->SetSelection( 5 );
1413 else if( cu_set.test( B_Cu ) )
1414 m_stackupImagesBook->SetSelection( 6 );
1415 else
1416 m_stackupImagesBook->SetSelection( 7 );
1417
1418 break;
1419
1420 case SMD_DLG_TYPE:
1421 case CONN_DLG_TYPE:
1422 case APERTURE_DLG_TYPE:
1423 m_stackupImagesBook->ChangeSelection( 3 );
1424 break;
1425 }
1426
1427 m_legacyTeardropsWarning->Show( m_board->LegacyTeardrops() );
1428}
1429
1430
1432{
1433 event.Enable( !m_board->LegacyTeardrops() );
1434}
1435
1436
1438{
1439 bool isOnCopperLayer = ( m_previewPad->GetLayerSet() & LSET::AllCuMask() ).any();
1440 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1441}
1442
1443
1444void DIALOG_PAD_PROPERTIES::updatePadLayersList( LSET layer_mask, bool remove_unconnected,
1445 bool keep_top_bottom )
1446{
1448
1449 switch( m_padType->GetSelection() )
1450 {
1451 case PTH_DLG_TYPE:
1452 if( !layer_mask.any() )
1453 layer_mask = PAD::PTHMask();
1454
1455 if( !( layer_mask & LSET::AllCuMask() ).any() )
1456 m_rbCopperLayersSel->SetSelection( 3 );
1457 else if( !remove_unconnected )
1458 m_rbCopperLayersSel->SetSelection( 0 );
1459 else if( keep_top_bottom )
1460 m_rbCopperLayersSel->SetSelection( 1 );
1461 else
1462 m_rbCopperLayersSel->SetSelection( 2 );
1463
1464 break;
1465
1466 case SMD_DLG_TYPE:
1467 if( !layer_mask.any() )
1468 layer_mask = PAD::SMDMask();
1469
1470 if( layer_mask.test( F_Cu ) )
1471 m_rbCopperLayersSel->SetSelection( 0 );
1472 else
1473 m_rbCopperLayersSel->SetSelection( 1 );
1474
1475 break;
1476
1477 case CONN_DLG_TYPE:
1478 if( !layer_mask.any() )
1479 layer_mask = PAD::ConnSMDMask();
1480
1481 if( layer_mask.test( F_Cu ) )
1482 m_rbCopperLayersSel->SetSelection( 0 );
1483 else
1484 m_rbCopperLayersSel->SetSelection( 1 );
1485
1486 break;
1487
1488 case NPTH_DLG_TYPE:
1489 if( !layer_mask.any() )
1490 layer_mask = PAD::UnplatedHoleMask();
1491
1492 if( layer_mask.test( F_Cu ) && layer_mask.test( B_Cu ) )
1493 m_rbCopperLayersSel->SetSelection( 0 );
1494 else if( layer_mask.test( F_Cu ) )
1495 m_rbCopperLayersSel->SetSelection( 1 );
1496 else if( layer_mask.test( B_Cu ) )
1497 m_rbCopperLayersSel->SetSelection( 2 );
1498 else
1499 m_rbCopperLayersSel->SetSelection( 3 );
1500
1501 break;
1502
1503 case APERTURE_DLG_TYPE:
1504 if( !layer_mask.any() )
1505 layer_mask = PAD::ApertureMask();
1506
1507 m_rbCopperLayersSel->SetSelection( 0 );
1508 break;
1509 }
1510
1511 m_layerFrontAdhesive->SetValue( layer_mask[F_Adhes] );
1512 m_layerBackAdhesive->SetValue( layer_mask[B_Adhes] );
1513
1514 m_layerFrontPaste->SetValue( layer_mask[F_Paste] );
1515 m_layerBackPaste->SetValue( layer_mask[B_Paste] );
1516
1517 m_layerFrontSilk->SetValue( layer_mask[F_SilkS] );
1518 m_layerBackSilk->SetValue( layer_mask[B_SilkS] );
1519
1520 m_layerFrontMask->SetValue( layer_mask[F_Mask] );
1521 m_layerBackMask->SetValue( layer_mask[B_Mask] );
1522
1523 m_layerECO1->SetValue( layer_mask[Eco1_User] );
1524 m_layerECO2->SetValue( layer_mask[Eco2_User] );
1525
1526 m_layerUserDwgs->SetValue( layer_mask[Dwgs_User] );
1527}
1528
1529
1531{
1532 bool retVal = DIALOG_SHIM::Show( aShow );
1533
1534 if( aShow )
1535 {
1536 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1537 // wxWidgets needs to have these set when the panel is visible for some reason.
1538 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1546
1547 Layout();
1548 }
1549
1550 return retVal;
1551}
1552
1553
1554void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1555{
1557 redraw();
1558
1559 if( m_initialized )
1560 OnModify();
1561}
1562
1563
1564void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1565{
1567 redraw();
1568
1569 if( m_initialized )
1570 OnModify();
1571}
1572
1573
1575{
1577
1578 wxArrayString error_msgs;
1579 wxArrayString warning_msgs;
1580
1581 m_previewPad->CheckPad( m_parentFrame, true,
1582 [&]( int errorCode, const wxString& msg )
1583 {
1584 if( errorCode == DRCE_PADSTACK_INVALID )
1585 error_msgs.Add( _( "Error: " ) + msg );
1586 else if( errorCode == DRCE_PADSTACK )
1587 warning_msgs.Add( _( "Warning: " ) + msg );
1588 else if( errorCode == DRCE_PAD_TH_WITH_NO_HOLE )
1589 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1590 } );
1591
1592 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1593 {
1594 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1595 : _( "Pad Properties Warnings" );
1596 HTML_MESSAGE_BOX dlg( this, title );
1597
1598 wxArrayString msgs = error_msgs;
1599
1600 for( const wxString& msg : warning_msgs )
1601 msgs.Add( msg );
1602
1603 dlg.ListSet( msgs );
1604
1605 dlg.ShowModal();
1606 }
1607
1608 return error_msgs.GetCount() == 0;
1609}
1610
1611
1613{
1614 if( !m_initialized )
1615 return;
1616
1617 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1618 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view->GetPainter() );
1619 KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings();
1620
1621 m_padPreviewGAL->StopDrawing();
1622
1623 // The layer used to place primitive items selected when editing custom pad shapes
1624 // we use here a layer never used in a pad:
1625 #define SELECTED_ITEMS_LAYER Dwgs_User
1626
1627 view->ClearTopLayers();
1629 view->SetTopLayer( m_editLayer );
1631
1632 static const std::vector<int> topLayers = {
1637 };
1638
1639 for( int layer : topLayers )
1640 view->SetTopLayer( layer );
1641
1642 m_axisOrigin->SetPosition( m_previewPad->GetPosition() );
1643
1644 view->Update( m_previewPad );
1645
1646 // delete previous items if highlight list
1647 while( m_highlight.size() )
1648 {
1649 delete m_highlight.back(); // the dtor also removes item from view
1650 m_highlight.pop_back();
1651 }
1652
1653 BOX2I bbox = m_previewPad->ViewBBox();
1654
1655 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1656 {
1657 // The origin always goes in the middle of the canvas; we want offsetting the pad
1658 // shape to move the pad, not the hole
1659 bbox.Move( -m_previewPad->GetPosition() );
1660 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1661 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1662
1663 // Don't blow up the GAL on too-large numbers
1664 if( maxXExtent > INT_MAX / 4 )
1665 maxXExtent = INT_MAX / 4;
1666
1667 if( maxYExtent > INT_MAX / 4 )
1668 maxYExtent = INT_MAX / 4;
1669
1670 BOX2D viewBox( m_previewPad->GetPosition(), {0, 0} );
1671 BOX2D canvasBox( m_previewPad->GetPosition(), {0, 0} );
1672 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1673 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1674
1675 view->SetBoundary( canvasBox );
1676
1677 // Autozoom
1678 view->SetViewport( viewBox );
1679
1680 m_padPreviewGAL->StartDrawing();
1681 m_padPreviewGAL->Refresh();
1682 }
1683}
1684
1685
1687{
1688 if( !wxDialog::TransferDataToWindow() )
1689 return false;
1690
1691 if( !m_panelGeneral->TransferDataToWindow() )
1692 return false;
1693
1694 if( !m_localSettingsPanel->TransferDataToWindow() )
1695 return false;
1696
1697 return true;
1698}
1699
1700
1702{
1703 BOARD_COMMIT commit( m_parent );
1704
1705 if( !wxDialog::TransferDataFromWindow() )
1706 return false;
1707
1708 if( !m_panelGeneral->TransferDataFromWindow() )
1709 return false;
1710
1711 if( !m_localSettingsPanel->TransferDataFromWindow() )
1712 return false;
1713
1714 if( !padValuesOK() )
1715 return false;
1716
1718 return false;
1719
1720 m_padPreviewGAL->StopDrawing();
1721
1722 PAD_TOOL* padTool = m_parent->GetToolManager()->GetTool<PAD_TOOL>();
1723 padTool->SetLastPadNumber( m_masterPad->GetNumber() );
1724
1725 // m_masterPad is a pattern: ensure there is no net for this pad:
1727
1728 if( !m_currentPad ) // Set current Pad parameters
1729 return true;
1730
1731 commit.Modify( m_currentPad );
1732
1733 // Update values
1734
1735 // transferDataToPad only handles the current edit layer, so m_masterPad isn't accurate
1736 // TODO(JE) this could be cleaner
1737 m_currentPad->SetPadstack( m_previewPad->Padstack() );
1738
1739 m_currentPad->SetAttribute( m_masterPad->GetAttribute() );
1740 m_currentPad->SetFPRelativeOrientation( m_masterPad->GetOrientation() );
1741 m_currentPad->SetPadToDieLength( m_masterPad->GetPadToDieLength() );
1742 m_currentPad->SetPadToDieDelay( m_masterPad->GetPadToDieDelay() );
1743 m_currentPad->SetLayerSet( m_masterPad->GetLayerSet() );
1744 m_currentPad->SetNumber( m_masterPad->GetNumber() );
1745
1746 int padNetcode = NETINFO_LIST::UNCONNECTED;
1747
1748 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1749 if( m_masterPad->GetAttribute() != PAD_ATTRIB::NPTH )
1750 padNetcode = m_padNetSelector->GetSelectedNetcode();
1751
1752 m_currentPad->SetNetCode( padNetcode );
1753
1754 m_currentPad->GetTeardropParams() = m_masterPad->GetTeardropParams();
1755
1756 // Set the fabrication property:
1757 m_currentPad->SetProperty( getSelectedProperty() );
1758
1759 // define the way the clearance area is defined in zones
1760 m_currentPad->SetCustomShapeInZoneOpt( m_masterPad->GetCustomShapeInZoneOpt() );
1761
1762 if( m_currentPad->GetParentFootprint() && m_currentPad->GetParentFootprint()->IsFlipped() )
1763 {
1764 // flip pad (up/down) around its position
1765 m_currentPad->Flip( m_currentPad->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1766 }
1767
1768 m_currentPad->SetPosition( m_masterPad->GetPosition() );
1769
1770 m_parent->SetMsgPanel( m_currentPad );
1771
1772 // redraw the area where the pad was
1773 m_parent->GetCanvas()->Refresh();
1774
1775 commit.Push( _( "Edit Pad Properties" ) );
1776
1777 return true;
1778}
1779
1780
1782{
1783 PAD_PROP prop = PAD_PROP::NONE;
1784
1785 switch( m_choiceFabProperty->GetSelection() )
1786 {
1787 case 0: prop = PAD_PROP::NONE; break;
1788 case 1: prop = PAD_PROP::BGA; break;
1789 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1790 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1791 case 4: prop = PAD_PROP::TESTPOINT; break;
1792 case 5: prop = PAD_PROP::HEATSINK; break;
1793 case 6: prop = PAD_PROP::MECHANICAL; break;
1794 case 7: prop = PAD_PROP::CASTELLATED; break;
1795 case 8: prop = PAD_PROP::PRESSFIT; break;
1796 }
1797
1798 return prop;
1799}
1800
1801
1803{
1804 bool isRound = ( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE );
1805
1806 if( isRound )
1807 {
1808 m_holeXLabel->SetLabel( _( "Diameter:" ) );
1809 m_holeY.Show( false );
1810 }
1811 else
1812 {
1813 m_holeXLabel->SetLabel( _( "Hole size X:" ) );
1814 m_holeY.Show( true );
1815 }
1816
1817 m_holeXLabel->GetParent()->Layout();
1818
1819 if( !isRound )
1820 {
1821 // Disable all
1822 m_backDrillChoice->Enable( false );
1823 m_backDrillTopLayer->Enable( false );
1824 m_backDrillTopLayerLabel->Enable( false );
1825 m_backDrillBottomLayer->Enable( false );
1826 m_backDrillBottomLayerLabel->Enable( false );
1827
1828 m_topPostMachining->Enable( false );
1829 m_topPostMachineSize1Binder.Enable( false );
1830 m_topPostMachineSize2Binder.Enable( false );
1831 m_topPostMachineSize1Label->Enable( false );
1832 m_topPostMachineSize2Label->Enable( false );
1833
1834 m_bottomPostMachining->Enable( false );
1835 m_bottomPostMachineSize1Binder.Enable( false );
1836 m_bottomPostMachineSize2Binder.Enable( false );
1837 m_bottomPostMachineSize1Label->Enable( false );
1838 m_bottomPostMachineSize2Label->Enable( false );
1839 }
1840 else
1841 {
1842 // Enable main choices
1843 m_backDrillChoice->Enable( true );
1844 m_topPostMachining->Enable( true );
1845 m_bottomPostMachining->Enable( true );
1846
1847 // Update sub-controls based on selection
1848 wxCommandEvent dummy;
1852 }
1853}
1854
1855
1857{
1858 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1860 {
1861 m_sizeXLabel->SetLabel( _( "Diameter:" ) );
1862 m_sizeY.Show( false );
1864 m_minTrackWidthHint->SetLabel( _( "d" ) );
1865 m_stLenPercentHint->SetLabel( _( "d" ) );
1866 m_stWidthPercentHint->SetLabel( _( "d" ) );
1867 }
1868 else
1869 {
1870 m_sizeXLabel->SetLabel( _( "Pad size X:" ) );
1871 m_sizeY.Show( true );
1873 m_minTrackWidthHint->SetLabel( _( "w" ) );
1874 m_stLenPercentHint->SetLabel( _( "w" ) );
1875 m_stWidthPercentHint->SetLabel( _( "w" ) );
1876 }
1877
1878 m_sizeXLabel->GetParent()->Layout();
1879 resetSize();
1880 Layout();
1881 m_MainSizer->Fit( this );
1882}
1883
1884
1886{
1887 std::map<PCB_LAYER_ID, PCB_LAYER_ID> newLayerMap; // Map of new-layerss to init-from-layers
1888
1889 auto setMode =
1890 [&]( PADSTACK::MODE mode )
1891 {
1892 PADSTACK oldStack = aPad->Padstack();
1893
1894 aPad->Padstack().SetMode( mode );
1895
1897 [&]( PCB_LAYER_ID layer )
1898 {
1899 if( !oldStack.HasExplicitDefinitionForLayer( layer ) )
1900 {
1901 if( IsInnerCopperLayer( layer ) && layer != PADSTACK::INNER_LAYERS )
1902 newLayerMap[layer] = PADSTACK::INNER_LAYERS;
1903 else
1904 newLayerMap[layer] = F_Cu;
1905 }
1906 } );
1907 };
1908
1909 if( !Validate() )
1910 return false;
1911
1912 if( !m_panelGeneral->Validate() )
1913 return false;
1914
1915 if( !m_localSettingsPanel->Validate() )
1916 return false;
1917
1918 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1919 return false;
1920
1921 switch( m_cbPadstackMode->GetSelection() )
1922 {
1923 default:
1924 case 0: setMode( PADSTACK::MODE::NORMAL ); break;
1925 case 1: setMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1926 case 2: setMode( PADSTACK::MODE::CUSTOM ); break;
1927 }
1928
1929 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1930 aPad->SetShape( m_editLayer, code_shape[m_PadShapeSelector->GetSelection()] );
1931
1934 else
1936
1937 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
1939
1940 aPad->GetTeardropParams().m_Enabled = m_cbTeardrops->GetValue();
1947 aPad->GetTeardropParams().m_CurvedEdges = m_curvedEdges->GetValue();
1949
1950 // Read pad clearances values:
1951 if( m_clearance.IsNull() )
1952 aPad->SetLocalClearance( {} );
1953 else
1954 aPad->SetLocalClearance( m_clearance.GetIntValue() );
1955
1956 if( m_maskMargin.IsNull() )
1957 aPad->SetLocalSolderMaskMargin( {} );
1958 else
1959 aPad->SetLocalSolderMaskMargin( m_maskMargin.GetIntValue() );
1960
1961 aPad->SetLocalSolderPasteMargin( m_pasteMargin.GetOffsetValue() );
1962 aPad->SetLocalSolderPasteMarginRatio( m_pasteMargin.GetRatioValue() );
1963
1964 if( m_spokeWidth.IsNull() )
1966 else
1967 aPad->SetLocalThermalSpokeWidthOverride( m_spokeWidth.GetIntValue() );
1968
1969 if( m_thermalGap.IsNull() )
1970 aPad->SetLocalThermalGapOverride( {} );
1971 else
1972 aPad->SetLocalThermalGapOverride( m_thermalGap.GetIntValue() );
1973
1974 aPad->SetThermalSpokeAngle( m_spokeAngle.GetAngleValue() );
1975
1976 // And rotation
1977 aPad->SetOrientation( m_pad_orientation.GetAngleValue() );
1978
1979 switch( m_ZoneConnectionChoice->GetSelection() )
1980 {
1981 default:
1982 case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1983 case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
1984 case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1985 case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
1986 }
1987
1988 VECTOR2I pos( m_posX.GetIntValue(), m_posY.GetIntValue() );
1989
1990 if( FOOTPRINT* fp = aPad->GetParentFootprint() )
1991 {
1992 pos -= fp->GetPosition();
1993 RotatePoint( pos, -fp->GetOrientation() );
1994 }
1995
1996 aPad->SetPosition( pos );
1997
1998 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1999 {
2001 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeX.GetIntValue() ) );
2002 }
2003 else
2004 {
2006 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeY.GetIntValue() ) );
2007 }
2008
2009 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CIRCLE )
2010 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2011 else
2012 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeY.GetIntValue() ) );
2013
2014 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
2015 // remember DeltaSize.x is the Y size variation
2016 bool error = false;
2017 VECTOR2I delta( 0, 0 );
2018
2019 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::TRAPEZOID )
2020 {
2021 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
2022 if( m_trapAxisCtrl->GetSelection() == 0 )
2023 delta.x = m_trapDelta.GetIntValue();
2024 else
2025 delta.y = m_trapDelta.GetIntValue();
2026
2027 if( delta.x < 0 && delta.x < -aPad->GetSize( m_editLayer ).y )
2028 {
2029 delta.x = -aPad->GetSize( m_editLayer ).y + 2;
2030 error = true;
2031 }
2032
2033 if( delta.x > 0 && delta.x > aPad->GetSize( m_editLayer ).y )
2034 {
2035 delta.x = aPad->GetSize( m_editLayer ).y - 2;
2036 error = true;
2037 }
2038
2039 if( delta.y < 0 && delta.y < -aPad->GetSize( m_editLayer ).x )
2040 {
2041 delta.y = -aPad->GetSize( m_editLayer ).x + 2;
2042 error = true;
2043 }
2044
2045 if( delta.y > 0 && delta.y > aPad->GetSize( m_editLayer ).x )
2046 {
2047 delta.y = aPad->GetSize( m_editLayer ).x - 2;
2048 error = true;
2049 }
2050 }
2051
2052 aPad->SetDelta( m_editLayer, delta );
2053
2054 if( m_offsetShapeOpt->GetValue() )
2055 aPad->SetOffset( m_editLayer, VECTOR2I( m_offsetX.GetIntValue(), m_offsetY.GetIntValue() ) );
2056 else
2057 aPad->SetOffset( m_editLayer, VECTOR2I() );
2058
2059 // Read pad length die
2060 if( m_padToDieOpt->GetValue() )
2061 aPad->SetPadToDieLength( m_padToDie.GetIntValue() );
2062 else
2063 aPad->SetPadToDieLength( 0 );
2064
2065 if( m_padToDieDelayOpt->GetValue() )
2066 aPad->SetPadToDieDelay( m_padToDieDelay.GetIntValue() );
2067 else
2068 aPad->SetPadToDieDelay( 0 );
2069
2070 aPad->SetNumber( m_padNumCtrl->GetValue() );
2071 aPad->SetNetCode( m_padNetSelector->GetSelectedNetcode() );
2072
2073 int chamfers = 0;
2074
2075 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
2076 {
2077 if( m_cbTopLeft->GetValue() )
2078 chamfers |= RECT_CHAMFER_TOP_LEFT;
2079
2080 if( m_cbTopRight->GetValue() )
2081 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2082
2083 if( m_cbBottomLeft->GetValue() )
2084 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2085
2086 if( m_cbBottomRight->GetValue() )
2087 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2088 }
2089 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
2090 {
2091 if( m_cbTopLeft1->GetValue() )
2092 chamfers |= RECT_CHAMFER_TOP_LEFT;
2093
2094 if( m_cbTopRight1->GetValue() )
2095 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2096
2097 if( m_cbBottomLeft1->GetValue() )
2098 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2099
2100 if( m_cbBottomRight1->GetValue() )
2101 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2102 }
2103
2104 aPad->SetChamferPositions( m_editLayer, chamfers );
2105
2106 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
2107 {
2108 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
2109 // that is the minimal area of this pad, and is useful to ensure a hole
2110 // diameter is acceptable, and is used in Gerber files as flashed area
2111 // reference
2113 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2114 }
2115
2116 // Define the way the clearance area is defined in zones. Since all non-custom pad
2117 // shapes are convex to begin with, this really only makes any difference for custom
2118 // pad shapes.
2121
2122 switch( aPad->GetAttribute() )
2123 {
2124 case PAD_ATTRIB::PTH:
2125 break;
2126
2127 case PAD_ATTRIB::CONN:
2128 case PAD_ATTRIB::SMD:
2129 // SMD and PAD_ATTRIB::CONN has no hole.
2130 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
2131 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
2132 // and are intended to be used in virtual edge board connectors
2133 // However we can accept a non null offset,
2134 // mainly to allow complex pads build from a set of basic pad shapes
2135 aPad->SetDrillSize( VECTOR2I( 0, 0 ) );
2136 break;
2137
2138 case PAD_ATTRIB::NPTH:
2139 // Mechanical purpose only:
2140 // no net name, no pad name allowed
2141 aPad->SetNumber( wxEmptyString );
2143 break;
2144
2145 default:
2146 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
2147 break;
2148 }
2149
2150 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::ROUNDRECT )
2151 {
2152 aPad->SetRoundRectRadiusRatio( m_editLayer, m_cornerRatio.GetDoubleValue() / 100.0 );
2153 }
2154 else if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CHAMFERED_RECT )
2155 {
2157 {
2158 aPad->SetChamferRectRatio( m_editLayer, m_mixedChamferRatio.GetDoubleValue() / 100.0 );
2159 aPad->SetRoundRectRadiusRatio( m_editLayer, m_mixedCornerRatio.GetDoubleValue() / 100.0 );
2160 }
2161 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
2162 {
2163 aPad->SetChamferRectRatio( m_editLayer, m_chamferRatio.GetDoubleValue() / 100.0 );
2165 }
2166 }
2167
2169
2170 LSET padLayerMask = LSET();
2171 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
2172
2174
2175 switch( m_padType->GetSelection() )
2176 {
2177 case PTH_DLG_TYPE:
2178 switch( copperLayersChoice )
2179 {
2180 case 0:
2181 // All copper layers
2182 padLayerMask |= LSET::AllCuMask();
2183 break;
2184
2185 case 1:
2186 // Front, back and connected
2187 padLayerMask |= LSET::AllCuMask();
2189 break;
2190
2191 case 2:
2192 // Connected only
2193 padLayerMask |= LSET::AllCuMask();
2195 break;
2196
2197 case 3:
2198 // No copper layers
2199 break;
2200 }
2201
2202 break;
2203
2204 case NPTH_DLG_TYPE:
2205 switch( copperLayersChoice )
2206 {
2207 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
2208 case 1: padLayerMask.set( F_Cu ); break;
2209 case 2: padLayerMask.set( B_Cu ); break;
2210 default: break;
2211 }
2212
2213 break;
2214
2215 case SMD_DLG_TYPE:
2216 case CONN_DLG_TYPE:
2217 switch( copperLayersChoice )
2218 {
2219 case 0: padLayerMask.set( F_Cu ); break;
2220 case 1: padLayerMask.set( B_Cu ); break;
2221 }
2222
2223 break;
2224
2225 case APERTURE_DLG_TYPE:
2226 // no copper layers
2227 break;
2228 }
2229
2230 if( m_layerFrontAdhesive->GetValue() )
2231 padLayerMask.set( F_Adhes );
2232
2233 if( m_layerBackAdhesive->GetValue() )
2234 padLayerMask.set( B_Adhes );
2235
2236 if( m_layerFrontPaste->GetValue() )
2237 padLayerMask.set( F_Paste );
2238
2239 if( m_layerBackPaste->GetValue() )
2240 padLayerMask.set( B_Paste );
2241
2242 if( m_layerFrontSilk->GetValue() )
2243 padLayerMask.set( F_SilkS );
2244
2245 if( m_layerBackSilk->GetValue() )
2246 padLayerMask.set( B_SilkS );
2247
2248 if( m_layerFrontMask->GetValue() )
2249 padLayerMask.set( F_Mask );
2250
2251 if( m_layerBackMask->GetValue() )
2252 padLayerMask.set( B_Mask );
2253
2254 if( m_layerECO1->GetValue() )
2255 padLayerMask.set( Eco1_User );
2256
2257 if( m_layerECO2->GetValue() )
2258 padLayerMask.set( Eco2_User );
2259
2260 if( m_layerUserDwgs->GetValue() )
2261 padLayerMask.set( Dwgs_User );
2262
2263 aPad->SetLayerSet( padLayerMask );
2264
2265 // Save backdrill properties
2266 PADSTACK::DRILL_PROPS secondaryDrill;
2267 secondaryDrill.size = VECTOR2I( m_backDrillBottomSizeBinder.GetIntValue(),
2268 m_backDrillBottomSizeBinder.GetIntValue() );
2269 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2270
2271 PADSTACK::DRILL_PROPS tertiaryDrill;
2272 tertiaryDrill.size = VECTOR2I( m_backDrillTopSizeBinder.GetIntValue(),
2273 m_backDrillTopSizeBinder.GetIntValue() );
2274 tertiaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2275
2276 if( !m_backDrillChoice->GetSelection() )
2277 {
2278 secondaryDrill.start = UNDEFINED_LAYER;
2279 secondaryDrill.end = UNDEFINED_LAYER;
2280 }
2281
2282 if( m_backDrillChoice->GetSelection() == 1 || m_backDrillChoice->GetSelection() == 3 ) // Front
2283 {
2284 tertiaryDrill.start = F_Cu;
2285
2286 if( m_backDrillTopLayer->GetSelection() != wxNOT_FOUND )
2287 tertiaryDrill.end = ToLAYER_ID( (intptr_t)m_backDrillTopLayer->GetClientData( m_backDrillTopLayer->GetSelection() ) );
2288 else
2289 tertiaryDrill.end = UNDEFINED_LAYER;
2290 }
2291
2292 if( m_backDrillChoice->GetSelection() == 2 || m_backDrillChoice->GetSelection() == 3 ) // Back
2293 {
2294 secondaryDrill.start = B_Cu;
2295
2296 if( m_backDrillBottomLayer->GetSelection() != wxNOT_FOUND )
2297 secondaryDrill.end = ToLAYER_ID( (intptr_t)m_backDrillBottomLayer->GetClientData( m_backDrillBottomLayer->GetSelection() ) );
2298 else
2299 secondaryDrill.end = UNDEFINED_LAYER;
2300 }
2301
2302 aPad->Padstack().SecondaryDrill() = secondaryDrill;
2303 aPad->Padstack().TertiaryDrill() = tertiaryDrill;
2304
2305 // Front Post Machining
2306 PADSTACK::POST_MACHINING_PROPS frontPostMachining;
2307
2308 switch( m_topPostMachining->GetSelection() )
2309 {
2310 case 1: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2311 case 2: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2312 default: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2313 }
2314
2315 frontPostMachining.size = m_topPostMachineSize1Binder.GetIntValue();
2316
2317 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2318 frontPostMachining.angle = KiROUND( m_topPostMachineSize2Binder.GetDoubleValue() * 10.0 );
2319 else
2320 frontPostMachining.depth = m_topPostMachineSize2Binder.GetIntValue();
2321
2322 aPad->Padstack().FrontPostMachining() = frontPostMachining;
2323
2324 // Back Post Machining
2325 PADSTACK::POST_MACHINING_PROPS backPostMachining;
2326
2327 switch( m_bottomPostMachining->GetSelection() )
2328 {
2329 case 1: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2330 case 2: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2331 default: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2332 }
2333
2334 backPostMachining.size = m_bottomPostMachineSize1Binder.GetIntValue();
2335
2336 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2337 backPostMachining.angle = KiROUND( m_bottomPostMachineSize2Binder.GetDoubleValue() * 10.0 );
2338 else
2339 backPostMachining.depth = m_bottomPostMachineSize2Binder.GetIntValue();
2340
2341 aPad->Padstack().BackPostMachining() = backPostMachining;
2342
2343 // If we created new layers, initialize them
2344 for( const auto& [newLayer, initFromLayer] : newLayerMap )
2345 {
2346 if( newLayer != m_editLayer && newLayer != initFromLayer )
2347 aPad->Padstack().CopperLayer( newLayer ) = aPad->Padstack().CopperLayer( initFromLayer );
2348 }
2349
2350 return !error;
2351}
2352
2353
2354
2355
2356void DIALOG_PAD_PROPERTIES::onBackDrillChoice( wxCommandEvent& event )
2357{
2358 int selection = m_backDrillChoice->GetSelection();
2359 // 0: None, 1: Top, 2: Bottom, 3: Both
2360
2361 bool enableTop = ( selection == 1 || selection == 3 );
2362 bool enableBottom = ( selection == 2 || selection == 3 );
2363
2364 m_backDrillTopSizeBinder.Enable( enableTop );
2365 m_backDrillTopLayer->Enable( enableTop );
2366 m_backDrillTopLayerLabel->Enable( enableTop );
2367
2368 m_backDrillBottomSizeBinder.Enable( enableBottom );
2369 m_backDrillBottomLayer->Enable( enableBottom );
2370 m_backDrillBottomLayerLabel->Enable( enableBottom );
2371
2372}
2373
2374
2376{
2377 int selection = m_topPostMachining->GetSelection();
2378 // 0: None, 1: Countersink, 2: Counterbore
2379
2380 bool enable = ( selection != 0 );
2381 m_topPostMachineSize1Binder.Enable( enable );
2382 m_topPostMachineSize2Binder.Enable( enable );
2383 m_topPostMachineSize1Label->Enable( enable );
2384 m_topPostMachineSize2Label->Enable( enable );
2385
2386 if( selection == 1 ) // Countersink
2387 {
2388 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2389 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
2391
2392 if( m_topPostMachineSize2Binder.IsIndeterminate() || m_topPostMachineSize2Binder.GetDoubleValue() == 0 )
2393 m_topPostMachineSize2Binder.SetDoubleValue( 82.0 );
2394 }
2395 else if( selection == 2 ) // Counterbore
2396 {
2397 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2398 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2399 m_topPostMachineSize2Binder.SetUnits( m_parent->GetUserUnits() );
2400 }
2401}
2402
2403
2405{
2406 int selection = m_bottomPostMachining->GetSelection();
2407 // 0: None, 1: Countersink, 2: Counterbore
2408
2409 bool enable = ( selection != 0 );
2410 m_bottomPostMachineSize1Binder.Enable( enable );
2411 m_bottomPostMachineSize2Binder.Enable( enable );
2412 m_bottomPostMachineSize1Label->Enable( enable );
2413 m_bottomPostMachineSize2Label->Enable( enable );
2414
2415 if( selection == 1 ) // Countersink
2416 {
2417 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2418 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
2420
2421 if( m_bottomPostMachineSize2Binder.IsIndeterminate() || m_bottomPostMachineSize2Binder.GetDoubleValue() == 0 )
2422 m_bottomPostMachineSize2Binder.SetDoubleValue( 82.0 );
2423 }
2424 else if( selection == 2 ) // Counterbore
2425 {
2426 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2427 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2428 m_bottomPostMachineSize2Binder.SetUnits( m_parent->GetUserUnits() );
2429 }
2430}
2431
2432
2433void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2434{
2435 if( m_offsetShapeOpt->GetValue() )
2436 {
2437 m_offsetX.SetValue( m_previewPad->GetOffset( m_editLayer ).x );
2438 m_offsetY.SetValue( m_previewPad->GetOffset( m_editLayer ).y );
2439 }
2440
2441 // Show/hide controls depending on m_offsetShapeOpt being enabled
2442 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2443 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2444
2445 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2446 m_notebook->GetPage( i )->Layout();
2447
2448 OnValuesChanged( event );
2449}
2450
2451
2453{
2454 if( m_padToDieOpt->GetValue() && m_currentPad )
2455 m_padToDie.SetValue( m_currentPad->GetPadToDieLength() );
2456
2457 OnValuesChanged( event );
2458}
2459
2460
2462{
2463 if( m_padToDieDelayOpt->GetValue() && m_currentPad )
2464 m_padToDieDelay.SetValue( m_currentPad->GetPadToDieDelay() );
2465
2466 OnValuesChanged( event );
2467}
2468
2469
2470void DIALOG_PAD_PROPERTIES::onModify( wxSpinDoubleEvent& aEvent )
2471{
2472 if( m_initialized )
2473 OnModify();
2474}
2475
2476
2477void DIALOG_PAD_PROPERTIES::onModify( wxCommandEvent& aEvent )
2478{
2479 if( m_initialized )
2480 OnModify();
2481}
2482
2483
2484void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2485{
2486 if( m_initialized )
2487 {
2489 return;
2490
2491 // If the pad size has changed, update the displayed values for rounded rect pads.
2494
2495 redraw();
2496 OnModify();
2497 }
2498}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
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 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
void updatePadLayersList(LSET layer_mask, bool remove_unconnected, bool keep_top_bottom)
Updates the CheckBox states in pad layers list, based on the layer_mask (if non-empty) or the default...
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:548
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:300
void SetBoundary(const BOX2D &aBoundary)
Set limits for view area.
Definition view.h:287
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:1727
void SetLayerVisible(int aLayer, bool aVisible=true)
Control the visibility of a particular layer.
Definition view.h:401
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:203
void ClearTopLayers()
Remove all layers from the on-the-top set (they are no longer displayed over the rest of layers).
Definition view.cpp:899
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:847
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:221
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:247
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:364
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:357
DRILL_PROPS & TertiaryDrill()
Definition padstack.h:354
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:351
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:360
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:1348
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:369
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:1421
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition pad.cpp:390
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:941
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:383
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:3165
static LSET ApertureMask()
layer set for an aperture pad
Definition pad.cpp:397
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition pad.cpp:376
void SetChamferPositions(PCB_LAYER_ID aLayer, int aPositions)
Has meaning only for chamfered rectangular pads.
Definition pad.h:831
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:1429
void SetLocalClearance(std::optional< int > aClearance)
Definition pad.h:584
void SetLayerSet(const LSET &aLayers) override
Definition pad.cpp:1619
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:903
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:677
@ 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:699
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:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
@ 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