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-2021 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 sTool->FilterCollectorForFreePads( aCollector );
77 },
78 !m_isFootprintEditor /* prompt user regarding locked items */ );
79
80 if( selection.Empty() )
81 return 0;
82
84
85 PCB_TYPE_COLLECTOR collector;
86 collector.Collect( static_cast<BOARD_ITEM*>( m_selection.GetTopLeftItem() ), { PCB_PAD_T } );
87
88 if( collector.GetCount() == 0 )
89 {
90 for( FOOTPRINT* footprint : editFrame->GetBoard()->Footprints() )
91 {
92 for( PAD* pad : footprint->Pads() )
93 {
94 if( pad->IsSelected() )
95 collector.Append( pad );
96
97 if( collector.GetCount() > 0 )
98 break;
99 }
100
101 if( collector.GetCount() > 0 )
102 break;
103 }
104 }
105
106 if( collector.GetCount() > 0 )
107 m_selectionAnchor = collector[0]->GetPosition();
108 else
110
111 // The dialog is not modal and not deleted between calls.
112 // It means some options can have changed since the last call.
113 // Therefore we need to rebuild it in case UI units have changed since the last call.
114 if( m_dialog && m_dialog->GetUserUnits() != editFrame->GetUserUnits() )
115 {
116 m_dialog->Destroy();
117 m_dialog = nullptr;
118 }
119
120 if( !m_dialog )
122
123 m_dialog->Show( true );
124
125 return 0;
126}
127
128
130 const VECTOR2I& aTranslation )
131{
132 VECTOR2I aggregateTranslation = aPosAnchor + aTranslation - GetSelectionAnchorPosition();
133
134 for( EDA_ITEM* item : m_selection )
135 {
136 // Don't move a pad by itself unless editing the footprint
137 if( item->Type() == PCB_PAD_T && frame()->IsType( FRAME_PCB_EDITOR ) )
138 item = item->GetParent();
139
140 m_commit->Modify( item );
141
142 // If moving a group, record position of all the descendants for undo
143 if( item->Type() == PCB_GROUP_T )
144 {
145 PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
146 group->RunOnDescendants( [&]( BOARD_ITEM* bItem )
147 {
148 m_commit->Modify( bItem );
149 });
150 }
151
152 static_cast<BOARD_ITEM*>( item )->Move( aggregateTranslation );
153 }
154
155 m_commit->Push( _( "Position Relative" ) );
156
157 if( m_selection.IsHover() )
159
161
162 canvas()->Refresh();
163 return 0;
164}
165
166
168{
169 std::string tool = "pcbnew.PositionRelative.selectReferenceItem";
171 STATUS_TEXT_POPUP statusPopup( frame() );
172 bool done = false;
173
174 Activate();
175
176 statusPopup.SetText( _( "Click on reference item..." ) );
177
178 picker->SetClickHandler(
179 [&]( const VECTOR2D& aPoint ) -> bool
180 {
183 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
184 PCB_SELECTION_TOOL* sTool )
185 {
186 } );
187
188 if( sel.Empty() )
189 return true; // still looking for an item
190
191 m_anchor_item = sel.Front();
192 statusPopup.Hide();
193
194 if( m_dialog )
195 m_dialog->UpdateAnchor( sel.Front() );
196
197 return false; // got our item; don't need any more
198 } );
199
200 picker->SetMotionHandler(
201 [&] ( const VECTOR2D& aPos )
202 {
203 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
204 } );
205
206 picker->SetCancelHandler(
207 [&]()
208 {
209 statusPopup.Hide();
210
211 if( m_dialog )
213 } );
214
215 picker->SetFinalizeHandler(
216 [&]( const int& aFinalState )
217 {
218 done = true;
219 } );
220
221 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
222 statusPopup.Popup();
223 canvas()->SetStatusPopup( statusPopup.GetPanel() );
224
225 m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
226
227 while( !done )
228 {
229 // Pass events unless we receive a null event, then we must shut down
230 if( TOOL_EVENT* evt = Wait() )
231 evt->SetPassEvent();
232 else
233 break;
234 }
235
236 canvas()->SetStatusPopup( nullptr );
237
238 return 0;
239}
240
241
243{
247}
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:50
FOOTPRINTS & Footprints()
Definition: board.h:307
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
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:210
PADS & Pads()
Definition: footprint.h:174
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
Definition: pad.h:58
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:261
static TOOL_ACTION selectpositionRelativeItem
Selection of anchor item for position relative tool.
Definition: pcb_actions.h:264
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
BOARD * GetBoard() const
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 FilterCollectorForFreePads(GENERAL_COLLECTOR &aCollector) const
Check the "allow free pads" setting and if disabled, replace any pads in the collector with their par...
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
FOOTPRINT * footprint() const
Collect all BOARD_ITEM objects of a given set of KICAD_T type(s).
Definition: collectors.h:522
void Collect(BOARD_ITEM *aBoard, const std::vector< KICAD_T > &aTypes)
Collect BOARD_ITEM objects using this class's Inspector method, which does the collection.
Definition: collectors.cpp:631
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:81
EDA_ITEM * Front() const
Definition: selection.h:200
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:107
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:83
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
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