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 cursorPos = grid.BestSnapAnchor( cursorPos, m_layerMask );
121 controls->ForceCursorPosition( true, cursorPos );
122 }
123
124 if( evt->IsCancelInteractive() || evt->IsActivate() )
125 {
126 if( m_cancelHandler )
127 {
128 try
129 {
130 (*m_cancelHandler)();
131 }
132 catch( std::exception& )
133 {
134 }
135 }
136
137 // Activating a new tool may have alternate finalization from canceling the current tool
138 if( evt->IsActivate() )
139 finalize_state = END_ACTIVATE;
140 else
141 finalize_state = EVT_CANCEL;
142
143 break;
144 }
145 else if( evt->IsClick( BUT_LEFT ) )
146 {
147 bool getNext = false;
148
149 m_picked = cursorPos;
150
151 if( m_clickHandler )
152 {
153 try
154 {
155 getNext = (*m_clickHandler)( *m_picked );
156 }
157 catch( std::exception& )
158 {
159 finalize_state = EXCEPTION_CANCEL;
160 break;
161 }
162 }
163
164 if( !getNext )
165 {
166 finalize_state = CLICK_CANCEL;
167 break;
168 }
169 else
170 {
171 setControls();
172 }
173 }
174 else if( evt->IsMotion() )
175 {
176 if( m_motionHandler )
177 {
178 try
179 {
180 (*m_motionHandler)( cursorPos );
181 }
182 catch( std::exception& )
183 {
184 }
185 }
186 }
187 else if( evt->IsDblClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) )
188 {
189 // Not currently used, but we don't want to pass them either
190 }
191 else if( evt->IsClick( BUT_RIGHT ) )
192 {
194 m_menu->ShowContextMenu( dummy );
195 }
196 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
197 // but we don't at present have that, so we just knock out some of the egregious ones.
198 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
199 {
200 wxBell();
201 }
202 else
203 {
204 evt->SetPassEvent();
205 }
206 }
207
209 {
210 try
211 {
212 (*m_finalizeHandler)( finalize_state );
213 }
214 catch( std::exception& )
215 {
216 }
217 }
218
219 reset();
220 controls->ForceCursorPosition( false );
221 controls->ShowCursor( false );
222
223 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
224 frame->PopTool( sourceEvent );
225
226 return 0;
227}
228
229
235
236
238{
240
241 controls->CaptureCursor( false );
242 controls->SetAutoPan( false );
243}
244
245
247{
249 STATUS_TEXT_POPUP statusPopup( frame() );
250 bool done = false;
251
252 wxCHECK( params.m_Receiver, -1 );
253
254 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
255
256 // By pushing this tool, we stop the Selection tool popping a disambiuation menu
257 // in cases like returning to the Position Relative dialog after the selection.
258 frame()->PushTool( aEvent );
259 Activate();
260
261 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
262
263 const auto sendPoint =
264 [&]( const std::optional<VECTOR2I>& aPoint )
265 {
266 statusPopup.Hide();
267 params.m_Receiver->UpdatePickedPoint( aPoint );
268 };
269
270 SetSnapping( true );
273
275 [&]( const VECTOR2D& aPoint ) -> bool
276 {
277 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
278
279 sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
280
281 return false; // got our item; don't need any more
282 } );
283
285 [&]( const VECTOR2D& aPos )
286 {
287 grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
288 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
289 } );
290
292 [&]()
293 {
294 sendPoint( std::nullopt );
295 } );
296
298 [&]( const int& aFinalState )
299 {
300 done = true;
301 } );
302
303 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
304 statusPopup.Popup();
305 canvas()->SetStatusPopup( statusPopup.GetPanel() );
306
307 // Drop into the main event loop
308 Main( aEvent );
309
311 canvas()->SetStatusPopup( nullptr );
312 frame()->PopTool( aEvent );
313 return 0;
314}
315
316
318{
320 STATUS_TEXT_POPUP statusPopup( frame() );
321 bool done = false;
322 EDA_ITEM* anchor_item = nullptr;
323
324 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
325
326 frame()->PushTool( aEvent );
327 Activate();
328
329 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
330
331 const auto sendItem =
332 [&]( const EDA_ITEM* aItem )
333 {
334 statusPopup.Hide();
335 params.m_Receiver->UpdatePickedItem( aItem );
336 };
337
339 SetSnapping( false );
341
343 [&]( const VECTOR2D& aPoint ) -> bool
344 {
346 const PCB_SELECTION& sel = selectionTool->RequestSelection(
347 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
348 {
349 } );
350
351 if( sel.Empty() )
352 return true; // still looking for an item
353
354 anchor_item = sel.Front();
355
356 if( params.m_ItemFilter && !params.m_ItemFilter( anchor_item ) )
357 return true;
358
359 sendItem( sel.Front() );
360 return false; // got our item; don't need any more
361 } );
362
364 [&]( const VECTOR2D& aPos )
365 {
366 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
367 } );
368
370 [&]()
371 {
372 if( anchor_item && ( !params.m_ItemFilter || params.m_ItemFilter( anchor_item ) ) )
373 sendItem( anchor_item );
374 } );
375
377 [&]( const int& aFinalState )
378 {
379 done = true;
380 } );
381
382 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
383 statusPopup.Popup();
384 canvas()->SetStatusPopup( statusPopup.GetPanel() );
385
386 // Drop into the main event loop
387 Main( aEvent );
388
390 canvas()->SetStatusPopup( nullptr );
391 frame()->PopTool( aEvent );
392 return 0;
393}
394
395
static TOOL_ACTION pickerSubTool
Definition actions.h:253
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION pickerTool
Definition actions.h:252
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:223
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:96
@ BULLSEYE
Definition cursors.h:56
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