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 <tool/tool_manager.h>
27 #include <board_commit.h>
28 #include <footprint.h>
29 #include <pcb_draw_panel_gal.h>
30 #include <pcbnew_settings.h>
31 
32 #include <tools/pcb_grid_helper.h>
34 #include <tools/pcb_actions.h>
35 #include <tools/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 
46  BOARD_COMMIT commit( frame() );
47 
49 
50  Activate();
51  // Must be done after Activate() so that it gets set into the correct context
52  controls()->ShowCursor( true );
53  // do not capture or auto-pan until we start placing an item
54 
55  PCB_GRID_HELPER grid( m_toolMgr, frame()->GetMagneticItemsSettings() );
56 
57  // Add a VIEW_GROUP that serves as a preview for the new item
58  PCB_SELECTION preview;
59  view()->Add( &preview );
60 
61  aPlacer->m_board = board();
62  aPlacer->m_frame = frame();
63  aPlacer->m_modifiers = 0;
64 
65  auto makeNewItem =
66  [&]( VECTOR2I aPosition )
67  {
68  if( frame()->GetModel() )
69  newItem = aPlacer->CreateItem();
70 
71  if( newItem )
72  {
73  newItem->SetPosition( (wxPoint) aPosition );
74  preview.Add( newItem.get() );
75 
76  if( newItem->Type() == PCB_FOOTPRINT_T )
77  {
78  FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( newItem.get() );
79 
80  // footprints have more drawable parts
81  fp->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) );
82  }
83  }
84  };
85 
86  if( aOptions & IPO_SINGLE_CLICK )
87  makeNewItem( controls()->GetCursorPosition() );
88 
89  auto setCursor =
90  [&]()
91  {
92  if( !newItem )
94  else
96  };
97 
98  // Set initial cursor
99  setCursor();
100 
101  // Main loop: keep receiving events
102  while( TOOL_EVENT* evt = Wait() )
103  {
104  setCursor();
105 
106  grid.SetSnap( false ); // Interactive placement tools need to set their own item snaps
107  grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
108  VECTOR2I cursorPos = grid.BestSnapAnchor( controls()->GetMousePosition(), nullptr );
109 
110  aPlacer->m_modifiers = evt->Modifier();
111 
112  auto cleanup =
113  [&] ()
114  {
115  newItem = nullptr;
116  preview.Clear();
117  view()->Update( &preview );
118  controls()->SetAutoPan( false );
119  controls()->CaptureCursor( false );
120  controls()->ShowCursor( true );
121  };
122 
123  if( evt->IsCancelInteractive() )
124  {
125  if( aOptions & IPO_SINGLE_CLICK )
126  {
127  cleanup();
128  frame()->PopTool( aTool );
129  break;
130  }
131  else if( newItem )
132  {
133  cleanup();
134  }
135  else
136  {
137  frame()->PopTool( aTool );
138  break;
139  }
140  }
141  else if( evt->IsActivate() )
142  {
143  if( newItem )
144  cleanup();
145 
146  if( evt->IsPointEditor() )
147  {
148  // don't exit (the point editor runs in the background)
149  }
150  else if( evt->IsMoveTool() )
151  {
152  // leave ourselves on the stack so we come back after the move
153  break;
154  }
155  else
156  {
157  frame()->PopTool( aTool );
158  break;
159  }
160  }
161  else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
162  {
163  if( !newItem )
164  {
165  // create the item if possible
166  makeNewItem( cursorPos );
167 
168  // no item created, so wait for another click
169  if( !newItem )
170  continue;
171 
172  controls()->CaptureCursor( true );
173  controls()->SetAutoPan( true );
174  }
175  else
176  {
177  auto oldFlags = newItem->GetFlags();
178  newItem->ClearFlags();
179 
180  if( !aPlacer->PlaceItem( newItem.get(), commit ) )
181  {
182  newItem->SetFlags( oldFlags );
183  continue;
184  }
185 
186  preview.Clear();
187  newItem.release();
188  commit.Push( aCommitMessage );
189 
190  controls()->CaptureCursor( false );
191  controls()->SetAutoPan( false );
192  controls()->ShowCursor( true );
193 
194  if( !( aOptions & IPO_REPEAT ) )
195  break;
196 
197  if( aOptions & IPO_SINGLE_CLICK )
198  makeNewItem( controls()->GetCursorPosition() );
199 
200  setCursor();
201  }
202  }
203  else if( evt->IsClick( BUT_RIGHT ) )
204  {
206  }
207  else if( evt->IsAction( &PCB_ACTIONS::trackViaSizeChanged ) )
208  {
210  }
211  else if( newItem && evt->Category() == TC_COMMAND )
212  {
213  /*
214  * Handle any events that can affect the item as we move it around
215  */
216  if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) && ( aOptions & IPO_ROTATE ) )
217  {
218  const int rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *frame(), *evt );
219  newItem->Rotate( newItem->GetPosition(), rotationAngle );
220  view()->Update( &preview );
221  }
222  else if( evt->IsAction( &PCB_ACTIONS::flip ) && ( aOptions & IPO_FLIP ) )
223  {
224  newItem->Flip( newItem->GetPosition(), frame()->Settings().m_FlipLeftRight );
225  view()->Update( &preview );
226  }
227  else if( evt->IsAction( &PCB_ACTIONS::viaSizeInc )
228  || evt->IsAction( &PCB_ACTIONS::viaSizeDec ) )
229  {
230  // Refresh preview after event runs
232  }
233  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
234  {
235  frame()->OnEditItemRequest( newItem.get() );
236 
237  // Notify other tools of the changes
239  }
240  else if( evt->IsAction( &ACTIONS::refreshPreview ) )
241  {
242  preview.Clear();
243  newItem.release();
244 
245  makeNewItem( (wxPoint) cursorPos );
246  aPlacer->SnapItem( newItem.get() );
247  view()->Update( &preview );
248  }
249  else
250  {
251  evt->SetPassEvent();
252  }
253  }
254  else if( newItem && evt->IsMotion() )
255  {
256  // track the cursor
257  newItem->SetPosition( (wxPoint) cursorPos );
258  aPlacer->SnapItem( newItem.get() );
259 
260  // Show a preview of the item
261  view()->Update( &preview );
262  }
263  else
264  {
265  evt->SetPassEvent();
266  }
267  }
268 
269  view()->Remove( &preview );
271  controls()->SetAutoPan( false );
272  controls()->CaptureCursor( false );
273 }
274 
275 
277 {
278  // A basic context manu. Many (but not all) tools will choose to override this.
279  CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
280 
281  // cancel current tool goes in main context menu at the top if present
283  ctxMenu.AddSeparator( 1 );
284 
285  // Finally, add the standard zoom/grid items
286  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
287 
288  return true;
289 }
290 
291 
293 {
294 }
295 
296 
298 {
299 }
300 
301 
303 {
304  return frame()->GetDisplayOptions();
305 }
306 
308 {
309  return static_cast<PCB_DRAW_PANEL_GAL*>( frame()->GetCanvas() );
310 }
311 
312 
314 {
316 
317  return selTool->GetSelection();
318 }
319 
320 
322 {
324 
325  return selTool->GetSelection();
326 }
327 
328 
330 {
331  return frame()->Settings().m_Use45DegreeLimit;
332 }
333 
334 
336 {
337  // Base implementation performs no snapping
338 }
339 
340 
342 {
343  aCommit.Add( aItem );
344  return true;
345 }
346 
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:82
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
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
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:31
static TOOL_ACTION viaSizeInc
Definition: pcb_actions.h:296
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
virtual std::unique_ptr< BOARD_ITEM > CreateItem()=0
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
virtual void OnEditItemRequest(BOARD_ITEM *aItem)=0
Install the corresponding dialog editor for the given item.
static TOOL_ACTION cancelInteractive
Definition: actions.h:62
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:117
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:299
virtual void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
bool IsRotateToolEvt(const TOOL_EVENT &aEvt)
Function isRotateToolEvt()
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:75
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:204
TOOL_MANAGER * GetManager() const
Return 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)
PCB_SELECTION & GetSelection()
Return the set of currently selected items.
Container for display options like enable/disable some optional drawings.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: pcb_view.cpp:92
const PCB_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.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
virtual void PopTool(const std::string &actionName)
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
Generic, UI-independent tool event.
Definition: tool_event.h:152
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)
Add an item to the group.
Definition: view_group.cpp:56
bool Is45Limited() const
Should the tool use its 45° mode option?
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
const PCB_DISPLAY_OPTIONS & displayOptions() const
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
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
virtual bool Init() override
Init() is called once upon a registration of the tool.
PCBNEW_SETTINGS & Settings()
The selection tool: currently supports:
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
void Activate()
Run the tool.
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invoke a function on all BOARD_ITEMs that belong to the footprint (pads, drawings,...
Definition: footprint.cpp:1236
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
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:64
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)
Add a menu entry to run a TOOL_ACTION on selected items.
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:59
static TOOL_ACTION viaSizeDec
Definition: pcb_actions.h:297
static TOOL_ACTION refreshPreview
Definition: actions.h:106