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 The 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, see <https://www.gnu.org/licenses/>.
18 */
19#include "tool/group_tool.h"
20
21#include <set>
22
23#include <wx/string.h>
24
25#include <eda_draw_frame.h>
26#include <kiplatform/ui.h>
27#include <tool/actions.h>
28#include <tool/tool_manager.h>
29#include <tool/picker_tool.h>
30#include <tool/selection.h>
31#include <tool/selection_tool.h>
32#include <status_popup.h>
33#include <commit.h>
34#include <bitmaps.h>
36#include <eda_group.h>
37
39{
40public:
42 {
43 SetIcon( BITMAPS::group ); // fixme
44 SetTitle( _( "Grouping" ) );
45
50 }
51
52 ACTION_MENU* create() const override
53 {
56 return menu;
57 }
58
60
61private:
62 void update() override
63 {
64 int selectionCount = 0;
65 bool hasGroup = false;
66 bool hasMember = false;
67 bool onlyOneGroup = false;
68 bool hasUngroupedItems = false;
69
70 if( m_selectionTool != nullptr )
71 {
72 for( EDA_ITEM* item : m_selectionTool->GetSelection() )
73 {
74 selectionCount++;
75
76 if( item->Type() == PCB_GROUP_T || item->Type() == SCH_GROUP_T )
77 {
78 // Only allow one group to be selected for adding to existing group
79 if( hasGroup )
80 onlyOneGroup = false;
81 else
82 {
83 onlyOneGroup = true;
84 hasGroup = true;
85 }
86 }
87 else if( !item->GetParentGroup() )
88 hasUngroupedItems = true;
89
90 if( item->GetParentGroup() )
91 hasMember = true;
92 }
93 }
94
95 Enable( ACTIONS::group.GetUIId(), selectionCount >= 2 );
96 Enable( ACTIONS::ungroup.GetUIId(), hasGroup );
97 Enable( ACTIONS::addToGroup.GetUIId(), onlyOneGroup && hasUngroupedItems );
98 Enable( ACTIONS::removeFromGroup.GetUIId(), hasMember );
99 }
100
101private:
103};
104
105
107{
108}
109
110
116
117
119{
122
123 // Find the selection tool, so they can cooperate
124 m_selectionTool = static_cast<SELECTION_TOOL*>( m_toolMgr->FindTool( "common.InteractiveSelection" ) );
125 wxCHECK( m_selectionTool, false );
126
127 TOOL_MENU& selToolMenu = m_selectionTool->GetToolMenu();
128
129 std::shared_ptr<GROUP_CONTEXT_MENU> groupMenu = std::make_shared<GROUP_CONTEXT_MENU>();
130 groupMenu->SetTool( this );
131 groupMenu->SetSelectionTool( m_selectionTool );
132 selToolMenu.RegisterSubMenu( groupMenu );
133
134 selToolMenu.GetMenu().AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
135
136 return true;
137}
138
139
141{
142 EDA_GROUP* group = aEvent.Parameter<EDA_GROUP*>();
143
145 m_propertiesDialog->Destroy();
146
148
149 m_propertiesDialog->Show( true );
150
151 return 0;
152}
153
154
155int GROUP_TOOL::Ungroup( const TOOL_EVENT& aEvent )
156{
157 const SELECTION& selection = m_selectionTool->GetSelection();
158 EDA_ITEMS toSelect;
159
160 if( selection.Empty() )
162
163 SELECTION selCopy = selection;
165
166 for( EDA_ITEM* item : selCopy )
167 {
168 if( EDA_GROUP* group = dynamic_cast<EDA_GROUP*>( item ) )
169 {
170 group->AsEdaItem()->SetSelected();
171 m_commit->Remove( group->AsEdaItem(), m_frame->GetScreen() );
172
173 for( EDA_ITEM* member : group->GetItems() )
174 {
175 m_commit->Modify( member, m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
176 toSelect.push_back( member );
177 }
178
179 group->RemoveAll();
180 }
181 }
182
183 m_commit->Push( _( "Ungroup Items" ) );
184
185 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSelect );
186
188 m_frame->OnModify();
189
190 return 0;
191}
192
193
195{
196 const SELECTION& selection = m_selectionTool->GetSelection();
197
198 EDA_GROUP* group = nullptr;
199 EDA_ITEMS toAdd;
200 wxString errorMsg;
201
202 for( EDA_ITEM* item : selection )
203 {
204 if( item->Type() == PCB_GROUP_T || item->Type() == SCH_GROUP_T )
205 {
206 // Only allow one group to be selected for adding to existing group
207 if( group != nullptr )
208 return 0;
209
210 group = dynamic_cast<EDA_GROUP*>( item );
211 }
212 else if( !item->GetParentGroup() && canGroupItem( item, errorMsg ) )
213 {
214 toAdd.push_back( item );
215 }
216 }
217
218 if( !group || toAdd.empty() )
219 {
220 if( !errorMsg.IsEmpty() )
221 m_frame->ShowInfoBarWarning( errorMsg );
222
223 return 0;
224 }
225
227
228 m_commit->Modify( group->AsEdaItem(), m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
229
230 for( EDA_ITEM* item : toAdd )
231 {
232 EDA_GROUP* existingGroup = item->GetParentGroup();
233
234 if( existingGroup != group )
235 {
236 m_commit->Modify( item, m_frame->GetScreen() );
237
238 if( existingGroup )
239 m_commit->Modify( existingGroup->AsEdaItem(), m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
240
241 group->AddItem( item );
242 }
243 }
244
245 m_commit->Push( _( "Add Items to Group" ) );
246
247 m_selectionTool->AddItemToSel( group->AsEdaItem() );
249 m_frame->OnModify();
250
251 if( !errorMsg.IsEmpty() )
252 m_frame->ShowInfoBarWarning( errorMsg );
253
254 return 0;
255}
256
257
259{
260 const SELECTION& selection = m_selectionTool->GetSelection();
261
262 if( selection.Empty() )
264
265 std::set<EDA_GROUP*> affectedGroups;
266
267 for( EDA_ITEM* item : selection )
268 {
269 if( EDA_GROUP* group = item->GetParentGroup() )
270 {
271 m_commit->Modify( group->AsEdaItem(), m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
272 m_commit->Modify( item, m_frame->GetScreen() );
273 group->RemoveItem( item );
274 affectedGroups.insert( group );
275 }
276 }
277
278 for( EDA_GROUP* group : affectedGroups )
279 {
280 if( group->GetItems().size() < 2 )
281 {
282 group->RemoveAll();
283 m_commit->Remove( group->AsEdaItem(), m_frame->GetScreen() );
284 }
285 }
286
287 m_commit->Push( _( "Remove Group Items" ) );
288
290 m_frame->OnModify();
291
292 return 0;
293}
294
295
297{
298 const SELECTION& selection = m_selectionTool->GetSelection();
299
300 if( selection.GetSize() == 1 &&
301 (selection[0]->Type() == SCH_GROUP_T || selection[0]->Type() == PCB_GROUP_T) )
302 {
303 m_selectionTool->EnterGroup();
304 }
305
306 return 0;
307}
308
309
311{
312 m_selectionTool->ExitGroup( true /* Select the group */ );
313 return 0;
314}
315
316
static TOOL_ACTION pickNewGroupMember
Definition actions.h:244
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition actions.h:213
static TOOL_ACTION group
Definition actions.h:235
static TOOL_ACTION groupEnter
Definition actions.h:239
static TOOL_ACTION groupProperties
Definition actions.h:243
static TOOL_ACTION ungroup
Definition actions.h:236
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION addToGroup
Definition actions.h:237
static TOOL_ACTION removeFromGroup
Definition actions.h:238
static TOOL_ACTION groupLeave
Definition actions.h:240
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:228
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
Default constructor.
void SetTitle(const wxString &aTitle) override
Set title for the menu.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:42
virtual EDA_ITEM * AsEdaItem()=0
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:348
SELECTION_TOOL * m_selectionTool
void SetSelectionTool(SELECTION_TOOL *aTool)
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
void update() override
Update menu state stub.
virtual int GroupProperties(const TOOL_EVENT &aEvent)
SELECTION_TOOL * m_selectionTool
Definition group_tool.h:83
virtual int LeaveGroup(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
virtual int RemoveFromGroup(const TOOL_EVENT &aEvent)
Restrict selection to only member of the group.
DIALOG_GROUP_PROPERTIES * m_propertiesDialog
Definition group_tool.h:82
virtual std::shared_ptr< COMMIT > createCommit()=0
EDA_DRAW_FRAME * m_frame
Definition group_tool.h:81
virtual int Ungroup(const TOOL_EVENT &aEvent)
Add selection to group.
virtual int AddToGroup(const TOOL_EVENT &aEvent)
Remove selection from group.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
virtual int Group(const TOOL_EVENT &aEvent)=0
Ungroup selected items.
std::shared_ptr< COMMIT > m_commit
Definition group_tool.h:84
virtual int PickNewMember(const TOOL_EVENT &aEvent)=0
Invoke the picker tool to select a new member of the group.
void setTransitions() override
< Set up handlers for various events.
virtual bool canGroupItem(EDA_ITEM *aItem, wxString &aErrorMsg) const =0
Get the correctly casted group type from the item.
virtual int EnterGroup(const TOOL_EVENT &aEvent)
Leave the current group (deselect its members and select the group as a whole).
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:101
bool Empty() const
Checks if there is anything selected.
Definition selection.h:111
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
Generic, UI-independent tool event.
Definition tool_event.h:167
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:469
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_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
Manage a CONDITIONAL_MENU and some number of CONTEXT_MENUs as sub-menus.
Definition tool_menu.h:39
CONDITIONAL_MENU & GetMenu()
Definition tool_menu.cpp:40
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition tool_menu.cpp:46
#define _(s)
@ NO_RECURSE
Definition eda_item.h:50
std::vector< EDA_ITEM * > EDA_ITEMS
@ SCH_GROUP_T
Definition typeinfo.h:170
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:104