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