KiCad PCB EDA Suite
Loading...
Searching...
No Matches
position_relative_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) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <functional>
25#include <memory>
26using namespace std::placeholders;
27
28#include <kiplatform/ui.h>
30#include <tools/pcb_actions.h>
35#include <status_popup.h>
36#include <board_commit.h>
37#include <confirm.h>
38#include <collectors.h>
39#include <pad.h>
40#include <footprint.h>
41#include <pcb_group.h>
42
43
45 PCB_TOOL_BASE( "pcbnew.PositionRelative" ),
46 m_dialog( nullptr ),
47 m_selectionTool( nullptr ),
48 m_anchor_item( nullptr )
49{
50}
51
52
54{
55 if( aReason != RUN )
56 m_commit = std::make_unique<BOARD_COMMIT>( this );
57}
58
59
61{
62 // Find the selection tool, so they can cooperate
64
65 return m_selectionTool != nullptr;
66}
67
68
70{
71 PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
72
74 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
75 {
76 sTool->FilterCollectorForHierarchy( aCollector, true );
77 sTool->FilterCollectorForMarkers( aCollector );
78 },
79 !m_isFootprintEditor /* prompt user regarding locked items */ );
80
81 if( selection.Empty() )
82 return 0;
83
85
86 // We prefer footprints, then pads, then anything else here.
87 EDA_ITEM* preferredItem = m_selection.GetTopLeftItem( true );
88
89 if( !preferredItem && m_selection.HasType( PCB_PAD_T ) )
90 {
91 PCB_SELECTION padsOnly = m_selection;
92 std::deque<EDA_ITEM*>& items = padsOnly.Items();
93 items.erase( std::remove_if( items.begin(), items.end(),
94 []( const EDA_ITEM* aItem )
95 {
96 return aItem->Type() != PCB_PAD_T;
97 } ), items.end() );
98
99 preferredItem = padsOnly.GetTopLeftItem();
100 }
101
102 if( preferredItem )
103 m_selectionAnchor = preferredItem->GetPosition();
104 else
106
107 // The dialog is not modal and not deleted between calls.
108 // It means some options can have changed since the last call.
109 // Therefore we need to rebuild it in case UI units have changed since the last call.
110 if( m_dialog && m_dialog->GetUserUnits() != editFrame->GetUserUnits() )
111 {
112 m_dialog->Destroy();
113 m_dialog = nullptr;
114 }
115
116 if( !m_dialog )
117 m_dialog = new DIALOG_POSITION_RELATIVE( editFrame );
118
119 m_dialog->Show( true );
120
121 return 0;
122}
123
124
126 const VECTOR2I& aTranslation )
127{
128 VECTOR2I aggregateTranslation = aPosAnchor + aTranslation - GetSelectionAnchorPosition();
129
130 for( EDA_ITEM* item : m_selection )
131 {
132 if( !item->IsBOARD_ITEM() )
133 continue;
134
135 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
136
137 // Don't move a pad by itself unless editing the footprint
138 if( boardItem->Type() == PCB_PAD_T
139 && !frame()->GetPcbNewSettings()->m_AllowFreePads
140 && frame()->IsType( FRAME_PCB_EDITOR ) )
141 {
142 boardItem = boardItem->GetParent();
143 }
144
145 m_commit->Modify( boardItem );
146 boardItem->Move( aggregateTranslation );
147 }
148
149 m_commit->Push( _( "Position Relative" ) );
150
151 if( m_selection.IsHover() )
153
155
156 canvas()->Refresh();
157 return 0;
158}
159
160
162{
164 STATUS_TEXT_POPUP statusPopup( frame() );
165 bool done = false;
166
167 Activate();
168
169 statusPopup.SetText( _( "Click on reference item..." ) );
170
171 picker->SetClickHandler(
172 [&]( const VECTOR2D& aPoint ) -> bool
173 {
176 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
177 PCB_SELECTION_TOOL* sTool )
178 {
179 } );
180
181 if( sel.Empty() )
182 return true; // still looking for an item
183
184 m_anchor_item = sel.Front();
185 statusPopup.Hide();
186
187 if( m_dialog )
188 m_dialog->UpdateAnchor( sel.Front() );
189
190 return false; // got our item; don't need any more
191 } );
192
193 picker->SetMotionHandler(
194 [&] ( const VECTOR2D& aPos )
195 {
196 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
197 } );
198
199 picker->SetCancelHandler(
200 [&]()
201 {
202 statusPopup.Hide();
203
204 if( m_dialog )
206 } );
207
208 picker->SetFinalizeHandler(
209 [&]( const int& aFinalState )
210 {
211 done = true;
212 } );
213
214 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
215 statusPopup.Popup();
216 canvas()->SetStatusPopup( statusPopup.GetPanel() );
217
219
220 while( !done )
221 {
222 // Pass events unless we receive a null event, then we must shut down
223 if( TOOL_EVENT* evt = Wait() )
224 evt->SetPassEvent();
225 else
226 break;
227 }
228
229 canvas()->SetStatusPopup( nullptr );
230
231 return 0;
232}
233
234
236{
238 STATUS_TEXT_POPUP statusPopup( frame() );
239 bool done = false;
240
241 PCB_GRID_HELPER grid_helper( m_toolMgr, frame()->GetMagneticItemsSettings() );
242
243 Activate();
244
245 statusPopup.SetText( _( "Click on reference point..." ) );
246
247 picker->SetClickHandler(
248 [&]( const VECTOR2D& aPoint ) -> bool
249 {
250 std::optional<VECTOR2I> snapped = grid_helper.GetSnappedPoint();
251
252 statusPopup.Hide();
253
254 if( m_dialog )
255 m_dialog->UpdateAnchor( snapped ? *snapped : VECTOR2I( aPoint ) );
256
257 return false; // got our item; don't need any more
258 } );
259
260 picker->SetMotionHandler(
261 [&] ( const VECTOR2D& aPos )
262 {
263 grid_helper.SetSnap( !( picker->CurrentModifiers() & MD_SHIFT ) );
264 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
265 } );
266
267 picker->SetCancelHandler(
268 [&]()
269 {
270 statusPopup.Hide();
271
272 if( m_dialog )
273 m_dialog->UpdateAnchor( std::nullopt );
274 } );
275
276 picker->SetFinalizeHandler(
277 [&]( const int& aFinalState )
278 {
279 done = true;
280 } );
281
282 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
283 statusPopup.Popup();
284 canvas()->SetStatusPopup( statusPopup.GetPanel() );
285
287
288 while( !done )
289 {
290 // Pass events unless we receive a null event, then we must shut down
291 if( TOOL_EVENT* evt = Wait() )
292 evt->SetPassEvent();
293 else
294 break;
295 }
296
297 canvas()->SetStatusPopup( nullptr );
298
299 return 0;
300}
301
302
304{
310}
static TOOL_ACTION pickerTool
Definition: actions.h:194
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:330
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:218
bool Show(bool show) override
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:128
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
void SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:243
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:277
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:108
std::optional< VECTOR2I > GetSnappedPoint() const
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION selectPositionRelativePoint
Definition: pcb_actions.h:325
static TOOL_ACTION positionRelative
Activation of the position relative tool.
Definition: pcb_actions.h:321
static TOOL_ACTION selectPositionRelativeItem
Selection of anchor item for position relative tool.
Definition: pcb_actions.h:324
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
Generic tool for picking an item.
The selection tool: currently supports:
void FilterCollectorForMarkers(GENERAL_COLLECTOR &aCollector) const
Drop any PCB_MARKERs from the collector.
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
void FilterCollectorForHierarchy(GENERAL_COLLECTOR &aCollector, bool aMultiselect) const
In general we don't want to select both a parent and any of it's children.
EDA_ITEM * GetTopLeftItem(bool aFootprintsOnly=false) const override
T * frame() const
PCB_DRAW_PANEL_GAL * canvas() const
bool m_isFootprintEditor
const PCB_SELECTION & selection() const
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition: picker_tool.h:84
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:73
int CurrentModifiers() const
Definition: picker_tool.h:110
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
Definition: picker_tool.h:93
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:104
int RelativeItemSelectionMove(const VECTOR2I &anchor, const VECTOR2I &translation)
Position the m_position_relative_selection selection relative to anchor position using the given tran...
int SelectPositionRelativePoint(const TOOL_EVENT &aEvent)
Invoke the picker tool to select the point to which the previous selection will be placed relative to...
int PositionRelative(const TOOL_EVENT &aEvent)
Invoke a dialog box to allow positioning of the item relative to another by an exact amount.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int SelectPositionRelativeItem(const TOOL_EVENT &aEvent)
Invoke the picker tool to select the item to which the previous selection will be placed relative to.
bool Init() override
Init() is called once upon a registration of the tool.
DIALOG_POSITION_RELATIVE * m_dialog
std::unique_ptr< BOARD_COMMIT > m_commit
VECTOR2I GetSelectionAnchorPosition() const
Return the position of the selected item(s)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
PCB_SELECTION_TOOL * m_selectionTool
bool IsHover() const
Definition: selection.h:84
EDA_ITEM * Front() const
Definition: selection.h:172
bool HasType(KICAD_T aType) const
Checks if there is at least one item of requested kind.
Definition: selection.cpp:145
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:177
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:84
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:218
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ RUN
Tool is invoked after being inactive.
Definition: tool_base.h:79
Generic, UI-independent tool event.
Definition: tool_event.h:167
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).
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 ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
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
EDA_UNITS GetUserUnits() const
This file is part of the common library.
#define _(s)
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:620
Class to handle a set of BOARD_ITEMs.
@ MD_SHIFT
Definition: tool_event.h:142
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87