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>
28 #include <tools/pcb_picker_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 {
39 public:
41  {
42  SetIcon( BITMAPS::group ); // fixme
43  SetTitle( _( "Grouping" ) );
44 
49  }
50 
51  ACTION_MENU* create() const override
52  {
53  return new GROUP_CONTEXT_MENU();
54  }
55 
56 private:
57  void update() override
58  {
60  BOARD* board = selTool->GetBoard();
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  Enable( PCB_ACTIONS::groupEnter.GetUIId(), legalOps.enter );
73  }
74 };
75 
76 
78  PCB_TOOL_BASE( "pcbnew.Groups" ),
79  m_frame( nullptr ),
80  m_propertiesDialog( nullptr ),
81  m_selectionTool( nullptr )
82 {
83 }
84 
85 
87 {
88  m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
89 
90  if( aReason != RUN )
91  m_commit = std::make_unique<BOARD_COMMIT>( this );
92 }
93 
94 
96 {
97  m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
98 
99  // Find the selection tool, so they can cooperate
101 
102  std::shared_ptr<GROUP_CONTEXT_MENU> groupMenu = std::make_shared<GROUP_CONTEXT_MENU>();
103  groupMenu->SetTool( this );
104 
105  // Add the group control menus to relevant other tools
106  if( m_selectionTool )
107  {
108  TOOL_MENU& toolMenu = m_selectionTool->GetToolMenu();
109  CONDITIONAL_MENU& menu = toolMenu.GetMenu();
110 
111  toolMenu.AddSubMenu( groupMenu );
112 
113  menu.AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
114  }
115 
116  return true;
117 }
118 
119 
121 {
122  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
123  PCB_GROUP* group = aEvent.Parameter<PCB_GROUP*>();
124 
125  if( m_propertiesDialog )
126  m_propertiesDialog->Destroy();
127 
129 
130  m_propertiesDialog->Show( true );
131 
132  return 0;
133 }
134 
135 
137 {
138  std::string tool = "pcbnew.EditGroups.selectNewMember";
140  STATUS_TEXT_POPUP statusPopup( frame() );
141  bool done = false;
142 
143  if( m_propertiesDialog )
144  m_propertiesDialog->Show( false );
145 
146  Activate();
147 
148  statusPopup.SetText( _( "Click on new member..." ) );
149 
150  picker->SetClickHandler(
151  [&]( const VECTOR2D& aPoint ) -> bool
152  {
154 
156  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
157  PCB_SELECTION_TOOL* sTool )
158  {
159  } );
160 
161  if( sel.Empty() )
162  return true; // still looking for an item
163 
164  statusPopup.Hide();
165 
166  if( m_propertiesDialog )
167  {
169  m_propertiesDialog->Show( true );
170  }
171 
172  return false; // got our item; don't need any more
173  } );
174 
175  picker->SetMotionHandler(
176  [&] ( const VECTOR2D& aPos )
177  {
178  statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
179  } );
180 
181  picker->SetCancelHandler(
182  [&]()
183  {
184  if( m_propertiesDialog )
185  m_propertiesDialog->Show( true );
186 
187  statusPopup.Hide();
188  } );
189 
190  picker->SetFinalizeHandler(
191  [&]( const int& aFinalState )
192  {
193  done = true;
194  } );
195 
196  statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
197  statusPopup.Popup();
198 
199  m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
200 
201  while( !done )
202  {
203  // Pass events unless we receive a null event, then we must shut down
204  if( TOOL_EVENT* evt = Wait() )
205  evt->SetPassEvent();
206  else
207  break;
208  }
209 
210  return 0;
211 }
212 
213 
214 int GROUP_TOOL::Group( const TOOL_EVENT& aEvent )
215 {
218 
219  if( m_isFootprintEditor )
220  {
221  selection = selTool->RequestSelection(
222  []( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
223  {
224  } );
225  }
226  else
227  {
228  selection = selTool->RequestSelection(
229  []( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
230  {
231  // Iterate from the back so we don't have to worry about removals.
232  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
233  {
234  BOARD_ITEM* item = aCollector[ i ];
235 
236  switch( item->Type() )
237  {
238  case PCB_FP_TEXT_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 
259  if( m_isFootprintEditor )
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 
315 int 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  {
333  if( m_isFootprintEditor )
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( "Remove Group Items" );
402 
404  m_frame->OnModify();
405 
406  return 0;
407 }
408 
409 
410 int GROUP_TOOL::EnterGroup( const TOOL_EVENT& aEvent )
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 
422 int GROUP_TOOL::LeaveGroup( const TOOL_EVENT& aEvent )
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 selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:66
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
int LeaveGroup(const TOOL_EVENT &aEvent)
Definition: group_tool.cpp:422
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:60
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
int GroupProperties(const TOOL_EVENT &aEvent)
Definition: group_tool.cpp:120
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
void select(BOARD_ITEM *aItem)
Take necessary action mark an item as selected.
static TOOL_ACTION groupLeave
Definition: pcb_actions.h:432
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
void SaveCopyInUndoList(EDA_ITEM *aItemToCopy, UNDO_REDO aTypeCommand) override
Create a new entry in undo list of commands.
Definition: undo_redo.cpp:179
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.
BOARD * board() const
void update() override
Update menu state stub.
Definition: group_tool.cpp:57
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:48
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
void setTransitions() override
< Set up handlers for various events.
Definition: group_tool.cpp:429
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:79
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
Tool is invoked after being inactive.
Definition: tool_base.h:79
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
Manage a CONDITIONAL_MENU and some number of CONTEXT_MENUs as sub-menus.
Definition: tool_menu.h:42
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:566
TOOL_MENU & GetToolMenu()
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
PCB_BASE_EDIT_FRAME * m_frame
Definition: group_tool.h:73
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
static TOOL_ACTION group
Definition: pcb_actions.h:428
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:102
static TOOL_ACTION ungroup
Definition: pcb_actions.h:429
virtual bool IsLocked() const
Definition: board_item.cpp:64
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
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).
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:110
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:205
int RemoveFromGroup(const TOOL_EVENT &aEvent)
Restrict selection to only member of the group.
Definition: group_tool.cpp:373
static TOOL_ACTION pickerTool
Definition: actions.h:155
PCB_BASE_EDIT_FRAME * frame() const
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
Definition: group_tool.cpp:51
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:82
PCB_SELECTION & GetSelection()
Return the set of currently selected items.
static TOOL_ACTION removeFromGroup
Definition: pcb_actions.h:430
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:608
const PCB_SELECTION & selection() const
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:318
std::unique_ptr< BOARD_COMMIT > m_commit
Definition: group_tool.h:76
PCB_SELECTION_TOOL * m_selectionTool
Definition: group_tool.h:75
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Definition: group_tool.cpp:86
DIALOG_GROUP_PROPERTIES * m_propertiesDialog
Definition: group_tool.h:74
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:432
Generic, UI-independent tool event.
Definition: tool_event.h:152
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition: picker_tool.h:82
static TOOL_ACTION pickNewGroupMember
Definition: pcb_actions.h:215
void DoAddMember(EDA_ITEM *aItem)
bool Init() override
Init() is called once upon a registration of the tool.
Definition: group_tool.cpp:95
#define _(s)
A holder to handle information on schematic or board items.
bool m_isFootprintEditor
bool Show(bool show) override
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:98
Generic tool for picking an item.
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:88
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:71
int Ungroup(const TOOL_EVENT &aEvent)
Remove selection from group.
Definition: group_tool.cpp:315
virtual void OnModify()
Must be called after a change in order to set the "modify" flag of the current screen and update the ...
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection set, filtered according to aFlags and aClientFilter.
Common, abstract interface for edit frames.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
TOOL_MANAGER * getToolManager() const
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:240
BOARD * GetBoard() const
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:52
class ZONE, managed by a footprint
Definition: typeinfo.h:94
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
The selection tool: currently supports:
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:710
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
int Group(const TOOL_EVENT &aEvent)
Ungroup selected items.
Definition: group_tool.cpp:214
void Activate()
Run the tool.
int PickNewMember(const TOOL_EVENT &aEvent)
Invoke the picker tool to select a new member of the group.
Definition: group_tool.cpp:136
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
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Removes an item from the container.
Definition: footprint.cpp:513
int ClearSelection(const TOOL_EVENT &aEvent)
static TOOL_ACTION groupEnter
Definition: pcb_actions.h:431
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:56
static TOOL_ACTION groupProperties
Definition: pcb_actions.h:214
void SetCancelHandler(CANCEL_HANDLER aHandler)
Set a handler for cancel events (ESC or context-menu Cancel).
Definition: picker_tool.h:91
EDA_ITEM * Front() const
Definition: selection.h:145
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112