KiCad PCB EDA Suite
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 (C) 1992-2022 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 <base_units.h>
28#include <bitmaps.h>
29#include <board_commit.h>
30#include <board.h>
32#include <footprint.h>
33#include <confirm.h>
34#include <core/arraydim.h>
35#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
39#include <macros.h>
40#include <pad.h>
41#include <pcb_base_frame.h>
43#include <pcb_painter.h>
44#include <pcbnew_settings.h>
46#include <view/view_controls.h>
48#include <tool/tool_manager.h>
49#include <tools/pad_tool.h>
50#include <advanced_config.h> // for pad property feature management
51#include <wx/choicdlg.h>
52
54
55// list of pad shapes, ordered like the pad shape wxChoice in dialog.
57{
64 PAD_SHAPE::CHAMFERED_RECT, // choice = CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT
65 PAD_SHAPE::CUSTOM, // choice = CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
66 PAD_SHAPE::CUSTOM // choice = PAD_SHAPE::CUSTOM_RECT_ANCHOR
67};
68
69
70// the ordered index of the pad shape wxChoice in dialog.
71// keep it consistent with code_shape[] and dialog strings
73{
83};
84
85
87{
92 PAD_ATTRIB::SMD // Aperture pad :type SMD with no copper layers,
93 // only on tech layers (usually only on paste layer
94};
95
96
97// These define have the same value as the m_PadType wxChoice GetSelected() return value
98#define PTH_DLG_TYPE 0
99#define SMD_DLG_TYPE 1
100#define CONN_DLG_TYPE 2
101#define NPTH_DLG_TYPE 3
102#define APERTURE_DLG_TYPE 4
103
104
106{
107 DIALOG_PAD_PROPERTIES dlg( this, aPad );
108
109 dlg.ShowQuasiModal();
110}
111
112
115 m_parent( aParent ),
116 m_canUpdate( false ),
117 m_posX( aParent, m_posXLabel, m_posXCtrl, m_posXUnits ),
118 m_posY( aParent, m_posYLabel, m_posYCtrl, m_posYUnits ),
119 m_sizeX( aParent, m_sizeXLabel, m_sizeXCtrl, m_sizeXUnits ),
120 m_sizeY( aParent, m_sizeYLabel, m_sizeYCtrl, m_sizeYUnits ),
121 m_offsetX( aParent, m_offsetXLabel, m_offsetXCtrl, m_offsetXUnits ),
122 m_offsetY( aParent, m_offsetYLabel, m_offsetYCtrl, m_offsetYUnits ),
123 m_padToDie( aParent, m_padToDieLabel, m_padToDieCtrl, m_padToDieUnits ),
124 m_trapDelta( aParent, m_trapDeltaLabel, m_trapDeltaCtrl, m_trapDeltaUnits ),
125 m_cornerRadius( aParent, m_cornerRadiusLabel, m_cornerRadiusCtrl, m_cornerRadiusUnits ),
126 m_cornerRatio( aParent, m_cornerRatioLabel, m_cornerRatioCtrl, m_cornerRatioUnits ),
127 m_chamferRatio( aParent, m_chamferRatioLabel, m_chamferRatioCtrl, m_chamferRatioUnits ),
128 m_mixedCornerRatio( aParent, m_mixedCornerRatioLabel, m_mixedCornerRatioCtrl,
129 m_mixedCornerRatioUnits ),
130 m_mixedChamferRatio( aParent, m_mixedChamferRatioLabel, m_mixedChamferRatioCtrl,
131 m_mixedChamferRatioUnits ),
132 m_holeX( aParent, m_holeXLabel, m_holeXCtrl, m_holeXUnits ),
133 m_holeY( aParent, m_holeYLabel, m_holeYCtrl, m_holeYUnits ),
134 m_clearance( aParent, m_clearanceLabel, m_clearanceCtrl, m_clearanceUnits ),
135 m_maskMargin( aParent, m_maskMarginLabel, m_maskMarginCtrl, m_maskMarginUnits ),
136 m_pasteMargin( aParent, m_pasteMarginLabel, m_pasteMarginCtrl, m_pasteMarginUnits ),
137 m_pasteMarginRatio( aParent, m_pasteMarginRatioLabel, m_pasteMarginRatioCtrl,
138 m_pasteMarginRatioUnits ),
139 m_thermalGap( aParent, m_thermalGapLabel, m_thermalGapCtrl, m_thermalGapUnits ),
140 m_spokeWidth( aParent, m_spokeWidthLabel, m_spokeWidthCtrl, m_spokeWidthUnits ),
141 m_spokeAngle( aParent, m_spokeAngleLabel, m_spokeAngleCtrl, m_spokeAngleUnits ),
142 m_pad_orientation( aParent, m_PadOrientText, m_cb_padrotation, m_orientationUnits )
143{
144 SetName( PAD_PROPERTIES_DLG_NAME );
145 m_isFpEditor = dynamic_cast<FOOTPRINT_EDIT_FRAME*>( aParent ) != nullptr;
146
147 m_currentPad = aPad; // aPad can be NULL, if the dialog is called
148 // from the footprint editor to set default pad setup
149
151
152 // Configure display origin transforms
155
158
160
163
165 m_dummyPad = new PAD( (FOOTPRINT*) nullptr );
166
167 if( aPad )
168 {
169 SetTitle( _( "Pad Properties" ) );
170
171 *m_dummyPad = *aPad;
173 }
174 else
175 {
176 SetTitle( _( "Default Pad Properties for Add Pad Tool" ) );
177
179 }
180
181 if( m_isFpEditor )
182 {
183 m_padNetLabel->Show( false );
184 m_padNetSelector->Show( false );
185 }
186
187 // Pad needs to have a parent for painting; use the parent board for its design settings
188 if( !m_dummyPad->GetParent() )
190
197
200
202
205
206 initValues();
207
208 wxFont infoFont = KIUI::GetInfoFont( this );
209 m_copperLayersLabel->SetFont( infoFont );
210 m_techLayersLabel->SetFont( infoFont );
211 m_parentInfo->SetFont( infoFont );
212
213 infoFont.SetStyle( wxFONTSTYLE_ITALIC );
214 m_nonCopperNote->SetFont( infoFont );
215 m_staticTextInfoPaste->SetFont( infoFont );
216 m_staticTextPrimitiveListWarning->SetFont( infoFont );
217
220
221 // Usually, TransferDataToWindow is called by OnInitDialog
222 // calling it here fixes all widget sizes so FinishDialogSettings can safely fix minsizes
224
225 // Initialize canvas to be able to display the dummy pad:
227
230 m_canUpdate = true;
231
232 m_padNetSelector->Connect( NET_SELECTED,
233 wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ),
234 nullptr, this );
235
236 if( m_padType->GetSelection() != PTH_DLG_TYPE && m_padType->GetSelection() != NPTH_DLG_TYPE )
237 {
238 m_gbSizerHole->Show( false );
239 m_staticline6->Show( false );
240 }
241
242 // Now all widgets have the size fixed, call FinishDialogSettings
244
245 // Update widgets
246 wxUpdateUIEvent dummyUI;
247 OnUpdateUI( dummyUI );
248
249 // Post a dummy size event to force the pad preview panel to update the
250 // view: actual size, best zoom ... after the frame is shown
251 PostSizeEvent();
252}
253
254
256{
257 m_padNetSelector->Disconnect( NET_SELECTED,
258 wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ),
259 nullptr, this );
260
261 delete m_dummyPad;
262 delete m_axisOrigin;
263}
264
265
266// Store the pad draw option during a session.
268
269
270void DIALOG_PAD_PROPERTIES::OnInitDialog( wxInitDialogEvent& event )
271{
272 m_selectedColor = COLOR4D( 1.0, 1.0, 1.0, 0.7 );
273
274 // Needed on some WM to be sure the pad is redrawn according to the final size
275 // of the canvas, with the right zoom factor
276 redraw();
277}
278
279
280void DIALOG_PAD_PROPERTIES::OnCancel( wxCommandEvent& event )
281{
282 // Mandatory to avoid m_panelShowPadGal trying to draw something
283 // in a non valid context during closing process:
285
286 // Now call default handler for wxID_CANCEL command event
287 event.Skip();
288}
289
290
292{
293 // Enable or disable the widgets in page managing custom shape primitives
294 m_listCtrlPrimitives->Enable( aEnable );
295 m_buttonDel->Enable( aEnable );
296 m_buttonEditShape->Enable( aEnable );
297 m_buttonAddShape->Enable( aEnable );
298 m_buttonDup->Enable( aEnable );
299 m_buttonGeometry->Enable( aEnable );
300}
301
302
304{
305 // Initialize the canvas to display the pad
306 m_padPreviewGAL = new PCB_DRAW_PANEL_GAL( m_boardViewPanel, -1, wxDefaultPosition,
307 wxDefaultSize,
310
311 m_padPreviewSizer->Add( m_padPreviewGAL, 12, wxEXPAND | wxALL, 5 );
312
313 // Show the X and Y axis. It is useful because pad shape can have an offset
314 // or be a complex shape.
315 KIGFX::COLOR4D axis_color = LIGHTBLUE;
316
318 pcbIUScale.mmToIU( 0.2 ),
321
324 m_padPreviewGAL->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
325
326 KIGFX::VIEW_CONTROLS* parentViewControls = m_parent->GetCanvas()->GetViewControls();
327 m_padPreviewGAL->GetViewControls()->ApplySettings( parentViewControls->GetSettings() );
328
329 m_padPreviewGAL->Show();
330
332
333 // fix the pad render mode (filled/not filled)
334 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
335
336 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
337 settings->SetHighContrast( false );
338 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
339
340 // gives a non null grid size (0.001mm) because GAL layer does not like a 0 size grid:
341 double gridsize = 0.001 * pcbIUScale.IU_PER_MM;
342 view->GetGAL()->SetGridSize( VECTOR2D( gridsize, gridsize ) );
343
344 // And do not show the grid:
345 view->GetGAL()->SetGridVisibility( false );
346 view->Add( m_dummyPad );
347 view->Add( m_axisOrigin );
348
350 Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_PROPERTIES::OnResize ) );
351}
352
353
355{
356 // Note: use ChangeValue() to avoid generating a wxEVT_TEXT event
358
361
364}
365
366
368{
371 {
372 return;
373 }
374
375 if( m_cornerRadius.GetValue() < 0 )
376 m_cornerRadiusCtrl->ChangeValue( "0" );
377
379 {
381
384
385 redraw();
386 }
387}
388
389
391{
394 {
395 return;
396 }
397
398 wxObject* ctrl = event.GetEventObject();
399 wxString value = event.GetString();
400 bool changed = false;
401
402 if( ctrl == m_cornerRatioCtrl || ctrl == m_mixedCornerRatioCtrl )
403 {
404 double ratioPercent;
405
406 if( value.ToDouble( &ratioPercent ) )
407 {
408 // Clamp ratioPercent to acceptable value (0.0 to 50.0)
409 if( ratioPercent < 0.0 )
410 {
413 }
414 else if( ratioPercent > 50.0 )
415 {
418 }
419
420 if( ctrl == m_cornerRatioCtrl )
421 m_mixedCornerRatioCtrl->ChangeValue( value );
422 else
423 m_cornerRatioCtrl->ChangeValue( value );
424
425 changed = true;
426 }
427 }
428 else if( ctrl == m_chamferRatioCtrl || ctrl == m_mixedChamferRatioCtrl )
429 {
430 double ratioPercent;
431
432 if( value.ToDouble( &ratioPercent ) )
433 {
434 // Clamp ratioPercent to acceptable value (0.0 to 50.0)
435 if( ratioPercent < 0.0 )
436 {
439 }
440 else if( ratioPercent > 50.0 )
441 {
444 }
445
446 if( ctrl == m_chamferRatioCtrl )
447 m_mixedChamferRatioCtrl->ChangeValue( value );
448 else
449 m_chamferRatioCtrl->ChangeValue( value );
450
451 changed = true;
452 }
453 }
454
455 if( changed && transferDataToPad( m_dummyPad ) )
457
458 redraw();
459}
460
461
463{
464 wxString msg;
465
466 // Disable pad net name wxTextCtrl if the caller is the footprint editor
467 // because nets are living only in the board managed by the board editor
469
481
482 if( m_currentPad )
483 {
485
486 FOOTPRINT* footprint = m_currentPad->GetParent();
487
488 if( footprint )
489 {
492
493 // Display parent footprint info
494 msg.Printf( _("Footprint %s (%s), %s, rotated %g deg"),
495 footprint->Reference().GetShownText(),
496 footprint->Value().GetShownText(),
497 footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
498 footprint->GetOrientation().AsDegrees() );
499 }
500
501 m_parentInfo->SetLabel( msg );
502 }
503 else
504 {
505 m_isFlipped = false;
506 }
507
508 if( m_isFlipped )
509 {
510 // flip pad (up/down) around its position
512 }
513
515
517
518 if( m_currentPad )
519 {
520 m_padNumCtrl->SetValue( m_dummyPad->GetNumber() );
521 }
522 else
523 {
525 m_padNumCtrl->SetValue( padTool->GetLastPadNumber() );
526 }
527
529
530 // Display current pad parameters units:
533
536
539
540 m_offsetShapeOpt->SetValue( m_dummyPad->GetOffset() != wxPoint() );
543
544 if( m_dummyPad->GetDelta().x )
545 {
547 m_trapAxisCtrl->SetSelection( 0 );
548 }
549 else
550 {
552 m_trapAxisCtrl->SetSelection( 1 );
553 }
554
555 m_padToDieOpt->SetValue( m_dummyPad->GetPadToDieLength() != 0 );
557
566
567 switch( m_dummyPad->GetZoneConnection() )
568 {
569 default:
570 case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
571 case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
572 case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
573 case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
574 }
575
577 m_ZoneCustomPadShape->SetSelection( 1 );
578 else
579 m_ZoneCustomPadShape->SetSelection( 0 );
580
581 switch( m_dummyPad->GetShape() )
582 {
583 default:
584 case PAD_SHAPE::CIRCLE: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
585 case PAD_SHAPE::OVAL: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_OVAL ); break;
586 case PAD_SHAPE::RECT: m_PadShapeSelector->SetSelection( CHOICE_SHAPE_RECT ); break;
589
593 else
595 break;
596
600 else
602 break;
603 }
604
613
615
617
618 // Type of pad selection
620
621 if( aperture )
622 {
623 m_padType->SetSelection( APERTURE_DLG_TYPE );
624 }
625 else
626 {
627 switch( m_dummyPad->GetAttribute() )
628 {
629 case PAD_ATTRIB::PTH: m_padType->SetSelection( PTH_DLG_TYPE ); break;
630 case PAD_ATTRIB::SMD: m_padType->SetSelection( SMD_DLG_TYPE ); break;
631 case PAD_ATTRIB::CONN: m_padType->SetSelection( CONN_DLG_TYPE ); break;
632 case PAD_ATTRIB::NPTH: m_padType->SetSelection( NPTH_DLG_TYPE ); break;
633 }
634 }
635
636 switch( m_dummyPad->GetProperty() )
637 {
638 case PAD_PROP::NONE: m_choiceFabProperty->SetSelection( 0 ); break;
639 case PAD_PROP::BGA: m_choiceFabProperty->SetSelection( 1 ); break;
640 case PAD_PROP::FIDUCIAL_LOCAL: m_choiceFabProperty->SetSelection( 2 ); break;
641 case PAD_PROP::FIDUCIAL_GLBL: m_choiceFabProperty->SetSelection( 3 ); break;
642 case PAD_PROP::TESTPOINT: m_choiceFabProperty->SetSelection( 4 ); break;
643 case PAD_PROP::HEATSINK: m_choiceFabProperty->SetSelection( 5 ); break;
644 case PAD_PROP::CASTELLATED: m_choiceFabProperty->SetSelection( 6 ); break;
645 }
646
647 // Ensure the pad property is compatible with the pad type
649 {
650 m_choiceFabProperty->SetSelection( 0 );
651 m_choiceFabProperty->Enable( false );
652 }
653
655 m_holeShapeCtrl->SetSelection( 0 );
656 else
657 m_holeShapeCtrl->SetSelection( 1 );
658
661
662 // Update some dialog widgets state (Enable/disable options):
663 wxCommandEvent cmd_event;
664 OnPadShapeSelection( cmd_event );
665 OnOffsetCheckbox( cmd_event );
666
667 // Update basic shapes list
669}
670
671// A small helper function, to display coordinates:
672static wxString formatCoord( EDA_UNITS aUnits, VECTOR2I aCoord )
673{
674 return wxString::Format( wxT( "(X:%s Y:%s)" ),
677}
678
680{
681 m_listCtrlPrimitives->ClearAll();
682
683 wxListItem itemCol;
684 itemCol.SetImage(-1);
685
686 for( int ii = 0; ii < 5; ++ii )
687 m_listCtrlPrimitives->InsertColumn(ii, itemCol);
688
689 wxString bs_info[5];
690
691 for( unsigned ii = 0; ii < m_primitives.size(); ++ii )
692 {
693 const std::shared_ptr<PCB_SHAPE>& primitive = m_primitives[ii];
694
695 for( wxString& s : bs_info )
696 s.Empty();
697
698 bs_info[4] = _( "width" ) + wxS( " " )+ EDA_UNIT_UTILS::UI::MessageTextFromValue( pcbIUScale, m_units,
699 primitive->GetWidth() );
700
701 switch( primitive->GetShape() )
702 {
703 case SHAPE_T::SEGMENT:
704 bs_info[0] = _( "Segment" );
705 bs_info[1] = _( "from" ) + wxS( " " ) + formatCoord( m_units, primitive->GetStart() );
706 bs_info[2] = _( "to" ) + wxS( " " ) + formatCoord( m_units, primitive->GetEnd() );
707 break;
708
709 case SHAPE_T::BEZIER:
710 bs_info[0] = _( "Bezier" );
711 bs_info[1] = _( "from" ) + wxS( " " ) + formatCoord( m_units, primitive->GetStart() );
712 bs_info[2] = _( "to" ) + wxS( " " ) + formatCoord( m_units, primitive->GetEnd() );
713 break;
714
715 case SHAPE_T::ARC:
716 bs_info[0] = _( "Arc" );
717 bs_info[1] = _( "center" ) + wxS( " " ) + formatCoord( m_units, primitive->GetCenter() );
718 bs_info[2] = _( "start" ) + wxS( " " ) + formatCoord( m_units, primitive->GetStart() );
719 bs_info[3] = _( "angle" ) + wxS( " " ) + EDA_UNIT_UTILS::FormatAngle( primitive->GetArcAngle() );
720 break;
721
722 case SHAPE_T::CIRCLE:
723 if( primitive->GetWidth() )
724 bs_info[0] = _( "Ring" );
725 else
726 bs_info[0] = _( "Circle" );
727
728 bs_info[1] = _( "at" ) + wxS( " " ) + formatCoord( m_units, primitive->GetStart() );
729 bs_info[2] = _( "radius" ) + wxS( " " ) + EDA_UNIT_UTILS::UI::MessageTextFromValue( pcbIUScale, m_units,
730 primitive->GetRadius() );
731 break;
732
733 case SHAPE_T::POLY:
734 bs_info[0] = _( "Polygon" );
735 bs_info[1] = wxString::Format( _( "corners count %d" ),
736 primitive->GetPolyShape().Outline( 0 ).PointCount() );
737 break;
738
739 case SHAPE_T::RECT:
740 if( primitive->IsAnnotationProxy() )
741 bs_info[0] = _( "Number box" );
742 else
743 bs_info[0] = _( "Rectangle" );
744
745 bs_info[1] = _( "from" ) + wxS( " " ) + formatCoord( m_units, primitive->GetStart() );
746 bs_info[2] = _( "to" ) + wxS( " " ) + formatCoord( m_units, primitive->GetEnd() );
747 break;
748
749 default:
750 bs_info[0] = _( "Unknown primitive" );
751 break;
752 }
753
754 long tmp = m_listCtrlPrimitives->InsertItem( ii, bs_info[0] );
755 m_listCtrlPrimitives->SetItemData( tmp, ii );
756
757 for( int jj = 0, col = 0; jj < 5; ++jj )
758 m_listCtrlPrimitives->SetItem( tmp, col++, bs_info[jj] );
759 }
760
761 // Now columns are filled, ensure correct width of columns
762 for( unsigned ii = 0; ii < 5; ++ii )
763 m_listCtrlPrimitives->SetColumnWidth( ii, wxLIST_AUTOSIZE );
764}
765
766
767void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
768{
769 redraw();
770 event.Skip();
771}
772
773
774void DIALOG_PAD_PROPERTIES::onChangePadMode( wxCommandEvent& event )
775{
777
779
780 // fix the pad render mode (filled/not filled)
781 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
782
783 settings->m_ForcePadSketchModeOn = m_cbShowPadOutline->IsChecked();
784 settings->SetHighContrast( false );
785 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
786
787 redraw();
788}
789
790
792{
793 switch( m_PadShapeSelector->GetSelection() )
794 {
798 m_shapePropsBook->SetSelection( 0 );
799 break;
800
802 m_shapePropsBook->SetSelection( 1 );
803 break;
804
806 {
807 m_shapePropsBook->SetSelection( 2 );
808
809 // A reasonable default (from IPC-7351C)
810 if( m_dummyPad->GetRoundRectRadiusRatio() == 0.0 )
812
813 break;
814 }
815
817 m_shapePropsBook->SetSelection( 3 );
818
819 // Reasonable default
820 if( m_dummyPad->GetChamferRectRatio() == 0.0 )
822
823 // Ensure the displayed value is up to date:
825
826 // A reasonable default is one corner chamfered (usual for some SMD pads).
827 if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
828 && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
829 {
830 m_cbTopLeft->SetValue( true );
831 m_cbTopRight->SetValue( false );
832 m_cbBottomLeft->SetValue( false );
833 m_cbBottomRight->SetValue( false );
834 }
835
836 break;
837
839 m_shapePropsBook->SetSelection( 4 );
840
841 // Reasonable defaults (corner radius from IPC-7351C)
843 && m_dummyPad->GetChamferRectRatio() == 0.0 )
844 {
845 if( m_dummyPad->GetRoundRectRadiusRatio() == 0.0 )
847
848 if( m_dummyPad->GetChamferRectRatio() == 0.0 )
850 }
851
852 // Ensure the displayed values are up to date:
855 break;
856
857 case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE::CUSTOM, circular anchor
858 case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE::CUSTOM, rect anchor
859 m_shapePropsBook->SetSelection( 0 );
860 break;
861 }
862
863 // Note: must do this before enabling/disabling m_sizeY as we're using that as a flag to see
864 // what the last shape was.
865 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE )
866 {
867 if( m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_90 )
869 }
870 else
871 {
872 if( !m_sizeYCtrl->IsEnabled() && m_spokeAngle.GetAngleValue() == ANGLE_45 )
874 }
875
876 // Readjust props book size
877 wxSize size = m_shapePropsBook->GetSize();
878 size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
879 m_shapePropsBook->SetMaxSize( size );
880
883
887
888 if( !m_offsetShapeOpt->IsEnabled() )
889 m_offsetShapeOpt->SetValue( false );
890
891 // Show/hide controls depending on m_offsetShapeOpt being enabled
892 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
893 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
894
895 bool is_custom = m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
897
898 enablePrimitivePage( is_custom );
899
902
903 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
904 m_notebook->GetPage( i )->Layout();
905
906 // Resize the dialog if its height is too small to show all widgets:
907 if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
908 m_MainSizer->SetSizeHints( this );
909
911 redraw();
912}
913
914
916{
919 redraw();
920}
921
922
923void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
924{
926 redraw();
927}
928
929
931{
932 m_rbCopperLayersSel->Clear();
933
934 switch( m_padType->GetSelection() )
935 {
936 case PTH_DLG_TYPE:
937 m_rbCopperLayersSel->Append( _( "All copper layers" ) );
938 m_rbCopperLayersSel->Append( wxString::Format( _( "%s, %s and connected layers" ),
940 m_board->GetLayerName( B_Cu ) ) );
941 m_rbCopperLayersSel->Append( _( "Connected layers only" ) );
942 m_rbCopperLayersSel->Append( _( "None" ) );
943 break;
944
945 case NPTH_DLG_TYPE:
946 m_rbCopperLayersSel->Append( wxString::Format( _( "%s and %s" ),
948 m_board->GetLayerName( B_Cu ) ) );
951 m_rbCopperLayersSel->Append( _( "None" ) );
952 break;
953
954 case SMD_DLG_TYPE:
955 case CONN_DLG_TYPE:
958 break;
959
961 m_rbCopperLayersSel->Append( _( "None" ) );
962 break;
963 }
964}
965
966
967void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
968{
969 bool hasHole = true;
970 bool hasConnection = true;
971 bool hasProperty = true;
972
973 switch( m_padType->GetSelection() )
974 {
975 case PTH_DLG_TYPE: hasHole = true; hasConnection = true; hasProperty = true; break;
976 case SMD_DLG_TYPE: hasHole = false; hasConnection = true; hasProperty = true; break;
977 case CONN_DLG_TYPE: hasHole = false; hasConnection = true; hasProperty = true; break;
978 case NPTH_DLG_TYPE: hasHole = true; hasConnection = false; hasProperty = false; break;
979 case APERTURE_DLG_TYPE: hasHole = false; hasConnection = false; hasProperty = true; break;
980 }
981
982 // Update Layers dropdown list and selects the "best" layer set for the new pad type:
984
985 m_gbSizerHole->Show( hasHole );
986 m_staticline6->Show( hasHole );
987 if( !hasHole )
988 {
989 m_holeX.ChangeValue( 0 );
990 m_holeY.ChangeValue( 0 );
991 }
992 else if ( m_holeX.GetValue() == 0 && m_currentPad )
993 {
996 }
997
998 if( !hasConnection )
999 {
1000 m_padNumCtrl->ChangeValue( wxEmptyString );
1002 m_padToDieOpt->SetValue( false );
1003 }
1004 else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad )
1005 {
1006 m_padNumCtrl->ChangeValue( m_currentPad->GetNumber() );
1008 }
1009
1010 if( !hasProperty )
1011 m_choiceFabProperty->SetSelection( 0 );
1012
1013 m_choiceFabProperty->Enable( hasProperty );
1014
1016
1017 // Layout adjustment is needed if the hole details got shown/hidden
1018 m_LeftBoxSizer->Layout();
1019 redraw();
1020}
1021
1022
1023void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1024{
1025 bool hasHole = true;
1026 bool hasConnection = true;
1027
1028 switch( m_padType->GetSelection() )
1029 {
1030 case PTH_DLG_TYPE: /* PTH */ hasHole = true; hasConnection = true; break;
1031 case SMD_DLG_TYPE: /* SMD */ hasHole = false; hasConnection = true; break;
1032 case CONN_DLG_TYPE: /* CONN */ hasHole = false; hasConnection = true; break;
1033 case NPTH_DLG_TYPE: /* NPTH */ hasHole = true; hasConnection = false; break;
1034 case APERTURE_DLG_TYPE: /* Aperture */ hasHole = false; hasConnection = false; break;
1035 }
1036
1037 // Enable/disable hole controls
1038 m_holeShapeLabel->Enable( hasHole );
1039 m_holeShapeCtrl->Enable( hasHole );
1040 m_holeX.Enable( hasHole );
1041 m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_OVAL );
1042
1043 // Enable/disable number and net
1044 m_padNumLabel->Enable( hasConnection );
1045 m_padNumCtrl->Enable( hasConnection );
1046
1047 if( m_padNetLabel->IsShown() )
1048 {
1049 m_padNetLabel->Enable( hasConnection && m_canEditNetName && m_currentPad );
1050 m_padNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
1051 }
1052
1053 // Enable/disable pad length-to-die
1054 m_padToDieOpt->Enable( hasConnection );
1055
1056 if( !m_padToDieOpt->IsEnabled() )
1057 m_padToDieOpt->SetValue( false );
1058
1059 // We can show/hide this here because it doesn't require the layout to be refreshed.
1060 // All the others have to be done in their event handlers because doing a layout here
1061 // causes infinite looping on MSW.
1062 m_padToDie.Show( m_padToDieOpt->GetValue() );
1063
1064 // Enable/disable Copper Layers control
1065 m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE );
1066
1068
1069 switch( m_padType->GetSelection() )
1070 {
1071 case PTH_DLG_TYPE:
1072 if( !cu_set.any() )
1073 m_stackupImagesBook->SetSelection( 3 );
1074 else if( !m_dummyPad->GetRemoveUnconnected() )
1075 m_stackupImagesBook->SetSelection( 0 );
1076 else if( m_dummyPad->GetKeepTopBottom() )
1077 m_stackupImagesBook->SetSelection( 1 );
1078 else
1079 m_stackupImagesBook->SetSelection( 2 );
1080
1081 break;
1082
1083 case NPTH_DLG_TYPE:
1084 if( cu_set.test( F_Cu ) && cu_set.test( B_Cu ) )
1085 m_stackupImagesBook->SetSelection( 4 );
1086 else if( cu_set.test( F_Cu ) )
1087 m_stackupImagesBook->SetSelection( 5 );
1088 else if( cu_set.test( B_Cu ) )
1089 m_stackupImagesBook->SetSelection( 6 );
1090 else
1091 m_stackupImagesBook->SetSelection( 7 );
1092
1093 break;
1094
1095 case SMD_DLG_TYPE:
1096 case CONN_DLG_TYPE:
1097 case APERTURE_DLG_TYPE:
1098 m_stackupImagesBook->ChangeSelection( 3 );
1099 break;
1100 }
1101}
1102
1103
1105{
1106 bool isOnCopperLayer = ( m_dummyPad->GetLayerSet() & LSET::AllCuMask() ).any();
1107 m_nonCopperWarningBook->ChangeSelection( isOnCopperLayer ? 0 : 1 );
1108}
1109
1110
1111void DIALOG_PAD_PROPERTIES::updatePadLayersList( LSET layer_mask, bool remove_unconnected,
1112 bool keep_top_bottom )
1113{
1115
1116 switch( m_padType->GetSelection() )
1117 {
1118 case PTH_DLG_TYPE:
1119 if( !layer_mask.any() )
1120 layer_mask = PAD::PTHMask();
1121
1122 if( !( layer_mask & LSET::AllCuMask() ).any() )
1123 m_rbCopperLayersSel->SetSelection( 3 );
1124 else if( !remove_unconnected )
1125 m_rbCopperLayersSel->SetSelection( 0 );
1126 else if( keep_top_bottom )
1127 m_rbCopperLayersSel->SetSelection( 1 );
1128 else
1129 m_rbCopperLayersSel->SetSelection( 2 );
1130
1131 break;
1132
1133 case SMD_DLG_TYPE:
1134 if( !layer_mask.any() )
1135 layer_mask = PAD::SMDMask();
1136
1137 if( layer_mask.test( F_Cu ) )
1138 m_rbCopperLayersSel->SetSelection( 0 );
1139 else
1140 m_rbCopperLayersSel->SetSelection( 1 );
1141
1142 break;
1143
1144 case CONN_DLG_TYPE:
1145 if( !layer_mask.any() )
1146 layer_mask = PAD::ConnSMDMask();
1147
1148 if( layer_mask.test( F_Cu ) )
1149 m_rbCopperLayersSel->SetSelection( 0 );
1150 else
1151 m_rbCopperLayersSel->SetSelection( 1 );
1152
1153 break;
1154
1155 case NPTH_DLG_TYPE:
1156 if( !layer_mask.any() )
1157 layer_mask = PAD::UnplatedHoleMask();
1158
1159 if( layer_mask.test( F_Cu ) && layer_mask.test( B_Cu ) )
1160 m_rbCopperLayersSel->SetSelection( 0 );
1161 else if( layer_mask.test( F_Cu ) )
1162 m_rbCopperLayersSel->SetSelection( 1 );
1163 else if( layer_mask.test( B_Cu ) )
1164 m_rbCopperLayersSel->SetSelection( 2 );
1165 else
1166 m_rbCopperLayersSel->SetSelection( 3 );
1167
1168 break;
1169
1170 case APERTURE_DLG_TYPE:
1171 if( !layer_mask.any() )
1172 layer_mask = PAD::ApertureMask();
1173
1174 m_rbCopperLayersSel->SetSelection( 0 );
1175 break;
1176 }
1177
1178 m_PadLayerAdhCmp->SetValue( layer_mask[F_Adhes] );
1179 m_PadLayerAdhCu->SetValue( layer_mask[B_Adhes] );
1180
1181 m_PadLayerPateCmp->SetValue( layer_mask[F_Paste] );
1182 m_PadLayerPateCu->SetValue( layer_mask[B_Paste] );
1183
1184 m_PadLayerSilkCmp->SetValue( layer_mask[F_SilkS] );
1185 m_PadLayerSilkCu->SetValue( layer_mask[B_SilkS] );
1186
1187 m_PadLayerMaskCmp->SetValue( layer_mask[F_Mask] );
1188 m_PadLayerMaskCu->SetValue( layer_mask[B_Mask] );
1189
1190 m_PadLayerECO1->SetValue( layer_mask[Eco1_User] );
1191 m_PadLayerECO2->SetValue( layer_mask[Eco2_User] );
1192
1193 m_PadLayerDraft->SetValue( layer_mask[Dwgs_User] );
1194}
1195
1196
1198{
1199 bool retVal = DIALOG_SHIM::Show( aShow );
1200
1201 if( aShow )
1202 {
1203 // It *should* work to set the stackup bitmap in the constructor, but it doesn't.
1204 // wxWidgets needs to have these set when the panel is visible for some reason.
1205 // https://gitlab.com/kicad/code/kicad/-/issues/5534
1213
1214 Layout();
1215 }
1216
1217 return retVal;
1218}
1219
1220
1221void DIALOG_PAD_PROPERTIES::OnSetCopperLayers( wxCommandEvent& event )
1222{
1224 redraw();
1225}
1226
1227
1228void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1229{
1231 redraw();
1232}
1233
1234
1236{
1237 bool error = !transferDataToPad( m_dummyPad );
1238
1239 wxArrayString error_msgs;
1240 wxArrayString warning_msgs;
1241 VECTOR2I pad_size = m_dummyPad->GetSize();
1242 VECTOR2I drill_size = m_dummyPad->GetDrillSize();
1243
1245 {
1246 // allow 0-sized anchor pads
1247 }
1248 else if( m_dummyPad->GetShape() == PAD_SHAPE::CIRCLE )
1249 {
1250 if( pad_size.x <= 0 )
1251 error_msgs.Add( _( "Error: Pad must have a positive size." ) );
1252 }
1253 else
1254 {
1255 if( pad_size.x <= 0 || pad_size.y <= 0 )
1256 error_msgs.Add( _( "Error: Pad must have a positive size." ) );
1257 }
1258
1259 // Test hole against pad shape
1261 {
1262 int maxError = m_board->GetDesignSettings().m_MaxError;
1263 SHAPE_POLY_SET padOutline;
1264
1265 m_dummyPad->TransformShapeToPolygon( padOutline, UNDEFINED_LAYER, 0, maxError,
1266 ERROR_INSIDE );
1267
1268 if( !padOutline.Collide( m_dummyPad->GetPosition() ) )
1269 {
1270 warning_msgs.Add( _( "Warning: Pad hole not inside pad shape." ) );
1271 }
1272 else if( m_dummyPad->GetAttribute() == PAD_ATTRIB::PTH )
1273 {
1274 std::shared_ptr<SHAPE_SEGMENT> slot = m_dummyPad->GetEffectiveHoleShape();
1275 SHAPE_POLY_SET slotOutline;
1276
1277 TransformOvalToPolygon( slotOutline, slot->GetSeg().A, slot->GetSeg().B,
1278 slot->GetWidth(), maxError, ERROR_INSIDE );
1279
1280 padOutline.BooleanSubtract( slotOutline, SHAPE_POLY_SET::PM_FAST );
1281
1282 if( padOutline.IsEmpty() )
1283 warning_msgs.Add( _( "Warning: Pad hole will leave no copper." ) );
1284 }
1285 }
1286
1287 if( m_dummyPad->GetLocalClearance() < 0 )
1288 warning_msgs.Add( _( "Warning: Negative local clearance values will have no effect." ) );
1289
1290 // Some pads need a negative solder mask clearance (mainly for BGA with small pads)
1291 // However the negative solder mask clearance must not create negative mask size
1292 // Therefore test for minimal acceptable negative value
1294 {
1295 int absMargin = abs( m_dummyPad->GetLocalSolderMaskMargin() );
1296
1298 {
1299 for( const std::shared_ptr<PCB_SHAPE>& shape : m_dummyPad->GetPrimitives() )
1300 {
1301 BOX2I shapeBBox = shape->GetBoundingBox();
1302
1303 if( absMargin > shapeBBox.GetWidth() || absMargin > shapeBBox.GetHeight() )
1304 {
1305 warning_msgs.Add( _( "Warning: Negative solder mask clearances larger than "
1306 "some shape primitives. Results may be surprising." ) );
1307
1308 break;
1309 }
1310 }
1311 }
1312 else if( absMargin > pad_size.x || absMargin > pad_size.y )
1313 {
1314 warning_msgs.Add( _( "Warning: Negative solder mask clearance larger than pad. No "
1315 "solder mask will be generated." ) );
1316 }
1317 }
1318
1319 // Some pads need a positive solder paste clearance (mainly for BGA with small pads)
1320 // However, a positive value can create issues if the resulting shape is too big.
1321 // (like a solder paste creating a solder paste area on a neighbor pad or on the solder mask)
1322 // So we could ask for user to confirm the choice
1323 // For now we just check for disappearing paste
1324 wxSize paste_size;
1325 int paste_margin = m_dummyPad->GetLocalSolderPasteMargin();
1326 double paste_ratio = m_dummyPad->GetLocalSolderPasteMarginRatio();
1327
1328 paste_size.x = pad_size.x + paste_margin + KiROUND( pad_size.x * paste_ratio );
1329 paste_size.y = pad_size.y + paste_margin + KiROUND( pad_size.y * paste_ratio );
1330
1331 if( paste_size.x <= 0 || paste_size.y <= 0 )
1332 {
1333 warning_msgs.Add( _( "Warning: Negative solder paste margins larger than pad. No solder "
1334 "paste mask will be generated." ) );
1335 }
1336
1337 LSET padlayers_mask = m_dummyPad->GetLayerSet();
1338
1339 if( padlayers_mask == 0 )
1340 error_msgs.Add( _( "Error: pad has no layer." ) );
1341
1342 if( !padlayers_mask[F_Cu] && !padlayers_mask[B_Cu] )
1343 {
1344 if( ( drill_size.x || drill_size.y ) && m_dummyPad->GetAttribute() != PAD_ATTRIB::NPTH )
1345 {
1346 warning_msgs.Add( _( "Warning: Plated through holes should normally have a copper pad "
1347 "on at least one layer." ) );
1348 }
1349 }
1350
1351 if( error )
1352 error_msgs.Add( _( "Error: Trapazoid delta is too large." ) );
1353
1354 switch( m_dummyPad->GetAttribute() )
1355 {
1356 case PAD_ATTRIB::NPTH: // Not plated, but through hole, a hole is expected
1357 case PAD_ATTRIB::PTH: // Pad through hole, a hole is also expected
1358 if( drill_size.x <= 0
1359 || ( drill_size.y <= 0 && m_dummyPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ) )
1360 {
1361 error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
1362 }
1363 break;
1364
1365 case PAD_ATTRIB::CONN: // Connector pads are smd pads, just they do not have solder paste.
1366 if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
1367 {
1368 warning_msgs.Add( _( "Warning: Connector pads normally have no solder paste. Use a "
1369 "SMD pad instead." ) );
1370 }
1372
1373 case PAD_ATTRIB::SMD: // SMD and Connector pads (One external copper layer only)
1374 {
1375 if( drill_size.x > 0 || drill_size.y > 0 )
1376 {
1377 error_msgs.Add( _( "Error: SMD pad has a hole." ) );
1378 }
1379
1380 LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
1381
1382 if( ( padlayers_mask[F_Cu] && padlayers_mask[B_Cu] ) || innerlayers_mask.count() != 0 )
1383 warning_msgs.Add( _( "Warning: SMD pad has no outer layers." ) );
1384 }
1385 break;
1386 }
1387
1391 {
1392 warning_msgs.Add( _( "Warning: Fiducial property makes no sense on NPTH pads." ) );
1393 }
1394
1397 {
1398 warning_msgs.Add( _( "Warning: Testpoint property makes no sense on NPTH pads." ) );
1399 }
1400
1403 {
1404 warning_msgs.Add( _( "Warning: Heatsink property makes no sense of NPTH pads." ) );
1405 }
1406
1409 {
1410 warning_msgs.Add( _( "Warning: Castellated property is for PTH pads." ) );
1411 }
1412
1415 {
1416 warning_msgs.Add( _( "Warning: BGA property is for SMD pads." ) );
1417 }
1418
1421 {
1423
1424 if( m_cornerRatio.GetDoubleValue() < 0.0 )
1425 error_msgs.Add( _( "Error: Negative corner size." ) );
1426 else if( m_cornerRatio.GetDoubleValue() > 50.0 )
1427 warning_msgs.Add( _( "Warning: Corner size will make pad circular." ) );
1428 }
1429
1430 // PADSTACKS TODO: this will need to check each layer in the pad...
1432 {
1433 SHAPE_POLY_SET mergedPolygon;
1434 m_dummyPad->MergePrimitivesAsPolygon( &mergedPolygon );
1435
1436 if( mergedPolygon.OutlineCount() > 1 )
1437 error_msgs.Add( _( "Error: Custom pad shape must resolve to a single polygon." ) );
1438 }
1439
1440
1441 if( error_msgs.GetCount() || warning_msgs.GetCount() )
1442 {
1443 wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
1444 : _( "Pad Properties Warnings" );
1445 HTML_MESSAGE_BOX dlg( this, title );
1446
1447 wxArrayString msgs = error_msgs;
1448
1449 for( const wxString& msg : warning_msgs )
1450 msgs.Add( msg );
1451
1452 dlg.ListSet( msgs );
1453
1454 dlg.ShowModal();
1455 }
1456
1457 return error_msgs.GetCount() == 0;
1458}
1459
1460
1462{
1463 if( !m_canUpdate )
1464 return;
1465
1468
1469 // The layer used to place primitive items selected when editing custom pad shapes
1470 // we use here a layer never used in a pad:
1471 #define SELECTED_ITEMS_LAYER Dwgs_User
1472
1474 KIGFX::PCB_RENDER_SETTINGS* settings =
1475 static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
1477
1478 view->Update( m_dummyPad );
1479
1480 // delete previous items if highlight list
1481 while( m_highlight.size() )
1482 {
1483 delete m_highlight.back(); // the dtor also removes item from view
1484 m_highlight.pop_back();
1485 }
1486
1487 // highlight selected primitives:
1488 long select = m_listCtrlPrimitives->GetFirstSelected();
1489
1490 while( select >= 0 )
1491 {
1492 PCB_SHAPE* dummyShape = static_cast<PCB_SHAPE*>( m_primitives[select]->Clone() );
1493 dummyShape->SetLayer( SELECTED_ITEMS_LAYER );
1494 dummyShape->Rotate( VECTOR2I( 0, 0), m_dummyPad->GetOrientation() );
1495 dummyShape->Move( m_dummyPad->GetPosition() );
1496
1497 view->Add( dummyShape );
1498 m_highlight.push_back( dummyShape );
1499
1500 select = m_listCtrlPrimitives->GetNextSelected( select );
1501 }
1502
1503 BOX2I bbox = m_dummyPad->ViewBBox();
1504
1505 if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1506 {
1507 // The origin always goes in the middle of the canvas; we want offsetting the pad
1508 // shape to move the pad, not the hole
1509 bbox.Move( -m_dummyPad->GetPosition() );
1510 int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1511 int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1512
1513 // Don't blow up the GAL on too-large numbers
1514 if( maxXExtent > INT_MAX / 4 )
1515 maxXExtent = INT_MAX / 4;
1516
1517 if( maxYExtent > INT_MAX / 4 )
1518 maxYExtent = INT_MAX / 4;
1519
1520 BOX2D viewBox( m_dummyPad->GetPosition(), {0, 0} );
1521 BOX2D canvasBox( m_dummyPad->GetPosition(), {0, 0} );
1522 viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1523 canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1524
1525 view->SetBoundary( canvasBox );
1526
1527 // Autozoom
1528 view->SetViewport( viewBox );
1529
1532 }
1533}
1534
1535
1537{
1538 if( !wxDialog::TransferDataToWindow() )
1539 return false;
1540
1541 if( !m_panelGeneral->TransferDataToWindow() )
1542 return false;
1543
1544 if( !m_localSettingsPanel->TransferDataToWindow() )
1545 return false;
1546
1547 return true;
1548}
1549
1550
1552{
1553 BOARD_COMMIT commit( m_parent );
1554
1555 if( !wxDialog::TransferDataFromWindow() )
1556 return false;
1557
1558 if( !m_panelGeneral->TransferDataFromWindow() )
1559 return false;
1560
1561 if( !m_localSettingsPanel->TransferDataFromWindow() )
1562 return false;
1563
1564 if( !padValuesOK() )
1565 return false;
1566
1568 return false;
1569
1571 padTool->SetLastPadNumber( m_padMaster->GetNumber() );
1572
1573 // m_padMaster is a pattern: ensure there is no net for this pad:
1575
1576 if( !m_currentPad ) // Set current Pad parameters
1577 return true;
1578
1579 commit.Modify( m_currentPad );
1580
1581 // Update values
1586
1587 VECTOR2I size;
1588 FOOTPRINT* footprint = m_currentPad->GetParent();
1589
1591
1592 size = m_padMaster->GetDelta();
1593 m_currentPad->SetDelta( size );
1594
1597
1598 VECTOR2I offset = m_padMaster->GetOffset();
1599 m_currentPad->SetOffset( offset );
1600
1602
1605
1608
1612
1614
1615 int padNetcode = NETINFO_LIST::UNCONNECTED;
1616
1617 // For PAD_ATTRIB::NPTH, ensure there is no net name selected
1619 padNetcode = m_padNetSelector->GetSelectedNetcode();
1620
1621 m_currentPad->SetNetCode( padNetcode );
1633
1634 // rounded rect pads with radius ratio = 0 are in fact rect pads.
1635 // So set the right shape (and perhaps issues with a radius = 0)
1638 {
1640 }
1641
1642 // Set the fabrication property:
1644
1645 // define the way the clearance area is defined in zones
1647
1648 if( m_isFlipped )
1649 {
1650 // flip pad (up/down) around its position
1652 }
1653
1654 if( footprint )
1655 {
1656 // compute the pos 0 value, i.e. pad position for footprint with orientation = 0
1657 // i.e. relative to footprint origin (footprint position)
1658 VECTOR2I pt = m_currentPad->GetPosition() - footprint->GetPosition();
1659 RotatePoint( pt, -footprint->GetOrientation() );
1660 m_currentPad->SetPos0( pt );
1662 }
1663
1665
1666 // redraw the area where the pad was
1668
1669 commit.Push( _( "Modify pad" ) );
1670
1671 return true;
1672}
1673
1674
1676{
1677 PAD_PROP prop = PAD_PROP::NONE;
1678
1679 switch( m_choiceFabProperty->GetSelection() )
1680 {
1681 case 0: prop = PAD_PROP::NONE; break;
1682 case 1: prop = PAD_PROP::BGA; break;
1683 case 2: prop = PAD_PROP::FIDUCIAL_LOCAL; break;
1684 case 3: prop = PAD_PROP::FIDUCIAL_GLBL; break;
1685 case 4: prop = PAD_PROP::TESTPOINT; break;
1686 case 5: prop = PAD_PROP::HEATSINK; break;
1687 case 6: prop = PAD_PROP::CASTELLATED; break;
1688 }
1689
1690 return prop;
1691}
1692
1694{
1695 m_holeXLabel->SetLabel( ( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1696 ? _( "Diameter:" )
1697 : _( "Hole size X:" ) );
1699 && m_holeShapeCtrl->GetSelection() != CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR );
1700 m_holeXLabel->GetParent()->Layout();
1701}
1702
1704{
1705 m_sizeXLabel->SetLabel( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CIRCLE
1706 || m_PadShapeSelector->GetSelection()
1708 ? _( "Diameter:" )
1709 : _( "Pad size X:" ) );
1712 m_sizeXLabel->GetParent()->Layout();
1713}
1714
1715
1717{
1718 if( !Validate() )
1719 return false;
1720
1721 if( !m_panelGeneral->Validate() )
1722 return false;
1723
1724 if( !m_localSettingsPanel->Validate() )
1725 return false;
1726
1727 if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1728 return false;
1729
1730 aPad->SetAttribute( code_type[m_padType->GetSelection()] );
1731 aPad->SetShape( code_shape[m_PadShapeSelector->GetSelection()] );
1732
1735 else
1737
1738 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
1740
1741 // Read pad clearances values:
1749
1750 // And rotation
1752
1753 switch( m_ZoneConnectionChoice->GetSelection() )
1754 {
1755 default:
1756 case 0: aPad->SetZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1757 case 1: aPad->SetZoneConnection( ZONE_CONNECTION::FULL ); break;
1758 case 2: aPad->SetZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1759 case 3: aPad->SetZoneConnection( ZONE_CONNECTION::NONE ); break;
1760 }
1761
1762 aPad->SetPosition( wxPoint( m_posX.GetValue(), m_posY.GetValue() ) );
1763
1764 if( m_holeShapeCtrl->GetSelection() == CHOICE_SHAPE_CIRCLE )
1765 {
1767 aPad->SetDrillSize( wxSize( m_holeX.GetValue(), m_holeX.GetValue() ) );
1768 }
1769 else
1770 {
1772 aPad->SetDrillSize( wxSize( m_holeX.GetValue(), m_holeY.GetValue() ) );
1773 }
1774
1775 if( aPad->GetShape() == PAD_SHAPE::CIRCLE )
1776 aPad->SetSize( wxSize( m_sizeX.GetValue(), m_sizeX.GetValue() ) );
1777 else
1778 aPad->SetSize( wxSize( m_sizeX.GetValue(), m_sizeY.GetValue() ) );
1779
1780 // For a trapezoid, test delta value (be sure delta is not too large for pad size)
1781 // remember DeltaSize.x is the Y size variation
1782 bool error = false;
1783 wxSize delta( 0, 0 );
1784
1785 if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
1786 {
1787 // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
1788 if( m_trapAxisCtrl->GetSelection() == 0 )
1790 else
1792
1793 if( delta.x < 0 && delta.x < -aPad->GetSize().y )
1794 {
1795 delta.x = -aPad->GetSize().y + 2;
1796 error = true;
1797 }
1798
1799 if( delta.x > 0 && delta.x > aPad->GetSize().y )
1800 {
1801 delta.x = aPad->GetSize().y - 2;
1802 error = true;
1803 }
1804
1805 if( delta.y < 0 && delta.y < -aPad->GetSize().x )
1806 {
1807 delta.y = -aPad->GetSize().x + 2;
1808 error = true;
1809 }
1810
1811 if( delta.y > 0 && delta.y > aPad->GetSize().x )
1812 {
1813 delta.y = aPad->GetSize().x - 2;
1814 error = true;
1815 }
1816 }
1817
1818 aPad->SetDelta( delta );
1819
1820 if( m_offsetShapeOpt->GetValue() )
1821 aPad->SetOffset( wxPoint( m_offsetX.GetValue(), m_offsetY.GetValue() ) );
1822 else
1823 aPad->SetOffset( wxPoint() );
1824
1825 // Read pad length die
1826 if( m_padToDieOpt->GetValue() )
1828 else
1829 aPad->SetPadToDieLength( 0 );
1830
1831 aPad->SetNumber( m_padNumCtrl->GetValue() );
1833
1834 int chamfers = 0;
1835
1836 if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
1837 {
1838 if( m_cbTopLeft->GetValue() )
1839 chamfers |= RECT_CHAMFER_TOP_LEFT;
1840
1841 if( m_cbTopRight->GetValue() )
1842 chamfers |= RECT_CHAMFER_TOP_RIGHT;
1843
1844 if( m_cbBottomLeft->GetValue() )
1845 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1846
1847 if( m_cbBottomRight->GetValue() )
1848 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1849 }
1850 else if( m_PadShapeSelector->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
1851 {
1852 if( m_cbTopLeft1->GetValue() )
1853 chamfers |= RECT_CHAMFER_TOP_LEFT;
1854
1855 if( m_cbTopRight1->GetValue() )
1856 chamfers |= RECT_CHAMFER_TOP_RIGHT;
1857
1858 if( m_cbBottomLeft1->GetValue() )
1859 chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1860
1861 if( m_cbBottomRight1->GetValue() )
1862 chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1863 }
1864 aPad->SetChamferPositions( chamfers );
1865
1866 if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
1867 {
1868 // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
1869 // that is the minimal area of this pad, and is useful to ensure a hole
1870 // diameter is acceptable, and is used in Gerber files as flashed area
1871 // reference
1872 if( aPad->GetAnchorPadShape() == PAD_SHAPE::CIRCLE )
1873 aPad->SetSize( wxSize( m_sizeX.GetValue(), m_sizeX.GetValue() ) );
1874 }
1875
1876 // Define the way the clearance area is defined in zones. Since all non-custom pad
1877 // shapes are convex to begin with, this really only makes any difference for custom
1878 // pad shapes.
1879 aPad->SetCustomShapeInZoneOpt( m_ZoneCustomPadShape->GetSelection() == 0 ?
1882
1883 switch( aPad->GetAttribute() )
1884 {
1885 case PAD_ATTRIB::PTH:
1886 break;
1887
1888 case PAD_ATTRIB::CONN:
1889 case PAD_ATTRIB::SMD:
1890 // SMD and PAD_ATTRIB::CONN has no hole.
1891 // basically, SMD and PAD_ATTRIB::CONN are same type of pads
1892 // PAD_ATTRIB::CONN has just a default non technical layers that differs from SMD
1893 // and are intended to be used in virtual edge board connectors
1894 // However we can accept a non null offset,
1895 // mainly to allow complex pads build from a set of basic pad shapes
1896 aPad->SetDrillSize( wxSize( 0, 0 ) );
1897 break;
1898
1899 case PAD_ATTRIB::NPTH:
1900 // Mechanical purpose only:
1901 // no net name, no pad name allowed
1902 aPad->SetNumber( wxEmptyString );
1904 break;
1905
1906 default:
1907 wxFAIL_MSG( wxT( "DIALOG_PAD_PROPERTIES::transferDataToPad: unknown pad type" ) );
1908 break;
1909 }
1910
1911 if( aPad->GetShape() == PAD_SHAPE::ROUNDRECT )
1912 {
1914 }
1915 else if( aPad->GetShape() == PAD_SHAPE::CHAMFERED_RECT )
1916 {
1918 {
1921 }
1922 else // Choice is CHOICE_SHAPE_CHAMFERED_RECT, no rounded corner
1923 {
1925 aPad->SetRoundRectRadiusRatio( 0 );
1926 }
1927 }
1928
1930
1931 LSET padLayerMask = LSET();
1932 int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
1933
1934 aPad->SetRemoveUnconnected( false );
1935 aPad->SetKeepTopBottom( false );
1936
1937 switch( m_padType->GetSelection() )
1938 {
1939 case PTH_DLG_TYPE:
1940 switch( copperLayersChoice )
1941 {
1942 case 0:
1943 // All copper layers
1944 padLayerMask |= LSET::AllCuMask();
1945 break;
1946
1947 case 1:
1948 // Front, back and connected
1949 padLayerMask |= LSET::AllCuMask();
1950 aPad->SetRemoveUnconnected( true );
1951 aPad->SetKeepTopBottom( true );
1952 break;
1953
1954 case 2:
1955 // Connected only
1956 padLayerMask |= LSET::AllCuMask();
1957 aPad->SetRemoveUnconnected( true );
1958 break;
1959
1960 case 3:
1961 // No copper layers
1962 break;
1963 }
1964
1965 break;
1966
1967 case NPTH_DLG_TYPE:
1968 switch( copperLayersChoice )
1969 {
1970 case 0: padLayerMask.set( F_Cu ).set( B_Cu ); break;
1971 case 1: padLayerMask.set( F_Cu ); break;
1972 case 2: padLayerMask.set( B_Cu ); break;
1973 default: break;
1974 }
1975
1976 break;
1977
1978 case SMD_DLG_TYPE:
1979 case CONN_DLG_TYPE:
1980 switch( copperLayersChoice )
1981 {
1982 case 0: padLayerMask.set( F_Cu ); break;
1983 case 1: padLayerMask.set( B_Cu ); break;
1984 }
1985
1986 break;
1987
1988 case APERTURE_DLG_TYPE:
1989 // no copper layers
1990 break;
1991 }
1992
1993 if( m_PadLayerAdhCmp->GetValue() )
1994 padLayerMask.set( F_Adhes );
1995
1996 if( m_PadLayerAdhCu->GetValue() )
1997 padLayerMask.set( B_Adhes );
1998
1999 if( m_PadLayerPateCmp->GetValue() )
2000 padLayerMask.set( F_Paste );
2001
2002 if( m_PadLayerPateCu->GetValue() )
2003 padLayerMask.set( B_Paste );
2004
2005 if( m_PadLayerSilkCmp->GetValue() )
2006 padLayerMask.set( F_SilkS );
2007
2008 if( m_PadLayerSilkCu->GetValue() )
2009 padLayerMask.set( B_SilkS );
2010
2011 if( m_PadLayerMaskCmp->GetValue() )
2012 padLayerMask.set( F_Mask );
2013
2014 if( m_PadLayerMaskCu->GetValue() )
2015 padLayerMask.set( B_Mask );
2016
2017 if( m_PadLayerECO1->GetValue() )
2018 padLayerMask.set( Eco1_User );
2019
2020 if( m_PadLayerECO2->GetValue() )
2021 padLayerMask.set( Eco2_User );
2022
2023 if( m_PadLayerDraft->GetValue() )
2024 padLayerMask.set( Dwgs_User );
2025
2026 aPad->SetLayerSet( padLayerMask );
2027
2028 return !error;
2029}
2030
2031
2032void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
2033{
2034 if( m_offsetShapeOpt->GetValue() )
2035 {
2038 }
2039
2040 // Show/hide controls depending on m_offsetShapeOpt being enabled
2041 m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
2042 m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
2043
2044 for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
2045 m_notebook->GetPage( i )->Layout();
2046
2047 OnValuesChanged( event );
2048}
2049
2050
2052{
2053 if( m_padToDieOpt->GetValue() && m_currentPad )
2055
2056 OnValuesChanged( event );
2057}
2058
2059
2060void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
2061{
2062 if( m_canUpdate )
2063 {
2065 return;
2066
2067 // If the pad size has changed, update the displayed values for rounded rect pads.
2069
2070 redraw();
2071 }
2072}
2073
2075{
2076 long select = m_listCtrlPrimitives->GetFirstSelected();
2077
2078 if( select < 0 )
2079 {
2080 wxMessageBox( _( "No shape selected" ) );
2081 return;
2082 }
2083
2084 std::shared_ptr<PCB_SHAPE>& shape = m_primitives[select];
2085
2086 if( shape->GetShape() == SHAPE_T::POLY )
2087 {
2088 DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, shape.get() );
2089
2090 if( dlg.ShowModal() != wxID_OK )
2091 return;
2092
2094 }
2095
2096 else
2097 {
2098 DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, shape.get() );
2099
2100 if( dlg.ShowModal() != wxID_OK )
2101 return;
2102
2104 }
2105
2107
2109 redraw();
2110}
2111
2112
2114{
2115 // Called on a double click on the basic shapes list
2116 // To Do: highlight the primitive(s) currently selected.
2117 redraw();
2118}
2119
2120
2122{
2123 editPrimitive();
2124}
2125
2126
2127void DIALOG_PAD_PROPERTIES::onEditPrimitive( wxCommandEvent& event )
2128{
2129 editPrimitive();
2130}
2131
2132
2133void DIALOG_PAD_PROPERTIES::onDeletePrimitive( wxCommandEvent& event )
2134{
2135 long select = m_listCtrlPrimitives->GetFirstSelected();
2136
2137 if( select < 0 )
2138 return;
2139
2140 // Multiple selections are allowed. get them and remove corresponding shapes
2141 std::vector<long> indexes;
2142 indexes.push_back( select );
2143
2144 while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
2145 indexes.push_back( select );
2146
2147 // Erase all select shapes
2148 for( unsigned ii = indexes.size(); ii > 0; --ii )
2149 m_primitives.erase( m_primitives.begin() + indexes[ii-1] );
2150
2152
2154 redraw();
2155}
2156
2157
2158void DIALOG_PAD_PROPERTIES::onAddPrimitive( wxCommandEvent& event )
2159{
2160 // Ask user for shape type
2161 wxString shapelist[] = {
2162 _( "Segment" ),
2163 _( "Arc" ),
2164 _( "Bezier" ),
2165 _( "Ring/Circle" ),
2166 _( "Polygon" ),
2167 _( "Number box" ),
2168 };
2169
2170 int type = wxGetSingleChoiceIndex( _( "Shape type:" ), _( "Add Primitive" ),
2171 arrayDim( shapelist ), shapelist, 0, this );
2172
2173 // User pressed cancel
2174 if( type == -1 )
2175 return;
2176
2179
2180 PCB_SHAPE* primitive = new PCB_SHAPE();
2181 primitive->SetShape( listtype[type] );
2182
2183 if( type == static_cast<int>( arrayDim( shapelist ) ) - 1 )
2184 primitive->SetIsAnnotationProxy();
2185
2188 primitive->SetFilled( true );
2189
2190 if( listtype[type] == SHAPE_T::POLY )
2191 {
2192 DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, primitive );
2193
2194 if( dlg.ShowModal() != wxID_OK )
2195 return;
2196 }
2197 else
2198 {
2199 DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, primitive );
2200
2201 if( dlg.ShowModal() != wxID_OK )
2202 return;
2203 }
2204
2205 m_primitives.emplace_back( primitive );
2206
2208
2210 redraw();
2211}
2212
2213
2215{
2216 long select = m_listCtrlPrimitives->GetFirstSelected();
2217
2218 if( select < 0 )
2219 {
2220 wxMessageBox( _( "No shape selected" ) );
2221 return;
2222 }
2223
2224 // Multiple selections are allowed. Build selected shapes list
2225 std::vector<std::shared_ptr<PCB_SHAPE>> shapeList;
2226 shapeList.emplace_back( m_primitives[select] );
2227
2228 while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
2229 shapeList.emplace_back( m_primitives[select] );
2230
2231 DIALOG_PAD_PRIMITIVES_TRANSFORM dlg( this, m_parent, shapeList, false );
2232
2233 if( dlg.ShowModal() != wxID_OK )
2234 return;
2235
2236 dlg.Transform();
2237
2239
2241 redraw();
2242}
2243
2244
2246{
2247 long select = m_listCtrlPrimitives->GetFirstSelected();
2248
2249 if( select < 0 )
2250 {
2251 wxMessageBox( _( "No shape selected" ) );
2252 return;
2253 }
2254
2255 // Multiple selections are allowed. Build selected shapes list
2256 std::vector<std::shared_ptr<PCB_SHAPE>> shapeList;
2257 shapeList.emplace_back( m_primitives[select] );
2258
2259 while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
2260 shapeList.emplace_back( m_primitives[select] );
2261
2262 DIALOG_PAD_PRIMITIVES_TRANSFORM dlg( this, m_parent, shapeList, true );
2263
2264 if( dlg.ShowModal() != wxID_OK )
2265 return;
2266
2267 // Transfer new settings
2268 // save duplicates to a separate vector to avoid m_primitives reallocation,
2269 // as shapeList contains pointers to its elements
2270 std::vector<std::shared_ptr<PCB_SHAPE>> duplicates;
2271 dlg.Transform( &duplicates, dlg.GetDuplicateCount() );
2272 std::move( duplicates.begin(), duplicates.end(), std::back_inserter( m_primitives ) );
2273
2275
2277 redraw();
2278}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
@ pads_npth_top
@ pads_reset_unused
@ pads_remove_unused
@ pads_npth_bottom
@ pads_npth_top_bottom
@ pads_remove_unused_keep_bottom
@ dialog_warning
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
std::unique_ptr< PAD > m_Pad_Master
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:214
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:765
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:456
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:686
coord_type GetTop() const
Definition: box2.h:194
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:111
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
coord_type GetRight() const
Definition: box2.h:189
coord_type GetLeft() const
Definition: box2.h:193
const Vec & GetSize() const
Definition: box2.h:179
coord_type GetBottom() const
Definition: box2.h:190
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
A dialog to edit basic shape parameters.
bool TransferDataFromWindow() override
Transfer data out of the GUI.
A dialog to apply geometry transforms to a shape or set of shapes (move, rotate around origin,...
void Transform(std::vector< std::shared_ptr< PCB_SHAPE > > *aList=nullptr, int aDuplicateCount=0)
Apply geometric transform (rotation, move, scale) defined in dialog aDuplicate = 1 .
A dialog to edit basic polygonal shape parameters.
bool TransferDataFromWindow() override
Transfer data out of the GUI.
Class DIALOG_PAD_PROPERTIES_BASE.
void OnUpdateUINonCopperWarning(wxUpdateUIEvent &event) override
void OnInitDialog(wxInitDialogEvent &event) override
void PadTypeSelected(wxCommandEvent &event) override
void OnPadShapeSelection(wxCommandEvent &event) override
bool transferDataToPad(PAD *aPad)
Copy values from dialog field to aPad's members.
void onAddPrimitive(wxCommandEvent &event) override
bool TransferDataFromWindow() override
Updates the different parameters for the component being edited.
bool Show(bool aShow) override
std::vector< std::shared_ptr< PCB_SHAPE > > m_primitives
bool padValuesOK()
test if all values are acceptable for the pad
void onPrimitiveDClick(wxMouseEvent &event) override
Called on a double click on the basic shapes list.
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 onEditPrimitive(wxCommandEvent &event) override
void onChangePadMode(wxCommandEvent &event) override
void OnPrimitiveSelection(wxListEvent &event) override
Called on selection/deselection of a basic shape.
std::vector< PCB_SHAPE * > m_highlight
KIGFX::ORIGIN_VIEWITEM * m_axisOrigin
void OnSetCopperLayers(wxCommandEvent &event) override
void OnCancel(wxCommandEvent &event) override
void onCornerRadiusChange(wxCommandEvent &event) override
void updatePadLayersList(LSET layer_mask, bool remove_unconnected, bool keep_top_bottom)
Updates the CheckBox states in pad layers list, based on the layer_mask (if non-empty) or the default...
PAD_PROP getSelectedProperty()
Return the pad property currently selected.
void OnSetLayers(wxCommandEvent &event) override
void onCornerSizePercentChange(wxCommandEvent &event) override
void enablePrimitivePage(bool aEnable)
enable (or disable) the primitive page editor
void OnPadToDieCheckbox(wxCommandEvent &event) override
void onGeometryTransform(wxCommandEvent &event) override
void onDuplicatePrimitive(wxCommandEvent &event) override
void OnDrillShapeSelected(wxCommandEvent &event) override
void onDeletePrimitive(wxCommandEvent &event) override
Event handlers of basic shapes list panel.
void OnUpdateUI(wxUpdateUIEvent &event) override
bool Show(bool show) override
EDA_UNITS m_units
Definition: dialog_shim.h:202
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowQuasiModal()
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
double AsDegrees() const
Definition: eda_angle.h:149
bool IsType(FRAME_T aType) const
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
KIGFX::GAL_DISPLAY_OPTIONS & GetGalDisplayOptions()
Return a reference to the gal rendering options used by GAL for rendering.
GAL_TYPE GetBackend() const
Return the type of backend currently used by GAL canvas.
void StopDrawing()
Prevent the GAL canvas from further drawing until it is recreated or StartDrawing() is called.
KIGFX::VIEW_CONTROLS * GetViewControls() const
Return a pointer to the #VIEW_CONTROLS instance used in the panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
void StartDrawing()
Begin drawing if it was stopped previously.
void SetStealsFocus(bool aStealsFocus)
Set whether focus is taken on certain events (mouseover, keys, etc).
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:141
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
void SetFilled(bool aFlag)
Definition: eda_shape.h:95
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:112
void SetIsAnnotationProxy(bool aIsProxy=true)
Definition: eda_shape.h:88
EDA_ANGLE GetOrientation() const
Definition: footprint.h:191
bool IsFlipped() const
Definition: footprint.h:324
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:567
VECTOR2I GetPosition() const override
Definition: footprint.h:188
FP_TEXT & Reference()
Definition: footprint.h:568
virtual wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const override
Return the string actually shown after processing of the base text.
Definition: fp_text.cpp:415
void ListSet(const wxString &aList)
Add a list of items.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
void SetGridSize(const VECTOR2D &aGridSize)
Set the grid size.
void SetGridVisibility(bool aVisibility)
Set the visibility setting of the grid.
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition: pcb_painter.h:72
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,...
void ApplySettings(const VC_SETTINGS &aSettings)
Load new settings from program common settings.
const VC_SETTINGS & GetSettings() const
Apply VIEW_CONTROLS settings from an object.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition: view.cpp:523
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
void SetBoundary(const BOX2D &aBoundary)
Set limits for view area.
Definition: view.h:279
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:1591
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:195
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:825
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:733
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
static const int UNCONNECTED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:382
void SetBoard(BOARD *aBoard)
int GetSelectedNetcode()
void SetSelectedNetcode(int aNetcode)
void SetNetInfo(NETINFO_LIST *aNetInfoList)
Tool relating to pads and pad settings.
Definition: pad_tool.h:37
void SetLastPadNumber(const wxString &aPadNumber)
Definition: pad_tool.h:66
wxString GetLastPadNumber() const
Definition: pad_tool.h:65
Definition: pad.h:59
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.cpp:814
bool IsAperturePad() const
Definition: pad.h:407
void SetAttribute(PAD_ATTRIB aAttribute)
Definition: pad.cpp:690
void SetLayerSet(LSET aLayers) override
Definition: pad.h:396
PAD_PROP GetProperty() const
Definition: pad.h:403
bool GetRemoveUnconnected() const
Definition: pad.h:609
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: pad.h:383
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:397
const VECTOR2I & GetDrillSize() const
Definition: pad.h:267
PAD_ATTRIB GetAttribute() const
Definition: pad.h:400
void SetLocalSolderPasteMargin(int aMargin)
Definition: pad.h:423
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:196
ZONE_CONNECTION GetZoneConnection() const
Definition: pad.h:522
void SetRemoveUnconnected(bool aSet)
Set the unconnected removal property.
Definition: pad.h:608
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition: pad.cpp:1601
void SetThermalGap(int aGap)
Definition: pad.h:553
void SetThermalSpokeAngle(const EDA_ANGLE &aAngle)
The orientation of the thermal spokes.
Definition: pad.h:540
const wxString & GetNumber() const
Definition: pad.h:135
void MergePrimitivesAsPolygon(SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
double GetLocalSolderPasteMarginRatio() const
Definition: pad.h:425
int GetRoundRectCornerRadius() const
Definition: pad.cpp:345
void DeletePrimitivesList()
Clear the basic shapes list.
void SetDrillShape(PAD_DRILL_SHAPE_T aShape)
Definition: pad.h:382
VECTOR2I GetPosition() const override
Definition: pad.h:202
void SetProperty(PAD_PROP aProperty)
Definition: pad.cpp:701
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:330
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:541
void SetOffset(const VECTOR2I &aOffset)
Definition: pad.h:273
void SetChamferRectRatio(double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition: pad.cpp:368
const VECTOR2I & GetOffset() const
Definition: pad.h:274
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pad.cpp:217
void SetRoundRectCornerRadius(double aRadius)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:351
void SetLocalClearance(int aClearance)
Definition: pad.h:420
void SetKeepTopBottom(bool aSet)
Set whether we keep the top and bottom connections even if they are not connected.
Definition: pad.h:614
void SetNumber(const wxString &aNumber)
Set the pad number (note that it can be alphanumeric, such as the array reference "AA12").
Definition: pad.h:134
void SetZoneConnection(ZONE_CONNECTION aType)
Definition: pad.h:521
int GetLocalSolderMaskMargin() const
Definition: pad.h:415
bool GetKeepTopBottom() const
Definition: pad.h:615
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: pad.h:212
FOOTPRINT * GetParent() const
Definition: pad.cpp:1486
void SetDelta(const VECTOR2I &aSize)
Definition: pad.h:263
bool IsOnCopperLayer() const override
Definition: pad.h:242
void SetPosition(const VECTOR2I &aPos) override
Definition: pad.h:196
const VECTOR2I & GetDelta() const
Definition: pad.h:264
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition: pad.cpp:210
void SetDrillSize(const VECTOR2I &aSize)
Definition: pad.h:266
PAD_SHAPE GetShape() const
Definition: pad.h:194
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:370
void Flip(const VECTOR2I &VECTOR2I, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: pad.cpp:718
static LSET ApertureMask()
layer set for an aperture pad
Definition: pad.cpp:224
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pad.cpp:1462
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:203
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: pad.h:426
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:185
int GetThermalSpokeWidth() const
Definition: pad.h:531
int GetLocalSolderPasteMargin() const
Definition: pad.h:422
void SetPos0(const VECTOR2I &aPos)
Definition: pad.h:250
void SetCustomShapeInZoneOpt(CUST_PAD_SHAPE_IN_ZONE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones.
Definition: pad.h:222
void SetRoundRectRadiusRatio(double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition: pad.cpp:360
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:233
void SetOrientation(const EDA_ANGLE &aAngle)
Set the rotation angle of the pad.
Definition: pad.cpp:709
int GetChamferPositions() const
Definition: pad.h:594
void ReplacePrimitives(const std::vector< std::shared_ptr< PCB_SHAPE > > &aPrimitivesList)
Clear the current custom shape primitives list and import a new list.
void SetLocalSolderMaskMargin(int aMargin)
Definition: pad.h:416
void SetThermalSpokeWidth(int aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: pad.h:530
void SetSize(const VECTOR2I &aSize)
Definition: pad.h:256
double GetRoundRectRadiusRatio() const
Definition: pad.h:575
int GetThermalGap() const
Definition: pad.h:554
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:422
const VECTOR2I & GetSize() const
Definition: pad.h:257
void SetChamferPositions(int aPositions)
Has meaning only for chamfered rectangular pads.
Definition: pad.h:593
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:207
double GetChamferRectRatio() const
Definition: pad.h:584
void SetPadToDieLength(int aLength)
Definition: pad.h:412
bool IsFlipped() const
Definition: pad.cpp:231
int GetPadToDieLength() const
Definition: pad.h:413
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
void ShowPadPropertiesDialog(PAD *aPad)
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
void UpdateColors()
Update the color settings in the painter and GAL.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
virtual void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:191
virtual void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:163
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:72
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
bool IsEmpty() const
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
int OutlineCount() const
Return the number of vertices in a given outline/hole.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:88
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
virtual void ChangeDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
virtual long long int GetValue()
Return the current value in Internal Units.
void Enable(bool aEnable)
Enable/disable the label, widget and units label.
virtual void SetPrecision(int aLength)
Normally not needed, but can be used to set the precision when using internal units that are floats (...
virtual void SetUnits(EDA_UNITS aUnits)
Normally not needed (as the UNIT_BINDER inherits from the parent frame), but can be used to set to DE...
virtual EDA_ANGLE GetAngleValue()
virtual void SetNegativeZero()
Definition: unit_binder.h:71
virtual double GetDoubleValue()
Return the current value in Internal Units.
virtual void SetAngleValue(const EDA_ANGLE &aValue)
virtual void ChangeAngleValue(const EDA_ANGLE &aValue)
virtual void SetDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED)
Validate the control against the given range, informing the user of any errors found.
virtual void ChangeValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void Show(bool aShow, bool aResize=false)
Show/hide the label, widget and units label.
void SetCoordType(ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType)
Set the current origin transform mode.
Definition: unit_binder.h:187
@ LIGHTBLUE
Definition: color4d.h:62
This file is part of the common library.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
#define APERTURE_DLG_TYPE
#define CONN_DLG_TYPE
static wxString formatCoord(EDA_UNITS aUnits, VECTOR2I aCoord)
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.
#define _(s)
static constexpr EDA_ANGLE & ANGLE_45
Definition: eda_angle.h:424
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:425
#define BRIGHTENED
item is drawn with a bright contour
#define SELECTED
Item was manually selected by the user.
SHAPE_T
Definition: eda_shape.h:41
EDA_UNITS
Definition: eda_units.h:43
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
@ ERROR_INSIDE
@ B_Adhes
Definition: layer_ids.h:97
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_SilkS
Definition: layer_ids.h:104
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ Eco2_User
Definition: layer_ids.h:112
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
Definition: eda_units.cpp:326
std::string FormatAngle(const EDA_ANGLE &aAngle)
Converts aAngle from board units to a string appropriate for writing to file.
Definition: eda_units.cpp:131
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:156
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:412
@ CUST_PAD_SHAPE_IN_ZONE_OUTLINE
Definition: pad.h:44
@ CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL
Definition: pad.h:45
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: pad_shapes.h:81
@ NPTH
like PAD_PTH, but not plated
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
@ CONN
Like smd, does not appear on the solder paste layer (default)
@ PAD_DRILL_SHAPE_CIRCLE
Definition: pad_shapes.h:70
@ PAD_DRILL_SHAPE_OBLONG
Definition: pad_shapes.h:71
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: pad_shapes.h:35
PAD_PROP
The set of pad properties used in Gerber files (Draw files, and P&P files) to define some properties ...
Definition: pad_shapes.h:97
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
@ NONE
no special fabrication property
@ TESTPOINT
a test point pad
@ CASTELLATED
a pad with a castellated through hole
@ BGA
Smd pad, used in BGA footprints.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
const double IU_PER_MM
Definition: base_units.h:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
constexpr int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:617
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618
@ THERMAL
Use thermal relief for pads.
@ NONE
Pads are not covered.
@ FULL
pads are covered by copper