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 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>
27 #include <ee_actions.h>
28 #include <bitmaps.h>
29 #include <base_struct.h>
30 #include <lib_edit_frame.h>
31 #include "lib_move_tool.h"
32 #include "lib_pin_tool.h"
33 
34 
36  EE_TOOL_BASE( "eeschema.SymbolMoveTool" ),
37  m_moveInProgress( false ),
38  m_moveOffset( 0, 0 )
39 {
40 }
41 
42 
44 {
46 
47  //
48  // Add move actions to the selection tool menu
49  //
51 
53 
54  return true;
55 }
56 
57 
59 {
60  EE_TOOL_BASE::Reset( aReason );
61 
62  if( aReason == MODEL_RELOAD )
63  {
64  m_moveInProgress = false;
65  m_moveOffset = { 0, 0 };
66  }
67 }
68 
69 
70 int LIB_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
71 {
73  controls->SetSnapping( true );
74 
75  m_anchorPos = { 0, 0 };
76 
77  // Be sure that there is at least one item that we can move. If there's no selection try
78  // looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection).
80  bool unselect = selection.IsHover();
81 
82  if( selection.Empty() || m_moveInProgress )
83  return 0;
84 
85  std::string tool = aEvent.GetCommandStr().get();
86  m_frame->PushTool( tool );
87  Activate();
88 
89  controls->ShowCursor( true );
90  controls->SetAutoPan( true );
91 
92  bool restore_state = false;
93  bool chain_commands = false;
94  TOOL_EVENT* evt = const_cast<TOOL_EVENT*>( &aEvent );
95  VECTOR2I prevPos;
96 
97  if( !selection.Front()->IsNew() )
99 
100  m_cursor = controls->GetCursorPosition();
101 
102  // Main loop: keep receiving events
103  do
104  {
105  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
106  controls->SetSnapping( !evt->Modifier( MD_ALT ) );
107 
108  if( evt->IsAction( &EE_ACTIONS::move ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT )
109  || evt->IsAction( &ACTIONS::refreshPreview ) )
110  {
111  if( !m_moveInProgress ) // Prepare to start moving/dragging
112  {
113  LIB_ITEM* lib_item = (LIB_ITEM*) selection.Front();
114 
115  // Pick up any synchronized pins
116  //
117  // Careful when pasting. The pasted pin will be at the same location as it
118  // was copied from, leading us to believe it's a synchronized pin. It's not.
119  if( selection.GetSize() == 1 && lib_item->Type() == LIB_PIN_T
121  && ( lib_item->GetEditFlags() & IS_PASTED ) == 0 )
122  {
123  LIB_PIN* cur_pin = (LIB_PIN*) lib_item;
124  LIB_PART* part = m_frame->GetCurPart();
125 
126  for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
127  {
128  if( pin->GetPosition() == cur_pin->GetPosition()
129  && pin->GetOrientation() == cur_pin->GetOrientation()
130  && pin->GetConvert() == cur_pin->GetConvert() )
131  {
132  m_selectionTool->AddItemToSel( pin, true /*quiet mode*/ );
133  }
134  }
135  }
136 
137  // Apply any initial offset in case we're coming from a previous command.
138  //
139  for( EDA_ITEM* item : selection )
140  moveItem( item, m_moveOffset );
141 
142  // Set up the starting position and move/drag offset
143  //
144  m_cursor = controls->GetCursorPosition();
145 
146  if( lib_item->IsNew() )
147  {
148  m_anchorPos = selection.GetReferencePoint();
149  VECTOR2I delta = m_cursor - mapCoords( m_anchorPos );
150 
151  // Drag items to the current cursor position
152  for( EDA_ITEM* item : selection )
153  {
154  moveItem( item, delta );
155  updateView( item );
156  }
157 
159  }
160  else if( selection.Size() == 1 && m_frame->GetMoveWarpsCursor() )
161  {
162  wxPoint itemPos = lib_item->GetPosition();
163  m_anchorPos = wxPoint( itemPos.x, -itemPos.y );
164 
165  getViewControls()->WarpCursor( m_anchorPos, true, true );
167  }
168  else
169  {
172  }
173 
174  controls->SetCursorPosition( m_cursor, false );
176 
177  prevPos = m_cursor;
178  controls->SetAutoPan( true );
179  m_moveInProgress = true;
180  }
181 
182  //------------------------------------------------------------------------
183  // Follow the mouse
184  //
185  m_cursor = controls->GetCursorPosition();
186  VECTOR2I delta( m_cursor - prevPos );
188 
189  m_moveOffset += delta;
190  prevPos = m_cursor;
191 
192  for( EDA_ITEM* item : selection )
193  {
194  moveItem( item, delta );
195  updateView( item );
196  }
197 
200  }
201  //------------------------------------------------------------------------
202  // Handle cancel
203  //
204  else if( evt->IsCancelInteractive() || evt->IsActivate() )
205  {
206  if( m_moveInProgress )
207  restore_state = true;
208 
209  break;
210  }
211  //------------------------------------------------------------------------
212  // Handle TOOL_ACTION special cases
213  //
214  else if( evt->Action() == TA_UNDO_REDO_PRE )
215  {
216  unselect = true;
217  break;
218  }
219  else if( evt->Category() == TC_COMMAND )
220  {
221  if( evt->IsAction( &ACTIONS::doDelete ) )
222  {
223  // Exit on a remove operation; there is no further processing for removed items.
224  break;
225  }
226  else if( evt->IsAction( &ACTIONS::duplicate ) )
227  {
228  if( selection.Front()->IsNew() )
229  {
230  // This doesn't really make sense; we'll just end up dragging a stack of
231  // objects so Duplicate() is going to ignore this and we'll just carry on.
232  continue;
233  }
234 
235  // Move original back and exit. The duplicate will run in its own loop.
236  restore_state = true;
237  unselect = false;
238  chain_commands = true;
239  break;
240  }
241  }
242  //------------------------------------------------------------------------
243  // Handle context menu
244  //
245  else if( evt->IsClick( BUT_RIGHT ) )
246  {
248  }
249  //------------------------------------------------------------------------
250  // Handle drop
251  //
252  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
253  {
254  if( selection.GetSize() == 1 && selection.Front()->Type() == LIB_PIN_T )
255  {
257 
258  if( !pinTool->PlacePin( (LIB_PIN*) selection.Front() ) )
259  restore_state = true;
260  }
261 
262  break; // Finish
263  }
264  else
265  evt->SetPassEvent();
266 
267  } while( ( evt = Wait() ) ); // Assignment intentional; not equality test
268 
269  controls->ForceCursorPosition( false );
270  controls->ShowCursor( false );
271  controls->SetSnapping( false );
272  controls->SetAutoPan( false );
273 
274  if( !chain_commands )
275  m_moveOffset = { 0, 0 };
276 
277  m_anchorPos = { 0, 0 };
278 
279  for( auto item : selection )
280  item->ClearEditFlags();
281 
282  if( restore_state )
283  {
285 
286  if( unselect )
288  else
290  }
291  else
292  {
293  if( unselect )
295 
296  m_frame->OnModify();
297  }
298 
299  m_moveInProgress = false;
300  m_frame->PopTool( tool );
301  return 0;
302 }
303 
304 
306 {
307  static_cast<LIB_ITEM*>( aItem )->Offset( mapCoords( aDelta ));
308  aItem->SetFlags( IS_MOVED );
309 }
310 
311 
313 {
314  if( m_moveInProgress && aSelection.HasReferencePoint() )
315  return false;
316 
317  // When there is only one item selected, the reference point is its position...
318  if( aSelection.Size() == 1 )
319  {
320  LIB_ITEM* item = static_cast<LIB_ITEM*>( aSelection.Front() );
321  aSelection.SetReferencePoint( item->GetPosition() );
322  }
323  // ...otherwise modify items with regard to the grid-snapped cursor position
324  else
325  {
327  aSelection.SetReferencePoint( m_cursor );
328  }
329 
330  return true;
331 }
332 
333 
335 {
336  Go( &LIB_MOVE_TOOL::Main, EE_ACTIONS::move.MakeEvent() );
337 }
VECTOR2I m_cursor
Last cursor position (needed for getModificationPoint() to avoid changes of edit reference point).
Definition: lib_move_tool.h:73
virtual wxPoint GetPosition() const =0
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
bool m_moveInProgress
Flag determining if anything is being dragged right now
Definition: lib_move_tool.h:66
LIB_PART * GetCurPart() const
Return the current part being edited or NULL if none selected.
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
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
static const TOOL_EVENT SelectedEvent
Definition: actions.h:197
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
bool IsHover() const
Definition: selection.h:69
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
Model changes (required full reload)
Definition: tool_base.h:82
static TOOL_ACTION doDelete
Definition: actions.h:74
int GetOrientation() const
Definition: lib_pin.h:204
void SetCurrentCursor(wxStockCursor aStockCursorID)
Function SetCurrentCursor Set the current cursor shape for this panel.
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
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:219
static SELECTION_CONDITION IdleSelection
TOOL_MENU & GetToolMenu()
bool IsMotion() const
Definition: tool_event.h:306
virtual void SetSnapping(bool aEnabled)
Function SetSnapping() Enables/disables snapping cursor to grid.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
void setTransitions() override
Sets up handlers for various events.
TOOL_EVENT_CATEGORY Category() const
Returns the category (eg. mouse/keyboard/action) of an event..
Definition: tool_event.h:247
VECTOR2I m_anchorPos
Definition: lib_move_tool.h:74
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:201
The base class for drawable items used by schematic library components.
Definition: lib_item.h:61
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
bool IsNew() const
Definition: base_struct.h:228
bool updateModificationPoint(EE_SELECTION &aSelection)
Returns the right modification point (e.g.
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()
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:243
virtual void WarpCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
Function WarpCursor() If enabled (.
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:296
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:265
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
STATUS_FLAGS GetEditFlags() const
Definition: base_struct.h:270
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagates an event to tools that requested events of matching type(s).
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Class TOOL_EVENT.
Definition: tool_event.h:171
Define a library symbol object.
void SetPassEvent()
Definition: tool_event.h:256
Class VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (...
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:140
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:58
bool IsMouseUp(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:301
static VECTOR2D mapCoords(const wxPoint &aCoord)
int GetConvert() const
Definition: lib_item.h:304
bool IsCancelInteractive()
Function IsCancelInteractive()
Definition: tool_event.cpp:190
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
Definition: lib_pin.h:427
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.
int Modifier(int aMask=MD_MODIFIER_MASK) const
Returns information about key modifiers state (Ctrl, Alt, etc.)
Definition: tool_event.h:342
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:463
bool IsActivate() const
Definition: tool_event.h:321
bool HasReferencePoint() const
Definition: selection.h:233
void updateView(EDA_ITEM *aItem) const
Similar to getView()->Update(), but handles items that are redrawn by their parents.
Definition: ee_tool_base.h:104
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:117
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:163
bool GetMoveWarpsCursor() const
Indicates that a move operation should warp the mouse pointer to the origin of the move object.
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:79
virtual void PopTool(const std::string &actionName)
void Activate()
Function Activate() Runs the tool.
static TOOL_ACTION move
Definition: ee_actions.h:115
Class EE_TOOL_BASE.
Definition: ee_tool_base.h:50
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
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:237
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Function AddItem()
bool PlacePin(LIB_PIN *aPin)
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
static TOOL_ACTION duplicate
Definition: actions.h:73
static TOOL_ACTION refreshPreview
Definition: actions.h:101
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
Definition: base_struct.h:133
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:182
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210
virtual void UpdateMsgPanel()
Redraw the message panel.
VECTOR2I m_moveOffset
Used for chaining commands
Definition: lib_move_tool.h:69
#define IS_MOVED
Item being moved.
Definition: base_struct.h:119