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 ),
158{
159 SetName( PAD_PROPERTIES_DLG_NAME );
161
162 m_currentPad = aPad; // aPad can be NULL, if the dialog is called
163 // from the footprint editor to set default pad setup
164
165 m_board = m_parent->GetBoard();
166
167 // Configure display origin transforms
170
171 m_padNetSelector->SetNetInfo( &m_board->GetNetInfo() );
172
174
178
179 m_masterPad = m_parent->GetDesignSettings().m_Pad_Master.get();
180 m_previewPad = new PAD( (FOOTPRINT*) nullptr );
181
182 if( aPad )
183 {
184 SetTitle( _( "Pad Properties" ) );
185
186 *m_previewPad = *aPad;
187 m_previewPad->GetTeardropParams() = aPad->GetTeardropParams();
188 m_previewPad->ClearFlags( SELECTED|BRIGHTENED );
189 }
190 else
191 {
192 SetTitle( _( "Default Pad Properties for Add Pad Tool" ) );
193
195 m_previewPad->GetTeardropParams() = m_masterPad->GetTeardropParams();
196 }
197
198 // TODO(JE) padstacks: should this be re-run when pad mode changes?
199 // Pads have a hardcoded internal rounding ratio which is 0.25 by default, even if
200 // they're not a rounded shape. This makes it hard to detect an intentional 0.25
201 // ratio, or one that's only there because it's the PAD default.
202 // Zero it out here to mark that we should recompute a better ratio if the user
203 // selects a pad shape which would need a default rounding ratio computed for it
204 m_previewPad->Padstack().ForEachUniqueLayer(
205 [&]( PCB_LAYER_ID aLayer )
206 {
208 m_previewPad->SetRoundRectRadiusRatio( aLayer, 0.0 );
209 } );
210
211 if( m_isFpEditor )
212 {
213 m_padNetLabel->Show( false );
214 m_padNetSelector->Show( false );
215 }
216
217 m_FlippedWarningSizer->Show( false );
218
219 // Pad needs to have a parent for painting; use the parent board for its design settings
220 if( !m_previewPad->GetParent() )
221 m_previewPad->SetParent( m_board );
222
228 m_pad_orientation.SetPrecision( 3 );
229
231 m_spokeAngle.SetPrecision( 3 );
232
233 m_pasteMargin.SetNegativeZero();
234
236 m_pasteMarginRatio.SetNegativeZero();
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( cmd_event );
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 if( m_isFpEditor && m_board->GetFirstFootprint() )
691 {
692 switch( m_board->GetFirstFootprint()->GetAttributes() )
693 {
695 m_previewPad->SetAttribute( PAD_ATTRIB::PTH );
696
697 if( m_previewPad->GetDrillSizeX() == 0 )
698 m_board->GetDesignSettings().SetDefaultMasterPad();
699
700 break;
701
703 m_previewPad->SetLayerSet( PAD::SMDMask() );
704 m_previewPad->SetAttribute( PAD_ATTRIB::SMD );
705 break;
706 }
707 }
708 }
709
711
712 m_padNetSelector->SetSelectedNetcode( m_previewPad->GetNetCode() );
713
714 // Display current pad parameters units:
715 m_posX.ChangeValue( absPos.x );
716 m_posY.ChangeValue( absPos.y );
717
718 m_holeX.ChangeValue( m_previewPad->GetDrillSize().x );
719 m_holeY.ChangeValue( m_previewPad->GetDrillSize().y );
720
721 // TODO(JE) padstacks -- does this need to be saved/restored every time the layer changes?
722 // Store the initial thermal spoke angle to restore it, because some initializations
723 // can change this value (mainly after m_PadShapeSelector initializations)
724 EDA_ANGLE spokeInitialAngle = m_previewPad->GetThermalSpokeAngle();
725
727
728 m_padToDieOpt->SetValue( m_previewPad->GetPadToDieLength() != 0 );
729 m_padToDie.ChangeValue( m_previewPad->GetPadToDieLength() );
730
731 m_padToDieDelayOpt->SetValue( m_previewPad->GetPadToDieDelay() != 0 );
732 m_padToDieDelay.ChangeValue( m_previewPad->GetPadToDieDelay() );
733
734 if( m_previewPad->GetLocalClearance().has_value() )
735 m_clearance.ChangeValue( m_previewPad->GetLocalClearance().value() );
736 else
737 m_clearance.ChangeValue( wxEmptyString );
738
739 if( m_previewPad->GetLocalSolderMaskMargin().has_value() )
740 m_maskMargin.ChangeValue( m_previewPad->GetLocalSolderMaskMargin().value() );
741 else
742 m_maskMargin.ChangeValue( wxEmptyString );
743
744 if( m_previewPad->GetLocalSolderPasteMargin().has_value() )
745 m_pasteMargin.ChangeValue( m_previewPad->GetLocalSolderPasteMargin().value() );
746 else
747 m_pasteMargin.ChangeValue( wxEmptyString );
748
749 if( m_previewPad->GetLocalSolderPasteMarginRatio().has_value() )
750 m_pasteMarginRatio.ChangeDoubleValue( m_previewPad->GetLocalSolderPasteMarginRatio().value() * 100.0 );
751 else
752 m_pasteMarginRatio.ChangeValue( wxEmptyString );
753
754 if( m_previewPad->GetLocalThermalSpokeWidthOverride().has_value() )
755 m_spokeWidth.ChangeValue( m_previewPad->GetLocalThermalSpokeWidthOverride().value() );
756 else
757 m_spokeWidth.SetNull();
758
759 if( m_previewPad->GetLocalThermalGapOverride().has_value() )
760 m_thermalGap.ChangeValue( m_previewPad->GetLocalThermalGapOverride().value() );
761 else
762 m_thermalGap.SetNull();
763
764 m_spokeAngle.ChangeAngleValue( m_previewPad->GetThermalSpokeAngle() );
765 m_pad_orientation.ChangeAngleValue( m_previewPad->GetOrientation() );
766
767 m_cbTeardrops->SetValue( m_previewPad->GetTeardropParams().m_Enabled );
768 m_cbTeardropsUseNextTrack->SetValue( m_previewPad->GetTeardropParams().m_AllowUseTwoTracks );
769 m_cbPreferZoneConnection->SetValue( !m_previewPad->GetTeardropParams().m_TdOnPadsInZones );
770 m_teardropMaxLenSetting.SetValue( m_previewPad->GetTeardropParams().m_TdMaxLen );
771 m_teardropMaxHeightSetting.SetValue( m_previewPad->GetTeardropParams().m_TdMaxWidth );
772 m_spTeardropLenPercent->SetValue( m_previewPad->GetTeardropParams().m_BestLengthRatio *100 );
773 m_spTeardropSizePercent->SetValue( m_previewPad->GetTeardropParams().m_BestWidthRatio *100 );
774 m_spTeardropHDPercent->SetValue( m_previewPad->GetTeardropParams().m_WidthtoSizeFilterRatio*100 );
775 m_curvedEdges->SetValue( m_previewPad->GetTeardropParams().m_CurvedEdges );
776
777 switch( m_previewPad->GetLocalZoneConnection() )
778 {
779 default:
780 case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
781 case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
782 case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
783 case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
784 }
785
786 if( m_previewPad->GetCustomShapeInZoneOpt() == CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL )
787 m_ZoneCustomPadShape->SetSelection( 1 );
788 else
789 m_ZoneCustomPadShape->SetSelection( 0 );
790
791 // Type of pad selection
792 bool aperture =
793 m_previewPad->GetAttribute() == PAD_ATTRIB::SMD && m_previewPad->IsAperturePad();
794
795 if( aperture )
796 {
797 m_padType->SetSelection( APERTURE_DLG_TYPE );
798 }
799 else
800 {
801 switch( m_previewPad->GetAttribute() )
802 {
803 case PAD_ATTRIB::PTH: m_padType->SetSelection( PTH_DLG_TYPE ); break;
804 case PAD_ATTRIB::SMD: m_padType->SetSelection( SMD_DLG_TYPE ); break;
805 case PAD_ATTRIB::CONN: m_padType->SetSelection( CONN_DLG_TYPE ); break;
806 case PAD_ATTRIB::NPTH: m_padType->SetSelection( NPTH_DLG_TYPE ); break;
807 }
808 }
809
810 switch( m_previewPad->GetProperty() )
811 {
812 case PAD_PROP::NONE: m_choiceFabProperty->SetSelection( 0 ); break;
813 case PAD_PROP::BGA: m_choiceFabProperty->SetSelection( 1 ); break;
814 case PAD_PROP::FIDUCIAL_LOCAL: m_choiceFabProperty->SetSelection( 2 ); break;
815 case PAD_PROP::FIDUCIAL_GLBL: m_choiceFabProperty->SetSelection( 3 ); break;
816 case PAD_PROP::TESTPOINT: m_choiceFabProperty->SetSelection( 4 ); break;
817 case PAD_PROP::HEATSINK: m_choiceFabProperty->SetSelection( 5 ); break;
818 case PAD_PROP::MECHANICAL: m_choiceFabProperty->SetSelection( 6 ); break;
819 case PAD_PROP::CASTELLATED: m_choiceFabProperty->SetSelection( 7 ); break;
820 case PAD_PROP::PRESSFIT: m_choiceFabProperty->SetSelection( 8 ); break;
821 }
822
823 if( m_previewPad->GetDrillShape() != PAD_DRILL_SHAPE::OBLONG )
824 m_holeShapeCtrl->SetSelection( 0 );
825 else
826 m_holeShapeCtrl->SetSelection( 1 );
827
828 // Backdrill properties
829 const PADSTACK::DRILL_PROPS& secondaryDrill = m_previewPad->Padstack().SecondaryDrill();
830 const PADSTACK::DRILL_PROPS& tertiaryDrill = m_previewPad->Padstack().TertiaryDrill();
831 bool hasBackdrill = secondaryDrill.start != UNDEFINED_LAYER;
832 bool hasTertiaryDrill = tertiaryDrill.start != UNDEFINED_LAYER;
833
834 int selection = hasBackdrill
835 ? ( hasTertiaryDrill ? 3 : 2 )
836 : ( hasTertiaryDrill ? 1 : 0 );
837 m_backDrillChoice->SetSelection( selection );
838
839 if( !hasBackdrill )
840 {
841 m_backDrillBottomSizeBinder.SetValue( 0 );
842 }
843 else
844 {
845 m_backDrillBottomSizeBinder.SetValue( secondaryDrill.size.x );
846
847 for( unsigned int i = 0; i < m_backDrillBottomLayer->GetCount(); ++i )
848 {
849 if( (PCB_LAYER_ID)(intptr_t)m_backDrillBottomLayer->GetClientData( i ) == secondaryDrill.end )
850 {
851 m_backDrillBottomLayer->SetSelection( i );
852 break;
853 }
854 }
855 }
856
857 if( !hasTertiaryDrill )
858 {
859 m_backDrillTopSizeBinder.SetValue( 0 );
860 }
861 else
862 {
863 m_backDrillTopSizeBinder.SetValue( tertiaryDrill.size.x );
864
865 for( unsigned int i = 0; i < m_backDrillTopLayer->GetCount(); ++i )
866 {
867 if( (PCB_LAYER_ID)(intptr_t)m_backDrillTopLayer->GetClientData( i ) == tertiaryDrill.end )
868 {
869 m_backDrillTopLayer->SetSelection( i );
870 break;
871 }
872 }
873 }
874
875 // Post machining
876 const PADSTACK::POST_MACHINING_PROPS& frontPostMachining = m_previewPad->Padstack().FrontPostMachining();
877
878 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
879 m_topPostMachining->SetSelection( 2 );
880 else if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
881 m_topPostMachining->SetSelection( 1 );
882 else
883 m_topPostMachining->SetSelection( 0 );
884
885 m_topPostMachineSize1Binder.SetValue( frontPostMachining.size );
886
887 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
888 m_topPostMachineSize2Binder.SetValue( frontPostMachining.angle );
889 else
890 m_topPostMachineSize2Binder.SetValue( frontPostMachining.depth );
891
892 const PADSTACK::POST_MACHINING_PROPS& backPostMachining = m_previewPad->Padstack().BackPostMachining();
893
894 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
895 m_bottomPostMachining->SetSelection( 2 );
896 else if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
897 m_bottomPostMachining->SetSelection( 1 );
898 else
899 m_bottomPostMachining->SetSelection( 0 );
900
901 m_bottomPostMachineSize1Binder.SetValue( backPostMachining.size );
902
903 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
904 m_bottomPostMachineSize2Binder.SetValue( backPostMachining.angle );
905 else
906 m_bottomPostMachineSize2Binder.SetValue( backPostMachining.depth );
907
908
909 updatePadLayersList( m_previewPad->GetLayerSet(), m_previewPad->GetRemoveUnconnected(),
910 m_previewPad->GetKeepTopBottom() );
911
912 // Update some dialog widgets state (Enable/disable options):
913 wxCommandEvent cmd_event;
914 OnPadShapeSelection( cmd_event );
915 OnOffsetCheckbox( cmd_event );
917
918 // Restore thermal spoke angle to its initial value, because it can be modified
919 // by the call to OnPadShapeSelection()
920 m_previewPad->SetThermalSpokeAngle( spokeInitialAngle );
921 m_spokeAngle.SetAngleValue( m_previewPad->GetThermalSpokeAngle() );
922}
923
924
926{
927 m_primitives = m_previewPad->GetPrimitives( m_editLayer );
928
929 m_sizeX.ChangeValue( m_previewPad->GetSize( m_editLayer ).x );
930 m_sizeY.ChangeValue( m_previewPad->GetSize( m_editLayer ).y );
931
932 m_offsetShapeOpt->SetValue( m_previewPad->GetOffset( m_editLayer ) != VECTOR2I() );
933 m_offsetX.ChangeValue( m_previewPad->GetOffset( m_editLayer ).x );
934 m_offsetY.ChangeValue( m_previewPad->GetOffset( m_editLayer ).y );
935
936 if( m_previewPad->GetDelta( m_editLayer ).x )
937 {
938 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).x );
939 m_trapAxisCtrl->SetSelection( 0 );
940 }
941 else
942 {
943 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).y );
944 m_trapAxisCtrl->SetSelection( 1 );
945 }
946
947 switch( m_previewPad->GetShape( m_editLayer ) )
948 {
949 default:
950 case PAD_SHAPE::CIRCLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
951 case PAD_SHAPE::OVAL: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_OVAL ); break;
952 case PAD_SHAPE::RECTANGLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_RECT ); break;
955
957 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) > 0.0 )
959 else
961 break;
962
964 if( m_previewPad->GetAnchorPadShape( m_editLayer ) == PAD_SHAPE::RECTANGLE )
966 else
968 break;
969 }
970
971 int chamferPositions = m_previewPad->GetChamferPositions( m_editLayer );
972
973 m_cbTopLeft->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
974 m_cbTopLeft1->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
975 m_cbTopRight->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
976 m_cbTopRight1->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
977 m_cbBottomLeft->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
978 m_cbBottomLeft1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
979 m_cbBottomRight->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
980 m_cbBottomRight1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
981
983}
984
985
987{
988 // NOTE: synchronize changes here with DIALOG_TRACK_VIA_PROPERTIES::afterPadstackModeChanged
989
990 wxCHECK_MSG( m_board, /* void */, "Expected valid board in afterPadstackModeChanged" );
991 m_cbEditLayer->Clear();
992
993 switch( m_previewPad->Padstack().Mode() )
994 {
996 m_cbPadstackMode->SetSelection( 0 );
997 m_cbEditLayer->Append( m_board->GetLayerName( F_Cu ) );
998 m_cbEditLayer->Disable();
1000 m_editLayerCtrlMap = { { 0, F_Cu } };
1001 break;
1002
1004 {
1005 m_cbPadstackMode->SetSelection( 1 );
1006 m_cbEditLayer->Enable();
1007
1008 std::vector choices = {
1009 m_board->GetLayerName( F_Cu ),
1010 _( "Inner Layers" ),
1011 m_board->GetLayerName( B_Cu )
1012 };
1013
1014 m_cbEditLayer->Append( choices );
1015
1017 { 0, F_Cu },
1019 { 2, B_Cu }
1020 };
1021
1022 if( m_editLayer != F_Cu && m_editLayer != B_Cu )
1024
1025 break;
1026 }
1027
1029 {
1030 m_cbPadstackMode->SetSelection( 2 );
1031 m_cbEditLayer->Enable();
1032 LSET layers = LSET::AllCuMask() & m_board->GetEnabledLayers();
1033
1034 for( PCB_LAYER_ID layer : layers.UIOrder() )
1035 {
1036 int idx = m_cbEditLayer->Append( m_board->GetLayerName( layer ) );
1037 m_editLayerCtrlMap[idx] = layer;
1038 }
1039
1040 break;
1041 }
1042 }
1043
1044 for( const auto& [idx, layer] : m_editLayerCtrlMap )
1045 {
1046 if( layer == m_editLayer )
1047 {
1048 m_cbEditLayer->SetSelection( idx );
1049 break;
1050 }
1051 }
1052}
1053
1054
1055void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
1056{
1057 redraw();
1058 event.Skip();
1059}
1060
1061
1062void DIALOG_PAD_PROPERTIES::onChangePadMode( wxCommandEvent& event )
1063{
1064 m_sketchPreview = m_cbShowPadOutline->GetValue();
1065
1066 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1067
1068 // fix the pad render mode (filled/not filled)
1069 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
1070
1071 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
1072 settings->SetHighContrast( false );
1073 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
1074
1075 redraw();
1076}
1077
1078
1080{
1081 switch( m_PadShapeSelector->GetSelection() )
1082 {
1084 case CHOICE_SHAPE_OVAL:
1085 case CHOICE_SHAPE_RECT:
1086 m_shapePropsBook->SetSelection( 0 );
1087 break;
1088
1090 m_shapePropsBook->SetSelection( 1 );
1091 break;
1092
1094 {
1095 m_shapePropsBook->SetSelection( 2 );
1096
1097 // Reasonable defaults
1098 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0 )
1099 {
1100 const double ipcRadiusRatio =
1102 m_cornerRatio.ChangeDoubleValue( ipcRadiusRatio * 100 );
1103 }
1104
1105 break;
1106 }
1107
1109 m_shapePropsBook->SetSelection( 3 );
1110
1111 // Reasonable default
1112 if( m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1113 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1114
1115 // Ensure the displayed value is up to date:
1116 m_chamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1117
1118 // A reasonable default is one corner chamfered (usual for some SMD pads).
1119 if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
1120 && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
1121 {
1122 m_cbTopLeft->SetValue( true );
1123 m_cbTopRight->SetValue( false );
1124 m_cbBottomLeft->SetValue( false );
1125 m_cbBottomRight->SetValue( false );
1126 }
1127
1128 break;
1129
1131 m_shapePropsBook->SetSelection( 4 );
1132
1133 // Reasonable defaults
1134 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0
1135 && m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1136 {
1137 const double ipcRadiusRatio =
1139 m_previewPad->SetRoundRectRadiusRatio( m_editLayer, ipcRadiusRatio );
1140 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1141 }
1142
1143 // Ensure the displayed values are up to date:
1144 m_mixedChamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1145 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
1146 break;
1147
1148 case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE::CUSTOM, circular anchor
1149 case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE::CUSTOM, rect anchor
1150 m_shapePropsBook->SetSelection( 0 );
1151 break;
1152 }
1153
1154 // Note: must do this before enabling/disabling m_sizeY as we're using that as a flag to see
1155 // what the last shape was.
1156 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE )
1157 {
1158 if( m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_90 )
1159 m_spokeAngle.SetAngleValue( ANGLE_45 );
1160 }
1161 else
1162 {
1163 if( !m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_45 )
1164 m_spokeAngle.SetAngleValue( ANGLE_90 );
1165 }
1166
1167 // Readjust props book size
1168 wxSize size = m_shapePropsBook->GetSize();
1169 size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
1170 m_shapePropsBook->SetMaxSize( size );
1171
1172 m_sizeY.Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE
1174
1175 m_offsetShapeOpt->Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE );
1176
1177 if( !m_offsetShapeOpt->IsEnabled() )
1178 m_offsetShapeOpt->SetValue( false );
1179
1180 // Show/hide controls depending on m_offsetShapeOpt being enabled
1181 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
1182 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
1183
1186
1187 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
1188 m_notebook->GetPage( i )->Layout();
1189
1190 // Resize the dialog if its height is too small to show all widgets:
1191 if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
1192 m_MainSizer->SetSizeHints( this );
1193
1195 redraw();
1196
1197 if( m_initialized )
1198 OnModify();
1199}
1200
1201
1203{
1204 if( m_holeShapeCtrl->GetSelection() != CHOICE_SHAPE_CIRCLE )
1205 {
1206 bool hasBackdrill = ( m_backDrillChoice->GetSelection() != 0 );
1207 bool hasTopPost = ( m_topPostMachining->GetSelection() != 0 );
1208 bool hasBottomPost = ( m_bottomPostMachining->GetSelection() != 0 );
1209
1210 if( hasBackdrill || hasTopPost || hasBottomPost )
1211 {
1212 if( wxMessageBox( _( "Switching to non-circular hole will disable backdrills and post-machining. Continue?" ),
1213 _( "Warning" ), wxOK | wxCANCEL | wxICON_WARNING, this ) != wxOK )
1214 {
1215 m_holeShapeCtrl->SetSelection( CHOICE_SHAPE_CIRCLE );
1216 return;
1217 }
1218 }
1219 }
1220
1223 redraw();
1224
1225 if( m_initialized )
1226 OnModify();
1227}
1228
1229
1230void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
1231{
1233 redraw();
1234
1235 if( m_initialized )
1236 OnModify();
1237}
1238
1239
1241{
1242 m_rbCopperLayersSel->Clear();
1243
1244 switch( m_padType->GetSelection() )
1245 {
1246 case PTH_DLG_TYPE:
1247 m_rbCopperLayersSel->Append( _( "All copper layers" ) );
1248 m_rbCopperLayersSel->Append( wxString::Format( _( "%s, %s and connected layers" ),
1249 m_board->GetLayerName( F_Cu ),
1250 m_board->GetLayerName( B_Cu ) ) );
1251 m_rbCopperLayersSel->Append( _( "Connected layers only" ) );
1252 m_rbCopperLayersSel->Append( _( "None" ) );
1253 break;
1254
1255 case NPTH_DLG_TYPE:
1256 m_rbCopperLayersSel->Append( wxString::Format( _( "%s and %s" ),
1257 m_board->GetLayerName( F_Cu ),
1258 m_board->GetLayerName( B_Cu ) ) );
1259 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1260 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1261 m_rbCopperLayersSel->Append( _( "None" ) );
1262 break;
1263
1264 case SMD_DLG_TYPE:
1265 case CONN_DLG_TYPE:
1266 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1267 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1268 break;
1269
1270 case APERTURE_DLG_TYPE:
1271 m_rbCopperLayersSel->Append( _( "None" ) );
1272 break;
1273 }
1274
1275 m_backDrillTopLayer->Clear();
1276 m_backDrillBottomLayer->Clear();
1277
1278 for( PCB_LAYER_ID layerId : m_board->GetEnabledLayers().UIOrder() )
1279 {
1280 if( IsCopperLayer( layerId ) )
1281 {
1282 wxString layerName = m_board->GetLayerName( layerId );
1283 m_backDrillTopLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1284 m_backDrillBottomLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1285 }
1286 }
1287}
1288
1289
1290void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
1291{
1292 bool hasHole = true;
1293 bool hasConnection = true;
1294
1295 switch( m_padType->GetSelection() )
1296 {
1297 case PTH_DLG_TYPE: hasHole = true; hasConnection = true; break;
1298 case SMD_DLG_TYPE: hasHole = false; hasConnection = true; break;
1299 case CONN_DLG_TYPE: hasHole = false; hasConnection = true; break;
1300 case NPTH_DLG_TYPE: hasHole = true; hasConnection = false; break;
1301 case APERTURE_DLG_TYPE: hasHole = false; hasConnection = false; break;
1302 }
1303
1304 // Update Layers dropdown list and selects the "best" layer set for the new pad type:
1305 updatePadLayersList( {}, m_previewPad->GetRemoveUnconnected(),
1306 m_previewPad->GetKeepTopBottom() );
1307
1308 m_gbSizerHole->Show( hasHole );
1309 m_staticline71->Show( hasHole );
1310
1311 if( !hasHole )
1312 {
1313 m_holeX.ChangeValue( 0 );
1314 m_holeY.ChangeValue( 0 );
1315 }
1316 else if( m_holeX.GetValue() == 0 )
1317 {
1318 if( m_currentPad )
1319 {
1320 m_holeX.ChangeValue( m_currentPad->GetDrillSize().x );
1321 m_holeY.ChangeValue( m_currentPad->GetDrillSize().y );
1322 }
1323 else
1324 {
1325 m_holeX.ChangeValue( pcbIUScale.mmToIU( DEFAULT_PAD_DRILL_DIAMETER_MM ) );
1326 }
1327 }
1328
1329 if( !hasConnection )
1330 {
1331 m_padNumCtrl->ChangeValue( wxEmptyString );
1332 m_padNetSelector->SetSelectedNetcode( 0 );
1333 m_padToDieOpt->SetValue( false );
1334 m_padToDieDelayOpt->SetValue( false );
1335 }
1336 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1337 {
1338 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1339 m_padNetSelector->SetSelectedNetcode( m_currentPad->GetNetCode() );
1340 }
1341
1343
1344 // For now, padstack controls only enabled for PTH pads
1345 bool enablePadstack = m_padType->GetSelection() == PTH_DLG_TYPE;
1346 m_padstackControls->Show( enablePadstack );
1347
1348 if( !enablePadstack )
1349 {
1350 m_editLayer = F_Cu;
1352 }
1353
1354 // Layout adjustment is needed if the hole details got shown/hidden
1355 m_LeftBoxSizer->Layout();
1356 redraw();
1357
1358 if( m_initialized )
1359 OnModify();
1360}
1361
1362
1363void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1364{
1365 bool hasHole = true;
1366 bool hasConnection = true;
1367
1368 switch( m_padType->GetSelection() )
1369 {
1370 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1371 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1372 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1373 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1374 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1375 }
1376
1377 // Enable/disable hole controls
1378 m_holeShapeLabel->Enable( hasHole );
1379 m_holeShapeCtrl->Enable( hasHole );
1380 m_holeX.Enable( hasHole );
1381 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1382
1383 // Enable/disable number and net
1384 m_padNumLabel->Enable( hasConnection );
1385 m_padNumCtrl->Enable( hasConnection );
1386
1387 if( m_padNetLabel->IsShown() )
1388 {
1389 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1390 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1391 }
1392
1393 // Enable/disable pad length-to-die
1394 m_padToDieOpt->Enable( hasConnection );
1395 m_padToDieDelayOpt->Enable( hasConnection );
1396
1397 if( !m_padToDieOpt->IsEnabled() )
1398 m_padToDieOpt->SetValue( false );
1399
1400 if( !m_padToDieDelayOpt->IsEnabled() )
1401 m_padToDieDelayOpt->SetValue( false );
1402
1403 // We can show/hide this here because it doesn't require the layout to be refreshed.
1404 // All the others have to be done in their event handlers because doing a layout here
1405 // causes infinite looping on MSW.
1406 m_padToDie.Show( m_padToDieOpt->GetValue() );
1407 m_padToDieDelay.Show( m_padToDieDelayOpt->GetValue() );
1408
1409 // Enable/disable Copper Layers control
1410 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1411
1412 LSET cu_set = m_previewPad->GetLayerSet() & LSET::AllCuMask();
1413
1414 switch( m_padType->GetSelection() )
1415 {
1416 case PTH_DLG_TYPE:
1417 if( !cu_set.any() )
1418 m_stackupImagesBook->SetSelection( 3 );
1419 else if( !m_previewPad->GetRemoveUnconnected() )
1420 m_stackupImagesBook->SetSelection( 0 );
1421 else if( m_previewPad->GetKeepTopBottom() )
1422 m_stackupImagesBook->SetSelection( 1 );
1423 else
1424 m_stackupImagesBook->SetSelection( 2 );
1425
1426 break;
1427
1428 case NPTH_DLG_TYPE:
1429 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1430 m_stackupImagesBook->SetSelection( 4 );
1431 else if( cu_set.test( F_Cu ) )
1432 m_stackupImagesBook->SetSelection( 5 );
1433 else if( cu_set.test( B_Cu ) )
1434 m_stackupImagesBook->SetSelection( 6 );
1435 else
1436 m_stackupImagesBook->SetSelection( 7 );
1437
1438 break;
1439
1440 case SMD_DLG_TYPE:
1441 case CONN_DLG_TYPE:
1442 case APERTURE_DLG_TYPE:
1443 m_stackupImagesBook->ChangeSelection( 3 );
1444 break;
1445 }
1446
1447 m_legacyTeardropsWarning->Show( m_board->LegacyTeardrops() );
1448}
1449
1450
1452{
1453 event.Enable( !m_board->LegacyTeardrops() );
1454}
1455
1456
1458{
1459 bool isOnCopperLayer = ( m_previewPad->GetLayerSet() & LSET::AllCuMask() ).any();
1460 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1461}
1462
1463
1464void DIALOG_PAD_PROPERTIES::updatePadLayersList( LSET layer_mask, bool remove_unconnected,
1465 bool keep_top_bottom )
1466{
1468
1469 switch( m_padType->GetSelection() )
1470 {
1471 case PTH_DLG_TYPE:
1472 if( !layer_mask.any() )
1473 layer_mask = PAD::PTHMask();
1474
1475 if( !( layer_mask & LSET::AllCuMask() ).any() )
1476 m_rbCopperLayersSel->SetSelection( 3 );
1477 else if( !remove_unconnected )
1478 m_rbCopperLayersSel->SetSelection( 0 );
1479 else if( keep_top_bottom )
1480 m_rbCopperLayersSel->SetSelection( 1 );
1481 else
1482 m_rbCopperLayersSel->SetSelection( 2 );
1483
1484 break;
1485
1486 case SMD_DLG_TYPE:
1487 if( !layer_mask.any() )
1488 layer_mask = PAD::SMDMask();
1489
1490 if( layer_mask.test( F_Cu ) )
1491 m_rbCopperLayersSel->SetSelection( 0 );
1492 else
1493 m_rbCopperLayersSel->SetSelection( 1 );
1494
1495 break;
1496
1497 case CONN_DLG_TYPE:
1498 if( !layer_mask.any() )
1499 layer_mask = PAD::ConnSMDMask();
1500
1501 if( layer_mask.test( F_Cu ) )
1502 m_rbCopperLayersSel->SetSelection( 0 );
1503 else
1504 m_rbCopperLayersSel->SetSelection( 1 );
1505
1506 break;
1507
1508 case NPTH_DLG_TYPE:
1509 if( !layer_mask.any() )
1510 layer_mask = PAD::UnplatedHoleMask();
1511
1512 if( layer_mask.test( F_Cu ) && layer_mask.test( B_Cu ) )
1513 m_rbCopperLayersSel->SetSelection( 0 );
1514 else if( layer_mask.test( F_Cu ) )
1515 m_rbCopperLayersSel->SetSelection( 1 );
1516 else if( layer_mask.test( B_Cu ) )
1517 m_rbCopperLayersSel->SetSelection( 2 );
1518 else
1519 m_rbCopperLayersSel->SetSelection( 3 );
1520
1521 break;
1522
1523 case APERTURE_DLG_TYPE:
1524 if( !layer_mask.any() )
1525 layer_mask = PAD::ApertureMask();
1526
1527 m_rbCopperLayersSel->SetSelection( 0 );
1528 break;
1529 }
1530
1531 m_layerFrontAdhesive->SetValue( layer_mask[F_Adhes] );
1532 m_layerBackAdhesive->SetValue( layer_mask[B_Adhes] );
1533
1534 m_layerFrontPaste->SetValue( layer_mask[F_Paste] );
1535 m_layerBackPaste->SetValue( layer_mask[B_Paste] );
1536
1537 m_layerFrontSilk->SetValue( layer_mask[F_SilkS] );
1538 m_layerBackSilk->SetValue( layer_mask[B_SilkS] );
1539
1540 m_layerFrontMask->SetValue( layer_mask[F_Mask] );
1541 m_layerBackMask->SetValue( layer_mask[B_Mask] );
1542
1543 m_layerECO1->SetValue( layer_mask[Eco1_User] );
1544 m_layerECO2->SetValue( layer_mask[Eco2_User] );
1545
1546 m_layerUserDwgs->SetValue( layer_mask[Dwgs_User] );
1547}
1548
1549
1551{
1552 bool retVal = DIALOG_SHIM::Show( aShow );
1553
1554 if( aShow )
1555 {
1556 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1557 // wxWidgets needs to have these set when the panel is visible for some reason.
1558 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1566
1567 Layout();
1568 }
1569
1570 return retVal;
1571}
1572
1573
1574void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1575{
1577 redraw();
1578
1579 if( m_initialized )
1580 OnModify();
1581}
1582
1583
1584void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1585{
1587 redraw();
1588
1589 if( m_initialized )
1590 OnModify();
1591}
1592
1593
1595{
1597
1598 wxArrayString error_msgs;
1599 wxArrayString warning_msgs;
1600
1601 m_previewPad->CheckPad( m_parentFrame, true,
1602 [&]( int errorCode, const wxString& msg )
1603 {
1604 if( errorCode == DRCE_PADSTACK_INVALID )
1605 error_msgs.Add( _( "Error: " ) + msg );
1606 else if( errorCode == DRCE_PADSTACK )
1607 warning_msgs.Add( _( "Warning: " ) + msg );
1608 else if( errorCode == DRCE_PAD_TH_WITH_NO_HOLE )
1609 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1610 } );
1611
1612 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1613 {
1614 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1615 : _( "Pad Properties Warnings" );
1616 HTML_MESSAGE_BOX dlg( this, title );
1617
1618 wxArrayString msgs = error_msgs;
1619
1620 for( const wxString& msg : warning_msgs )
1621 msgs.Add( msg );
1622
1623 dlg.ListSet( msgs );
1624
1625 dlg.ShowModal();
1626 }
1627
1628 return error_msgs.GetCount() == 0;
1629}
1630
1631
1633{
1634 if( !m_initialized )
1635 return;
1636
1637 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1638 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view->GetPainter() );
1639 KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings();
1640
1641 m_padPreviewGAL->StopDrawing();
1642
1643 // The layer used to place primitive items selected when editing custom pad shapes
1644 // we use here a layer never used in a pad:
1645 #define SELECTED_ITEMS_LAYER Dwgs_User
1646
1647 view->ClearTopLayers();
1649 view->SetTopLayer( m_editLayer );
1651
1652 static const std::vector<int> topLayers = {
1657 };
1658
1659 for( int layer : topLayers )
1660 view->SetTopLayer( layer );
1661
1662 m_axisOrigin->SetPosition( m_previewPad->GetPosition() );
1663
1664 view->Update( m_previewPad );
1665
1666 // delete previous items if highlight list
1667 while( m_highlight.size() )
1668 {
1669 delete m_highlight.back(); // the dtor also removes item from view
1670 m_highlight.pop_back();
1671 }
1672
1673 BOX2I bbox = m_previewPad->ViewBBox();
1674
1675 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1676 {
1677 // The origin always goes in the middle of the canvas; we want offsetting the pad
1678 // shape to move the pad, not the hole
1679 bbox.Move( -m_previewPad->GetPosition() );
1680 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1681 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1682
1683 // Don't blow up the GAL on too-large numbers
1684 if( maxXExtent > INT_MAX / 4 )
1685 maxXExtent = INT_MAX / 4;
1686
1687 if( maxYExtent > INT_MAX / 4 )
1688 maxYExtent = INT_MAX / 4;
1689
1690 BOX2D viewBox( m_previewPad->GetPosition(), {0, 0} );
1691 BOX2D canvasBox( m_previewPad->GetPosition(), {0, 0} );
1692 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1693 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1694
1695 view->SetBoundary( canvasBox );
1696
1697 // Autozoom
1698 view->SetViewport( viewBox );
1699
1700 m_padPreviewGAL->StartDrawing();
1701 m_padPreviewGAL->Refresh();
1702 }
1703}
1704
1705
1707{
1708 if( !wxDialog::TransferDataToWindow() )
1709 return false;
1710
1711 if( !m_panelGeneral->TransferDataToWindow() )
1712 return false;
1713
1714 if( !m_localSettingsPanel->TransferDataToWindow() )
1715 return false;
1716
1717 return true;
1718}
1719
1720
1722{
1723 BOARD_COMMIT commit( m_parent );
1724
1725 if( !wxDialog::TransferDataFromWindow() )
1726 return false;
1727
1728 if( !m_panelGeneral->TransferDataFromWindow() )
1729 return false;
1730
1731 if( !m_localSettingsPanel->TransferDataFromWindow() )
1732 return false;
1733
1734 if( !padValuesOK() )
1735 return false;
1736
1738 return false;
1739
1740 m_padPreviewGAL->StopDrawing();
1741
1742 PAD_TOOL* padTool = m_parent->GetToolManager()->GetTool<PAD_TOOL>();
1743 padTool->SetLastPadNumber( m_masterPad->GetNumber() );
1744
1745 // m_masterPad is a pattern: ensure there is no net for this pad:
1747
1748 if( !m_currentPad ) // Set current Pad parameters
1749 return true;
1750
1751 commit.Modify( m_currentPad );
1752
1753 // Update values
1754
1755 // transferDataToPad only handles the current edit layer, so m_masterPad isn't accurate
1756 // TODO(JE) this could be cleaner
1757 m_currentPad->SetPadstack( m_previewPad->Padstack() );
1758
1759 m_currentPad->SetAttribute( m_masterPad->GetAttribute() );
1760 m_currentPad->SetFPRelativeOrientation( m_masterPad->GetOrientation() );
1761 m_currentPad->SetPadToDieLength( m_masterPad->GetPadToDieLength() );
1762 m_currentPad->SetPadToDieDelay( m_masterPad->GetPadToDieDelay() );
1763 m_currentPad->SetLayerSet( m_masterPad->GetLayerSet() );
1764 m_currentPad->SetNumber( m_masterPad->GetNumber() );
1765
1766 int padNetcode = NETINFO_LIST::UNCONNECTED;
1767
1768 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1769 if( m_masterPad->GetAttribute() != PAD_ATTRIB::NPTH )
1770 padNetcode = m_padNetSelector->GetSelectedNetcode();
1771
1772 m_currentPad->SetNetCode( padNetcode );
1773
1774 m_currentPad->GetTeardropParams() = m_masterPad->GetTeardropParams();
1775
1776 // Set the fabrication property:
1777 m_currentPad->SetProperty( getSelectedProperty() );
1778
1779 // define the way the clearance area is defined in zones
1780 m_currentPad->SetCustomShapeInZoneOpt( m_masterPad->GetCustomShapeInZoneOpt() );
1781
1782 if( m_currentPad->GetParentFootprint() && m_currentPad->GetParentFootprint()->IsFlipped() )
1783 {
1784 // flip pad (up/down) around its position
1785 m_currentPad->Flip( m_currentPad->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1786 }
1787
1788 m_currentPad->SetPosition( m_masterPad->GetPosition() );
1789
1790 m_parent->SetMsgPanel( m_currentPad );
1791
1792 // redraw the area where the pad was
1793 m_parent->GetCanvas()->Refresh();
1794
1795 commit.Push( _( "Edit Pad Properties" ) );
1796
1797 return true;
1798}
1799
1800
1802{
1803 PAD_PROP prop = PAD_PROP::NONE;
1804
1805 switch( m_choiceFabProperty->GetSelection() )
1806 {
1807 case 0: prop = PAD_PROP::NONE; break;
1808 case 1: prop = PAD_PROP::BGA; break;
1809 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1810 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1811 case 4: prop = PAD_PROP::TESTPOINT; break;
1812 case 5: prop = PAD_PROP::HEATSINK; break;
1813 case 6: prop = PAD_PROP::MECHANICAL; break;
1814 case 7: prop = PAD_PROP::CASTELLATED; break;
1815 case 8: prop = PAD_PROP::PRESSFIT; break;
1816 }
1817
1818 return prop;
1819}
1820
1821
1823{
1824 bool isRound = ( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE );
1825
1826 if( isRound )
1827 {
1828 m_holeXLabel->SetLabel( _( "Diameter:" ) );
1829 m_holeY.Show( false );
1830 }
1831 else
1832 {
1833 m_holeXLabel->SetLabel( _( "Hole size X:" ) );
1834 m_holeY.Show( true );
1835 }
1836
1837 m_holeXLabel->GetParent()->Layout();
1838
1839 if( !isRound )
1840 {
1841 // Disable all
1842 m_backDrillChoice->Enable( false );
1843 m_backDrillTopLayer->Enable( false );
1844 m_backDrillTopLayerLabel->Enable( false );
1845 m_backDrillBottomLayer->Enable( false );
1846 m_backDrillBottomLayerLabel->Enable( false );
1847
1848 m_topPostMachining->Enable( false );
1849 m_topPostMachineSize1Binder.Enable( false );
1850 m_topPostMachineSize2Binder.Enable( false );
1851 m_topPostMachineSize1Label->Enable( false );
1852 m_topPostMachineSize2Label->Enable( false );
1853
1854 m_bottomPostMachining->Enable( false );
1855 m_bottomPostMachineSize1Binder.Enable( false );
1856 m_bottomPostMachineSize2Binder.Enable( false );
1857 m_bottomPostMachineSize1Label->Enable( false );
1858 m_bottomPostMachineSize2Label->Enable( false );
1859 }
1860 else
1861 {
1862 // Enable main choices
1863 m_backDrillChoice->Enable( true );
1864 m_topPostMachining->Enable( true );
1865 m_bottomPostMachining->Enable( true );
1866
1867 // Update sub-controls based on selection
1868 wxCommandEvent dummy;
1872 }
1873}
1874
1875
1877{
1878 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1880 {
1881 m_sizeXLabel->SetLabel( _( "Diameter:" ) );
1882 m_sizeY.Show( false );
1884 m_minTrackWidthHint->SetLabel( _( "d" ) );
1885 m_stLenPercentHint->SetLabel( _( "d" ) );
1886 m_stWidthPercentHint->SetLabel( _( "d" ) );
1887 }
1888 else
1889 {
1890 m_sizeXLabel->SetLabel( _( "Pad size X:" ) );
1891 m_sizeY.Show( true );
1893 m_minTrackWidthHint->SetLabel( _( "w" ) );
1894 m_stLenPercentHint->SetLabel( _( "w" ) );
1895 m_stWidthPercentHint->SetLabel( _( "w" ) );
1896 }
1897
1898 m_sizeXLabel->GetParent()->Layout();
1899 resetSize();
1900 Layout();
1901 m_MainSizer->Fit( this );
1902}
1903
1904
1906{
1907 if( !Validate() )
1908 return false;
1909
1910 if( !m_panelGeneral->Validate() )
1911 return false;
1912
1913 if( !m_localSettingsPanel->Validate() )
1914 return false;
1915
1916 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1917 return false;
1918
1919 switch( m_cbPadstackMode->GetSelection() )
1920 {
1921 default:
1922 case 0: aPad->Padstack().SetMode( PADSTACK::MODE::NORMAL ); break;
1923 case 1: aPad->Padstack().SetMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1924 case 2: aPad->Padstack().SetMode( PADSTACK::MODE::CUSTOM ); break;
1925 }
1926
1927 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1928 aPad->SetShape( m_editLayer, code_shape[m_PadShapeSelector->GetSelection()] );
1929
1932 else
1934
1935 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
1937
1938 aPad->GetTeardropParams().m_Enabled = m_cbTeardrops->GetValue();
1945 aPad->GetTeardropParams().m_CurvedEdges = m_curvedEdges->GetValue();
1947
1948 // Read pad clearances values:
1949 if( m_clearance.IsNull() )
1950 aPad->SetLocalClearance( {} );
1951 else
1952 aPad->SetLocalClearance( m_clearance.GetIntValue() );
1953
1954 if( m_maskMargin.IsNull() )
1955 aPad->SetLocalSolderMaskMargin( {} );
1956 else
1957 aPad->SetLocalSolderMaskMargin( m_maskMargin.GetIntValue() );
1958
1959 if( m_pasteMargin.IsNull() )
1960 aPad->SetLocalSolderPasteMargin( {} );
1961 else
1962 aPad->SetLocalSolderPasteMargin( m_pasteMargin.GetIntValue() );
1963
1964 if( m_pasteMarginRatio.IsNull() )
1966 else
1967 aPad->SetLocalSolderPasteMarginRatio( m_pasteMarginRatio.GetDoubleValue() / 100.0 );
1968
1969 if( m_spokeWidth.IsNull() )
1971 else
1972 aPad->SetLocalThermalSpokeWidthOverride( m_spokeWidth.GetIntValue() );
1973
1974 if( m_thermalGap.IsNull() )
1975 aPad->SetLocalThermalGapOverride( {} );
1976 else
1977 aPad->SetLocalThermalGapOverride( m_thermalGap.GetIntValue() );
1978
1979 aPad->SetThermalSpokeAngle( m_spokeAngle.GetAngleValue() );
1980
1981 // And rotation
1982 aPad->SetOrientation( m_pad_orientation.GetAngleValue() );
1983
1984 switch( m_ZoneConnectionChoice->GetSelection() )
1985 {
1986 default:
1987 case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1988 case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
1989 case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1990 case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
1991 }
1992
1993 VECTOR2I pos( m_posX.GetIntValue(), m_posY.GetIntValue() );
1994
1995 if( FOOTPRINT* fp = aPad->GetParentFootprint() )
1996 {
1997 pos -= fp->GetPosition();
1998 RotatePoint( pos, -fp->GetOrientation() );
1999 }
2000
2001 aPad->SetPosition( pos );
2002
2003 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
2004 {
2006 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeX.GetIntValue() ) );
2007 }
2008 else
2009 {
2011 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeY.GetIntValue() ) );
2012 }
2013
2014 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CIRCLE )
2015 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2016 else
2017 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeY.GetIntValue() ) );
2018
2019 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
2020 // remember DeltaSize.x is the Y size variation
2021 bool error = false;
2022 VECTOR2I delta( 0, 0 );
2023
2024 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::TRAPEZOID )
2025 {
2026 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
2027 if( m_trapAxisCtrl->GetSelection() == 0 )
2028 delta.x = m_trapDelta.GetIntValue();
2029 else
2030 delta.y = m_trapDelta.GetIntValue();
2031
2032 if( delta.x < 0 && delta.x < -aPad->GetSize( m_editLayer ).y )
2033 {
2034 delta.x = -aPad->GetSize( m_editLayer ).y + 2;
2035 error = true;
2036 }
2037
2038 if( delta.x > 0 && delta.x > aPad->GetSize( m_editLayer ).y )
2039 {
2040 delta.x = aPad->GetSize( m_editLayer ).y - 2;
2041 error = true;
2042 }
2043
2044 if( delta.y < 0 && delta.y < -aPad->GetSize( m_editLayer ).x )
2045 {
2046 delta.y = -aPad->GetSize( m_editLayer ).x + 2;
2047 error = true;
2048 }
2049
2050 if( delta.y > 0 && delta.y > aPad->GetSize( m_editLayer ).x )
2051 {
2052 delta.y = aPad->GetSize( m_editLayer ).x - 2;
2053 error = true;
2054 }
2055 }
2056
2057 aPad->SetDelta( m_editLayer, delta );
2058
2059 if( m_offsetShapeOpt->GetValue() )
2060 aPad->SetOffset( m_editLayer, VECTOR2I( m_offsetX.GetIntValue(), m_offsetY.GetIntValue() ) );
2061 else
2062 aPad->SetOffset( m_editLayer, VECTOR2I() );
2063
2064 // Read pad length die
2065 if( m_padToDieOpt->GetValue() )
2066 aPad->SetPadToDieLength( m_padToDie.GetIntValue() );
2067 else
2068 aPad->SetPadToDieLength( 0 );
2069
2070 if( m_padToDieDelayOpt->GetValue() )
2071 aPad->SetPadToDieDelay( m_padToDieDelay.GetIntValue() );
2072 else
2073 aPad->SetPadToDieDelay( 0 );
2074
2075 aPad->SetNumber( m_padNumCtrl->GetValue() );
2076 aPad->SetNetCode( m_padNetSelector->GetSelectedNetcode() );
2077
2078 int chamfers = 0;
2079
2080 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
2081 {
2082 if( m_cbTopLeft->GetValue() )
2083 chamfers |= RECT_CHAMFER_TOP_LEFT;
2084
2085 if( m_cbTopRight->GetValue() )
2086 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2087
2088 if( m_cbBottomLeft->GetValue() )
2089 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2090
2091 if( m_cbBottomRight->GetValue() )
2092 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2093 }
2094 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
2095 {
2096 if( m_cbTopLeft1->GetValue() )
2097 chamfers |= RECT_CHAMFER_TOP_LEFT;
2098
2099 if( m_cbTopRight1->GetValue() )
2100 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2101
2102 if( m_cbBottomLeft1->GetValue() )
2103 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2104
2105 if( m_cbBottomRight1->GetValue() )
2106 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2107 }
2108
2109 aPad->SetChamferPositions( m_editLayer, chamfers );
2110
2111 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
2112 {
2113 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
2114 // that is the minimal area of this pad, and is useful to ensure a hole
2115 // diameter is acceptable, and is used in Gerber files as flashed area
2116 // reference
2118 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2119 }
2120
2121 // Define the way the clearance area is defined in zones. Since all non-custom pad
2122 // shapes are convex to begin with, this really only makes any difference for custom
2123 // pad shapes.
2126
2127 switch( aPad->GetAttribute() )
2128 {
2129 case PAD_ATTRIB::PTH:
2130 break;
2131
2132 case PAD_ATTRIB::CONN:
2133 case PAD_ATTRIB::SMD:
2134 // SMD and PAD_ATTRIB::CONN has no hole.
2135 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
2136 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
2137 // and are intended to be used in virtual edge board connectors
2138 // However we can accept a non null offset,
2139 // mainly to allow complex pads build from a set of basic pad shapes
2140 aPad->SetDrillSize( VECTOR2I( 0, 0 ) );
2141 break;
2142
2143 case PAD_ATTRIB::NPTH:
2144 // Mechanical purpose only:
2145 // no net name, no pad name allowed
2146 aPad->SetNumber( wxEmptyString );
2148 break;
2149
2150 default:
2151 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
2152 break;
2153 }
2154
2155 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::ROUNDRECT )
2156 {
2157 aPad->SetRoundRectRadiusRatio( m_editLayer, m_cornerRatio.GetDoubleValue() / 100.0 );
2158 }
2159 else if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CHAMFERED_RECT )
2160 {
2162 {
2163 aPad->SetChamferRectRatio( m_editLayer, m_mixedChamferRatio.GetDoubleValue() / 100.0 );
2164 aPad->SetRoundRectRadiusRatio( m_editLayer, m_mixedCornerRatio.GetDoubleValue() / 100.0 );
2165 }
2166 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
2167 {
2168 aPad->SetChamferRectRatio( m_editLayer, m_chamferRatio.GetDoubleValue() / 100.0 );
2170 }
2171 }
2172
2174
2175 LSET padLayerMask = LSET();
2176 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
2177
2179
2180 switch( m_padType->GetSelection() )
2181 {
2182 case PTH_DLG_TYPE:
2183 switch( copperLayersChoice )
2184 {
2185 case 0:
2186 // All copper layers
2187 padLayerMask |= LSET::AllCuMask();
2188 break;
2189
2190 case 1:
2191 // Front, back and connected
2192 padLayerMask |= LSET::AllCuMask();
2194 break;
2195
2196 case 2:
2197 // Connected only
2198 padLayerMask |= LSET::AllCuMask();
2200 break;
2201
2202 case 3:
2203 // No copper layers
2204 break;
2205 }
2206
2207 break;
2208
2209 case NPTH_DLG_TYPE:
2210 switch( copperLayersChoice )
2211 {
2212 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
2213 case 1: padLayerMask.set( F_Cu ); break;
2214 case 2: padLayerMask.set( B_Cu ); break;
2215 default: break;
2216 }
2217
2218 break;
2219
2220 case SMD_DLG_TYPE:
2221 case CONN_DLG_TYPE:
2222 switch( copperLayersChoice )
2223 {
2224 case 0: padLayerMask.set( F_Cu ); break;
2225 case 1: padLayerMask.set( B_Cu ); break;
2226 }
2227
2228 break;
2229
2230 case APERTURE_DLG_TYPE:
2231 // no copper layers
2232 break;
2233 }
2234
2235 if( m_layerFrontAdhesive->GetValue() )
2236 padLayerMask.set( F_Adhes );
2237
2238 if( m_layerBackAdhesive->GetValue() )
2239 padLayerMask.set( B_Adhes );
2240
2241 if( m_layerFrontPaste->GetValue() )
2242 padLayerMask.set( F_Paste );
2243
2244 if( m_layerBackPaste->GetValue() )
2245 padLayerMask.set( B_Paste );
2246
2247 if( m_layerFrontSilk->GetValue() )
2248 padLayerMask.set( F_SilkS );
2249
2250 if( m_layerBackSilk->GetValue() )
2251 padLayerMask.set( B_SilkS );
2252
2253 if( m_layerFrontMask->GetValue() )
2254 padLayerMask.set( F_Mask );
2255
2256 if( m_layerBackMask->GetValue() )
2257 padLayerMask.set( B_Mask );
2258
2259 if( m_layerECO1->GetValue() )
2260 padLayerMask.set( Eco1_User );
2261
2262 if( m_layerECO2->GetValue() )
2263 padLayerMask.set( Eco2_User );
2264
2265 if( m_layerUserDwgs->GetValue() )
2266 padLayerMask.set( Dwgs_User );
2267
2268 aPad->SetLayerSet( padLayerMask );
2269
2270 // Save backdrill properties
2271 PADSTACK::DRILL_PROPS secondaryDrill;
2272 secondaryDrill.size = VECTOR2I( m_backDrillBottomSizeBinder.GetIntValue(),
2273 m_backDrillBottomSizeBinder.GetIntValue() );
2274 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2275
2276 PADSTACK::DRILL_PROPS tertiaryDrill;
2277 tertiaryDrill.size = VECTOR2I( m_backDrillTopSizeBinder.GetIntValue(),
2278 m_backDrillTopSizeBinder.GetIntValue() );
2279 tertiaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2280
2281 if( !m_backDrillChoice->GetSelection() )
2282 {
2283 secondaryDrill.start = UNDEFINED_LAYER;
2284 secondaryDrill.end = UNDEFINED_LAYER;
2285 }
2286
2287 if( m_backDrillChoice->GetSelection() & 1 ) // Bottom
2288 {
2289 secondaryDrill.start = B_Cu;
2290
2291 if( m_backDrillBottomLayer->GetSelection() != wxNOT_FOUND )
2292 secondaryDrill.end = (PCB_LAYER_ID)(intptr_t)m_backDrillBottomLayer->GetClientData( m_backDrillBottomLayer->GetSelection() );
2293 else
2294 secondaryDrill.end = UNDEFINED_LAYER;
2295 }
2296
2297 if( m_backDrillChoice->GetSelection() & 2 ) // Top
2298 {
2299 tertiaryDrill.start = F_Cu;
2300
2301 if( m_backDrillTopLayer->GetSelection() != wxNOT_FOUND )
2302 tertiaryDrill.end = (PCB_LAYER_ID)(intptr_t)m_backDrillTopLayer->GetClientData( m_backDrillTopLayer->GetSelection() );
2303 else
2304 tertiaryDrill.end = UNDEFINED_LAYER;
2305 }
2306
2307 aPad->Padstack().SecondaryDrill() = secondaryDrill;
2308 aPad->Padstack().TertiaryDrill() = tertiaryDrill;
2309
2310 // Front Post Machining
2311 PADSTACK::POST_MACHINING_PROPS frontPostMachining;
2312
2313 switch( m_topPostMachining->GetSelection() )
2314 {
2315 case 1: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2316 case 2: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2317 default: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2318 }
2319
2320 frontPostMachining.size = m_topPostMachineSize1Binder.GetIntValue();
2321
2322 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2323 frontPostMachining.angle = m_topPostMachineSize2Binder.GetIntValue();
2324 else
2325 frontPostMachining.depth = m_topPostMachineSize2Binder.GetIntValue();
2326
2327 aPad->Padstack().FrontPostMachining() = frontPostMachining;
2328
2329 // Back Post Machining
2330 PADSTACK::POST_MACHINING_PROPS backPostMachining;
2331
2332 switch( m_bottomPostMachining->GetSelection() )
2333 {
2334 case 1: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2335 case 2: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2336 default: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2337 }
2338
2339 backPostMachining.size = m_bottomPostMachineSize1Binder.GetIntValue();
2340
2341 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2342 backPostMachining.angle = m_bottomPostMachineSize2Binder.GetIntValue();
2343 else
2344 backPostMachining.depth = m_bottomPostMachineSize2Binder.GetIntValue();
2345
2346 aPad->Padstack().BackPostMachining() = backPostMachining;
2347
2348 return !error;
2349}
2350
2351
2352
2353
2354void DIALOG_PAD_PROPERTIES::onBackDrillChoice( wxCommandEvent& event )
2355{
2356 int selection = m_backDrillChoice->GetSelection();
2357 // 0: None, 1: Bottom, 2: Top, 3: Both
2358
2359 bool enableTop = ( selection == 2 || selection == 3 );
2360 bool enableBottom = ( selection == 1 || selection == 3 );
2361
2362 m_backDrillTopSizeBinder.Enable( enableTop );
2363 m_backDrillTopLayer->Enable( enableTop );
2364 m_backDrillTopLayerLabel->Enable( enableTop );
2365
2366 m_backDrillBottomSizeBinder.Enable( enableBottom );
2367 m_backDrillBottomLayer->Enable( enableBottom );
2368 m_backDrillBottomLayerLabel->Enable( enableBottom );
2369
2370}
2371
2372
2374{
2375 int selection = m_topPostMachining->GetSelection();
2376 // 0: None, 1: Countersink, 2: Counterbore
2377
2378 bool enable = ( selection != 0 );
2379 m_topPostMachineSize1Binder.Enable( enable );
2380 m_topPostMachineSize2Binder.Enable( enable );
2381 m_topPostMachineSize1Label->Enable( enable );
2382 m_topPostMachineSize2Label->Enable( enable );
2383
2384 if( selection == 1 ) // Countersink
2385 {
2386 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2387 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
2388
2389 if( m_topPostMachineSize2Binder.IsIndeterminate() || m_topPostMachineSize2Binder.GetDoubleValue() == 0 )
2390 m_topPostMachineSize2Binder.SetValue( "82" );
2391 }
2392 else if( selection == 2 ) // Counterbore
2393 {
2394 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2395 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2396 }
2397}
2398
2399
2401{
2402 int selection = m_bottomPostMachining->GetSelection();
2403 // 0: None, 1: Countersink, 2: Counterbore
2404
2405 bool enable = ( selection != 0 );
2406 m_bottomPostMachineSize1Binder.Enable( enable );
2407 m_bottomPostMachineSize2Binder.Enable( enable );
2408 m_bottomPostMachineSize1Label->Enable( enable );
2409 m_bottomPostMachineSize2Label->Enable( enable );
2410
2411 if( selection == 1 ) // Countersink
2412 {
2413 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2414 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
2415
2416 if( m_bottomPostMachineSize2Binder.IsIndeterminate() || m_bottomPostMachineSize2Binder.GetDoubleValue() == 0 )
2417 m_bottomPostMachineSize2Binder.SetValue( "82" );
2418 }
2419 else if( selection == 2 ) // Counterbore
2420 {
2421 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2422 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2423 }
2424}
2425
2426
2427void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2428{
2429 if( m_offsetShapeOpt->GetValue() )
2430 {
2431 m_offsetX.SetValue( m_previewPad->GetOffset( m_editLayer ).x );
2432 m_offsetY.SetValue( m_previewPad->GetOffset( m_editLayer ).y );
2433 }
2434
2435 // Show/hide controls depending on m_offsetShapeOpt being enabled
2436 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2437 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2438
2439 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2440 m_notebook->GetPage( i )->Layout();
2441
2442 OnValuesChanged( event );
2443}
2444
2445
2447{
2448 if( m_padToDieOpt->GetValue() && m_currentPad )
2449 m_padToDie.SetValue( m_currentPad->GetPadToDieLength() );
2450
2451 OnValuesChanged( event );
2452}
2453
2454
2456{
2457 if( m_padToDieDelayOpt->GetValue() && m_currentPad )
2458 m_padToDieDelay.SetValue( m_currentPad->GetPadToDieDelay() );
2459
2460 OnValuesChanged( event );
2461}
2462
2463
2464void DIALOG_PAD_PROPERTIES::onModify( wxSpinDoubleEvent& aEvent )
2465{
2466 if( m_initialized )
2467 OnModify();
2468}
2469
2470
2471void DIALOG_PAD_PROPERTIES::onModify( wxCommandEvent& aEvent )
2472{
2473 if( m_initialized )
2474 OnModify();
2475}
2476
2477
2478void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2479{
2480 if( m_initialized )
2481 {
2483 return;
2484
2485 // If the pad size has changed, update the displayed values for rounded rect pads.
2488
2489 redraw();
2490 OnModify();
2491 }
2492}
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
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 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
void onChangePadMode(wxCommandEvent &event) override
std::vector< PCB_SHAPE * > m_highlight
void OnPadstackModeChanged(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
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:66
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition view.cpp:542
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:298
void SetBoundary(const BOX2D &aBoundary)
Set limits for view area.
Definition view.h:286
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:1685
void SetLayerVisible(int aLayer, bool aVisible=true)
Control the visibility of a particular layer.
Definition view.h:400
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:202
void ClearTopLayers()
Remove all layers from the on-the-top set (they are no longer displayed over the rest of layers).
Definition view.cpp:891
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:839
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:220
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:726
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:247
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition padstack.h:351
void SetMode(MODE aMode)
POST_MACHINING_PROPS & FrontPostMachining()
Definition padstack.h:344
DRILL_PROPS & TertiaryDrill()
Definition padstack.h:341
@ 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:338
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:347
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:1318
void SetLocalThermalGapOverride(const std::optional< int > &aOverride)
Definition pad.h:767
PAD_ATTRIB GetAttribute() const
Definition pad.h:558
static LSET PTHMask()
layer set for a through hole pad
Definition pad.cpp:339
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition pad.h:739
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition pad.h:597
void SetLocalThermalSpokeWidthOverride(std::optional< int > aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition pad.h:723
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:1385
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition pad.cpp:360
void SetDelta(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.h:293
void SetPadToDieDelay(int aDelay)
Definition pad.h:573
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:431
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pad.h:580
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition pad.h:318
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:603
void SetChamferRectRatio(PCB_LAYER_ID aLayer, double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition pad.cpp:911
void SetPosition(const VECTOR2I &aPos) override
Definition pad.h:203
const PADSTACK & Padstack() const
Definition pad.h:328
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition pad.cpp:353
void SetDrillSize(const VECTOR2I &aSize)
Definition pad.h:311
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:3097
static LSET ApertureMask()
layer set for an aperture pad
Definition pad.cpp:367
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition pad.cpp:346
void SetChamferPositions(PCB_LAYER_ID aLayer, int aPositions)
Has meaning only for chamfered rectangular pads.
Definition pad.h:824
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition pad.h:587
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition pad.cpp:1393
void SetLocalClearance(std::optional< int > aClearance)
Definition pad.h:577
void SetLayerSet(const LSET &aLayers) override
Definition pad.h:554
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:873
void SetPadToDieLength(int aLength)
Definition pad.h:570
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.
@ FP_SMD
Definition footprint.h:82
@ FP_THROUGH_HOLE
Definition footprint.h:81
@ 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
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
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:44
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:27
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:261
PCB_LAYER_ID start
Definition padstack.h:264
PCB_LAYER_ID end
Definition padstack.h:265
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:262
PAD_DRILL_SHAPE shape
Definition padstack.h:263
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Definition padstack.h:275
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