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 The 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>
33#include <tool/tool_manager.h>
36#include <view/view_controls.h>
37
38
40 PCB_TOOL_BASE( "pcbnew.InteractivePicker" ),
41 PICKER_TOOL_BASE() // calls reset()
42{
43}
44
45
47{
48 CONDITIONAL_MENU& menu = m_menu->GetMenu();
49
50 auto snapIsSetToAllLayers =
51 [this]( const SELECTION& aSel )
52 {
54 {
55 if( frame->GetMagneticItemsSettings() )
56 return frame->GetMagneticItemsSettings()->allLayers;
57 }
58
59 return false;
60 };
61
62 // "Cancel" goes at the top of the context menu when a tool is active
64
65 menu.AddSeparator( 1 );
66
67 menu.AddItem( PCB_ACTIONS::magneticSnapAllLayers, !snapIsSetToAllLayers, 1 );
68 menu.AddItem( PCB_ACTIONS::magneticSnapActiveLayer, snapIsSetToAllLayers, 1 );
69
70 menu.AddSeparator( 1 );
71
73 frame->AddStandardSubMenus( *m_menu.get() );
74
75 return true;
76}
77
78
80{
83 PCB_GRID_HELPER grid( m_toolMgr, frame->GetMagneticItemsSettings() );
84 int finalize_state = WAIT_CANCEL;
85
86 TOOL_EVENT sourceEvent;
87
88 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
89 {
90 wxCHECK_MSG( aEvent.Parameter<const TOOL_EVENT*>(), -1,
91 wxT( "PCB_PICKER_TOOL::Main() called without a source event" ) );
92
93 sourceEvent = *aEvent.Parameter<const TOOL_EVENT*>();
94 frame->PushTool( sourceEvent );
95 }
96
97 Activate();
99
100 auto setCursor =
101 [&]()
102 {
103 frame->GetCanvas()->SetCurrentCursor( m_cursor );
104 controls->ShowCursor( true );
105 };
106
107 // Set initial cursor
108 setCursor();
109 VECTOR2D cursorPos;
110
111 while( TOOL_EVENT* evt = Wait() )
112 {
113 setCursor();
114 cursorPos = controls->GetMousePosition();
115
116 if( m_snap )
117 {
118 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
119 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
120
121 if( !evt->IsActivate() && !evt->IsCancelInteractive() )
122 {
123 // If we are switching, the canvas may not be valid any more
124 cursorPos = grid.BestSnapAnchor( cursorPos, nullptr );
125 controls->ForceCursorPosition( true, cursorPos );
126 }
127 else
128 {
129 grid.FullReset();
130 }
131 }
132
133 if( evt->IsCancelInteractive() || evt->IsActivate() )
134 {
135 if( m_cancelHandler )
136 {
137 try
138 {
139 (*m_cancelHandler)();
140 }
141 catch( std::exception& )
142 {
143 }
144 }
145
146 // Activating a new tool may have alternate finalization from canceling the current tool
147 if( evt->IsActivate() )
148 finalize_state = END_ACTIVATE;
149 else
150 finalize_state = EVT_CANCEL;
151
152 break;
153 }
154 else if( evt->IsClick( BUT_LEFT ) )
155 {
156 bool getNext = false;
157
158 m_picked = cursorPos;
159
160 if( m_clickHandler )
161 {
162 try
163 {
164 getNext = (*m_clickHandler)( *m_picked );
165 }
166 catch( std::exception& )
167 {
168 finalize_state = EXCEPTION_CANCEL;
169 break;
170 }
171 }
172
173 if( !getNext )
174 {
175 finalize_state = CLICK_CANCEL;
176 break;
177 }
178 else
179 {
180 setControls();
181 }
182 }
183 else if( evt->IsMotion() )
184 {
185 if( m_motionHandler )
186 {
187 try
188 {
189 (*m_motionHandler)( cursorPos );
190 }
191 catch( std::exception& )
192 {
193 }
194 }
195 }
196 else if( evt->IsDblClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) )
197 {
198 // Not currently used, but we don't want to pass them either
199 }
200 else if( evt->IsClick( BUT_RIGHT ) )
201 {
203 m_menu->ShowContextMenu( dummy );
204 }
205 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
206 // but we don't at present have that, so we just knock out some of the egregious ones.
207 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
208 {
209 wxBell();
210 }
211 else
212 {
213 evt->SetPassEvent();
214 }
215 }
216
218 {
219 try
220 {
221 (*m_finalizeHandler)( finalize_state );
222 }
223 catch( std::exception& )
224 {
225 }
226 }
227
228 reset();
229 controls->ForceCursorPosition( false );
230 controls->ShowCursor( false );
231
232 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
233 frame->PopTool( sourceEvent );
234
235 return 0;
236}
237
238
244
245
247{
249
250 controls->CaptureCursor( false );
251 controls->SetAutoPan( false );
252}
253
254
256{
258 STATUS_TEXT_POPUP statusPopup( frame() );
259 bool done = false;
260
261 wxCHECK( params.m_Receiver, -1 );
262
263 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
264
265 // By pushing this tool, we stop the Selection tool popping a disambiuation menu
266 // in cases like returning to the Position Relative dialog after the selection.
267 frame()->PushTool( aEvent );
268 Activate();
269
270 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
271
272 const auto sendPoint =
273 [&]( const std::optional<VECTOR2I>& aPoint )
274 {
275 statusPopup.Hide();
276 params.m_Receiver->UpdatePickedPoint( aPoint );
277 };
278
279 SetSnapping( true );
282
284 [&]( const VECTOR2D& aPoint ) -> bool
285 {
286 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
287
288 sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
289
290 return false; // got our item; don't need any more
291 } );
292
294 [&]( const VECTOR2D& aPos )
295 {
296 grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
297 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
298 } );
299
301 [&]()
302 {
303 sendPoint( std::nullopt );
304 } );
305
307 [&]( const int& aFinalState )
308 {
309 done = true;
310 } );
311
312 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
313 statusPopup.Popup();
314 canvas()->SetStatusPopup( statusPopup.GetPanel() );
315
316 // Drop into the main event loop
317 Main( aEvent );
318
320 canvas()->SetStatusPopup( nullptr );
321 frame()->PopTool( aEvent );
322 return 0;
323}
324
325
327{
329 STATUS_TEXT_POPUP statusPopup( frame() );
330 bool done = false;
331 EDA_ITEM* anchor_item = nullptr;
332
333 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
334
335 frame()->PushTool( aEvent );
336 Activate();
337
338 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
339
340 const auto sendItem =
341 [&]( const EDA_ITEM* aItem )
342 {
343 statusPopup.Hide();
344 params.m_Receiver->UpdatePickedItem( aItem );
345 };
346
348 SetSnapping( false );
350
352 [&]( const VECTOR2D& aPoint ) -> bool
353 {
355 const PCB_SELECTION& sel = selectionTool->RequestSelection(
356 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
357 {
358 } );
359
360 if( sel.Empty() )
361 return true; // still looking for an item
362
363 anchor_item = sel.Front();
364
365 if( params.m_ItemFilter && !params.m_ItemFilter( anchor_item ) )
366 return true;
367
368 sendItem( sel.Front() );
369 return false; // got our item; don't need any more
370 } );
371
373 [&]( const VECTOR2D& aPos )
374 {
375 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
376 } );
377
379 [&]()
380 {
381 if( anchor_item && ( !params.m_ItemFilter || params.m_ItemFilter( anchor_item ) ) )
382 sendItem( anchor_item );
383 } );
384
386 [&]( const int& aFinalState )
387 {
388 done = true;
389 } );
390
391 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
392 statusPopup.Popup();
393 canvas()->SetStatusPopup( statusPopup.GetPanel() );
394
395 // Drop into the main event loop
396 Main( aEvent );
397
399 canvas()->SetStatusPopup( nullptr );
400 frame()->PopTool( aEvent );
401 return 0;
402}
403
404
static TOOL_ACTION pickerSubTool
Definition actions.h:254
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION pickerTool
Definition actions.h:253
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
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:98
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
void SetSnap(bool aSnap)
std::optional< VECTOR2I > GetSnappedPoint() const
An interface for classes handling user events controlling the view behavior such as zooming,...
static const LSET & AllLayersMask()
Definition lset.cpp:624
static TOOL_ACTION magneticSnapAllLayers
static TOOL_ACTION magneticSnapActiveLayer
Snapping controls.
static TOOL_ACTION selectPointInteractively
static TOOL_ACTION selectItemInteractively
Selection of reference points/items.
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)
Return the current selection, filtered according to aClientFilter.
T * frame() const
KIGFX::VIEW_CONTROLS * controls() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
PCB_DRAW_PANEL_GAL * canvas() const
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:92
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:66
int CurrentModifiers() const
std::optional< VECTOR2D > m_picked
std::optional< FINALIZE_HANDLER > m_finalizeHandler
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:64
std::optional< MOTION_HANDLER > m_motionHandler
std::optional< CLICK_HANDLER > m_clickHandler
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
std::optional< CANCEL_HANDLER > m_cancelHandler
virtual void reset()
Reinitializes tool to its initial state.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
EDA_ITEM * Front() const
Definition selection.h:177
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
Extension of STATUS_POPUP for displaying a single line text.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:38
Generic, UI-independent tool event.
Definition tool_event.h:171
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
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.
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
@ PLACE
Definition cursors.h:98
@ BULLSEYE
Definition cursors.h:58
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:689
std::vector< FAB_LAYER_COLOR > dummy
std::function< bool(EDA_ITEM *)> m_ItemFilter
@ MD_SHIFT
Definition tool_event.h:143
@ BUT_LEFT
Definition tool_event.h:132
@ BUT_RIGHT
Definition tool_event.h:133
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694