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