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 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
49 CONDITIONAL_MENU& menu = m_menu->GetMenu();
50
51 const auto snapIsSetToAllLayers =
52 [=]( const SELECTION& aSel )
53 {
54 if( frame )
55 return frame->GetMagneticItemsSettings()->allLayers;
56 else
57 return false;
58 };
59
60 // "Cancel" goes at the top of the context menu when a tool is active
62
63 menu.AddSeparator( 1 );
64
65 menu.AddItem( PCB_ACTIONS::magneticSnapAllLayers, !snapIsSetToAllLayers, 1 );
66 menu.AddItem( PCB_ACTIONS::magneticSnapActiveLayer, snapIsSetToAllLayers, 1 );
67
68 menu.AddSeparator( 1 );
69
70 if( frame )
71 frame->AddStandardSubMenus( *m_menu.get() );
72
73 return true;
74}
75
76
78{
80 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
81 PCB_GRID_HELPER grid( m_toolMgr, frame->GetMagneticItemsSettings() );
82 int finalize_state = WAIT_CANCEL;
83
84 TOOL_EVENT sourceEvent;
85
86 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
87 {
88 wxCHECK_MSG( aEvent.Parameter<const TOOL_EVENT*>(), -1,
89 wxT( "PCB_PICKER_TOOL::Main() called without a source event" ) );
90
91 sourceEvent = *aEvent.Parameter<const TOOL_EVENT*>();
92 frame->PushTool( sourceEvent );
93 }
94
95 Activate();
97
98 auto setCursor =
99 [&]()
100 {
101 frame->GetCanvas()->SetCurrentCursor( m_cursor );
102 controls->ShowCursor( true );
103 };
104
105 // Set initial cursor
106 setCursor();
107 VECTOR2D cursorPos;
108
109 while( TOOL_EVENT* evt = Wait() )
110 {
111 setCursor();
112 cursorPos = controls->GetMousePosition();
113
114 if( m_snap )
115 {
116 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
117 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
118 cursorPos = grid.BestSnapAnchor( cursorPos, m_layerMask );
119 controls->ForceCursorPosition( true, cursorPos );
120 }
121
122 if( evt->IsCancelInteractive() || evt->IsActivate() )
123 {
124 if( m_cancelHandler )
125 {
126 try
127 {
128 (*m_cancelHandler)();
129 }
130 catch( std::exception& )
131 {
132 }
133 }
134
135 // Activating a new tool may have alternate finalization from canceling the current tool
136 if( evt->IsActivate() )
137 finalize_state = END_ACTIVATE;
138 else
139 finalize_state = EVT_CANCEL;
140
141 break;
142 }
143 else if( evt->IsClick( BUT_LEFT ) )
144 {
145 bool getNext = false;
146
147 m_picked = cursorPos;
148
149 if( m_clickHandler )
150 {
151 try
152 {
153 getNext = (*m_clickHandler)( *m_picked );
154 }
155 catch( std::exception& )
156 {
157 finalize_state = EXCEPTION_CANCEL;
158 break;
159 }
160 }
161
162 if( !getNext )
163 {
164 finalize_state = CLICK_CANCEL;
165 break;
166 }
167 else
168 {
169 setControls();
170 }
171 }
172 else if( evt->IsMotion() )
173 {
174 if( m_motionHandler )
175 {
176 try
177 {
178 (*m_motionHandler)( cursorPos );
179 }
180 catch( std::exception& )
181 {
182 }
183 }
184 }
185 else if( evt->IsDblClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) )
186 {
187 // Not currently used, but we don't want to pass them either
188 }
189 else if( evt->IsClick( BUT_RIGHT ) )
190 {
192 m_menu->ShowContextMenu( dummy );
193 }
194 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
195 // but we don't at present have that, so we just knock out some of the egregious ones.
196 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
197 {
198 wxBell();
199 }
200 else
201 {
202 evt->SetPassEvent();
203 }
204 }
205
207 {
208 try
209 {
210 (*m_finalizeHandler)( finalize_state );
211 }
212 catch( std::exception& )
213 {
214 }
215 }
216
217 reset();
219 controls->ShowCursor( false );
220
221 if( aEvent.IsAction( &ACTIONS::pickerTool ) )
222 frame->PopTool( sourceEvent );
223
224 return 0;
225}
226
227
229{
232}
233
234
236{
238
239 controls->CaptureCursor( false );
240 controls->SetAutoPan( false );
241}
242
243
245{
247 STATUS_TEXT_POPUP statusPopup( frame() );
248 bool done = false;
249
250 wxCHECK( params.m_Receiver, -1 );
251
252 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
253
254 // By pushing this tool, we stop the Selection tool popping a disambiuation menu
255 // in cases like returning to the Position Relative dialog after the selection.
256 frame()->PushTool( aEvent );
257 Activate();
258
259 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
260
261 const auto sendPoint = [&]( const std::optional<VECTOR2I>& aPoint )
262 {
263 statusPopup.Hide();
264 params.m_Receiver->UpdatePickedPoint( aPoint );
265 };
266
267 SetSnapping( true );
268 SetCursor( KICURSOR::PLACE );
270
272 [&]( const VECTOR2D& aPoint ) -> bool
273 {
274 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
275
276 sendPoint( snapped ? *snapped : VECTOR2I( aPoint ) );
277
278 return false; // got our item; don't need any more
279 } );
280
282 [&]( const VECTOR2D& aPos )
283 {
284 grid_helper.SetSnap( !( CurrentModifiers() & MD_SHIFT ) );
285 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
286 } );
287
289 [&]()
290 {
291 sendPoint( std::nullopt );
292 } );
293
295 [&]( const int& aFinalState )
296 {
297 done = true;
298 } );
299
300 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
301 statusPopup.Popup();
302 canvas()->SetStatusPopup( statusPopup.GetPanel() );
303
304 // Drop into the main event loop
305 Main( aEvent );
306
307 canvas()->SetStatusPopup( nullptr );
308 frame()->PopTool( aEvent );
309 return 0;
310}
311
313{
315 STATUS_TEXT_POPUP statusPopup( frame() );
316 bool done = false;
317 EDA_ITEM* anchor_item = nullptr;
318
320
321 frame()->PushTool( aEvent );
322 Activate();
323
324 statusPopup.SetText( wxGetTranslation( params.m_Prompt ) );
325
326 const auto sendItem = [&]( const EDA_ITEM* aItem )
327 {
328 statusPopup.Hide();
329 params.m_Receiver->UpdatePickedItem( aItem );
330 };
331
332 SetCursor( KICURSOR::BULLSEYE );
333 SetSnapping( false );
335
337 [&]( const VECTOR2D& aPoint ) -> bool
338 {
340 const PCB_SELECTION& sel = selectionTool->RequestSelection(
341 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
342 PCB_SELECTION_TOOL* sTool )
343 {
344 } );
345
346 if( sel.Empty() )
347 return true; // still looking for an item
348
349 anchor_item = sel.Front();
350
351 if( params.m_ItemFilter && !params.m_ItemFilter( anchor_item ) )
352 return true;
353
354 sendItem( sel.Front() );
355 return false; // got our item; don't need any more
356 } );
357
359 [&]( const VECTOR2D& aPos )
360 {
361 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
362 } );
363
365 [&]()
366 {
367 if( anchor_item && ( !params.m_ItemFilter || params.m_ItemFilter( anchor_item ) ) )
368 sendItem( anchor_item );
369 } );
370
372 [&]( const int& aFinalState )
373 {
374 done = true;
375 } );
376
377 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
378 statusPopup.Popup();
379 canvas()->SetStatusPopup( statusPopup.GetPanel() );
380
381 // Drop into the main event loop
382 Main( aEvent );
383
384 canvas()->SetStatusPopup( nullptr );
385 frame()->PopTool( aEvent );
386 return 0;
387}
388
389
391{
392 // clang-format off
397 // clang-format on
398}
static TOOL_ACTION pickerSubTool
Definition: actions.h:251
static TOOL_ACTION cancelInteractive
Definition: actions.h:72
static TOOL_ACTION pickerTool
Definition: actions.h:250
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:221
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)
Definition: grid_helper.h:118
std::optional< VECTOR2I > GetSnappedPoint() const
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
static const LSET & AllLayersMask()
Definition: lset.cpp:624
static TOOL_ACTION magneticSnapAllLayers
Definition: pcb_actions.h:236
static TOOL_ACTION magneticSnapActiveLayer
Snapping controls.
Definition: pcb_actions.h:235
static TOOL_ACTION selectPointInteractively
Definition: pcb_actions.h:311
static TOOL_ACTION selectItemInteractively
Selection of reference points/items.
Definition: pcb_actions.h:310
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, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
T * frame() const
KIGFX::VIEW_CONTROLS * controls() const
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
Definition: picker_tool.h:118
void ClearHandlers()
Definition: picker_tool.h:68
std::optional< VECTOR2D > m_picked
Definition: picker_tool.h:134
std::optional< FINALIZE_HANDLER > m_finalizeHandler
Definition: picker_tool.h:132
void SetCursor(KICURSOR aCursor)
Definition: picker_tool.h:64
std::optional< MOTION_HANDLER > m_motionHandler
Definition: picker_tool.h:130
std::optional< CLICK_HANDLER > m_clickHandler
Definition: picker_tool.h:129
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
Definition: picker_tool.h:101
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:112
std::optional< CANCEL_HANDLER > m_cancelHandler
Definition: picker_tool.h:131
KICURSOR m_cursor
Definition: picker_tool.h:125
virtual void reset()
Reinitializes tool to its initial state.
Definition: picker_tool.cpp:32
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.
Definition: status_popup.h:83
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:168
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
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.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:683
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