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 ) || evt->IsAction( &ACTIONS::cursorClick ) )
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() || evt->IsAction( &ACTIONS::refreshPreview ) )
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 )
227 || evt->IsAction( &ACTIONS::cursorDblClick )
228 || evt->IsDrag( BUT_LEFT ) )
229 {
230 // Not currently used, but we don't want to pass them either
231 }
232 else if( evt->IsClick( BUT_RIGHT ) )
233 {
235 m_menu->ShowContextMenu( dummy );
236 }
237 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
238 // but we don't at present have that, so we just knock out some of the egregious ones.
239 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
240 {
241 wxBell();
242 }
243 else
244 {
245 evt->SetPassEvent();
246 }
247 }
248
250 {
251 try
252 {
253 (*m_finalizeHandler)( finalize_state );
254 }
255 catch( std::exception& )
256 {
257 }
258 }
259
260 reset();
261 controls->ForceCursorPosition( false );
262 controls->ShowCursor( false );
263
264 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
265 frame->PopTool( sourceEvent );
266
267 return 0;
268}
269
270
279
280
282{
284
285 controls->CaptureCursor( false );
286 controls->SetAutoPan( false );
287}
288
289
291{
293 STATUS_TEXT_POPUP statusPopup( frame() );
294 bool done = false;
295
296 wxCHECK( params.m_Receiver, -1 );
297
298 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
299
300 // By pushing this tool, we stop the Selection tool popping a disambiuation menu
301 // in cases like returning to the Position Relative dialog after the selection.
302 SCOPED_TOOL_PUSHER raii( frame(), aEvent );
303 Activate();
304
305 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
306
307 const auto sendPoint =
308 [&]( const std::optional<VECTOR2I>& aPoint )
309 {
310 statusPopup.Hide();
311 params.m_Receiver->UpdatePickedPoint( aPoint );
312 };
313
314 SetSnapping( true );
317
319 [&]( const VECTOR2D& aPoint ) -> bool
320 {
321 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
322
323 sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
324
325 return false; // got our item; don't need any more
326 } );
327
329 [&]( const VECTOR2D& aPos )
330 {
331 grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
332 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
333 } );
334
336 [&]()
337 {
338 sendPoint( std::nullopt );
339 } );
340
342 [&]( const int& aFinalState )
343 {
344 done = true;
345 } );
346
347 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
348 statusPopup.Popup();
349 canvas()->SetStatusPopup( statusPopup.GetPanel() );
350
351 // Drop into the main event loop
352 Main( aEvent );
353
355 canvas()->SetStatusPopup( nullptr );
356 return 0;
357}
358
359
361{
363 STATUS_TEXT_POPUP statusPopup( frame() );
364 bool done = false;
365
366 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
367 SCOPED_TOOL_PUSHER raii( frame(), aEvent );
368 Activate();
369
370 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
371
372 const auto sendItem =
373 [&]( const EDA_ITEM* aItem )
374 {
375 statusPopup.Hide();
376 params.m_Receiver->UpdatePickedItem( aItem );
377 };
378
380 SetSnapping( false );
382
384 [&]( const VECTOR2D& aPoint ) -> bool
385 {
387 const PCB_SELECTION& sel = selectionTool->RequestSelection(
388 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
389 {
390 } );
391
392 if( sel.Empty() )
393 return true; // still looking for an item
394
395 EDA_ITEM* item = sel.Front();
396
397 if( params.m_ItemFilter && !params.m_ItemFilter( item ) )
398 return true;
399
400 sendItem( item );
401 return false; // got our item; don't need any more
402 } );
403
405 [&]( const VECTOR2D& aPos )
406 {
407 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
408 } );
409
411 [&]()
412 {
413 sendItem( nullptr );
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 cursorDblClick
Definition actions.h:177
static TOOL_ACTION cursorClick
Definition actions.h:176
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION refreshPreview
Definition actions.h:155
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
Init() is called once upon a registration of the tool.
int SelectPointInteractively(const TOOL_EVENT &aEvent)
std::set< SNAP_CANDIDATE_SUBTYPE > m_suppressedSnaps
int Main(const TOOL_EVENT &aEvent)
Main event loop.
void setControls()
Applies the requested VIEW_CONTROLS settings.
void reset() override
Reinitialize tool to its initial state.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
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
Return the instance of KIGFX::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:484
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:851
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:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707