KiCad PCB EDA Suite
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 <tool/tool_manager.h>
25#include <tools/pcb_actions.h>
27#include <tools/group_tool.h>
29#include <status_popup.h>
30#include <board_commit.h>
31#include <bitmaps.h>
33#include <pcb_group.h>
34#include <collectors.h>
35#include <footprint.h>
36
38{
39public:
41 {
42 SetIcon( BITMAPS::group ); // fixme
43 SetTitle( _( "Grouping" ) );
44
48 }
49
50 ACTION_MENU* create() const override
51 {
52 return new GROUP_CONTEXT_MENU();
53 }
54
55private:
56 void update() override
57 {
59 BOARD* board = static_cast<BOARD*>( getToolManager()->GetModel() );
60
61 const auto& selection = selTool->GetSelection();
62
63 wxString check = board->GroupsSanityCheck();
64 wxCHECK_RET( check == wxEmptyString, _( "Group is in inconsistent state:" ) + wxS( " " ) + check );
65
66 BOARD::GroupLegalOpsField legalOps = board->GroupLegalOps( selection );
67
68 Enable( PCB_ACTIONS::group.GetUIId(), legalOps.create );
69 Enable( PCB_ACTIONS::ungroup.GetUIId(), legalOps.ungroup );
70 Enable( PCB_ACTIONS::removeFromGroup.GetUIId(), legalOps.removeItems );
71 }
72};
73
74
76 PCB_TOOL_BASE( "pcbnew.Groups" ),
77 m_frame( nullptr ),
78 m_propertiesDialog( nullptr ),
79 m_selectionTool( nullptr )
80{
81}
82
83
85{
86 m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
87
88 if( aReason != RUN )
89 m_commit = std::make_unique<BOARD_COMMIT>( this );
90}
91
92
94{
95 m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
96
97 // Find the selection tool, so they can cooperate
99
100 // Add the group control menus to relevant other tools
101 if( m_selectionTool )
102 {
103 TOOL_MENU& selToolMenu = m_selectionTool->GetToolMenu();
104
105 std::shared_ptr<GROUP_CONTEXT_MENU> groupMenu = std::make_shared<GROUP_CONTEXT_MENU>();
106 groupMenu->SetTool( this );
107 selToolMenu.RegisterSubMenu( groupMenu );
108
109 selToolMenu.GetMenu().AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
110 }
111
112 return true;
113}
114
115
117{
118 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
119 PCB_GROUP* group = aEvent.Parameter<PCB_GROUP*>();
120
122 m_propertiesDialog->Destroy();
123
125
126 m_propertiesDialog->Show( true );
127
128 return 0;
129}
130
131
133{
134 std::string tool = "pcbnew.EditGroups.selectNewMember";
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 m_propertiesDialog->DoAddMember( sel.Front() );
165 m_propertiesDialog->Show( true );
166 }
167
168 return false; // got our item; don't need any more
169 } );
170
171 picker->SetMotionHandler(
172 [&] ( const VECTOR2D& aPos )
173 {
174 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
175 } );
176
177 picker->SetCancelHandler(
178 [&]()
179 {
181 m_propertiesDialog->Show( true );
182
183 statusPopup.Hide();
184 } );
185
186 picker->SetFinalizeHandler(
187 [&]( const int& aFinalState )
188 {
189 done = true;
190 } );
191
192 statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
193 statusPopup.Popup();
194 canvas()->SetStatusPopup( statusPopup.GetPanel() );
195
196 m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
197
198 while( !done )
199 {
200 // Pass events unless we receive a null event, then we must shut down
201 if( TOOL_EVENT* evt = Wait() )
202 evt->SetPassEvent();
203 else
204 break;
205 }
206
207 canvas()->SetStatusPopup( nullptr );
208
209 return 0;
210}
211
212
213int GROUP_TOOL::Group( const TOOL_EVENT& aEvent )
214{
217
219 {
220 selection = selTool->RequestSelection(
221 []( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
222 {
223 } );
224 }
225 else
226 {
227 selection = selTool->RequestSelection(
228 []( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
229 {
230 // Iterate from the back so we don't have to worry about removals.
231 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
232 {
233 BOARD_ITEM* item = aCollector[ i ];
234
235 switch( item->Type() )
236 {
237 case PCB_FP_TEXT_T:
238 case PCB_FP_TEXTBOX_T:
239 case PCB_FP_SHAPE_T:
240 case PCB_FP_ZONE_T:
241 case PCB_PAD_T:
242 aCollector.Remove( item );
243 break;
244
245 default:
246 break;
247 }
248 }
249 } );
250 }
251
252 if( selection.Empty() )
253 return 0;
254
255 BOARD* board = getModel<BOARD>();
256 PCB_GROUP* group = nullptr;
257 bool lockGroup = false;
258
260 {
261 FOOTPRINT* parentFootprint = board->GetFirstFootprint();
262
263 m_frame->SaveCopyInUndoList( parentFootprint, UNDO_REDO::CHANGED );
264
265 group = new PCB_GROUP( parentFootprint );
266 parentFootprint->Add( group );
267
268 for( EDA_ITEM* eda_item : selection )
269 {
270 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( eda_item );
271
272 if( item->IsLocked() )
273 lockGroup = true;
274
275 group->AddItem( item );
276 }
277 }
278 else
279 {
280 PICKED_ITEMS_LIST undoList;
281
282 group = new PCB_GROUP( board );
283 board->Add( group );
284
285 undoList.PushItem( ITEM_PICKER( nullptr, group, UNDO_REDO::NEWITEM ) );
286
287 for( EDA_ITEM* eda_item : selection )
288 {
289 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( eda_item );
290
291 if( item->IsLocked() )
292 lockGroup = true;
293
294 group->AddItem( static_cast<BOARD_ITEM*>( item ) );
295
296 undoList.PushItem( ITEM_PICKER( nullptr, item, UNDO_REDO::REGROUP ) );
297 }
298
300 }
301
302 if( lockGroup )
303 group->SetLocked( true );
304
305 selTool->ClearSelection();
306 selTool->select( group );
307
309 m_frame->OnModify();
310
311 return 0;
312}
313
314
315int GROUP_TOOL::Ungroup( const TOOL_EVENT& aEvent )
316{
317 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
318 BOARD* board = getModel<BOARD>();
319 std::vector<BOARD_ITEM*> members;
320
321 if( selection.Empty() )
323
324 PCB_SELECTION selCopy = selection;
326
327 for( EDA_ITEM* item : selCopy )
328 {
329 PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( item );
330
331 if( group )
332 {
334 {
335 FOOTPRINT* parentFootprint = board->GetFirstFootprint();
336
337 m_frame->SaveCopyInUndoList( parentFootprint, UNDO_REDO::CHANGED );
338
339 group->RemoveAll();
340 parentFootprint->Remove( group );
341 }
342 else
343 {
344 PICKED_ITEMS_LIST undoList;
345
346 for( BOARD_ITEM* member : group->GetItems() )
347 {
348 undoList.PushItem( ITEM_PICKER( nullptr, member, UNDO_REDO::UNGROUP ) );
349 members.push_back( member );
350 }
351
352 group->RemoveAll();
353 board->Remove( group );
354
355 undoList.PushItem( ITEM_PICKER( nullptr, group, UNDO_REDO::DELETED ) );
356
358 }
359
360 group->SetSelected();
361 }
362 }
363
364 m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &members );
365
367 m_frame->OnModify();
368
369 return 0;
370}
371
372
374{
376 const PCB_SELECTION& selection = selTool->GetSelection();
377 BOARD_COMMIT commit( m_frame );
378
379 if( selection.Empty() )
381
382 std::map<PCB_GROUP*, std::vector<BOARD_ITEM*>> groupMap;
383
384 for( EDA_ITEM* item : selection )
385 {
386 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
387 PCB_GROUP* group = boardItem->GetParentGroup();
388
389 if( group )
390 groupMap[ group ].push_back( boardItem );
391 }
392
393 for( std::pair<PCB_GROUP*, std::vector<BOARD_ITEM*>> pair : groupMap )
394 {
395 commit.Modify( pair.first );
396
397 for( BOARD_ITEM* item : pair.second )
398 pair.first->RemoveItem( item );
399 }
400
401 commit.Push( wxT( "Remove Group Items" ) );
402
404 m_frame->OnModify();
405
406 return 0;
407}
408
409
411{
413 const PCB_SELECTION& selection = selTool->GetSelection();
414
415 if( selection.GetSize() == 1 && selection[0]->Type() == PCB_GROUP_T )
416 selTool->EnterGroup();
417
418 return 0;
419}
420
421
423{
424 m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->ExitGroup( true /* Select the group */ );
425 return 0;
426}
427
428
430{
433
434 Go( &GROUP_TOOL::Group, PCB_ACTIONS::group.MakeEvent() );
439}
static TOOL_ACTION pickerTool
Definition: actions.h:158
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:87
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:72
virtual bool IsLocked() const
Definition: board_item.cpp:71
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:711
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:397
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:820
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 & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
bool Show(bool show) override
void SetStatusPopup(wxWindow *aPopup)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
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
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:621
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:561
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:204
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
Definition: group_tool.cpp:50
void update() override
Update menu state stub.
Definition: group_tool.cpp:56
int GroupProperties(const TOOL_EVENT &aEvent)
Definition: group_tool.cpp:116
int LeaveGroup(const TOOL_EVENT &aEvent)
Definition: group_tool.cpp:422
bool Init() override
Init() is called once upon a registration of the tool.
Definition: group_tool.cpp:93
int RemoveFromGroup(const TOOL_EVENT &aEvent)
Restrict selection to only member of the group.
Definition: group_tool.cpp:373
DIALOG_GROUP_PROPERTIES * m_propertiesDialog
Definition: group_tool.h:74
int Group(const TOOL_EVENT &aEvent)
Ungroup selected items.
Definition: group_tool.cpp:213
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:315
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:84
void setTransitions() override
< Set up handlers for various events.
Definition: group_tool.cpp:429
int PickNewMember(const TOOL_EVENT &aEvent)
Invoke the picker tool to select a new member of the group.
Definition: group_tool.cpp:132
int EnterGroup(const TOOL_EVENT &aEvent)
Leave the current group (deselect its members and select the group as a whole).
Definition: group_tool.cpp:410
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:56
static TOOL_ACTION groupLeave
Definition: pcb_actions.h:474
static TOOL_ACTION group
Definition: pcb_actions.h:470
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION ungroup
Definition: pcb_actions.h:471
static TOOL_ACTION groupProperties
Definition: pcb_actions.h:249
static TOOL_ACTION pickNewGroupMember
Definition: pcb_actions.h:250
static TOOL_ACTION groupEnter
Definition: pcb_actions.h:473
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:66
static TOOL_ACTION removeFromGroup
Definition: pcb_actions.h:472
Common, abstract interface for edit frames.
void SaveCopyInUndoList(EDA_ITEM *aItemToCopy, UNDO_REDO aTypeCommand) override
Create a new entry in undo list of commands.
Definition: undo_redo.cpp:282
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
PCB_DRAW_PANEL_GAL * canvas() const
bool m_isFootprintEditor
const PCB_SELECTION & selection() const
A holder to handle information on schematic or board items.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
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
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:97
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
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
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()
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.
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, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
EDA_ITEM * GetModel() const
Definition: tool_manager.h:292
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
#define _(s)
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
Definition: typeinfo.h:93
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92