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 
63 }
64 
65 
67 {
69 
70  if( selTool )
71  {
72  // Add context menu entries that are displayed when selection tool is active
73  CONDITIONAL_MENU& menu = selTool->GetToolMenu().GetMenu();
74 
78 
79  auto explodeCondition =
80  [&]( const SELECTION& aSel )
81  {
82  return m_editPad == niluuid && aSel.Size() == 1 && aSel[0]->Type() == PCB_PAD_T;
83  };
84 
85  auto recombineCondition =
86  [&]( const SELECTION& aSel )
87  {
88  return m_editPad != niluuid;
89  };
90 
91  menu.AddSeparator( 400 );
92 
94  {
96  menu.AddItem( PCB_ACTIONS::recombinePad, recombineCondition, 400 );
97  menu.AddItem( PCB_ACTIONS::explodePad, explodeCondition, 400 );
98  }
99 
100  menu.AddItem( PCB_ACTIONS::copyPadSettings, singlePadSel, 400 );
101  menu.AddItem( PCB_ACTIONS::applyPadSettings, padSel, 400 );
102  menu.AddItem( PCB_ACTIONS::pushPadSettings, singlePadSel, 400 );
103  }
104 
105  auto& ctxMenu = m_menu.GetMenu();
106 
107  // cancel current tool goes in main context menu at the top if present
109  ctxMenu.AddSeparator( 1 );
110 
116 
117  // Finally, add the standard zoom/grid items
118  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
119 
120  return true;
121 }
122 
123 
125 {
127  const PCB_SELECTION& selection = selTool->GetSelection();
128  const PAD* masterPad = frame()->GetDesignSettings().m_Pad_Master.get();
129 
130  BOARD_COMMIT commit( frame() );
131 
132  // for every selected pad, paste global settings
133  for( EDA_ITEM* item : selection )
134  {
135  if( item->Type() == PCB_PAD_T )
136  {
137  commit.Modify( item );
138  static_cast<PAD&>( *item ).ImportSettingsFrom( *masterPad );
139  }
140  }
141 
142  commit.Push( _( "Paste Pad Properties" ) );
143 
145  frame()->Refresh();
146 
147  return 0;
148 }
149 
150 
152 {
154  const PCB_SELECTION& selection = selTool->GetSelection();
155 
156  // can only copy from a single pad
157  if( selection.Size() == 1 )
158  {
159  EDA_ITEM* item = selection[0];
160 
161  if( item->Type() == PCB_PAD_T )
162  {
163  const PAD& selPad = static_cast<const PAD&>( *item );
164  frame()->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( selPad );
165  }
166  }
167 
168  return 0;
169 }
170 
171 
172 static void doPushPadProperties( BOARD& board, const PAD& aSrcPad, BOARD_COMMIT& commit,
173  bool aSameFootprints,
174  bool aPadShapeFilter,
175  bool aPadOrientFilter,
176  bool aPadLayerFilter,
177  bool aPadTypeFilter )
178 {
179  const FOOTPRINT* refFootprint = aSrcPad.GetParent();
180 
181  double pad_orient = aSrcPad.GetOrientation() - refFootprint->GetOrientation();
182 
183  for( FOOTPRINT* footprint : board.Footprints() )
184  {
185  if( !aSameFootprints && ( footprint != refFootprint ) )
186  continue;
187 
188  if( footprint->GetFPID() != refFootprint->GetFPID() )
189  continue;
190 
191  for( auto pad : footprint->Pads() )
192  {
193  if( aPadShapeFilter && ( pad->GetShape() != aSrcPad.GetShape() ) )
194  continue;
195 
196  double currpad_orient = pad->GetOrientation() - footprint->GetOrientation();
197 
198  if( aPadOrientFilter && ( currpad_orient != pad_orient ) )
199  continue;
200 
201  if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) )
202  continue;
203 
204  if( aPadTypeFilter && ( pad->GetAttribute() != aSrcPad.GetAttribute() ) )
205  continue;
206 
207  // Special-case for aperture pads
208  if( aPadTypeFilter && pad->GetAttribute() == PAD_ATTRIB::CONN )
209  {
210  if( pad->IsAperturePad() != aSrcPad.IsAperturePad() )
211  continue;
212  }
213 
214  commit.Modify( pad );
215 
216  // Apply source pad settings to this pad
217  pad->ImportSettingsFrom( aSrcPad );
218  }
219  }
220 }
221 
222 
224 {
226  const PCB_SELECTION& selection = selTool->GetSelection();
227  PAD* srcPad;
228 
229  if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
230  srcPad = static_cast<PAD*>( selection[0] );
231  else
232  return 0;
233 
234  FOOTPRINT* footprint = srcPad->GetParent();
235 
236  if( !footprint )
237  return 0;
238 
240 
242  int dialogRet = dlg.ShowModal();
243 
244  if( dialogRet == wxID_CANCEL )
245  return 0;
246 
247  const bool edit_Same_Modules = (dialogRet == 1);
248 
249  BOARD_COMMIT commit( frame() );
250 
251  doPushPadProperties( *getModel<BOARD>(), *srcPad, commit, edit_Same_Modules,
256 
257  commit.Push( _( "Push Pad Settings" ) );
258 
260  frame()->Refresh();
261 
262  return 0;
263 }
264 
265 
267 {
268  if( !board()->GetFirstFootprint() || board()->GetFirstFootprint()->Pads().empty() )
269  return 0;
270 
271  GENERAL_COLLECTOR collector;
272  const KICAD_T types[] = { PCB_PAD_T, EOT };
273 
275  guide.SetIgnoreMTextsMarkedNoShow( true );
276  guide.SetIgnoreMTextsOnBack( true );
277  guide.SetIgnoreMTextsOnFront( true );
278  guide.SetIgnoreModulesVals( true );
279  guide.SetIgnoreModulesRefs( true );
280 
281  DIALOG_ENUM_PADS settingsDlg( frame() );
282 
283  if( settingsDlg.ShowModal() != wxID_OK )
284  return 0;
285 
286  int seqPadNum = settingsDlg.GetStartNumber();
287  wxString padPrefix = settingsDlg.GetPrefix();
288  std::deque<int> storedPadNumbers;
289  std::map<wxString, std::pair<int, wxString>> oldNumbers;
290 
292 
293  std::string tool = aEvent.GetCommandStr().get();
294  frame()->PushTool( tool );
295 
296  VECTOR2I oldCursorPos; // store the previous mouse cursor position, during mouse drag
297  std::list<PAD*> selectedPads;
298  BOARD_COMMIT commit( frame() );
299  bool isFirstPoint = true; // make sure oldCursorPos is initialized at least once
300  PADS pads = board()->GetFirstFootprint()->Pads();
301 
302  MAGNETIC_SETTINGS mag_settings;
303  mag_settings.graphics = false;
304  mag_settings.tracks = MAGNETIC_OPTIONS::NO_EFFECT;
305  mag_settings.pads = MAGNETIC_OPTIONS::CAPTURE_ALWAYS;
306  PCB_GRID_HELPER grid( m_toolMgr, &mag_settings );
307 
308  grid.SetSnap( true );
309  grid.SetUseGrid( false );
310 
311  auto setCursor =
312  [&]()
313  {
315  };
316 
317  Activate();
318  // Must be done after Activate() so that it gets set into the correct context
319  getViewControls()->ShowCursor( true );
320  // Set initial cursor
321  setCursor();
322 
323  STATUS_TEXT_POPUP statusPopup( frame() );
324  wxString msg = _( "Click on pad %s%d\nPress <esc> to cancel or double-click to commit" );
325  statusPopup.SetText( wxString::Format( msg, padPrefix, seqPadNum ) );
326  statusPopup.Popup();
327  statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
328 
329  while( TOOL_EVENT* evt = Wait() )
330  {
331  setCursor();
332 
333  VECTOR2I cursorPos = grid.AlignToNearestPad( getViewControls()->GetMousePosition(), pads );
334  getViewControls()->ForceCursorPosition( true, cursorPos );
335 
336  if( evt->IsCancelInteractive() )
337  {
339  commit.Revert();
340 
341  frame()->PopTool( tool );
342  break;
343  }
344  else if( evt->IsActivate() )
345  {
346  commit.Push( _( "Renumber pads" ) );
347 
348  frame()->PopTool( tool );
349  break;
350  }
351  else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
352  {
353  selectedPads.clear();
354 
355  // Be sure the old cursor mouse position was initialized:
356  if( isFirstPoint )
357  {
358  oldCursorPos = cursorPos;
359  isFirstPoint = false;
360  }
361 
362  // wxWidgets deliver mouse move events not frequently enough, resulting in skipping
363  // pads if the user moves cursor too fast. To solve it, create a line that approximates
364  // the mouse move and search pads that are on the line.
365  int distance = ( cursorPos - oldCursorPos ).EuclideanNorm();
366  // Search will be made every 0.1 mm:
367  int segments = distance / int( 0.1*IU_PER_MM ) + 1;
368  const wxPoint line_step( ( cursorPos - oldCursorPos ) / segments );
369 
370  collector.Empty();
371 
372  for( int j = 0; j < segments; ++j )
373  {
374  wxPoint testpoint( cursorPos.x - j * line_step.x, cursorPos.y - j * line_step.y );
375  collector.Collect( board(), types, testpoint, guide );
376 
377  for( int i = 0; i < collector.GetCount(); ++i )
378  selectedPads.push_back( static_cast<PAD*>( collector[i] ) );
379  }
380 
381  selectedPads.unique();
382 
383  for( PAD* pad : selectedPads )
384  {
385  // If pad was not selected, then enumerate it
386  if( !pad->IsSelected() )
387  {
388  commit.Modify( pad );
389 
390  // Rename pad and store the old name
391  int newval;
392 
393  if( storedPadNumbers.size() > 0 )
394  {
395  newval = storedPadNumbers.front();
396  storedPadNumbers.pop_front();
397  }
398  else
399  newval = seqPadNum++;
400 
401  wxString newNumber = wxString::Format( wxT( "%s%d" ), padPrefix, newval );
402  oldNumbers[newNumber] = { newval, pad->GetNumber() };
403  pad->SetNumber( newNumber );
404  SetLastPadNumber( newNumber );
405  pad->SetSelected();
406  getView()->Update( pad );
407 
408  // Ensure the popup text shows the correct next value
409  if( storedPadNumbers.size() > 0 )
410  newval = storedPadNumbers.front();
411  else
412  newval = seqPadNum;
413 
414  statusPopup.SetText( wxString::Format( msg, padPrefix, newval ) );
415  }
416 
417  // ... or restore the old name if it was enumerated and clicked again
418  else if( pad->IsSelected() && evt->IsClick( BUT_LEFT ) )
419  {
420  auto it = oldNumbers.find( pad->GetNumber() );
421  wxASSERT( it != oldNumbers.end() );
422 
423  if( it != oldNumbers.end() )
424  {
425  storedPadNumbers.push_back( it->second.first );
426  pad->SetNumber( it->second.second );
427  SetLastPadNumber( it->second.second );
428  oldNumbers.erase( it );
429 
430  int newval = storedPadNumbers.front();
431 
432  statusPopup.SetText( wxString::Format( msg, padPrefix, newval ) );
433  }
434 
435  pad->ClearSelected();
436  getView()->Update( pad );
437  }
438  }
439  }
440  else if( ( evt->IsKeyPressed() && evt->KeyCode() == WXK_RETURN ) ||
441  evt->IsDblClick( BUT_LEFT ) )
442  {
443  commit.Push( _( "Renumber pads" ) );
444  frame()->PopTool( tool );
445  break;
446  }
447  else if( evt->IsClick( BUT_RIGHT ) )
448  {
450  }
451  else
452  {
453  evt->SetPassEvent();
454  }
455 
456  // Prepare the next loop by updating the old cursor mouse position
457  // to this last mouse cursor position
458  oldCursorPos = getViewControls()->GetCursorPosition();
459  statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
460  }
461 
462  for( PAD* p : board()->GetFirstFootprint()->Pads() )
463  {
464  p->ClearSelected();
465  getView()->Update( p );
466  }
467 
468  statusPopup.Hide();
470  return 0;
471 }
472 
473 
474 int PAD_TOOL::PlacePad( const TOOL_EVENT& aEvent )
475 {
476  if( !board()->GetFirstFootprint() )
477  return 0;
478 
479  struct PAD_PLACER : public INTERACTIVE_PLACER_BASE
480  {
481  PAD_PLACER( PAD_TOOL* aPadTool )
482  {
483  m_padTool = aPadTool;
484  }
485 
486  virtual ~PAD_PLACER()
487  {
488  }
489 
490  std::unique_ptr<BOARD_ITEM> CreateItem() override
491  {
492  PAD* pad = new PAD( m_board->GetFirstFootprint() );
493  PAD* master = m_frame->GetDesignSettings().m_Pad_Master.get();
494 
495  pad->ImportSettingsFrom( *master );
496 
497  // If the footprint type and master pad type directly conflict then make some
498  // adjustments. Otherwise assume the user set what they wanted.
499  if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_SMD )
500  && master->GetAttribute() == PAD_ATTRIB::PTH )
501  {
502  pad->SetAttribute( PAD_ATTRIB::SMD );
503  pad->SetShape( PAD_SHAPE::ROUNDRECT );
504  pad->SetSizeX( 1.5 * pad->GetSizeY() );
505  pad->SetLayerSet( PAD::SMDMask() );
506  }
507  else if( ( m_board->GetFirstFootprint()->GetAttributes() & FP_THROUGH_HOLE )
508  && master->GetAttribute() == PAD_ATTRIB::SMD )
509  {
510  pad->SetAttribute( PAD_ATTRIB::PTH );
511  pad->SetShape( PAD_SHAPE::CIRCLE );
512  pad->SetSize( wxSize( pad->GetSizeX(), pad->GetSizeX() ) );
513  pad->SetLayerSet( PAD::PTHMask() );
514  }
515 
516  if( pad->CanHaveNumber() )
517  {
518  wxString padNumber = m_padTool->GetLastPadNumber();
519  padNumber = m_board->GetFirstFootprint()->GetNextPadNumber( padNumber );
520  pad->SetNumber( padNumber );
521  m_padTool->SetLastPadNumber( padNumber );
522  }
523 
524  return std::unique_ptr<BOARD_ITEM>( pad );
525  }
526 
527  bool PlaceItem( BOARD_ITEM *aItem, BOARD_COMMIT& aCommit ) override
528  {
529  PAD* pad = dynamic_cast<PAD*>( aItem );
530 
531  if( pad )
532  {
533  m_frame->GetDesignSettings().m_Pad_Master->ImportSettingsFrom( *pad );
534  pad->SetLocalCoord();
535  aCommit.Add( aItem );
536  return true;
537  }
538 
539  return false;
540  }
541 
542  PAD_TOOL* m_padTool;
543  };
544 
545  PAD_PLACER placer( this );
546 
547  doInteractiveItemPlacement( aEvent.GetCommandStr().get(), &placer, _( "Place pad" ),
549 
550  return 0;
551 }
552 
553 
554 int PAD_TOOL::EditPad( const TOOL_EVENT& aEvent )
555 {
557  WX_INFOBAR* infoBar = frame()->GetInfoBar();
559  wxString msg;
560 
561  if( m_editPad != niluuid )
562  {
563  PAD* pad = dynamic_cast<PAD*>( frame()->GetItem( m_editPad ) );
564 
565  if( pad )
566  recombinePad( pad );
567 
568  m_editPad = niluuid;
569  }
570  else if( selection.Size() == 1 && selection[0]->Type() == PCB_PAD_T )
571  {
572  PAD* pad = static_cast<PAD*>( selection[0] );
573  PCB_LAYER_ID layer = explodePad( pad );
574 
576  frame()->SetActiveLayer( layer );
577 
578  if( !m_wasHighContrast )
580 
581  if( PCB_ACTIONS::explodePad.GetHotKey() == PCB_ACTIONS::recombinePad.GetHotKey() )
582  {
583  msg.Printf( _( "Pad Edit Mode. Press %s again to exit." ),
585 
586  else
587  {
588  msg.Printf( _( "Pad Edit Mode. Press %s to exit." ),
590  }
591 
592  infoBar->RemoveAllButtons();
593  infoBar->ShowMessage( msg, wxICON_INFORMATION );
594 
595  m_editPad = pad->m_Uuid;
596  }
597 
598  if( m_editPad == niluuid )
599  {
600  bool highContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
601 
602  if( m_wasHighContrast != highContrast )
604 
605  infoBar->Dismiss();
606  }
607 
608  return 0;
609 }
610 
611 
613 {
614  PCB_LAYER_ID layer;
615  BOARD_COMMIT commit( frame() );
616 
617  if( aPad->IsOnLayer( F_Cu ) )
618  layer = F_Cu;
619  else if( aPad->IsOnLayer( B_Cu ) )
620  layer = B_Cu;
621  else
622  layer = *aPad->GetLayerSet().UIOrder();
623 
624  if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
625  {
626  commit.Modify( aPad );
627 
628  for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives() )
629  {
630  FP_SHAPE* shape = new FP_SHAPE( board()->GetFirstFootprint() );
631 
632  shape->SetShape( primitive->GetShape() );
633  shape->SetFilled( primitive->IsFilled() );
634  shape->SetWidth( primitive->GetWidth() );
635 
636  switch( shape->GetShape() )
637  {
638  case SHAPE_T::SEGMENT:
639  case SHAPE_T::RECT:
640  case SHAPE_T::CIRCLE:
641  shape->SetStart( primitive->GetStart() );
642  shape->SetEnd( primitive->GetEnd() );
643  break;
644 
645  case SHAPE_T::ARC:
646  shape->SetStart( primitive->GetStart() );
647  shape->SetEnd( primitive->GetEnd() );
648  shape->SetCenter( primitive->GetCenter() );
649  break;
650 
651  case SHAPE_T::BEZIER:
652  shape->SetStart( primitive->GetStart() );
653  shape->SetEnd( primitive->GetEnd() );
654  shape->SetBezierC1( primitive->GetBezierC1() );
655  shape->SetBezierC2( primitive->GetBezierC2() );
656  break;
657 
658  case SHAPE_T::POLY:
659  shape->SetPolyShape( primitive->GetPolyShape() );
660  break;
661 
662  default:
664  }
665 
666  shape->SetLocalCoord();
667  shape->Move( aPad->GetPosition() );
668  shape->Rotate( aPad->GetPosition(), aPad->GetOrientation() );
669  shape->SetLayer( layer );
670 
671  commit.Add( shape );
672  }
673 
674  aPad->SetShape( aPad->GetAnchorPadShape() );
675  aPad->DeletePrimitivesList();
676  m_editPad = aPad->m_Uuid;
677  }
678 
679  commit.Push( _("Edit pad shapes") );
681  return layer;
682 }
683 
684 
686 {
687  int maxError = board()->GetDesignSettings().m_MaxError;
688 
689  auto findNext =
690  [&]( PCB_LAYER_ID aLayer ) -> FP_SHAPE*
691  {
692  SHAPE_POLY_SET padPoly;
693  aPad->TransformShapeWithClearanceToPolygon( padPoly, aLayer, 0, maxError,
694  ERROR_INSIDE );
695 
696  for( BOARD_ITEM* item : board()->GetFirstFootprint()->GraphicalItems() )
697  {
698  PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( item );
699 
700  if( !shape || ( shape->GetEditFlags() & STRUCT_DELETED ) )
701  continue;
702 
703  if( shape->GetLayer() != aLayer )
704  continue;
705 
706  SHAPE_POLY_SET drawPoly;
707  shape->TransformShapeWithClearanceToPolygon( drawPoly, aLayer, 0, maxError,
708  ERROR_INSIDE );
709  drawPoly.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST );
710 
711  if( !drawPoly.IsEmpty() )
712  return (FP_SHAPE*) item;
713  }
714 
715  return nullptr;
716  };
717 
718  BOARD_COMMIT commit( frame() );
719  PCB_LAYER_ID layer;
720 
721  if( aPad->IsOnLayer( F_Cu ) )
722  layer = F_Cu;
723  else if( aPad->IsOnLayer( B_Cu ) )
724  layer = B_Cu;
725  else
726  layer = *aPad->GetLayerSet().UIOrder();
727 
728  while( FP_SHAPE* fpShape = findNext( layer ) )
729  {
730  commit.Modify( aPad );
731 
732  // We've found an intersecting item. First convert the pad to a custom-shape
733  // pad (if it isn't already)
734  //
735  if( aPad->GetShape() == PAD_SHAPE::RECT || aPad->GetShape() == PAD_SHAPE::CIRCLE )
736  {
737  aPad->SetAnchorPadShape( aPad->GetShape() );
738  }
739  else if( aPad->GetShape() != PAD_SHAPE::CUSTOM )
740  {
741  // Create a new minimally-sized circular anchor and convert existing pad
742  // to a polygon primitive
743  SHAPE_POLY_SET existingOutline;
744  aPad->TransformShapeWithClearanceToPolygon( existingOutline, layer, 0, maxError,
745  ERROR_INSIDE );
746 
748  if( aPad->GetSizeX() > aPad->GetSizeY() )
749  aPad->SetSizeX( aPad->GetSizeY() );
750 
751  aPad->SetOffset( wxPoint( 0, 0 ) );
752 
753  PCB_SHAPE* shape = new PCB_SHAPE( nullptr, SHAPE_T::POLY );
754  shape->SetFilled( true );
755  shape->SetWidth( 0 );
756  shape->SetPolyShape( existingOutline );
757  shape->Move( - aPad->GetPosition() );
758  shape->Rotate( wxPoint( 0, 0 ), - aPad->GetOrientation() );
759 
760  aPad->AddPrimitive( shape );
761  }
762 
763  aPad->SetShape( PAD_SHAPE::CUSTOM );
764 
765  // Now add the new shape to the primitives list
766  //
767  PCB_SHAPE* pcbShape = new PCB_SHAPE;
768 
769  pcbShape->SetShape( fpShape->GetShape() );
770  pcbShape->SetFilled( fpShape->IsFilled() );
771  pcbShape->SetWidth( fpShape->GetWidth() );
772 
773 
774  switch( pcbShape->GetShape() )
775  {
776  case SHAPE_T::SEGMENT:
777  case SHAPE_T::RECT:
778  case SHAPE_T::CIRCLE:
779  pcbShape->SetStart( fpShape->GetStart() );
780  pcbShape->SetEnd( fpShape->GetEnd() );
781  break;
782 
783  case SHAPE_T::ARC:
784  pcbShape->SetStart( fpShape->GetStart() );
785  pcbShape->SetEnd( fpShape->GetEnd() );
786  pcbShape->SetCenter( fpShape->GetCenter() );
787  break;
788 
789  case SHAPE_T::BEZIER:
790  pcbShape->SetStart( fpShape->GetStart() );
791  pcbShape->SetEnd( fpShape->GetEnd() );
792  pcbShape->SetBezierC1( fpShape->GetBezierC1() );
793  pcbShape->SetBezierC2( fpShape->GetBezierC2() );
794  break;
795 
796  case SHAPE_T::POLY:
797  pcbShape->SetPolyShape( fpShape->GetPolyShape() );
798  break;
799 
800  default:
801  UNIMPLEMENTED_FOR( pcbShape->SHAPE_T_asString() );
802  }
803 
804  pcbShape->Move( - aPad->GetPosition() );
805  pcbShape->Rotate( wxPoint( 0, 0 ), - aPad->GetOrientation() );
806  aPad->AddPrimitive( pcbShape );
807 
808  fpShape->SetFlags( STRUCT_DELETED );
809  commit.Remove( fpShape );
810  }
811 
812  commit.Push(_("Recombine pads") );
813 }
814 
815 
817 {
821 
824 
827 }
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:63
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:83
KIID m_editPad
Definition: pad_tool.h:84
void SetEnd(const wxPoint &aEnd)
Definition: eda_shape.h:126
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:163
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:172
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:215
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:567
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:144
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:101
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:83
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:81
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:223
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:326
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:124
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:158
#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:88
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:266
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:612
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:1415
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:1530
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:91
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:147
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:338
SHAPE_T GetShape() const
Definition: eda_shape.h:92
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:685
int EditPad(const TOOL_EVENT &aEvent)
Enter/exit WYSIWYG pad shape editing.
Definition: pad_tool.cpp:554
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:66
int PlacePad(const TOOL_EVENT &aEvent)
Place a pad in footprint editor.
Definition: pad_tool.cpp:474
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:165
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:142
void setTransitions() override
< Bind handlers to corresponding TOOL_ACTIONs.
Definition: pad_tool.cpp:816
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:151
void SetAnchorPadShape(PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition: pad.h:209