KiCad PCB EDA Suite
sch_move_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) 2019 CERN
5  * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <tool/tool_manager.h>
26 #include <tools/ee_grid_helper.h>
29 #include <ee_actions.h>
30 #include <bitmaps.h>
31 #include <eda_item.h>
32 #include <sch_item.h>
33 #include <sch_component.h>
34 #include <sch_sheet.h>
35 #include <sch_line.h>
36 #include <sch_edit_frame.h>
37 #include <eeschema_id.h>
38 #include <pgm_base.h>
40 #include "sch_move_tool.h"
41 
42 
43 // For adding to or removing from selections
44 #define QUIET_MODE true
45 
46 
48  EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveMove" ),
49  m_moveInProgress( false ),
50  m_isDragOperation( false ),
51  m_moveOffset( 0, 0 )
52 {
53 }
54 
55 
57 {
59 
60  auto moveCondition = [] ( const SELECTION& aSel ) {
61  if( aSel.Empty() )
62  return false;
63 
65  return false;
66 
67  return true;
68  };
69 
70  // Add move actions to the selection tool menu
71  //
73 
74  selToolMenu.AddItem( EE_ACTIONS::move, moveCondition, 150 );
75  selToolMenu.AddItem( EE_ACTIONS::drag, moveCondition, 150 );
76  selToolMenu.AddItem( EE_ACTIONS::alignToGrid, moveCondition, 150 );
77 
78  return true;
79 }
80 
81 
82 static const KICAD_T movableItems[] =
83 {
89  SCH_LINE_T,
91  SCH_TEXT_T,
99  EOT
100 };
101 
102 
103 /* TODO - Tom/Jeff
104  - add preferences option "Move origin: always cursor / item origin"
105  - add preferences option "Default drag action: drag items / move"
106  - add preferences option "Drag always selects"
107  */
108 
109 
110 int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
111 {
112  EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
114  EE_GRID_HELPER grid( m_toolMgr );
115 
116  m_anchorPos.reset();
117 
118  if( aEvent.IsAction( &EE_ACTIONS::move ) )
119  m_isDragOperation = false;
120  else if( aEvent.IsAction( &EE_ACTIONS::drag ) )
121  m_isDragOperation = true;
122  else if( aEvent.IsAction( &EE_ACTIONS::moveActivate ) )
124  else
125  return 0;
126 
127  if( m_moveInProgress )
128  {
129  auto sel = m_selectionTool->GetSelection().Front();
130 
131  if( sel && !sel->IsNew() )
132  {
133  // User must have switched from move to drag or vice-versa. Reset the selected
134  // items so we can start again with the current m_isDragOperation.
138  m_moveInProgress = false;
139  controls->SetAutoPan( false );
140 
141  // And give it a kick so it doesn't have to wait for the first mouse movement to
142  // refresh.
144  }
145 
146  return 0;
147  }
148 
149  // Be sure that there is at least one item that we can move. If there's no selection try
150  // looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection).
152  bool unselect = selection.IsHover();
153 
154  // Keep an original copy of the starting points for cleanup after the move
155  std::vector<DANGLING_END_ITEM> internalPoints;
156 
157  Activate();
158  controls->ShowCursor( true );
159 
160  std::string tool = aEvent.GetCommandStr().get();
161  m_frame->PushTool( tool );
162 
163  if( selection.Empty() )
164  {
165  // Note that it's important to go through push/pop even when the selection is empty.
166  // This keeps other tools from having to special-case an empty move.
167  m_frame->PopTool( tool );
168  return 0;
169  }
170 
171  bool restore_state = false;
172  bool chain_commands = false;
173  TOOL_EVENT* evt = const_cast<TOOL_EVENT*>( &aEvent );
174  VECTOR2I prevPos;
175 
176  m_cursor = controls->GetCursorPosition();
177 
178  // Main loop: keep receiving events
179  do
180  {
182 
184  || evt->IsAction( &EE_ACTIONS::move ) || evt->IsAction( &EE_ACTIONS::drag )
185  || evt->IsMotion() || evt->IsDrag( BUT_LEFT )
186  || evt->IsAction( &ACTIONS::refreshPreview ) )
187  {
188  if( !m_moveInProgress ) // Prepare to start moving/dragging
189  {
190  SCH_ITEM* sch_item = (SCH_ITEM*) selection.Front();
191  bool appendUndo = sch_item && sch_item->IsNew();
192  bool placingNewItems = sch_item && sch_item->IsNew();
193 
194  //------------------------------------------------------------------------
195  // Setup a drag or a move
196  //
197  m_dragAdditions.clear();
198  m_specialCaseLabels.clear();
199  internalPoints.clear();
200 
201  for( SCH_ITEM* it : m_frame->GetScreen()->Items() )
202  {
203  it->ClearFlags( TEMP_SELECTED );
204 
205  if( !it->IsSelected() )
206  it->ClearFlags( STARTPOINT | ENDPOINT );
207 
208  if( !selection.IsHover() && it->IsSelected() )
209  it->SetFlags( STARTPOINT | ENDPOINT );
210  }
211 
212  if( m_isDragOperation )
213  {
214  // Add connections to the selection for a drag.
215  //
216  for( EDA_ITEM* edaItem : selection )
217  {
218  SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
219  std::vector<wxPoint> connections;
220 
221  if( item->Type() == SCH_LINE_T )
222  static_cast<SCH_LINE*>( item )->GetSelectedPoints( connections );
223  else
224  connections = item->GetConnectionPoints();
225 
226  for( wxPoint point : connections )
227  getConnectedDragItems( item, point, m_dragAdditions );
228  }
229 
231  }
232  else
233  {
234  // Mark the edges of the block with dangling flags for a move.
235  for( EDA_ITEM* item : selection )
236  static_cast<SCH_ITEM*>( item )->GetEndPoints( internalPoints );
237 
238  for( EDA_ITEM* item : selection )
239  static_cast<SCH_ITEM*>( item )->UpdateDanglingState( internalPoints );
240  }
241  // Generic setup
242  //
243  for( EDA_ITEM* item : selection )
244  {
245  if( item->IsNew() )
246  {
247  if( item->HasFlag( TEMP_SELECTED ) && m_isDragOperation )
248  {
249  // Item was added in getConnectedDragItems
250  saveCopyInUndoList( (SCH_ITEM*) item, UNDO_REDO::NEWITEM, appendUndo );
251  appendUndo = true;
252  }
253  else
254  {
255  // Item was added in a previous command (and saved to undo by
256  // that command)
257  }
258  }
259  else if( item->GetParent() && item->GetParent()->IsSelected() )
260  {
261  // Item will be (or has been) saved to undo by parent
262  }
263  else
264  {
265  saveCopyInUndoList( (SCH_ITEM*) item, UNDO_REDO::CHANGED, appendUndo );
266  appendUndo = true;
267  }
268 
269  SCH_ITEM* schItem = (SCH_ITEM*) item;
270  schItem->SetStoredPos( schItem->GetPosition() );
271  }
272 
273  // Set up the starting position and move/drag offset
274  //
275  m_cursor = controls->GetCursorPosition();
276 
277  if( evt->IsAction( &EE_ACTIONS::restartMove ) )
278  {
279  wxASSERT_MSG( m_anchorPos, "Should be already set from previous cmd" );
280  }
281  else if( placingNewItems )
282  {
283  m_anchorPos = selection.GetReferencePoint();
284  }
285 
286  if( m_anchorPos )
287  {
288  VECTOR2I delta = m_cursor - (*m_anchorPos);
289 
290  // Drag items to the current cursor position
291  for( EDA_ITEM* item : selection )
292  {
293  // Don't double move pins, fields, etc.
294  if( item->GetParent() && item->GetParent()->IsSelected() )
295  continue;
296 
297  moveItem( item, delta );
298  updateItem( item, false );
299  }
300 
302  }
303  // For some items, moving the cursor to anchor is not good (for instance large
304  // hierarchical sheets or components can have the anchor outside the view)
305  else if( selection.Size() == 1 && !sch_item->IsMovableFromAnchorPoint() )
306  {
309  }
310  else
311  {
312  if( m_frame->GetMoveWarpsCursor() )
313  {
314  // User wants to warp the mouse
315  std::vector<SCH_ITEM*> items;
316 
317  for( EDA_ITEM* item : selection )
318  items.push_back( static_cast<SCH_ITEM*>( item ) );
319 
320  m_cursor = grid.BestDragOrigin( m_cursor, items );
321  }
322  else
323  {
324  // User does not want to warp the mouse
326  }
327  }
328 
329 
330  controls->SetCursorPosition( m_cursor, false );
332 
333  prevPos = m_cursor;
334  controls->SetAutoPan( true );
335  m_moveInProgress = true;
336  }
337 
338  //------------------------------------------------------------------------
339  // Follow the mouse
340  //
341  m_cursor = controls->GetCursorPosition();
342  VECTOR2I delta( m_cursor - prevPos );
344 
345  m_moveOffset += delta;
346  prevPos = m_cursor;
347 
348  for( EDA_ITEM* item : selection )
349  {
350  // Don't double move pins, fields, etc.
351  if( item->GetParent() && item->GetParent()->IsSelected() )
352  continue;
353 
354  moveItem( item, delta );
355  updateItem( item, false );
356  }
357 
359  }
360  //------------------------------------------------------------------------
361  // Handle cancel
362  //
363  else if( evt->IsCancelInteractive() )
364  {
365  if( m_moveInProgress )
366  {
367  evt->SetPassEvent( false );
368  restore_state = true;
369  }
370 
371  break;
372  }
373  //------------------------------------------------------------------------
374  // Handle TOOL_ACTION special cases
375  //
376  else if( evt->Action() == TA_UNDO_REDO_PRE )
377  {
378  unselect = true;
379  break;
380  }
381  else if( evt->IsAction( &ACTIONS::doDelete ) )
382  {
383  // Exit on a remove operation; there is no further processing for removed items.
384  break;
385  }
386  else if( evt->IsAction( &ACTIONS::duplicate ) )
387  {
388  if( selection.Front()->IsNew() )
389  {
390  // This doesn't really make sense; we'll just end up dragging a stack of
391  // objects so Duplicate() is going to ignore this and we'll just carry on.
392  continue;
393  }
394 
395  // Move original back and exit. The duplicate will run in its own loop.
396  restore_state = true;
397  unselect = false;
398  chain_commands = true;
399  break;
400  }
401  else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
402  {
403  if( evt->GetCommandId().get() >= ID_POPUP_SCH_SELECT_UNIT_CMP
405  {
406  SCH_COMPONENT* component = dynamic_cast<SCH_COMPONENT*>( selection.Front() );
407  int unit = evt->GetCommandId().get() - ID_POPUP_SCH_SELECT_UNIT_CMP;
408 
409  if( component )
410  {
411  m_frame->SelectUnit( component, unit );
413  }
414  }
415  }
416  //------------------------------------------------------------------------
417  // Handle context menu
418  //
419  else if( evt->IsClick( BUT_RIGHT ) )
420  {
422  }
423  //------------------------------------------------------------------------
424  // Handle drop
425  //
426  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
427  {
428  break; // Finish
429  }
430  else
431  evt->SetPassEvent();
432 
433  controls->SetAutoPan( m_moveInProgress );
434 
435  } while( ( evt = Wait() ) ); //Should be assignment not equality test
436 
437  controls->ForceCursorPosition( false );
438  controls->ShowCursor( false );
439  controls->SetAutoPan( false );
440 
441  if( !chain_commands )
442  m_moveOffset = { 0, 0 };
443 
444  m_anchorPos.reset();
445 
446  for( EDA_ITEM* item : selection )
447  item->ClearEditFlags();
448 
449  if( restore_state )
450  {
453  }
454  else
455  {
456  // One last update after exiting loop (for slower stuff, such as updating SCREEN's RTree).
457  for( auto item : selection )
458  updateItem( item, true );
459 
460  // If we move items away from a junction, we _may_ want to add a junction there
461  // to denote the state.
462  for( auto it : internalPoints )
463  {
464  if( m_frame->GetScreen()->IsJunctionNeeded( it.GetPosition(), true ) )
465  m_frame->AddJunction( m_frame->GetScreen(), it.GetPosition(), true, false );
466  }
467 
468  m_toolMgr->RunAction( EE_ACTIONS::addNeededJunctions, true, &selection );
470 
473 
474  m_frame->OnModify();
475  }
476 
477  if( unselect )
479  else
480  m_selectionTool->RebuildSelection(); // Schematic cleanup might have merged lines, etc.
481 
482  m_dragAdditions.clear();
483  m_moveInProgress = false;
484  m_frame->PopTool( tool );
485  return 0;
486 }
487 
488 
489 void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, wxPoint aPoint,
490  EDA_ITEMS& aList )
491 {
492  EE_RTREE& items = m_frame->GetScreen()->Items();
493  EE_RTREE::EE_TYPE itemsOverlapping = items.Overlapping( aOriginalItem->GetBoundingBox() );
494  bool ptHasUnselectedJunction = false;
495 
496  for( SCH_ITEM* item : itemsOverlapping )
497  {
498  if( item->Type() == SCH_JUNCTION_T && item->IsConnected( aPoint ) && !item->IsSelected() )
499  {
500  ptHasUnselectedJunction = true;
501  break;
502  }
503  }
504 
505  for( SCH_ITEM *test : itemsOverlapping )
506  {
507  if( test == aOriginalItem || test->IsSelected() || !test->CanConnect( aOriginalItem ) )
508  continue;
509 
510  KICAD_T testType = test->Type();
511 
512  switch( testType )
513  {
514  case SCH_LINE_T:
515  {
516  // Select the connected end of wires/bus connections that don't have an unselected
517  // junction isolating them from the drag
518  if( ptHasUnselectedJunction )
519  break;
520 
521  SCH_LINE* testLine = static_cast<SCH_LINE*>( test );
522 
523  if( testLine->GetStartPoint() == aPoint )
524  {
525  if( !testLine->HasFlag( TEMP_SELECTED ) )
526  aList.push_back( testLine );
527 
528  testLine->SetFlags( STARTPOINT | TEMP_SELECTED );
529  }
530  else if( testLine->GetEndPoint() == aPoint )
531  {
532  if( !testLine->HasFlag( TEMP_SELECTED ) )
533  aList.push_back( testLine );
534 
535  testLine->SetFlags( ENDPOINT | TEMP_SELECTED );
536  }
537  else
538  {
539  break;
540  }
541 
542  // Since only one end is going to move, the movement vector of any labels attached
543  // to it is scaled by the proportion of the line length the label is from the moving
544  // end.
545  for( SCH_ITEM* item : itemsOverlapping )
546  {
547  if( item->Type() == SCH_LABEL_T )
548  {
549  SCH_TEXT* label = static_cast<SCH_TEXT*>( item );
550 
551  if( label->IsSelected() )
552  continue; // These will be moved on their own because they're selected
553 
554  if( label->CanConnect( testLine )
555  && testLine->HitTest( label->GetPosition(), 1 ) )
556  {
557  if( !label->HasFlag( TEMP_SELECTED ) )
558  aList.push_back( label );
559 
561  info.attachedLine = testLine;
562  info.originalLabelPos = label->GetPosition();
563  m_specialCaseLabels[label] = info;
564  }
565  }
566  }
567 
568  break;
569  }
570 
571  case SCH_SHEET_T:
572  // Dragging a sheet just because it's connected to something else feels a bit like
573  // the tail wagging the dog, but this could be moved down to the next case.
574  break;
575 
576  case SCH_COMPONENT_T:
577  case SCH_JUNCTION_T:
578  if( test->IsConnected( aPoint ) )
579  {
580  // Add a new wire between the component or junction and the selected item so
581  // the selected item can be dragged.
582  SCH_LINE* newWire = new SCH_LINE( aPoint, LAYER_WIRE );
583  newWire->SetFlags( IS_NEW );
584  m_frame->AddToScreen( newWire, m_frame->GetScreen() );
585 
586  newWire->SetFlags( TEMP_SELECTED | STARTPOINT );
587  aList.push_back( newWire );
588  }
589  break;
590 
591  case SCH_NO_CONNECT_T:
592  // Select no-connects that are connected to items being moved.
593  if( !test->HasFlag( TEMP_SELECTED ) && test->IsConnected( aPoint ) )
594  {
595  aList.push_back( test );
596  test->SetFlags( TEMP_SELECTED );
597  }
598 
599  break;
600 
601  case SCH_LABEL_T:
602  case SCH_GLOBAL_LABEL_T:
603  case SCH_HIER_LABEL_T:
605  case SCH_BUS_BUS_ENTRY_T:
606  // Performance optimization:
607  if( test->HasFlag( TEMP_SELECTED ) )
608  break;
609 
610  // Select labels and bus entries that are connected to a wire being moved.
611  if( aOriginalItem->Type() == SCH_LINE_T )
612  {
613  std::vector<wxPoint> connections = test->GetConnectionPoints();
614 
615  for( wxPoint& point : connections )
616  {
617  if( aOriginalItem->HitTest( point, 1 ) )
618  {
619  test->SetFlags( TEMP_SELECTED );
620  aList.push_back( test );
621 
622  // A bus entry needs its wire & label as well
623  if( testType == SCH_BUS_WIRE_ENTRY_T || testType == SCH_BUS_BUS_ENTRY_T )
624  {
625  std::vector<wxPoint> ends = test->GetConnectionPoints();
626  wxPoint otherEnd;
627 
628  if( ends[0] == point )
629  otherEnd = ends[1];
630  else
631  otherEnd = ends[0];
632 
633  getConnectedDragItems( test, otherEnd, aList );
634  }
635  break;
636  }
637  }
638  }
639 
640  break;
641 
642  default:
643  break;
644  }
645  }
646 }
647 
648 
649 void SCH_MOVE_TOOL::moveItem( EDA_ITEM* aItem, const VECTOR2I& aDelta )
650 {
651  switch( aItem->Type() )
652  {
653  case SCH_LINE_T:
654  {
655  SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
656 
657  if( aItem->HasFlag( STARTPOINT ) )
658  line->MoveStart( (wxPoint) aDelta );
659 
660  if( aItem->HasFlag( ENDPOINT ) )
661  line->MoveEnd( (wxPoint) aDelta );
662 
663  }
664  break;
665 
666  case SCH_PIN_T:
667  case SCH_FIELD_T:
668  {
669  SCH_ITEM* parent = (SCH_ITEM*) aItem->GetParent();
670  wxPoint delta( aDelta );
671 
672  if( parent && parent->Type() == SCH_COMPONENT_T )
673  {
674  SCH_COMPONENT* component = (SCH_COMPONENT*) aItem->GetParent();
675  TRANSFORM transform = component->GetTransform().InverseTransform();
676 
677  delta = transform.TransformCoordinate( delta );
678  }
679 
680  static_cast<SCH_ITEM*>( aItem )->Move( delta );
681 
682  // If we're moving a field with respect to its parent then it's no longer auto-placed
683  if( aItem->Type() == SCH_FIELD_T && parent && !parent->IsSelected() )
684  parent->ClearFieldsAutoplaced();
685 
686  break;
687  }
688  case SCH_SHEET_PIN_T:
689  {
690  SCH_SHEET_PIN* pin = (SCH_SHEET_PIN*) aItem;
691  pin->SetStoredPos( pin->GetStoredPos() + (wxPoint) aDelta );
692  pin->ConstrainOnEdge( pin->GetStoredPos() );
693  break;
694  }
695  case SCH_LABEL_T:
696  {
697  SCH_TEXT* label = static_cast<SCH_TEXT*>( aItem );
698 
699  if( m_specialCaseLabels.count( label ) )
700  {
702  SEG currentLine( info.attachedLine->GetStartPoint(), info.attachedLine->GetEndPoint() );
703  label->SetPosition( (wxPoint) currentLine.NearestPoint( info.originalLabelPos ) );
704  }
705  else
706  label->Move( (wxPoint) aDelta );
707 
708  break;
709  }
710  default:
711  static_cast<SCH_ITEM*>( aItem )->Move( (wxPoint) aDelta );
712  break;
713  }
714 
715  getView()->Hide( aItem, false );
716  aItem->SetFlags( IS_MOVED );
717 }
718 
719 
721 {
722  EE_GRID_HELPER grid( m_toolMgr);
724  bool append_undo = false;
725 
726  for( SCH_ITEM* it : m_frame->GetScreen()->Items() )
727  {
728  if( !it->IsSelected() )
729  it->ClearFlags( STARTPOINT | ENDPOINT );
730 
731  if( !selection.IsHover() && it->IsSelected() )
732  it->SetFlags( STARTPOINT | ENDPOINT );
733 
734  it->SetStoredPos( it->GetPosition() );
735 
736  if( it->Type() == SCH_SHEET_T )
737  {
738  for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( it )->GetPins() )
739  pin->SetStoredPos( pin->GetPosition() );
740  }
741  }
742 
743  for( EDA_ITEM* item : selection )
744  {
745  if( item->Type() == SCH_LINE_T )
746  {
747  SCH_LINE* line = static_cast<SCH_LINE*>( item );
748  std::vector<int> flags{ STARTPOINT, ENDPOINT };
749  std::vector<wxPoint> pts{ line->GetStartPoint(), line->GetEndPoint() };
750 
751  for( int ii = 0; ii < 2; ++ii )
752  {
753  EDA_ITEMS drag_items{ item };
754  line->ClearFlags();
755  line->SetFlags( flags[ii] );
756  getConnectedDragItems( line, pts[ii], drag_items );
757  std::set<EDA_ITEM*> unique_items( drag_items.begin(), drag_items.end() );
758 
759  VECTOR2I gridpt = grid.AlignGrid( pts[ii] ) - pts[ii];
760 
761  if( gridpt != VECTOR2I( 0, 0 ) )
762  {
763  for( auto dritem : unique_items )
764  {
765  if( dritem->GetParent() && dritem->GetParent()->IsSelected() )
766  continue;
767 
768  saveCopyInUndoList( dritem, UNDO_REDO::CHANGED, append_undo );
769  append_undo = true;
770 
771  moveItem( dritem, gridpt );
772  updateItem( dritem, true );
773  }
774  }
775  }
776  }
777  else
778  {
779  std::vector<wxPoint> connections;
780  EDA_ITEMS drag_items{ item };
781  connections = static_cast<SCH_ITEM*>( item )->GetConnectionPoints();
782 
783  for( const wxPoint& point : connections )
784  getConnectedDragItems( static_cast<SCH_ITEM*>( item ), point, drag_items );
785 
786  std::map<VECTOR2I, int> shifts;
787  VECTOR2I most_common( 0, 0 );
788  int max_count = 0;
789 
790  for( const wxPoint& conn : connections )
791  {
792  VECTOR2I gridpt = grid.AlignGrid( conn ) - conn;
793 
794  shifts[gridpt]++;
795 
796  if( shifts[gridpt] > max_count )
797  {
798  most_common = gridpt;
799  max_count = shifts[most_common];
800  }
801  }
802 
803  if( most_common != VECTOR2I( 0, 0 ) )
804  {
805  for( EDA_ITEM* dritem : drag_items )
806  {
807  if( dritem->GetParent() && dritem->GetParent()->IsSelected() )
808  continue;
809 
810  saveCopyInUndoList( dritem, UNDO_REDO::CHANGED, append_undo );
811  append_undo = true;
812 
813  moveItem( dritem, most_common );
814  updateItem( dritem, true );
815  }
816  }
817  }
818  }
819 
821  m_toolMgr->RunAction( EE_ACTIONS::addNeededJunctions, true, &selection );
822 
825 
826  m_frame->OnModify();
827  return 0;
828 }
829 
830 
832 {
834  Go( &SCH_MOVE_TOOL::Main, EE_ACTIONS::move.MakeEvent() );
835  Go( &SCH_MOVE_TOOL::Main, EE_ACTIONS::drag.MakeEvent() );
837 }
static TOOL_ACTION moveActivate
Definition: ee_actions.h:113
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hides the item in the view (e.g.
Definition: view.cpp:1480
OPT< int > GetCommandId() const
Definition: tool_event.h:458
bool SchematicCleanUp(SCH_SCREEN *aScreen=nullptr)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
bool IsHover() const
Definition: selection.h:70
void SetPassEvent(bool aPass=true)
Definition: tool_event.h:256
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
virtual std::vector< wxPoint > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:397
void getConnectedDragItems(SCH_ITEM *aOriginalItem, wxPoint aPoint, EDA_ITEMS &aList)
Finds additional items for a drag operation.
wxPoint GetStartPoint() const
Definition: sch_line.h:94
bool IsSelected() const
Definition: eda_item.h:191
virtual bool IsMovableFromAnchorPoint()
Definition: sch_item.h:247
static TOOL_ACTION doDelete
Definition: actions.h:75
bool IsJunctionNeeded(const wxPoint &aPosition, bool aNew=false)
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:371
int Main(const TOOL_EVENT &aEvent)
Runs an interactive move of the selected items, or the item under the cursor.
VECTOR2I m_cursor
Last cursor position (needed for getModificationPoint() to avoid changes of edit reference point).
Definition: sch_move_tool.h:88
TOOL_ACTIONS Action() const
Returns more specific information about the type of an event.
Definition: tool_event.h:250
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:178
VECTOR2I m_moveOffset
Used for chaining commands
Definition: sch_move_tool.h:84
static TOOL_ACTION restartMove
Definition: ee_actions.h:197
void MoveStart(const wxPoint &aMoveVector)
Definition: sch_line.cpp:120
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
EE_TYPE Overlapping(const EDA_RECT &aRect)
Definition: sch_rtree.h:224
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
TRANSFORM InverseTransform() const
Calculate the Inverse mirror/rotation transform.
Definition: transform.cpp:59
TOOL_MENU & GetToolMenu()
bool IsMotion() const
Definition: tool_event.h:306
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:141
int AddItemsToSel(const TOOL_EVENT &aEvent)
Schematic editor (Eeschema) main window.
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
EE_RTREE - Implements an R-tree for fast spatial and type indexing of schematic items.
Definition: sch_rtree.h:41
bool m_moveInProgress
Flag determining if anything is being dragged right now
Definition: sch_move_tool.h:77
virtual wxPoint GetPosition() const
Definition: eda_item.h:325
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
static TOOL_ACTION alignToGrid
Definition: ee_actions.h:111
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:102
#define TEMP_SELECTED
flag indicating that the structure has already selected
Definition: eda_item.h:114
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
EDA_ITEMS m_dragAdditions
Items (such as wires) which were added to the selection for a drag
Definition: sch_move_tool.h:81
void SetCurrentCursor(KICURSOR cursor)
Function SetCurrentCursor Set the current cursor shape for this panel.
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:213
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Definition: sch_line.cpp:717
wxPoint TransformCoordinate(const wxPoint &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:42
bool IsNew() const
Definition: eda_item.h:187
bool IsAction(const TOOL_ACTION *aAction) const
Function IsAction() Tests if the event contains an action issued upon activation of the given TOOL_AC...
Definition: tool_event.cpp:67
SCH_JUNCTION * AddJunction(SCH_SCREEN *aScreen, const wxPoint &aPos, bool aAppendToUndo, bool aFinal=true)
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:69
EE_SELECTION & GetSelection()
Function GetSelection()
EE_SELECTION & RequestSelection(const KICAD_T *aFilterList=EE_COLLECTOR::AllItems)
Function RequestSelection()
virtual bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Definition: eda_item.h:295
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
wxPoint & GetStoredPos()
Definition: sch_item.h:249
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:296
virtual bool CanConnect(const SCH_ITEM *aItem) const
Definition: sch_item.h:378
for transforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
void Move(const wxPoint &aMoveVector) override
Move the item by aMoveVector to a new position.
Definition: sch_text.h:274
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:220
std::map< SCH_TEXT *, SPECIAL_CASE_LABEL_INFO > m_specialCaseLabels
Definition: sch_move_tool.h:94
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false)
Similar to m_frame->SaveCopyInUndoList(), but handles items that are owned by their parents.
Definition: ee_tool_base.h:138
virtual void PopTool(const std::string &actionName)
TRANSFORM & GetTransform() const
boost::optional< VECTOR2I > m_anchorPos
Definition: sch_move_tool.h:90
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
TOOL_EVENT.
Definition: tool_event.h:171
int AlignElements(const TOOL_EVENT &aEvent)
Aligns selected elements to the grid.
void ClearFieldsAutoplaced()
Set fields automatically placed flag false.
Definition: sch_item.h:458
EDA_ITEM * GetParent() const
Definition: eda_item.h:183
VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (such a...
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:181
static const TOOL_EVENT SelectedItemsMoved
Definition: actions.h:216
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:85
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:576
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
bool m_isDragOperation
Definition: sch_move_tool.h:78
static TOOL_ACTION addNeededJunctions
Definition: ee_actions.h:75
bool IsMouseUp(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:301
void ConstrainOnEdge(wxPoint Pos)
Adjust label position to edge based on proximity to vertical or horizontal edge of the parent sheet.
wxPoint GetPosition() const override
Definition: sch_text.h:312
#define IS_MOVED
Item being moved.
Definition: eda_item.h:105
bool IsCancelInteractive()
Function IsCancelInteractive()
Definition: tool_event.cpp:190
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
void SelectUnit(SCH_COMPONENT *aComponent, int aUnit)
Definition: getpart.cpp:198
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:120
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
Similar to getView()->Update(), but handles items that are redrawn by their parents and updating the ...
Definition: ee_tool_base.h:107
Definition: seg.h:39
#define STARTPOINT
When a line is selected, these flags indicate which.
Definition: eda_item.h:111
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:463
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, const std::vector< SCH_ITEM * > &aItem)
see class PGM_BASE
void AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen)
Add an item to the screen (and view) aScreen is the screen the item is located on,...
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
void MoveEnd(const wxPoint &aMoveVector)
Definition: sch_line.cpp:130
void moveItem(EDA_ITEM *aItem, const VECTOR2I &aDelta)
static TOOL_ACTION drag
Definition: ee_actions.h:115
void RollbackSchematicFromUndo()
Performs an undo of the last edit WITHOUT logging a corresponding redo.
EE_RTREE & Items()
Definition: sch_screen.h:159
void RebuildSelection()
Rebuilds the selection from the EDA_ITEMs' selection flags.
The EE_TYPE struct provides a type-specific auto-range iterator to the RTree.
Definition: sch_rtree.h:181
VECTOR2I AlignGrid(const VECTOR2I &aPoint) const
Schematic symbol object.
Definition: sch_component.h:79
EDA_ITEM is a base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:221
bool GetMoveWarpsCursor() const
Indicates that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:159
void Activate()
Function Activate() Runs the tool.
static TOOL_ACTION move
Definition: ee_actions.h:114
#define ENDPOINT
ends. (Used to support dragging.)
Definition: eda_item.h:112
EE_TOOL_BASE.
Definition: ee_tool_base.h:50
static const KICAD_T movableItems[]
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: eda_item.cpp:89
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
bool HasFlag(STATUS_FLAGS aFlag)
Definition: eda_item.h:223
#define QUIET_MODE
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
void setTransitions() override
Sets up handlers for various events.
void SetPosition(const wxPoint &aPosition) override
Definition: sch_text.h:313
void PostEvent(const TOOL_EVENT &aEvent)
Puts an event to the event queue to be processed at the end of event processing cycle.
Definition: tool_manager.h:274
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Adds a menu entry to run a TOOL_ACTION on selected items.
void SetStoredPos(wxPoint aPos)
Definition: sch_item.h:250
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
#define IS_NEW
New item, just created.
Definition: eda_item.h:106
static TOOL_ACTION duplicate
Definition: actions.h:74
static TOOL_ACTION refreshPreview
Definition: actions.h:104
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:201
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181
wxPoint GetEndPoint() const
Definition: sch_line.h:97