KiCad PCB EDA Suite
lib_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 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <tool/tool_manager.h>
26 #include <ee_actions.h>
27 #include <ee_hotkeys.h>
28 #include <view/view.h>
29 #include <bitmaps.h>
30 #include <base_struct.h>
31 #include <lib_edit_frame.h>
32 #include <eeschema_id.h>
33 #include "lib_move_tool.h"
34 #include "lib_pin_tool.h"
35 
36 
38  EE_TOOL_BASE( "libedit.InteractiveMove" ),
39  m_moveInProgress( false ),
40  m_moveOffset( 0, 0 )
41 {
42 }
43 
44 
46 {
47 }
48 
49 
51 {
53 
54  //
55  // Add move actions to the selection tool menu
56  //
58 
60 
61  return true;
62 }
63 
64 
66 {
67  EE_TOOL_BASE::Reset( aReason );
68 
69  if( aReason == MODEL_RELOAD )
70  {
71  m_moveInProgress = false;
72  m_moveOffset = { 0, 0 };
73  }
74 }
75 
76 
77 int LIB_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
78 {
80 
81  controls->SetSnapping( true );
82  VECTOR2I originalCursorPos = controls->GetCursorPosition();
83 
84  // Be sure that there is at least one item that we can move. If there's no selection try
85  // looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection).
87  bool unselect = selection.IsHover();
88 
89  if( selection.Empty() )
90  return 0;
91 
92  m_frame->SetToolID( ID_SCH_MOVE, wxCURSOR_DEFAULT, _( "Move Items" ) );
93 
94  Activate();
95  controls->ShowCursor( true );
96  controls->SetAutoPan( true );
97 
98  bool restore_state = false;
99  bool chain_commands = false;
100  OPT_TOOL_EVENT evt = aEvent;
101  VECTOR2I prevPos;
102 
103  if( !selection.Front()->IsNew() )
105 
106  // Main loop: keep receiving events
107  do
108  {
109  controls->SetSnapping( !evt->Modifier( MD_ALT ) );
110 
111  if( evt->IsAction( &EE_ACTIONS::move ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT )
112  || evt->IsAction( &EE_ACTIONS::refreshPreview ) )
113  {
114  if( !m_moveInProgress ) // Prepare to start moving/dragging
115  {
116  // Pick up any synchronized pins
117  //
118  if( selection.GetSize() == 1 && selection.Front()->Type() == LIB_PIN_T
119  && m_frame->SynchronizePins() )
120  {
121  LIB_PIN* cur_pin = (LIB_PIN*) selection.Front();
122  LIB_PART* part = m_frame->GetCurPart();
123 
124  for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
125  {
126  if( pin->GetPosition() == cur_pin->GetPosition()
127  && pin->GetOrientation() == cur_pin->GetOrientation()
128  && pin->GetConvert() == cur_pin->GetConvert() )
129  {
130  m_selectionTool->AddItemToSel( pin, true );
131  }
132  }
133  }
134 
135  // Apply any initial offset in case we're coming from a previous command.
136  //
137  for( EDA_ITEM* item : selection )
138  moveItem( item, m_moveOffset );
139 
140  // Set up the starting position and move/drag offset
141  //
142  m_cursor = controls->GetCursorPosition();
143 
144  if( selection.HasReferencePoint() )
145  {
146  VECTOR2I delta = m_cursor - selection.GetReferencePoint();
147 
148  // Drag items to the current cursor position
149  for( EDA_ITEM* item : selection )
150  {
151  // Don't double move pins, fields, etc.
152  if( item->GetParent() && item->GetParent()->IsSelected() )
153  continue;
154 
155  moveItem( item, delta );
156  updateView( item );
157  }
158 
159  selection.SetReferencePoint( m_cursor );
160  }
161  else if( selection.Size() == 1 )
162  {
163  // Set the current cursor position to the first dragged item origin,
164  // so the movement vector can be computed later
165  updateModificationPoint( selection );
166  m_cursor = originalCursorPos;
167  }
168  else
169  {
170  updateModificationPoint( selection );
171  }
172 
173  controls->SetCursorPosition( m_cursor, false );
174 
175  prevPos = m_cursor;
176  controls->SetAutoPan( true );
177  m_moveInProgress = true;
178  }
179 
180  //------------------------------------------------------------------------
181  // Follow the mouse
182  //
183  m_cursor = controls->GetCursorPosition();
184  VECTOR2I delta( m_cursor - prevPos );
185  selection.SetReferencePoint( m_cursor );
186 
187  m_moveOffset += delta;
188  prevPos = m_cursor;
189 
190  for( EDA_ITEM* item : selection )
191  {
192  moveItem( item, delta );
193  updateView( item );
194  }
195 
198  }
199  //------------------------------------------------------------------------
200  // Handle cancel
201  //
202  else if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) )
203  {
204  if( m_moveInProgress )
205  restore_state = true;
206 
207  break;
208  }
209  //------------------------------------------------------------------------
210  // Handle TOOL_ACTION special cases
211  //
212  else if( evt->Action() == TA_UNDO_REDO_PRE )
213  {
214  unselect = true;
215  break;
216  }
217  else if( evt->Category() == TC_COMMAND )
218  {
219  if( evt->IsAction( &EE_ACTIONS::doDelete ) )
220  {
221  // Exit on a remove operation; there is no further processing for removed items.
222  break;
223  }
224  else if( evt->IsAction( &EE_ACTIONS::duplicate ) )
225  {
226  if( selection.Front()->IsNew() )
227  {
228  // This doesn't really make sense; we'll just end up dragging a stack of
229  // objects so Duplicate() is going to ignore this and we'll just carry on.
230  continue;
231  }
232 
233  // Move original back and exit. The duplicate will run in its own loop.
234  restore_state = true;
235  unselect = false;
236  chain_commands = true;
237  break;
238  }
239  }
240  //------------------------------------------------------------------------
241  // Handle context menu
242  //
243  else if( evt->IsClick( BUT_RIGHT ) )
244  {
246  }
247  //------------------------------------------------------------------------
248  // Handle drop
249  //
250  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
251  {
252  if( selection.GetSize() == 1 && selection.Front()->Type() == LIB_PIN_T )
253  {
255 
256  if( !pinTool->PlacePin( (LIB_PIN*) selection.Front() ) )
257  restore_state = true;
258  }
259 
260  break; // Finish
261  }
262 
263  } while( ( evt = Wait() ) ); //Should be assignment not equality test
264 
265  controls->ForceCursorPosition( false );
266  controls->ShowCursor( false );
267  controls->SetSnapping( false );
268  controls->SetAutoPan( false );
269 
270  if( !chain_commands )
271  m_moveOffset = { 0, 0 };
272 
273  m_moveInProgress = false;
275 
276  selection.ClearReferencePoint();
277 
278  for( auto item : selection )
279  item->ClearEditFlags();
280 
281  if( unselect )
283 
284  if( restore_state )
286  else
287  m_frame->OnModify();
288 
289  return 0;
290 }
291 
292 
294 {
295  static_cast<LIB_ITEM*>( aItem )->Offset( mapCoords( aDelta ));
296  aItem->SetFlags( IS_MOVED );
297 }
298 
299 
301 {
302  if( m_moveInProgress && aSelection.HasReferencePoint() )
303  return false;
304 
305  // When there is only one item selected, the reference point is its position...
306  if( aSelection.Size() == 1 )
307  {
308  LIB_ITEM* item = static_cast<LIB_ITEM*>( aSelection.Front() );
309  aSelection.SetReferencePoint( item->GetPosition() );
310  }
311  // ...otherwise modify items with regard to the grid-snapped cursor position
312  else
313  {
315  aSelection.SetReferencePoint( m_cursor );
316  }
317 
318  return true;
319 }
320 
321 
323 {
324  Go( &LIB_MOVE_TOOL::Main, EE_ACTIONS::move.MakeEvent() );
325 }
VECTOR2I m_cursor
Last cursor position (needed for getModificationPoint() to avoid changes of edit reference point).
Definition: lib_move_tool.h:72
virtual wxPoint GetPosition() const =0
Return the current draw object position.
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
void ClearReferencePoint()
Definition: selection.h:213
bool m_moveInProgress
Flag determining if anything is being dragged right now
Definition: lib_move_tool.h:65
LIB_PART * GetCurPart() const
Return the current part being edited or NULL if none selected.
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
Definition: ee_tool_base.h:90
bool IsHover() const
Definition: selection.h:69
Model changes (required full reload)
Definition: tool_base.h:83
static TOOL_ACTION duplicate
Definition: ee_actions.h:118
TOOL_MENU & GetToolMenu()
int GetOrientation() const
Definition: lib_pin.h:205
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
int Main(const TOOL_EVENT &aEvent)
Function Main()
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
static SELECTION_CONDITION IdleSelection
OPT_TOOL_EVENT Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
virtual void SetSnapping(bool aEnabled)
Function SetSnapping() Enables/disables snapping cursor to grid.
static TOOL_ACTION refreshPreview
Definition: ee_actions.h:168
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:125
void setTransitions() override
Sets up handlers for various events.
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
static const int delta[8][2]
Definition: solve.cpp:112
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:136
The base class for drawable items used by schematic library components.
Definition: lib_draw_item.h:67
bool IsNew() const
Definition: base_struct.h:222
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:69
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:208
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:259
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
Class TOOL_EVENT.
Definition: tool_event.h:167
Define a library symbol object.
Class VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (...
static TOOL_ACTION doDelete
Definition: ee_actions.h:131
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:143
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
bool updateModificationPoint(SELECTION &aSelection)
Returns the right modification point (e.g.
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:57
virtual void SetToolID(int aId, int aCursor, const wxString &aToolMsg)
Set the tool command ID to aId and sets the cursor to aCursor.
bool IsCancelInteractive(const TOOL_EVENT &aEvt)
Function IsCancelInteractive()
Definition: tool_event.cpp:177
static VECTOR2D mapCoords(const wxPoint &aCoord)
int GetConvert() const
TOOL_MENU m_menu
Menu model displayed by the tool.
Definition: ee_tool_base.h:147
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:119
void moveItem(EDA_ITEM *aItem, VECTOR2I aDelta)
wxPoint GetPosition() const override
Return the current draw object position.
Definition: lib_pin.h:432
virtual unsigned int GetSize() const override
Function GetSize() Returns the number of stored items.
Definition: selection.h:98
LIB_PIN * GetNextPin(LIB_PIN *aItem=NULL)
Return the next pin object from the draw list.
virtual void SetNoToolSelected()
Select the ID_NO_TOOL_SELECTED id tool (Idle tool)
bool HasReferencePoint() const
Definition: selection.h:198
void updateView(EDA_ITEM *aItem) const
Similar to getView()->Update(), but handles items that are redrawn by their parents.
Definition: ee_tool_base.h:107
int AddItemToSel(const TOOL_EVENT &aEvent)
int Size() const
Returns the number of selected parts.
Definition: selection.h:125
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO_T aType, bool aAppend=false)
Similar to m_frame->SaveCopyInUndoList(), but handles items that are owned by their parents.
Definition: ee_tool_base.h:120
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:157
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:80
void Activate()
Function Activate() Runs the tool.
bool SynchronizePins()
Pin editing (add, delete, move...) can be synchronized between units when units are interchangeable b...
static TOOL_ACTION move
Definition: ee_actions.h:116
Class EE_TOOL_BASE.
Definition: ee_tool_base.h:49
Basic classes for most KiCad items.
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:41
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:238
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Function AddItem()
SELECTION & RequestSelection(const KICAD_T *aFilterList=EE_COLLECTOR::AllItems)
Function RequestSelection()
bool PlacePin(LIB_PIN *aPin)
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false)=0
Moves cursor to the requested position expressed in world coordinates.
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:155
OPT< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:486
KICAD_T Type() const
Function Type()
Definition: base_struct.h:204
virtual void UpdateMsgPanel()
Redraw the message panel.
VECTOR2I m_moveOffset
Used for chaining commands
Definition: lib_move_tool.h:68
#define IS_MOVED
Item being moved.
Definition: base_struct.h:113