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 )
111  {
112  if( !m_moveInProgress ) // Prepare to start moving/dragging
113  {
114  LIB_ITEM* lib_item = (LIB_ITEM*) selection.Front();
115 
116  // Pick up any synchronized pins
117  //
118  // Careful when pasting. The pasted pin will be at the same location as it
119  // was copied from, leading us to believe it's a synchronized pin. It's not.
120  if( selection.GetSize() == 1 && lib_item->Type() == LIB_PIN_T
122  && ( lib_item->GetEditFlags() & IS_PASTED ) == 0 )
123  {
124  LIB_PIN* cur_pin = (LIB_PIN*) lib_item;
125  LIB_PART* part = m_frame->GetCurPart();
126 
127  for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
128  {
129  if( pin->GetPosition() == cur_pin->GetPosition()
130  && pin->GetOrientation() == cur_pin->GetOrientation()
131  && pin->GetConvert() == cur_pin->GetConvert() )
132  {
133  m_selectionTool->AddItemToSel( pin, true /*quiet mode*/ );
134  }
135  }
136  }
137 
138  // Apply any initial offset in case we're coming from a previous command.
139  //
140  for( EDA_ITEM* item : selection )
141  moveItem( item, m_moveOffset );
142 
143  // Set up the starting position and move/drag offset
144  //
145  m_cursor = controls->GetCursorPosition();
146 
147  if( lib_item->IsNew() )
148  {
149  m_anchorPos = selection.GetReferencePoint();
150  VECTOR2I delta = m_cursor - mapCoords( m_anchorPos );
151 
152  // Drag items to the current cursor position
153  for( EDA_ITEM* item : selection )
154  {
155  moveItem( item, delta );
156  updateView( item );
157  }
158 
160  }
161  else if( selection.Size() == 1 && m_frame->GetMoveWarpsCursor() )
162  {
163  wxPoint itemPos = lib_item->GetPosition();
164  m_anchorPos = wxPoint( itemPos.x, -itemPos.y );
165 
166  getViewControls()->WarpCursor( m_anchorPos, true, true );
168  }
169  else
170  {
173  }
174 
175  controls->SetCursorPosition( m_cursor, false );
177 
178  prevPos = m_cursor;
179  controls->SetAutoPan( true );
180  m_moveInProgress = true;
181  }
182 
183  //------------------------------------------------------------------------
184  // Follow the mouse
185  //
186  m_cursor = controls->GetCursorPosition();
187  VECTOR2I delta( m_cursor - prevPos );
189 
190  m_moveOffset += delta;
191  prevPos = m_cursor;
192 
193  for( EDA_ITEM* item : selection )
194  {
195  moveItem( item, delta );
196  updateView( item );
197  }
198 
201  }
202  //------------------------------------------------------------------------
203  // Handle cancel
204  //
205  else if( evt->IsCancelInteractive() || evt->IsActivate() )
206  {
207  if( m_moveInProgress )
208  restore_state = true;
209 
210  break;
211  }
212  //------------------------------------------------------------------------
213  // Handle TOOL_ACTION special cases
214  //
215  else if( evt->Action() == TA_UNDO_REDO_PRE )
216  {
217  unselect = true;
218  break;
219  }
220  else if( evt->Category() == TC_COMMAND )
221  {
222  if( evt->IsAction( &ACTIONS::doDelete ) )
223  {
224  // Exit on a remove operation; there is no further processing for removed items.
225  break;
226  }
227  else if( evt->IsAction( &ACTIONS::duplicate ) )
228  {
229  if( selection.Front()->IsNew() )
230  {
231  // This doesn't really make sense; we'll just end up dragging a stack of
232  // objects so Duplicate() is going to ignore this and we'll just carry on.
233  continue;
234  }
235 
236  // Move original back and exit. The duplicate will run in its own loop.
237  restore_state = true;
238  unselect = false;
239  chain_commands = true;
240  break;
241  }
242  }
243  //------------------------------------------------------------------------
244  // Handle context menu
245  //
246  else if( evt->IsClick( BUT_RIGHT ) )
247  {
249  }
250  //------------------------------------------------------------------------
251  // Handle drop
252  //
253  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
254  {
255  if( selection.GetSize() == 1 && selection.Front()->Type() == LIB_PIN_T )
256  {
258 
259  if( !pinTool->PlacePin( (LIB_PIN*) selection.Front() ) )
260  restore_state = true;
261  }
262 
263  break; // Finish
264  }
265  else
266  evt->SetPassEvent();
267 
268  } while( ( evt = Wait() ) ); // Assignment intentional; not equality test
269 
270  controls->ForceCursorPosition( false );
271  controls->ShowCursor( false );
272  controls->SetSnapping( false );
273  controls->SetAutoPan( false );
274 
275  if( !chain_commands )
276  m_moveOffset = { 0, 0 };
277 
278  m_anchorPos = { 0, 0 };
279 
280  for( auto item : selection )
281  item->ClearEditFlags();
282 
283  if( restore_state )
284  {
286 
287  if( unselect )
289  else
291  }
292  else
293  {
294  if( unselect )
296 
297  m_frame->OnModify();
298  }
299 
300  m_moveInProgress = false;
301  m_frame->PopTool( tool );
302  return 0;
303 }
304 
305 
307 {
308  static_cast<LIB_ITEM*>( aItem )->Offset( mapCoords( aDelta ));
309  aItem->SetFlags( IS_MOVED );
310 }
311 
312 
314 {
315  if( m_moveInProgress && aSelection.HasReferencePoint() )
316  return false;
317 
318  // When there is only one item selected, the reference point is its position...
319  if( aSelection.Size() == 1 )
320  {
321  LIB_ITEM* item = static_cast<LIB_ITEM*>( aSelection.Front() );
322  aSelection.SetReferencePoint( item->GetPosition() );
323  }
324  // ...otherwise modify items with regard to the grid-snapped cursor position
325  else
326  {
328  aSelection.SetReferencePoint( m_cursor );
329  }
330 
331  return true;
332 }
333 
334 
336 {
337  Go( &LIB_MOVE_TOOL::Main, EE_ACTIONS::move.MakeEvent() );
339 }
VECTOR2I m_cursor
Last cursor position (needed for getModificationPoint() to avoid changes of edit reference point).
Definition: lib_move_tool.h:73
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
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:203
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
bool IsHover() const
Definition: selection.h:71
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:206
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()
static TOOL_ACTION symbolMoveActivate
Definition: ee_actions.h:111
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
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:140
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
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Moves cursor to the requested position expressed in world coordinates.
LIB_PART * GetCurPart()
Return the current part being edited or NULL if none selected.
VECTOR2I m_anchorPos
Definition: lib_move_tool.h:74
virtual wxPoint GetPosition() const
Definition: base_struct.h:337
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:207
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:199
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:245
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:232
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
STATUS_FLAGS GetEditFlags() const
Definition: base_struct.h:237
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagates an event to tools that requested events of matching type(s).
virtual void PopTool(const std::string &actionName)
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
Define a library symbol object.
void SetPassEvent()
Definition: tool_event.h:256
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:153
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:56
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:298
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:121
void moveItem(EDA_ITEM *aItem, VECTOR2I aDelta)
wxPoint GetPosition() const override
Definition: lib_pin.h:430
virtual unsigned int GetSize() const override
Function GetSize() Returns the number of stored items.
Definition: selection.h:100
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:235
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:127
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
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
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
bool GetMoveWarpsCursor() const
Indicates that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:107
void Activate()
Function Activate() Runs the tool.
static TOOL_ACTION move
Definition: ee_actions.h:113
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:268
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:102
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
Definition: base_struct.h:130
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:184
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
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:116