KiCad PCB EDA Suite
class_pcb_group.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 Joshua Redstone redstone at gmail.com
5  * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 #include <bitmaps.h>
25 #include <class_board.h>
26 #include <class_board_item.h>
27 #include <class_pcb_group.h>
28 #include <confirm.h>
29 #include <widgets/msgpanel.h>
30 #include <view/view.h>
31 
33  BOARD_ITEM( aParent, PCB_GROUP_T )
34 {
35 }
36 
37 
39 {
40  // Items can only be in one group at a time
41  if( aItem->GetParentGroup() )
42  aItem->GetParentGroup()->RemoveItem( aItem );
43 
44  m_items.insert( aItem );
45  aItem->SetParentGroup( this );
46  return true;
47 }
48 
49 
51 {
52  // Only clear the item's group field if it was inside this group
53  if( m_items.erase( aItem ) == 1 )
54  {
55  aItem->SetParentGroup( nullptr );
56  return true;
57  }
58 
59  return false;
60 }
61 
62 
64 {
65  for( BOARD_ITEM* item : m_items )
66  item->SetParentGroup( nullptr );
67 
68  m_items.clear();
69 }
70 
71 
73 {
74  PCB_GROUP* candidate = item->GetParentGroup();
75 
76  if( !candidate && item->GetParent() && item->GetParent()->Type() == PCB_MODULE_T )
77  candidate = item->GetParent()->GetParentGroup();
78 
79  while( candidate && candidate->GetParentGroup() && candidate->GetParentGroup() != scope )
80  candidate = candidate->GetParentGroup();
81 
82  return candidate == scope ? nullptr : candidate;
83 }
84 
85 
87 {
88  if( item->GetParent() && item->GetParent()->Type() == PCB_MODULE_T )
89  item = item->GetParent();
90 
91  for( PCB_GROUP* parent = item->GetParentGroup(); parent; parent = parent->GetParentGroup() )
92  {
93  if( parent == scope )
94  return true;
95  }
96 
97  return false;
98 }
99 
100 
101 wxPoint PCB_GROUP::GetPosition() const
102 {
103  return GetBoundingBox().Centre();
104 }
105 
106 
107 void PCB_GROUP::SetPosition( const wxPoint& aNewpos )
108 {
109  wxPoint delta = aNewpos - GetPosition();
110 
111  Move( delta );
112 }
113 
114 
116 {
117  // Use copy constructor to get the same uuid and other fields
118  PCB_GROUP* newGroup = new PCB_GROUP( *this );
119  return newGroup;
120 }
121 
122 
124 {
125  // Use copy constructor to get the same uuid and other fields
126  PCB_GROUP* newGroup = new PCB_GROUP( *this );
127  newGroup->m_items.clear();
128 
129  for( BOARD_ITEM* member : m_items )
130  {
131  if( member->Type() == PCB_GROUP_T )
132  newGroup->AddItem( static_cast<PCB_GROUP*>( member )->DeepClone() );
133  else
134  newGroup->AddItem( static_cast<BOARD_ITEM*>( member->Clone() ) );
135  }
136 
137  return newGroup;
138 }
139 
140 
142 {
143  PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( this->Duplicate() );
144  newGroup->m_items.clear();
145 
146  for( BOARD_ITEM* member : m_items )
147  {
148  if( member->Type() == PCB_GROUP_T )
149  newGroup->AddItem( static_cast<PCB_GROUP*>( member )->DeepDuplicate() );
150  else
151  newGroup->AddItem( static_cast<BOARD_ITEM*>( member->Duplicate() ) );
152  }
153 
154  return newGroup;
155 }
156 
157 
159 {
160  assert( aImage->Type() == PCB_GROUP_T );
161 
162  std::swap( *( (PCB_GROUP*) this ), *( (PCB_GROUP*) aImage ) );
163 }
164 
165 
166 bool PCB_GROUP::HitTest( const wxPoint& aPosition, int aAccuracy ) const
167 {
168  // Groups are selected by promoting a selection of one of their children
169  return false;
170 }
171 
172 
173 bool PCB_GROUP::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
174 {
175  // Groups are selected by promoting a selection of one of their children
176  return false;
177 }
178 
179 
181 {
182  EDA_RECT area;
183 
184  for( BOARD_ITEM* item : m_items )
185  area.Merge( item->GetBoundingBox() );
186 
187  area.Inflate( Millimeter2iu( 0.25 ) ); // Give a min size to the area
188 
189  return area;
190 }
191 
192 
193 SEARCH_RESULT PCB_GROUP::Visit( INSPECTOR aInspector, void* aTestData, const KICAD_T aScanTypes[] )
194 {
195  for( const KICAD_T* stype = aScanTypes; *stype != EOT; ++stype )
196  {
197  // If caller wants to inspect my type
198  if( *stype == Type() )
199  {
200  if( SEARCH_RESULT::QUIT == aInspector( this, aTestData ) )
201  return SEARCH_RESULT::QUIT;
202  }
203  }
204 
206 }
207 
208 
210 {
211  LSET aSet;
212 
213  for( BOARD_ITEM* item : m_items )
214  aSet |= item->GetLayerSet();
215 
216  return aSet;
217 }
218 
219 
220 bool PCB_GROUP::IsOnLayer( PCB_LAYER_ID aLayer ) const
221 {
222  // A group is on a layer if any item is on the layer
223  for( BOARD_ITEM* item : m_items )
224  {
225  if( item->IsOnLayer( aLayer ) )
226  return true;
227  }
228 
229  return false;
230 }
231 
232 
233 void PCB_GROUP::ViewGetLayers( int aLayers[], int& aCount ) const
234 {
235  // What layer to put bounding box on? change in class_pcb_group.cpp
236  std::unordered_set<int> layers = { LAYER_ANCHOR }; // for bounding box
237 
238  for( BOARD_ITEM* item : m_items )
239  {
240  int member_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], member_layers_count;
241  item->ViewGetLayers( member_layers, member_layers_count );
242 
243  for( int i = 0; i < member_layers_count; i++ )
244  layers.insert( member_layers[i] );
245  }
246 
247  aCount = layers.size();
248  int i = 0;
249 
250  for( int layer : layers )
251  aLayers[i++] = layer;
252 }
253 
254 
255 double PCB_GROUP::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
256 {
257  if( aView->IsLayerVisible( LAYER_ANCHOR ) )
258  return 0.0;
259 
260  return std::numeric_limits<double>::max();
261 }
262 
263 
264 void PCB_GROUP::Move( const wxPoint& aMoveVector )
265 {
266  for( BOARD_ITEM* member : m_items )
267  member->Move( aMoveVector );
268 }
269 
270 
271 void PCB_GROUP::Rotate( const wxPoint& aRotCentre, double aAngle )
272 {
273  for( BOARD_ITEM* item : m_items )
274  item->Rotate( aRotCentre, aAngle );
275 }
276 
277 
278 void PCB_GROUP::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
279 {
280  for( BOARD_ITEM* item : m_items )
281  item->Flip( aCentre, aFlipLeftRight );
282 }
283 
284 
285 wxString PCB_GROUP::GetSelectMenuText( EDA_UNITS aUnits ) const
286 {
287  if( m_name.empty() )
288  {
289  return wxString::Format( _( "Anonymous Group, %zu members" ),
290  m_items.size() );
291  }
292 
293  return wxString::Format( _( "Group \"%s\", %zu members" ),
294  m_name,
295  m_items.size() );
296 }
297 
298 
300 {
301  return module_xpm;
302 }
303 
304 
305 void PCB_GROUP::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
306 {
307  aList.emplace_back( _( "Group" ), m_name.empty() ? _( "Anonymous" ) :
308  wxString::Format( "\"%s\"", m_name ), DARKCYAN );
309  aList.emplace_back( _( "Members" ), wxString::Format( "%zu", m_items.size() ), BROWN );
310 }
311 
312 
313 void PCB_GROUP::RunOnChildren( const std::function<void( BOARD_ITEM* )>& aFunction ) const
314 {
315  try
316  {
317  for( BOARD_ITEM* item : m_items )
318  aFunction( item );
319  }
320  catch( std::bad_function_call& )
321  {
322  wxFAIL_MSG( wxT( "Error calling function in PCB_GROUP::RunOnChildren" ) );
323  }
324 }
325 
326 
327 void PCB_GROUP::RunOnDescendants( const std::function<void( BOARD_ITEM* )>& aFunction ) const
328 {
329  try
330  {
331  for( BOARD_ITEM* item : m_items )
332  {
333  aFunction( item );
334 
335  if( item->Type() == PCB_GROUP_T )
336  static_cast<PCB_GROUP*>( item )->RunOnDescendants( aFunction );
337  }
338  }
339  catch( std::bad_function_call& )
340  {
341  wxFAIL_MSG( wxT( "Error calling function in PCB_GROUP::RunOnDescendants" ) );
342  }
343 }
PCB_GROUP * GetParentGroup() const
void RemoveAll()
void ViewGetLayers(int aLayers[], int &aCount) const override
bool AddItem(BOARD_ITEM *aItem)
Adds item to group.
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
const BITMAP_OPAQUE module_xpm[1]
Definition: module.cpp:29
void Merge(const EDA_RECT &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect.
Definition: eda_rect.cpp:431
PNG memory record (file in memory).
Definition: bitmap_def.h:29
void SwapData(BOARD_ITEM *aImage) override
static bool WithinScope(BOARD_ITEM *item, PCB_GROUP *scope)
This file is part of the common library.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:109
PCB_GROUP is a set of BOARD_ITEMs (i.e., without duplicates)
Classes BOARD_ITEM and BOARD_CONNECTED_ITEM.
anchor of items having an anchor point (texts, footprints)
wxPoint GetPosition() const override
Definition: color4d.h:62
SEARCH_RESULT Visit(INSPECTOR aInspector, void *aTestData, const KICAD_T aScanTypes[]) override
PCB_GROUP * DeepClone() const
const EDA_RECT GetBoundingBox() const override
The base class for create windows for drawing purpose.
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
PCB_GROUP * DeepDuplicate() const
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:94
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
static constexpr int VIEW_MAX_LAYERS
maximum number of layers that may be shown
Definition: view.h:694
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
class MODULE, a footprint
Definition: typeinfo.h:89
void Rotate(const wxPoint &aRotCentre, double aAngle) override
PCB_LAYER_ID
A quick note on layer IDs:
LSET is a set of PCB_LAYER_IDs.
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
void Move(const wxPoint &aMoveVector) override
wxString m_name
LSET GetLayerSet() const override
bool RemoveItem(BOARD_ITEM *aItem)
Removes item from group.
void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invokes a function on all descendents of the group.
BITMAP_DEF GetMenuImage() const override
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
static PCB_GROUP * TopLevelGroup(BOARD_ITEM *item, PCB_GROUP *scope)
EDA_UNITS
Definition: eda_units.h:38
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
void SetPosition(const wxPoint &aNewpos) override
#define _(s)
Definition: 3d_actions.cpp:33
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: eda_item.h:148
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invokes a function on all members of the group.
wxPoint Centre() const
Definition: eda_rect.h:62
virtual BOARD_ITEM * Duplicate() const
Function Duplicate creates a copy of a BOARD_ITEM.
VIEW.
Definition: view.h:63
SEARCH_RESULT
Definition: eda_item.h:40
Message panel definition file.
BOARD_ITEM_CONTAINER * GetParent() const
static constexpr int Millimeter2iu(double mm)
std::unordered_set< BOARD_ITEM * > m_items
PCB_GROUP(BOARD_ITEM *aParent)
EDA_ITEM * Clone() const override
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:363
Class to handle a set of BOARD_ITEMs.
KICAD_T Type() const
Function Type()
Definition: eda_item.h:182
bool IsLayerVisible(int aLayer) const
Function IsLayerVisible() Returns information about visibility of a particular layer.
Definition: view.h:402
void SetParentGroup(PCB_GROUP *aGroup)