KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 <pgm_base.h>
32#include <pcbnew_settings.h>
36#include <tools/pcb_actions.h>
39
40
43 const wxString& aCommitMessage, int aOptions )
44{
45 using namespace std::placeholders;
46 std::unique_ptr<BOARD_ITEM> newItem;
47
48 frame()->PushTool( aTool );
49
50 BOARD_COMMIT commit( frame() );
51
53
54 Activate();
55 // Must be done after Activate() so that it gets set into the correct context
56 controls()->ShowCursor( true );
57 controls()->ForceCursorPosition( false );
58 // do not capture or auto-pan until we start placing an item
59
60 PCB_GRID_HELPER grid( m_toolMgr, frame()->GetMagneticItemsSettings() );
61
62 // Add a VIEW_GROUP that serves as a preview for the new item
63 PCB_SELECTION preview;
64 view()->Add( &preview );
65
66 aPlacer->m_board = board();
67 aPlacer->m_frame = frame();
68 aPlacer->m_modifiers = 0;
69
70 auto makeNewItem =
71 [&]( VECTOR2I aPosition )
72 {
73 if( frame()->GetModel() )
74 newItem = aPlacer->CreateItem();
75
76 if( newItem )
77 {
78 newItem->SetPosition( aPosition );
79 preview.Add( newItem.get() );
80
81 if( newItem->Type() == PCB_FOOTPRINT_T )
82 {
83 FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( newItem.get() );
84
85 // footprints have more drawable parts
86 fp->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) );
87 }
88 }
89 };
90
91 if( aOptions & IPO_SINGLE_CLICK )
92 makeNewItem( controls()->GetCursorPosition() );
93
94 auto setCursor =
95 [&]()
96 {
97 if( !newItem )
98 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
99 else
100 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
101 };
102
103 // Set initial cursor
104 setCursor();
105
106 // Main loop: keep receiving events
107 while( TOOL_EVENT* evt = Wait() )
108 {
109 setCursor();
110
111 grid.SetSnap( false ); // Interactive placement tools need to set their own item snaps
112 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
113 VECTOR2I cursorPos = grid.BestSnapAnchor( controls()->GetMousePosition(), nullptr );
114
115 aPlacer->m_modifiers = evt->Modifier();
116
117 auto cleanup =
118 [&] ()
119 {
120 newItem = nullptr;
121 preview.Clear();
122 view()->Update( &preview );
123 controls()->SetAutoPan( false );
124 controls()->CaptureCursor( false );
125 controls()->ShowCursor( true );
126 controls()->ForceCursorPosition( false );
127 };
128
129 if( evt->IsCancelInteractive() )
130 {
131 if( aOptions & IPO_SINGLE_CLICK )
132 {
133 cleanup();
134 frame()->PopTool( aTool );
135 break;
136 }
137 else if( newItem )
138 {
139 cleanup();
140 }
141 else
142 {
143 frame()->PopTool( aTool );
144 break;
145 }
146 }
147 else if( evt->IsActivate() )
148 {
149 if( newItem )
150 cleanup();
151
152 if( evt->IsPointEditor() )
153 {
154 // don't exit (the point editor runs in the background)
155 }
156 else if( evt->IsMoveTool() )
157 {
158 // leave ourselves on the stack so we come back after the move
159 break;
160 }
161 else
162 {
163 frame()->PopTool( aTool );
164 break;
165 }
166 }
167 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
168 {
169 if( !newItem )
170 {
171 // create the item if possible
172 makeNewItem( cursorPos );
173
174 // no item created, so wait for another click
175 if( !newItem )
176 continue;
177
178 controls()->CaptureCursor( true );
179 controls()->SetAutoPan( true );
180 }
181 else
182 {
183 BOARD_ITEM* newBoardItem = newItem.release();
184 EDA_ITEM_FLAGS oldFlags = newBoardItem->GetFlags();
185
186 newBoardItem->ClearFlags();
187
188 if( !aPlacer->PlaceItem( newBoardItem, commit ) )
189 {
190 newBoardItem->SetFlags( oldFlags );
191 newItem.reset( newBoardItem );
192 continue;
193 }
194
195 preview.Clear();
196 commit.Push( aCommitMessage );
197
198 controls()->CaptureCursor( false );
199 controls()->SetAutoPan( false );
200 controls()->ShowCursor( true );
201
202 if( !( aOptions & IPO_REPEAT ) )
203 break;
204
205 if( aOptions & IPO_SINGLE_CLICK )
206 makeNewItem( controls()->GetCursorPosition() );
207
208 setCursor();
209 }
210 }
211 else if( evt->IsClick( BUT_RIGHT ) )
212 {
214 }
215 else if( evt->IsAction( &PCB_ACTIONS::trackViaSizeChanged ) )
216 {
218 }
219 else if( newItem && evt->Category() == TC_COMMAND )
220 {
221 /*
222 * Handle any events that can affect the item as we move it around
223 */
224 if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) && ( aOptions & IPO_ROTATE ) )
225 {
226 EDA_ANGLE rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *frame(), *evt );
227 newItem->Rotate( newItem->GetPosition(), rotationAngle );
228 view()->Update( &preview );
229 }
230 else if( evt->IsAction( &PCB_ACTIONS::flip ) && ( aOptions & IPO_FLIP ) )
231 {
232 newItem->Flip( newItem->GetPosition(), frame()->GetPcbNewSettings()->m_FlipLeftRight );
233 view()->Update( &preview );
234 }
235 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
236 {
237 frame()->OnEditItemRequest( newItem.get() );
238
239 // Notify other tools of the changes
241 }
242 else if( evt->IsAction( &ACTIONS::refreshPreview ) )
243 {
244 preview.Clear();
245 newItem.reset();
246
247 makeNewItem( cursorPos );
248 aPlacer->SnapItem( newItem.get() );
249 view()->Update( &preview );
250 }
251 else
252 {
253 evt->SetPassEvent();
254 }
255 }
256 else if( newItem && evt->IsMotion() )
257 {
258 // track the cursor
259 newItem->SetPosition( cursorPos );
260 aPlacer->SnapItem( newItem.get() );
261
262 // Show a preview of the item
263 view()->Update( &preview );
264 }
265 else
266 {
267 evt->SetPassEvent();
268 }
269 }
270
271 view()->Remove( &preview );
272 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
273 controls()->SetAutoPan( false );
274 controls()->CaptureCursor( false );
275 controls()->ForceCursorPosition( false );
276}
277
278
280{
281 // A basic context manu. Many (but not all) tools will choose to override this.
282 CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
283
284 // cancel current tool goes in main context menu at the top if present
286 ctxMenu.AddSeparator( 1 );
287
288 // Finally, add the standard zoom/grid items
289 getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
290
291 return true;
292}
293
294
296{
297}
298
299
301{
302}
303
304
306{
307 return frame()->GetPcbNewSettings()->m_Display;
308}
309
311{
312 return static_cast<PCB_DRAW_PANEL_GAL*>( frame()->GetCanvas() );
313}
314
315
317{
319
320 return selTool->GetSelection();
321}
322
323
325{
327
328 return selTool->GetSelection();
329}
330
331
333{
334 SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
335
336 if( frame()->IsType( FRAME_PCB_EDITOR ) )
337 return mgr.GetAppSettings<PCBNEW_SETTINGS>()->m_Use45DegreeLimit;
338 else
339 return mgr.GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>()->m_Use45Limit;
340}
341
342
344{
345 // Base implementation performs no snapping
346}
347
348
350{
351 aCommit.Add( aItem );
352 return true;
353}
354
static TOOL_ACTION cancelInteractive
Definition: actions.h:63
static TOOL_ACTION refreshPreview
Definition: actions.h:110
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:71
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:79
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 AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:125
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:126
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
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:1392
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
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:75
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void Add(VIEW_ITEM *aItem)
Add an item to the group.
Definition: view_group.cpp:57
DISPLAY_OPTIONS m_Display
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:338
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:149
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:126
virtual void OnEditItemRequest(BOARD_ITEM *aItem)=0
Install the corresponding dialog editor for the given item.
PCBNEW_SETTINGS * GetPcbNewSettings() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
KIGFX::PCB_VIEW * view() const
virtual bool Is45Limited() const
Should the tool use its 45° mode option?
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
PCB_DRAW_PANEL_GAL * canvas() const
PCBNEW_SETTINGS::DISPLAY_OPTIONS & displayOptions() const
virtual void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
@ IPO_FLIP
Handle flip action in the loop by calling the item's flip method.
@ IPO_ROTATE
Handle the rotate action in the loop by calling the item's rotate method.
@ IPO_SINGLE_CLICK
Create an item immediately on placement starting, otherwise show the pencil cursor until the item is ...
@ IPO_REPEAT
Allow repeat placement of the item.
virtual bool Init() override
Init() is called once upon a registration of the tool.
virtual void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void doInteractiveItemPlacement(const TOOL_EVENT &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...
const PCB_SELECTION & selection() const
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:92
T * GetAppSettings()
Returns a handle to the a given settings by type If the settings have already been loaded,...
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:145
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
Generic, UI-independent tool event.
Definition: tool_event.h:156
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
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.
void Activate()
Run the tool.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
std::uint32_t EDA_ITEM_FLAGS
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
EDA_ANGLE GetEventRotationAngle(const PCB_BASE_EDIT_FRAME &aFrame, const TOOL_EVENT &aEvent)
Function getEventRotationAngle()
bool IsRotateToolEvt(const TOOL_EVENT &aEvt)
Function isRotateToolEvt()
see class PGM_BASE
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:115
virtual void SnapItem(BOARD_ITEM *aItem)
PCB_BASE_EDIT_FRAME * m_frame
Definition: pcb_tool_base.h:64
virtual std::unique_ptr< BOARD_ITEM > CreateItem()=0
virtual bool PlaceItem(BOARD_ITEM *aItem, BOARD_COMMIT &aCommit)
@ TC_COMMAND
Definition: tool_event.h:52
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86