KiCad PCB EDA Suite
edit_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) 2013-2017 CERN
5  * @author Maciej Suminski <maciej.suminski@cern.ch>
6  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  * Copyright (C) 2017-2021 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 <limits>
28 #include <board.h>
29 #include <footprint.h>
30 #include <fp_shape.h>
31 #include <collectors.h>
32 #include <pcb_edit_frame.h>
34 #include <kiway.h>
35 #include <array_creator.h>
36 #include <pcbnew_settings.h>
37 #include <status_popup.h>
39 #include <tool/tool_manager.h>
40 #include <tools/pcb_actions.h>
42 #include <tools/edit_tool.h>
43 #include <tools/pcb_picker_tool.h>
44 #include <tools/tool_event_utils.h>
45 #include <tools/pcb_grid_helper.h>
46 #include <tools/pad_tool.h>
47 #include <pad_naming.h>
48 #include <view/view_controls.h>
51 #include <confirm.h>
52 #include <bitmaps.h>
53 #include <cassert>
54 #include <functional>
55 using namespace std::placeholders;
56 #include "kicad_clipboard.h"
57 #include <wx/hyperlink.h>
58 #include <widgets/infobar.h>
59 #include <router/router_tool.h>
63 #include <board_commit.h>
64 #include <pcb_target.h>
65 #include <zone_filler.h>
66 
67 
69  PCB_TOOL_BASE( "pcbnew.InteractiveEdit" ),
70  m_selectionTool( NULL ),
71  m_dragging( false )
72 {
73 }
74 
75 
77 {
78  m_dragging = false;
79 
80  m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( getEditFrame<PCB_BASE_EDIT_FRAME>() );
81 
82  if( aReason != RUN )
83  m_commit.reset( new BOARD_COMMIT( this ) );
84 }
85 
86 
88  CONDITIONAL_MENU( aTool )
89 {
91  SetTitle( _( "Special Tools" ) );
92 
97 }
98 
99 
101 {
102  // Find the selection tool, so they can cooperate
104 
105  auto inFootprintEditor =
106  [ this ]( const SELECTION& aSelection )
107  {
108  return m_isFootprintEditor;
109  };
110 
111  auto singleFootprintCondition = SELECTION_CONDITIONS::OnlyType( PCB_FOOTPRINT_T )
113 
114  auto noActiveToolCondition =
115  [ this ]( const SELECTION& aSelection )
116  {
117  return frame()->ToolStackIsEmpty();
118  };
119 
120  auto notMovingCondition =
121  [ this ]( const SELECTION& aSelection )
122  {
125  };
126 
127  auto noItemsCondition =
128  [ this ]( const SELECTION& aSelections ) -> bool
129  {
130  return frame()->GetBoard() && !frame()->GetBoard()->IsEmpty();
131  };
132 
133  // Add context menu entries that are displayed when selection tool is active
135 
136  menu.AddItem( PCB_ACTIONS::move, SELECTION_CONDITIONS::NotEmpty && notMovingCondition );
148  menu.AddItem( PCB_ACTIONS::mirror, inFootprintEditor && SELECTION_CONDITIONS::NotEmpty );
149 
152 
153  // Footprint actions
154  menu.AddSeparator();
155  menu.AddItem( PCB_ACTIONS::editFpInFpEditor, singleFootprintCondition );
156  menu.AddItem( PCB_ACTIONS::updateFootprint, singleFootprintCondition );
157  menu.AddItem( PCB_ACTIONS::changeFootprint, singleFootprintCondition );
158 
159  // Add the submenu for create array and special move
160  auto specialToolsSubMenu = std::make_shared<SPECIAL_TOOLS_CONTEXT_MENU>( this );
161  menu.AddSeparator();
162  m_selectionTool->GetToolMenu().AddSubMenu( specialToolsSubMenu );
163  menu.AddMenu( specialToolsSubMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
164 
165  menu.AddSeparator( 150 );
168  // Selection tool handles the context menu for some other tools, such as the Picker.
169  // Don't add things like Paste when another tool is active.
170  menu.AddItem( ACTIONS::paste, noActiveToolCondition, 150 );
173 
174  menu.AddSeparator( 150 );
175  menu.AddItem( ACTIONS::selectAll, noItemsCondition, 150 );
176 
177  return true;
178 }
179 
180 
181 int EDIT_TOOL::GetAndPlace( const TOOL_EVENT& aEvent )
182 {
184  FOOTPRINT* fp = getEditFrame<PCB_BASE_FRAME>()->GetFootprintFromBoardByReference();
185 
186  if( fp )
187  {
189  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, (void*) fp );
190 
191  selectionTool->GetSelection().SetReferencePoint( fp->GetPosition() );
193  }
194 
195  return 0;
196 }
197 
198 
199 bool EDIT_TOOL::invokeInlineRouter( int aDragMode )
200 {
202 
203  if( !theRouter )
204  return false;
205 
206  // don't allow switch from moving to dragging
207  if( m_dragging )
208  {
209  wxBell();
210  return false;
211  }
212 
213  // make sure we don't accidentally invoke inline routing mode while the router is already active!
214  if( theRouter->IsToolActive() )
215  return false;
216 
217  if( theRouter->CanInlineDrag( aDragMode ) )
218  {
220  return true;
221  }
222 
223  return false;
224 }
225 
226 
228 {
230 
231  return router && router->Router()->Settings().InlineDragEnabled();
232 }
233 
234 
236 {
238 
239  return router && router->IsToolActive();
240 }
241 
242 
243 int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
244 {
245  int mode = PNS::DM_ANY;
246 
247  if( aEvent.IsAction( &PCB_ACTIONS::dragFreeAngle ) )
248  mode |= PNS::DM_FREE_ANGLE;
249 
251  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
252  {
253  // Iterate from the back so we don't have to worry about removals.
254  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
255  {
256  BOARD_ITEM* item = aCollector[ i ];
257 
258  // We don't operate on pads; convert them to footprint selections
259  if( !sTool->IsFootprintEditor() && item->IsLocked() && item->Type() == PCB_PAD_T
260  && !item->GetParent()->IsLocked() )
261  {
262  aCollector.Remove( item );
263 
264  if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
265  aCollector.Append( item->GetParent() );
266  }
267  }
268 
269  sTool->FilterCollectorForGroups( aCollector );
270  },
271  !m_isFootprintEditor /* prompt user regarding locked items */ );
272 
273  if( selection.Empty() )
274  return 0;
275 
276  if( selection.Size() == 1 && selection.Front()->Type() == PCB_ARC_T )
277  {
278  // TODO: This really should be done in PNS to ensure DRC is maintained, but for now
279  // it allows interactive editing of an arc track
280  return DragArcTrack( aEvent );
281  }
282  else
283  {
284  invokeInlineRouter( mode );
285  }
286 
287  return 0;
288 }
289 
290 
292 {
294 
295  if( selection.Size() != 1 || selection.Front()->Type() != PCB_ARC_T )
296  return 0;
297 
298  Activate();
299 
300  ARC* theArc = static_cast<ARC*>( selection.Front() );
301 
303 
304  controls->ShowCursor( true );
305  controls->SetAutoPan( true );
306  bool restore_state = false;
307 
308  VECTOR2I arcCenter = theArc->GetCenter();
309  SEG tanStart = SEG( arcCenter, theArc->GetStart() ).PerpendicularSeg( theArc->GetStart() );
310  SEG tanEnd = SEG( arcCenter, theArc->GetEnd() ).PerpendicularSeg( theArc->GetEnd() );
311 
312  if( tanStart.ApproxParallel( tanEnd ) )
313  return 0; // don't bother with 180 degree arcs
314 
315  //Ensure the tangent segments are in the correct orientation
316  VECTOR2I tanIntersect = tanStart.IntersectLines( tanEnd ).get();
317  tanStart.A = tanIntersect;
318  tanStart.B = theArc->GetStart();
319  tanEnd.A = tanIntersect;
320  tanEnd.B = theArc->GetEnd();
321 
322  KICAD_T track_types[] = { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, EOT };
323 
324  auto getUniqueTrackAtAnchorCollinear =
325  [&]( const VECTOR2I& aAnchor, const SEG& aCollinearSeg ) -> TRACK*
326  {
327  auto conn = board()->GetConnectivity();
328  auto itemsOnAnchor = conn->GetConnectedItemsAtAnchor( theArc, aAnchor, track_types );
329  TRACK* retval = nullptr;
330 
331  if( itemsOnAnchor.size() == 1 && itemsOnAnchor.front()->Type() == PCB_TRACE_T )
332  {
333  retval = static_cast<TRACK*>( itemsOnAnchor.front() );
334  SEG trackSeg( retval->GetStart(), retval->GetEnd() );
335 
336  //Ensure it is collinear
337  if( !trackSeg.ApproxCollinear( aCollinearSeg ) )
338  retval = nullptr;
339  }
340 
341  if( !retval )
342  {
343  retval = new TRACK( theArc->GetParent() );
344  retval->SetStart( (wxPoint) aAnchor );
345  retval->SetEnd( (wxPoint) aAnchor );
346  retval->SetNet( theArc->GetNet() );
347  retval->SetLayer( theArc->GetLayer() );
348  retval->SetWidth( theArc->GetWidth() );
349  retval->SetFlags( IS_NEW );
350  getView()->Add( retval );
351  }
352 
353  return retval;
354  };
355 
356  TRACK* trackOnStart = getUniqueTrackAtAnchorCollinear( theArc->GetStart(), tanStart);
357  TRACK* trackOnEnd = getUniqueTrackAtAnchorCollinear( theArc->GetEnd(), tanEnd );
358 
359  // Make copies of items to be edited
360  ARC* theArcCopy = new ARC( *theArc );
361  TRACK* trackOnStartCopy = new TRACK( *trackOnStart );
362  TRACK* trackOnEndCopy = new TRACK( *trackOnEnd );
363 
364  if( trackOnStart->GetLength() > tanStart.Length() )
365  {
366  tanStart.A = trackOnStart->GetStart();
367  tanStart.B = trackOnStart->GetEnd();
368  }
369 
370  if( trackOnEnd->GetLength() > tanEnd.Length() )
371  {
372  tanEnd.A = trackOnEnd->GetStart();
373  tanEnd.B = trackOnEnd->GetEnd();
374  }
375 
376  auto isTrackStartClosestToArcStart =
377  [&]( TRACK* aPointA ) -> bool
378  {
379  return GetLineLength( aPointA->GetStart(), theArc->GetStart() )
380  < GetLineLength( aPointA->GetEnd(), theArc->GetStart() );
381  };
382 
383  bool isStartTrackOnStartPt = isTrackStartClosestToArcStart( trackOnStart );
384  bool isEndTrackOnStartPt = isTrackStartClosestToArcStart( trackOnEnd );
385 
386  // Calculate constraints
387  //======================
388  // maxTanCircle is the circle with maximum radius that is tangent to the two adjacent straight
389  // tracks and whose tangent points are constrained within the original tracks and their
390  // projected intersection points.
391  //
392  // The cursor will be constrained first within the isosceles triangle formed by the segments
393  // cSegTanStart, cSegTanEnd and cSegChord. After that it will be constratined to be outside
394  // maxTanCircle.
395  //
396  //
397  // ____________ <-cSegTanStart
398  // / * . ' *
399  // cSegTanEnd-> / * . ' *
400  // /* . ' <-cSegChord *
401  // /. '
402  // /* *
403  //
404  // * c * <-maxTanCircle
405  //
406  // * *
407  //
408  // * *
409  // * *
410  // * *
411  //
412 
413  auto getFurthestPointToTanInterstect =
414  [&]( VECTOR2I& aPointA, VECTOR2I& aPointB ) -> VECTOR2I
415  {
416  if( ( aPointA - tanIntersect ).EuclideanNorm()
417  > ( aPointB - tanIntersect ).EuclideanNorm() )
418  {
419  return aPointA;
420  }
421  else
422  {
423  return aPointB;
424  }
425  };
426 
427  CIRCLE maxTanCircle;
428 
429  VECTOR2I tanStartPoint = getFurthestPointToTanInterstect( tanStart.A, tanStart.B );
430  VECTOR2I tanEndPoint = getFurthestPointToTanInterstect( tanEnd.A, tanEnd.B );
431  VECTOR2I tempTangentPoint = tanEndPoint;
432 
433  if( getFurthestPointToTanInterstect( tanStartPoint, tanEndPoint ) == tanEndPoint )
434  tempTangentPoint = tanStartPoint;
435 
436  maxTanCircle.ConstructFromTanTanPt( tanStart, tanEnd, tempTangentPoint );
437  VECTOR2I maxTanPtStart = tanStart.LineProject( maxTanCircle.Center );
438  VECTOR2I maxTanPtEnd = tanEnd.LineProject( maxTanCircle.Center );
439 
440  SEG cSegTanStart( maxTanPtStart, tanIntersect );
441  SEG cSegTanEnd( maxTanPtEnd, tanIntersect );
442  SEG cSegChord( maxTanPtStart, maxTanPtEnd );
443 
444  int cSegTanStartSide = cSegTanStart.Side( theArc->GetMid() );
445  int cSegTanEndSide = cSegTanEnd.Side( theArc->GetMid() );
446  int cSegChordSide = cSegChord.Side( theArc->GetMid() );
447 
448  // Start the tool loop
449  //====================
450  while( TOOL_EVENT* evt = Wait() )
451  {
453 
454  // Constrain cursor within the isosceles triangle
455  if( cSegTanStartSide != cSegTanStart.Side( m_cursor )
456  || cSegTanEndSide != cSegTanEnd.Side( m_cursor )
457  || cSegChordSide != cSegChord.Side( m_cursor ) )
458  {
459  std::vector<VECTOR2I> possiblePoints;
460 
461  possiblePoints.push_back( cSegTanEnd.NearestPoint( m_cursor ) );
462  possiblePoints.push_back( cSegChord.NearestPoint( m_cursor ) );
463 
464  VECTOR2I closest = cSegTanStart.NearestPoint( m_cursor );
465 
466  for( VECTOR2I candidate : possiblePoints )
467  {
468  if( ( candidate - m_cursor ).EuclideanNorm()
469  < ( closest - m_cursor ).EuclideanNorm() )
470  {
471  closest = candidate;
472  }
473  }
474 
475  m_cursor = closest;
476  }
477 
478  // Constrain cursor to be outside maxTanCircle
479  if( ( m_cursor - maxTanCircle.Center ).EuclideanNorm() < maxTanCircle.Radius )
480  m_cursor = maxTanCircle.NearestPoint( m_cursor );
481 
483 
484  // Calculate resulting object coordinates
485  CIRCLE circlehelper;
486  circlehelper.ConstructFromTanTanPt( cSegTanStart, cSegTanEnd, m_cursor );
487 
488  VECTOR2I newCenter = circlehelper.Center;
489  VECTOR2I newStart = cSegTanStart.LineProject( newCenter );
490  VECTOR2I newEnd = cSegTanEnd.LineProject( newCenter );
491  VECTOR2I newMid = GetArcMid( newStart, newEnd, newCenter );
492 
493  //Update objects
494  theArc->SetStart( (wxPoint) newStart );
495  theArc->SetEnd( (wxPoint) newEnd );
496  theArc->SetMid( (wxPoint) newMid );
497 
498  if( isStartTrackOnStartPt )
499  trackOnStart->SetStart( (wxPoint) newStart );
500  else
501  trackOnStart->SetEnd( (wxPoint) newStart );
502 
503  if( isEndTrackOnStartPt )
504  trackOnEnd->SetStart( (wxPoint) newEnd );
505  else
506  trackOnEnd->SetEnd( (wxPoint) newEnd );
507 
508  //Update view
509  getView()->Update( trackOnStart );
510  getView()->Update( trackOnEnd );
511  getView()->Update( theArc );
512 
513  //Handle events
514  if( evt->IsCancelInteractive() || evt->IsActivate() )
515  {
516  restore_state = true; // Canceling the tool means that items have to be restored
517  break; // Finish
518  }
519  else if( evt->IsAction( &ACTIONS::undo ) )
520  {
521  restore_state = true; // Perform undo locally
522  break; // Finish
523  }
524  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT )
525  || evt->IsDblClick( BUT_LEFT ) )
526  {
527  break; // Finish
528  }
529  }
530 
531  // Ensure we only do one commit operation on each object
532  auto processTrack =
533  [&]( TRACK* aTrack, TRACK* aTrackCopy )
534  {
535  if( aTrack->IsNew() )
536  {
537  getView()->Remove( aTrack );
538 
539  if( aTrack->GetStart() == aTrack->GetEnd() )
540  {
541  delete aTrack;
542  delete aTrackCopy;
543  aTrack = nullptr;
544  aTrackCopy = nullptr;
545  }
546  else
547  {
548  m_commit->Add( aTrack );
549  delete aTrackCopy;
550  aTrackCopy = nullptr;
551  }
552  }
553  else if( aTrack->GetStart() == aTrack->GetEnd() )
554  {
555  aTrack->SwapData( aTrackCopy ); //restore the original before notifying COMMIT
556  m_commit->Remove( aTrack );
557  delete aTrackCopy;
558  aTrackCopy = nullptr;
559  }
560  else
561  {
562  m_commit->Modified( aTrack, aTrackCopy );
563  }
564  };
565 
566  processTrack( trackOnStart, trackOnStartCopy );
567  processTrack( trackOnEnd, trackOnEndCopy );
568  processTrack( theArc, theArcCopy );
569 
570  // Should we commit?
571  if( restore_state )
572  m_commit->Revert();
573  else
574  m_commit->Push( _( "Drag Arc Track" ) );
575 
576  return 0;
577 }
578 
579 
580 int EDIT_TOOL::Move( const TOOL_EVENT& aEvent )
581 {
582  if( isRouterActive() )
583  {
584  wxBell();
585  return 0;
586  }
587 
588  return doMoveSelection( aEvent );
589 }
590 
591 
593 {
594  if( isRouterActive() )
595  {
596  wxBell();
597  return 0;
598  }
599 
600  return doMoveSelection( aEvent, true );
601 }
602 
603 
604 // Note: aEvent MUST NOT be const&; the source will get de-allocated if we go into the picker's
605 // event loop.
606 int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference )
607 {
608  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
610  VECTOR2I originalCursorPos = controls->GetCursorPosition();
611 
612  // Be sure that there is at least one item that we can modify. If nothing was selected before,
613  // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection)
615  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
616  {
617  // Iterate from the back so we don't have to worry about removals.
618  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
619  {
620  BOARD_ITEM* item = aCollector[ i ];
621 
622  if( item->Type() == PCB_MARKER_T )
623  aCollector.Remove( item );
624  }
625  } );
626 
627  if( m_dragging || selection.Empty() )
628  return 0;
629 
630  LSET item_layers = selection.GetSelectionLayers();
631  bool unselect = selection.IsHover(); // N.B. This must be saved before the re-selection
632  // below
633  VECTOR2I pickedReferencePoint;
634 
635  // Now filter out locked and grouped items. We cannot do this in the first RequestSelection()
636  // as we need the item_layers when a pad is the selection front.
638  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
639  {
640  std::set<BOARD_ITEM*> to_add;
641 
642  // Iterate from the back so we don't have to worry about removals.
643  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
644  {
645  BOARD_ITEM* item = aCollector[ i ];
646 
647  if( item->Type() == PCB_MARKER_T )
648  aCollector.Remove( item );
649 
651  if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T && item->IsLocked()
652  && !item->GetParent()->IsLocked() )
653  {
654  if( !aCollector.HasItem( item->GetParent() ) )
655  to_add.insert( item->GetParent() );
656 
657  aCollector.Remove( item );
658  }
659  }
660 
661  for( BOARD_ITEM* item : to_add )
662  aCollector.Append( item );
663  },
664  !m_isFootprintEditor /* prompt user regarding locked items only in pcb editor*/ );
665 
666  if( selection.Empty() )
667  return 0;
668 
669  std::string tool = aEvent.GetCommandStr().get();
670  editFrame->PushTool( tool );
671  Activate();
672  controls->ShowCursor( true );
673  controls->SetAutoPan( true );
674 
675  if( aPickReference && !pickReferencePoint( _( "Select reference point for move..." ), "", "",
676  pickedReferencePoint ) )
677  {
678  if( unselect )
680 
681  editFrame->PopTool( tool );
682  return 0;
683  }
684 
685  std::vector<BOARD_ITEM*> sel_items;
686 
687  for( EDA_ITEM* item : selection )
688  {
689  BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( item );
690  FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item );
691 
692  if( boardItem )
693  sel_items.push_back( boardItem );
694 
695  if( footprint )
696  {
697  for( PAD* pad : footprint->Pads() )
698  sel_items.push_back( pad );
699  }
700  }
701 
702  bool restore_state = false;
703  VECTOR2I totalMovement;
704  PCB_GRID_HELPER grid( m_toolMgr, editFrame->GetMagneticItemsSettings() );
705  TOOL_EVENT* evt = const_cast<TOOL_EVENT*>( &aEvent );
706  VECTOR2I prevPos;
707 
708  // Prime the pump
710 
711  // Main loop: keep receiving events
712  do
713  {
714  VECTOR2I movement;
716  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
717  grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->Modifier( MD_ALT ) );
718 
719  if( evt->IsAction( &PCB_ACTIONS::move ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT )
720  || evt->IsAction( &ACTIONS::refreshPreview )
721  || evt->IsAction( &PCB_ACTIONS::moveWithReference ) )
722  {
723  if( m_dragging && evt->Category() == TC_MOUSE )
724  {
725  VECTOR2I mousePos( controls->GetMousePosition() );
726 
727  m_cursor = grid.BestSnapAnchor( mousePos, item_layers, sel_items );
728 
730  {
732 
733  // The arrow keys are by definition SINGLE AXIS. Do not allow the other
734  // axis to be snapped to the grid.
735  if( action == ACTIONS::CURSOR_LEFT || action == ACTIONS::CURSOR_RIGHT )
736  m_cursor.y = prevPos.y;
737  else if( action == ACTIONS::CURSOR_UP || action == ACTIONS::CURSOR_DOWN )
738  m_cursor.x = prevPos.x;
739  }
740 
743 
744  movement = m_cursor - prevPos;
745  prevPos = m_cursor;
746  totalMovement += movement;
747 
748  // Drag items to the current cursor position
749  for( EDA_ITEM* item : sel_items )
750  {
751  // Don't double move footprint pads, fields, etc.
752  //
753  // For PCB_GROUP_T, we make sure the selection includes only the top level
754  // group and not its descendants.
755  if( !item->GetParent() || !item->GetParent()->IsSelected() )
756  static_cast<BOARD_ITEM*>( item )->Move( movement );
757  }
758 
760  }
761  else if( !m_dragging && !evt->IsAction( &ACTIONS::refreshPreview ) )
762  {
763  // Prepare to start dragging
764  if( !( evt->IsAction( &PCB_ACTIONS::move )
765  || evt->IsAction( &PCB_ACTIONS::moveWithReference ) )
767  {
769  break;
770  }
771 
772  m_dragging = true;
773 
774  // When editing footprints, all items have the same parent
775  if( IsFootprintEditor() )
776  {
777  m_commit->Modify( selection.Front() );
778  }
779  else
780  {
781  // Save items, so changes can be undone
782  for( EDA_ITEM* item : selection )
783  {
784  // Don't double move footprint pads, fields, etc.
785  //
786  // For PCB_GROUP_T, the parent is the board.
787  if( item->GetParent() && item->GetParent()->IsSelected() )
788  continue;
789 
790  m_commit->Modify( item );
791 
792  // If moving a group, record position of all the descendants for undo
793  if( item->Type() == PCB_GROUP_T )
794  {
795  PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
796  group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
797  {
798  m_commit->Modify( bItem );
799  });
800  }
801  }
802  }
803 
804  editFrame->UndoRedoBlock( true );
806 
808  {
809  // start moving with the reference point attached to the cursor
810  grid.SetAuxAxes( false );
811 
812  movement = m_cursor - selection.GetReferencePoint();
813 
814  // Drag items to the current cursor position
815  for( EDA_ITEM* item : selection )
816  {
817  // Don't double move footprint pads, fields, etc.
818  if( item->GetParent() && item->GetParent()->IsSelected() )
819  continue;
820 
821  static_cast<BOARD_ITEM*>( item )->Move( movement );
822  }
823 
825  }
826  else
827  {
828  std::vector<BOARD_ITEM*> items;
829 
830  for( EDA_ITEM* item : selection )
831  items.push_back( static_cast<BOARD_ITEM*>( item ) );
832 
833  m_cursor = grid.BestDragOrigin( originalCursorPos, items );
834 
835  // Set the current cursor position to the first dragged item origin, so the
836  // movement vector could be computed later
837  if( aPickReference )
838  {
839  selection.SetReferencePoint( pickedReferencePoint );
840  controls->ForceCursorPosition( true, pickedReferencePoint );
841  m_cursor = pickedReferencePoint;
842  }
843  else
844  {
845  // Check if user wants to warp the mouse to origin of moved object
846  if( !editFrame->GetMoveWarpsCursor() )
847  m_cursor = originalCursorPos; // No, so use original mouse pos instead
848 
850  grid.SetAuxAxes( true, m_cursor );
851  }
852  }
853 
855 
856  prevPos = m_cursor;
857  controls->SetAutoPan( true );
859  }
860 
862  new VECTOR2I( movement ) );
863  }
864 
865  else if( evt->IsCancelInteractive() || evt->IsActivate() )
866  {
867  if( m_dragging && evt->IsCancelInteractive() )
868  evt->SetPassEvent( false );
869 
870  restore_state = true; // Canceling the tool means that items have to be restored
871  break; // Finish
872  }
873 
874  else if( evt->IsAction( &ACTIONS::undo ) )
875  {
876  restore_state = true; // Perform undo locally
877  break; // Finish
878  }
879 
880  // Dispatch TOOL_ACTIONs
881  else if( evt->IsAction( &ACTIONS::doDelete ) )
882  {
883  break; // finish -- there is no further processing for removed items
884  }
885  else if( evt->IsAction( &ACTIONS::duplicate ) )
886  {
887  break; // finish -- Duplicate tool will start a new Move with the dup'ed items
888  }
889  else if( evt->IsAction( &PCB_ACTIONS::moveExact ) )
890  {
891  // Reset positions so the Move Exactly is from the start.
892  for( EDA_ITEM* item : selection )
893  {
894  BOARD_ITEM* i = static_cast<BOARD_ITEM*>( item );
895  i->Move( -totalMovement );
896  }
897 
898  break; // finish -- we moved exactly, so we are finished
899  }
900  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
901  {
902  break; // finish
903  }
904  else
905  {
906  evt->SetPassEvent();
907  }
908 
909  } while( ( evt = Wait() ) ); // Assignment (instead of equality test) is intentional
910 
911  controls->ForceCursorPosition( false );
912  controls->ShowCursor( false );
913  controls->SetAutoPan( false );
914 
915  m_dragging = false;
916  editFrame->UndoRedoBlock( false );
917 
918  // Discard reference point when selection is "dropped" onto the board
920 
921  // TODO: there's an ecapsulation leak here: this commit often has more than just the move
922  // in it; for instance it might have a paste, append board, etc. as well.
923  if( restore_state )
924  m_commit->Revert();
925  else
926  m_commit->Push( _( "Drag" ) );
927 
928  // Remove the dynamic ratsnest from the screen
930 
931  if( unselect )
933 
934  editFrame->PopTool( tool );
935  return 0;
936 }
937 
938 
940 {
942  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
943  {
944  // Iterate from the back so we don't have to worry about removals.
945  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
946  {
947  BOARD_ITEM* item = aCollector[ i ];
948 
949  if( !dynamic_cast<TRACK*>( item ) )
950  aCollector.Remove( item );
951  }
952  },
953  true /* prompt user regarding locked items */ );
954 
955  for( EDA_ITEM* item : selection )
956  {
957  if( item->Type() == PCB_VIA_T )
958  {
959  VIA* via = static_cast<VIA*>( item );
960 
961  m_commit->Modify( via );
962 
963  int new_width;
964  int new_drill;
965 
966  if( via->GetViaType() == VIATYPE::MICROVIA )
967  {
968  NETCLASS* netClass = via->GetNetClass();
969 
970  new_width = netClass->GetuViaDiameter();
971  new_drill = netClass->GetuViaDrill();
972  }
973  else
974  {
975  new_width = board()->GetDesignSettings().GetCurrentViaSize();
976  new_drill = board()->GetDesignSettings().GetCurrentViaDrill();
977  }
978 
979  via->SetDrill( new_drill );
980  via->SetWidth( new_width );
981  }
982  else if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
983  {
984  TRACK* track = dynamic_cast<TRACK*>( item );
985 
986  wxCHECK( track, 0 );
987 
988  m_commit->Modify( track );
989 
990  int new_width = board()->GetDesignSettings().GetCurrentTrackWidth();
991  track->SetWidth( new_width );
992  }
993  }
994 
995  m_commit->Push( _("Edit track width/via size") );
996 
997  if( selection.IsHover() )
998  {
1000 
1001  // Notify other tools of the changes -- This updates the visual ratsnest
1003  }
1004 
1005  return 0;
1006 }
1007 
1008 
1010 {
1011  // Store last used fillet radius to allow pressing "enter" if repeat fillet is required
1012  static long long filletRadiusIU = 0;
1013 
1015  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1016  {
1017  // Iterate from the back so we don't have to worry about removals.
1018  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1019  {
1020  BOARD_ITEM* item = aCollector[i];
1021 
1022  if( !dynamic_cast<TRACK*>( item ) )
1023  aCollector.Remove( item );
1024  }
1025  },
1026  !m_dragging /* prompt user regarding locked items */ );
1027 
1028  if( selection.Size() < 2 )
1029  {
1030  frame()->ShowInfoBarMsg( _( "At least two straight track segments must be selected." ) );
1031  return 0;
1032  }
1033 
1034  WX_UNIT_ENTRY_DIALOG dia( frame(), _( "Enter fillet radius:" ), _( "Fillet Tracks" ),
1035  filletRadiusIU );
1036 
1037  if( dia.ShowModal() == wxID_CANCEL )
1038  return 0;
1039 
1040  filletRadiusIU = dia.GetValue();
1041 
1042  if( filletRadiusIU == 0 )
1043  {
1044  frame()->ShowInfoBarMsg( _( "A radius of zero was entered.\n"
1045  "The fillet operation was not performed." ) );
1046  return 0;
1047  }
1048 
1049 
1050  struct FILLET_OP
1051  {
1052  TRACK* t1;
1053  TRACK* t2;
1054  //If true, start point of track is modified after ARC is added, otherwise the end point:
1055  bool t1Start = true;
1056  bool t2Start = true;
1057  };
1058 
1059  std::vector<FILLET_OP> filletOperations;
1060  KICAD_T track_types[] = { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, EOT };
1061  bool operationPerformedOnAtLeastOne = false;
1062  bool didOneAttemptFail = false;
1063  std::set<TRACK*> processedTracks;
1064 
1065  for( auto it = selection.begin(); it != selection.end(); it++ )
1066  {
1067  TRACK* track = dyn_cast<TRACK*>( *it );
1068 
1069  if( !track || track->Type() != PCB_TRACE_T || track->IsLocked()
1070  || track->GetLength() == 0 )
1071  {
1072  continue;
1073  }
1074 
1075  auto processFilletOp =
1076  [&]( bool aStartPoint )
1077  {
1078  wxPoint anchor = ( aStartPoint ) ? track->GetStart() : track->GetEnd();
1079  auto connectivity = board()->GetConnectivity();
1080  auto itemsOnAnchor = connectivity->GetConnectedItemsAtAnchor( track, anchor,
1081  track_types );
1082 
1083  if( itemsOnAnchor.size() > 0
1084  && selection.Contains( itemsOnAnchor.at( 0 ) )
1085  && itemsOnAnchor.at( 0 )->Type() == PCB_TRACE_T )
1086  {
1087  TRACK* trackOther = dyn_cast<TRACK*>( itemsOnAnchor.at( 0 ) );
1088 
1089  // Make sure we don't fillet the same pair of tracks twice
1090  if( processedTracks.find( trackOther ) == processedTracks.end() )
1091  {
1092  if( itemsOnAnchor.size() == 1 )
1093  {
1094  FILLET_OP filletOp;
1095  filletOp.t1 = track;
1096  filletOp.t2 = trackOther;
1097  filletOp.t1Start = aStartPoint;
1098  filletOp.t2Start = track->IsPointOnEnds( filletOp.t2->GetStart() );
1099  filletOperations.push_back( filletOp );
1100  }
1101  else
1102  {
1103  // User requested to fillet these two tracks but not possible as
1104  // there are other elements connected at that point
1105  didOneAttemptFail = true;
1106  }
1107  }
1108  }
1109  };
1110 
1111  processFilletOp( true ); // on the start point of track
1112  processFilletOp( false ); // on the end point of track
1113 
1114  processedTracks.insert( track );
1115  }
1116 
1117  std::vector<BOARD_ITEM*> itemsToAddToSelection;
1118 
1119  for( FILLET_OP filletOp : filletOperations )
1120  {
1121  TRACK* track1 = filletOp.t1;
1122  TRACK* track2 = filletOp.t2;
1123 
1124  bool trackOnStart = track1->IsPointOnEnds( track2->GetStart() );
1125  bool trackOnEnd = track1->IsPointOnEnds( track2->GetEnd() );
1126 
1127  if( trackOnStart && trackOnEnd )
1128  continue; // Ignore duplicate tracks
1129 
1130  if( ( trackOnStart || trackOnEnd ) && track1->GetLayer() == track2->GetLayer() )
1131  {
1132  SEG t1Seg( track1->GetStart(), track1->GetEnd() );
1133  SEG t2Seg( track2->GetStart(), track2->GetEnd() );
1134 
1135  if( t1Seg.ApproxCollinear( t2Seg ) )
1136  continue;
1137 
1138  SHAPE_ARC sArc( t1Seg, t2Seg, filletRadiusIU );
1139 
1140  wxPoint t1newPoint, t2newPoint;
1141 
1142  auto setIfPointOnSeg =
1143  []( wxPoint& aPointToSet, SEG aSegment, VECTOR2I aVecToTest )
1144  {
1145  VECTOR2I segToVec = aSegment.NearestPoint( aVecToTest ) - aVecToTest;
1146 
1147  // Find out if we are on the segment (minimum precision)
1148  if( segToVec.EuclideanNorm() < SHAPE_ARC::MIN_PRECISION_IU )
1149  {
1150  aPointToSet.x = aVecToTest.x;
1151  aPointToSet.y = aVecToTest.y;
1152  return true;
1153  }
1154 
1155  return false;
1156  };
1157 
1158  //Do not draw a fillet if the end points of the arc are not within the track segments
1159  if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.GetP0() )
1160  && !setIfPointOnSeg( t2newPoint, t2Seg, sArc.GetP0() ) )
1161  {
1162  didOneAttemptFail = true;
1163  continue;
1164  }
1165 
1166  if( !setIfPointOnSeg( t1newPoint, t1Seg, sArc.GetP1() )
1167  && !setIfPointOnSeg( t2newPoint, t2Seg, sArc.GetP1() ) )
1168  {
1169  didOneAttemptFail = true;
1170  continue;
1171  }
1172 
1173  ARC* tArc = new ARC( frame()->GetBoard(), &sArc );
1174  tArc->SetLayer( track1->GetLayer() );
1175  tArc->SetWidth( track1->GetWidth() );
1176  tArc->SetNet( track1->GetNet() );
1177  m_commit->Add( tArc );
1178  itemsToAddToSelection.push_back( tArc );
1179 
1180  m_commit->Modify( track1 );
1181  m_commit->Modify( track2 );
1182 
1183  if( filletOp.t1Start )
1184  track1->SetStart( t1newPoint );
1185  else
1186  track1->SetEnd( t1newPoint );
1187 
1188  if( filletOp.t2Start )
1189  track2->SetStart( t2newPoint );
1190  else
1191  track2->SetEnd( t2newPoint );
1192 
1193  operationPerformedOnAtLeastOne = true;
1194  }
1195  }
1196 
1197  m_commit->Push( _( "Fillet Tracks" ) );
1198 
1199  //select the newly created arcs
1200  for( BOARD_ITEM* item : itemsToAddToSelection )
1201  m_selectionTool->AddItemToSel( item );
1202 
1203  if( !operationPerformedOnAtLeastOne )
1204  frame()->ShowInfoBarMsg( _( "Unable to fillet the selected track segments." ) );
1205  else if( didOneAttemptFail )
1206  frame()->ShowInfoBarMsg( _( "Some of the track segments could not be filleted." ) );
1207 
1208  return 0;
1209 }
1210 
1211 
1212 int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
1213 {
1214  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1216  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1217  {
1218  } );
1219 
1220  // Tracks & vias are treated in a special way:
1222  {
1223  DIALOG_TRACK_VIA_PROPERTIES dlg( editFrame, selection, *m_commit );
1224  dlg.ShowQuasiModal(); // QuasiModal required for NET_SELECTOR
1225  }
1226  else if( selection.Size() == 1 )
1227  {
1228  // Display properties dialog
1229  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
1230 
1231  // Do not handle undo buffer, it is done by the properties dialogs
1232  editFrame->OnEditItemRequest( item );
1233 
1234  // Notify other tools of the changes
1236  }
1237  else if( selection.Size() == 0 && getView()->IsLayerVisible( LAYER_DRAWINGSHEET ) )
1238  {
1239  DS_PROXY_VIEW_ITEM* ds = editFrame->GetCanvas()->GetDrawingSheet();
1240  VECTOR2D cursorPos = getViewControls()->GetCursorPosition( false );
1241 
1242  if( ds && ds->HitTestDrawingSheetItems( getView(), (wxPoint) cursorPos ) )
1244  }
1245 
1246  if( selection.IsHover() )
1247  {
1249 
1250  // Notify other tools of the changes -- This updates the visual ratsnest
1252  }
1253 
1254  return 0;
1255 }
1256 
1257 
1258 int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
1259 {
1260  if( isRouterActive() )
1261  {
1262  wxBell();
1263  return 0;
1264  }
1265 
1266  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1267 
1269  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1270  {
1271  std::set<BOARD_ITEM*> added_items;
1272 
1273  // Iterate from the back so we don't have to worry about removals.
1274  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1275  {
1276  BOARD_ITEM* item = aCollector[i];
1277 
1278  // We don't operate on pads; convert them to footprint selections
1279  if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
1280  && !item->GetParent()->IsLocked() )
1281  {
1282  aCollector.Remove( item );
1283 
1284  if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
1285  added_items.insert( item->GetParent() );
1286  }
1287 
1288  // We can't rotate both a footprint and its text in the same operation, so if
1289  // both are selected, remove the text
1290  if( item->Type() == PCB_FP_TEXT_T && aCollector.HasItem( item->GetParent() ) )
1291  aCollector.Remove( item );
1292  }
1293 
1294  for( BOARD_ITEM* item : added_items )
1295  aCollector.Append( item );
1296 
1297  sTool->FilterCollectorForGroups( aCollector );
1298  },
1299  !m_dragging && !m_isFootprintEditor /* prompt user regarding locked items */ );
1300 
1301  if( selection.Empty() )
1302  return 0;
1303 
1304  OPT<VECTOR2I> oldRefPt = boost::make_optional<VECTOR2I>( false, VECTOR2I( 0, 0 ) );
1305 
1307  oldRefPt = selection.GetReferencePoint();
1308 
1310 
1312  const int rotateAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *editFrame, aEvent );
1313 
1314  // When editing footprints, all items have the same parent
1315  if( IsFootprintEditor() )
1316  m_commit->Modify( selection.Front() );
1317 
1318  for( EDA_ITEM* item : selection )
1319  {
1320  if( !item->IsNew() && !IsFootprintEditor() )
1321  {
1322  m_commit->Modify( item );
1323 
1324  // If rotating a group, record position of all the descendants for undo
1325  if( item->Type() == PCB_GROUP_T )
1326  {
1327  static_cast<PCB_GROUP*>( item )->RunOnDescendants(
1328  [&]( BOARD_ITEM* bItem )
1329  {
1330  m_commit->Modify( bItem );
1331  });
1332  }
1333  }
1334 
1335  static_cast<BOARD_ITEM*>( item )->Rotate( refPt, rotateAngle );
1336  }
1337 
1338  if( !m_dragging )
1339  m_commit->Push( _( "Rotate" ) );
1340 
1341  if( selection.IsHover() && !m_dragging )
1343 
1345 
1346  if( m_dragging )
1348 
1349  // Restore the old reference so any mouse dragging that occurs doesn't make the selection jump
1350  // to this now invalid reference
1351  if( oldRefPt )
1352  selection.SetReferencePoint( *oldRefPt );
1353  else
1355 
1356  return 0;
1357 }
1358 
1359 
1363 static wxPoint mirrorPointX( const wxPoint& aPoint, const wxPoint& aMirrorPoint )
1364 {
1365  wxPoint mirrored = aPoint;
1366 
1367  mirrored.x -= aMirrorPoint.x;
1368  mirrored.x = -mirrored.x;
1369  mirrored.x += aMirrorPoint.x;
1370 
1371  return mirrored;
1372 }
1373 
1374 
1378 static void mirrorPadX( PAD& aPad, const wxPoint& aMirrorPoint )
1379 {
1380  if( aPad.GetShape() == PAD_SHAPE_CUSTOM )
1381  aPad.FlipPrimitives( true ); // mirror primitives left to right
1382 
1383  wxPoint tmpPt = mirrorPointX( aPad.GetPosition(), aMirrorPoint );
1384  aPad.SetPosition( tmpPt );
1385 
1386  aPad.SetX0( aPad.GetPosition().x );
1387 
1388  tmpPt = aPad.GetOffset();
1389  tmpPt.x = -tmpPt.x;
1390  aPad.SetOffset( tmpPt );
1391 
1392  auto tmpz = aPad.GetDelta();
1393  tmpz.x = -tmpz.x;
1394  aPad.SetDelta( tmpz );
1395 
1396  aPad.SetOrientation( -aPad.GetOrientation() );
1397 }
1398 
1399 
1400 int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
1401 {
1402  if( isRouterActive() )
1403  {
1404  wxBell();
1405  return 0;
1406  }
1407 
1409  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1410  {
1411  std::set<BOARD_ITEM*> added_items;
1412 
1413  // Iterate from the back so we don't have to worry about removals.
1414  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1415  {
1416  BOARD_ITEM* item = aCollector[i];
1417 
1418  // We don't operate on pads; convert them to footprint selections
1419  if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
1420  && !item->GetParent()->IsLocked() )
1421  {
1422  aCollector.Remove( item );
1423 
1424  if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
1425  added_items.insert( item->GetParent() );
1426  }
1427  }
1428 
1429  for( BOARD_ITEM* item : added_items )
1430  aCollector.Append( item );
1431 
1432  sTool->FilterCollectorForGroups( aCollector );
1433  },
1434  !m_dragging && !m_isFootprintEditor /* prompt user regarding locked items */ );
1435 
1436  if( selection.Empty() )
1437  return 0;
1438 
1440  auto refPoint = selection.GetReferencePoint();
1441  wxPoint mirrorPoint( refPoint.x, refPoint.y );
1442 
1443  // When editing footprints, all items have the same parent
1444  if( IsFootprintEditor() )
1445  m_commit->Modify( selection.Front() );
1446 
1447  for( EDA_ITEM* item : selection )
1448  {
1449  // only modify items we can mirror
1450  switch( item->Type() )
1451  {
1452  case PCB_FP_SHAPE_T:
1453  case PCB_FP_TEXT_T:
1454  case PCB_FP_ZONE_T:
1455  case PCB_PAD_T:
1456  // Only create undo entry for items on the board
1457  if( !item->IsNew() && !IsFootprintEditor() )
1458  m_commit->Modify( item );
1459 
1460  break;
1461  default:
1462  continue;
1463  }
1464 
1465  // modify each object as necessary
1466  switch( item->Type() )
1467  {
1468  case PCB_FP_SHAPE_T:
1469  {
1470  FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1471  shape->Mirror( mirrorPoint, false );
1472  break;
1473  }
1474 
1475  case PCB_FP_ZONE_T:
1476  {
1477  FP_ZONE* zone = static_cast<FP_ZONE*>( item );
1478  zone->Mirror( mirrorPoint, false );
1479  break;
1480  }
1481 
1482  case PCB_FP_TEXT_T:
1483  {
1484  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1485  text->Mirror( mirrorPoint, false );
1486  break;
1487  }
1488 
1489  case PCB_PAD_T:
1490  {
1491  PAD* pad = static_cast<PAD*>( item );
1492  mirrorPadX( *pad, mirrorPoint );
1493  break;
1494  }
1495 
1496  default:
1497  // it's likely the commit object is wrong if you get here
1498  // Unsure if PCB_GROUP_T needs special attention here.
1499  assert( false );
1500  break;
1501  }
1502  }
1503 
1504  if( !m_dragging )
1505  m_commit->Push( _( "Mirror" ) );
1506 
1507  if( selection.IsHover() && !m_dragging )
1509 
1511 
1512  if( m_dragging )
1514 
1515  return 0;
1516 }
1517 
1518 
1519 int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
1520 {
1521  if( isRouterActive() )
1522  {
1523  wxBell();
1524  return 0;
1525  }
1526 
1528  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1529  {
1530  std::set<BOARD_ITEM*> added_items;
1531 
1532  // Iterate from the back so we don't have to worry about removals.
1533  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1534  {
1535  BOARD_ITEM* item = aCollector[i];
1536 
1537  // We don't operate on pads; convert them to footprint selections
1538  if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
1539  && !item->GetParent()->IsLocked() )
1540  {
1541  aCollector.Remove( item );
1542 
1543  if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
1544  added_items.insert( item->GetParent() );
1545  }
1546 
1547  // We can't flip both a footprint and its text in the same operation, so if
1548  // both are selected, remove the text
1549  if( item->Type() == PCB_FP_TEXT_T && aCollector.HasItem( item->GetParent() ) )
1550  aCollector.Remove( item );
1551  }
1552 
1553  for( BOARD_ITEM* item : added_items )
1554  aCollector.Append( item );
1555 
1556  sTool->FilterCollectorForGroups( aCollector );
1557  },
1558  !m_dragging && !m_isFootprintEditor/* prompt user regarding locked items */ );
1559 
1560  if( selection.Empty() )
1561  return 0;
1562 
1563  OPT<VECTOR2I> oldRefPt = boost::make_optional<VECTOR2I>( false, VECTOR2I( 0, 0 ) );
1564 
1566  oldRefPt = selection.GetReferencePoint();
1567 
1569 
1570  // Flip around the anchor for footprints, and the bounding box center for board items
1571  VECTOR2I refPt = IsFootprintEditor() ? VECTOR2I( 0, 0 ) : selection.GetCenter();
1572 
1573  // If only one item selected, flip around the selection or item anchor point (instead
1574  // of the bounding box center) to avoid moving the item anchor
1575  if( selection.GetSize() == 1 )
1576  {
1578  refPt = selection.GetReferencePoint();
1579  else
1580  refPt = static_cast<BOARD_ITEM*>( selection.GetItem( 0 ) )->GetPosition();
1581  }
1582 
1583  bool leftRight = frame()->Settings().m_FlipLeftRight;
1584 
1585  // When editing footprints, all items have the same parent
1586  if( IsFootprintEditor() )
1587  m_commit->Modify( selection.Front() );
1588 
1589  for( EDA_ITEM* item : selection )
1590  {
1591  if( !item->IsNew() && !IsFootprintEditor() )
1592  m_commit->Modify( item );
1593 
1594  if( item->Type() == PCB_GROUP_T )
1595  {
1596  static_cast<PCB_GROUP*>( item )->RunOnDescendants( [&]( BOARD_ITEM* bItem )
1597  {
1598  m_commit->Modify( bItem );
1599  });
1600  }
1601 
1602  static_cast<BOARD_ITEM*>( item )->Flip( refPt, leftRight );
1603  }
1604 
1605  if( !m_dragging )
1606  m_commit->Push( _( "Change Side / Flip" ) );
1607 
1608  if( selection.IsHover() && !m_dragging )
1610 
1612 
1613  if( m_dragging )
1615 
1616  // Restore the old reference so any mouse dragging that occurs doesn't make the selection jump
1617  // to this now invalid reference
1618  if( oldRefPt )
1619  selection.SetReferencePoint( *oldRefPt );
1620  else
1622 
1623  return 0;
1624 }
1625 
1626 
1627 int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
1628 {
1629  if( isRouterActive() )
1630  {
1631  wxBell();
1632  return 0;
1633  }
1634 
1635  std::vector<BOARD_ITEM*> lockedItems;
1636  Activate();
1637 
1638  // get a copy instead of reference (as we're going to clear the selection before removing items)
1639  PCB_SELECTION selectionCopy;
1642 
1643  // If we are in a "Cut" operation, then the copied selection exists already and we want to
1644  // delete exactly that; no more, no fewer. Any filtering for locked items must be done in
1645  // the copyToClipboard() routine.
1646  if( isCut )
1647  {
1648  selectionCopy = m_selectionTool->GetSelection();
1649  }
1650  else
1651  {
1652  selectionCopy = m_selectionTool->RequestSelection(
1653  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1654  {
1655  },
1656  !m_isFootprintEditor /* prompt user regarding locked items */ );
1657  }
1658 
1659  bool isHover = selectionCopy.IsHover();
1660 
1661  // in "alternative" mode, deletion is not just a simple list of selected items,
1662  // it removes whole tracks, not just segments
1663  if( isAlt && isHover
1664  && ( selectionCopy.HasType( PCB_TRACE_T ) || selectionCopy.HasType( PCB_VIA_T ) ) )
1665  {
1667  }
1668 
1669  if( selectionCopy.Empty() )
1670  return 0;
1671 
1672  // As we are about to remove items, they have to be removed from the selection first
1674 
1675  for( EDA_ITEM* item : selectionCopy )
1676  {
1677  PCB_GROUP* parentGroup = static_cast<BOARD_ITEM*>( item )->GetParentGroup();
1678 
1679  if( parentGroup )
1680  {
1681  m_commit->Modify( parentGroup );
1682  parentGroup->RemoveItem( static_cast<BOARD_ITEM*>( item ) );
1683  }
1684 
1685  switch( item->Type() )
1686  {
1687  case PCB_FP_TEXT_T:
1688  {
1689  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1690  FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1691 
1692  if( text->GetType() == FP_TEXT::TEXT_is_DIVERS )
1693  {
1694  m_commit->Modify( parent );
1695  getView()->Remove( text );
1696  parent->Remove( text );
1697  }
1698  }
1699  break;
1700 
1701  case PCB_PAD_T:
1702  {
1703  PAD* pad = static_cast<PAD*>( item );
1704  FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1705 
1706  m_commit->Modify( parent );
1707  getView()->Remove( pad );
1708  parent->Remove( pad );
1709  }
1710  break;
1711 
1712  case PCB_FP_ZONE_T:
1713  {
1714  FP_ZONE* zone = static_cast<FP_ZONE*>( item );
1715  FOOTPRINT* parent = static_cast<FOOTPRINT*>( item->GetParent() );
1716 
1717  m_commit->Modify( parent );
1718  getView()->Remove( zone );
1719  parent->Remove( zone );
1720  }
1721  break;
1722 
1723  case PCB_ZONE_T:
1724  // We process the zones special so that cutouts can be deleted when the delete tool
1725  // is called from inside a cutout when the zone is selected.
1726  {
1727  // Only interact with cutouts when deleting and a single item is selected
1728  if( !isCut && selectionCopy.GetSize() == 1 )
1729  {
1731  ZONE* zone = static_cast<ZONE*>( item );
1732 
1733  int outlineIdx, holeIdx;
1734 
1735  if( zone->HitTestCutout( curPos, &outlineIdx, &holeIdx ) )
1736  {
1737  // Remove the cutout
1738  m_commit->Modify( zone );
1739  zone->RemoveCutout( outlineIdx, holeIdx );
1740 
1741  std::vector<ZONE*> toFill;
1742  toFill.emplace_back( zone );
1743 
1744  // Fill the modified zone
1745  ZONE_FILLER filler( board(), m_commit.get() );
1746  filler.InstallNewProgressReporter( frame(), _( "Fill Zone" ), 4 );
1747 
1748  if( !filler.Fill( toFill ) )
1749  {
1750  m_commit->Revert();
1751  return 1;
1752  }
1753 
1754  // Update the display
1755  zone->HatchBorder();
1756  canvas()->Refresh();
1757 
1758  // Restore the selection on the original zone
1760 
1761  break;
1762  }
1763  }
1764 
1765  // Remove the entire zone otherwise
1766  m_commit->Remove( item );
1767  }
1768  break;
1769 
1770  case PCB_GROUP_T:
1771  {
1772  PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
1773 
1774  auto removeItem = [&]( BOARD_ITEM* bItem )
1775  {
1776  if( bItem->GetParent() && bItem->GetParent()->Type() == PCB_FOOTPRINT_T )
1777  {
1778  // Silently ignore delete of Reference or Value if they happen to be in
1779  // group.
1780  if( bItem->Type() == PCB_FP_TEXT_T )
1781  {
1782  if( static_cast<FP_TEXT*>( bItem )->GetType() != FP_TEXT::TEXT_is_DIVERS )
1783  return;
1784  }
1785 
1786  m_commit->Modify( bItem->GetParent() );
1787  getView()->Remove( bItem );
1788  bItem->GetParent()->Remove( bItem );
1789  }
1790  else
1791  {
1792  m_commit->Remove( bItem );
1793  }
1794  };
1795 
1796  removeItem( group );
1797 
1798  group->RunOnDescendants( [&]( BOARD_ITEM* aDescendant )
1799  {
1800  removeItem( aDescendant );
1801  });
1802  }
1803  break;
1804 
1805  default:
1806  m_commit->Remove( item );
1807  break;
1808  }
1809  }
1810 
1811  // If the entered group has been emptied then leave it.
1812  PCB_GROUP* enteredGroup = m_selectionTool->GetEnteredGroup();
1813 
1814  if( enteredGroup && enteredGroup->GetItems().empty() )
1816 
1817  if( isCut )
1818  m_commit->Push( _( "Cut" ) );
1819  else
1820  m_commit->Push( _( "Delete" ) );
1821 
1822  return 0;
1823 }
1824 
1825 
1826 int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
1827 {
1828  if( isRouterActive() )
1829  {
1830  wxBell();
1831  return 0;
1832  }
1833 
1835  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1836  {
1837  std::set<BOARD_ITEM*> added_items;
1838 
1839  // Iterate from the back so we don't have to worry about removals.
1840  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1841  {
1842  BOARD_ITEM* item = aCollector[i];
1843 
1844  if( item->Type() == PCB_MARKER_T )
1845  aCollector.Remove( item );
1846 
1847  // We don't operate on pads; convert them to footprint selections
1848  if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
1849  && !item->GetParent()->IsLocked() )
1850  {
1851  aCollector.Remove( item );
1852 
1853  if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
1854  added_items.insert( item->GetParent() );
1855  }
1856  }
1857 
1858  for( BOARD_ITEM* item : added_items )
1859  aCollector.Append( item );
1860 
1861  sTool->FilterCollectorForGroups( aCollector );
1862  },
1863  !m_isFootprintEditor /* prompt user regarding locked items */ );
1864 
1865  if( selection.Empty() )
1866  return 0;
1867 
1868  wxPoint translation;
1869  double rotation;
1870  ROTATION_ANCHOR rotationAnchor = selection.Size() > 1 ? ROTATE_AROUND_SEL_CENTER
1872 
1873  // TODO: Implement a visible bounding border at the edge
1874  auto sel_box = selection.GetBoundingBox();
1875 
1876  DIALOG_MOVE_EXACT dialog( frame(), translation, rotation, rotationAnchor, sel_box );
1877  int ret = dialog.ShowModal();
1878 
1879  if( ret == wxID_OK )
1880  {
1881  VECTOR2I rp = selection.GetCenter();
1882  wxPoint selCenter( rp.x, rp.y );
1883 
1884  // Make sure the rotation is from the right reference point
1885  selCenter += translation;
1886 
1887  // When editing footprints, all items have the same parent
1888  if( IsFootprintEditor() )
1889  m_commit->Modify( selection.Front() );
1890 
1891  for( EDA_ITEM* selItem : selection )
1892  {
1893  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selItem );
1894 
1895  if( !item->IsNew() && !IsFootprintEditor() )
1896  {
1897  m_commit->Modify( item );
1898 
1899  if( item->Type() == PCB_GROUP_T )
1900  {
1901  PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
1902 
1903  group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
1904  {
1905  m_commit->Modify( bItem );
1906  });
1907  }
1908  }
1909 
1910  item->Move( translation );
1911 
1912  switch( rotationAnchor )
1913  {
1915  item->Rotate( item->GetPosition(), rotation );
1916  break;
1918  item->Rotate( selCenter, rotation );
1919  break;
1921  item->Rotate( (wxPoint) frame()->GetScreen()->m_LocalOrigin, rotation );
1922  break;
1924  item->Rotate( board()->GetDesignSettings().m_AuxOrigin, rotation );
1925  break;
1926  }
1927 
1928  if( !m_dragging )
1929  getView()->Update( item );
1930  }
1931 
1932  m_commit->Push( _( "Move exact" ) );
1933 
1934  if( selection.IsHover() )
1936 
1938 
1939  if( m_dragging )
1941  }
1942 
1943  return 0;
1944 }
1945 
1946 
1947 int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
1948 {
1949  if( isRouterActive() )
1950  {
1951  wxBell();
1952  return 0;
1953  }
1954 
1955  bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement );
1956 
1957  // Be sure that there is at least one item that we can modify
1959  []( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
1960  {
1961  std::set<BOARD_ITEM*> added_items;
1962 
1963  // Iterate from the back so we don't have to worry about removals.
1964  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
1965  {
1966  BOARD_ITEM* item = aCollector[i];
1967 
1968  // We don't operate on pads; convert them to footprint selections
1969  if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
1970  && !item->GetParent()->IsLocked() )
1971  {
1972  aCollector.Remove( item );
1973 
1974  if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
1975  added_items.insert( item->GetParent() );
1976  }
1977  }
1978 
1979  for( BOARD_ITEM* item : added_items )
1980  aCollector.Append( item );
1981 
1982  sTool->FilterCollectorForGroups( aCollector );
1983  } );
1984 
1985  if( selection.Empty() )
1986  return 0;
1987 
1988  // we have a selection to work on now, so start the tool process
1989  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1990 
1991  // If the selection was given a hover, we do not keep the selection after completion
1992  bool is_hover = selection.IsHover();
1993 
1994  std::vector<BOARD_ITEM*> new_items;
1995  new_items.reserve( selection.Size() );
1996 
1997 
1998  // Each selected item is duplicated and pushed to new_items list
1999  // Old selection is cleared, and new items are then selected.
2000  for( EDA_ITEM* item : selection )
2001  {
2002  BOARD_ITEM* dupe_item = nullptr;
2003  BOARD_ITEM* orig_item = static_cast<BOARD_ITEM*>( item );
2004 
2005  if( m_isFootprintEditor )
2006  {
2007  FOOTPRINT* parentFootprint = editFrame->GetBoard()->GetFirstFootprint();
2008  dupe_item = parentFootprint->DuplicateItem( orig_item );
2009 
2010  if( increment && item->Type() == PCB_PAD_T
2011  && PAD_NAMING::PadCanHaveName( *static_cast<PAD*>( dupe_item ) ) )
2012  {
2013  PAD_TOOL* padTool = m_toolMgr->GetTool<PAD_TOOL>();
2014  wxString padName = padTool->GetLastPadName();
2015  padName = parentFootprint->GetNextPadName( padName );
2016  padTool->SetLastPadName( padName );
2017  static_cast<PAD*>( dupe_item )->SetName( padName );
2018  }
2019  }
2020  else if( orig_item->GetParent() && orig_item->GetParent()->Type() == PCB_FOOTPRINT_T )
2021  {
2022  FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( orig_item->GetParent() );
2023 
2024  m_commit->Modify( parentFootprint );
2025  dupe_item = parentFootprint->DuplicateItem( orig_item, true /* add to parent */ );
2026  }
2027  else
2028  {
2029  switch( orig_item->Type() )
2030  {
2031  case PCB_FOOTPRINT_T:
2032  case PCB_TEXT_T:
2033  case PCB_SHAPE_T:
2034  case PCB_TRACE_T:
2035  case PCB_VIA_T:
2036  case PCB_ZONE_T:
2037  case PCB_TARGET_T:
2038  case PCB_DIM_ALIGNED_T:
2039  case PCB_DIM_CENTER_T:
2040  case PCB_DIM_ORTHOGONAL_T:
2041  case PCB_DIM_LEADER_T:
2042  dupe_item = orig_item->Duplicate();
2043  break;
2044 
2045  case PCB_GROUP_T:
2046  dupe_item = static_cast<PCB_GROUP*>( orig_item )->DeepDuplicate();
2047  break;
2048 
2049  default:
2050  // Silently drop other items (such as footprint texts) from duplication
2051  break;
2052  }
2053  }
2054 
2055  if( dupe_item )
2056  {
2057  if( dupe_item->Type() == PCB_GROUP_T )
2058  {
2059  static_cast<PCB_GROUP*>( dupe_item )->RunOnDescendants(
2060  [&]( BOARD_ITEM* bItem )
2061  {
2062  m_commit->Add( bItem );
2063  });
2064  }
2065 
2066  // Clear the selection flag here, otherwise the PCB_SELECTION_TOOL
2067  // will not properly select it later on
2068  dupe_item->ClearSelected();
2069 
2070  new_items.push_back( dupe_item );
2071  m_commit->Add( dupe_item );
2072  }
2073  }
2074 
2075  // Clear the old selection first
2077 
2078  // Select the new items
2079  m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &new_items );
2080 
2081  // record the new items as added
2082  if( !selection.Empty() )
2083  {
2084  editFrame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ),
2085  (int) new_items.size() ) );
2086 
2087  // If items were duplicated, pick them up
2088  // this works well for "dropping" copies around and pushes the commit
2090  Move( evt );
2091 
2092  // After moving the new items, we need to refresh the group and view flags
2094 
2095  if( !is_hover )
2096  m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &new_items );
2097  }
2098 
2099  return 0;
2100 }
2101 
2102 
2104 {
2105  if( isRouterActive() )
2106  {
2107  wxBell();
2108  return 0;
2109  }
2110 
2111  // Be sure that there is at least one item that we can modify
2113  []( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2114  {
2115  std::set<BOARD_ITEM*> added_items;
2116 
2117  // Iterate from the back so we don't have to worry about removals.
2118  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
2119  {
2120  BOARD_ITEM* item = aCollector[i];
2121 
2122  // We don't operate on pads; convert them to footprint selections
2123  if( !sTool->IsFootprintEditor() && item->Type() == PCB_PAD_T
2124  && !item->GetParent()->IsLocked() )
2125  {
2126  aCollector.Remove( item );
2127 
2128  if( item->GetParent() && !aCollector.HasItem( item->GetParent() ) )
2129  added_items.insert( item->GetParent() );
2130  }
2131  }
2132 
2133  for( BOARD_ITEM* item : added_items )
2134  aCollector.Append( item );
2135 
2136  sTool->FilterCollectorForGroups( aCollector );
2137  } );
2138 
2139  if( selection.Empty() )
2140  return 0;
2141 
2142  // we have a selection to work on now, so start the tool process
2143  PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
2144  ARRAY_CREATOR array_creator( *editFrame, m_isFootprintEditor, selection );
2145  array_creator.Invoke();
2146 
2147  return 0;
2148 }
2149 
2150 
2152  PCB_SELECTION_TOOL* sTool )
2153 {
2154  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
2155  {
2156  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( aCollector[i] );
2157 
2158  if( item->Type() != PCB_PAD_T )
2159  aCollector.Remove( i );
2160  }
2161 }
2162 
2163 
2165  PCB_SELECTION_TOOL* sTool )
2166 {
2167  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
2168  {
2169  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( aCollector[i] );
2170 
2171  if( item->Type() != PCB_FOOTPRINT_T )
2172  aCollector.Remove( i );
2173  }
2174 }
2175 
2176 
2178 {
2179  if( m_dragging && aSelection.HasReferencePoint() )
2180  return false;
2181 
2182  // When there is only one item selected, the reference point is its position...
2183  if( aSelection.Size() == 1 )
2184  {
2185  auto item = static_cast<BOARD_ITEM*>( aSelection.Front() );
2186  auto pos = item->GetPosition();
2187  aSelection.SetReferencePoint( VECTOR2I( pos.x, pos.y ) );
2188  }
2189  // ...otherwise modify items with regard to the grid-snapped cursor position
2190  else
2191  {
2193  aSelection.SetReferencePoint( m_cursor );
2194  }
2195 
2196  return true;
2197 }
2198 
2199 
2200 bool EDIT_TOOL::pickReferencePoint( const wxString& aTooltip, const wxString& aSuccessMessage,
2201  const wxString& aCanceledMessage, VECTOR2I& aReferencePoint )
2202 {
2204  OPT<VECTOR2I> pickedPoint;
2205  bool done = false;
2206 
2207  m_statusPopup->SetText( aTooltip );
2208 
2209  picker->SetClickHandler(
2210  [&]( const VECTOR2D& aPoint ) -> bool
2211  {
2212  pickedPoint = aPoint;
2213 
2214  if( !aSuccessMessage.empty() )
2215  {
2216  m_statusPopup->SetText( aSuccessMessage );
2217  m_statusPopup->Expire( 800 );
2218  }
2219  else
2220  {
2221  m_statusPopup->Hide();
2222  }
2223 
2224  return false; // we don't need any more points
2225  } );
2226 
2227  picker->SetMotionHandler(
2228  [&]( const VECTOR2D& aPos )
2229  {
2230  m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
2231  } );
2232 
2233  picker->SetCancelHandler(
2234  [&]()
2235  {
2236  if( !aCanceledMessage.empty() )
2237  {
2238  m_statusPopup->SetText( aCanceledMessage );
2239  m_statusPopup->Expire( 800 );
2240  }
2241  else
2242  {
2243  m_statusPopup->Hide();
2244  }
2245  } );
2246 
2247  picker->SetFinalizeHandler(
2248  [&]( const int& aFinalState )
2249  {
2250  done = true;
2251  } );
2252 
2253  m_statusPopup->Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
2254  m_statusPopup->Popup();
2255 
2256  std::string tool = "";
2257  m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
2258 
2259  while( !done )
2260  {
2261  // Pass events unless we receive a null event, then we must shut down
2262  if( TOOL_EVENT* evt = Wait() )
2263  evt->SetPassEvent();
2264  else
2265  break;
2266  }
2267 
2268  // Ensure statusPopup is hidden after use and before deleting it:
2269  m_statusPopup->Hide();
2270 
2271  if( pickedPoint.is_initialized() )
2272  aReferencePoint = pickedPoint.get();
2273 
2274  return pickedPoint.is_initialized();
2275 }
2276 
2277 
2279 {
2280  std::string tool = "pcbnew.InteractiveEdit.selectReferencePoint";
2281  CLIPBOARD_IO io;
2282  PCB_GRID_HELPER grid( m_toolMgr, getEditFrame<PCB_BASE_EDIT_FRAME>()->GetMagneticItemsSettings() );
2283 
2284  frame()->PushTool( tool );
2285  Activate();
2286 
2288  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
2289  {
2290  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
2291  {
2292  BOARD_ITEM* item = aCollector[i];
2293 
2294  // We can't copy both a footprint and its text in the same operation, so if
2295  // both are selected, remove the text
2296  if( item->Type() == PCB_FP_TEXT_T && aCollector.HasItem( item->GetParent() ) )
2297  aCollector.Remove( item );
2298  }
2299  },
2300  aEvent.IsAction( &ACTIONS::cut ) && !m_isFootprintEditor /* prompt user regarding locked items */ );
2301 
2302  if( !selection.Empty() )
2303  {
2304  std::vector<BOARD_ITEM*> items;
2305 
2306  for( EDA_ITEM* item : selection )
2307  items.push_back( static_cast<BOARD_ITEM*>( item ) );
2308 
2309  VECTOR2I refPoint;
2310 
2311  if( aEvent.IsAction( &PCB_ACTIONS::copyWithReference ) )
2312  {
2313  if( !pickReferencePoint( _( "Select reference point for the copy..." ),
2314  _( "Selection copied" ),
2315  _( "Copy cancelled" ),
2316  refPoint ) )
2317  return 0;
2318  }
2319  else
2320  {
2321  refPoint = grid.BestDragOrigin( getViewControls()->GetCursorPosition(), items );
2322  }
2323 
2324  selection.SetReferencePoint( refPoint );
2325 
2326  io.SetBoard( board() );
2328  frame()->SetStatusText( _( "Selection copied" ) );
2329  }
2330 
2331  frame()->PopTool( tool );
2332 
2333  return 0;
2334 }
2335 
2336 
2338 {
2339  if( !copyToClipboard( aEvent ) )
2340  {
2341  // N.B. Setting the CUT flag prevents lock filtering as we only want to delete the items
2342  // that were copied to the clipboard, no more, no fewer. Filtering for locked item, if
2343  // any will be done in the copyToClipboard() routine
2344  TOOL_EVENT evt( aEvent.Category(), aEvent.Action(), TOOL_ACTION_SCOPE::AS_GLOBAL );
2346  Remove( evt );
2347  }
2348 
2349  return 0;
2350 }
2351 
2352 
2354 {
2356  Go( &EDIT_TOOL::Move, PCB_ACTIONS::move.MakeEvent() );
2357  Go( &EDIT_TOOL::Drag, PCB_ACTIONS::drag45Degree.MakeEvent() );
2359  Go( &EDIT_TOOL::Rotate, PCB_ACTIONS::rotateCw.MakeEvent() );
2360  Go( &EDIT_TOOL::Rotate, PCB_ACTIONS::rotateCcw.MakeEvent() );
2361  Go( &EDIT_TOOL::Flip, PCB_ACTIONS::flip.MakeEvent() );
2362  Go( &EDIT_TOOL::Remove, ACTIONS::doDelete.MakeEvent() );
2363  Go( &EDIT_TOOL::Remove, PCB_ACTIONS::deleteFull.MakeEvent() );
2367  Go( &EDIT_TOOL::Duplicate, ACTIONS::duplicate.MakeEvent() );
2370  Go( &EDIT_TOOL::Mirror, PCB_ACTIONS::mirror.MakeEvent() );
2373 
2374  Go( &EDIT_TOOL::copyToClipboard, ACTIONS::copy.MakeEvent() );
2376  Go( &EDIT_TOOL::cutToClipboard, ACTIONS::cut.MakeEvent() );
2377 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:148
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:70
long long GetValue()
Returns the value in internal units.
int Length() const
Return the length (this).
Definition: seg.h:340
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:63
VECTOR2I GetReferencePoint() const
Definition: selection.h:259
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:93
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 setTransitions() override
< Set up handlers for various events.
Definition: edit_tool.cpp:2353
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
BOARD_ITEM * DuplicateItem(const BOARD_ITEM *aItem, bool aAddToFootprint=false)
Duplicate a given item within the footprint, optionally adding it to the board.
Definition: footprint.cpp:1601
VECTOR2I m_cursor
Definition: edit_tool.h:193
void ClearReferencePoint()
Definition: selection.h:269
void FlipPrimitives(bool aFlipLeftRight)
Flip (mirror) the primitives left to right or top to bottom, around the anchor position in custom pad...
Definition: pcbnew/pad.cpp:647
bool IsCurrentTool(const TOOL_ACTION &aAction) const
void SetOffset(const wxPoint &aOffset)
Definition: pad.h:248
Definition: track.h:343
virtual wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: track.h:301
int DragArcTrack(const TOOL_EVENT &aEvent)
Drag-resize an arc (and change end points of connected straight segments).
Definition: edit_tool.cpp:291
int Properties(const TOOL_EVENT &aEvent)
Display properties window for the selected object.
Definition: edit_tool.cpp:1212
int Rotate(const TOOL_EVENT &aEvent)
Rotate currently selected items.
Definition: edit_tool.cpp:1258
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:96
static TOOL_ACTION deleteFull
Definition: pcb_actions.h:131
class ALIGNED_DIMENSION, a linear dimension (graphic item)
Definition: typeinfo.h:100
class LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
Definition: zone.cpp:786
bool IsHover() const
Definition: selection.h:72
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:223
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
static const KICAD_T Tracks[]
A scan list for only TRACKs.
Definition: collectors.h:299
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.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
BOARD * board() const
static TOOL_ACTION editFpInFpEditor
Definition: pcb_actions.h:344
static TOOL_ACTION pageSettings
Definition: actions.h:59
REMOVE_FLAGS
Definition: actions.h:199
static TOOL_ACTION changeTrackWidth
Update selected tracks & vias to the current track & via dimensions.
Definition: pcb_actions.h:115
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:194
This file is part of the common library.
static TOOL_ACTION doDelete
Definition: actions.h:75
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
void SetEnd(const wxPoint &aEnd)
Definition: track.h:112
bool HasType(KICAD_T aType) const
Checks if there is at least one item of requested kind.
Definition: selection.h:233
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
std::unique_ptr< BOARD_COMMIT > m_commit
Definition: edit_tool.h:191
void ClearSelected()
Definition: eda_item.h:181
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
const wxPoint & GetStart() const
Definition: track.h:116
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
TOOL_ACTIONS Action() const
These give a tool a method of informing the TOOL_MANAGER that a particular event should be passed on ...
Definition: tool_event.h:251
static SELECTION_CONDITION OnlyTypes(const KICAD_T aTypes[])
Create a functor that tests if the selected items are only of given types.
class CENTER_DIMENSION, a center point marking (graphic item)
Definition: typeinfo.h:102
int ChangeTrackWidth(const TOOL_EVENT &aEvent)
Definition: edit_tool.cpp:939
virtual NETCLASS * GetNetClass() const
Return the NETCLASS for this item.
virtual VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
Definition: selection.h:139
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
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:142
Tool is invoked after being inactive.
Definition: tool_base.h:80
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
ITER end()
Definition: selection.h:63
virtual void OnEditItemRequest(BOARD_ITEM *aItem)=0
Install the corresponding dialog editor for the given item.
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:351
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:121
Tool relating to pads and pad settings.
Definition: pad_tool.h:35
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:520
TOOL_MENU & GetToolMenu()
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:141
static TOOL_ACTION selectConnection
Select tracks between junctions or expands an existing selection to pads or the entire connection.
Definition: pcb_actions.h:78
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
static TOOL_ACTION getAndPlace
Find an item and start moving.
Definition: pcb_actions.h:463
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:141
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:248
static TOOL_ACTION mirror
Mirroring of selected items.
Definition: pcb_actions.h:112
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
static TOOL_ACTION changeFootprint
Definition: pcb_actions.h:324
static void mirrorPadX(PAD &aPad, const wxPoint &aMirrorPoint)
Mirror a pad in the vertical axis passing through a point (mirror left to right)
Definition: edit_tool.cpp:1378
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
bool HitTestDrawingSheetItems(KIGFX::VIEW *aView, const wxPoint &aPosition)
PAD_SHAPE_T GetShape() const
Definition: pad.h:169
PCB_GROUP * GetEnteredGroup()
Apply the SELECTION_FILTER_OPTIONS to a collection of items.
static TOOL_ACTION updateFootprint
Definition: pcb_actions.h:322
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition: seg.h:193
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:100
PCB_SELECTION_TOOL * m_selectionTool
Definition: edit_tool.h:190
void UndoRedoBlock(bool aBlock=true)
Enable/disable undo and redo operations.
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
virtual wxPoint GetPosition() const
Definition: eda_item.h:301
void SetDelta(const wxSize &aSize)
Definition: pad.h:238
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.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
void SetBoard(BOARD *aBoard)
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
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).
void Mirror(const wxPoint &aCentre, bool aMirrorAroundXAxis)
Mirror text position in footprint editing the text itself is not mirrored, and the layer not modified...
Definition: fp_text.cpp:173
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:115
void SetCurrentCursor(KICURSOR cursor)
Set the current cursor shape for this panel.
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:214
CIRCLE & ConstructFromTanTanPt(const SEG &aLineA, const SEG &aLineB, const VECTOR2I &aP)
Constructs this circle such that it is tangent to the given segmetns and passes through the given poi...
Definition: circle.cpp:51
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
int Mirror(const TOOL_EVENT &aEvent)
Mirror the current selection.
Definition: edit_tool.cpp:1400
PADS & Pads()
Definition: footprint.h:164
void InstallNewProgressReporter(wxWindow *aParent, const wxString &aTitle, int aNumPhases)
Definition: zone_filler.cpp:70
const VC_SETTINGS & GetSettings() const
Apply VIEW_CONTROLS settings from an object.
bool IsNew() const
Definition: eda_item.h:168
void SetWidth(int aWidth)
Definition: track.h:109
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:70
static TOOL_ACTION moveExact
Activation of the exact move tool.
Definition: pcb_actions.h:124
int cutToClipboard(const TOOL_EVENT &aEvent)
Cut the current selection to the clipboard by formatting it as a fake pcb see #AppendBoardFromClipboa...
Definition: edit_tool.cpp:2337
bool pickReferencePoint(const wxString &aTooltip, const wxString &aSuccessMessage, const wxString &aCanceledMessage, VECTOR2I &aReferencePoint)
Definition: edit_tool.cpp:2200
DS_PROXY_VIEW_ITEM * GetDrawingSheet() const
static TOOL_ACTION pickerTool
Definition: actions.h:158
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:105
static TOOL_ACTION filletTracks
Fillet (i.e. adds an arc tangent to) all selected straight tracks by a user defined radius.
Definition: pcb_actions.h:118
PCB_BASE_EDIT_FRAME * frame() const
bool HitTestCutout(const VECTOR2I &aRefPos, int *aOutlineIdx=nullptr, int *aHoleIdx=nullptr) const
Tests if the given point is contained within a cutout of the zone.
Definition: zone.cpp:518
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
void SetParameter(T aParam)
Set a non-standard parameter assigned to the event.
Definition: tool_event.h:461
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:87
PCB_SELECTION & GetSelection()
Return the set of currently selected items.
ITER begin()
Definition: selection.h:62
static TOOL_ACTION copy
Definition: actions.h:70
int Flip(const TOOL_EVENT &aEvent)
Rotate currently selected items.
Definition: edit_tool.cpp:1519
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:264
static TOOL_ACTION duplicateIncrement
Activation of the duplication tool with incrementing (e.g. pad number)
Definition: pcb_actions.h:127
const wxPoint & GetOffset() const
Definition: pad.h:249
bool isInteractiveDragEnabled() const
Definition: edit_tool.cpp:227
int GetAndPlace(const TOOL_EVENT &aEvent)
Definition: edit_tool.cpp:181
VECTOR2I LineProject(const VECTOR2I &aP) const
Compute the perpendicular projection point of aP on a line passing through ends of the segment.
Definition: seg.h:389
static TOOL_ACTION rotateCw
Rotation of selected objects.
Definition: pcb_actions.h:105
LSET is a set of PCB_LAYER_IDs.
const wxPoint & GetMid() const
Definition: track.h:292
const PCB_SELECTION & selection() const
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:202
void SetLastPadName(const wxString &aPadName)
Definition: pad_tool.h:63
FOOTPRINT * GetFirstFootprint() const
Gets the first footprint on the board or nullptr.
Definition: board.h:380
#define NULL
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:341
An extension of WX_TEXT_ENTRY_DIALOG that uses UNIT_BINDER to request a dimension (e....
const VECTOR2I GetArcMid(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aMinArcAngle=true)
Returns the middle point of an arc, half-way between aStart and aEnd.
Definition: trigo.cpp:162
bool ApproxParallel(const SEG &aSeg) const
Definition: seg.h:280
int doMoveSelection(TOOL_EVENT aEvent, bool aPickReference=false)
Definition: edit_tool.cpp:606
wxString GetLastPadName() const
Definition: pad_tool.h:62
bool updateModificationPoint(PCB_SELECTION &aSelection)
Definition: edit_tool.cpp:2177
bool m_dragging
Definition: edit_tool.h:192
virtual EDA_RECT GetBoundingBox() const
Definition: selection.h:180
void HatchBorder()
Function HatchBorder computes the hatch lines depending on the hatch parameters and stores it in the ...
Definition: zone.cpp:923
TEXT_TYPE GetType() const
Definition: fp_text.h:141
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
virtual void Move(const wxPoint &aMoveVector)
Move this object.
Definition: board_item.h:277
virtual void PopTool(const std::string &actionName)
int ShowQuasiModal()
void AddItemToSel(BOARD_ITEM *aItem, bool aQuietMode=false)
Select all items on the board.
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:443
bool PadCanHaveName(const PAD &aPad)
Check if a pad should be named.
Definition: pad_naming.cpp:26
const VECTOR2I & GetP0() const
Definition: shape_arc.h:95
void SetIcon(const BITMAP_OPAQUE *aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:71
Generic, UI-independent tool event.
Definition: tool_event.h:173
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:46
static TOOL_ACTION createArray
Tool for creating an array of objects.
Definition: pcb_actions.h:387
static const int MIN_PRECISION_IU
This is the minimum precision for all the points in a shape.
Definition: shape.h:122
bool Contains(EDA_ITEM *aItem) const
Definition: selection.h:114
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition: picker_tool.h:80
FOOTPRINT * footprint() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:414
static TOOL_ACTION cut
Definition: actions.h:69
bool ToolStackIsEmpty()
Definition: tools_holder.h:117
bool HasItem(const EDA_ITEM *aItem) const
Tests if aItem has already been collected.
Definition: collector.h:203
int FilletTracks(const TOOL_EVENT &aEvent)
Fillet (i.e.
Definition: edit_tool.cpp:1009
bool Init() override
Init() is called once upon a registration of the tool.
Definition: edit_tool.cpp:100
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.h:422
An interface for classes handling user events controlling the view behavior such as zooming,...
int MoveWithReference(const TOOL_EVENT &aEvent)
Move an item but with a reference point selected first.
Definition: edit_tool.cpp:592
int Drag(const TOOL_EVENT &aEvent)
Invoke the PNS router to drag tracks or do an offline resizing of an arc track if a single arc track ...
Definition: edit_tool.cpp:243
void SetX0(int x)
Definition: pad.h:229
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
bool RemoveItem(BOARD_ITEM *aItem)
Remove item from group.
Definition: pcb_group.cpp:50
std::unique_ptr< STATUS_TEXT_POPUP > m_statusPopup
Definition: edit_tool.h:195
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, std::vector< BOARD_ITEM * > &aItem)
int Radius
Public to make access simpler.
Definition: circle.h:36
class ZONE, a copper pour area
Definition: typeinfo.h:105
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:217
Class Circle Represents basic circle geometry with utility geometry functions.
Definition: circle.h:33
virtual void Rotate(const wxPoint &aRotCentre, double aAngle)
Rotate this object.
Definition: board_item.h:294
int GetuViaDiameter() const
Definition: netclass.h:140
void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invoke a function on all descendants of the group.
Definition: pcb_group.cpp:324
Global action (toolbar/main menu event, global shortcut)
Definition: tool_event.h:151
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.h:106
void ExitGroup(bool aSelectGroup=false)
Leave the currently entered group.
static TOOL_ACTION copyWithReference
copy command with manual reference point selection
Definition: pcb_actions.h:102
void SetMid(const wxPoint &aMid)
Definition: track.h:291
ROTATION_ANCHOR
bool m_isFootprintEditor
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:209
static TOOL_ACTION hideDynamicRatsnest
Definition: pcb_actions.h:456
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
Definition: track.cpp:894
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
static void PadFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type PCB_PAD_T.
Definition: edit_tool.cpp:2151
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...
int Move(const TOOL_EVENT &aEvent)
Main loop in which events are handled.
Definition: edit_tool.cpp:580
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:122
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:104
static TOOL_ACTION inlineBreakTrack
Breaks track when router is not activated.
Definition: pcb_actions.h:139
Generic tool for picking an item.
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Definition: edit_tool.cpp:76
BOARD * GetBoard()
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:101
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:69
static TOOL_ACTION rotateCcw
Definition: pcb_actions.h:106
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
const wxSize & GetDelta() const
Definition: pad.h:239
int MoveExact(const TOOL_EVENT &aEvent)
Invoke a dialog box to allow moving of the item by an exact amount.
Definition: edit_tool.cpp:1826
Definition: seg.h:41
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:471
int Remove(const TOOL_EVENT &aEvent)
Delete currently selected items.
Definition: edit_tool.cpp:1627
static ROUTER * theRouter
Definition: pns_router.cpp:59
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:109
SPECIAL_TOOLS_CONTEXT_MENU(TOOL_INTERACTIVE *aTool)
Definition: edit_tool.cpp:87
static const KICAD_T DraggableItems[]
A scan list for items that can be dragged.
Definition: collectors.h:314
virtual bool IsLocked() const
Definition: board_item.h:249
bool invokeInlineRouter(int aDragMode)
Definition: edit_tool.cpp:199
bool HasReferencePoint() const
Definition: selection.h:254
class MARKER_PCB, a marker used to show something
Definition: typeinfo.h:98
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:89
const BITMAP_OPAQUE special_tools_xpm[1]
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection set, filtered according to aFlags and aClientFilter.
int CreateArray(const TOOL_EVENT &aEvent)
Create an array of the selected items, invoking the array editor dialog to set the options.
Definition: edit_tool.cpp:2103
KIGFX::VIEW_CONTROLS * controls() const
int GetWidth() const
Definition: track.h:110
STATUS_FLAGS IsPointOnEnds(const wxPoint &point, int min_dist=0) const
Function IsPointOnEnds returns STARTPOINT if point if near (dist = min_dist) start point,...
Definition: track.cpp:188
Common, abstract interface for edit frames.
wxPoint GetPosition() const override
Definition: pad.h:177
Definition: track.h:262
#define _(s)
Definition: 3d_actions.cpp:33
long m_lastKeyboardCursorCommand
Position of the above event.
wxString GetNextPadName(const wxString &aLastPadName) const
Return the next available pad name in the footprint.
Definition: footprint.cpp:1686
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:241
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:52
bool m_lastKeyboardCursorPositionValid
ACTIONS::CURSOR_UP, ACTIONS::CURSOR_DOWN, etc.
bool IsToolActive() const
Definition: tool_base.cpp:31
void SetPosition(const wxPoint &aPos) override
Definition: pad.h:171
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:66
void Mirror(const wxPoint &aCentre, bool aMirrorAroundXAxis)
Mirror an edge of the footprint.
Definition: fp_shape.cpp:223
class ZONE, managed by a footprint
Definition: typeinfo.h:94
static SELECTION_CONDITION OnlyType(KICAD_T aType)
Create a functor that tests if the selected items are only of given type.
VECTOR2I A
Definition: seg.h:49
VECTOR2I Center
Public to make access simpler.
Definition: circle.h:37
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: track.h:474
PCBNEW_SETTINGS & Settings()
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Definition: tool_action.h:123
int Size() const
Returns the number of selected parts.
Definition: selection.h:128
bool isRouterActive() const
Definition: edit_tool.cpp:235
VIATYPE GetViaType() const
Definition: track.h:373
void Mirror(const wxPoint &aMirrorRef, bool aMirrorLeftRight)
Function Mirror Mirror the outlines , relative to a given horizontal axis the layer is not changed.
Definition: zone.cpp:741
The selection tool: currently supports:
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:149
bool IsFootprintEditor() const
static wxPoint mirrorPointX(const wxPoint &aPoint, const wxPoint &aMirrorPoint)
Definition: edit_tool.cpp:1363
static TOOL_ACTION positionRelative
Activation of the position relative tool.
Definition: pcb_actions.h:236
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
const wxPoint & GetEnd() const
Definition: track.h:113
boost::optional< T > OPT
Definition: optional.h:7
virtual double GetLength() const
Function GetLength returns the length of the track using the hypotenuse calculation.
Definition: track.h:141
bool GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:140
void Activate()
Run the tool.
void SetStart(const wxPoint &aStart)
Definition: track.h:115
int GetuViaDrill() const
Definition: netclass.h:144
virtual BOARD_ITEM * Duplicate() const
Create a copy of a of this BOARD_ITEM.
Definition: board_item.h:202
class ORTHOGONAL_DIMENSION, a linear dimension constrained to x/y
Definition: typeinfo.h:103
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
static TOOL_ACTION undo
Definition: actions.h:67
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:321
drawingsheet frame and titleblock
int copyToClipboard(const TOOL_EVENT &aEvent)
Send the current selection to the clipboard by formatting it as a fake pcb see #AppendBoardFromClipbo...
Definition: edit_tool.cpp:2278
static TOOL_ACTION updateLocalRatsnest
Definition: pcb_actions.h:457
static void FootprintFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
A selection filter which prunes the selection to contain only items of type #PCB_MODULE_T.
Definition: edit_tool.cpp:2164
BOARD * GetBoard() const
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
void FilterCollectorForGroups(GENERAL_COLLECTOR &aCollector) const
ROUTER * Router() const
Definition: pad.h:60
void SaveSelection(const PCB_SELECTION &selected, bool isFootprintEditor)
PCB_DRAW_PANEL_GAL * canvas() const
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:168
static TOOL_ACTION moveWithReference
move with a reference point
Definition: pcb_actions.h:99
int GetEventRotationAngle(const PCB_BASE_EDIT_FRAME &aFrame, const TOOL_EVENT &aEvt)
Function getEventRotationAngle()
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
Definition: tool_manager.h:267
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
int Duplicate(const TOOL_EVENT &aEvent)
Duplicate the current selection and starts a move action.
Definition: edit_tool.cpp:1947
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:173
static TOOL_ACTION selectAll
Definition: actions.h:73
const LSET GetSelectionLayers()
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:189
#define IS_NEW
New item, just created.
Definition: eda_item.h:106
bool IsEmpty() const
Definition: board.h:351
const VECTOR2I & GetP1() const
Definition: shape_arc.h:96
static TOOL_ACTION paste
Definition: actions.h:71
FP_ZONE is a specialization of ZONE for use in footprints.
Definition: zone.h:965
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
static TOOL_ACTION duplicate
Definition: actions.h:74
Definition: track.h:83
void SetOrientation(double aAngle)
Set the rotation angle of the pad.
Definition: pcbnew/pad.cpp:579
static TOOL_ACTION refreshPreview
Definition: actions.h:109
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
Definition: picker_tool.h:89
EDA_ITEM * Front() const
Definition: selection.h:203
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:1508
int Side(const VECTOR2I &aP) const
Determine on which side of directed line passing via segment ends point aP lies.
Definition: seg.h:143
void DisplayToolMsg(const wxString &msg) override
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
VECTOR2I NearestPoint(const VECTOR2I &aP) const
Function NearestPoint()
Definition: circle.cpp:188
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:404
VECTOR2I B
Definition: seg.h:50