KiCad PCB EDA Suite
pad_tool.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) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include "pad_tool.h"
26 #include <macros.h>
27 #include <class_draw_panel_gal.h>
28 #include <view/view_controls.h>
29 #include <tool/tool_manager.h>
30 #include <board_design_settings.h>
31 #include <board_item.h>
32 #include <footprint.h>
33 #include <fp_shape.h>
34 #include <pad.h>
35 #include <pcbnew_settings.h>
36 #include <board_commit.h>
38 #include <tools/pcb_actions.h>
39 #include <tools/pcb_grid_helper.h>
42 #include <tools/edit_tool.h>
44 #include <widgets/infobar.h>
45 
47  PCB_TOOL_BASE( "pcbnew.PadTool" ),
48  m_wasHighContrast( false ),
49  m_editPad( niluuid )
50 {}
51 
52 
54 {}
55 
56 
58 {
59  if( aReason == MODEL_RELOAD )
60  m_lastPadNumber = wxT( "1" );
61 
62  if( m_editPad != niluuid )
63  {
65  bool highContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
66 
67  if( m_wasHighContrast != highContrast )
69 
70  frame()->GetInfoBar()->Dismiss();
71  }
72 
74 }
75 
76 
78 {
80 
81  if( selTool )
82  {
83  // Add context menu entries that are displayed when selection tool is active
84  CONDITIONAL_MENU& menu = selTool->GetToolMenu().GetMenu();
85 
89 
90  auto explodeCondition =
91  [&]( const SELECTION& aSel )
92  {
93  return m_editPad == niluuid && aSel.Size() == 1 && aSel[0]->Type() == PCB_PAD_T;
94  };
95 
96  auto recombineCondition =
97  [&]( const SELECTION& aSel )
98  {
99  return m_editPad != niluuid;
100  };
101 
102  menu.AddSeparator( 400 );
103 
104  if( m_isFootprintEditor )
105  {
107  menu.AddItem( PCB_ACTIONS::recombinePad, recombineCondition, 400 );
108  menu.AddItem( PCB_ACTIONS::explodePad, explodeCondition, 400 );
109  }
110 
111  menu.AddItem( PCB_ACTIONS::copyPadSettings, singlePadSel, 400 );
112  menu.AddItem( PCB_ACTIONS::applyPadSettings, padSel, 400 );
113  menu.AddItem( PCB_ACTIONS::pushPadSettings, singlePadSel, 400 );
114  }
115 
116  auto& ctxMenu = m_menu.GetMenu();
117 
118  // cancel current tool goes in main context menu at the top if present
120  ctxMenu.AddSeparator( 1 );
121 
127 
128  // Finally, add the standard zoom/grid items
129  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
130 
131  return true;
132 }
133 
134 
136 {
138  const PCB_SELECTION& selection = selTool->GetSelection();
139  const PAD* masterPad = frame()->GetDesignSettings().m_Pad_Master.get();
140 
141  BOARD_COMMIT commit( frame() );
142 
143  // for every selected pad, paste global settings
144  for( EDA_ITEM* item : selection )
145  {
146  if( item->Type() == PCB_PAD_T )
147  {
148  commit.Modify( item );
149  static_cast<PAD&>( *item ).ImportSettingsFrom( *masterPad );
150  }
151  }
152 
153  commit.Push( _( "Paste Pad Properties" ) );
154 
156  frame()->Refresh();
157 
158  return 0;
159 }
160 
161 
163 {
165  const PCB_SELECTION& selection = selTool->GetSelection();
166 
167  // can only copy from a single pad
168  if( selection.Size() == 1 )
169  {
170  EDA_ITEM* item = selection[0];
171 
172  if( item->Type() == PCB_PAD_T )
173  {
174  const PAD& selPad = static_cast<const PAD&>( *item );
175  frame()->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( selPad );
176  }
177  }
178 
179  return 0;
180 }
181 
182 
183 static void doPushPadProperties( BOARD& board, const PAD& aSrcPad, BOARD_COMMIT& commit,
184  bool aSameFootprints,
185  bool aPadShapeFilter,
186  bool aPadOrientFilter,
187  bool aPadLayerFilter,
188  bool aPadTypeFilter )
189 {
190  const FOOTPRINT* refFootprint = aSrcPad.GetParent();
191 
192  double pad_orient = aSrcPad.GetOrientation() - refFootprint->GetOrientation();
193 
194  for( FOOTPRINT* footprint : board.Footprints() )
195  {
196  if( !aSameFootprints && ( footprint != refFootprint ) )
197  continue;
198 
199  if( footprint->GetFPID() != refFootprint->GetFPID() )
200  continue;
201 
202  for( auto pad : footprint->Pads() )
203  {
204  if( aPadShapeFilter && ( pad->GetShape() != aSrcPad.GetShape() ) )
205  continue;
206 
207  double currpad_orient = pad->GetOrientation() - footprint->GetOrientation();
208 
209  if( aPadOrientFilter && ( currpad_orient != pad_orient ) )
210  continue;
211 
212  if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) )
213  continue;
214 
215  if( aPadTypeFilter && ( pad->GetAttribute() != aSrcPad.GetAttribute() ) )
216  continue;
217 
218  // Special-case for aperture pads
219  if( aPadTypeFilter && pad->GetAttribute() == PAD_ATTRIB::CONN )
220  {
221  if( pad->IsAperturePad() != aSrcPad.IsAperturePad() )
222  continue;
223  }
224 
225  commit.Modify( pad );
226 
227  // Apply source pad settings to this pad
228  pad->ImportSettingsFrom( aSrcPad );
229  }
230  }
231 }
232 
233 
235 {
237  const PCB_SELECTION& selection = selTool->GetSelection();
238  PAD* srcPad;
239 
240  if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
241  srcPad = static_cast<PAD*>( selection[0] );
242  else
243  return 0;
244 
245  FOOTPRINT* footprint = srcPad->GetParent();
246 
247  if( !footprint )
248  return 0;
249 
251 
253  int dialogRet = dlg.ShowModal();
254 
255  if( dialogRet == wxID_CANCEL )
256  return 0;
257 
258  const bool edit_Same_Modules = (dialogRet == 1);
259 
260  BOARD_COMMIT commit( frame() );
261 
262  doPushPadProperties( *getModel<BOARD>(), *srcPad, commit, edit_Same_Modules,
267 
268  commit.Push( _( "Push Pad Settings" ) );
269 
271  frame()->Refresh();
272 
273  return 0;
274 }
275 
276 
278 {
279  if( !board()->GetFirstFootprint() || board()->GetFirstFootprint()->Pads().empty() )
280  return 0;
281 
282  GENERAL_COLLECTOR collector;
283  const KICAD_T types[] = { PCB_PAD_T, EOT };
284 
286  guide.SetIgnoreMTextsMarkedNoShow( true );
287  guide.SetIgnoreMTextsOnBack( true );
288  guide.SetIgnoreMTextsOnFront( true );
289  guide.SetIgnoreModulesVals( true );
290  guide.SetIgnoreModulesRefs( true );
291 
292  DIALOG_ENUM_PADS settingsDlg( frame() );
293 
294  if( settingsDlg.ShowModal() != wxID_OK )
295  return 0;
296 
297  int seqPadNum = settingsDlg.GetStartNumber();
298  wxString padPrefix = settingsDlg.GetPrefix();
299  std::deque<int> storedPadNumbers;
300  std::map<wxString, std::pair<int, wxString>> oldNumbers;
301 
303 
304  std::string tool = aEvent.GetCommandStr().get();
305  frame()->PushTool( tool );
306 
307  VECTOR2I oldCursorPos; // store the previous mouse cursor position, during mouse drag
308  std::list<PAD*> selectedPads;
309  BOARD_COMMIT commit( frame() );
310  bool isFirstPoint = true; // make sure oldCursorPos is initialized at least once
311  PADS pads = board()->GetFirstFootprint()->Pads();
312 
313  MAGNETIC_SETTINGS mag_settings;
314  mag_settings.graphics = false;
315  mag_settings.tracks = MAGNETIC_OPTIONS::NO_EFFECT;
316  mag_settings.pads = MAGNETIC_OPTIONS::CAPTURE_ALWAYS;
317  PCB_GRID_HELPER grid( m_toolMgr, &mag_settings );
318 
319  grid.SetSnap( true );
320  grid.SetUseGrid( false );
321 
322  auto setCursor =
323  [&]()
324  {
326  };
327 
328  Activate();
329  // Must be done after Activate() so that it gets set into the correct context
330  getViewControls()->ShowCursor( true );
331  // Set initial cursor
332  setCursor();
333 
334  STATUS_TEXT_POPUP statusPopup( frame() );
335  wxString msg = _( "Click on pad %s%d\nPress <esc> to cancel or double-click to commit" );
336  statusPopup.SetText( wxString::Format( msg, padPrefix, seqPadNum ) );
337  statusPopup.Popup();
338  statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
339 
340  while( TOOL_EVENT* evt = Wait() )
341  {
342  setCursor();
343 
344  VECTOR2I cursorPos = grid.AlignToNearestPad( getViewControls()->GetMousePosition(), pads );
345  getViewControls()->ForceCursorPosition( true, cursorPos );
346 
347  if( evt->IsCancelInteractive() )
348  {
350  commit.Revert();
351 
352  frame()->PopTool( tool );
353  break;
354  }
355  else if( evt->IsActivate() )
356  {
357  commit.Push( _( "Renumber pads" ) );
358 
359  frame()->PopTool( tool );
360  break;
361  }
362  else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
363  {
364  selectedPads.clear();
365 
366  // Be sure the old cursor mouse position was initialized:
367  if( isFirstPoint )
368  {
369  oldCursorPos = cursorPos;
370  isFirstPoint = false;
371  }
372 
373  // wxWidgets deliver mouse move events not frequently enough, resulting in skipping
374  // pads if the user moves cursor too fast. To solve it, create a line that approximates
375  // the mouse move and search pads that are on the line.
376  int distance = ( cursorPos - oldCursorPos ).EuclideanNorm();
377  // Search will be made every 0.1 mm:
378  int segments = distance / int( 0.1*IU_PER_MM ) + 1;
379  const wxPoint line_step( ( cursorPos - oldCursorPos ) / segments );
380 
381  collector.Empty();
382 
383  for( int j = 0; j < segments; ++j )
384  {
385  wxPoint testpoint( cursorPos.x - j * line_step.x, cursorPos.y - j * line_step.y );
386  collector.Collect( board(), types, testpoint, guide );
387 
388  for( int i = 0; i < collector.GetCount(); ++i )
389  selectedPads.push_back( static_cast<PAD*>( collector[i] ) );
390  }
391 
392  selectedPads.unique();
393 
394  for( PAD* pad : selectedPads )
395  {
396  // If pad was not selected, then enumerate it
397  if( !pad->IsSelected() )
398  {
399  commit.Modify( pad );
400 
401  // Rename pad and store the old name
402  int newval;
403 
404  if( storedPadNumbers.size() > 0 )
405  {
406  newval = storedPadNumbers.front();
407  storedPadNumbers.pop_front();
408  }
409  else
410  newval = seqPadNum++;
411 
412  wxString newNumber = wxString::Format( wxT( "%s%d" ), padPrefix, newval );
413  oldNumbers[newNumber] = { newval, pad->GetNumber() };
414  pad->SetNumber( newNumber );
415  SetLastPadNumber( newNumber );
416  pad->SetSelected();
417  getView()->Update( pad );
418 
419  // Ensure the popup text shows the correct next value
420  if( storedPadNumbers.size() > 0 )
421  newval = storedPadNumbers.front();
422  else
423  newval = seqPadNum;
424 
425  statusPopup.SetText( wxString::Format( msg, padPrefix, newval ) );
426  }
427 
428  // ... or restore the old name if it was enumerated and clicked again
429  else if( pad->IsSelected() && evt->IsClick( BUT_LEFT ) )
430  {
431  auto it = oldNumbers.find( pad->GetNumber() );
432  wxASSERT( it != oldNumbers.end() );
433 
434  if( it != oldNumbers.end() )
435  {
436  storedPadNumbers.push_back( it->second.first );
437  pad->SetNumber( it->second.second );
438  SetLastPadNumber( it->second.second );
439  oldNumbers.erase( it );
440 
441  int newval = storedPadNumbers.front();
442 
443  statusPopup.SetText( wxString::Format( msg, padPrefix, newval ) );
444  }
445 
446  pad->ClearSelected();
447  getView()->Update( pad );
448  }
449  }
450  }
451  else if( ( evt->IsKeyPressed() && evt->KeyCode() == WXK_RETURN ) ||
452  evt->IsDblClick( BUT_LEFT ) )
453  {
454  commit.Push( _( "Renumber pads" ) );
455  frame()->PopTool( tool );
456  break;
457  }
458  else if( evt->IsClick( BUT_RIGHT ) )
459  {
461  }
462  else
463  {
464  evt->SetPassEvent();
465  }
466 
467  // Prepare the next loop by updating the old cursor mouse position
468  // to this last mouse cursor position
469  oldCursorPos = getViewControls()->GetCursorPosition();
470  statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
471  }
472 
473  for( PAD* p : board()->GetFirstFootprint()->Pads() )
474  {
475  p->ClearSelected();
476  getView()->Update( p );
477  }
478 
479  statusPopup.Hide();
481  return 0;
482 }
483 
484 
485 int PAD_TOOL::PlacePad( const TOOL_EVENT& aEvent )
486 {
487  if( !board()->GetFirstFootprint() )
488  return 0;
489 
490  struct PAD_PLACER : public INTERACTIVE_PLACER_BASE
491  {
492  PAD_PLACER( PAD_TOOL* aPadTool )
493  {
494  m_padTool = aPadTool;
495  }
496 
497  virtual ~PAD_PLACER()
498  {
499  }
500 
501  std::unique_ptr<BOARD_ITEM> CreateItem() override
502  {
503  PAD* pad = new PAD( m_board->GetFirstFootprint() );
504  PAD* master = m_frame->GetDesignSettings().m_Pad_Master.get();
505 
506  pad->ImportSettingsFrom( *master );
507 
508  // If the footprint type and master pad type directly conflict then make some
509  // adjustments. Otherwise assume the user set what they wanted.
510  if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_SMD )
511  && master->GetAttribute() == PAD_ATTRIB::PTH )
512  {
513  pad->SetAttribute( PAD_ATTRIB::SMD );
514  pad->SetShape( PAD_SHAPE::ROUNDRECT );
515  pad->SetSizeX( 1.5 * pad->GetSizeY() );
516  pad->SetLayerSet( PAD::SMDMask() );
517  }
518  else if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_THROUGH_HOLE )
519  && master->GetAttribute() == PAD_ATTRIB::SMD )
520  {
521  pad->SetAttribute( PAD_ATTRIB::PTH );
522  pad->SetShape( PAD_SHAPE::CIRCLE );
523  pad->SetSize( wxSize( pad->GetSizeX(), pad->GetSizeX() ) );
524  pad->SetLayerSet( PAD::PTHMask() );
525  }
526 
527  if( pad->CanHaveNumber() )
528  {
529  wxString padNumber = m_padTool->GetLastPadNumber();
530  padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
531  pad->SetNumber( padNumber );
532  m_padTool->SetLastPadNumber( padNumber );
533  }
534 
535  return std::unique_ptr<BOARD_ITEM>( pad );
536  }
537 
538  bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
539  {
540  PAD* pad = dynamic_cast<PAD*>( aItem );
541 
542  if( pad )
543  {
544  m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
545  pad->SetLocalCoord();
546  aCommit.Add( aItem );
547  return true;
548  }
549 
550  return false;
551  }
552 
553  PAD_TOOL* m_padTool;
554  };
555 
556  PAD_PLACER placer( this );
557 
558  doInteractiveItemPlacement( aEvent.GetCommandStr().get(), &placer, _( "Place pad" ),
560 
561  return 0;
562 }
563 
564 
565 int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
566 {
568  WX_INFOBAR* infoBar = frame()->GetInfoBar();
570  wxString msg;
571 
572  if( m_editPad != niluuid )
573  {
574  PAD* pad = dynamic_cast<PAD*>( frame()->GetItem( m_editPad ) );
575 
576  if( pad )
577  recombinePad( pad );
578 
579  m_editPad = niluuid;
580  }
581  else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
582  {
583  PAD* pad = static_cast<PAD*>( selection[0] );
584  PCB_LAYER_ID layer = explodePad( pad );
585 
587  frame()->SetActiveLayer( layer );
588 
589  if( !m_wasHighContrast )
591 
592  if( PCB_ACTIONS::explodePad.GetHotKey() == PCB_ACTIONS::recombinePad.GetHotKey() )
593  {
594  msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
596 
597  else
598  {
599  msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
601  }
602 
603  infoBar->RemoveAllButtons();
604  infoBar->ShowMessage( msg, wxICON_INFORMATION );
605 
606  m_editPad = pad->m_Uuid;
607  }
608 
609  if( m_editPad == niluuid )
610  {
611  bool highContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
612 
613  if( m_wasHighContrast != highContrast )
615 
616  infoBar->Dismiss();
617  }
618 
619  return 0;
620 }
621 
622 
624 {
625  PCB_LAYER_ID layer;
626  BOARD_COMMIT commit( frame() );
627 
628  if( aPad->IsOnLayer( F_Cu ) )
629  layer = F_Cu;
630  else if( aPad->IsOnLayer( B_Cu ) )
631  layer = B_Cu;
632  else
633  layer = *aPad->GetLayerSet().UIOrder();
634 
635  if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
636  {
637  commit.Modify( aPad );
638 
639  for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives() )
640  {
641  FP_SHAPE* shape = new FP_SHAPE( board()->GetFirstFootprint() );
642 
643  shape->SetShape( primitive->GetShape() );
644  shape->SetFilled( primitive->IsFilled() );
645  shape->SetWidth( primitive->GetWidth() );
646 
647  switch( shape->GetShape() )
648  {
649  case SHAPE_T::SEGMENT:
650  case SHAPE_T::RECT:
651  case SHAPE_T::CIRCLE:
652  shape->SetStart( primitive->GetStart() );
653  shape->SetEnd( primitive->GetEnd() );
654  break;
655 
656  case SHAPE_T::ARC:
657  shape->SetStart( primitive->GetStart() );
658  shape->SetEnd( primitive->GetEnd() );
659  shape->SetCenter( primitive->GetCenter() );
660  break;
661 
662  case SHAPE_T::BEZIER:
663  shape->SetStart( primitive->GetStart() );
664  shape->SetEnd( primitive->GetEnd() );
665  shape->SetBezierC1( primitive->GetBezierC1() );
666  shape->SetBezierC2( primitive->GetBezierC2() );
667  break;
668 
669  case SHAPE_T::POLY:
670  shape->SetPolyShape( primitive->GetPolyShape() );
671  break;
672 
673  default:
675  }
676 
677  shape->SetLocalCoord();
678  shape->Move( aPad->GetPosition() );
679  shape->Rotate( aPad->GetPosition(), aPad->GetOrientation() );
680  shape->SetLayer( layer );
681 
682  commit.Add( shape );
683  }
684 
685  aPad->SetShape( aPad->GetAnchorPadShape() );
686  aPad->DeletePrimitivesList();
687  m_editPad = aPad->m_Uuid;
688  }
689 
690  commit.Push( _("Edit pad shapes") );
692  return layer;
693 }
694 
695 
697 {
698  int maxError = board()->GetDesignSettings().m_MaxError;
699 
700  // Don't leave an object in the point editor that might no longer exist after
701  // recombining the pad.
703 
704  auto findNext =
705  [&]( PCB_LAYER_ID aLayer ) -> FP_SHAPE*
706  {
707  SHAPE_POLY_SET padPoly;
708  aPad->TransformShapeWithClearanceToPolygon( padPoly, aLayer, 0, maxError,
709  ERROR_INSIDE );
710 
711  for( BOARD_ITEM* item : board()->GetFirstFootprint()->GraphicalItems() )
712  {
713  PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( item );
714 
715  if( !shape || ( shape->GetEditFlags() & STRUCT_DELETED ) )
716  continue;
717 
718  if( shape->GetLayer() != aLayer )
719  continue;
720 
721  SHAPE_POLY_SET drawPoly;
722  shape->TransformShapeWithClearanceToPolygon( drawPoly, aLayer, 0, maxError,
723  ERROR_INSIDE );
724  drawPoly.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST );
725 
726  if( !drawPoly.IsEmpty() )
727  return (FP_SHAPE*) item;
728  }
729 
730  return nullptr;
731  };
732 
733  BOARD_COMMIT commit( frame() );
734  PCB_LAYER_ID layer;
735 
736  if( aPad->IsOnLayer( F_Cu ) )
737  layer = F_Cu;
738  else if( aPad->IsOnLayer( B_Cu ) )
739  layer = B_Cu;
740  else
741  layer = *aPad->GetLayerSet().UIOrder();
742 
743  while( FP_SHAPE* fpShape = findNext( layer ) )
744  {
745  commit.Modify( aPad );
746 
747  // We've found an intersecting item. First convert the pad to a custom-shape
748  // pad (if it isn't already)
749  //
750  if( aPad->GetShape() == PAD_SHAPE::RECT || aPad->GetShape() == PAD_SHAPE::CIRCLE )
751  {
752  aPad->SetAnchorPadShape( aPad->GetShape() );
753  }
754  else if( aPad->GetShape() != PAD_SHAPE::CUSTOM )
755  {
756  // Create a new minimally-sized circular anchor and convert existing pad
757  // to a polygon primitive
758  SHAPE_POLY_SET existingOutline;
759  aPad->TransformShapeWithClearanceToPolygon( existingOutline, layer, 0, maxError,
760  ERROR_INSIDE );
761 
763  if( aPad->GetSizeX() > aPad->GetSizeY() )
764  aPad->SetSizeX( aPad->GetSizeY() );
765 
766  aPad->SetOffset( wxPoint( 0, 0 ) );
767 
768  PCB_SHAPE* shape = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
769  shape->SetFilled( true );
770  shape->SetWidth( 0 );
771  shape->SetPolyShape( existingOutline );
772  shape->Move( - aPad->GetPosition() );
773  shape->Rotate( wxPoint( 0, 0 ), - aPad->GetOrientation() );
774 
775  aPad->AddPrimitive( shape );
776  }
777 
778  aPad->SetShape( PAD_SHAPE::CUSTOM );
779 
780  // Now add the new shape to the primitives list
781  //
782  PCB_SHAPE* pcbShape = new PCB_SHAPE;
783 
784  pcbShape->SetShape( fpShape->GetShape() );
785  pcbShape->SetFilled( fpShape->IsFilled() );
786  pcbShape->SetWidth( fpShape->GetWidth() );
787 
788 
789  switch( pcbShape->GetShape() )
790  {
791  case SHAPE_T::SEGMENT:
792  case SHAPE_T::RECT:
793  case SHAPE_T::CIRCLE:
794  pcbShape->SetStart( fpShape->GetStart() );
795  pcbShape->SetEnd( fpShape->GetEnd() );
796  break;
797 
798  case SHAPE_T::ARC:
799  pcbShape->SetStart( fpShape->GetStart() );
800  pcbShape->SetEnd( fpShape->GetEnd() );
801  pcbShape->SetCenter( fpShape->GetCenter() );
802  break;
803 
804  case SHAPE_T::BEZIER:
805  pcbShape->SetStart( fpShape->GetStart() );
806  pcbShape->SetEnd( fpShape->GetEnd() );
807  pcbShape->SetBezierC1( fpShape->GetBezierC1() );
808  pcbShape->SetBezierC2( fpShape->GetBezierC2() );
809  break;
810 
811  case SHAPE_T::POLY:
812  pcbShape->SetPolyShape( fpShape->GetPolyShape() );
813  break;
814 
815  default:
816  UNIMPLEMENTED_FOR( pcbShape->SHAPE_T_asString() );
817  }
818 
819  pcbShape->Move( - aPad->GetPosition() );
820  pcbShape->Rotate( wxPoint( 0, 0 ), - aPad->GetOrientation() );
821  aPad->AddPrimitive( pcbShape );
822 
823  fpShape->SetFlags( STRUCT_DELETED );
824  commit.Remove( fpShape );
825  }
826 
827  commit.Push( _( "Recombine pads" ) );
828 }
829 
830 
832 {
836 
839 
842 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
void Empty()
Clear the list.
Definition: collector.h:90
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: infobar.cpp:142
void SetOffset(const wxPoint &aOffset)
Definition: pad.h:249
void SetLastPadNumber(const wxString &aPadNumber)
Definition: pad_tool.h:65
const int GetSizeY() const
Definition: pad.h:237
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
static TOOL_ACTION explodePad
Definition: pcb_actions.h:383
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
KIID niluuid(0)
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
static PCB_SHAPE * findNext(PCB_SHAPE *aShape, const wxPoint &aPoint, const std::vector< PCB_SHAPE * > &aList, unsigned aLimit)
Searches for a PCB_SHAPE matching a given end point or start point in a list.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
Handle flip action in the loop by calling the item's flip method.
BOARD * board() const
void SetFilled(bool aFlag)
Definition: eda_shape.h:92
KIID m_editPad
Definition: pad_tool.h:86
void SetEnd(const wxPoint &aEnd)
Definition: eda_shape.h:135
Model changes (required full reload)
Definition: tool_base.h:80
void DeletePrimitivesList()
Clear the basic shapes list.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:164
static void doPushPadProperties(BOARD &board, const PAD &aSrcPad, BOARD_COMMIT &commit, bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter, bool aPadLayerFilter, bool aPadTypeFilter)
Definition: pad_tool.cpp:183
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
static constexpr double IU_PER_MM
Mock up a conversion function.
void Collect(BOARD_ITEM *aItem, const KICAD_T aScanList[], const wxPoint &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:571
void SetIgnoreModulesVals(bool ignore)
Definition: collectors.h:547
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:235
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:79
virtual void Revert() override
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
PAD_TOOL()
Definition: pad_tool.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
bool IsEmpty() const
static TOOL_ACTION enumeratePads
Tool for quick pad enumeration.
Definition: pcb_actions.h:387
Like smd, does not appear on the solder paste layer (default)
Smd pad, appears on the solder paste layer (default)
static TOOL_ACTION cancelInteractive
Definition: actions.h:62
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:117
Tool relating to pads and pad settings.
Definition: pad_tool.h:35
double GetOrientation() const
Definition: footprint.h:191
TOOL_MENU & GetToolMenu()
void SetIgnoreModulesRefs(bool ignore)
Definition: collectors.h:553
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:568
void SetSizeX(const int aX)
Definition: pad.h:234
static SELECTION_CONDITION HasType(KICAD_T aType)
Create a functor that tests if among the selected items there is at least one of a given type.
static TOOL_ACTION placePad
Activation of the drawing tool (placing a PAD)
Definition: pcb_actions.h:381
static TOOL_ACTION mirror
Mirroring of selected items.
Definition: pcb_actions.h:108
class PAD, a pad in a footprint
Definition: typeinfo.h:89
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
virtual void Rotate(const wxPoint &aRotCentre, double aAngle) override
Rotate this object.
Definition: pcb_shape.cpp:109
bool IsAperturePad() const
Definition: pad.h:378
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
void Reset(RESET_REASON aReason) override
Basic initialization.
Definition: pad_tool.cpp:57
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
std::unique_ptr< PAD > m_Pad_Master
search types array terminator (End Of Types)
Definition: typeinfo.h:81
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:205
void SetBezierC1(const wxPoint &aPt)
Definition: eda_shape.h:153
PADS & Pads()
Definition: footprint.h:169
Plated through hole pad.
This file contains miscellaneous commonly used macros and functions.
void SetStart(const wxPoint &aStart)
Definition: eda_shape.h:110
PCB_BASE_EDIT_FRAME * frame() const
static TOOL_ACTION pushPadSettings
Copy the current pad's settings to other pads in the footprint or on the board.
Definition: pcb_actions.h:407
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:82
PCB_SELECTION & GetSelection()
Return the set of currently selected items.
virtual void Move(const wxPoint &aMoveVector) override
Move this object.
Definition: pcb_shape.cpp:97
Container for display options like enable/disable some optional drawings.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:175
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
static TOOL_ACTION rotateCw
Rotation of selected objects.
Definition: pcb_actions.h:101
bool m_wasHighContrast
Definition: pad_tool.h:85
const PCB_SELECTION & selection() const
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:318
wxString m_lastPadNumber
Definition: pad_tool.h:83
double GetOrientation() const
Return the rotation angle of the pad in a variety of units (the basic call returns tenths of degrees)...
Definition: pad.h:349
int pushPadSettings(const TOOL_EVENT &aEvent)
Definition: pad_tool.cpp:234
void SetIgnoreMTextsOnBack(bool ignore)
Definition: collectors.h:505
static TOOL_ACTION copyPadSettings
Copy the selected pad's settings to the board design settings.
Definition: pcb_actions.h:401
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
Allow repeat placement of the item.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
Represent a set of closed polygons.
virtual void PopTool(const std::string &actionName)
void SetIgnoreMTextsOnFront(bool ignore)
Definition: collectors.h:511
void Rotate(const wxPoint &aRotCentre, double aAngle) override
Rotate an edge of the footprint.
Definition: fp_shape.cpp:343
FOOTPRINTS & Footprints()
Definition: board.h:234
Generic, UI-independent tool event.
Definition: tool_event.h:152
Inactive layers are shown normally (no high-contrast mode)
wxString GetPrefix() const
static TOOL_ACTION applyPadSettings
Copy the default pad settings to the selected pad.
Definition: pcb_actions.h:404
int pastePadProperties(const TOOL_EVENT &aEvent)
Copy pad settings from a pad to the board design settings.
Definition: pad_tool.cpp:135
FOOTPRINT * footprint() const
static TOOL_ACTION recombinePad
Definition: pcb_actions.h:384
static LSET PTHMask()
layer set for a through hole pad
Definition: pad.cpp:159
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
PAD_SHAPE GetShape() const
Definition: pad.h:170
#define STRUCT_DELETED
flag indication structures to be erased
#define _(s)
virtual void Popup(wxWindow *aFocus=nullptr)
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
void SetWidth(int aWidth)
Definition: eda_shape.h:97
const LIB_ID & GetFPID() const
Definition: footprint.h:195
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:368
COMMIT & Remove(EDA_ITEM *aItem)
Notify observers that aItem has been removed.
Definition: commit.h:90
std::function< bool(const SELECTION &)> SELECTION_CONDITION
< Functor type that checks a specific condition for selected items.
Create an item immediately on placement starting, otherwise show the pencil cursor until the item is ...
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:157
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
virtual void Move(const wxPoint &aWhere)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
void SetCenter(const wxPoint &aCenter)
Definition: eda_shape.cpp:419
void SetIgnoreMTextsMarkedNoShow(bool ignore)
Definition: collectors.h:499
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:71
int EnumeratePads(const TOOL_EVENT &aEvent)
Tool for quick pad enumeration.
Definition: pad_tool.cpp:277
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
bool m_isFootprintEditor
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:286
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
PCB_LAYER_ID explodePad(PAD *aPad)
Definition: pad_tool.cpp:623
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
const KIID m_Uuid
Definition: eda_item.h:474
static TOOL_ACTION rotateCcw
Definition: pcb_actions.h:102
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
FOOTPRINT * GetParent() const
Definition: pad.cpp:1439
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:460
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:105
A modified version of the wxInfoBar class that allows us to:
Definition: infobar.h:73
Handle the rotate action in the loop by calling the item's rotate method.
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition: pad.cpp:1554
wxPoint GetPosition() const override
Definition: pad.h:178
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
PAD_ATTRIB GetAttribute() const
Definition: pad.h:371
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:240
~PAD_TOOL()
React to model/view changes.
Definition: pad_tool.cpp:53
Definition: layer_ids.h:71
static SELECTION_CONDITION OnlyType(KICAD_T aType)
Create a functor that tests if the selected items are only of given type.
MAGNETIC_OPTIONS pads
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:100
const int GetSizeX() const
Definition: pad.h:235
int Size() const
Returns the number of selected parts.
Definition: selection.h:104
void AddPrimitive(PCB_SHAPE *aPrimitive)
Add item to the custom shape primitives list.
The selection tool: currently supports:
static bool empty(const wxTextEntryBase *aCtrl)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
void SetBezierC2(const wxPoint &aPt)
Definition: eda_shape.h:156
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
void Activate()
Run the tool.
void SetShape(PAD_SHAPE aShape)
Set the new shape of this pad.
Definition: pad.h:161
WX_INFOBAR * GetInfoBar()
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
void SetLocalCoord()
Set relative coordinates from draw coordinates.
Definition: fp_shape.cpp:52
int GetStartNumber() const
Return common prefix for all enumerated pads.
void Move(const wxPoint &aMoveVector) override
Move an edge of the footprint.
Definition: fp_shape.cpp:355
SHAPE_T GetShape() const
Definition: eda_shape.h:101
void doInteractiveItemPlacement(const std::string &aTool, INTERACTIVE_PLACER_BASE *aPlacer, const wxString &aCommitMessage, int aOptions=IPO_ROTATE|IPO_FLIP|IPO_REPEAT)
Helper function for performing a common interactive idiom: wait for a left click, place an item there...
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
void recombinePad(PAD *aPad)
Definition: pad_tool.cpp:696
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition: pad_tool.cpp:565
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:377
Definition: pad.h:57
bool Init() override
Init() is called once upon a registration of the tool.
Definition: pad_tool.cpp:77
int PlacePad(const TOOL_EVENT &aEvent)
Place a pad in footprint editor.
Definition: pad_tool.cpp:485
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
Definition: pcb_shape.cpp:236
LSEQ UIOrder() const
Definition: lset.cpp:904
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pad.cpp:166
static TOOL_ACTION highContrastMode
Definition: actions.h:103
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:143
void setTransitions() override
< Bind handlers to corresponding TOOL_ACTIONs.
Definition: pad_tool.cpp:831
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:59
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:301
PAD_SHAPE GetAnchorPadShape() const
Definition: pad.h:183
void SetText(const wxString &aText)
Display a text.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
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:1570
MAGNETIC_OPTIONS tracks
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
int copyPadSettings(const TOOL_EVENT &aEvent)
Push pad settings from a pad to other pads on board or footprint.
Definition: pad_tool.cpp:162
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:209