KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_picker_tool.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) 2015 CERN
5 * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "pcb_picker_tool.h"
27
28#include "pcb_actions.h"
29#include "pcb_grid_helper.h"
31#include <kiplatform/ui.h>
32#include <status_popup.h>
35#include <view/view_controls.h>
36
37
39 PCB_TOOL_BASE( "pcbnew.InteractivePicker" ),
40 PICKER_TOOL_BASE() // calls reset()
41{
42}
43
44
46{
47 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
48 MAGNETIC_SETTINGS& magneticSettings = *frame->GetMagneticItemsSettings();
49 CONDITIONAL_MENU& menu = m_menu->GetMenu();
50
51 const auto snapIsSetToAllLayers = [&]( const SELECTION& aSel )
52 {
53 return magneticSettings.allLayers;
54 };
55
56 // "Cancel" goes at the top of the context menu when a tool is active
58
59 menu.AddSeparator( 1 );
60
61 menu.AddItem( PCB_ACTIONS::magneticSnapAllLayers, !snapIsSetToAllLayers, 1 );
62 menu.AddItem( PCB_ACTIONS::magneticSnapActiveLayer, snapIsSetToAllLayers, 1 );
63
64 menu.AddSeparator( 1 );
65
66 if( frame )
67 frame->AddStandardSubMenus( *m_menu.get() );
68
69 return true;
70}
71
72
74{
76 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
77 PCB_GRID_HELPER grid( m_toolMgr, frame->GetMagneticItemsSettings() );
78 int finalize_state = WAIT_CANCEL;
79
80 TOOL_EVENT sourceEvent;
81
82 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
83 {
84 wxCHECK_MSG( aEvent.Parameter<const TOOL_EVENT*>(), -1,
85 wxT( "PCB_PICKER_TOOL::Main() called without a source event" ) );
86
87 sourceEvent = *aEvent.Parameter<const TOOL_EVENT*>();
88 frame->PushTool( sourceEvent );
89 }
90
91 Activate();
93
94 auto setCursor =
95 [&]()
96 {
97 frame->GetCanvas()->SetCurrentCursor( m_cursor );
98 controls->ShowCursor( true );
99 };
100
101 // Set initial cursor
102 setCursor();
103 VECTOR2D cursorPos;
104
105 while( TOOL_EVENT* evt = Wait() )
106 {
107 setCursor();
108 cursorPos = controls->GetMousePosition();
109
110 if( m_snap )
111 {
112 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
113 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
114 cursorPos = grid.BestSnapAnchor( cursorPos, m_layerMask );
115 controls->ForceCursorPosition( true, cursorPos );
116 }
117
118 if( evt->IsCancelInteractive() || evt->IsActivate() )
119 {
120 if( m_cancelHandler )
121 {
122 try
123 {
124 (*m_cancelHandler)();
125 }
126 catch( std::exception& )
127 {
128 }
129 }
130
131 // Activating a new tool may have alternate finalization from canceling the current tool
132 if( evt->IsActivate() )
133 finalize_state = END_ACTIVATE;
134 else
135 finalize_state = EVT_CANCEL;
136
137 break;
138 }
139 else if( evt->IsClick( BUT_LEFT ) )
140 {
141 bool getNext = false;
142
143 m_picked = cursorPos;
144
145 if( m_clickHandler )
146 {
147 try
148 {
149 getNext = (*m_clickHandler)( *m_picked );
150 }
151 catch( std::exception& )
152 {
153 finalize_state = EXCEPTION_CANCEL;
154 break;
155 }
156 }
157
158 if( !getNext )
159 {
160 finalize_state = CLICK_CANCEL;
161 break;
162 }
163 else
164 {
165 setControls();
166 }
167 }
168 else if( evt->IsMotion() )
169 {
170 if( m_motionHandler )
171 {
172 try
173 {
174 (*m_motionHandler)( cursorPos );
175 }
176 catch( std::exception& )
177 {
178 }
179 }
180 }
181 else if( evt->IsDblClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) )
182 {
183 // Not currently used, but we don't want to pass them either
184 }
185 else if( evt->IsClick( BUT_RIGHT ) )
186 {
188 m_menu->ShowContextMenu( dummy );
189 }
190 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
191 // but we don't at present have that, so we just knock out some of the egregious ones.
192 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
193 {
194 wxBell();
195 }
196 else
197 {
198 evt->SetPassEvent();
199 }
200 }
201
203 {
204 try
205 {
206 (*m_finalizeHandler)( finalize_state );
207 }
208 catch( std::exception& )
209 {
210 }
211 }
212
213 reset();
215 controls->ShowCursor( false );
216
217 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
218 frame->PopTool( sourceEvent );
219
220 return 0;
221}
222
223
225{
228}
229
230
232{
234
235 controls->CaptureCursor( false );
236 controls->SetAutoPan( false );
237}
238
239
241{
243 STATUS_TEXT_POPUP statusPopup( frame() );
244 bool done = false;
245
246 wxCHECK( params.m_Receiver, -1 );
247
248 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
249
250 Activate();
251
252 statusPopup.SetText( _( params.m_Prompt ) );
253
254 const auto sendPoint = [&]( const std::optional<VECTOR2I>& aPoint )
255 {
256 statusPopup.Hide();
257 params.m_Receiver->UpdatePickedPoint( aPoint );
258 };
259
261 [&]( const VECTOR2D& aPoint ) -> bool
262 {
263 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
264
265 sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
266
267 return false; // got our item; don't need any more
268 } );
269
271 [&]( const VECTOR2D& aPos )
272 {
273 grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
274 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
275 } );
276
278 [&]()
279 {
280 sendPoint( std::nullopt );
281 } );
282
284 [&]( const int& aFinalState )
285 {
286 done = true;
287 } );
288
289 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
290 statusPopup.Popup();
291 canvas()->SetStatusPopup( statusPopup.GetPanel() );
292
293 // Drop into the main event loop
294 Main( aEvent );
295
296 canvas()->SetStatusPopup( nullptr );
297 return 0;
298}
299
301{
303 STATUS_TEXT_POPUP statusPopup( frame() );
304 bool done = false;
305 EDA_ITEM* anchor_item = nullptr;
306
308
309 Activate();
310
311 statusPopup.SetText( _( params.m_Prompt ) );
312
313 const auto sendItem = [&]( const EDA_ITEM* aItem )
314 {
315 statusPopup.Hide();
316 params.m_Receiver->UpdatePickedItem( aItem );
317 };
318
320 [&]( const VECTOR2D& aPoint ) -> bool
321 {
323 const PCB_SELECTION& sel = selectionTool->RequestSelection(
324 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
325 PCB_SELECTION_TOOL* sTool )
326 {
327 } );
328
329 if( sel.Empty() )
330 return true; // still looking for an item
331
332 anchor_item = sel.Front();
333
334 if( params.m_ItemFilter && !params.m_ItemFilter( anchor_item ) )
335 return true;
336
337 sendItem( sel.Front() );
338 return false; // got our item; don't need any more
339 } );
340
342 [&]( const VECTOR2D& aPos )
343 {
344 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
345 } );
346
348 [&]()
349 {
350 if( anchor_item && ( !params.m_ItemFilter || params.m_ItemFilter( anchor_item ) ) )
351 sendItem( anchor_item );
352 } );
353
355 [&]( const int& aFinalState )
356 {
357 done = true;
358 } );
359
360 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
361 statusPopup.Popup();
362 canvas()->SetStatusPopup( statusPopup.GetPanel() );
363
364 // Drop into the main event loop
365 Main( aEvent );
366
367 canvas()->SetStatusPopup( nullptr );
368 return 0;
369}
370
371
373{
374 // clang-format off
379 // clang-format on
380}
static TOOL_ACTION pickerSubTool
Definition: actions.h:205
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
static TOOL_ACTION pickerTool
Definition: actions.h:204
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 SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:202
void SetSnap(bool aSnap)
Definition: grid_helper.h:111
std::optional< VECTOR2I > GetSnappedPoint() const
An interface for classes handling user events controlling the view behavior such as zooming,...
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 VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
static LSET AllLayersMask()
Definition: lset.cpp:711
static TOOL_ACTION magneticSnapAllLayers
Definition: pcb_actions.h:248
static TOOL_ACTION magneticSnapActiveLayer
Snapping controls.
Definition: pcb_actions.h:247
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION selectPointInteractively
Definition: pcb_actions.h:332
static TOOL_ACTION selectItemInteractively
Selection of reference points/items.
Definition: pcb_actions.h:331
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
virtual void UpdatePickedItem(const EDA_ITEM *aItem)=0
virtual void UpdatePickedPoint(const std::optional< VECTOR2I > &aPoint)=0
int SelectItemInteractively(const TOOL_EVENT &aEvent)
LSET m_layerMask
< The layer set to use for optional snapping.
bool Init() override
Main event loop.
int SelectPointInteractively(const TOOL_EVENT &aEvent)
int Main(const TOOL_EVENT &aEvent)
void setControls()
Reinitialize tool to its initial state.
void reset() override
< Reinitializes tool to its initial state.
void setTransitions() override
<
The selection tool: currently supports:
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
T * frame() const
KIGFX::VIEW_CONTROLS * controls() const
PCB_DRAW_PANEL_GAL * canvas() const
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition: picker_tool.h:84
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:73
int CurrentModifiers() const
Definition: picker_tool.h:110
std::optional< VECTOR2D > m_picked
Definition: picker_tool.h:126
std::optional< FINALIZE_HANDLER > m_finalizeHandler
Definition: picker_tool.h:124
std::optional< MOTION_HANDLER > m_motionHandler
Definition: picker_tool.h:122
std::optional< CLICK_HANDLER > m_clickHandler
Definition: picker_tool.h:121
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
Definition: picker_tool.h:93
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:104
std::optional< CANCEL_HANDLER > m_cancelHandler
Definition: picker_tool.h:123
KICURSOR m_cursor
Definition: picker_tool.h:117
virtual void reset()
< Reinitializes tool to its initial state.
Definition: picker_tool.cpp:32
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
EDA_ITEM * Front() const
Definition: selection.h:172
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:84
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:218
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
std::unique_ptr< 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 RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
#define _(s)
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:620
std::vector< FAB_LAYER_COLOR > dummy
std::function< bool(EDA_ITEM *)> m_ItemFilter
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691