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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "pcb_picker_tool.h"
23
24#include "pcb_actions.h"
25#include "pcb_grid_helper.h"
27#include <kiplatform/ui.h>
28#include <status_popup.h>
29#include <tool/tool_manager.h>
32#include <view/view_controls.h>
33
34
36 PCB_TOOL_BASE( "pcbnew.InteractivePicker" ),
37 PICKER_TOOL_BASE() // calls reset()
38{
39}
40
41
43{
44 CONDITIONAL_MENU& menu = m_menu->GetMenu();
45
46 auto snapIsSetToAllLayers =
47 [this]( const SELECTION& aSel )
48 {
50 {
51 if( frame->GetMagneticItemsSettings() )
52 return frame->GetMagneticItemsSettings()->allLayers;
53 }
54
55 return false;
56 };
57
58 // "Cancel" goes at the top of the context menu when a tool is active
60
61 menu.AddSeparator( 1 );
62
63 menu.AddItem( PCB_ACTIONS::magneticSnapAllLayers, !snapIsSetToAllLayers, 1 );
64 menu.AddItem( PCB_ACTIONS::magneticSnapActiveLayer, snapIsSetToAllLayers, 1 );
65
66 menu.AddSeparator( 1 );
67
69 frame->AddStandardSubMenus( *m_menu.get() );
70
71 return true;
72}
73
74
76{
79 PCB_GRID_HELPER grid( m_toolMgr, frame->GetMagneticItemsSettings() );
80 int finalize_state = WAIT_CANCEL;
81
82 grid.SetConstructionGeometryEnabled( m_constructionGeometry );
83
84 grid.SetSuppressedSnapSubtypes( m_suppressedSnaps );
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.ResolveSnap( cursorPos, nullptr ).position;
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->IsDrag( BUT_LEFT ) && m_areaHandler )
197 {
198 bool getNext = false;
199
200 // Wait() suspends the coroutine of the tool it is called on. The selection tool
201 // cannot pump its own area loop while we own the stream.
203 {
204 finalize_state = EVT_CANCEL;
205 break;
206 }
207
208 try
209 {
210 getNext = (*m_areaHandler)();
211 }
212 catch( std::exception& )
213 {
214 finalize_state = EXCEPTION_CANCEL;
215 break;
216 }
217
218 if( !getNext )
219 {
220 finalize_state = CLICK_CANCEL;
221 break;
222 }
223
224 setControls();
225 }
226 else if( evt->IsDblClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) )
227 {
228 // Not currently used, but we don't want to pass them either
229 }
230 else if( evt->IsClick( BUT_RIGHT ) )
231 {
233 m_menu->ShowContextMenu( dummy );
234 }
235 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
236 // but we don't at present have that, so we just knock out some of the egregious ones.
237 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
238 {
239 wxBell();
240 }
241 else
242 {
243 evt->SetPassEvent();
244 }
245 }
246
248 {
249 try
250 {
251 (*m_finalizeHandler)( finalize_state );
252 }
253 catch( std::exception& )
254 {
255 }
256 }
257
258 reset();
259 controls->ForceCursorPosition( false );
260 controls->ShowCursor( false );
261
262 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
263 frame->PopTool( sourceEvent );
264
265 return 0;
266}
267
268
277
278
280{
282
283 controls->CaptureCursor( false );
284 controls->SetAutoPan( false );
285}
286
287
289{
291 STATUS_TEXT_POPUP statusPopup( frame() );
292 bool done = false;
293
294 wxCHECK( params.m_Receiver, -1 );
295
296 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
297
298 // By pushing this tool, we stop the Selection tool popping a disambiuation menu
299 // in cases like returning to the Position Relative dialog after the selection.
300 SCOPED_TOOL_PUSHER raii( frame(), aEvent );
301 Activate();
302
303 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
304
305 const auto sendPoint =
306 [&]( const std::optional<VECTOR2I>& aPoint )
307 {
308 statusPopup.Hide();
309 params.m_Receiver->UpdatePickedPoint( aPoint );
310 };
311
312 SetSnapping( true );
315
317 [&]( const VECTOR2D& aPoint ) -> bool
318 {
319 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
320
321 sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
322
323 return false; // got our item; don't need any more
324 } );
325
327 [&]( const VECTOR2D& aPos )
328 {
329 grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
330 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
331 } );
332
334 [&]()
335 {
336 sendPoint( std::nullopt );
337 } );
338
340 [&]( const int& aFinalState )
341 {
342 done = true;
343 } );
344
345 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
346 statusPopup.Popup();
347 canvas()->SetStatusPopup( statusPopup.GetPanel() );
348
349 // Drop into the main event loop
350 Main( aEvent );
351
353 canvas()->SetStatusPopup( nullptr );
354 return 0;
355}
356
357
359{
361 STATUS_TEXT_POPUP statusPopup( frame() );
362 bool done = false;
363 EDA_ITEM* anchor_item = nullptr;
364
365 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
366 SCOPED_TOOL_PUSHER raii( frame(), aEvent );
367 Activate();
368
369 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
370
371 const auto sendItem =
372 [&]( const EDA_ITEM* aItem )
373 {
374 statusPopup.Hide();
375 params.m_Receiver->UpdatePickedItem( aItem );
376 };
377
379 SetSnapping( false );
381
383 [&]( const VECTOR2D& aPoint ) -> bool
384 {
386 const PCB_SELECTION& sel = selectionTool->RequestSelection(
387 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
388 {
389 } );
390
391 if( sel.Empty() )
392 return true; // still looking for an item
393
394 anchor_item = sel.Front();
395
396 if( params.m_ItemFilter && !params.m_ItemFilter( anchor_item ) )
397 return true;
398
399 sendItem( sel.Front() );
400 return false; // got our item; don't need any more
401 } );
402
404 [&]( const VECTOR2D& aPos )
405 {
406 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
407 } );
408
410 [&]()
411 {
412 if( anchor_item && ( !params.m_ItemFilter || params.m_ItemFilter( anchor_item ) ) )
413 sendItem( anchor_item );
414 } );
415
417 [&]( const int& aFinalState )
418 {
419 done = true;
420 } );
421
422 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
423 statusPopup.Popup();
424 canvas()->SetStatusPopup( statusPopup.GetPanel() );
425
426 // Drop into the main event loop
427 Main( aEvent );
428
430 canvas()->SetStatusPopup( nullptr );
431 return 0;
432}
433
434
static TOOL_ACTION pickerSubTool
Definition actions.h:250
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION pickerTool
Definition actions.h:249
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
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:203
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:637
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.
PCB_SELECTION_TOOL::AREA_PREVIEW m_areaPreviewHandler
bool Init() override
Main event loop.
int SelectPointInteractively(const TOOL_EVENT &aEvent)
std::set< SNAP_CANDIDATE_SUBTYPE > m_suppressedSnaps
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
<
void ClearHandlers()
Handlers only.
The selection tool: currently supports:
bool DragSelectionArea(TOOL_INTERACTIVE &aTool, AREA_PREVIEW aPreview=nullptr)
Drive the rectangle drag-selection loop from another tool's event loop.
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:65
int CurrentModifiers() const
std::optional< VECTOR2D > m_picked
std::optional< FINALIZE_HANDLER > m_finalizeHandler
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:63
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.
std::optional< AREA_HANDLER > m_areaHandler
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
EDA_ITEM * Front() const
Definition selection.h:176
bool Empty() const
Checks if there is anything selected.
Definition selection.h:114
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:182
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:40
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:34
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.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:469
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:94
@ BULLSEYE
Definition cursors.h:54
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:839
std::vector< FAB_LAYER_COLOR > dummy
std::function< bool(EDA_ITEM *)> m_ItemFilter
@ MD_SHIFT
Definition tool_event.h:139
@ BUT_LEFT
Definition tool_event.h:128
@ BUT_RIGHT
Definition tool_event.h:129
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682