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 <pcbnew_settings.h>
33 #include "selection_tool.h"
34 #include "pcb_actions.h"
35 #include "tool_event_utils.h"
36 
37 void PCB_TOOL_BASE::doInteractiveItemPlacement( const std::string& aTool,
38  INTERACTIVE_PLACER_BASE* aPlacer,
39  const wxString& aCommitMessage, int aOptions )
40 {
41  using namespace std::placeholders;
42  std::unique_ptr<BOARD_ITEM> newItem;
43 
44  frame()->PushTool( aTool );
45  Activate();
46 
47  BOARD_COMMIT commit( frame() );
48 
50 
51  // do not capture or auto-pan until we start placing an item
52  controls()->ShowCursor( 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  if( !newItem )
89  frame()->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL );
90  else
91  frame()->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
92 
93  VECTOR2I cursorPos = controls()->GetCursorPosition();
94  aPlacer->m_modifiers = evt->Modifier();
95 
96  auto cleanup = [&] ()
97  {
98  newItem = nullptr;
99  preview.Clear();
100  view()->Update( &preview );
101  controls()->SetAutoPan( false );
102  controls()->CaptureCursor( false );
103  controls()->ShowCursor( true );
104  };
105 
106  if( evt->IsCancelInteractive() )
107  {
108  if( aOptions & IPO_SINGLE_CLICK )
109  {
110  cleanup();
111  frame()->PopTool( aTool );
112  break;
113  }
114  else if( newItem )
115  cleanup();
116  else
117  {
118  frame()->PopTool( aTool );
119  break;
120  }
121  }
122  else if( evt->IsActivate() )
123  {
124  if( newItem )
125  cleanup();
126 
127  if( evt->IsPointEditor() )
128  {
129  // don't exit (the point editor runs in the background)
130  }
131  else if( evt->IsMoveTool() )
132  {
133  // leave ourselves on the stack so we come back after the move
134  break;
135  }
136  else
137  {
138  frame()->PopTool( aTool );
139  break;
140  }
141  }
142  else if( evt->IsClick( BUT_LEFT ) )
143  {
144  if( !newItem )
145  {
146  // create the item if possible
147  makeNewItem( cursorPos );
148 
149  // no item created, so wait for another click
150  if( !newItem )
151  continue;
152 
153  controls()->CaptureCursor( true );
154  controls()->SetAutoPan( true );
155  }
156  else
157  {
158  auto oldFlags = newItem->GetFlags();
159  newItem->ClearFlags();
160 
161  if( !aPlacer->PlaceItem( newItem.get(), commit ) )
162  {
163  newItem->SetFlags( oldFlags );
164  continue;
165  }
166 
167  preview.Clear();
168  newItem.release();
169  commit.Push( aCommitMessage );
170 
171  controls()->CaptureCursor( false );
172  controls()->SetAutoPan( false );
173  controls()->ShowCursor( true );
174 
175  if( !( aOptions & IPO_REPEAT ) )
176  break;
177 
178  if( aOptions & IPO_SINGLE_CLICK )
179  makeNewItem( controls()->GetCursorPosition() );
180  }
181  }
182  else if( evt->IsClick( BUT_RIGHT ) )
183  {
185  }
186  else if( evt->IsAction( &PCB_ACTIONS::trackViaSizeChanged ) )
187  {
189  }
190  else if( newItem && evt->Category() == TC_COMMAND )
191  {
192  /*
193  * Handle any events that can affect the item as we move it around
194  */
195  if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) && ( aOptions & IPO_ROTATE ) )
196  {
197  const int rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *frame(), *evt );
198  newItem->Rotate( newItem->GetPosition(), rotationAngle );
199  view()->Update( &preview );
200  }
201  else if( evt->IsAction( &PCB_ACTIONS::flip ) && ( aOptions & IPO_FLIP ) )
202  {
203  newItem->Flip( newItem->GetPosition(), frame()->Settings().m_FlipLeftRight );
204  view()->Update( &preview );
205  }
206  else if( evt->IsAction( &PCB_ACTIONS::viaSizeInc )
207  || evt->IsAction( &PCB_ACTIONS::viaSizeDec ) )
208  {
209  // Refresh preview after event runs
211  }
212  else if( evt->IsAction( &ACTIONS::refreshPreview ) )
213  {
214  preview.Clear();
215  newItem.release();
216 
217  makeNewItem( (wxPoint) cursorPos );
218  aPlacer->SnapItem( newItem.get() );
219  view()->Update( &preview );
220  }
221  }
222 
223  else if( newItem && evt->IsMotion() )
224  {
225  // track the cursor
226  newItem->SetPosition( (wxPoint) cursorPos );
227  aPlacer->SnapItem( newItem.get() );
228 
229  // Show a preview of the item
230  view()->Update( &preview );
231  }
232 
233  else
234  evt->SetPassEvent();
235  }
236 
237  view()->Remove( &preview );
238 }
239 
240 
242 {
243  // A basic context manu. Many (but not all) tools will choose to override this.
244 
245  auto& ctxMenu = m_menu.GetMenu();
246 
247  // cancel current tool goes in main context menu at the top if present
249  ctxMenu.AddSeparator( 1 );
250 
251  // Finally, add the standard zoom/grid items
252  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
253 
254  return true;
255 }
256 
257 
259 {
260 }
261 
262 
264 {
265 }
266 
267 
269 {
270  return frame()->GetDisplayOptions();
271 }
272 
274 {
275  return static_cast<PCB_DRAW_PANEL_GAL*>( frame()->GetCanvas() );
276 }
277 
278 
280 {
281  auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
282  const auto& selection = selTool->GetSelection();
283  return selection;
284 }
285 
286 
288 {
289  auto selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
290  auto& selection = selTool->GetSelection();
291  return selection;
292 }
293 
294 
296 {
297  // Base implementation performs no snapping
298 }
299 
300 
302 {
303  aCommit.Add( aItem );
304  return true;
305 }
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:62
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
virtual void Clear() override
Function Clear() Removes all the stored items from the group.
Definition: selection.h:95
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)
Handle flip action in the loop by calling the item's flip method.
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:93
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
static TOOL_ACTION viaSizeInc
Definition: pcb_actions.h:283
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
virtual std::unique_ptr< BOARD_ITEM > CreateItem()=0
void SetCurrentCursor(wxStockCursor aStockCursorID)
Function SetCurrentCursor Set the current cursor shape for this panel.
VIEW_CONTROLS class definition.
SELECTION_TOOL.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
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 PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:140
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:286
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()
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Function GetDisplayOptions Display options control the way tracks, vias, outlines and other things ar...
virtual void Remove(VIEW_ITEM *aItem) override
Function Remove() Removes a VIEW_ITEM from the view.
Definition: pcb_view.cpp:76
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:76
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
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.
Allow repeat placement of the item.
virtual void PopTool(const std::string &actionName)
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
TOOL_EVENT.
Definition: tool_event.h:171
KIGFX::PCB_VIEW * view() const
Create an item immediately on placement starting, otherwise show the pencil cursor until the item is ...
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.
const PCB_DISPLAY_OPTIONS & displayOptions() const
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
Function GetModel()
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:105
Handle the rotate action in the loop by calling the item's rotate method.
KIGFX::VIEW_CONTROLS * controls() const
MODULE * module() const
virtual bool Init() override
Function Init() Init() is called once upon a registration of the tool.
PCBNEW_SETTINGS & Settings()
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
void Activate()
Function Activate() Runs the tool.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Function Add() Adds a VIEW_ITEM to the view.
Definition: pcb_view.cpp:59
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:62
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)
Adds a menu entry to run a TOOL_ACTION on selected items.
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
static TOOL_ACTION viaSizeDec
Definition: pcb_actions.h:284
static TOOL_ACTION refreshPreview
Definition: actions.h:104
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.