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 #include "pcb_selection_tool.h"
32 #include "pcb_actions.h"
33 #include "tool_event_utils.h"
34 
35 void PCB_TOOL_BASE::doInteractiveItemPlacement( const std::string& aTool,
36  INTERACTIVE_PLACER_BASE* aPlacer,
37  const wxString& aCommitMessage, int aOptions )
38 {
39  using namespace std::placeholders;
40  std::unique_ptr<BOARD_ITEM> newItem;
41 
42  frame()->PushTool( aTool );
43  Activate();
44 
45  BOARD_COMMIT commit( frame() );
46 
48 
49  // do not capture or auto-pan until we start placing an item
50  controls()->ShowCursor( true );
51 
52  // Add a VIEW_GROUP that serves as a preview for the new item
53  PCB_SELECTION preview;
54  view()->Add( &preview );
55 
56  aPlacer->m_board = board();
57  aPlacer->m_frame = frame();
58  aPlacer->m_modifiers = 0;
59 
60  auto makeNewItem =
61  [&]( VECTOR2I aPosition )
62  {
63  if( frame()->GetModel() )
64  newItem = aPlacer->CreateItem();
65 
66  if( newItem )
67  {
68  newItem->SetPosition( (wxPoint) aPosition );
69  preview.Add( newItem.get() );
70 
71  if( newItem->Type() == PCB_FOOTPRINT_T )
72  {
73  FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( newItem.get() );
74 
75  // footprints have more drawable parts
76  fp->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) );
77  }
78  }
79  };
80 
81  if( aOptions & IPO_SINGLE_CLICK )
82  makeNewItem( controls()->GetCursorPosition() );
83 
84  auto setCursor =
85  [&]()
86  {
87  if( !newItem )
89  else
91  };
92 
93  // Set initial cursor
94  setCursor();
95 
96  // Main loop: keep receiving events
97  while( TOOL_EVENT* evt = Wait() )
98  {
99  setCursor();
100 
101  VECTOR2I cursorPos = controls()->GetCursorPosition();
102  aPlacer->m_modifiers = evt->Modifier();
103 
104  auto cleanup =
105  [&] ()
106  {
107  newItem = nullptr;
108  preview.Clear();
109  view()->Update( &preview );
110  controls()->SetAutoPan( false );
111  controls()->CaptureCursor( false );
112  controls()->ShowCursor( true );
113  };
114 
115  if( evt->IsCancelInteractive() )
116  {
117  if( aOptions & IPO_SINGLE_CLICK )
118  {
119  cleanup();
120  frame()->PopTool( aTool );
121  break;
122  }
123  else if( newItem )
124  cleanup();
125  else
126  {
127  frame()->PopTool( aTool );
128  break;
129  }
130  }
131  else if( evt->IsActivate() )
132  {
133  if( newItem )
134  cleanup();
135 
136  if( evt->IsPointEditor() )
137  {
138  // don't exit (the point editor runs in the background)
139  }
140  else if( evt->IsMoveTool() )
141  {
142  // leave ourselves on the stack so we come back after the move
143  break;
144  }
145  else
146  {
147  frame()->PopTool( aTool );
148  break;
149  }
150  }
151  else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
152  {
153  if( !newItem )
154  {
155  // create the item if possible
156  makeNewItem( cursorPos );
157 
158  // no item created, so wait for another click
159  if( !newItem )
160  continue;
161 
162  controls()->CaptureCursor( true );
163  controls()->SetAutoPan( true );
164  }
165  else
166  {
167  auto oldFlags = newItem->GetFlags();
168  newItem->ClearFlags();
169 
170  if( !aPlacer->PlaceItem( newItem.get(), commit ) )
171  {
172  newItem->SetFlags( oldFlags );
173  continue;
174  }
175 
176  preview.Clear();
177  newItem.release();
178  commit.Push( aCommitMessage );
179 
180  controls()->CaptureCursor( false );
181  controls()->SetAutoPan( false );
182  controls()->ShowCursor( true );
183 
184  if( !( aOptions & IPO_REPEAT ) )
185  break;
186 
187  if( aOptions & IPO_SINGLE_CLICK )
188  makeNewItem( controls()->GetCursorPosition() );
189 
190  setCursor();
191  }
192  }
193  else if( evt->IsClick( BUT_RIGHT ) )
194  {
196  }
197  else if( evt->IsAction( &PCB_ACTIONS::trackViaSizeChanged ) )
198  {
200  }
201  else if( newItem && evt->Category() == TC_COMMAND )
202  {
203  /*
204  * Handle any events that can affect the item as we move it around
205  */
206  if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) && ( aOptions & IPO_ROTATE ) )
207  {
208  const int rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *frame(), *evt );
209  newItem->Rotate( newItem->GetPosition(), rotationAngle );
210  view()->Update( &preview );
211  }
212  else if( evt->IsAction( &PCB_ACTIONS::flip ) && ( aOptions & IPO_FLIP ) )
213  {
214  newItem->Flip( newItem->GetPosition(), frame()->Settings().m_FlipLeftRight );
215  view()->Update( &preview );
216  }
217  else if( evt->IsAction( &PCB_ACTIONS::viaSizeInc )
218  || evt->IsAction( &PCB_ACTIONS::viaSizeDec ) )
219  {
220  // Refresh preview after event runs
222  }
223  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
224  {
225  frame()->OnEditItemRequest( newItem.get() );
226 
227  // Notify other tools of the changes
229  }
230  else if( evt->IsAction( &ACTIONS::refreshPreview ) )
231  {
232  preview.Clear();
233  newItem.release();
234 
235  makeNewItem( (wxPoint) cursorPos );
236  aPlacer->SnapItem( newItem.get() );
237  view()->Update( &preview );
238  }
239  else
240  {
241  evt->SetPassEvent();
242  }
243  }
244  else if( newItem && evt->IsMotion() )
245  {
246  // track the cursor
247  newItem->SetPosition( (wxPoint) cursorPos );
248  aPlacer->SnapItem( newItem.get() );
249 
250  // Show a preview of the item
251  view()->Update( &preview );
252  }
253  else
254  {
255  evt->SetPassEvent();
256  }
257  }
258 
259  view()->Remove( &preview );
261 }
262 
263 
265 {
266  // A basic context manu. Many (but not all) tools will choose to override this.
267  CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
268 
269  // cancel current tool goes in main context menu at the top if present
271  ctxMenu.AddSeparator( 1 );
272 
273  // Finally, add the standard zoom/grid items
274  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
275 
276  return true;
277 }
278 
279 
281 {
282 }
283 
284 
286 {
287 }
288 
289 
291 {
292  return frame()->GetDisplayOptions();
293 }
294 
296 {
297  return static_cast<PCB_DRAW_PANEL_GAL*>( frame()->GetCanvas() );
298 }
299 
300 
302 {
304 
305  return selTool->GetSelection();
306 }
307 
308 
310 {
312 
313  return selTool->GetSelection();
314 }
315 
316 
318 {
319  // Base implementation performs no snapping
320 }
321 
322 
324 {
325  aCommit.Add( aItem );
326  return true;
327 }
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:63
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:96
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:82
static TOOL_ACTION viaSizeInc
Definition: pcb_actions.h:300
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:215
virtual void OnEditItemRequest(BOARD_ITEM *aItem)=0
Install the corresponding dialog editor for the given item.
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.
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:121
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:141
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:303
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...
void SetCurrentCursor(KICURSOR cursor)
Set the current cursor shape for this panel.
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:214
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:77
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:144
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:173
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
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:109
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:78
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:1174
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:65
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:301
static TOOL_ACTION refreshPreview
Definition: actions.h:109
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.