KiCad PCB EDA Suite
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
29#include <tools/pcb_actions.h>
33#include <status_popup.h>
34#include <board_commit.h>
35#include <confirm.h>
36#include <collectors.h>
37#include <pad.h>
38#include <footprint.h>
39#include <pcb_group.h>
40
41
43 PCB_TOOL_BASE( "pcbnew.PositionRelative" ),
44 m_dialog( nullptr ),
45 m_selectionTool( nullptr ),
46 m_anchor_item( nullptr )
47{
48}
49
50
52{
53 if( aReason != RUN )
54 m_commit = std::make_unique<BOARD_COMMIT>( this );
55}
56
57
59{
60 // Find the selection tool, so they can cooperate
62
63 return m_selectionTool != nullptr;
64}
65
66
68{
69 PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
70
72 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
73 {
74 sTool->FilterCollectorForHierarchy( aCollector, true );
75 sTool->FilterCollectorForMarkers( aCollector );
76 },
77 !m_isFootprintEditor /* prompt user regarding locked items */ );
78
79 if( selection.Empty() )
80 return 0;
81
83
84 // We prefer footprints, then pads, then anything else here.
85 EDA_ITEM* preferredItem = m_selection.GetTopLeftItem( true );
86
87 if( !preferredItem && m_selection.HasType( PCB_PAD_T ) )
88 {
89 PCB_SELECTION padsOnly = m_selection;
90 std::deque<EDA_ITEM*>& items = padsOnly.Items();
91 items.erase( std::remove_if( items.begin(), items.end(),
92 []( const EDA_ITEM* aItem )
93 {
94 return aItem->Type() != PCB_PAD_T;
95 } ), items.end() );
96
97 preferredItem = padsOnly.GetTopLeftItem();
98 }
99
100 if( preferredItem )
101 m_selectionAnchor = preferredItem->GetPosition();
102 else
104
105 // The dialog is not modal and not deleted between calls.
106 // It means some options can have changed since the last call.
107 // Therefore we need to rebuild it in case UI units have changed since the last call.
108 if( m_dialog && m_dialog->GetUserUnits() != editFrame->GetUserUnits() )
109 {
110 m_dialog->Destroy();
111 m_dialog = nullptr;
112 }
113
114 if( !m_dialog )
115 m_dialog = new DIALOG_POSITION_RELATIVE( editFrame );
116
117 m_dialog->Show( true );
118
119 return 0;
120}
121
122
124 const VECTOR2I& aTranslation )
125{
126 VECTOR2I aggregateTranslation = aPosAnchor + aTranslation - GetSelectionAnchorPosition();
127
128 for( EDA_ITEM* item : m_selection )
129 {
130 // Don't move a pad by itself unless editing the footprint
131 if( item->Type() == PCB_PAD_T
132 && !frame()->GetPcbNewSettings()->m_AllowFreePads
133 && frame()->IsType( FRAME_PCB_EDITOR ) )
134 {
135 item = item->GetParent();
136 }
137
138 m_commit->Modify( item );
139
140 // If moving a group, record position of all the descendants for undo
141 if( item->Type() == PCB_GROUP_T )
142 {
143 PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
144 group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
145 {
146 m_commit->Modify( bItem );
147 });
148 }
149
150 static_cast<BOARD_ITEM*>( item )->Move( aggregateTranslation );
151 }
152
153 m_commit->Push( _( "Position Relative" ) );
154
155 if( m_selection.IsHover() )
157
159
160 canvas()->Refresh();
161 return 0;
162}
163
164
166{
167 std::string tool = "pcbnew.PositionRelative.selectReferenceItem";
169 STATUS_TEXT_POPUP statusPopup( frame() );
170 bool done = false;
171
172 Activate();
173
174 statusPopup.SetText( _( "Click on reference item..." ) );
175
176 picker->SetClickHandler(
177 [&]( const VECTOR2D& aPoint ) -> bool
178 {
181 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
182 PCB_SELECTION_TOOL* sTool )
183 {
184 } );
185
186 if( sel.Empty() )
187 return true; // still looking for an item
188
189 m_anchor_item = sel.Front();
190 statusPopup.Hide();
191
192 if( m_dialog )
193 m_dialog->UpdateAnchor( sel.Front() );
194
195 return false; // got our item; don't need any more
196 } );
197
198 picker->SetMotionHandler(
199 [&] ( const VECTOR2D& aPos )
200 {
201 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
202 } );
203
204 picker->SetCancelHandler(
205 [&]()
206 {
207 statusPopup.Hide();
208
209 if( m_dialog )
211 } );
212
213 picker->SetFinalizeHandler(
214 [&]( const int& aFinalState )
215 {
216 done = true;
217 } );
218
219 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
220 statusPopup.Popup();
221 canvas()->SetStatusPopup( statusPopup.GetPanel() );
222
223 m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
224
225 while( !done )
226 {
227 // Pass events unless we receive a null event, then we must shut down
228 if( TOOL_EVENT* evt = Wait() )
229 evt->SetPassEvent();
230 else
231 break;
232 }
233
234 canvas()->SetStatusPopup( nullptr );
235
236 return 0;
237}
238
239
241{
245}
static TOOL_ACTION pickerTool
Definition: actions.h:158
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
bool Show(bool show) override
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:121
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
void SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:249
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:213
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION positionRelative
Activation of the position relative tool.
Definition: pcb_actions.h:269
static TOOL_ACTION selectpositionRelativeItem
Selection of anchor item for position relative tool.
Definition: pcb_actions.h:272
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
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
PCB_BASE_EDIT_FRAME * 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:82
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:71
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
Definition: picker_tool.h:91
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:102
int RelativeItemSelectionMove(const VECTOR2I &anchor, const VECTOR2I &translation)
Position the m_position_relative_selection selection relative to anchor position using the given tran...
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:83
EDA_ITEM * Front() const
Definition: selection.h:208
bool HasType(KICAD_T aType) const
Checks if there is at least one item of requested kind.
Definition: selection.cpp:144
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:213
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:83
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
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:156
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, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
EDA_UNITS GetUserUnits() const
This file is part of the common library.
#define _(s)
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87