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