KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_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 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, 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#include <bitmaps.h>
24#include <eda_draw_frame.h>
25#include <eda_group.h>
27#include <sch_item.h>
28#include <sch_group.h>
29#include <sch_screen.h>
30#include <sch_symbol.h>
31#include <symbol.h>
32#include <confirm.h>
33#include <widgets/msgpanel.h>
34#include <view/view.h>
35
36#include <wx/debug.h>
37#include <properties/property.h>
39
44
46{
48}
49
54
55std::unordered_set<SCH_ITEM*> SCH_GROUP::GetSchItems() const
56{
57 std::unordered_set<SCH_ITEM*> items;
58
59 for( EDA_ITEM* item : m_items )
60 {
61 if( item->IsSCH_ITEM() )
62 items.insert( static_cast<SCH_ITEM*>( item ) );
63 }
64
65 return items;
66}
67
68
69/*
70 * @return if not in the symbol editor and aItem is in a symbol, returns the
71 * symbol's parent group. Otherwise, returns the aItem's parent group.
72 */
73EDA_GROUP* getClosestGroup( SCH_ITEM* aItem, bool isSymbolEditor )
74{
75 if( !isSymbolEditor && aItem->GetParent() && aItem->GetParent()->Type() == SCH_SYMBOL_T )
76 return static_cast<SCH_SYMBOL*>( aItem->GetParent() )->GetParentGroup();
77 else
78 return aItem->GetParentGroup();
79}
80
81
83EDA_GROUP* getNestedGroup( SCH_ITEM* aItem, EDA_GROUP* aScope, bool isSymbolEditor )
84{
85 EDA_GROUP* group = getClosestGroup( aItem, isSymbolEditor );
86
87 if( group == aScope )
88 return nullptr;
89
90 while( group && group->AsEdaItem()->GetParentGroup() && group->AsEdaItem()->GetParentGroup() != aScope )
91 {
92 if( group->AsEdaItem()->GetParent()->Type() == LIB_SYMBOL_T && isSymbolEditor )
93 break;
94
95 group = group->AsEdaItem()->GetParentGroup();
96 }
97
98 return group;
99}
100
101
102EDA_GROUP* SCH_GROUP::TopLevelGroup( SCH_ITEM* aItem, EDA_GROUP* aScope, bool isSymbolEditor )
103{
104 return getNestedGroup( aItem, aScope, isSymbolEditor );
105}
106
107
108bool SCH_GROUP::WithinScope( SCH_ITEM* aItem, SCH_GROUP* aScope, bool isSymbolEditor )
109{
110 EDA_GROUP* group = getClosestGroup( aItem, isSymbolEditor );
111
112 if( group && group == aScope )
113 return true;
114
115 EDA_GROUP* nested = getNestedGroup( aItem, aScope, isSymbolEditor );
116
117 return nested && nested->AsEdaItem()->GetParentGroup() && nested->AsEdaItem()->GetParentGroup() == aScope;
118}
119
120
122{
123 return GetBoundingBox().Centre();
124}
125
126
127void SCH_GROUP::SetPosition( const VECTOR2I& aNewpos )
128{
129 VECTOR2I delta = aNewpos - GetPosition();
130
131 Move( delta );
132}
133
134
136{
137 // Use copy constructor to get the same uuid and other fields
138 SCH_GROUP* newGroup = new SCH_GROUP( *this );
139 return newGroup;
140}
141
142
144{
145 // Use copy constructor to get the same uuid and other fields
146 SCH_GROUP* newGroup = new SCH_GROUP( *this );
147 newGroup->m_items.clear();
148
149 for( EDA_ITEM* member : m_items )
150 {
151 if( member->Type() == SCH_GROUP_T )
152 newGroup->AddItem( static_cast<SCH_GROUP*>( member )->DeepClone() );
153 else
154 newGroup->AddItem( static_cast<SCH_ITEM*>( member->Clone() ) );
155 }
156
157 return newGroup;
158}
159
160
161SCH_GROUP* SCH_GROUP::DeepDuplicate( bool addToParentGroup, SCH_COMMIT* aCommit ) const
162{
163 SCH_GROUP* newGroup = static_cast<SCH_GROUP*>( Duplicate( addToParentGroup, aCommit ) );
164 newGroup->m_items.clear();
165
166 for( EDA_ITEM* member : m_items )
167 {
168 if( member->Type() == SCH_GROUP_T )
169 newGroup->AddItem( static_cast<SCH_GROUP*>( member )->DeepDuplicate( IGNORE_PARENT_GROUP ) );
170 else
171 newGroup->AddItem( static_cast<SCH_ITEM*>( member )->Duplicate( IGNORE_PARENT_GROUP ) );
172 }
173
174 return newGroup;
175}
176
177
179{
180 assert( aImage->Type() == SCH_GROUP_T );
181 SCH_GROUP* image = static_cast<SCH_GROUP*>( aImage );
182
183 std::swap( m_items, image->m_items );
184 std::swap( m_name, image->m_name );
185 std::swap( m_designBlockLibId, image->m_designBlockLibId );
186
187 // A group doesn't own its children (they're owned by the schematic), so undo doesn't do a
188 // deep clone when making an image. However, it's still safest to update the parentGroup
189 // pointers of the group's children. We must do it in the right order in case any of the
190 // children are shared (ie: image first, "this" second so that any shared children end up
191 // with "this").
192 image->RunOnChildren(
193 [&]( SCH_ITEM* child )
194 {
195 child->SetParentGroup( image );
196 },
198
200 [&]( SCH_ITEM* child )
201 {
202 child->SetParentGroup( this );
203 },
205}
206
207
208bool SCH_GROUP::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
209{
210 // Groups are selected by promoting a selection of one of their children
211 return false;
212}
213
214
215bool SCH_GROUP::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
216{
217 // Groups are selected by promoting a selection of one of their children
218 return false;
219}
220
221
223{
224 BOX2I bbox;
225
226 for( EDA_ITEM* item : m_items )
227 {
228 if( item->Type() == SCH_SYMBOL_T || item->Type() == LIB_SYMBOL_T )
229 bbox.Merge( static_cast<SYMBOL*>( item )->GetBoundingBox() );
230 else
231 bbox.Merge( item->GetBoundingBox() );
232 }
233
234 bbox.Inflate( schIUScale.MilsToIU( 10 ) );
235
236 return bbox;
237}
238
239
240INSPECT_RESULT SCH_GROUP::Visit( INSPECTOR aInspector, void* aTestData,
241 const std::vector<KICAD_T>& aScanTypes )
242{
243 for( KICAD_T scanType : aScanTypes )
244 {
245 if( scanType == Type() )
246 {
247 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
249 }
250 }
251
253}
254
255
256std::vector<int> SCH_GROUP::ViewGetLayers() const
257{
258 return { LAYER_SCHEMATIC_ANCHOR };
259}
260
261
262double SCH_GROUP::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
263{
265 return LOD_SHOW;
266
267 return LOD_HIDE;
268}
269
270
271void SCH_GROUP::Move( const VECTOR2I& aMoveVector )
272{
273 for( EDA_ITEM* member : m_items )
274 {
275 EDA_ITEM_FLAGS flags = member->GetFlags();
276
277 if( member->Type() == SCH_LINE_T )
278 member->SetFlags( STARTPOINT | ENDPOINT );
279
280 static_cast<SCH_ITEM*>( member )->Move( aMoveVector );
281
282 member->SetFlags( flags );
283 }
284}
285
286
287void SCH_GROUP::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
288{
289 for( EDA_ITEM* member : m_items )
290 {
291 EDA_ITEM_FLAGS flags = member->GetFlags();
292
293 if( member->Type() == SCH_LINE_T )
294 member->SetFlags( STARTPOINT | ENDPOINT );
295
296 static_cast<SCH_ITEM*>( member )->Rotate( aCenter, aRotateCCW );
297
298 member->SetFlags( flags );
299 }
300}
301
302
304{
305 for( EDA_ITEM* member : m_items )
306 {
307 EDA_ITEM_FLAGS flags = member->GetFlags();
308
309 if( member->Type() == SCH_LINE_T )
310 member->SetFlags( STARTPOINT | ENDPOINT );
311
312 static_cast<SCH_ITEM*>( member )->MirrorHorizontally( aCenter );
313
314 member->SetFlags( flags );
315 }
316}
317
318
320{
321 for( EDA_ITEM* member : m_items )
322 {
323 EDA_ITEM_FLAGS flags = member->GetFlags();
324
325 if( member->Type() == SCH_LINE_T )
326 member->SetFlags( STARTPOINT | ENDPOINT );
327
328 static_cast<SCH_ITEM*>( member )->MirrorVertically( aCenter );
329
330 member->SetFlags( flags );
331 }
332}
333
334
335void SCH_GROUP::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
336 int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
337{
338}
339
340
341wxString SCH_GROUP::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
342{
343 if( m_name.empty() )
344 return wxString::Format( _( "Unnamed Group, %zu members" ), m_items.size() );
345 else
346 return wxString::Format( _( "Group '%s', %zu members" ), m_name, m_items.size() );
347}
348
349
351{
352 return BITMAPS::module;
353}
354
355
356void SCH_GROUP::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
357{
358 aList.emplace_back( _( "Group" ), m_name.empty() ? _( "<unnamed>" ) : m_name );
359 aList.emplace_back( _( "Members" ), wxString::Format( wxT( "%zu" ), m_items.size() ) );
360}
361
362
363bool SCH_GROUP::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
364{
365 return EDA_ITEM::Matches( UnescapeString( GetName() ), aSearchData );
366}
367
368
369void SCH_GROUP::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
370{
371 try
372 {
373 for( EDA_ITEM* item : m_items )
374 {
375 aFunction( static_cast<SCH_ITEM*>( item ) );
376
377 if( item->Type() == SCH_GROUP_T && aMode == RECURSE_MODE::RECURSE )
378 static_cast<SCH_GROUP*>( item )->RunOnChildren( aFunction, RECURSE_MODE::RECURSE );
379 }
380 }
381 catch( std::bad_function_call& )
382 {
383 wxFAIL_MSG( wxT( "Error calling function in SCH_GROUP::RunOnChildren" ) );
384 }
385}
386
387
388bool SCH_GROUP::operator==( const SCH_ITEM& aSchItem ) const
389{
390 if( aSchItem.Type() != Type() )
391 return false;
392
393 const SCH_GROUP& other = static_cast<const SCH_GROUP&>( aSchItem );
394
395 return *this == other;
396}
397
398
399bool SCH_GROUP::operator==( const SCH_GROUP& aOther ) const
400{
401 if( m_items.size() != aOther.m_items.size() )
402 return false;
403
404 // The items in groups are in unordered sets hashed by the pointer value, so we need to
405 // order them by UUID (EDA_ITEM_SET) to compare
406 EDA_ITEM_SET itemSet( m_items.begin(), m_items.end() );
407 EDA_ITEM_SET otherItemSet( aOther.m_items.begin(), aOther.m_items.end() );
408
409 for( auto it1 = itemSet.begin(), it2 = otherItemSet.begin(); it1 != itemSet.end(); ++it1, ++it2 )
410 {
411 // Compare UUID instead of the items themselves because we only care if the contents
412 // of the group has changed, not which elements in the group have changed
413 if( ( *it1 )->m_Uuid != ( *it2 )->m_Uuid )
414 return false;
415 }
416
417 return true;
418}
419
420
421double SCH_GROUP::Similarity( const SCH_ITEM& aOther ) const
422{
423 if( aOther.Type() != Type() )
424 return 0.0;
425
426 const SCH_GROUP& other = static_cast<const SCH_GROUP&>( aOther );
427
428 double similarity = 0.0;
429
430 for( EDA_ITEM* item : m_items )
431 {
432 for( EDA_ITEM* otherItem : other.m_items )
433 {
434 similarity += static_cast<SCH_ITEM*>( item )->Similarity( *static_cast<SCH_ITEM*>( otherItem ) );
435 }
436 }
437
438 return similarity / m_items.size();
439}
440
441
442static struct SCH_GROUP_DESC
443{
445 {
452
453 propMgr.Mask( TYPE_HASH( SCH_GROUP ), TYPE_HASH( SCH_ITEM ), _HKI( "Position X" ) );
454 propMgr.Mask( TYPE_HASH( SCH_GROUP ), TYPE_HASH( SCH_ITEM ), _HKI( "Position Y" ) );
455
456 const wxString groupTab = _HKI( "Group Properties" );
457
458 propMgr.AddProperty(
460 groupTab );
461 }
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
BITMAPS
A list of all bitmap identifiers.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr Vec Centre() const
Definition box2.h:97
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
The base class for create windows for drawing purpose.
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
wxString m_name
Definition eda_group.h:77
std::unordered_set< EDA_ITEM * > m_items
Definition eda_group.h:76
wxString GetName() const
Definition eda_group.h:51
LIB_ID m_designBlockLibId
Definition eda_group.h:78
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition eda_group.cpp:27
virtual EDA_ITEM * AsEdaItem()=0
void SetName(const wxString &aName)
Definition eda_group.h:52
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:117
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:407
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:116
EDA_ITEM * GetParent() const
Definition eda_item.h:113
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:41
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:180
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:185
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition view.h:423
Base plotter engine class.
Definition plotter.h:136
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:52
SCH_GROUP * DeepDuplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr) const
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
std::vector< int > ViewGetLayers() const override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
static bool WithinScope(SCH_ITEM *aItem, SCH_GROUP *aScope, bool isSymbolEditor)
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
bool operator==(const SCH_GROUP &aOther) const
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
SCH_GROUP * DeepClone() const
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
INSPECT_RESULT Visit(INSPECTOR aInspector, void *aTestData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
void SetPosition(const VECTOR2I &aNewpos) override
std::unordered_set< SCH_ITEM * > GetSchItems() const
Definition sch_group.cpp:55
static EDA_GROUP * TopLevelGroup(SCH_ITEM *aItem, EDA_GROUP *aScope, bool isSymbolEditor)
void swapData(SCH_ITEM *aImage) override
Swap the internal data structures aItem with the schematic item.
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
VECTOR2I GetPosition() const override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:146
void SetLayer(SCH_LAYER_ID aLayer)
Definition sch_item.h:342
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:56
Schematic symbol object.
Definition sch_symbol.h:76
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
This file is part of the common library.
#define _(s)
RECURSE_MODE
Definition eda_item.h:51
@ RECURSE
Definition eda_item.h:52
@ NO_RECURSE
Definition eda_item.h:53
INSPECT_RESULT
Definition eda_item.h:45
std::set< EDA_ITEM *, CompareByUuid > EDA_ITEM_SET
Definition eda_item.h:576
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:92
#define IGNORE_PARENT_GROUP
Definition eda_item.h:56
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define STARTPOINT
When a line is selected, these flags indicate which.
@ LAYER_SCHEMATIC_ANCHOR
Definition layer_ids.h:500
@ LAYER_GROUP
Definition layer_ids.h:503
Message panel definition file.
#define _HKI(x)
Definition page_info.cpp:44
#define TYPE_HASH(x)
Definition property.h:74
#define REGISTER_TYPE(x)
static struct SCH_GROUP_DESC _SCH_GROUP_DESC
EDA_GROUP * getNestedGroup(SCH_ITEM *aItem, EDA_GROUP *aScope, bool isSymbolEditor)
Returns the top level group inside the aScope group, or nullptr.
Definition sch_group.cpp:83
EDA_GROUP * getClosestGroup(SCH_ITEM *aItem, bool isSymbolEditor)
Definition sch_group.cpp:73
Class to handle a set of SCH_ITEMs.
wxString UnescapeString(const wxString &aSource)
int delta
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ SCH_GROUP_T
Definition typeinfo.h:177
@ SCH_LINE_T
Definition typeinfo.h:167
@ LIB_SYMBOL_T
Definition typeinfo.h:152
@ SCH_SYMBOL_T
Definition typeinfo.h:176
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695