KiCad PCB EDA Suite
Loading...
Searching...
No Matches
group_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) 2020 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 <kiplatform/ui.h>
25#include <tool/tool_manager.h>
26#include <tools/pcb_actions.h>
28#include <tools/group_tool.h>
30#include <status_popup.h>
31#include <board_commit.h>
32#include <bitmaps.h>
34#include <pcb_group.h>
35#include <collectors.h>
36#include <footprint.h>
37
39{
40public:
42 {
43 SetIcon( BITMAPS::group ); // fixme
44 SetTitle( _( "Grouping" ) );
45
49 }
50
51 ACTION_MENU* create() const override
52 {
53 return new GROUP_CONTEXT_MENU();
54 }
55
56private:
57 void update() override
58 {
60 BOARD* board = static_cast<BOARD*>( getToolManager()->GetModel() );
61
62 const auto& selection = selTool->GetSelection();
63
64 wxString check = board->GroupsSanityCheck();
65 wxCHECK_RET( check == wxEmptyString, _( "Group is in inconsistent state:" ) + wxS( " " ) + check );
66
67 BOARD::GroupLegalOpsField legalOps = board->GroupLegalOps( selection );
68
69 Enable( PCB_ACTIONS::group.GetUIId(), legalOps.create );
70 Enable( PCB_ACTIONS::ungroup.GetUIId(), legalOps.ungroup );
71 Enable( PCB_ACTIONS::removeFromGroup.GetUIId(), legalOps.removeItems );
72 }
73};
74
75
77 PCB_TOOL_BASE( "pcbnew.Groups" ),
78 m_frame( nullptr ),
79 m_propertiesDialog( nullptr ),
80 m_selectionTool( nullptr )
81{
82}
83
84
86{
87 m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
88
89 if( aReason != RUN )
90 m_commit = std::make_unique<BOARD_COMMIT>( this );
91}
92
93
95{
96 m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
97
98 // Find the selection tool, so they can cooperate
100
101 // Add the group control menus to relevant other tools
102 if( m_selectionTool )
103 {
104 TOOL_MENU& selToolMenu = m_selectionTool->GetToolMenu();
105
106 std::shared_ptr<GROUP_CONTEXT_MENU> groupMenu = std::make_shared<GROUP_CONTEXT_MENU>();
107 groupMenu->SetTool( this );
108 selToolMenu.RegisterSubMenu( groupMenu );
109
110 selToolMenu.GetMenu().AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
111 }
112
113 return true;
114}
115
116
118{
119 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
120 PCB_GROUP* group = aEvent.Parameter<PCB_GROUP*>();
121
123 m_propertiesDialog->Destroy();
124
126
127 m_propertiesDialog->Show( true );
128
129 return 0;
130}
131
132
134{
136 STATUS_TEXT_POPUP statusPopup( frame() );
137 bool done = false;
138
140 m_propertiesDialog->Show( false );
141
142 Activate();
143
144 statusPopup.SetText( _( "Click on new member..." ) );
145
146 picker->SetClickHandler(
147 [&]( const VECTOR2D& aPoint ) -> bool
148 {
150
152 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
153 PCB_SELECTION_TOOL* sTool )
154 {
155 } );
156
157 if( sel.Empty() )
158 return true; // still looking for an item
159
160 statusPopup.Hide();
161
163 {
164 EDA_ITEM* elem = sel.Front();
165
166 if( !m_isFootprintEditor )
167 {
168 while( elem->GetParent() && elem->GetParent()->Type() != PCB_T )
169 elem = elem->GetParent();
170 }
171
173 m_propertiesDialog->Show( true );
174 }
175
176 return false; // got our item; don't need any more
177 } );
178
179 picker->SetMotionHandler(
180 [&] ( const VECTOR2D& aPos )
181 {
182 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
183 } );
184
185 picker->SetCancelHandler(
186 [&]()
187 {
188 if( m_propertiesDialog )
189 m_propertiesDialog->Show( true );
190
191 statusPopup.Hide();
192 } );
193
194 picker->SetFinalizeHandler(
195 [&]( const int& aFinalState )
196 {
197 done = true;
198 } );
199
200 statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
201 statusPopup.Popup();
202 canvas()->SetStatusPopup( statusPopup.GetPanel() );
203
204 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
205
206 while( !done )
207 {
208 // Pass events unless we receive a null event, then we must shut down
209 if( TOOL_EVENT* evt = Wait() )
210 evt->SetPassEvent();
211 else
212 break;
213 }
214
215 canvas()->SetStatusPopup( nullptr );
216
217 return 0;
218}
219
220
221int GROUP_TOOL::Group( const TOOL_EVENT& aEvent )
222{
225
227 {
228 selection = selTool->RequestSelection(
229 []( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
230 {
231 } );
232 }
233 else
234 {
235 selection = selTool->RequestSelection(
236 []( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
237 {
238 // Iterate from the back so we don't have to worry about removals.
239 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
240 {
241 BOARD_ITEM* item = aCollector[ i ];
242
243 if( item->GetParentFootprint() )
244 aCollector.Remove( item );
245 }
246 } );
247 }
248
249 if( selection.Empty() )
250 return 0;
251
252 BOARD* board = getModel<BOARD>();
253 BOARD_COMMIT commit( m_toolMgr );
254 PCB_GROUP* group = nullptr;
255
258 else
259 group = new PCB_GROUP( board );
260
261 for( EDA_ITEM* eda_item : selection )
262 {
263 if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( eda_item ) )
264 {
265 if( item->IsLocked() )
266 group->SetLocked( true );
267 }
268 }
269
270 commit.Add( group );
271
272 for( EDA_ITEM* eda_item : selection )
273 {
274 if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( eda_item ) )
275 commit.Stage( item, CHT_GROUP );
276 }
277
278 commit.Push( _( "Group Items" ) );
279
280 selTool->ClearSelection();
281 selTool->select( group );
282
284 m_frame->OnModify();
285
286 return 0;
287}
288
289
290int GROUP_TOOL::Ungroup( const TOOL_EVENT& aEvent )
291{
292 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
293 BOARD_COMMIT commit( m_toolMgr );
294 EDA_ITEMS toSelect;
295
296 if( selection.Empty() )
298
299 PCB_SELECTION selCopy = selection;
301
302 for( EDA_ITEM* item : selCopy )
303 {
304 PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( item );
305
306 if( group )
307 {
308 for( BOARD_ITEM* member : group->GetItems() )
309 {
310 commit.Stage( member, CHT_UNGROUP );
311 toSelect.push_back( member );
312 }
313
314 group->SetSelected();
315 commit.Remove( group );
316 }
317 }
318
319 commit.Push( _( "Ungroup Items" ) );
320
322
324 m_frame->OnModify();
325
326 return 0;
327}
328
329
331{
333 const PCB_SELECTION& selection = selTool->GetSelection();
334 BOARD_COMMIT commit( m_frame );
335
336 if( selection.Empty() )
338
339 for( EDA_ITEM* item : selection )
340 {
341 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
342 PCB_GROUP* group = boardItem->GetParentGroup();
343
344 if( group )
345 commit.Stage( boardItem, CHT_UNGROUP );
346 }
347
348 commit.Push( wxT( "Remove Group Items" ) );
349
351 m_frame->OnModify();
352
353 return 0;
354}
355
356
358{
360 const PCB_SELECTION& selection = selTool->GetSelection();
361
362 if( selection.GetSize() == 1 && selection[0]->Type() == PCB_GROUP_T )
363 selTool->EnterGroup();
364
365 return 0;
366}
367
368
370{
371 m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->ExitGroup( true /* Select the group */ );
372 return 0;
373}
374
375
377{
380
381 Go( &GROUP_TOOL::Group, PCB_ACTIONS::group.MakeEvent() );
386}
static TOOL_ACTION pickerTool
Definition: actions.h:189
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
TOOL_MANAGER * getToolManager() const
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:91
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:281
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:432
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:109
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been removed.
Definition: commit.h:92
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
void DoAddMember(EDA_ITEM *aItem)
bool Show(bool show) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:267
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:206
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
Definition: group_tool.cpp:51
void update() override
Update menu state stub.
Definition: group_tool.cpp:57
int GroupProperties(const TOOL_EVENT &aEvent)
Definition: group_tool.cpp:117
int LeaveGroup(const TOOL_EVENT &aEvent)
Definition: group_tool.cpp:369
bool Init() override
Init() is called once upon a registration of the tool.
Definition: group_tool.cpp:94
int RemoveFromGroup(const TOOL_EVENT &aEvent)
Restrict selection to only member of the group.
Definition: group_tool.cpp:330
DIALOG_GROUP_PROPERTIES * m_propertiesDialog
Definition: group_tool.h:74
int Group(const TOOL_EVENT &aEvent)
Ungroup selected items.
Definition: group_tool.cpp:221
std::unique_ptr< BOARD_COMMIT > m_commit
Definition: group_tool.h:76
PCB_SELECTION_TOOL * m_selectionTool
Definition: group_tool.h:75
int Ungroup(const TOOL_EVENT &aEvent)
Remove selection from group.
Definition: group_tool.cpp:290
PCB_BASE_EDIT_FRAME * m_frame
Definition: group_tool.h:73
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Definition: group_tool.cpp:85
void setTransitions() override
< Set up handlers for various events.
Definition: group_tool.cpp:376
int PickNewMember(const TOOL_EVENT &aEvent)
Invoke the picker tool to select a new member of the group.
Definition: group_tool.cpp:133
int EnterGroup(const TOOL_EVENT &aEvent)
Leave the current group (deselect its members and select the group as a whole).
Definition: group_tool.cpp:357
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:65
static TOOL_ACTION groupLeave
Definition: pcb_actions.h:523
static TOOL_ACTION group
Definition: pcb_actions.h:519
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION ungroup
Definition: pcb_actions.h:520
static TOOL_ACTION groupProperties
Definition: pcb_actions.h:298
static TOOL_ACTION pickNewGroupMember
Definition: pcb_actions.h:299
static TOOL_ACTION groupEnter
Definition: pcb_actions.h:522
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:76
static TOOL_ACTION removeFromGroup
Definition: pcb_actions.h:521
Common, abstract interface for edit frames.
void OnModify() override
Must be called after a change in order to set the "modify" flag and update other data structures and ...
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 select(EDA_ITEM *aItem) override
Take necessary action mark an item as selected.
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
void EnterGroup()
Enter the group at the head of the current selection.
int ClearSelection(const TOOL_EVENT &aEvent)
PCB_SELECTION & GetSelection()
PCB_BASE_EDIT_FRAME * frame() const
BOARD * board() const
bool m_isFootprintEditor
const PCB_SELECTION & selection() const
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:72
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:99
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:84
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
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
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
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_MENU & GetToolMenu()
void Activate()
Run the tool.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
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:145
EDA_ITEM * GetModel() const
Definition: tool_manager.h:393
Manage a CONDITIONAL_MENU and some number of CONTEXT_MENUs as sub-menus.
Definition: tool_menu.h:43
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
@ CHT_GROUP
Definition: commit.h:45
@ CHT_UNGROUP
Definition: commit.h:46
#define _(s)
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:532
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: gtk/ui.cpp:601
Class to handle a set of BOARD_ITEMs.
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110