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, dick@softplc.com
6  * Copyright (C) 2008-2013 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2020 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 <class_board.h>
31 #include <class_module.h>
32 #include <confirm.h>
33 #include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
34 #include <dialog_pad_properties.h>
36 #include <html_messagebox.h>
37 #include <macros.h>
38 #include <pcb_base_frame.h>
39 #include <pcb_painter.h>
40 #include <pcbnew_settings.h>
42 #include <view/view_controls.h>
43 #include <widgets/net_selector.h>
44 #include <tool/tool_manager.h>
45 #include <tools/pad_tool.h>
46 #include <advanced_config.h> // for pad property feature management
47 
48 
49 // list of pad shapes, ordered like the pad shape wxChoice in dialog.
51 {
58  PAD_SHAPE_CHAMFERED_RECT, // choice = CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT
59  PAD_SHAPE_CUSTOM, // choice = CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
60  PAD_SHAPE_CUSTOM // choice = PAD_SHAPE_CUSTOM_RECT_ANCHOR
61 };
62 
63 // the ordered index of the pad shape wxChoice in dialog.
64 // keep it consistent with code_shape[] and dialog strings
66 {
76 };
77 
79 {
84  PAD_ATTRIB_SMD // Aperture pad :type SMD with no copper layers,
85  // only on tech layers (usually only on paste layer
86 };
87 
88 // Default mask layers setup for pads according to the pad type
89 static const LSET std_pad_layers[] =
90 {
91  D_PAD::StandardMask(), // PAD_ATTRIB_STANDARD:
92  D_PAD::SMDMask(), // PAD_ATTRIB_SMD:
93  D_PAD::ConnSMDMask(), // PAD_ATTRIB_CONN:
94  D_PAD::UnplatedHoleMask(), // PAD_ATTRIB_HOLE_NOT_PLATED:
96 };
97 
98 
100 {
101  DIALOG_PAD_PROPERTIES dlg( this, aPad );
102 
103  if( dlg.ShowQuasiModal() == wxID_OK ) // QuasiModal required for NET_SELECTOR
104  {
105  // aPad can be NULL, if the dialog is called from the footprint editor
106  // to set the default pad setup
107  if( aPad )
108  {
109  PAD_TOOL* padTools = m_toolManager->GetTool<PAD_TOOL>();
110 
111  if( padTools )
112  padTools->SetLastPadName( aPad->GetName() );
113  }
114  }
115 }
116 
117 
119  DIALOG_PAD_PROPERTIES_BASE( aParent ),
120  m_parent( aParent ),
121  m_canUpdate( false ),
122  m_posX( aParent, m_posXLabel, m_posXCtrl, m_posXUnits ),
123  m_posY( aParent, m_posYLabel, m_posYCtrl, m_posYUnits ),
124  m_sizeX( aParent, m_sizeXLabel, m_sizeXCtrl, m_sizeXUnits, true ),
125  m_sizeY( aParent, m_sizeYLabel, m_sizeYCtrl, m_sizeYUnits, true ),
126  m_offsetX( aParent, m_offsetXLabel, m_offsetXCtrl, m_offsetXUnits, true ),
127  m_offsetY( aParent, m_offsetYLabel, m_offsetYCtrl, m_offsetYUnits, true ),
128  m_padToDie( aParent, m_padToDieLabel, m_padToDieCtrl, m_padToDieUnits, true ),
129  m_trapDelta( aParent, m_trapDeltaLabel, m_trapDeltaCtrl, m_trapDeltaUnits, true ),
130  m_cornerRadius( aParent, m_cornerRadiusLabel, m_tcCornerRadius, m_cornerRadiusUnits, true ),
131  m_holeX( aParent, m_holeXLabel, m_holeXCtrl, m_holeXUnits, true ),
132  m_holeY( aParent, m_holeYLabel, m_holeYCtrl, m_holeYUnits, true ),
133  m_OrientValidator( 1, &m_OrientValue ),
134  m_clearance( aParent, m_clearanceLabel, m_clearanceCtrl, m_clearanceUnits, true ),
135  m_maskClearance( aParent, m_maskClearanceLabel, m_maskClearanceCtrl, m_maskClearanceUnits, true ),
136  m_pasteClearance( aParent, m_pasteClearanceLabel, m_pasteClearanceCtrl, m_pasteClearanceUnits, true ),
137  m_spokeWidth( aParent, m_spokeWidthLabel, m_spokeWidthCtrl, m_spokeWidthUnits, true ),
138  m_thermalGap( aParent, m_thermalGapLabel, m_thermalGapCtrl, m_thermalGapUnits, true )
139 {
140  m_currentPad = aPad; // aPad can be NULL, if the dialog is called
141  // from the footprint editor to set default pad setup
142 
144 
145  // Disable the pad property if not allowed in advanced config
146  if( !ADVANCED_CFG::GetCfg().m_EnableUsePadProperty )
147  {
148  m_staticTextFabProperty->Show( false );
149  m_choiceFabProperty->Show( false );
150  }
151 
154 
155  m_OrientValidator.SetRange( -360.0, 360.0 );
156  m_orientation->SetValidator( m_OrientValidator );
157  m_OrientValidator.SetWindow( m_orientation );
158 
159  m_cbShowPadOutline->SetValue( m_sketchPreview );
160 
163 
165  m_dummyPad = new D_PAD( (MODULE*) NULL );
166 
167  if( aPad )
168  {
169  *m_dummyPad = *aPad;
171  }
172  else // We are editing a "master" pad, i.e. a template to create new pads
174 
175  initValues();
176 
177  wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
178  infoFont.SetSymbolicSize( wxFONTSIZE_SMALL );
179  m_techLayersLabel->SetFont( infoFont );
180  m_parentInfoLine1->SetFont( infoFont );
181  m_parentInfoLine2->SetFont( infoFont );
182 
183  infoFont.SetStyle( wxFONTSTYLE_ITALIC );
184  m_nonCopperNote->SetFont( infoFont );
185  m_staticTextInfoPaste->SetFont( infoFont );
186  m_staticTextInfoNegVal->SetFont( infoFont );
187  m_staticTextInfoPosValue->SetFont( infoFont );
188  m_staticTextPrimitiveListWarning->SetFont( infoFont );
189 
190  // Usually, TransferDataToWindow is called by OnInitDialog
191  // calling it here fixes all widget sizes so FinishDialogSettings can safely fix minsizes
193 
194  // Initialize canvas to be able to display the dummy pad:
195  prepareCanvas();
196 
198  m_sdbSizerOK->SetDefault();
199  m_canUpdate = true;
200 
201  m_PadNetSelector->Connect( NET_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ), NULL, this );
202 
203  // Now all widgets have the size fixed, call FinishDialogSettings
205 
206  wxUpdateUIEvent dummy;
207  OnUpdateUI( dummy );
208 }
209 
210 
212 {
213  m_PadNetSelector->Disconnect( NET_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES::OnValuesChanged ), NULL, this );
214 
215  delete m_dummyPad;
216  delete m_axisOrigin;
217 }
218 
219 
220 bool DIALOG_PAD_PROPERTIES::m_sketchPreview = false; // Stores the pad draw option during a session
221 
222 
223 void DIALOG_PAD_PROPERTIES::OnInitDialog( wxInitDialogEvent& event )
224 {
225  m_selectedColor = COLOR4D( 1.0, 1.0, 1.0, 0.7 );
226 
227  // Needed on some WM to be sure the pad is redrawn according to the final size
228  // of the canvas, with the right zoom factor
229  redraw();
230 }
231 
232 
233 void DIALOG_PAD_PROPERTIES::OnCancel( wxCommandEvent& event )
234 {
235  // Mandatory to avoid m_panelShowPadGal trying to draw something
236  // in a non valid context during closing process:
238 
239  // Now call default handler for wxID_CANCEL command event
240  event.Skip();
241 }
242 
243 
245 {
246  // Enable or disable the widgets in page managing custom shape primitives
247  m_listCtrlPrimitives->Enable( aEnable );
248  m_buttonDel->Enable( aEnable );
249  m_buttonEditShape->Enable( aEnable );
250  m_buttonAddShape->Enable( aEnable );
251  m_buttonDup->Enable( aEnable );
252  m_buttonGeometry->Enable( aEnable );
253 }
254 
255 
257 {
258  // Initialize the canvas to display the pad
259 #ifdef __WXMAC__
260  // Cairo renderer doesn't handle Retina displays
262 #else
264 #endif
265  m_padPreviewGAL = new PCB_DRAW_PANEL_GAL( this, -1, wxDefaultPosition, wxDefaultSize,
266  m_parent->GetGalDisplayOptions(), backend );
267 
268  m_padPreviewSizer->Add( m_padPreviewGAL, 12, wxEXPAND | wxALL, 5 );
269 
270  // Show the X and Y axis. It is usefull because pad shape can have an offset
271  // or be a complex shape.
272  KIGFX::COLOR4D axis_color = LIGHTBLUE;
273 
275  Millimeter2iu( 0.2 ),
277  m_axisOrigin->SetDrawAtZero( true );
278 
281 
284 
285  m_padPreviewGAL->Show();
286 
288 
289  // fix the pad render mode (filled/not filled)
290  auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
291  bool sketchMode = m_cbShowPadOutline->IsChecked();
292  settings->SetSketchMode( LAYER_PADS_TH, sketchMode );
293  settings->SetSketchMode( LAYER_PAD_FR, sketchMode );
294  settings->SetSketchMode( LAYER_PAD_BK, sketchMode );
295  settings->SetSketchModeGraphicItems( sketchMode );
296 
297  // gives a non null grid size (0.001mm) because GAL layer does not like a 0 size grid:
298  double gridsize = 0.001 * IU_PER_MM;
299  view->GetGAL()->SetGridSize( VECTOR2D( gridsize, gridsize ) );
300  // And do not show the grid:
301  view->GetGAL()->SetGridVisibility( false );
302  view->Add( m_dummyPad );
303  view->Add( m_axisOrigin );
304 
306  Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_PROPERTIES::OnResize ) );
307 }
308 
309 
311 {
312  // Note: use m_tcCornerSizeRatio->ChangeValue() to avoid generating a wxEVT_TEXT event
313 
316  {
317  wxString ratio = wxString::Format( "%.1f", m_dummyPad->GetRoundRectRadiusRatio() * 100 );
318  m_tcCornerSizeRatio->ChangeValue( ratio );
319  m_tcCornerSizeRatio1->ChangeValue( ratio );
321 
322  ratio = wxString::Format( "%.1f", m_dummyPad->GetChamferRectRatio() * 100 );
323  m_tcChamferRatio->ChangeValue( ratio );
324  m_tcChamferRatio1->ChangeValue( ratio );
325  }
326 }
327 
328 
329 void DIALOG_PAD_PROPERTIES::onCornerRadiusChange( wxCommandEvent& event )
330 {
333  return;
334 
335  double rrRadius = m_cornerRadius.GetValue();
336 
337  if( rrRadius < 0.0 )
338  {
339  rrRadius = 0.0;
340  m_tcCornerRadius->ChangeValue( wxString::Format( "%.1f", rrRadius ) );
341  }
342 
345 
346  auto ratio = wxString::Format( "%.1f", m_dummyPad->GetRoundRectRadiusRatio() * 100 );
347  m_tcCornerSizeRatio->ChangeValue( ratio );
348  m_tcCornerSizeRatio1->ChangeValue( ratio );
349  redraw();
350 }
351 
352 
354 {
357  {
358  return;
359  }
360 
361  wxObject* ctrl = event.GetEventObject();
362  wxString value = event.GetString();
363  bool changed = false;
364 
365  if( ctrl == m_tcCornerSizeRatio || ctrl == m_tcCornerSizeRatio1 )
366  {
367  double ratioPercent;
368 
369  if( value.ToDouble( &ratioPercent ) )
370  {
371  // Clamp ratioPercent to acceptable value (0.0 to 50.0)
372  if( ratioPercent < 0.0 )
373  {
374  ratioPercent = 0.0;
375  value.Printf( "%.1f", ratioPercent );
376  m_tcCornerSizeRatio->ChangeValue( value );
377  m_tcCornerSizeRatio1->ChangeValue( value );
378  }
379 
380  if( ratioPercent > 50.0 )
381  {
382  ratioPercent = 0.5;
383  value.Printf( "%.1f", ratioPercent*100.0 );
384  m_tcCornerSizeRatio->ChangeValue( value );
385  m_tcCornerSizeRatio1->ChangeValue( value );
386  }
387 
388  if( ctrl == m_tcCornerSizeRatio )
389  m_tcCornerSizeRatio1->ChangeValue( value );
390  else
391  m_tcCornerSizeRatio->ChangeValue( value );
392 
393  changed = true;
394  }
395  }
396  else if( ctrl == m_tcChamferRatio || ctrl == m_tcChamferRatio1 )
397  {
398  double ratioPercent;
399 
400  if( value.ToDouble( &ratioPercent ) )
401  {
402  // Clamp ratioPercent to acceptable value (0.0 to 50.0)
403  if( ratioPercent < 0.0 )
404  {
405  ratioPercent = 0.0;
406  value.Printf( "%.1f", ratioPercent );
407  m_tcChamferRatio->ChangeValue( value );
408  m_tcChamferRatio1->ChangeValue( value );
409  }
410 
411  if( ratioPercent > 50.0 )
412  {
413  ratioPercent = 0.5;
414  value.Printf( "%.1f", ratioPercent*100.0 );
415  m_tcChamferRatio->ChangeValue( value );
416  m_tcChamferRatio1->ChangeValue( value );
417  }
418 
419  if( ctrl == m_tcChamferRatio )
420  m_tcChamferRatio1->ChangeValue( value );
421  else
422  m_tcChamferRatio->ChangeValue( value );
423 
424  changed = true;
425  }
426  }
427 
428  if( changed )
429  {
432  redraw();
433  }
434 }
435 
436 
438 {
439  wxString msg;
440  double angle;
441 
442  // Disable pad net name wxTextCtrl if the caller is the footprint editor
443  // because nets are living only in the board managed by the board editor
445 
446  // Setup layers names from board
447  // Should be made first, before calling m_rbCopperLayersSel->SetSelection()
448  m_rbCopperLayersSel->SetString( 0, m_board->GetLayerName( F_Cu ) );
449  m_rbCopperLayersSel->SetString( 1, m_board->GetLayerName( B_Cu ) );
450 
451  m_PadLayerAdhCmp->SetLabel( m_board->GetLayerName( F_Adhes ) );
452  m_PadLayerAdhCu->SetLabel( m_board->GetLayerName( B_Adhes ) );
454  m_PadLayerPateCu->SetLabel( m_board->GetLayerName( B_Paste ) );
456  m_PadLayerSilkCu->SetLabel( m_board->GetLayerName( B_SilkS ) );
457  m_PadLayerMaskCmp->SetLabel( m_board->GetLayerName( F_Mask ) );
458  m_PadLayerMaskCu->SetLabel( m_board->GetLayerName( B_Mask ) );
459  m_PadLayerECO1->SetLabel( m_board->GetLayerName( Eco1_User ) );
460  m_PadLayerECO2->SetLabel( m_board->GetLayerName( Eco2_User ) );
462 
463  m_isFlipped = false;
464 
465  if( m_currentPad )
466  {
468 
469  // Diplay parent footprint info
470  MODULE* footprint = m_currentPad->GetParent();
471  wxString msg1, msg2;
472 
473  if( footprint )
474  {
475  wxString side = footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" );
476  msg1.Printf( _("Footprint %s (%s),"), footprint->GetReference(), footprint->GetValue() );
477  msg2.Printf( _("%s, rotated %.1f deg"), side, footprint->GetOrientation() / 10.0 );
478  }
479 
480  m_parentInfoLine1->SetLabel( msg1 );
481  m_parentInfoLine2->SetLabel( msg2 );
482  }
483 
484  if( m_isFlipped )
485  {
486  wxPoint pt = m_dummyPad->GetOffset();
487  pt.y = -pt.y;
488  m_dummyPad->SetOffset( pt );
489 
490  wxSize sz = m_dummyPad->GetDelta();
491  sz.y = -sz.y;
492  m_dummyPad->SetDelta( sz );
493 
494  // flip pad's layers
496 
497  // flip custom pad shapes
499  }
500 
502 
504 
505  m_PadNumCtrl->SetValue( m_dummyPad->GetName() );
507 
508  // Display current pad parameters units:
511 
514 
517 
518  m_offsetShapeOpt->SetValue( m_dummyPad->GetOffset() != wxPoint() );
521 
522  if( m_dummyPad->GetDelta().x )
523  {
525  m_trapAxisCtrl->SetSelection( 0 );
526  }
527  else
528  {
530  m_trapAxisCtrl->SetSelection( 1 );
531  }
532 
533  m_padToDieOpt->SetValue( m_dummyPad->GetPadToDieLength() != 0 );
535 
541 
542  // Prefer "-0" to "0" for normally negative values
544  m_pasteClearanceCtrl->SetValue( wxT( "-" ) + m_pasteClearanceCtrl->GetValue() );
545 
546  msg.Printf( wxT( "%f" ), m_dummyPad->GetLocalSolderPasteMarginRatio() * 100.0 );
547 
548  if( m_dummyPad->GetLocalSolderPasteMarginRatio() == 0.0 && msg[0] == '0' )
549  // Sometimes Printf adds a sign if the value is small
550  m_SolderPasteMarginRatioCtrl->SetValue( wxT( "-" ) + msg );
551  else
553 
554  switch( m_dummyPad->GetZoneConnection() )
555  {
556  default:
557  case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
558  case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
559  case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
560  case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
561  }
562 
564  m_ZoneCustomPadShape->SetSelection( 1 );
565  else
566  m_ZoneCustomPadShape->SetSelection( 0 );
567 
568  if( m_currentPad )
569  {
571  MODULE* footprint = m_currentPad->GetParent();
572 
573  if( footprint )
574  angle -= footprint->GetOrientation();
575 
576  if( m_isFlipped )
577  angle = -angle;
578 
580  }
581 
583 
584  NORMALIZE_ANGLE_180( angle ); // ? normalizing is in D_PAD::SetOrientation()
585 
586  // Set layers used by this pad: :
588 
589  // Pad Orient
590  // Note: use ChangeValue() instead of SetValue() so that we don't generate events
592 
593  switch( m_dummyPad->GetShape() )
594  {
595  default:
596  case PAD_SHAPE_CIRCLE: m_PadShape->SetSelection( CHOICE_SHAPE_CIRCLE ); break;
597  case PAD_SHAPE_OVAL: m_PadShape->SetSelection( CHOICE_SHAPE_OVAL ); break;
598  case PAD_SHAPE_RECT: m_PadShape->SetSelection( CHOICE_SHAPE_RECT ); break;
599  case PAD_SHAPE_TRAPEZOID: m_PadShape->SetSelection( CHOICE_SHAPE_TRAPEZOID ); break;
600  case PAD_SHAPE_ROUNDRECT: m_PadShape->SetSelection( CHOICE_SHAPE_ROUNDRECT ); break;
601 
603  if( m_dummyPad->GetRoundRectRadiusRatio() > 0.0 )
605  else
606  m_PadShape->SetSelection( CHOICE_SHAPE_CHAMFERED_RECT );
607  break;
608 
609  case PAD_SHAPE_CUSTOM:
612  else
614  break;
615  }
616 
625 
627 
629 
630  // Type of pad selection
631  bool aperture = m_dummyPad->GetAttribute() == PAD_ATTRIB_CONN && m_dummyPad->IsAperturePad();
632 
633  if( aperture )
634  {
635  m_PadType->SetSelection( 4 );
636  }
637  else
638  {
639  switch( m_dummyPad->GetAttribute() )
640  {
641  case PAD_ATTRIB_STANDARD: m_PadType->SetSelection( 0 ); break;
642  case PAD_ATTRIB_SMD: m_PadType->SetSelection( 1 ); break;
643  case PAD_ATTRIB_CONN: m_PadType->SetSelection( 2 ); break;
644  case PAD_ATTRIB_HOLE_NOT_PLATED: m_PadType->SetSelection( 3 ); break;
645  }
646  }
647 
648  switch( m_dummyPad->GetProperty() )
649  {
650  case PAD_PROP_NONE: m_choiceFabProperty->SetSelection( 0 ); break;
651  case PAD_PROP_BGA: m_choiceFabProperty->SetSelection( 1 ); break;
652  case PAD_PROP_FIDUCIAL_LOCAL: m_choiceFabProperty->SetSelection( 2 ); break;
653  case PAD_PROP_FIDUCIAL_GLBL: m_choiceFabProperty->SetSelection( 3 ); break;
654  case PAD_PROP_TESTPOINT: m_choiceFabProperty->SetSelection( 4 ); break;
655  case PAD_PROP_HEATSINK: m_choiceFabProperty->SetSelection( 5 ); break;
656  case PAD_PROP_CASTELLATED: m_choiceFabProperty->SetSelection( 6 ); break;
657  }
658 
659  // Ensure the pad property is compatible with the pad type
661  {
662  m_choiceFabProperty->SetSelection( 0 );
663  m_choiceFabProperty->Enable( false );
664  }
665 
667  m_holeShapeCtrl->SetSelection( 0 );
668  else
669  m_holeShapeCtrl->SetSelection( 1 );
670 
671  // Update some dialog widgets state (Enable/disable options):
672  wxCommandEvent cmd_event;
674  OnPadShapeSelection( cmd_event );
675  OnOffsetCheckbox( cmd_event );
676 
677  // Update basic shapes list
679 }
680 
681 // A small helper function, to display coordinates:
682 static wxString formatCoord( EDA_UNITS aUnits, wxPoint aCoord )
683 {
684  return wxString::Format( "(X:%s Y:%s)",
685  MessageTextFromValue( aUnits, aCoord.x, true ),
686  MessageTextFromValue( aUnits, aCoord.y, true ) );
687 }
688 
690 {
691  m_listCtrlPrimitives->ClearAll();
692 
693  wxListItem itemCol;
694  itemCol.SetImage(-1);
695 
696  for( int ii = 0; ii < 5; ++ii )
697  m_listCtrlPrimitives->InsertColumn(ii, itemCol);
698 
699  wxString bs_info[5];
700 
701  for( unsigned ii = 0; ii < m_primitives.size(); ++ii )
702  {
703  const std::shared_ptr<DRAWSEGMENT>& primitive = m_primitives[ii];
704 
705  for( wxString& s : bs_info )
706  s.Empty();
707 
708  bs_info[4] = _( "width " ) + MessageTextFromValue( m_units, primitive->GetWidth(), true );
709 
710  switch( primitive->GetShape() )
711  {
712  case S_SEGMENT: // usual segment : line with rounded ends
713  bs_info[0] = _( "Segment" );
714  bs_info[1] = _( "from " ) + formatCoord( m_units, primitive->GetStart() );
715  bs_info[2] = _( "to " ) + formatCoord( m_units, primitive->GetEnd() );
716  break;
717 
718  case S_CURVE: // Bezier segment
719  bs_info[0] = _( "Bezier" );
720  bs_info[1] = _( "from " ) + formatCoord( m_units, primitive->GetStart() );
721  bs_info[2] = _( "to " ) + formatCoord( m_units, primitive->GetEnd() );
722  break;
723 
724  case S_ARC: // Arc with rounded ends
725  bs_info[0] = _( "Arc" );
726  bs_info[1] = _( "center " ) + formatCoord( m_units, primitive->GetCenter() );
727  bs_info[2] = _( "start " ) + formatCoord( m_units, primitive->GetArcStart() );
728  bs_info[3] = _( "angle " ) + FormatAngle( primitive->GetAngle() );
729  break;
730 
731  case S_CIRCLE: // ring or circle
732  if( primitive->GetWidth() )
733  bs_info[0] = _( "ring" );
734  else
735  bs_info[0] = _( "circle" );
736 
737  bs_info[1] = formatCoord( m_units, primitive->GetStart() );
738  bs_info[2] = _( "radius " ) + MessageTextFromValue( m_units, primitive->GetRadius(), true );
739  break;
740 
741  case S_POLYGON: // polygon
742  bs_info[0] = "Polygon";
743  bs_info[1] = wxString::Format( _( "corners count %d" ),
744  (int) primitive->GetPolyShape().Outline( 0 ).PointCount() );
745  break;
746 
747  default:
748  bs_info[0] = "Unknown primitive";
749  break;
750  }
751 
752  long tmp = m_listCtrlPrimitives->InsertItem( ii, bs_info[0] );
753  m_listCtrlPrimitives->SetItemData( tmp, ii );
754 
755  for( int jj = 0, col = 0; jj < 5; ++jj )
756  m_listCtrlPrimitives->SetItem( tmp, col++, bs_info[jj] );
757  }
758 
759  // Now columns are filled, ensure correct width of columns
760  for( unsigned ii = 0; ii < 5; ++ii )
761  m_listCtrlPrimitives->SetColumnWidth( ii, wxLIST_AUTOSIZE );
762 }
763 
764 void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
765 {
766  redraw();
767  event.Skip();
768 }
769 
770 
771 void DIALOG_PAD_PROPERTIES::onChangePadMode( wxCommandEvent& event )
772 {
773  m_sketchPreview = m_cbShowPadOutline->GetValue();
774 
776 
777  // fix the pad render mode (filled/not filled)
778  KIGFX::PCB_RENDER_SETTINGS* settings =
779  static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
780 
785 
786  redraw();
787 }
788 
789 
790 
791 void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
792 {
793  switch( m_PadShape->GetSelection() )
794  {
795  case CHOICE_SHAPE_CIRCLE:
796  case CHOICE_SHAPE_OVAL:
797  case CHOICE_SHAPE_RECT:
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 )
811  m_tcCornerSizeRatio->SetValue( "25" );
812  }
813  break;
814 
816  m_shapePropsBook->SetSelection( 3 );
817 
818  // A reasonable default is all corners chamfered.
819  if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue()
820  && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() )
821  {
822  m_cbTopLeft->SetValue( true );
823  m_cbTopRight->SetValue( true );
824  m_cbBottomLeft->SetValue( true );
825  m_cbBottomRight->SetValue( true );
826  }
827  break;
828 
830  {
831  m_shapePropsBook->SetSelection( 4 );
832 
833  // Reasonable defaults (corner radius from IPC-7351C)
834  if( m_dummyPad->GetRoundRectRadiusRatio() == 0.0 )
835  m_tcCornerSizeRatio->SetValue( "25" );
836 
837  if( m_dummyPad->GetChamferRectRatio() == 0.0 )
838  m_tcChamferRatio1->ChangeValue( "20" );
839  }
840  break;
841 
842  case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE_CUSTOM, circular anchor
843  case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE_CUSTOM, rect anchor
844  m_shapePropsBook->SetSelection( 0 );
845  break;
846  }
847 
848  // Readjust props book size
849  wxSize size = m_shapePropsBook->GetSize();
850  size.y = m_shapePropsBook->GetPage( m_shapePropsBook->GetSelection() )->GetBestSize().y;
851  m_shapePropsBook->SetMaxSize( size );
852 
853  m_sizeY.Enable( m_PadShape->GetSelection() != CHOICE_SHAPE_CIRCLE
854  && m_PadShape->GetSelection() != CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR );
855 
856  m_offsetShapeOpt->Enable( m_PadShape->GetSelection() != CHOICE_SHAPE_CIRCLE
857  && m_PadShape->GetSelection() != CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
858  && m_PadShape->GetSelection() != CHOICE_SHAPE_CUSTOM_RECT_ANCHOR );
859 
860  if( !m_offsetShapeOpt->IsEnabled() )
861  m_offsetShapeOpt->SetValue( false );
862 
863  // Show/hide controls depending on m_offsetShapeOpt being enabled
864  m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
865  m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
866 
867  bool is_custom = m_PadShape->GetSelection() == CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
868  || m_PadShape->GetSelection() == CHOICE_SHAPE_CUSTOM_RECT_ANCHOR;
869 
870  enablePrimitivePage( is_custom );
871  m_staticTextcps->Enable( is_custom );
872  m_ZoneCustomPadShape->Enable( is_custom );
873 
875 
877 
878  for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
879  m_notebook->GetPage( i )->Layout();
880 
881  // Resize the dialog if its height is too small to show all widgets:
882  if( m_MainSizer->GetSize().y < m_MainSizer->GetMinSize().y )
883  m_MainSizer->SetSizeHints( this );
884 
885  redraw();
886 }
887 
888 
889 void DIALOG_PAD_PROPERTIES::OnDrillShapeSelected( wxCommandEvent& event )
890 {
892  redraw();
893 }
894 
895 
896 void DIALOG_PAD_PROPERTIES::PadOrientEvent( wxCommandEvent& event )
897 {
899  redraw();
900 }
901 
902 
903 void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event )
904 {
905  int ii = m_PadType->GetSelection();
906 
907  if( (unsigned)ii >= arrayDim( code_type ) ) // catches < 0 also
908  ii = 0;
909 
910  bool hasHole, hasConnection, hasProperty;
911 
912  switch( ii )
913  {
914  default:
915  case 0: /* PTH */ hasHole = true; hasConnection = true; hasProperty = true; break;
916  case 1: /* SMD */ hasHole = false; hasConnection = true; hasProperty = true; break;
917  case 2: /* CONN */ hasHole = false; hasConnection = true; hasProperty = true; break;
918  case 3: /* NPTH */ hasHole = true; hasConnection = false; hasProperty = false; break;
919  case 4: /* Aperture */ hasHole = false; hasConnection = false; hasProperty = true; break;
920  }
921 
922  LSET layer_mask = std_pad_layers[ii];
923  setPadLayersList( layer_mask );
924 
925  if( !hasHole )
926  {
927  m_holeX.SetValue( 0 );
928  m_holeY.SetValue( 0 );
929  }
930  else if ( m_holeX.GetValue() == 0 && m_currentPad )
931  {
934  }
935 
936  if( !hasConnection )
937  {
938  m_PadNumCtrl->SetValue( wxEmptyString );
940  m_padToDieOpt->SetValue( false );
941  }
942  else if( m_PadNumCtrl->GetValue().IsEmpty() && m_currentPad )
943  {
944  m_PadNumCtrl->SetValue( m_currentPad->GetName() );
946  }
947 
948  if( !hasProperty )
949  m_choiceFabProperty->SetSelection( 0 );
950 
951  m_choiceFabProperty->Enable( hasProperty );
952 
954  redraw();
955 }
956 
957 
958 void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
959 {
960  int ii = m_PadType->GetSelection();
961 
962  if( (unsigned)ii >= arrayDim( code_type ) ) // catches < 0 also
963  ii = 0;
964 
965  bool hasHole, hasConnection;
966 
967  switch( ii )
968  {
969  default:
970  case 0: /* PTH */ hasHole = true; hasConnection = true; break;
971  case 1: /* SMD */ hasHole = false; hasConnection = true; break;
972  case 2: /* CONN */ hasHole = false; hasConnection = true; break;
973  case 3: /* NPTH */ hasHole = true; hasConnection = false; break;
974  case 4: /* Aperture */ hasHole = false; hasConnection = false; break;
975  }
976 
977  // Enable/disable hole controls
978  m_holeShapeLabel->Enable( hasHole );
979  m_holeShapeCtrl->Enable( hasHole );
980  m_holeX.Enable( hasHole );
981  m_holeY.Enable( hasHole && m_holeShapeCtrl->GetSelection() == 1 );
982 
983  // Enable/disable Pad number, net and pad length-to-die
984  m_PadNumText->Enable( hasConnection );
985  m_PadNumCtrl->Enable( hasConnection );
986  m_PadNameText->Enable( hasConnection );
987  m_PadNetSelector->Enable( hasConnection && m_canEditNetName && m_currentPad );
988  m_padToDieOpt->Enable( hasConnection );
989 
990  if( !m_padToDieOpt->IsEnabled() )
991  m_padToDieOpt->SetValue( false );
992 
993  // We can show/hide this here because it doesn't require the layout to be refreshed.
994  // All the others have to be done in their event handlers because doing a layout here
995  // causes infinite looping on MSW.
996  m_padToDie.Show( m_padToDieOpt->GetValue() );
997 
998  // Enable/disable Copper Layers control
999  m_rbCopperLayersSel->Enable( ii != 4 );
1000 }
1001 
1002 
1004 {
1005  LSET cu_set = layer_mask & LSET::AllCuMask();
1006 
1007  if( cu_set == LSET( F_Cu ) )
1008  m_rbCopperLayersSel->SetSelection( 0 );
1009  else if( cu_set == LSET( B_Cu ) )
1010  m_rbCopperLayersSel->SetSelection( 1 );
1011  else if( cu_set.any() )
1012  m_rbCopperLayersSel->SetSelection( 2 );
1013  else
1014  m_rbCopperLayersSel->SetSelection( 3 );
1015 
1016  m_PadLayerAdhCmp->SetValue( layer_mask[F_Adhes] );
1017  m_PadLayerAdhCu->SetValue( layer_mask[B_Adhes] );
1018 
1019  m_PadLayerPateCmp->SetValue( layer_mask[F_Paste] );
1020  m_PadLayerPateCu->SetValue( layer_mask[B_Paste] );
1021 
1022  m_PadLayerSilkCmp->SetValue( layer_mask[F_SilkS] );
1023  m_PadLayerSilkCu->SetValue( layer_mask[B_SilkS] );
1024 
1025  m_PadLayerMaskCmp->SetValue( layer_mask[F_Mask] );
1026  m_PadLayerMaskCu->SetValue( layer_mask[B_Mask] );
1027 
1028  m_PadLayerECO1->SetValue( layer_mask[Eco1_User] );
1029  m_PadLayerECO2->SetValue( layer_mask[Eco2_User] );
1030 
1031  m_PadLayerDraft->SetValue( layer_mask[Dwgs_User] );
1032 }
1033 
1034 
1035 // Called when select/deselect a layer.
1036 void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
1037 {
1039  redraw();
1040 }
1041 
1042 
1043 // test if all values are acceptable for the pad
1045 {
1046  bool error = transferDataToPad( m_dummyPad );
1047  bool skip_tstoffset = false; // the offset prm is not always tested
1048 
1049  wxArrayString error_msgs;
1050  wxString msg;
1051 
1052  // Test for incorrect values
1053  if( (m_dummyPad->GetSize().x <= 0) ||
1054  ((m_dummyPad->GetSize().y <= 0) && (m_dummyPad->GetShape() != PAD_SHAPE_CIRCLE)) )
1055  {
1056  error_msgs.Add( _( "Pad size must be greater than zero" ) );
1057  }
1058 
1059  if( (m_dummyPad->GetSize().x < m_dummyPad->GetDrillSize().x) ||
1060  (m_dummyPad->GetSize().y < m_dummyPad->GetDrillSize().y) )
1061  {
1062  error_msgs.Add( _( "Incorrect value for pad drill: pad drill bigger than pad size" ) );
1063  skip_tstoffset = true; // offset prm will be not tested because if the drill value
1064  // is incorrect the offset prm is always seen as incorrect, even if it is 0
1065  }
1066 
1067  if( m_dummyPad->GetLocalClearance() < 0 )
1068  {
1069  error_msgs.Add( _( "Pad local clearance must be zero or greater than zero" ) );
1070  }
1071 
1072  // Some pads need a negative solder mask clearance (mainly for BGA with small pads)
1073  // However the negative solder mask clearance must not create negative mask size
1074  // Therefore test for minimal acceptable negative value
1075  // Hovewer, a negative value can give strange result with custom shapes, so it is not
1076  // allowed for custom pad shape
1078  {
1080  error_msgs.Add( _( "Pad local solder mask clearance must be zero or greater than zero" ) );
1081  else
1082  {
1083  int min_smClearance = -std::min( m_dummyPad->GetSize().x, m_dummyPad->GetSize().y )/2;
1084 
1085  if( m_dummyPad->GetLocalSolderMaskMargin() <= min_smClearance )
1086  {
1087  error_msgs.Add( wxString::Format(
1088  _( "Pad local solder mask clearance must be greater than %s" ),
1089  StringFromValue( GetUserUnits(), min_smClearance, true, true ) ) );
1090  }
1091  }
1092  }
1093 
1094  // Some pads need a positive solder paste clearance (mainly for BGA with small pads)
1095  // Hovewer, a positive value can create issues if the resulting shape is too big.
1096  // (like a solder paste creating a solder paste area on a neighbour pad or on the solder mask)
1097  // So we could ask for user to confirm the choice
1098  // Currently there are no test
1099 
1100  LSET padlayers_mask = m_dummyPad->GetLayerSet();
1101 
1102  if( padlayers_mask == 0 )
1103  error_msgs.Add( _( "Error: pad has no layer" ) );
1104 
1105  if( !padlayers_mask[F_Cu] && !padlayers_mask[B_Cu] )
1106  {
1107  if( m_dummyPad->GetDrillSize().x || m_dummyPad->GetDrillSize().y )
1108  {
1109  // Note: he message is shown in an HTML window
1110  msg = _( "Error: the pad is not on a copper layer and has a hole" );
1111 
1113  {
1114  msg += wxT( "<br><br><i>" );
1115  msg += _( "For NPTH pad, set pad size value to pad drill value,"
1116  " if you do not want this pad plotted in gerber files" );
1117  }
1118 
1119  error_msgs.Add( msg );
1120  }
1121  }
1122 
1123  if( !skip_tstoffset )
1124  {
1125  wxPoint max_size;
1126  max_size.x = std::abs( m_dummyPad->GetOffset().x );
1127  max_size.y = std::abs( m_dummyPad->GetOffset().y );
1128  max_size.x += m_dummyPad->GetDrillSize().x / 2;
1129  max_size.y += m_dummyPad->GetDrillSize().y / 2;
1130 
1131  if( ( m_dummyPad->GetSize().x / 2 < max_size.x ) ||
1132  ( m_dummyPad->GetSize().y / 2 < max_size.y ) )
1133  {
1134  error_msgs.Add( _( "Incorrect value for pad offset" ) );
1135  }
1136  }
1137 
1138  if( error )
1139  error_msgs.Add( _( "Too large value for pad delta size" ) );
1140 
1141  switch( m_dummyPad->GetAttribute() )
1142  {
1143  case PAD_ATTRIB_HOLE_NOT_PLATED: // Not plated, but through hole, a hole is expected
1144  case PAD_ATTRIB_STANDARD : // Pad through hole, a hole is also expected
1145  if( m_dummyPad->GetDrillSize().x <= 0 ||
1147  error_msgs.Add( _( "Error: Through hole pad: drill diameter set to 0" ) );
1148  break;
1149 
1150  case PAD_ATTRIB_CONN: // Connector pads are smd pads, just they do not have solder paste.
1151  if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
1152  error_msgs.Add( _( "Error: Connector pads are not on the solder paste layer\n"
1153  "Use SMD pads instead" ) );
1155 
1156  case PAD_ATTRIB_SMD: // SMD and Connector pads (One external copper layer only)
1157  {
1158  LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
1159 
1160  if( ( padlayers_mask[F_Cu] && padlayers_mask[B_Cu] ) ||
1161  innerlayers_mask.count() != 0 )
1162  error_msgs.Add( _( "Error: only one external copper layer allowed for SMD or Connector pads" ) );
1163  }
1164  break;
1165  }
1166 
1167  if( m_dummyPad->GetProperty() != PAD_PROP_NONE &&
1169  error_msgs.Add( _( "Property cannot be set for NPTH" ) );
1170 
1173  error_msgs.Add( _( "Castellated property can be set only for PTH" ) );
1174 
1175  if( m_dummyPad->GetProperty() == PAD_PROP_BGA &&
1177  error_msgs.Add( _( "BGA property can be set only for SMD pads" ) );
1178 
1181  {
1182  wxASSERT( m_tcCornerSizeRatio->GetValue() == m_tcCornerSizeRatio1->GetValue() );
1183  wxString value = m_tcCornerSizeRatio->GetValue();
1184  double rrRadiusRatioPercent;
1185 
1186  if( !value.ToDouble( &rrRadiusRatioPercent ) )
1187  error_msgs.Add( _( "Incorrect corner size value" ) );
1188  else
1189  {
1190  if( rrRadiusRatioPercent < 0.0 )
1191  error_msgs.Add( _( "Incorrect (negative) corner size value" ) );
1192  else if( rrRadiusRatioPercent > 50.0 )
1193  error_msgs.Add( _( "Corner size value must be smaller than 50%" ) );
1194  }
1195  }
1196 
1198  {
1199  SHAPE_POLY_SET mergedPolygon;
1200  m_dummyPad->MergePrimitivesAsPolygon( &mergedPolygon );
1201 
1202  if( mergedPolygon.OutlineCount() > 1 )
1203  error_msgs.Add( _( "Incorrect pad shape: the shape must be equivalent to only one polygon" ) );
1204  }
1205 
1206 
1207  if( error_msgs.GetCount() )
1208  {
1209  HTML_MESSAGE_BOX dlg( this, _("Pad setup errors list" ) );
1210  dlg.ListSet( error_msgs );
1211  dlg.ShowModal();
1212  }
1213 
1214  return error_msgs.GetCount() == 0;
1215 }
1216 
1217 
1219 {
1220  if( !m_canUpdate )
1221  return;
1222 
1223  KIGFX::VIEW* view = m_padPreviewGAL->GetView();
1225 
1226  // The layer used to place primitive items selected when editing custom pad shapes
1227  // we use here a layer never used in a pad:
1228  #define SELECTED_ITEMS_LAYER Dwgs_User
1229 
1231  KIGFX::PCB_RENDER_SETTINGS* settings =
1232  static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
1234 
1235  view->Update( m_dummyPad );
1236 
1237  // delete previous items if highlight list
1238  while( m_highlight.size() )
1239  {
1240  delete m_highlight.back(); // the dtor also removes item from view
1241  m_highlight.pop_back();
1242  }
1243 
1244  // highlight selected primitives:
1245  long select = m_listCtrlPrimitives->GetFirstSelected();
1246 
1247  while( select >= 0 )
1248  {
1249  DRAWSEGMENT* dummySegment = (DRAWSEGMENT*) m_primitives[select]->Clone();
1250  dummySegment->SetLayer( SELECTED_ITEMS_LAYER );
1251  dummySegment->Rotate( wxPoint( 0, 0), m_dummyPad->GetOrientation() );
1252  dummySegment->Move( m_dummyPad->GetPosition() );
1253 
1254  view->Add( dummySegment );
1255  m_highlight.push_back( dummySegment );
1256 
1257  select = m_listCtrlPrimitives->GetNextSelected( select );
1258  }
1259 
1260  BOX2I bbox = m_dummyPad->ViewBBox();
1261 
1262  if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
1263  {
1264  // The origin always goes in the middle of the canvas; we want offsetting the pad
1265  // shape to move the pad, not the hole
1266  bbox.Move( -m_dummyPad->GetPosition() );
1267  int maxXExtent = std::max( abs( bbox.GetLeft() ), abs( bbox.GetRight() ) );
1268  int maxYExtent = std::max( abs( bbox.GetTop() ), abs( bbox.GetBottom() ) );
1269 
1270  // Don't blow up the GAL on too-large numbers
1271  if( maxXExtent > INT_MAX / 4 )
1272  maxXExtent = INT_MAX / 4;
1273 
1274  if( maxYExtent > INT_MAX / 4 )
1275  maxYExtent = INT_MAX / 4;
1276 
1277  BOX2D viewBox( m_dummyPad->GetPosition(), {0, 0} );
1278  BOX2D canvasBox( m_dummyPad->GetPosition(), {0, 0} );
1279  viewBox.Inflate( maxXExtent * 1.4, maxYExtent * 1.4 ); // add a margin
1280  canvasBox.Inflate( maxXExtent * 2.0, maxYExtent * 2.0 );
1281 
1282  view->SetBoundary( canvasBox );
1283 
1284  // Autozoom
1285  view->SetViewport( viewBox );
1286 
1289  }
1290 }
1291 
1292 
1294 {
1295  if( !wxDialog::TransferDataToWindow() )
1296  return false;
1297 
1298  if( !m_panelGeneral->TransferDataToWindow() )
1299  return false;
1300 
1301  if( !m_localSettingsPanel->TransferDataToWindow() )
1302  return false;
1303 
1304  return true;
1305 }
1306 
1307 
1309 {
1310  BOARD_COMMIT commit( m_parent );
1311 
1312  if( !wxDialog::TransferDataFromWindow() )
1313  return false;
1314 
1315  if( !m_panelGeneral->TransferDataFromWindow() )
1316  return false;
1317 
1318  if( !m_localSettingsPanel->TransferDataFromWindow() )
1319  return false;
1320 
1321  if( !padValuesOK() )
1322  return false;
1323 
1324  int isign = m_isFlipped ? -1 : 1;
1325 
1327  // m_padMaster is a pattern: ensure there is no net for this pad:
1329 
1330  if( !m_currentPad ) // Set current Pad parameters
1331  return true;
1332 
1333  commit.Modify( m_currentPad );
1334 
1335  // redraw the area where the pad was, without pad (delete pad on screen)
1337  m_parent->GetCanvas()->Refresh();
1339 
1340  // Update values
1344 
1345  wxSize size;
1346  MODULE* footprint = m_currentPad->GetParent();
1347 
1348  if( footprint )
1349  {
1350  footprint->SetLastEditTime();
1351 
1352  // compute the pos 0 value, i.e. pad position for footprint with orientation = 0
1353  // i.e. relative to footprint origin (footprint position)
1354  wxPoint pt = m_currentPad->GetPosition() - footprint->GetPosition();
1355  RotatePoint( &pt, -footprint->GetOrientation() );
1356  m_currentPad->SetPos0( pt );
1358  + footprint->GetOrientation() );
1359  }
1360 
1362 
1363  size = m_padMaster->GetDelta();
1364  size.y *= isign;
1365  m_currentPad->SetDelta( size );
1366 
1369 
1370  wxPoint offset = m_padMaster->GetOffset();
1371  offset.y *= isign;
1372  m_currentPad->SetOffset( offset );
1373 
1375 
1378 
1379 
1382 
1383  if( m_isFlipped )
1384  {
1387  }
1388 
1390 
1391  if( m_isFlipped )
1392  {
1394  }
1395 
1397 
1398  int padNetcode = NETINFO_LIST::UNCONNECTED;
1399 
1400  // For PAD_ATTRIB_HOLE_NOT_PLATED, ensure there is no net name selected
1402  padNetcode = m_PadNetSelector->GetSelectedNetcode();
1403 
1404  m_currentPad->SetNetCode( padNetcode );
1415 
1416  // rounded rect pads with radius ratio = 0 are in fact rect pads.
1417  // So set the right shape (and perhaps issues with a radius = 0)
1420  {
1422  }
1423 
1424  // Set the fabrication property:
1426 
1427  // define the way the clearance area is defined in zones
1429 
1430  if( footprint )
1431  footprint->CalculateBoundingBox();
1432 
1434 
1435  // redraw the area where the pad was
1436  m_parent->GetCanvas()->Refresh();
1437 
1438  commit.Push( _( "Modify pad" ) );
1439 
1440  return true;
1441 }
1442 
1443 
1445 {
1446  PAD_PROP_T prop = PAD_PROP_NONE;
1447 
1448  switch( m_choiceFabProperty->GetSelection() )
1449  {
1450  case 0: prop = PAD_PROP_NONE; break;
1451  case 1: prop = PAD_PROP_BGA; break;
1452  case 2: prop = PAD_PROP_FIDUCIAL_LOCAL; break;
1453  case 3: prop = PAD_PROP_FIDUCIAL_GLBL; break;
1454  case 4: prop = PAD_PROP_TESTPOINT; break;
1455  case 5: prop = PAD_PROP_HEATSINK; break;
1456  case 6: prop = PAD_PROP_CASTELLATED; break;
1457  }
1458 
1459  return prop;
1460 }
1461 
1462 
1464 {
1465  wxString msg;
1466 
1467  if( !Validate() )
1468  return true;
1469  if( !m_panelGeneral->Validate() )
1470  return true;
1471  if( !m_localSettingsPanel->Validate() )
1472  return true;
1473  if( !m_spokeWidth.Validate( 0, INT_MAX ) )
1474  return false;
1475 
1476  m_OrientValidator.TransferFromWindow();
1477 
1478  aPad->SetAttribute( code_type[m_PadType->GetSelection()] );
1479  aPad->SetShape( code_shape[m_PadShape->GetSelection()] );
1482 
1483  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
1484  aPad->SetPrimitives( m_primitives );
1485 
1486  // Read pad clearances values:
1491  aPad->SetThermalGap( m_thermalGap.GetValue() );
1492  double dtmp = 0.0;
1493  msg = m_SolderPasteMarginRatioCtrl->GetValue();
1494  msg.ToDouble( &dtmp );
1495 
1496  // A -50% margin ratio means no paste on a pad, the ratio must be >= -50%
1497  if( dtmp < -50.0 )
1498  dtmp = -50.0;
1499  // A margin ratio is always <= 0
1500  // 0 means use full pad copper area
1501  if( dtmp > 0.0 )
1502  dtmp = 0.0;
1503 
1504  aPad->SetLocalSolderPasteMarginRatio( dtmp / 100 );
1505 
1506  switch( m_ZoneConnectionChoice->GetSelection() )
1507  {
1508  default:
1509  case 0: aPad->SetZoneConnection( ZONE_CONNECTION::INHERITED ); break;
1510  case 1: aPad->SetZoneConnection( ZONE_CONNECTION::FULL ); break;
1511  case 2: aPad->SetZoneConnection( ZONE_CONNECTION::THERMAL ); break;
1512  case 3: aPad->SetZoneConnection( ZONE_CONNECTION::NONE ); break;
1513  }
1514 
1515  aPad->SetPosition( wxPoint( m_posX.GetValue(), m_posY.GetValue() ) );
1516  aPad->SetPos0( wxPoint( m_posX.GetValue(), m_posY.GetValue() ) );
1517 
1518  if( m_holeShapeCtrl->GetSelection() == 0 )
1519  {
1521  aPad->SetDrillSize( wxSize( m_holeX.GetValue(), m_holeX.GetValue() ) );
1522  }
1523  else
1524  {
1526  aPad->SetDrillSize( wxSize( m_holeX.GetValue(), m_holeY.GetValue() ) );
1527  }
1528 
1529  if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
1530  aPad->SetSize( wxSize( m_sizeX.GetValue(), m_sizeX.GetValue() ) );
1531  else
1532  aPad->SetSize( wxSize( m_sizeX.GetValue(), m_sizeY.GetValue() ) );
1533 
1534  // For a trapezoid, test delta value (be sure delta is not too large for pad size)
1535  // remember DeltaSize.x is the Y size variation
1536  bool error = false;
1537  wxSize delta( 0, 0 );
1538 
1539  if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID )
1540  {
1541  // For a trapezoid, only one of delta.x or delta.y is not 0, depending on axis.
1542  if( m_trapAxisCtrl->GetSelection() == 0 )
1543  delta.x = m_trapDelta.GetValue();
1544  else
1545  delta.y = m_trapDelta.GetValue();
1546 
1547  if( delta.x < 0 && delta.x <= -aPad->GetSize().y )
1548  {
1549  delta.x = -aPad->GetSize().y + 2;
1550  error = true;
1551  }
1552 
1553  if( delta.x > 0 && delta.x >= aPad->GetSize().y )
1554  {
1555  delta.x = aPad->GetSize().y - 2;
1556  error = true;
1557  }
1558 
1559  if( delta.y < 0 && delta.y <= -aPad->GetSize().x )
1560  {
1561  delta.y = -aPad->GetSize().x + 2;
1562  error = true;
1563  }
1564 
1565  if( delta.y > 0 && delta.y >= aPad->GetSize().x )
1566  {
1567  delta.y = aPad->GetSize().x - 2;
1568  error = true;
1569  }
1570  }
1571 
1572  aPad->SetDelta( delta );
1573 
1574  if( m_offsetShapeOpt->GetValue() )
1576  else
1577  aPad->SetOffset( wxPoint() );
1578 
1579  // Read pad length die
1580  if( m_padToDieOpt->GetValue() )
1582  else
1583  aPad->SetPadToDieLength( 0 );
1584 
1585  aPad->SetOrientation( m_OrientValue * 10.0 );
1586  aPad->SetName( m_PadNumCtrl->GetValue() );
1588 
1589  int chamfers = 0;
1590 
1591  if( m_PadShape->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT )
1592  {
1593  if( m_cbTopLeft->GetValue() )
1594  chamfers |= RECT_CHAMFER_TOP_LEFT;
1595 
1596  if( m_cbTopRight->GetValue() )
1597  chamfers |= RECT_CHAMFER_TOP_RIGHT;
1598 
1599  if( m_cbBottomLeft->GetValue() )
1600  chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1601 
1602  if( m_cbBottomRight->GetValue() )
1603  chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1604  }
1605  else if( m_PadShape->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
1606  {
1607  if( m_cbTopLeft1->GetValue() )
1608  chamfers |= RECT_CHAMFER_TOP_LEFT;
1609 
1610  if( m_cbTopRight1->GetValue() )
1611  chamfers |= RECT_CHAMFER_TOP_RIGHT;
1612 
1613  if( m_cbBottomLeft1->GetValue() )
1614  chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
1615 
1616  if( m_cbBottomRight1->GetValue() )
1617  chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
1618  }
1619  aPad->SetChamferPositions( chamfers );
1620 
1621  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
1622  {
1623  // The pad custom has a "anchor pad" (a basic shape: round or rect pad)
1624  // that is the minimal area of this pad, and is usefull to ensure a hole
1625  // diameter is acceptable, and is used in Gerber files as flashed area
1626  // reference
1627  if( aPad->GetAnchorPadShape() == PAD_SHAPE_CIRCLE )
1628  aPad->SetSize( wxSize( m_sizeX.GetValue(), m_sizeX.GetValue() ) );
1629 
1630  // define the way the clearance area is defined in zones
1631  aPad->SetCustomShapeInZoneOpt( m_ZoneCustomPadShape->GetSelection() == 0 ?
1634  }
1635 
1636  switch( aPad->GetAttribute() )
1637  {
1638  case PAD_ATTRIB_STANDARD:
1639  break;
1640 
1641  case PAD_ATTRIB_CONN:
1642  case PAD_ATTRIB_SMD:
1643  // SMD and PAD_ATTRIB_CONN has no hole.
1644  // basically, SMD and PAD_ATTRIB_CONN are same type of pads
1645  // PAD_ATTRIB_CONN has just a default non technical layers that differs from SMD
1646  // and are intended to be used in virtual edge board connectors
1647  // However we can accept a non null offset,
1648  // mainly to allow complex pads build from a set of basic pad shapes
1649  aPad->SetDrillSize( wxSize( 0, 0 ) );
1650  break;
1651 
1653  // Mechanical purpose only:
1654  // no net name, no pad name allowed
1655  aPad->SetName( wxEmptyString );
1657  break;
1658 
1659  default:
1660  DisplayError( NULL, wxT( "Error: unknown pad type" ) );
1661  break;
1662  }
1663 
1664  if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
1665  {
1666  double ratioPercent;
1667 
1668  m_tcCornerSizeRatio->GetValue().ToDouble( &ratioPercent );
1669  aPad->SetRoundRectRadiusRatio( ratioPercent / 100.0 );
1670  }
1671  else if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT
1672  && m_PadShape->GetSelection() == CHOICE_SHAPE_CHAMFERED_ROUNDED_RECT )
1673  {
1674  double ratioPercent;
1675 
1676  m_tcCornerSizeRatio1->GetValue().ToDouble( &ratioPercent );
1677  aPad->SetRoundRectRadiusRatio( ratioPercent / 100.0 );
1678  }
1679 
1680  if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
1681  {
1682  double ratioPercent;
1683 
1684  m_tcChamferRatio->GetValue().ToDouble( &ratioPercent );
1685  aPad->SetChamferRectRatio( ratioPercent / 100.0 );
1686  }
1687 
1688  aPad->SetProperty( getSelectedProperty() );
1689 
1690  LSET padLayerMask;
1691 
1692  switch( m_rbCopperLayersSel->GetSelection() )
1693  {
1694  case 0: padLayerMask.set( F_Cu ); break;
1695  case 1: padLayerMask.set( B_Cu ); break;
1696  case 2: padLayerMask |= LSET::AllCuMask(); break;
1697  case 3: break; // No copper layers
1698  }
1699 
1700  if( m_PadLayerAdhCmp->GetValue() )
1701  padLayerMask.set( F_Adhes );
1702 
1703  if( m_PadLayerAdhCu->GetValue() )
1704  padLayerMask.set( B_Adhes );
1705 
1706  if( m_PadLayerPateCmp->GetValue() )
1707  padLayerMask.set( F_Paste );
1708 
1709  if( m_PadLayerPateCu->GetValue() )
1710  padLayerMask.set( B_Paste );
1711 
1712  if( m_PadLayerSilkCmp->GetValue() )
1713  padLayerMask.set( F_SilkS );
1714 
1715  if( m_PadLayerSilkCu->GetValue() )
1716  padLayerMask.set( B_SilkS );
1717 
1718  if( m_PadLayerMaskCmp->GetValue() )
1719  padLayerMask.set( F_Mask );
1720 
1721  if( m_PadLayerMaskCu->GetValue() )
1722  padLayerMask.set( B_Mask );
1723 
1724  if( m_PadLayerECO1->GetValue() )
1725  padLayerMask.set( Eco1_User );
1726 
1727  if( m_PadLayerECO2->GetValue() )
1728  padLayerMask.set( Eco2_User );
1729 
1730  if( m_PadLayerDraft->GetValue() )
1731  padLayerMask.set( Dwgs_User );
1732 
1733  aPad->SetLayerSet( padLayerMask );
1734 
1735  return error;
1736 }
1737 
1738 
1739 void DIALOG_PAD_PROPERTIES::OnOffsetCheckbox( wxCommandEvent& event )
1740 {
1741  if( m_offsetShapeOpt->GetValue() && m_currentPad )
1742  {
1745  }
1746 
1747  // Show/hide controls depending on m_offsetShapeOpt being enabled
1748  m_offsetCtrls->Show( m_offsetShapeOpt->GetValue() );
1749  m_offsetShapeOptLabel->Show( m_offsetShapeOpt->GetValue() );
1750 
1751  for( size_t i = 0; i < m_notebook->GetPageCount(); ++i )
1752  m_notebook->GetPage( i )->Layout();
1753 
1754  OnValuesChanged( event );
1755 }
1756 
1757 
1758 void DIALOG_PAD_PROPERTIES::OnPadToDieCheckbox( wxCommandEvent& event )
1759 {
1760  if( m_padToDieOpt->GetValue() && m_currentPad )
1762 
1763  OnValuesChanged( event );
1764 }
1765 
1766 
1767 void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
1768 {
1769  if( m_canUpdate )
1770  {
1772  // If the pad size has changed, update the displayed values
1773  // for rounded rect pads
1775 
1776  redraw();
1777  }
1778 }
1779 
1781 {
1782  long select = m_listCtrlPrimitives->GetFirstSelected();
1783 
1784  if( select < 0 )
1785  {
1786  wxMessageBox( _( "No shape selected" ) );
1787  return;
1788  }
1789 
1790  std::shared_ptr<DRAWSEGMENT>& shape = m_primitives[select];
1791 
1792  if( shape->GetShape() == S_POLYGON )
1793  {
1794  DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, shape.get() );
1795 
1796  if( dlg.ShowModal() != wxID_OK )
1797  return;
1798 
1799  dlg.TransferDataFromWindow();
1800  }
1801 
1802  else
1803  {
1804  DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, shape.get() );
1805 
1806  if( dlg.ShowModal() != wxID_OK )
1807  return;
1808 
1809  dlg.TransferDataFromWindow();
1810  }
1811 
1813 
1814  if( m_canUpdate )
1815  {
1817  redraw();
1818  }
1819 }
1820 
1821 
1823 {
1824  // Called on a double click on the basic shapes list
1825  // To Do: highligth the primitive(s) currently selected.
1826  redraw();
1827 }
1828 
1829 
1831 void DIALOG_PAD_PROPERTIES::onPrimitiveDClick( wxMouseEvent& event )
1832 {
1833  editPrimitive();
1834 }
1835 
1836 
1837 // Called on a click on basic shapes list panel button
1838 void DIALOG_PAD_PROPERTIES::onEditPrimitive( wxCommandEvent& event )
1839 {
1840  editPrimitive();
1841 }
1842 
1843 // Called on a click on basic shapes list panel button
1844 void DIALOG_PAD_PROPERTIES::onDeletePrimitive( wxCommandEvent& event )
1845 {
1846  long select = m_listCtrlPrimitives->GetFirstSelected();
1847 
1848  if( select < 0 )
1849  return;
1850 
1851  // Multiple selections are allowed. get them and remove corresponding shapes
1852  std::vector<long> indexes;
1853  indexes.push_back( select );
1854 
1855  while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
1856  indexes.push_back( select );
1857 
1858  // Erase all select shapes
1859  for( unsigned ii = indexes.size(); ii > 0; --ii )
1860  m_primitives.erase( m_primitives.begin() + indexes[ii-1] );
1861 
1863 
1864  if( m_canUpdate )
1865  {
1867  redraw();
1868  }
1869 }
1870 
1871 
1872 void DIALOG_PAD_PROPERTIES::onAddPrimitive( wxCommandEvent& event )
1873 {
1874  // Ask user for shape type
1875  wxString shapelist[] = { _( "Segment" ), _( "Arc" ), _( "Bezier" ),
1876  _( "Ring/Circle" ), _( "Polygon" ) };
1877 
1878  int type = wxGetSingleChoiceIndex( _( "Shape type:" ), _( "Add Primitive" ),
1879  arrayDim( shapelist ), shapelist, 0, this );
1880 
1881  // User pressed cancel
1882  if( type == -1 )
1883  return;
1884 
1885  STROKE_T listtype[] = { S_SEGMENT, S_ARC, S_CURVE, S_CIRCLE, S_POLYGON };
1886 
1887  DRAWSEGMENT* primitive = new DRAWSEGMENT();
1888  primitive->SetShape( listtype[type] );
1890 
1891  if( listtype[type] == S_POLYGON )
1892  {
1893  DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, primitive );
1894 
1895  if( dlg.ShowModal() != wxID_OK )
1896  return;
1897  }
1898  else
1899  {
1900  DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, primitive );
1901 
1902  if( dlg.ShowModal() != wxID_OK )
1903  return;
1904  }
1905 
1906  m_primitives.emplace_back( primitive );
1907 
1909 
1910  if( m_canUpdate )
1911  {
1913  redraw();
1914  }
1915 }
1916 
1917 
1918 void DIALOG_PAD_PROPERTIES::onGeometryTransform( wxCommandEvent& event )
1919 {
1920  long select = m_listCtrlPrimitives->GetFirstSelected();
1921 
1922  if( select < 0 )
1923  {
1924  wxMessageBox( _( "No shape selected" ) );
1925  return;
1926  }
1927 
1928  // Multiple selections are allowed. Build selected shapes list
1929  std::vector<std::shared_ptr<DRAWSEGMENT>> shapeList;
1930  shapeList.emplace_back( m_primitives[select] );
1931 
1932  while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
1933  shapeList.emplace_back( m_primitives[select] );
1934 
1935  DIALOG_PAD_PRIMITIVES_TRANSFORM dlg( this, m_parent, shapeList, false );
1936 
1937  if( dlg.ShowModal() != wxID_OK )
1938  return;
1939 
1940  dlg.Transform();
1941 
1943 
1944  if( m_canUpdate )
1945  {
1947  redraw();
1948  }
1949 }
1950 
1951 
1952 void DIALOG_PAD_PROPERTIES::onDuplicatePrimitive( wxCommandEvent& event )
1953 {
1954  long select = m_listCtrlPrimitives->GetFirstSelected();
1955 
1956  if( select < 0 )
1957  {
1958  wxMessageBox( _( "No shape selected" ) );
1959  return;
1960  }
1961 
1962  // Multiple selections are allowed. Build selected shapes list
1963  std::vector<std::shared_ptr<DRAWSEGMENT>> shapeList;
1964  shapeList.emplace_back( m_primitives[select] );
1965 
1966  while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
1967  shapeList.emplace_back( m_primitives[select] );
1968 
1969  DIALOG_PAD_PRIMITIVES_TRANSFORM dlg( this, m_parent, shapeList, true );
1970 
1971  if( dlg.ShowModal() != wxID_OK )
1972  return;
1973 
1974  // Transfer new settings
1975  // save duplicates to a separate vector to avoid m_primitives reallocation,
1976  // as shapeList contains pointers to its elements
1977  std::vector<std::shared_ptr<DRAWSEGMENT>> duplicates;
1978  dlg.Transform( &duplicates, dlg.GetDuplicateCount() );
1979  std::move( duplicates.begin(), duplicates.end(), std::back_inserter( m_primitives ) );
1980 
1982 
1983  if( m_canUpdate )
1984  {
1986  redraw();
1987  }
1988 }
void OnInitDialog(wxInitDialogEvent &event) override
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:712
EDA_UNITS
Definition: common.h:198
void OnValuesChanged(wxCommandEvent &event) override
Called when a dimension has changed.
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
void Move(const Vec &aMoveVector)
Function Move moves the rectangle by the aMoveVector.
Definition: box2.h:119
int GetLocalSolderMaskMargin() const
Definition: class_pad.h:340
double GetOrientation() const
Definition: class_module.h:211
COMMIT & Modify(EDA_ITEM *aItem)
Modifies a given item in the model.
Definition: commit.h:103
void MergePrimitivesAsPolygon(SHAPE_POLY_SET *aMergedPolygon) const
Merge all basic shapes to a SHAPE_POLY_SET Note: The corners coordinates are relative to the pad posi...
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint BACK and FRONT copper layers, mask,...
Definition: lset.cpp:531
DIALOG_PAD_PROPERTIES(PCB_BASE_FRAME *aParent, D_PAD *aPad)
void SetShape(STROKE_T aShape)
int GetNetCode() const
Function GetNetCode.
void SetViewport(const BOX2D &aViewport)
Function SetViewport() Sets the visible area of the VIEW.
Definition: view.cpp:550
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project Overloaded in FOOTPRINT_EDIT_FRAME.
#define KI_FALLTHROUGH
void enablePrimitivePage(bool aEnable)
enable (or disable) the primitive page editor
int OutlineCount() const
Returns the number of outlines in the set
static LSET StandardMask()
layer set for a through hole pad
Definition: class_pad.cpp:99
KIGFX::VIEW_CONTROLS * GetViewControls() const
Function GetViewControls() Returns a pointer to the VIEW_CONTROLS instance used in the panel.
void FlipPrimitives()
Flip the basic shapes, in custom pads.
Definition: class_pad.cpp:472
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer.
virtual void Move(const wxPoint &aMoveVector) override
Function Move move this object.
no special fabrication property
Definition: pad_shapes.h:97
KIGFX::GAL_DISPLAY_OPTIONS & GetGalDisplayOptions()
Return a reference to the gal rendering options used by GAL for rendering.
virtual void SetTopLayer(int aLayer, bool aEnabled=true)
Function SetTopLayer() Sets given layer to be displayed on the top or sets back the default order of ...
Definition: view.cpp:860
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
PAD_ATTR_T
Enum PAD_ATTR_T is the set of pad shapes, used with D_PAD::{Set,Get}Attribute() The double name is fo...
Definition: pad_shapes.h:78
bool IsFlipped() const
function IsFlipped
Definition: class_module.h:288
PAD_PROP_T getSelectedProperty()
Return the pad property currently selected.
multilayer pads, usually with holes
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Implementation of conversion functions that require both schematic and board internal units.
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: class_pad.cpp:120
This file is part of the common library.
coord_type GetTop() const
Definition: box2.h:203
PAD_SHAPE_T GetAnchorPadShape() const
Function GetAnchorPadShape.
Definition: class_pad.h:168
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: class_pad.cpp:106
wxPoint GetPosition() const override
Definition: class_pad.h:162
VIEW_CONTROLS class definition.
static wxString formatCoord(EDA_UNITS aUnits, wxPoint aCoord)
void ApplySettings(const VC_SETTINGS &aSettings)
Applies VIEW_CONTROLS settings from an object
int GetLocalClearance(wxString *aSource=nullptr) const override
Function GetLocalClearance returns any local clearances set in the "classic" (ie: pre-rule) system.
Definition: class_pad.cpp:520
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
void SetBoard(BOARD *aBoard)
bool transferDataToPad(D_PAD *aPad)
Copy values from dialog field to aPad's members.
a fiducial (usually a smd) for the full board
Definition: pad_shapes.h:99
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void OnPadToDieCheckbox(wxCommandEvent &event) override
polygon (not yet used for tracks, but could be in microwave apps)
void SetChamferPositions(int aPositions)
has meaning only for chamfered rect pads set the position of the chamfers for orientation 0.
Definition: class_pad.h:490
void setPadLayersList(LSET layer_mask)
Function setPadLayersList updates the CheckBox states in pad layers list,.
bool IsFlipped() const
Definition: class_pad.cpp:134
int GetPadToDieLength() const
Definition: class_pad.h:338
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
wxFloatingPointValidator< double > m_OrientValidator
PAD_TOOL.
Definition: pad_tool.h:37
const wxString GetValue() const
Function GetValue.
Definition: class_module.h:458
bool SetNetCode(int aNetCode, bool aNoAssert)
Sets net using a net code.
coord_type GetRight() const
Definition: box2.h:198
Smd pad, used in BGA footprints.
Definition: pad_shapes.h:98
GAL * GetGAL() const
Function GetGAL() Returns the GAL this view is using to draw graphical primitives.
Definition: view.h:180
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:156
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
int GetSelectedNetcode()
const NETINFO_LIST & GetNetInfo() const
Definition: class_board.h:739
void onChangePadMode(wxCommandEvent &event) override
usual segment : line with rounded ends
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:226
void NORMALIZE_ANGLE_180(T &Angle)
Definition: trigo.h:354
coord_type GetBottom() const
Definition: box2.h:199
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
a pad used as heat sink, usually in SMD footprints
Definition: pad_shapes.h:102
void SetRoundRectRadiusRatio(double aRadiusScale)
has meaning only for rounded rect pads Set the ratio between the smaller X or Y size and the rounded ...
Definition: class_pad.cpp:178
int GetThermalGap() const
Definition: class_pad.cpp:650
void onCornerSizePercentChange(wxCommandEvent &event) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:114
void SetSketchModeGraphicItems(bool aEnabled)
Turns on/off sketch mode for graphic items (DRAWSEGMENTs, texts).
Definition: pcb_painter.h:151
void SetValue(const wxString &aValue) override
Set a new value in evaluator buffer, and display it in the wxTextCtrl.
PAD_SHAPE_T
Enum PAD_SHAPE_T is the set of pad shapes, used with D_PAD::{Set,Get}Shape()
Definition: pad_shapes.h:33
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:199
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:328
const VC_SETTINGS & GetSettings() const
Returns the current VIEW_CONTROLS settings
This file contains miscellaneous commonly used macros and functions.
bool TransferDataFromWindow() override
Function TransferDataFromWindow Transfer data out of the GUI.
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:433
int GetChamferPositions() const
Definition: class_pad.h:491
a pad with a castellated through hole
Definition: pad_shapes.h:103
static PAD_SHAPE_T code_shape[]
Classes used in Pcbnew, CvPcb and GerbView.
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:131
DIALOG_PAD_PROPERTIES, derived from DIALOG_PAD_PROPERTIES_BASE, created by wxFormBuilder.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Function GetLineThickness Returns the default graphic segment thickness from the layer class for the ...
KIGFX::ORIGIN_VIEWITEM * m_axisOrigin
PCB_RENDER_SETTINGS Stores PCB specific render settings.
Definition: pcb_painter.h:63
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
#define SELECTED
Definition: base_struct.h:124
void onAddPrimitive(wxCommandEvent &event) override
static PAD_ATTR_T code_type[]
void SetAnchorPadShape(PAD_SHAPE_T aShape)
Function SetAnchorPadShape Set the shape of the anchor pad for custm shped pads.
Definition: class_pad.h:195
void OnCancel(wxCommandEvent &event) override
std::string FormatAngle(double aAngle)
Function FormatAngle converts aAngle from board units to a string appropriate for writing to file.
Definition: base_units.cpp:589
void Show(bool aShow, bool aResize=false)
Function Show Shows/hides the label, widget and units label.
virtual const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers.
Definition: class_pad.cpp:1129
LSET is a set of PCB_LAYER_IDs.
pads are covered by copper
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:232
void SetLastPadName(const wxString &aPadName)
Definition: pad_tool.h:74
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
void OnSetLayers(wxCommandEvent &event) override
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void SetName(const wxString &aName)
Set the pad name (sometimes called pad number, although it can be an array reference like AA12).
Definition: class_pad.h:128
const BITMAP_OPAQUE dialog_warning_xpm[1]
SHAPE_POLY_SET.
void SetPos0(const wxPoint &aPos)
Definition: class_pad.h:214
int ShowQuasiModal()
void ListSet(const wxString &aList)
Add a list of items.
Arcs (with rounded ends)
const wxPoint & GetOffset() const
Definition: class_pad.h:230
ZONE_CONNECTION GetZoneConnection() const
Definition: class_pad.h:440
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:320
double GetChamferRectRatio() const
Definition: class_pad.h:483
int GetThermalWidth() const
Definition: class_pad.cpp:639
void Transform(std::vector< std::shared_ptr< DRAWSEGMENT >> *aList=NULL, int aDuplicateCount=0)
Apply geometric transform (rotation, move, scale) defined in dialog aDuplicate = 1 .
void SetLastEditTime(timestamp_t aTime)
Definition: class_module.h:343
LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_pad.h:325
void SetSelectedNetcode(int aNetcode)
Subclass of DIALOG_DISPLAY_HTML_TEXT_BASE, which is generated by wxFormBuilder.
void onCornerRadiusChange(wxCommandEvent &event) override
Class DIALOG_PAD_PROPERTIES_BASE.
void SetDrawAtZero(bool aDrawFlag)
Function SetDrawAtZero() Set the draw at zero flag.
void SetStealsFocus(bool aStealsFocus)
Set whether focus is taken on certain events (mouseover, keys, etc).
void OnResize(wxSizeEvent &event)
void OnPadShapeSelection(wxCommandEvent &event) override
void PadTypeSelected(wxCommandEvent &event) override
static LSET InternalCuMask()
Function InternalCuMask() returns a complete set of internal copper layers, which is all Cu layers ex...
Definition: lset.cpp:672
void SetThermalWidth(int aWidth)
Set the width of the thermal spokes connecting the pad to a zone.
Definition: class_pad.h:453
void onPrimitiveDClick(wxMouseEvent &event) override
Called on a double click on the basic shapes list.
#define BRIGHTENED
item is drawn with a bright contour
Definition: base_struct.h:139
const wxString & GetName() const
Definition: class_pad.h:129
void SetSize(const wxSize &aSize)
Definition: class_pad.h:220
STROKE_T
Enum STROKE_T is the set of shapes for segments (graphic segments and tracks) which are often in the ...
void SetLayerColor(int aLayer, const COLOR4D &aColor)
Function SetLayerColor Changes the color used to draw a layer.
void SetRoundRectCornerRadius(double aRadius)
Function SetRoundRectCornerRadius has meaning only for rounded rect pads.
Definition: class_pad.cpp:169
void OnDrillShapeSelected(wxCommandEvent &event) override
PAD_PROP_T
Enum PAD_PROP_T is the set of pad properties used in Gerber files (Draw files, and P&P files) to defi...
Definition: pad_shapes.h:95
void SetZoneConnection(ZONE_CONNECTION aType)
Definition: class_pad.h:439
PAD_PROP_T GetProperty() const
Definition: class_pad.h:331
void SetNetInfo(NETINFO_LIST *aNetInfoList)
Bezier Curve.
void SetPadToDieLength(int aLength)
Definition: class_pad.h:337
HTML_MESSAGE_BOX.
const wxSize & GetDelta() const
Definition: class_pad.h:224
void onGeometryTransform(wxCommandEvent &event) override
std::vector< std::shared_ptr< DRAWSEGMENT > > m_primitives
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1540
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:82
virtual KIGFX::PCB_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
void SetGridSize(const VECTOR2D &aGridSize)
Set the grid size.
void StartDrawing()
Function StartDrawing() Begins drawing if it was stopped previously.
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: class_pad.cpp:411
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
void UpdateColors()
Updates the color settings in the painter and GAL.
void SetLocalClearance(int aClearance)
Definition: class_pad.h:344
a dialog to edit basic polygonal shape parameters
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:160
ZONE_CONNECTION GetEffectiveZoneConnection() const
Return the zone connection in effect (either locally overridden or overridden in the parent module).
Definition: class_pad.cpp:628
MODULE * GetParent() const
Definition: class_pad.h:108
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: class_pad.h:350
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: class_pad.h:174
std::unique_ptr< typename std::remove_const< T >::type > Clone(const T &aItem)
Definition: pns_item.h:271
void OnPrimitiveSelection(wxListEvent &event) override
Called on selection/deselection of a basic shape.
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType)
Definition: base_units.cpp:124
void SetDrillShape(PAD_DRILL_SHAPE_T aShape)
Definition: class_pad.h:319
EDA_UNITS m_units
Definition: dialog_shim.h:197
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED, bool aUseMils=false)
Function Validate Validates the control against the given range, informing the user of any errors fou...
Use thermal relief for pads.
void onEditPrimitive(wxCommandEvent &event) override
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
bool TransferDataFromWindow() override
Updates the different parameters for the component being edited.
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:324
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:301
virtual void Rotate(const wxPoint &aRotCentre, double aAngle) override
Function Rotate Rotate this object.
void PadOrientEvent(wxCommandEvent &event) override
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:48
smd pads, front layer
a fiducial (usually a smd) local to the parent footprint
Definition: pad_shapes.h:100
bool IsType(FRAME_T aType) const
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
static const LSET std_pad_layers[]
void onDeletePrimitive(wxCommandEvent &event) override
Event handlers of basic shapes list panel.
void onDuplicatePrimitive(wxCommandEvent &event) override
void SetLocalSolderMaskMargin(int aMargin)
Definition: class_pad.h:341
#define _(s)
Definition: 3d_actions.cpp:33
void SetSketchMode(int aItemLayer, bool aEnabled)
Function SetSketchMode Turns on/off sketch mode for given item layer.
Definition: pcb_painter.h:131
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees,...
Definition: class_pad.h:315
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
const wxSize & GetDrillSize() const
Definition: class_pad.h:227
D_PAD m_Pad_Master
A dummy pad to store all default parameters.
PCB_DRAW_PANEL_GAL * m_padPreviewGAL
bool IsAperturePad() const
Definition: class_pad.h:335
void OnOffsetCheckbox(wxCommandEvent &event) override
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
Pads are not covered.
void SetShape(PAD_SHAPE_T aShape)
Set the new shape of this pad.
Definition: class_pad.h:145
void SetGridVisibility(bool aVisibility)
Sets the visibility setting of the grid.
#define SELECTED_ITEMS_LAYER
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
int GetRoundRectCornerRadius() const
Definition: class_pad.cpp:163
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:430
double GetRoundRectRadiusRatio() const
Definition: class_pad.h:475
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:233
bool padValuesOK()
test if all values are acceptable for the pad
void SetChamferRectRatio(double aChamferScale)
has meaning only for chamfered rect pads Set the ratio between the smaller X or Y size and chamfered ...
Definition: class_pad.cpp:186
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers of advanced config.
void SetLocalSolderPasteMargin(int aMargin)
Definition: class_pad.h:347
static LSET ConnSMDMask()
layer set for a SMD pad on Front layer used for edge board connectors
Definition: class_pad.cpp:113
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: class_pad.h:184
void SetPrimitives(const std::vector< std::shared_ptr< DRAWSEGMENT >> &aPrimitivesList)
Import to the basic shape list.
void InstallPadOptionsFrame(D_PAD *pad)
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:346
wxPoint GetPosition() const override
Definition: class_module.h:206
const Vec & GetSize() const
Definition: box2.h:188
PAD_SHAPE_T GetShape() const
Definition: class_pad.h:154
coord_type GetLeft() const
Definition: box2.h:202
static LSET ApertureMask()
layer set for an aperture pad
Definition: class_pad.cpp:127
BOARD * GetBoard() const
VIEW.
Definition: view.h:61
const std::vector< std::shared_ptr< DRAWSEGMENT > > & GetPrimitives() const
Accessor to the basic shape list.
Definition: class_pad.h:270
void SetBoundary(const BOX2D &aBoundary)
Function SetBoundary() Sets limits for view area.
Definition: view.h:267
const wxSize & GetSize() const
Definition: class_pad.h:221
void SetProperty(PAD_PROP_T aProperty)
Definition: class_pad.cpp:422
int GetLocalSolderPasteMargin() const
Definition: class_pad.h:346
std::vector< DRAWSEGMENT * > m_highlight
void SetOffset(const wxPoint &aOffset)
Definition: class_pad.h:229
a test point pad
Definition: pad_shapes.h:101
A dialog to apply geometry transforms to a shape or set of shapes (move, rotate around origin,...
void SetThermalGap(int aGap)
Definition: class_pad.h:456
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:476
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils, EDA_DATA_TYPE aType)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:233
PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
void DeletePrimitivesList()
clear the basic shapes list
void StopDrawing()
Function StopDrawing() Prevents the GAL canvas from further drawing till it is recreated or StartDraw...
void Enable(bool aEnable)
Function Enable Enables/diasables the label, widget and units label.
a dialog to edit basics shapes parameters.
double GetLocalSolderPasteMarginRatio() const
Definition: class_pad.h:349
#define DO_NOT_DRAW
Used to disable draw function.
Definition: base_struct.h:129
bool TransferDataFromWindow() override
Function TransferDataFromWindow Transfer data out of the GUI.
void SetDelta(const wxSize &aSize)
Definition: class_pad.h:223
void OnUpdateUI(wxUpdateUIEvent &event) override
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:99
virtual void ChangeValue(int aValue)
Function ChangeValue Changes the value (in Internal Units) for the text field, taking care of units c...
void SetWidth(int aWidth)