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 m_backDrillChoice->SetSelection( hasBackdrill ? ( hasTertiaryDrill ? 3 : 1 )
815 : ( hasTertiaryDrill ? 2 : 0 ) );
816
817 if( !hasBackdrill )
818 {
819 m_backDrillBottomSizeBinder.SetValue( 0 );
820 }
821 else
822 {
823 m_backDrillBottomSizeBinder.SetValue( secondaryDrill.size.x );
824
825 for( unsigned int i = 0; i < m_backDrillBottomLayer->GetCount(); ++i )
826 {
827 if( ToLAYER_ID( (intptr_t)m_backDrillBottomLayer->GetClientData( i ) ) == secondaryDrill.end )
828 {
829 m_backDrillBottomLayer->SetSelection( i );
830 break;
831 }
832 }
833 }
834
835 if( !hasTertiaryDrill )
836 {
837 m_backDrillTopSizeBinder.SetValue( 0 );
838 }
839 else
840 {
841 m_backDrillTopSizeBinder.SetValue( tertiaryDrill.size.x );
842
843 for( unsigned int i = 0; i < m_backDrillTopLayer->GetCount(); ++i )
844 {
845 if( ToLAYER_ID( (intptr_t)m_backDrillTopLayer->GetClientData( i ) ) == tertiaryDrill.end )
846 {
847 m_backDrillTopLayer->SetSelection( i );
848 break;
849 }
850 }
851 }
852
853 // Post machining
854 const PADSTACK::POST_MACHINING_PROPS& frontPostMachining = m_previewPad->Padstack().FrontPostMachining();
855
856 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
857 m_topPostMachining->SetSelection( 2 );
858 else if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
859 m_topPostMachining->SetSelection( 1 );
860 else
861 m_topPostMachining->SetSelection( 0 );
862
863 m_topPostMachineSize1Binder.SetValue( frontPostMachining.size );
864
865 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
866 m_topPostMachineSize2Binder.SetValue( frontPostMachining.angle );
867 else
868 m_topPostMachineSize2Binder.SetValue( frontPostMachining.depth );
869
870 const PADSTACK::POST_MACHINING_PROPS& backPostMachining = m_previewPad->Padstack().BackPostMachining();
871
872 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
873 m_bottomPostMachining->SetSelection( 2 );
874 else if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
875 m_bottomPostMachining->SetSelection( 1 );
876 else
877 m_bottomPostMachining->SetSelection( 0 );
878
879 m_bottomPostMachineSize1Binder.SetValue( backPostMachining.size );
880
881 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
882 m_bottomPostMachineSize2Binder.SetValue( backPostMachining.angle );
883 else
884 m_bottomPostMachineSize2Binder.SetValue( backPostMachining.depth );
885
886
887 updatePadLayersList( m_previewPad->GetLayerSet(), m_previewPad->GetRemoveUnconnected(),
888 m_previewPad->GetKeepTopBottom() );
889
890 // Update some dialog widgets state (Enable/disable options):
891 wxCommandEvent cmd_event;
892 OnPadShapeSelection( cmd_event );
893 OnOffsetCheckbox( cmd_event );
895
896 // Restore thermal spoke angle to its initial value, because it can be modified
897 // by the call to OnPadShapeSelection()
898 m_previewPad->SetThermalSpokeAngle( spokeInitialAngle );
899 m_spokeAngle.SetAngleValue( m_previewPad->GetThermalSpokeAngle() );
900}
901
902
904{
905 m_primitives = m_previewPad->GetPrimitives( m_editLayer );
906
907 m_sizeX.ChangeValue( m_previewPad->GetSize( m_editLayer ).x );
908 m_sizeY.ChangeValue( m_previewPad->GetSize( m_editLayer ).y );
909
910 m_offsetShapeOpt->SetValue( m_previewPad->GetOffset( m_editLayer ) != VECTOR2I() );
911 m_offsetX.ChangeValue( m_previewPad->GetOffset( m_editLayer ).x );
912 m_offsetY.ChangeValue( m_previewPad->GetOffset( m_editLayer ).y );
913
914 if( m_previewPad->GetDelta( m_editLayer ).x )
915 {
916 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).x );
917 m_trapAxisCtrl->SetSelection( 0 );
918 }
919 else
920 {
921 m_trapDelta.ChangeValue( m_previewPad->GetDelta( m_editLayer ).y );
922 m_trapAxisCtrl->SetSelection( 1 );
923 }
924
925 switch( m_previewPad->GetShape( m_editLayer ) )
926 {
927 default:
928 case PAD_SHAPE::CIRCLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
929 case PAD_SHAPE::OVAL: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_OVAL ); break;
930 case PAD_SHAPE::RECTANGLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_RECT ); break;
933
935 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) > 0.0 )
937 else
939 break;
940
942 if( m_previewPad->GetAnchorPadShape( m_editLayer ) == PAD_SHAPE::RECTANGLE )
944 else
946 break;
947 }
948
949 int chamferPositions = m_previewPad->GetChamferPositions( m_editLayer );
950
951 m_cbTopLeft->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
952 m_cbTopLeft1->SetValue( chamferPositions & RECT_CHAMFER_TOP_LEFT );
953 m_cbTopRight->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
954 m_cbTopRight1->SetValue( chamferPositions & RECT_CHAMFER_TOP_RIGHT );
955 m_cbBottomLeft->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
956 m_cbBottomLeft1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_LEFT );
957 m_cbBottomRight->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
958 m_cbBottomRight1->SetValue( chamferPositions & RECT_CHAMFER_BOTTOM_RIGHT );
959
961}
962
963
965{
966 // NOTE: synchronize changes here with DIALOG_TRACK_VIA_PROPERTIES::afterPadstackModeChanged
967
968 wxCHECK_MSG( m_board, /* void */, "Expected valid board in afterPadstackModeChanged" );
969 m_cbEditLayer->Clear();
970
971 switch( m_previewPad->Padstack().Mode() )
972 {
974 m_cbPadstackMode->SetSelection( 0 );
975 m_cbEditLayer->Append( m_board->GetLayerName( F_Cu ) );
976 m_cbEditLayer->Disable();
978 m_editLayerCtrlMap = { { 0, F_Cu } };
979 break;
980
982 {
983 m_cbPadstackMode->SetSelection( 1 );
984 m_cbEditLayer->Enable();
985
986 std::vector choices = {
987 m_board->GetLayerName( F_Cu ),
988 _( "Inner Layers" ),
989 m_board->GetLayerName( B_Cu )
990 };
991
992 m_cbEditLayer->Append( choices );
993
995 { 0, F_Cu },
997 { 2, B_Cu }
998 };
999
1000 if( m_editLayer != F_Cu && m_editLayer != B_Cu )
1002
1003 break;
1004 }
1005
1007 {
1008 m_cbPadstackMode->SetSelection( 2 );
1009 m_cbEditLayer->Enable();
1010 LSET layers = LSET::AllCuMask() & m_board->GetEnabledLayers();
1011
1012 for( PCB_LAYER_ID layer : layers.UIOrder() )
1013 {
1014 int idx = m_cbEditLayer->Append( m_board->GetLayerName( layer ) );
1015 m_editLayerCtrlMap[idx] = layer;
1016 }
1017
1018 break;
1019 }
1020 }
1021
1022 for( const auto& [idx, layer] : m_editLayerCtrlMap )
1023 {
1024 if( layer == m_editLayer )
1025 {
1026 m_cbEditLayer->SetSelection( idx );
1027 break;
1028 }
1029 }
1030}
1031
1032
1033void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
1034{
1035 redraw();
1036 event.Skip();
1037}
1038
1039
1040void DIALOG_PAD_PROPERTIES::onChangePadMode( wxCommandEvent& event )
1041{
1042 m_sketchPreview = m_cbShowPadOutline->GetValue();
1043
1044 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1045
1046 // fix the pad render mode (filled/not filled)
1047 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
1048
1049 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
1050 settings->SetHighContrast( false );
1051 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
1052
1053 redraw();
1054}
1055
1056
1058{
1059 switch( m_PadShapeSelector->GetSelection() )
1060 {
1062 case CHOICE_SHAPE_OVAL:
1063 case CHOICE_SHAPE_RECT:
1064 m_shapePropsBook->SetSelection( 0 );
1065 break;
1066
1068 m_shapePropsBook->SetSelection( 1 );
1069 break;
1070
1072 {
1073 m_shapePropsBook->SetSelection( 2 );
1074
1075 // Reasonable defaults
1076 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0 )
1077 {
1078 const double ipcRadiusRatio =
1080 m_cornerRatio.ChangeDoubleValue( ipcRadiusRatio * 100 );
1081 }
1082
1083 break;
1084 }
1085
1087 m_shapePropsBook->SetSelection( 3 );
1088
1089 // Reasonable default
1090 if( m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1091 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1092
1093 // Ensure the displayed value is up to date:
1094 m_chamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1095
1096 // A reasonable default is one corner chamfered (usual for some SMD pads).
1097 if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
1098 && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
1099 {
1100 m_cbTopLeft->SetValue( true );
1101 m_cbTopRight->SetValue( false );
1102 m_cbBottomLeft->SetValue( false );
1103 m_cbBottomRight->SetValue( false );
1104 }
1105
1106 break;
1107
1109 m_shapePropsBook->SetSelection( 4 );
1110
1111 // Reasonable defaults
1112 if( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) == 0.0
1113 && m_previewPad->GetChamferRectRatio( m_editLayer ) == 0.0 )
1114 {
1115 const double ipcRadiusRatio =
1117 m_previewPad->SetRoundRectRadiusRatio( m_editLayer, ipcRadiusRatio );
1118 m_previewPad->SetChamferRectRatio( m_editLayer, 0.2 );
1119 }
1120
1121 // Ensure the displayed values are up to date:
1122 m_mixedChamferRatio.ChangeDoubleValue( m_previewPad->GetChamferRectRatio( m_editLayer ) * 100.0 );
1123 m_mixedCornerRatio.ChangeDoubleValue( m_previewPad->GetRoundRectRadiusRatio( m_editLayer ) * 100.0 );
1124 break;
1125
1126 case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE::CUSTOM, circular anchor
1127 case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE::CUSTOM, rect anchor
1128 m_shapePropsBook->SetSelection( 0 );
1129 break;
1130 }
1131
1132 // Note: must do this before enabling/disabling m_sizeY as we're using that as a flag to see
1133 // what the last shape was.
1134 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE )
1135 {
1136 if( m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_90 )
1137 m_spokeAngle.SetAngleValue( ANGLE_45 );
1138 }
1139 else
1140 {
1141 if( !m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_45 )
1142 m_spokeAngle.SetAngleValue( ANGLE_90 );
1143 }
1144
1145 // Readjust props book size
1146 wxSize size = m_shapePropsBook->GetSize();
1147 size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
1148 m_shapePropsBook->SetMaxSize( size );
1149
1150 m_sizeY.Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE
1152
1153 m_offsetShapeOpt->Enable( m_PadShapeSelector->GetSelection() != CHOICE_SHAPE_CIRCLE );
1154
1155 if( !m_offsetShapeOpt->IsEnabled() )
1156 m_offsetShapeOpt->SetValue( false );
1157
1158 // Show/hide controls depending on m_offsetShapeOpt being enabled
1159 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
1160 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
1161
1164
1165 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
1166 m_notebook->GetPage( i )->Layout();
1167
1168 // Resize the dialog if its height is too small to show all widgets:
1169 if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
1170 m_MainSizer->SetSizeHints( this );
1171
1173 redraw();
1174
1175 if( m_initialized )
1176 OnModify();
1177}
1178
1179
1181{
1182 if( m_holeShapeCtrl->GetSelection() != CHOICE_SHAPE_CIRCLE )
1183 {
1184 bool hasBackdrill = ( m_backDrillChoice->GetSelection() != 0 );
1185 bool hasTopPost = ( m_topPostMachining->GetSelection() != 0 );
1186 bool hasBottomPost = ( m_bottomPostMachining->GetSelection() != 0 );
1187
1188 if( hasBackdrill || hasTopPost || hasBottomPost )
1189 {
1190 if( wxMessageBox( _( "Switching to non-circular hole will disable backdrills and post-machining. Continue?" ),
1191 _( "Warning" ), wxOK | wxCANCEL | wxICON_WARNING, this ) != wxOK )
1192 {
1193 m_holeShapeCtrl->SetSelection( CHOICE_SHAPE_CIRCLE );
1194 return;
1195 }
1196 }
1197 }
1198
1201 redraw();
1202
1203 if( m_initialized )
1204 OnModify();
1205}
1206
1207
1208void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
1209{
1211 redraw();
1212
1213 if( m_initialized )
1214 OnModify();
1215}
1216
1217
1219{
1220 m_rbCopperLayersSel->Clear();
1221
1222 switch( m_padType->GetSelection() )
1223 {
1224 case PTH_DLG_TYPE:
1225 m_rbCopperLayersSel->Append( _( "All copper layers" ) );
1226 m_rbCopperLayersSel->Append( wxString::Format( _( "%s, %s and connected layers" ),
1227 m_board->GetLayerName( F_Cu ),
1228 m_board->GetLayerName( B_Cu ) ) );
1229 m_rbCopperLayersSel->Append( _( "Connected layers only" ) );
1230 m_rbCopperLayersSel->Append( _( "None" ) );
1231 break;
1232
1233 case NPTH_DLG_TYPE:
1234 m_rbCopperLayersSel->Append( wxString::Format( _( "%s and %s" ),
1235 m_board->GetLayerName( F_Cu ),
1236 m_board->GetLayerName( B_Cu ) ) );
1237 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1238 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1239 m_rbCopperLayersSel->Append( _( "None" ) );
1240 break;
1241
1242 case SMD_DLG_TYPE:
1243 case CONN_DLG_TYPE:
1244 m_rbCopperLayersSel->Append( m_board->GetLayerName( F_Cu ) );
1245 m_rbCopperLayersSel->Append( m_board->GetLayerName( B_Cu ) );
1246 break;
1247
1248 case APERTURE_DLG_TYPE:
1249 m_rbCopperLayersSel->Append( _( "None" ) );
1250 break;
1251 }
1252
1253 m_backDrillTopLayer->Clear();
1254 m_backDrillBottomLayer->Clear();
1255
1256 for( PCB_LAYER_ID layerId : m_board->GetEnabledLayers().UIOrder() )
1257 {
1258 if( IsCopperLayer( layerId ) )
1259 {
1260 wxString layerName = m_board->GetLayerName( layerId );
1261 m_backDrillTopLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1262 m_backDrillBottomLayer->Append( layerName, wxBitmapBundle(), (void*)(intptr_t)layerId );
1263 }
1264 }
1265}
1266
1267
1268void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
1269{
1270 bool hasHole = true;
1271 bool hasConnection = true;
1272
1273 switch( m_padType->GetSelection() )
1274 {
1275 case PTH_DLG_TYPE: hasHole = true; hasConnection = true; break;
1276 case SMD_DLG_TYPE: hasHole = false; hasConnection = true; break;
1277 case CONN_DLG_TYPE: hasHole = false; hasConnection = true; break;
1278 case NPTH_DLG_TYPE: hasHole = true; hasConnection = false; break;
1279 case APERTURE_DLG_TYPE: hasHole = false; hasConnection = false; break;
1280 }
1281
1282 // Update Layers dropdown list and selects the "best" layer set for the new pad type:
1283 updatePadLayersList( {}, m_previewPad->GetRemoveUnconnected(),
1284 m_previewPad->GetKeepTopBottom() );
1285
1286 m_gbSizerHole->Show( hasHole );
1287 m_staticline71->Show( hasHole );
1288
1289 if( !hasHole )
1290 {
1291 m_holeX.ChangeValue( 0 );
1292 m_holeY.ChangeValue( 0 );
1293 }
1294 else if( m_holeX.GetValue() == 0 )
1295 {
1296 if( m_currentPad )
1297 {
1298 m_holeX.ChangeValue( m_currentPad->GetDrillSize().x );
1299 m_holeY.ChangeValue( m_currentPad->GetDrillSize().y );
1300 }
1301 else
1302 {
1303 m_holeX.ChangeValue( pcbIUScale.mmToIU( DEFAULT_PAD_DRILL_DIAMETER_MM ) );
1304 }
1305 }
1306
1307 if( !hasConnection )
1308 {
1309 m_padNumCtrl->ChangeValue( wxEmptyString );
1310 m_padNetSelector->SetSelectedNetcode( 0 );
1311 m_padToDieOpt->SetValue( false );
1312 m_padToDieDelayOpt->SetValue( false );
1313 }
1314 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1315 {
1316 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1317 m_padNetSelector->SetSelectedNetcode( m_currentPad->GetNetCode() );
1318 }
1319
1321
1322 // For now, padstack controls only enabled for PTH pads
1323 bool enablePadstack = m_padType->GetSelection() == PTH_DLG_TYPE;
1324 m_padstackControls->Show( enablePadstack );
1325
1326 if( !enablePadstack )
1327 {
1328 m_editLayer = F_Cu;
1330 }
1331
1332 // Layout adjustment is needed if the hole details got shown/hidden
1333 m_LeftBoxSizer->Layout();
1334 redraw();
1335
1336 if( m_initialized )
1337 OnModify();
1338}
1339
1340
1341void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1342{
1343 bool hasHole = true;
1344 bool hasConnection = true;
1345
1346 switch( m_padType->GetSelection() )
1347 {
1348 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1349 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1350 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1351 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1352 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1353 }
1354
1355 // Enable/disable hole controls
1356 m_holeShapeLabel->Enable( hasHole );
1357 m_holeShapeCtrl->Enable( hasHole );
1358 m_holeX.Enable( hasHole );
1359 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1360
1361 // Enable/disable number and net
1362 m_padNumLabel->Enable( hasConnection );
1363 m_padNumCtrl->Enable( hasConnection );
1364
1365 if( m_padNetLabel->IsShown() )
1366 {
1367 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1368 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1369 }
1370
1371 // Enable/disable pad length-to-die
1372 m_padToDieOpt->Enable( hasConnection );
1373 m_padToDieDelayOpt->Enable( hasConnection );
1374
1375 if( !m_padToDieOpt->IsEnabled() )
1376 m_padToDieOpt->SetValue( false );
1377
1378 if( !m_padToDieDelayOpt->IsEnabled() )
1379 m_padToDieDelayOpt->SetValue( false );
1380
1381 // We can show/hide this here because it doesn't require the layout to be refreshed.
1382 // All the others have to be done in their event handlers because doing a layout here
1383 // causes infinite looping on MSW.
1384 m_padToDie.Show( m_padToDieOpt->GetValue() );
1385 m_padToDieDelay.Show( m_padToDieDelayOpt->GetValue() );
1386
1387 // Enable/disable Copper Layers control
1388 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1389
1390 LSET cu_set = m_previewPad->GetLayerSet() & LSET::AllCuMask();
1391
1392 switch( m_padType->GetSelection() )
1393 {
1394 case PTH_DLG_TYPE:
1395 if( !cu_set.any() )
1396 m_stackupImagesBook->SetSelection( 3 );
1397 else if( !m_previewPad->GetRemoveUnconnected() )
1398 m_stackupImagesBook->SetSelection( 0 );
1399 else if( m_previewPad->GetKeepTopBottom() )
1400 m_stackupImagesBook->SetSelection( 1 );
1401 else
1402 m_stackupImagesBook->SetSelection( 2 );
1403
1404 break;
1405
1406 case NPTH_DLG_TYPE:
1407 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1408 m_stackupImagesBook->SetSelection( 4 );
1409 else if( cu_set.test( F_Cu ) )
1410 m_stackupImagesBook->SetSelection( 5 );
1411 else if( cu_set.test( B_Cu ) )
1412 m_stackupImagesBook->SetSelection( 6 );
1413 else
1414 m_stackupImagesBook->SetSelection( 7 );
1415
1416 break;
1417
1418 case SMD_DLG_TYPE:
1419 case CONN_DLG_TYPE:
1420 case APERTURE_DLG_TYPE:
1421 m_stackupImagesBook->ChangeSelection( 3 );
1422 break;
1423 }
1424
1425 m_legacyTeardropsWarning->Show( m_board->LegacyTeardrops() );
1426}
1427
1428
1430{
1431 event.Enable( !m_board->LegacyTeardrops() );
1432}
1433
1434
1436{
1437 bool isOnCopperLayer = ( m_previewPad->GetLayerSet() & LSET::AllCuMask() ).any();
1438 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1439}
1440
1441
1442void DIALOG_PAD_PROPERTIES::updatePadLayersList( LSET layer_mask, bool remove_unconnected,
1443 bool keep_top_bottom )
1444{
1446
1447 switch( m_padType->GetSelection() )
1448 {
1449 case PTH_DLG_TYPE:
1450 if( !layer_mask.any() )
1451 layer_mask = PAD::PTHMask();
1452
1453 if( !( layer_mask & LSET::AllCuMask() ).any() )
1454 m_rbCopperLayersSel->SetSelection( 3 );
1455 else if( !remove_unconnected )
1456 m_rbCopperLayersSel->SetSelection( 0 );
1457 else if( keep_top_bottom )
1458 m_rbCopperLayersSel->SetSelection( 1 );
1459 else
1460 m_rbCopperLayersSel->SetSelection( 2 );
1461
1462 break;
1463
1464 case SMD_DLG_TYPE:
1465 if( !layer_mask.any() )
1466 layer_mask = PAD::SMDMask();
1467
1468 if( layer_mask.test( F_Cu ) )
1469 m_rbCopperLayersSel->SetSelection( 0 );
1470 else
1471 m_rbCopperLayersSel->SetSelection( 1 );
1472
1473 break;
1474
1475 case CONN_DLG_TYPE:
1476 if( !layer_mask.any() )
1477 layer_mask = PAD::ConnSMDMask();
1478
1479 if( layer_mask.test( F_Cu ) )
1480 m_rbCopperLayersSel->SetSelection( 0 );
1481 else
1482 m_rbCopperLayersSel->SetSelection( 1 );
1483
1484 break;
1485
1486 case NPTH_DLG_TYPE:
1487 if( !layer_mask.any() )
1488 layer_mask = PAD::UnplatedHoleMask();
1489
1490 if( layer_mask.test( F_Cu ) && layer_mask.test( B_Cu ) )
1491 m_rbCopperLayersSel->SetSelection( 0 );
1492 else if( layer_mask.test( F_Cu ) )
1493 m_rbCopperLayersSel->SetSelection( 1 );
1494 else if( layer_mask.test( B_Cu ) )
1495 m_rbCopperLayersSel->SetSelection( 2 );
1496 else
1497 m_rbCopperLayersSel->SetSelection( 3 );
1498
1499 break;
1500
1501 case APERTURE_DLG_TYPE:
1502 if( !layer_mask.any() )
1503 layer_mask = PAD::ApertureMask();
1504
1505 m_rbCopperLayersSel->SetSelection( 0 );
1506 break;
1507 }
1508
1509 m_layerFrontAdhesive->SetValue( layer_mask[F_Adhes] );
1510 m_layerBackAdhesive->SetValue( layer_mask[B_Adhes] );
1511
1512 m_layerFrontPaste->SetValue( layer_mask[F_Paste] );
1513 m_layerBackPaste->SetValue( layer_mask[B_Paste] );
1514
1515 m_layerFrontSilk->SetValue( layer_mask[F_SilkS] );
1516 m_layerBackSilk->SetValue( layer_mask[B_SilkS] );
1517
1518 m_layerFrontMask->SetValue( layer_mask[F_Mask] );
1519 m_layerBackMask->SetValue( layer_mask[B_Mask] );
1520
1521 m_layerECO1->SetValue( layer_mask[Eco1_User] );
1522 m_layerECO2->SetValue( layer_mask[Eco2_User] );
1523
1524 m_layerUserDwgs->SetValue( layer_mask[Dwgs_User] );
1525}
1526
1527
1529{
1530 bool retVal = DIALOG_SHIM::Show( aShow );
1531
1532 if( aShow )
1533 {
1534 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1535 // wxWidgets needs to have these set when the panel is visible for some reason.
1536 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1544
1545 Layout();
1546 }
1547
1548 return retVal;
1549}
1550
1551
1552void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1553{
1555 redraw();
1556
1557 if( m_initialized )
1558 OnModify();
1559}
1560
1561
1562void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1563{
1565 redraw();
1566
1567 if( m_initialized )
1568 OnModify();
1569}
1570
1571
1573{
1575
1576 wxArrayString error_msgs;
1577 wxArrayString warning_msgs;
1578
1579 m_previewPad->CheckPad( m_parentFrame, true,
1580 [&]( int errorCode, const wxString& msg )
1581 {
1582 if( errorCode == DRCE_PADSTACK_INVALID )
1583 error_msgs.Add( _( "Error: " ) + msg );
1584 else if( errorCode == DRCE_PADSTACK )
1585 warning_msgs.Add( _( "Warning: " ) + msg );
1586 else if( errorCode == DRCE_PAD_TH_WITH_NO_HOLE )
1587 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1588 } );
1589
1590 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1591 {
1592 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1593 : _( "Pad Properties Warnings" );
1594 HTML_MESSAGE_BOX dlg( this, title );
1595
1596 wxArrayString msgs = error_msgs;
1597
1598 for( const wxString& msg : warning_msgs )
1599 msgs.Add( msg );
1600
1601 dlg.ListSet( msgs );
1602
1603 dlg.ShowModal();
1604 }
1605
1606 return error_msgs.GetCount() == 0;
1607}
1608
1609
1611{
1612 if( !m_initialized )
1613 return;
1614
1615 KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1616 KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( view->GetPainter() );
1617 KIGFX::PCB_RENDER_SETTINGS* settings = painter->GetSettings();
1618
1619 m_padPreviewGAL->StopDrawing();
1620
1621 // The layer used to place primitive items selected when editing custom pad shapes
1622 // we use here a layer never used in a pad:
1623 #define SELECTED_ITEMS_LAYER Dwgs_User
1624
1625 view->ClearTopLayers();
1627 view->SetTopLayer( m_editLayer );
1629
1630 static const std::vector<int> topLayers = {
1635 };
1636
1637 for( int layer : topLayers )
1638 view->SetTopLayer( layer );
1639
1640 m_axisOrigin->SetPosition( m_previewPad->GetPosition() );
1641
1642 view->Update( m_previewPad );
1643
1644 // delete previous items if highlight list
1645 while( m_highlight.size() )
1646 {
1647 delete m_highlight.back(); // the dtor also removes item from view
1648 m_highlight.pop_back();
1649 }
1650
1651 BOX2I bbox = m_previewPad->ViewBBox();
1652
1653 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1654 {
1655 // The origin always goes in the middle of the canvas; we want offsetting the pad
1656 // shape to move the pad, not the hole
1657 bbox.Move( -m_previewPad->GetPosition() );
1658 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1659 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1660
1661 // Don't blow up the GAL on too-large numbers
1662 if( maxXExtent > INT_MAX / 4 )
1663 maxXExtent = INT_MAX / 4;
1664
1665 if( maxYExtent > INT_MAX / 4 )
1666 maxYExtent = INT_MAX / 4;
1667
1668 BOX2D viewBox( m_previewPad->GetPosition(), {0, 0} );
1669 BOX2D canvasBox( m_previewPad->GetPosition(), {0, 0} );
1670 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1671 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1672
1673 view->SetBoundary( canvasBox );
1674
1675 // Autozoom
1676 view->SetViewport( viewBox );
1677
1678 m_padPreviewGAL->StartDrawing();
1679 m_padPreviewGAL->Refresh();
1680 }
1681}
1682
1683
1685{
1686 if( !wxDialog::TransferDataToWindow() )
1687 return false;
1688
1689 if( !m_panelGeneral->TransferDataToWindow() )
1690 return false;
1691
1692 if( !m_localSettingsPanel->TransferDataToWindow() )
1693 return false;
1694
1695 return true;
1696}
1697
1698
1700{
1701 BOARD_COMMIT commit( m_parent );
1702
1703 if( !wxDialog::TransferDataFromWindow() )
1704 return false;
1705
1706 if( !m_panelGeneral->TransferDataFromWindow() )
1707 return false;
1708
1709 if( !m_localSettingsPanel->TransferDataFromWindow() )
1710 return false;
1711
1712 if( !padValuesOK() )
1713 return false;
1714
1716 return false;
1717
1718 m_padPreviewGAL->StopDrawing();
1719
1720 PAD_TOOL* padTool = m_parent->GetToolManager()->GetTool<PAD_TOOL>();
1721 padTool->SetLastPadNumber( m_masterPad->GetNumber() );
1722
1723 // m_masterPad is a pattern: ensure there is no net for this pad:
1725
1726 if( !m_currentPad ) // Set current Pad parameters
1727 return true;
1728
1729 commit.Modify( m_currentPad );
1730
1731 // Update values
1732
1733 // transferDataToPad only handles the current edit layer, so m_masterPad isn't accurate
1734 // TODO(JE) this could be cleaner
1735 m_currentPad->SetPadstack( m_previewPad->Padstack() );
1736
1737 m_currentPad->SetAttribute( m_masterPad->GetAttribute() );
1738 m_currentPad->SetFPRelativeOrientation( m_masterPad->GetOrientation() );
1739 m_currentPad->SetPadToDieLength( m_masterPad->GetPadToDieLength() );
1740 m_currentPad->SetPadToDieDelay( m_masterPad->GetPadToDieDelay() );
1741 m_currentPad->SetLayerSet( m_masterPad->GetLayerSet() );
1742 m_currentPad->SetNumber( m_masterPad->GetNumber() );
1743
1744 int padNetcode = NETINFO_LIST::UNCONNECTED;
1745
1746 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1747 if( m_masterPad->GetAttribute() != PAD_ATTRIB::NPTH )
1748 padNetcode = m_padNetSelector->GetSelectedNetcode();
1749
1750 m_currentPad->SetNetCode( padNetcode );
1751
1752 m_currentPad->GetTeardropParams() = m_masterPad->GetTeardropParams();
1753
1754 // Set the fabrication property:
1755 m_currentPad->SetProperty( getSelectedProperty() );
1756
1757 // define the way the clearance area is defined in zones
1758 m_currentPad->SetCustomShapeInZoneOpt( m_masterPad->GetCustomShapeInZoneOpt() );
1759
1760 if( m_currentPad->GetParentFootprint() && m_currentPad->GetParentFootprint()->IsFlipped() )
1761 {
1762 // flip pad (up/down) around its position
1763 m_currentPad->Flip( m_currentPad->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
1764 }
1765
1766 m_currentPad->SetPosition( m_masterPad->GetPosition() );
1767
1768 m_parent->SetMsgPanel( m_currentPad );
1769
1770 // redraw the area where the pad was
1771 m_parent->GetCanvas()->Refresh();
1772
1773 commit.Push( _( "Edit Pad Properties" ) );
1774
1775 return true;
1776}
1777
1778
1780{
1781 PAD_PROP prop = PAD_PROP::NONE;
1782
1783 switch( m_choiceFabProperty->GetSelection() )
1784 {
1785 case 0: prop = PAD_PROP::NONE; break;
1786 case 1: prop = PAD_PROP::BGA; break;
1787 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1788 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1789 case 4: prop = PAD_PROP::TESTPOINT; break;
1790 case 5: prop = PAD_PROP::HEATSINK; break;
1791 case 6: prop = PAD_PROP::MECHANICAL; break;
1792 case 7: prop = PAD_PROP::CASTELLATED; break;
1793 case 8: prop = PAD_PROP::PRESSFIT; break;
1794 }
1795
1796 return prop;
1797}
1798
1799
1801{
1802 bool isRound = ( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE );
1803
1804 if( isRound )
1805 {
1806 m_holeXLabel->SetLabel( _( "Diameter:" ) );
1807 m_holeY.Show( false );
1808 }
1809 else
1810 {
1811 m_holeXLabel->SetLabel( _( "Hole size X:" ) );
1812 m_holeY.Show( true );
1813 }
1814
1815 m_holeXLabel->GetParent()->Layout();
1816
1817 if( !isRound )
1818 {
1819 // Disable all
1820 m_backDrillChoice->Enable( false );
1821 m_backDrillTopLayer->Enable( false );
1822 m_backDrillTopLayerLabel->Enable( false );
1823 m_backDrillBottomLayer->Enable( false );
1824 m_backDrillBottomLayerLabel->Enable( false );
1825
1826 m_topPostMachining->Enable( false );
1827 m_topPostMachineSize1Binder.Enable( false );
1828 m_topPostMachineSize2Binder.Enable( false );
1829 m_topPostMachineSize1Label->Enable( false );
1830 m_topPostMachineSize2Label->Enable( false );
1831
1832 m_bottomPostMachining->Enable( false );
1833 m_bottomPostMachineSize1Binder.Enable( false );
1834 m_bottomPostMachineSize2Binder.Enable( false );
1835 m_bottomPostMachineSize1Label->Enable( false );
1836 m_bottomPostMachineSize2Label->Enable( false );
1837 }
1838 else
1839 {
1840 // Enable main choices
1841 m_backDrillChoice->Enable( true );
1842 m_topPostMachining->Enable( true );
1843 m_bottomPostMachining->Enable( true );
1844
1845 // Update sub-controls based on selection
1846 wxCommandEvent dummy;
1850 }
1851}
1852
1853
1855{
1856 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1858 {
1859 m_sizeXLabel->SetLabel( _( "Diameter:" ) );
1860 m_sizeY.Show( false );
1862 m_minTrackWidthHint->SetLabel( _( "d" ) );
1863 m_stLenPercentHint->SetLabel( _( "d" ) );
1864 m_stWidthPercentHint->SetLabel( _( "d" ) );
1865 }
1866 else
1867 {
1868 m_sizeXLabel->SetLabel( _( "Pad size X:" ) );
1869 m_sizeY.Show( true );
1871 m_minTrackWidthHint->SetLabel( _( "w" ) );
1872 m_stLenPercentHint->SetLabel( _( "w" ) );
1873 m_stWidthPercentHint->SetLabel( _( "w" ) );
1874 }
1875
1876 m_sizeXLabel->GetParent()->Layout();
1877 resetSize();
1878 Layout();
1879 m_MainSizer->Fit( this );
1880}
1881
1882
1884{
1885 if( !Validate() )
1886 return false;
1887
1888 if( !m_panelGeneral->Validate() )
1889 return false;
1890
1891 if( !m_localSettingsPanel->Validate() )
1892 return false;
1893
1894 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1895 return false;
1896
1897 switch( m_cbPadstackMode->GetSelection() )
1898 {
1899 default:
1900 case 0: aPad->Padstack().SetMode( PADSTACK::MODE::NORMAL ); break;
1901 case 1: aPad->Padstack().SetMode( PADSTACK::MODE::FRONT_INNER_BACK ); break;
1902 case 2: aPad->Padstack().SetMode( PADSTACK::MODE::CUSTOM ); break;
1903 }
1904
1905 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1906 aPad->SetShape( m_editLayer, code_shape[m_PadShapeSelector->GetSelection()] );
1907
1910 else
1912
1913 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
1915
1916 aPad->GetTeardropParams().m_Enabled = m_cbTeardrops->GetValue();
1923 aPad->GetTeardropParams().m_CurvedEdges = m_curvedEdges->GetValue();
1925
1926 // Read pad clearances values:
1927 if( m_clearance.IsNull() )
1928 aPad->SetLocalClearance( {} );
1929 else
1930 aPad->SetLocalClearance( m_clearance.GetIntValue() );
1931
1932 if( m_maskMargin.IsNull() )
1933 aPad->SetLocalSolderMaskMargin( {} );
1934 else
1935 aPad->SetLocalSolderMaskMargin( m_maskMargin.GetIntValue() );
1936
1937 aPad->SetLocalSolderPasteMargin( m_pasteMargin.GetOffsetValue() );
1938 aPad->SetLocalSolderPasteMarginRatio( m_pasteMargin.GetRatioValue() );
1939
1940 if( m_spokeWidth.IsNull() )
1942 else
1943 aPad->SetLocalThermalSpokeWidthOverride( m_spokeWidth.GetIntValue() );
1944
1945 if( m_thermalGap.IsNull() )
1946 aPad->SetLocalThermalGapOverride( {} );
1947 else
1948 aPad->SetLocalThermalGapOverride( m_thermalGap.GetIntValue() );
1949
1950 aPad->SetThermalSpokeAngle( m_spokeAngle.GetAngleValue() );
1951
1952 // And rotation
1953 aPad->SetOrientation( m_pad_orientation.GetAngleValue() );
1954
1955 switch( m_ZoneConnectionChoice->GetSelection() )
1956 {
1957 default:
1958 case 0: aPad->SetLocalZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1959 case 1: aPad->SetLocalZoneConnection( ZONE_CONNECTION::FULL ); break;
1960 case 2: aPad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1961 case 3: aPad->SetLocalZoneConnection( ZONE_CONNECTION::NONE ); break;
1962 }
1963
1964 VECTOR2I pos( m_posX.GetIntValue(), m_posY.GetIntValue() );
1965
1966 if( FOOTPRINT* fp = aPad->GetParentFootprint() )
1967 {
1968 pos -= fp->GetPosition();
1969 RotatePoint( pos, -fp->GetOrientation() );
1970 }
1971
1972 aPad->SetPosition( pos );
1973
1974 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1975 {
1977 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeX.GetIntValue() ) );
1978 }
1979 else
1980 {
1982 aPad->SetDrillSize( VECTOR2I( m_holeX.GetIntValue(), m_holeY.GetIntValue() ) );
1983 }
1984
1985 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CIRCLE )
1986 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
1987 else
1988 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeY.GetIntValue() ) );
1989
1990 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
1991 // remember DeltaSize.x is the Y size variation
1992 bool error = false;
1993 VECTOR2I delta( 0, 0 );
1994
1995 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::TRAPEZOID )
1996 {
1997 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
1998 if( m_trapAxisCtrl->GetSelection() == 0 )
1999 delta.x = m_trapDelta.GetIntValue();
2000 else
2001 delta.y = m_trapDelta.GetIntValue();
2002
2003 if( delta.x < 0 && delta.x < -aPad->GetSize( m_editLayer ).y )
2004 {
2005 delta.x = -aPad->GetSize( m_editLayer ).y + 2;
2006 error = true;
2007 }
2008
2009 if( delta.x > 0 && delta.x > aPad->GetSize( m_editLayer ).y )
2010 {
2011 delta.x = aPad->GetSize( m_editLayer ).y - 2;
2012 error = true;
2013 }
2014
2015 if( delta.y < 0 && delta.y < -aPad->GetSize( m_editLayer ).x )
2016 {
2017 delta.y = -aPad->GetSize( m_editLayer ).x + 2;
2018 error = true;
2019 }
2020
2021 if( delta.y > 0 && delta.y > aPad->GetSize( m_editLayer ).x )
2022 {
2023 delta.y = aPad->GetSize( m_editLayer ).x - 2;
2024 error = true;
2025 }
2026 }
2027
2028 aPad->SetDelta( m_editLayer, delta );
2029
2030 if( m_offsetShapeOpt->GetValue() )
2031 aPad->SetOffset( m_editLayer, VECTOR2I( m_offsetX.GetIntValue(), m_offsetY.GetIntValue() ) );
2032 else
2033 aPad->SetOffset( m_editLayer, VECTOR2I() );
2034
2035 // Read pad length die
2036 if( m_padToDieOpt->GetValue() )
2037 aPad->SetPadToDieLength( m_padToDie.GetIntValue() );
2038 else
2039 aPad->SetPadToDieLength( 0 );
2040
2041 if( m_padToDieDelayOpt->GetValue() )
2042 aPad->SetPadToDieDelay( m_padToDieDelay.GetIntValue() );
2043 else
2044 aPad->SetPadToDieDelay( 0 );
2045
2046 aPad->SetNumber( m_padNumCtrl->GetValue() );
2047 aPad->SetNetCode( m_padNetSelector->GetSelectedNetcode() );
2048
2049 int chamfers = 0;
2050
2051 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
2052 {
2053 if( m_cbTopLeft->GetValue() )
2054 chamfers |= RECT_CHAMFER_TOP_LEFT;
2055
2056 if( m_cbTopRight->GetValue() )
2057 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2058
2059 if( m_cbBottomLeft->GetValue() )
2060 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2061
2062 if( m_cbBottomRight->GetValue() )
2063 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2064 }
2065 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
2066 {
2067 if( m_cbTopLeft1->GetValue() )
2068 chamfers |= RECT_CHAMFER_TOP_LEFT;
2069
2070 if( m_cbTopRight1->GetValue() )
2071 chamfers |= RECT_CHAMFER_TOP_RIGHT;
2072
2073 if( m_cbBottomLeft1->GetValue() )
2074 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
2075
2076 if( m_cbBottomRight1->GetValue() )
2077 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
2078 }
2079
2080 aPad->SetChamferPositions( m_editLayer, chamfers );
2081
2082 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CUSTOM )
2083 {
2084 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
2085 // that is the minimal area of this pad, and is useful to ensure a hole
2086 // diameter is acceptable, and is used in Gerber files as flashed area
2087 // reference
2089 aPad->SetSize( m_editLayer, VECTOR2I( m_sizeX.GetIntValue(), m_sizeX.GetIntValue() ) );
2090 }
2091
2092 // Define the way the clearance area is defined in zones. Since all non-custom pad
2093 // shapes are convex to begin with, this really only makes any difference for custom
2094 // pad shapes.
2097
2098 switch( aPad->GetAttribute() )
2099 {
2100 case PAD_ATTRIB::PTH:
2101 break;
2102
2103 case PAD_ATTRIB::CONN:
2104 case PAD_ATTRIB::SMD:
2105 // SMD and PAD_ATTRIB::CONN has no hole.
2106 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
2107 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
2108 // and are intended to be used in virtual edge board connectors
2109 // However we can accept a non null offset,
2110 // mainly to allow complex pads build from a set of basic pad shapes
2111 aPad->SetDrillSize( VECTOR2I( 0, 0 ) );
2112 break;
2113
2114 case PAD_ATTRIB::NPTH:
2115 // Mechanical purpose only:
2116 // no net name, no pad name allowed
2117 aPad->SetNumber( wxEmptyString );
2119 break;
2120
2121 default:
2122 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
2123 break;
2124 }
2125
2126 if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::ROUNDRECT )
2127 {
2128 aPad->SetRoundRectRadiusRatio( m_editLayer, m_cornerRatio.GetDoubleValue() / 100.0 );
2129 }
2130 else if( aPad->GetShape( m_editLayer ) == PAD_SHAPE::CHAMFERED_RECT )
2131 {
2133 {
2134 aPad->SetChamferRectRatio( m_editLayer, m_mixedChamferRatio.GetDoubleValue() / 100.0 );
2135 aPad->SetRoundRectRadiusRatio( m_editLayer, m_mixedCornerRatio.GetDoubleValue() / 100.0 );
2136 }
2137 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
2138 {
2139 aPad->SetChamferRectRatio( m_editLayer, m_chamferRatio.GetDoubleValue() / 100.0 );
2141 }
2142 }
2143
2145
2146 LSET padLayerMask = LSET();
2147 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
2148
2150
2151 switch( m_padType->GetSelection() )
2152 {
2153 case PTH_DLG_TYPE:
2154 switch( copperLayersChoice )
2155 {
2156 case 0:
2157 // All copper layers
2158 padLayerMask |= LSET::AllCuMask();
2159 break;
2160
2161 case 1:
2162 // Front, back and connected
2163 padLayerMask |= LSET::AllCuMask();
2165 break;
2166
2167 case 2:
2168 // Connected only
2169 padLayerMask |= LSET::AllCuMask();
2171 break;
2172
2173 case 3:
2174 // No copper layers
2175 break;
2176 }
2177
2178 break;
2179
2180 case NPTH_DLG_TYPE:
2181 switch( copperLayersChoice )
2182 {
2183 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
2184 case 1: padLayerMask.set( F_Cu ); break;
2185 case 2: padLayerMask.set( B_Cu ); break;
2186 default: break;
2187 }
2188
2189 break;
2190
2191 case SMD_DLG_TYPE:
2192 case CONN_DLG_TYPE:
2193 switch( copperLayersChoice )
2194 {
2195 case 0: padLayerMask.set( F_Cu ); break;
2196 case 1: padLayerMask.set( B_Cu ); break;
2197 }
2198
2199 break;
2200
2201 case APERTURE_DLG_TYPE:
2202 // no copper layers
2203 break;
2204 }
2205
2206 if( m_layerFrontAdhesive->GetValue() )
2207 padLayerMask.set( F_Adhes );
2208
2209 if( m_layerBackAdhesive->GetValue() )
2210 padLayerMask.set( B_Adhes );
2211
2212 if( m_layerFrontPaste->GetValue() )
2213 padLayerMask.set( F_Paste );
2214
2215 if( m_layerBackPaste->GetValue() )
2216 padLayerMask.set( B_Paste );
2217
2218 if( m_layerFrontSilk->GetValue() )
2219 padLayerMask.set( F_SilkS );
2220
2221 if( m_layerBackSilk->GetValue() )
2222 padLayerMask.set( B_SilkS );
2223
2224 if( m_layerFrontMask->GetValue() )
2225 padLayerMask.set( F_Mask );
2226
2227 if( m_layerBackMask->GetValue() )
2228 padLayerMask.set( B_Mask );
2229
2230 if( m_layerECO1->GetValue() )
2231 padLayerMask.set( Eco1_User );
2232
2233 if( m_layerECO2->GetValue() )
2234 padLayerMask.set( Eco2_User );
2235
2236 if( m_layerUserDwgs->GetValue() )
2237 padLayerMask.set( Dwgs_User );
2238
2239 aPad->SetLayerSet( padLayerMask );
2240
2241 // Save backdrill properties
2242 PADSTACK::DRILL_PROPS secondaryDrill;
2243 secondaryDrill.size = VECTOR2I( m_backDrillBottomSizeBinder.GetIntValue(),
2244 m_backDrillBottomSizeBinder.GetIntValue() );
2245 secondaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2246
2247 PADSTACK::DRILL_PROPS tertiaryDrill;
2248 tertiaryDrill.size = VECTOR2I( m_backDrillTopSizeBinder.GetIntValue(),
2249 m_backDrillTopSizeBinder.GetIntValue() );
2250 tertiaryDrill.shape = PAD_DRILL_SHAPE::CIRCLE;
2251
2252 if( !m_backDrillChoice->GetSelection() )
2253 {
2254 secondaryDrill.start = UNDEFINED_LAYER;
2255 secondaryDrill.end = UNDEFINED_LAYER;
2256 }
2257
2258 if( m_backDrillChoice->GetSelection() == 1 || m_backDrillChoice->GetSelection() == 3 ) // Front
2259 {
2260 tertiaryDrill.start = F_Cu;
2261
2262 if( m_backDrillTopLayer->GetSelection() != wxNOT_FOUND )
2263 tertiaryDrill.end = ToLAYER_ID( (intptr_t)m_backDrillTopLayer->GetClientData( m_backDrillTopLayer->GetSelection() ) );
2264 else
2265 tertiaryDrill.end = UNDEFINED_LAYER;
2266 }
2267
2268 if( m_backDrillChoice->GetSelection() == 2 || m_backDrillChoice->GetSelection() == 3 ) // Back
2269 {
2270 secondaryDrill.start = B_Cu;
2271
2272 if( m_backDrillBottomLayer->GetSelection() != wxNOT_FOUND )
2273 secondaryDrill.end = ToLAYER_ID( (intptr_t)m_backDrillBottomLayer->GetClientData( m_backDrillBottomLayer->GetSelection() ) );
2274 else
2275 secondaryDrill.end = UNDEFINED_LAYER;
2276 }
2277
2278 aPad->Padstack().SecondaryDrill() = secondaryDrill;
2279 aPad->Padstack().TertiaryDrill() = tertiaryDrill;
2280
2281 // Front Post Machining
2282 PADSTACK::POST_MACHINING_PROPS frontPostMachining;
2283
2284 switch( m_topPostMachining->GetSelection() )
2285 {
2286 case 1: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2287 case 2: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2288 default: frontPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2289 }
2290
2291 frontPostMachining.size = m_topPostMachineSize1Binder.GetIntValue();
2292
2293 if( frontPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2294 frontPostMachining.angle = m_topPostMachineSize2Binder.GetIntValue();
2295 else
2296 frontPostMachining.depth = m_topPostMachineSize2Binder.GetIntValue();
2297
2298 aPad->Padstack().FrontPostMachining() = frontPostMachining;
2299
2300 // Back Post Machining
2301 PADSTACK::POST_MACHINING_PROPS backPostMachining;
2302
2303 switch( m_bottomPostMachining->GetSelection() )
2304 {
2305 case 1: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK; break;
2306 case 2: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE; break;
2307 default: backPostMachining.mode = PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED; break;
2308 }
2309
2310 backPostMachining.size = m_bottomPostMachineSize1Binder.GetIntValue();
2311
2312 if( backPostMachining.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
2313 backPostMachining.angle = m_bottomPostMachineSize2Binder.GetIntValue();
2314 else
2315 backPostMachining.depth = m_bottomPostMachineSize2Binder.GetIntValue();
2316
2317 aPad->Padstack().BackPostMachining() = backPostMachining;
2318
2319 return !error;
2320}
2321
2322
2323
2324
2325void DIALOG_PAD_PROPERTIES::onBackDrillChoice( wxCommandEvent& event )
2326{
2327 int selection = m_backDrillChoice->GetSelection();
2328 // 0: None, 1: Top, 2: Bottom, 3: Both
2329
2330 bool enableTop = ( selection == 1 || selection == 3 );
2331 bool enableBottom = ( selection == 2 || selection == 3 );
2332
2333 m_backDrillTopSizeBinder.Enable( enableTop );
2334 m_backDrillTopLayer->Enable( enableTop );
2335 m_backDrillTopLayerLabel->Enable( enableTop );
2336
2337 m_backDrillBottomSizeBinder.Enable( enableBottom );
2338 m_backDrillBottomLayer->Enable( enableBottom );
2339 m_backDrillBottomLayerLabel->Enable( enableBottom );
2340
2341}
2342
2343
2345{
2346 int selection = m_topPostMachining->GetSelection();
2347 // 0: None, 1: Countersink, 2: Counterbore
2348
2349 bool enable = ( selection != 0 );
2350 m_topPostMachineSize1Binder.Enable( enable );
2351 m_topPostMachineSize2Binder.Enable( enable );
2352 m_topPostMachineSize1Label->Enable( enable );
2353 m_topPostMachineSize2Label->Enable( enable );
2354
2355 if( selection == 1 ) // Countersink
2356 {
2357 m_topPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2358 m_topPostMachineSize2Units->SetLabel( _( "deg" ) );
2359
2360 if( m_topPostMachineSize2Binder.IsIndeterminate() || m_topPostMachineSize2Binder.GetDoubleValue() == 0 )
2361 m_topPostMachineSize2Binder.SetValue( "82" );
2362 }
2363 else if( selection == 2 ) // Counterbore
2364 {
2365 m_topPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2366 m_topPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2367 }
2368}
2369
2370
2372{
2373 int selection = m_bottomPostMachining->GetSelection();
2374 // 0: None, 1: Countersink, 2: Counterbore
2375
2376 bool enable = ( selection != 0 );
2377 m_bottomPostMachineSize1Binder.Enable( enable );
2378 m_bottomPostMachineSize2Binder.Enable( enable );
2379 m_bottomPostMachineSize1Label->Enable( enable );
2380 m_bottomPostMachineSize2Label->Enable( enable );
2381
2382 if( selection == 1 ) // Countersink
2383 {
2384 m_bottomPostMachineSize2Label->SetLabel( _( "Angle:" ) );
2385 m_bottomPostMachineSize2Units->SetLabel( _( "deg" ) );
2386
2387 if( m_bottomPostMachineSize2Binder.IsIndeterminate() || m_bottomPostMachineSize2Binder.GetDoubleValue() == 0 )
2388 m_bottomPostMachineSize2Binder.SetValue( "82" );
2389 }
2390 else if( selection == 2 ) // Counterbore
2391 {
2392 m_bottomPostMachineSize2Label->SetLabel( _( "Depth:" ) );
2393 m_bottomPostMachineSize2Units->SetLabel( EDA_UNIT_UTILS::GetLabel( m_parent->GetUserUnits() ) );
2394 }
2395}
2396
2397
2398void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2399{
2400 if( m_offsetShapeOpt->GetValue() )
2401 {
2402 m_offsetX.SetValue( m_previewPad->GetOffset( m_editLayer ).x );
2403 m_offsetY.SetValue( m_previewPad->GetOffset( m_editLayer ).y );
2404 }
2405
2406 // Show/hide controls depending on m_offsetShapeOpt being enabled
2407 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2408 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2409
2410 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2411 m_notebook->GetPage( i )->Layout();
2412
2413 OnValuesChanged( event );
2414}
2415
2416
2418{
2419 if( m_padToDieOpt->GetValue() && m_currentPad )
2420 m_padToDie.SetValue( m_currentPad->GetPadToDieLength() );
2421
2422 OnValuesChanged( event );
2423}
2424
2425
2427{
2428 if( m_padToDieDelayOpt->GetValue() && m_currentPad )
2429 m_padToDieDelay.SetValue( m_currentPad->GetPadToDieDelay() );
2430
2431 OnValuesChanged( event );
2432}
2433
2434
2435void DIALOG_PAD_PROPERTIES::onModify( wxSpinDoubleEvent& aEvent )
2436{
2437 if( m_initialized )
2438 OnModify();
2439}
2440
2441
2442void DIALOG_PAD_PROPERTIES::onModify( wxCommandEvent& aEvent )
2443{
2444 if( m_initialized )
2445 OnModify();
2446}
2447
2448
2449void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2450{
2451 if( m_initialized )
2452 {
2454 return;
2455
2456 // If the pad size has changed, update the displayed values for rounded rect pads.
2459
2460 redraw();
2461 OnModify();
2462 }
2463}
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
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:737
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