KiCad PCB EDA Suite
pcb_tool_base.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) 2017-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 "pcb_tool_base.h"
25 
26 #include <view/view_controls.h>
27 #include <view/view.h>
28 #include <tool/tool_manager.h>
29 #include <board_commit.h>
30 #include <class_module.h>
31 #include <pcb_draw_panel_gal.h>
32 #include "selection_tool.h"
33 #include "pcb_actions.h"
34 #include "tool_event_utils.h"
35 
36 void PCB_TOOL_BASE::doInteractiveItemPlacement( const std::string& aTool,
37  INTERACTIVE_PLACER_BASE* aPlacer,
38  const wxString& aCommitMessage, int aOptions )
39 {
40  using namespace std::placeholders;
41  std::unique_ptr<BOARD_ITEM> newItem;
42 
43  frame()->PushTool( aTool );
44  Activate();
45 
46  BOARD_COMMIT commit( frame() );
47 
49 
50  // do not capture or auto-pan until we start placing an item
51  controls()->ShowCursor( true );
52  controls()->SetSnapping( true );
53 
54  // Add a VIEW_GROUP that serves as a preview for the new item
55  PCBNEW_SELECTION preview;
56  view()->Add( &preview );
57 
58  aPlacer->m_board = board();
59  aPlacer->m_frame = frame();
60  aPlacer->m_modifiers = 0;
61 
62  auto makeNewItem = [&] ( VECTOR2I aPosition )
63  {
64  if( frame()->GetModel() )
65  newItem = aPlacer->CreateItem();
66 
67  if( newItem )
68  {
69  newItem->SetPosition( (wxPoint) aPosition );
70  preview.Add( newItem.get() );
71 
72  if( newItem->Type() == PCB_MODULE_T )
73  {
74  auto module = dyn_cast<MODULE*>( newItem.get() );
75 
76  // modules have more drawable parts
77  module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) );
78  }
79  }
80  };
81 
82  if( aOptions & IPO_SINGLE_CLICK )
83  makeNewItem( controls()->GetCursorPosition() );
84 
85  // Main loop: keep receiving events
86  while( TOOL_EVENT* evt = Wait() )
87  {
88  VECTOR2I cursorPos = controls()->GetCursorPosition();
89  aPlacer->m_modifiers = evt->Modifier();
90 
91  auto cleanup = [&] ()
92  {
93  newItem = nullptr;
94  preview.Clear();
95  view()->Update( &preview );
96  controls()->SetAutoPan( false );
97  controls()->CaptureCursor( false );
98  controls()->ShowCursor( true );
99  };
100 
101  if( evt->IsCancelInteractive() )
102  {
103  if( aOptions & IPO_SINGLE_CLICK )
104  {
105  cleanup();
106  frame()->PopTool( aTool );
107  break;
108  }
109  else if( newItem )
110  cleanup();
111  else
112  {
113  frame()->PopTool( aTool );
114  break;
115  }
116  }
117  else if( evt->IsActivate() )
118  {
119  if( newItem )
120  cleanup();
121 
122  if( evt->IsPointEditor() )
123  {
124  // don't exit (the point editor runs in the background)
125  }
126  else if( evt->IsMoveTool() )
127  {
128  // leave ourselves on the stack so we come back after the move
129  break;
130  }
131  else
132  {
133  frame()->PopTool( aTool );
134  break;
135  }
136  }
137  else if( evt->IsClick( BUT_LEFT ) )
138  {
139  if( !newItem )
140  {
141  // create the item if possible
142  makeNewItem( cursorPos );
143 
144  // no item created, so wait for another click
145  if( !newItem )
146  continue;
147 
148  controls()->CaptureCursor( true );
149  controls()->SetAutoPan( true );
150  }
151  else
152  {
153  auto oldFlags = newItem->GetFlags();
154  newItem->ClearFlags();
155 
156  if( !aPlacer->PlaceItem( newItem.get(), commit ) )
157  {
158  newItem->SetFlags( oldFlags );
159  continue;
160  }
161 
162  preview.Clear();
163  newItem.release();
164  commit.Push( aCommitMessage );
165 
166  controls()->CaptureCursor( false );
167  controls()->SetAutoPan( false );
168  controls()->ShowCursor( true );
169 
170  if( !( aOptions & IPO_REPEAT ) )
171  break;
172 
173  if( aOptions & IPO_SINGLE_CLICK )
174  makeNewItem( controls()->GetCursorPosition() );
175  }
176  }
177  else if( evt->IsClick( BUT_RIGHT ) )
178  {
180  }
181  else if( newItem && evt->Category() == TC_COMMAND )
182  {
183  /*
184  * Handle any events that can affect the item as we move
185  * it around, eg rotate and flip
186  */
187 
188  if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) && ( aOptions & IPO_ROTATE ) )
189  {
190  const int rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *frame(), *evt );
191  newItem->Rotate( newItem->GetPosition(), rotationAngle );
192  view()->Update( &preview );
193  }
194  else if( evt->IsAction( &PCB_ACTIONS::flip ) && ( aOptions & IPO_FLIP ) )
195  {
196  newItem->Flip( newItem->GetPosition(), frame()->Settings().m_FlipLeftRight );
197  view()->Update( &preview );
198  }
199  }
200 
201  else if( newItem && evt->IsMotion() )
202  {
203  // track the cursor
204  newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
205  aPlacer->SnapItem( newItem.get() );
206 
207  // Show a preview of the item
208  view()->Update( &preview );
209  }
210 
211  else
212  evt->SetPassEvent();
213  }
214 
215  view()->Remove( &preview );
216 }
217 
218 
220 {
221  // A basic context manu. Many (but not all) tools will choose to override this.
222 
223  auto& ctxMenu = m_menu.GetMenu();
224 
225  // cancel current tool goes in main context menu at the top if present
227  ctxMenu.AddSeparator( 1 );
228 
229  // Finally, add the standard zoom/grid items
230  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
231 
232  return true;
233 }
234 
235 
237 {
238 }
239 
240 
242 {
243 }
244 
245 
247 {
248  return static_cast<PCB_DISPLAY_OPTIONS*>( frame()->GetDisplayOptions() );
249 }
250 
252 {
253  return static_cast<PCB_DRAW_PANEL_GAL*>( frame()->GetCanvas() );
254 }
255 
256 
258 {
259  auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
260  const auto& selection = selTool->GetSelection();
261  return selection;
262 }
263 
264 
266 {
267  auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
268  auto& selection = selTool->GetSelection();
269  return selection;
270 }
271 
272 
274 {
275  // Base implementation performs no snapping
276 }
277 
278 
280 {
281  aCommit.Add( aItem );
282  return true;
283 }
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:73
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
static bool ShowAlways(const SELECTION &aSelection)
Function ShowAlways The default condition function (always returns true).
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
PCB_DISPLAY_OPTIONS * displayOptions() const
virtual void Clear() override
Function Clear() Removes all the stored items from the group.
Definition: selection.h:93
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction)
Function RunOnChildren.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
virtual bool PlaceItem(BOARD_ITEM *aItem, BOARD_COMMIT &aCommit)
BOARD * board() const
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags) override
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: pcb_view.cpp:91
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
virtual std::unique_ptr< BOARD_ITEM > CreateItem()=0
VIEW_CONTROLS class definition.
Class SELECTION_TOOL.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
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
virtual void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
bool IsRotateToolEvt(const TOOL_EVENT &aEvt)
Function isRotateToolEvt()
virtual void Remove(VIEW_ITEM *aItem) override
Function Remove() Removes a VIEW_ITEM from the view.
Definition: pcb_view.cpp:74
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:74
TOOL_MANAGER * GetManager() const
Function GetManager() Returns the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:143
PCB_BASE_EDIT_FRAME * frame() const
virtual void SnapItem(BOARD_ITEM *aItem)
class MODULE, a footprint
Definition: typeinfo.h:89
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
const PCBNEW_SELECTION & selection() const
virtual void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
PCB_GENERAL_SETTINGS & Settings()
Class TOOL_EVENT.
Definition: tool_event.h:168
KIGFX::PCB_VIEW * view() const
virtual void Add(VIEW_ITEM *aItem)
Function Add() Adds an item to the group.
Definition: view_group.cpp:55
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:115
KIGFX::VIEW_CONTROLS * controls() const
MODULE * module() const
virtual bool Init() override
Function Init() Init() is called once upon a registration of the tool.
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
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.
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
Function GetModel()
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Function Add() Adds a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
Module description (excepted pads)
void doInteractiveItemPlacement(const std::string &aTool, INTERACTIVE_PLACER_BASE *aPlacer, const wxString &aCommitMessage, int aOptions=IPO_ROTATE|IPO_FLIP|IPO_REPEAT)
Helper function for performing a common interactive idiom: wait for a left click, place an item there...
PCB_BASE_EDIT_FRAME * m_frame
Definition: pcb_tool_base.h:58
PCB_DRAW_PANEL_GAL * canvas() const
int GetEventRotationAngle(const PCB_BASE_EDIT_FRAME &aFrame, const TOOL_EVENT &aEvt)
Function getEventRotationAngle()
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Function AddItem()
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.