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
42
44{
46}
47
52
53std::unordered_set<SCH_ITEM*> SCH_GROUP::GetSchItems() const
54{
55 std::unordered_set<SCH_ITEM*> items;
56
57 for( EDA_ITEM* item : m_items )
58 {
59 if( item->IsSCH_ITEM() )
60 items.insert( static_cast<SCH_ITEM*>( item ) );
61 }
62
63 return items;
64}
65
66
67/*
68 * @return if not in the symbol editor and aItem is in a symbol, returns the
69 * symbol's parent group. Otherwise, returns the aItem's parent group.
70 */
71EDA_GROUP* getClosestGroup( SCH_ITEM* aItem, bool isSymbolEditor )
72{
73 if( !isSymbolEditor && aItem->GetParent() && aItem->GetParent()->Type() == SCH_SYMBOL_T )
74 return static_cast<SCH_SYMBOL*>( aItem->GetParent() )->GetParentGroup();
75 else
76 return aItem->GetParentGroup();
77}
78
79
81EDA_GROUP* getNestedGroup( SCH_ITEM* aItem, EDA_GROUP* aScope, bool isSymbolEditor )
82{
83 EDA_GROUP* group = getClosestGroup( aItem, isSymbolEditor );
84
85 if( group == aScope )
86 return nullptr;
87
88 while( group && group->AsEdaItem()->GetParentGroup() && group->AsEdaItem()->GetParentGroup() != aScope )
89 {
90 if( group->AsEdaItem()->GetParent()->Type() == LIB_SYMBOL_T && isSymbolEditor )
91 break;
92
93 group = group->AsEdaItem()->GetParentGroup();
94 }
95
96 return group;
97}
98
99
100EDA_GROUP* SCH_GROUP::TopLevelGroup( SCH_ITEM* aItem, EDA_GROUP* aScope, bool isSymbolEditor )
101{
102 return getNestedGroup( aItem, aScope, isSymbolEditor );
103}
104
105
106bool SCH_GROUP::WithinScope( SCH_ITEM* aItem, SCH_GROUP* aScope, bool isSymbolEditor )
107{
108 EDA_GROUP* group = getClosestGroup( aItem, isSymbolEditor );
109
110 if( group && group == aScope )
111 return true;
112
113 EDA_GROUP* nested = getNestedGroup( aItem, aScope, isSymbolEditor );
114
115 return nested && nested->AsEdaItem()->GetParentGroup() && nested->AsEdaItem()->GetParentGroup() == aScope;
116}
117
118
120{
121 return GetBoundingBox().Centre();
122}
123
124
125void SCH_GROUP::SetPosition( const VECTOR2I& aNewpos )
126{
127 VECTOR2I delta = aNewpos - GetPosition();
128
129 Move( delta );
130}
131
132
134{
135 // Use copy constructor to get the same uuid and other fields
136 SCH_GROUP* newGroup = new SCH_GROUP( *this );
137 return newGroup;
138}
139
140
142{
143 // Use copy constructor to get the same uuid and other fields
144 SCH_GROUP* newGroup = new SCH_GROUP( *this );
145 newGroup->m_items.clear();
146
147 for( EDA_ITEM* member : m_items )
148 {
149 if( member->Type() == SCH_GROUP_T )
150 newGroup->AddItem( static_cast<SCH_GROUP*>( member )->DeepClone() );
151 else
152 newGroup->AddItem( static_cast<SCH_ITEM*>( member->Clone() ) );
153 }
154
155 return newGroup;
156}
157
158
159SCH_GROUP* SCH_GROUP::DeepDuplicate( bool addToParentGroup, SCH_COMMIT* aCommit ) const
160{
161 SCH_GROUP* newGroup = static_cast<SCH_GROUP*>( Duplicate( addToParentGroup, aCommit ) );
162 newGroup->m_items.clear();
163
164 for( EDA_ITEM* member : m_items )
165 {
166 if( member->Type() == SCH_GROUP_T )
167 newGroup->AddItem( static_cast<SCH_GROUP*>( member )->DeepDuplicate( IGNORE_PARENT_GROUP ) );
168 else
169 newGroup->AddItem( static_cast<SCH_ITEM*>( member )->Duplicate( IGNORE_PARENT_GROUP ) );
170 }
171
172 return newGroup;
173}
174
175
177{
178 assert( aImage->Type() == SCH_GROUP_T );
179 SCH_GROUP* image = static_cast<SCH_GROUP*>( aImage );
180
181 std::swap( m_items, image->m_items );
182 std::swap( m_name, image->m_name );
183 std::swap( m_designBlockLibId, image->m_designBlockLibId );
184
185 // A group doesn't own its children (they're owned by the schematic), so undo doesn't do a
186 // deep clone when making an image. However, it's still safest to update the parentGroup
187 // pointers of the group's children. We must do it in the right order in case any of the
188 // children are shared (ie: image first, "this" second so that any shared children end up
189 // with "this").
190 image->RunOnChildren(
191 [&]( SCH_ITEM* child )
192 {
193 child->SetParentGroup( image );
194 },
196
198 [&]( SCH_ITEM* child )
199 {
200 child->SetParentGroup( this );
201 },
203}
204
205
206bool SCH_GROUP::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
207{
208 // Groups are selected by promoting a selection of one of their children
209 return false;
210}
211
212
213bool SCH_GROUP::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
214{
215 // Groups are selected by promoting a selection of one of their children
216 return false;
217}
218
219
221{
222 BOX2I bbox;
223
224 for( EDA_ITEM* item : m_items )
225 {
226 if( item->Type() == SCH_SYMBOL_T || item->Type() == LIB_SYMBOL_T )
227 bbox.Merge( static_cast<SYMBOL*>( item )->GetBoundingBox() );
228 else
229 bbox.Merge( item->GetBoundingBox() );
230 }
231
232 bbox.Inflate( schIUScale.MilsToIU( 10 ) );
233
234 return bbox;
235}
236
237
238INSPECT_RESULT SCH_GROUP::Visit( INSPECTOR aInspector, void* aTestData,
239 const std::vector<KICAD_T>& aScanTypes )
240{
241 for( KICAD_T scanType : aScanTypes )
242 {
243 if( scanType == Type() )
244 {
245 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
247 }
248 }
249
251}
252
253
254std::vector<int> SCH_GROUP::ViewGetLayers() const
255{
256 return { LAYER_SCHEMATIC_ANCHOR };
257}
258
259
260double SCH_GROUP::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
261{
263 return LOD_SHOW;
264
265 return LOD_HIDE;
266}
267
268
269void SCH_GROUP::Move( const VECTOR2I& aMoveVector )
270{
271 for( EDA_ITEM* member : m_items )
272 {
273 EDA_ITEM_FLAGS flags = member->GetFlags();
274
275 if( member->Type() == SCH_LINE_T )
276 member->SetFlags( STARTPOINT | ENDPOINT );
277
278 static_cast<SCH_ITEM*>( member )->Move( aMoveVector );
279
280 member->SetFlags( flags );
281 }
282}
283
284
285void SCH_GROUP::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
286{
287 for( EDA_ITEM* member : m_items )
288 {
289 EDA_ITEM_FLAGS flags = member->GetFlags();
290
291 if( member->Type() == SCH_LINE_T )
292 member->SetFlags( STARTPOINT | ENDPOINT );
293
294 static_cast<SCH_ITEM*>( member )->Rotate( aCenter, aRotateCCW );
295
296 member->SetFlags( flags );
297 }
298}
299
300
302{
303 for( EDA_ITEM* member : m_items )
304 {
305 EDA_ITEM_FLAGS flags = member->GetFlags();
306
307 if( member->Type() == SCH_LINE_T )
308 member->SetFlags( STARTPOINT | ENDPOINT );
309
310 static_cast<SCH_ITEM*>( member )->MirrorHorizontally( aCenter );
311
312 member->SetFlags( flags );
313 }
314}
315
316
318{
319 for( EDA_ITEM* member : m_items )
320 {
321 EDA_ITEM_FLAGS flags = member->GetFlags();
322
323 if( member->Type() == SCH_LINE_T )
324 member->SetFlags( STARTPOINT | ENDPOINT );
325
326 static_cast<SCH_ITEM*>( member )->MirrorVertically( aCenter );
327
328 member->SetFlags( flags );
329 }
330}
331
332
333void SCH_GROUP::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
334 int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
335{
336 // TODO: should we plot the name & border of named groups?
337}
338
339
340wxString SCH_GROUP::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
341{
342 if( m_name.empty() )
343 return wxString::Format( _( "Unnamed Group, %zu members" ), m_items.size() );
344 else
345 return wxString::Format( _( "Group '%s', %zu members" ), m_name, m_items.size() );
346}
347
348
350{
351 return BITMAPS::module;
352}
353
354
355void SCH_GROUP::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
356{
357 aList.emplace_back( _( "Group" ), m_name.empty() ? _( "<unnamed>" ) : m_name );
358 aList.emplace_back( _( "Members" ), wxString::Format( wxT( "%zu" ), m_items.size() ) );
359}
360
361
362bool SCH_GROUP::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
363{
364 return EDA_ITEM::Matches( UnescapeString( GetName() ), aSearchData );
365}
366
367
368void SCH_GROUP::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
369{
370 try
371 {
372 for( EDA_ITEM* item : m_items )
373 {
374 aFunction( static_cast<SCH_ITEM*>( item ) );
375
376 if( item->Type() == SCH_GROUP_T && aMode == RECURSE_MODE::RECURSE )
377 static_cast<SCH_GROUP*>( item )->RunOnChildren( aFunction, RECURSE_MODE::RECURSE );
378 }
379 }
380 catch( std::bad_function_call& )
381 {
382 wxFAIL_MSG( wxT( "Error calling function in SCH_GROUP::RunOnChildren" ) );
383 }
384}
385
386
387bool SCH_GROUP::operator==( const SCH_ITEM& aSchItem ) const
388{
389 if( aSchItem.Type() != Type() )
390 return false;
391
392 const SCH_GROUP& other = static_cast<const SCH_GROUP&>( aSchItem );
393
394 return *this == other;
395}
396
397
398bool SCH_GROUP::operator==( const SCH_GROUP& aOther ) const
399{
400 if( m_items.size() != aOther.m_items.size() )
401 return false;
402
403 // The items in groups are in unordered sets hashed by the pointer value, so we need to
404 // order them by UUID (EDA_ITEM_SET) to compare
405 EDA_ITEM_SET itemSet( m_items.begin(), m_items.end() );
406 EDA_ITEM_SET otherItemSet( aOther.m_items.begin(), aOther.m_items.end() );
407
408 for( auto it1 = itemSet.begin(), it2 = otherItemSet.begin(); it1 != itemSet.end(); ++it1, ++it2 )
409 {
410 // Compare UUID instead of the items themselves because we only care if the contents
411 // of the group has changed, not which elements in the group have changed
412 if( ( *it1 )->m_Uuid != ( *it2 )->m_Uuid )
413 return false;
414 }
415
416 return true;
417}
418
419
420double SCH_GROUP::Similarity( const SCH_ITEM& aOther ) const
421{
422 if( aOther.Type() != Type() )
423 return 0.0;
424
425 const SCH_GROUP& other = static_cast<const SCH_GROUP&>( aOther );
426
427 double similarity = 0.0;
428
429 for( EDA_ITEM* item : m_items )
430 {
431 for( EDA_ITEM* otherItem : other.m_items )
432 {
433 similarity += static_cast<SCH_ITEM*>( item )->Similarity( *static_cast<SCH_ITEM*>( otherItem ) );
434 }
435 }
436
437 return similarity / m_items.size();
438}
439
440
441static struct SCH_GROUP_DESC
442{
444 {
451
452 propMgr.Mask( TYPE_HASH( SCH_GROUP ), TYPE_HASH( SCH_ITEM ), _HKI( "Position X" ) );
453 propMgr.Mask( TYPE_HASH( SCH_GROUP ), TYPE_HASH( SCH_ITEM ), _HKI( "Position Y" ) );
454
455 const wxString groupTab = _HKI( "Group Properties" );
456
457 propMgr.AddProperty(
459 groupTab );
460 }
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:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
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:115
EDA_ITEM * GetParent() const
Definition eda_item.h:112
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
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:66
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition view.h:422
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:53
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:167
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:140
void SetLayer(SCH_LAYER_ID aLayer)
Definition sch_item.h:341
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:54
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:50
@ RECURSE
Definition eda_item.h:51
@ NO_RECURSE
Definition eda_item.h:52
INSPECT_RESULT
Definition eda_item.h:44
std::set< EDA_ITEM *, CompareByUuid > EDA_ITEM_SET
Definition eda_item.h:577
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
#define IGNORE_PARENT_GROUP
Definition eda_item.h:55
#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:81
EDA_GROUP * getClosestGroup(SCH_ITEM *aItem, bool isSymbolEditor)
Definition sch_group.cpp:71
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