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 TOOL_EVENT sourceEvent;
83
84 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
85 {
86 wxCHECK_MSG( aEvent.Parameter<const TOOL_EVENT*>(), -1,
87 wxT( "PCB_PICKER_TOOL::Main() called without a source event" ) );
88
89 sourceEvent = *aEvent.Parameter<const TOOL_EVENT*>();
90 frame->PushTool( sourceEvent );
91 }
92
93 Activate();
95
96 auto setCursor =
97 [&]()
98 {
99 frame->GetCanvas()->SetCurrentCursor( m_cursor );
100 controls->ShowCursor( true );
101 };
102
103 // Set initial cursor
104 setCursor();
105 VECTOR2D cursorPos;
106
107 while( TOOL_EVENT* evt = Wait() )
108 {
109 setCursor();
110 cursorPos = controls->GetMousePosition();
111
112 if( m_snap )
113 {
114 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
115 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
116
117 if( !evt->IsActivate() && !evt->IsCancelInteractive() )
118 {
119 // If we are switching, the canvas may not be valid any more
120 cursorPos = grid.BestSnapAnchor( cursorPos, nullptr );
121 controls->ForceCursorPosition( true, cursorPos );
122 }
123 else
124 {
125 grid.FullReset();
126 }
127 }
128
129 if( evt->IsCancelInteractive() || evt->IsActivate() )
130 {
131 if( m_cancelHandler )
132 {
133 try
134 {
135 (*m_cancelHandler)();
136 }
137 catch( std::exception& )
138 {
139 }
140 }
141
142 // Activating a new tool may have alternate finalization from canceling the current tool
143 if( evt->IsActivate() )
144 finalize_state = END_ACTIVATE;
145 else
146 finalize_state = EVT_CANCEL;
147
148 break;
149 }
150 else if( evt->IsClick( BUT_LEFT ) )
151 {
152 bool getNext = false;
153
154 m_picked = cursorPos;
155
156 if( m_clickHandler )
157 {
158 try
159 {
160 getNext = (*m_clickHandler)( *m_picked );
161 }
162 catch( std::exception& )
163 {
164 finalize_state = EXCEPTION_CANCEL;
165 break;
166 }
167 }
168
169 if( !getNext )
170 {
171 finalize_state = CLICK_CANCEL;
172 break;
173 }
174 else
175 {
176 setControls();
177 }
178 }
179 else if( evt->IsMotion() )
180 {
181 if( m_motionHandler )
182 {
183 try
184 {
185 (*m_motionHandler)( cursorPos );
186 }
187 catch( std::exception& )
188 {
189 }
190 }
191 }
192 else if( evt->IsDblClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) )
193 {
194 // Not currently used, but we don't want to pass them either
195 }
196 else if( evt->IsClick( BUT_RIGHT ) )
197 {
199 m_menu->ShowContextMenu( dummy );
200 }
201 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
202 // but we don't at present have that, so we just knock out some of the egregious ones.
203 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
204 {
205 wxBell();
206 }
207 else
208 {
209 evt->SetPassEvent();
210 }
211 }
212
214 {
215 try
216 {
217 (*m_finalizeHandler)( finalize_state );
218 }
219 catch( std::exception& )
220 {
221 }
222 }
223
224 reset();
225 controls->ForceCursorPosition( false );
226 controls->ShowCursor( false );
227
228 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
229 frame->PopTool( sourceEvent );
230
231 return 0;
232}
233
234
240
241
243{
245
246 controls->CaptureCursor( false );
247 controls->SetAutoPan( false );
248}
249
250
252{
254 STATUS_TEXT_POPUP statusPopup( frame() );
255 bool done = false;
256
257 wxCHECK( params.m_Receiver, -1 );
258
259 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
260
261 // By pushing this tool, we stop the Selection tool popping a disambiuation menu
262 // in cases like returning to the Position Relative dialog after the selection.
263 frame()->PushTool( aEvent );
264 Activate();
265
266 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
267
268 const auto sendPoint =
269 [&]( const std::optional<VECTOR2I>& aPoint )
270 {
271 statusPopup.Hide();
272 params.m_Receiver->UpdatePickedPoint( aPoint );
273 };
274
275 SetSnapping( true );
278
280 [&]( const VECTOR2D& aPoint ) -> bool
281 {
282 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
283
284 sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
285
286 return false; // got our item; don't need any more
287 } );
288
290 [&]( const VECTOR2D& aPos )
291 {
292 grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
293 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
294 } );
295
297 [&]()
298 {
299 sendPoint( std::nullopt );
300 } );
301
303 [&]( const int& aFinalState )
304 {
305 done = true;
306 } );
307
308 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
309 statusPopup.Popup();
310 canvas()->SetStatusPopup( statusPopup.GetPanel() );
311
312 // Drop into the main event loop
313 Main( aEvent );
314
316 canvas()->SetStatusPopup( nullptr );
317 frame()->PopTool( aEvent );
318 return 0;
319}
320
321
323{
325 STATUS_TEXT_POPUP statusPopup( frame() );
326 bool done = false;
327 EDA_ITEM* anchor_item = nullptr;
328
329 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
330
331 frame()->PushTool( aEvent );
332 Activate();
333
334 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
335
336 const auto sendItem =
337 [&]( const EDA_ITEM* aItem )
338 {
339 statusPopup.Hide();
340 params.m_Receiver->UpdatePickedItem( aItem );
341 };
342
344 SetSnapping( false );
346
348 [&]( const VECTOR2D& aPoint ) -> bool
349 {
351 const PCB_SELECTION& sel = selectionTool->RequestSelection(
352 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
353 {
354 } );
355
356 if( sel.Empty() )
357 return true; // still looking for an item
358
359 anchor_item = sel.Front();
360
361 if( params.m_ItemFilter && !params.m_ItemFilter( anchor_item ) )
362 return true;
363
364 sendItem( sel.Front() );
365 return false; // got our item; don't need any more
366 } );
367
369 [&]( const VECTOR2D& aPos )
370 {
371 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
372 } );
373
375 [&]()
376 {
377 if( anchor_item && ( !params.m_ItemFilter || params.m_ItemFilter( anchor_item ) ) )
378 sendItem( anchor_item );
379 } );
380
382 [&]( const int& aFinalState )
383 {
384 done = true;
385 } );
386
387 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
388 statusPopup.Popup();
389 canvas()->SetStatusPopup( statusPopup.GetPanel() );
390
391 // Drop into the main event loop
392 Main( aEvent );
393
395 canvas()->SetStatusPopup( nullptr );
396 frame()->PopTool( aEvent );
397 return 0;
398}
399
400
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:96
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.
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:88
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:77
void SetSnapping(bool aSnap)
Definition picker_tool.h:62
int CurrentModifiers() const
std::optional< VECTOR2D > m_picked
std::optional< FINALIZE_HANDLER > m_finalizeHandler
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:60
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).
Definition picker_tool.h:97
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:173
bool Empty() const
Checks if there is anything selected.
Definition selection.h:111
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:766
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