KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_sheet.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) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <cstdlib>
27
28#include <bitmaps.h>
29#include <core/mirror.h>
30#include <core/kicad_algo.h>
31#include <sch_draw_panel.h>
32#include <trigo.h>
33#include <sch_edit_frame.h>
34#include <plotters/plotter.h>
35#include <sch_plotter.h>
36#include <string_utils.h>
37#include <widgets/msgpanel.h>
38#include <math/util.h> // for KiROUND
40#include <sch_sheet.h>
41#include <sch_sheet_path.h>
42#include <sch_sheet_pin.h>
43#include <sch_no_connect.h>
44#include <sch_symbol.h>
45#include <sch_painter.h>
46#include <schematic.h>
49#include <trace_helpers.h>
50#include <validators.h>
52#include <pgm_base.h>
53#include <wx/log.h>
54
80
81
83 SCH_ITEM( aSheet )
84{
85 m_pos = aSheet.m_pos;
86 m_size = aSheet.m_size;
87 m_layer = aSheet.m_layer;
88 const_cast<KIID&>( m_Uuid ) = aSheet.m_Uuid;
89 m_fields = aSheet.m_fields;
91 m_screen = aSheet.m_screen;
92
96 m_DNP = aSheet.m_DNP;
97
101 m_instances = aSheet.m_instances;
102
103 for( SCH_SHEET_PIN* pin : aSheet.m_pins )
104 {
105 m_pins.emplace_back( new SCH_SHEET_PIN( *pin ) );
106 m_pins.back()->SetParent( this );
107 }
108
109 for( SCH_FIELD& field : m_fields )
110 field.SetParent( this );
111
112 if( m_screen )
113 m_screen->IncRefCount();
114}
115
116
118{
119 // also, look at the associated sheet & its reference count
120 // perhaps it should be deleted also.
121 if( m_screen )
122 {
123 m_screen->DecRefCount();
124
125 if( m_screen->GetRefCount() == 0 )
126 delete m_screen;
127 }
128
129 // We own our pins; delete them
130 for( SCH_SHEET_PIN* pin : m_pins )
131 delete pin;
132}
133
134
136{
137 return new SCH_SHEET( *this );
138}
139
140
142{
143 if( aScreen == m_screen )
144 return;
145
146 if( m_screen != nullptr )
147 {
148 m_screen->DecRefCount();
149
150 if( m_screen->GetRefCount() == 0 )
151 {
152 delete m_screen;
153 m_screen = nullptr;
154 }
155 }
156
157 m_screen = aScreen;
158
159 if( m_screen )
160 m_screen->IncRefCount();
161}
162
163
165{
166 if( m_screen == nullptr )
167 return 0;
168
169 return m_screen->GetRefCount();
170}
171
172
174{
175 wxCHECK_MSG( Schematic(), false, "Can't call IsVirtualRootSheet without setting a schematic" );
176
177 return m_Uuid == niluuid;
178}
179
180
182{
183 wxCHECK_MSG( Schematic(), false, "Can't call IsTopLevelSheet without setting a schematic" );
184
185 return Schematic()->IsTopLevelSheet( this );
186}
187
188
189void SCH_SHEET::GetContextualTextVars( wxArrayString* aVars ) const
190{
191 auto add =
192 [&]( const wxString& aVar )
193 {
194 if( !alg::contains( *aVars, aVar ) )
195 aVars->push_back( aVar );
196 };
197
198 for( const SCH_FIELD& field : m_fields )
199 {
200 if( field.IsMandatory() )
201 add( field.GetCanonicalName().Upper() );
202 else
203 add( field.GetName() );
204 }
205
206 SCH_SHEET_PATH sheetPath = findSelf();
207
208 if( sheetPath.size() >= 2 )
209 {
210 sheetPath.pop_back();
211 sheetPath.Last()->GetContextualTextVars( aVars );
212 }
213 else if( Schematic() )
214 {
216 }
217
218 add( wxT( "#" ) );
219 add( wxT( "##" ) );
220 add( wxT( "SHEETPATH" ) );
221 add( wxT( "EXCLUDE_FROM_BOM" ) );
222 add( wxT( "EXCLUDE_FROM_BOARD" ) );
223 add( wxT( "EXCLUDE_FROM_SIM" ) );
224 add( wxT( "DNP" ) );
225 add( wxT( "ERC_ERROR <message_text>" ) );
226 add( wxT( "ERC_WARNING <message_text>" ) );
227
228 m_screen->GetTitleBlock().GetContextualTextVars( aVars );
229}
230
231
232bool SCH_SHEET::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
233{
234 wxCHECK( aPath, false );
235
236 SCHEMATIC* schematic = Schematic();
237
238 if( !schematic )
239 return false;
240
241 if( token->Contains( ':' ) )
242 {
243 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
244 return true;
245 }
246
247 for( const SCH_FIELD& field : m_fields )
248 {
249 wxString fieldName = field.IsMandatory() ? field.GetCanonicalName().Upper()
250 : field.GetName();
251
252 if( token->IsSameAs( fieldName ) )
253 {
254 *token = field.GetShownText( aPath, false, aDepth + 1 );
255 return true;
256 }
257 }
258
259 PROJECT* project = &schematic->Project();
260
261 // We cannot resolve text variables initially on load as we need to first load the screen and
262 // then parse the hierarchy. So skip the resolution if the screen isn't set yet
263 if( m_screen && m_screen->GetTitleBlock().TextVarResolver( token, project ) )
264 {
265 return true;
266 }
267
268 if( token->IsSameAs( wxT( "#" ) ) )
269 {
270 *token = wxString::Format( "%s", aPath->GetPageNumber() );
271 return true;
272 }
273 else if( token->IsSameAs( wxT( "##" ) ) )
274 {
275 *token = wxString::Format( wxT( "%d" ), (int) schematic->Hierarchy().size() );
276 return true;
277 }
278 else if( token->IsSameAs( wxT( "SHEETPATH" ) ) )
279 {
280 *token = aPath->PathHumanReadable();
281 return true;
282 }
283 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
284 {
285 *token = wxEmptyString;
286
287 if( aPath->GetExcludedFromBOM() || this->ResolveExcludedFromBOM() )
288 *token = _( "Excluded from BOM" );
289
290 return true;
291 }
292 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
293 {
294 *token = wxEmptyString;
295
296 if( aPath->GetExcludedFromBoard() || this->ResolveExcludedFromBoard() )
297 *token = _( "Excluded from board" );
298
299 return true;
300 }
301 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
302 {
303 *token = wxEmptyString;
304
305 if( aPath->GetExcludedFromSim() || this->ResolveExcludedFromSim() )
306 *token = _( "Excluded from simulation" );
307
308 return true;
309 }
310 else if( token->IsSameAs( wxT( "DNP" ) ) )
311 {
312 *token = wxEmptyString;
313
314 if( aPath->GetDNP() || this->ResolveDNP() )
315 *token = _( "DNP" );
316
317 return true;
318 }
319
320 // See if parent can resolve it (these will recurse to ancestors)
321
322 if( aPath->size() >= 2 )
323 {
324 SCH_SHEET_PATH path = *aPath;
325 path.pop_back();
326
327 if( path.Last()->ResolveTextVar( &path, token, aDepth + 1 ) )
328 return true;
329 }
330 else
331 {
332 if( schematic->ResolveTextVar( aPath, token, aDepth + 1 ) )
333 return true;
334 }
335
336 return false;
337}
338
339
341{
342 wxCHECK_RET( aItem->Type() == SCH_SHEET_T,
343 wxString::Format( wxT( "SCH_SHEET object cannot swap data with %s object." ),
344 aItem->GetClass() ) );
345
346 SCH_SHEET* sheet = ( SCH_SHEET* ) aItem;
347
348 std::swap( m_pos, sheet->m_pos );
349 std::swap( m_size, sheet->m_size );
350 m_fields.swap( sheet->m_fields );
351 std::swap( m_fieldsAutoplaced, sheet->m_fieldsAutoplaced );
352 m_pins.swap( sheet->m_pins );
353
354 // Update parent pointers after swapping.
355 for( SCH_SHEET_PIN* sheetPin : m_pins )
356 sheetPin->SetParent( this );
357
358 for( SCH_SHEET_PIN* sheetPin : sheet->m_pins )
359 sheetPin->SetParent( sheet );
360
361 for( SCH_FIELD& field : m_fields )
362 field.SetParent( this );
363
364 for( SCH_FIELD& field : sheet->m_fields )
365 field.SetParent( sheet );
366
367 std::swap( m_excludedFromSim, sheet->m_excludedFromSim );
368 std::swap( m_excludedFromBOM, sheet->m_excludedFromBOM );
369 std::swap( m_excludedFromBoard, sheet->m_excludedFromBoard );
370 std::swap( m_DNP, sheet->m_DNP );
371
372 std::swap( m_borderWidth, sheet->m_borderWidth );
373 std::swap( m_borderColor, sheet->m_borderColor );
374 std::swap( m_backgroundColor, sheet->m_backgroundColor );
375 std::swap( m_instances, sheet->m_instances );
376}
377
378
380{
381 if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
382 return field;
383
384 m_fields.emplace_back( this, aFieldType );
385 return &m_fields.back();
386}
387
388
389const SCH_FIELD* SCH_SHEET::GetField( FIELD_T aFieldType ) const
390{
391 return FindField( m_fields, aFieldType );
392}
393
394
395SCH_FIELD* SCH_SHEET::GetField( const wxString& aFieldName )
396{
397 return FindField( m_fields, aFieldName );
398}
399
400
401const SCH_FIELD* SCH_SHEET::GetField( const wxString& aFieldName ) const
402{
403 return FindField( m_fields, aFieldName );
404}
405
406
408{
409 return NextFieldOrdinal( m_fields );
410}
411
412
413void SCH_SHEET::SetFields( const std::vector<SCH_FIELD>& aFields )
414{
415 m_fields = aFields;
416
417 // Make sure that we get the UNIX variant of the file path
419}
420
421
423{
424 SCH_FIELD* field = GetField( aField.GetId() );
425
426 if( ( aField.GetId() == FIELD_T::SHEET_FILENAME ) || ( aField.GetId() == FIELD_T::SHEET_NAME ) )
427 return;
428
429 if( field )
430 *field = aField;
431 else
432 m_fields.emplace_back( aField );
433}
434
435
436void SCH_SHEET::SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath,
437 const wxString& aVariantName )
438{
439 wxCHECK( !aFieldName.IsEmpty(), /* void */ );
440
441 SCH_FIELD* field = GetField( aFieldName );
442
443 wxCHECK( field, /* void */ );
444
445 switch( field->GetId() )
446 {
448 {
449 // File names are stored using unix separators.
450 wxString tmp = aFieldText;
451 tmp.Replace( wxT( "\\" ), wxT( "/" ) );
453 break;
454 }
455
457 field->SetText( aFieldText );
458 break;
459
460 default:
461 if( aFieldText != field->GetText( aPath ) ) // Do not set the variant unless it's different than the default.
462 {
463 if( aVariantName.IsEmpty() )
464 {
465 field->SetText( aFieldText );
466 }
467 else
468 {
469 SCH_SHEET_INSTANCE* instance = getInstance( *aPath );
470
471 wxCHECK( instance, /* void */ );
472
473 if( instance->m_Variants.contains( aVariantName ) )
474 {
475 instance->m_Variants[aVariantName].m_Fields[aFieldName] = aFieldText;
476 }
477 else
478 {
479 SCH_SHEET_VARIANT newVariant( aVariantName );
480
481 newVariant.InitializeAttributes( *this );
482 newVariant.m_Fields[aFieldName] = aFieldText;
483 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
484 }
485 }
486 }
487
488 break;
489 }
490}
491
492
493wxString SCH_SHEET::GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath,
494 const wxString& aVariantName ) const
495{
496 wxCHECK( !aFieldName.IsEmpty(), wxEmptyString );
497
498 const SCH_FIELD* field = GetField( aFieldName );
499
500 wxCHECK( field, wxEmptyString );
501
502 switch( field->GetId() )
503 {
506 return field->GetText();
507 break;
508
509 default:
510 if( aVariantName.IsEmpty() )
511 {
512 return field->GetText();
513 }
514 else
515 {
516 const SCH_SHEET_INSTANCE* instance = getInstance( *aPath );
517
518 if( instance->m_Variants.contains( aVariantName )
519 && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) )
520 return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName );
521 }
522
523 break;
524 }
525
526 return field->GetText();
527}
528
529
531{
532 wxASSERT( aSheetPin != nullptr );
533 wxASSERT( aSheetPin->Type() == SCH_SHEET_PIN_T );
534
535 aSheetPin->SetParent( this );
536 m_pins.push_back( aSheetPin );
537 renumberPins();
538}
539
540
541void SCH_SHEET::RemovePin( const SCH_SHEET_PIN* aSheetPin )
542{
543 wxASSERT( aSheetPin != nullptr );
544 wxASSERT( aSheetPin->Type() == SCH_SHEET_PIN_T );
545
546 for( auto i = m_pins.begin(); i < m_pins.end(); ++i )
547 {
548 if( *i == aSheetPin )
549 {
550 m_pins.erase( i );
551 renumberPins();
552 return;
553 }
554 }
555}
556
557
558bool SCH_SHEET::HasPin( const wxString& aName ) const
559{
560 for( SCH_SHEET_PIN* pin : m_pins )
561 {
562 if( pin->GetText().Cmp( aName ) == 0 )
563 return true;
564 }
565
566 return false;
567}
568
569
570bool SCH_SHEET::doIsConnected( const VECTOR2I& aPosition ) const
571{
572 for( SCH_SHEET_PIN* sheetPin : m_pins )
573 {
574 if( sheetPin->GetPosition() == aPosition )
575 return true;
576 }
577
578 return false;
579}
580
581
583{
584 int leftRight = 0;
585 int topBottom = 0;
586
587 for( SCH_SHEET_PIN* pin : m_pins )
588 {
589 switch( pin->GetSide() )
590 {
591 case SHEET_SIDE::LEFT: leftRight++; break;
592 case SHEET_SIDE::RIGHT: leftRight++; break;
593 case SHEET_SIDE::TOP: topBottom++; break;
594 case SHEET_SIDE::BOTTOM: topBottom++; break;
595 default: break;
596 }
597 }
598
599 return topBottom > 0 && leftRight == 0;
600}
601
602
604{
605 for( SCH_SHEET_PIN* pin : m_pins )
606 {
607 /* Search the schematic for a hierarchical label corresponding to this sheet label. */
608 const SCH_HIERLABEL* HLabel = nullptr;
609
610 for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_HIER_LABEL_T ) )
611 {
612 if( !pin->GetText().Cmp( static_cast<SCH_HIERLABEL*>( aItem )->GetText() ) )
613 {
614 HLabel = static_cast<SCH_HIERLABEL*>( aItem );
615 break;
616 }
617 }
618
619 if( HLabel == nullptr ) // Corresponding hierarchical label not found.
620 return true;
621 }
622
623 return false;
624}
625
626
627int bumpToNextGrid( const int aVal, const int aDirection )
628{
629 constexpr int gridSize = schIUScale.MilsToIU( 50 );
630
631 int base = aVal / gridSize;
632 int excess = abs( aVal % gridSize );
633
634 if( aDirection > 0 )
635 {
636 return ( base + 1 ) * gridSize;
637 }
638 else if( excess > 0 )
639 {
640 return ( base ) * gridSize;
641 }
642 else
643 {
644 return ( base - 1 ) * gridSize;
645 }
646}
647
648
649int SCH_SHEET::GetMinWidth( bool aFromLeft ) const
650{
651 int pinsLeft = m_pos.x + m_size.x;
652 int pinsRight = m_pos.x;
653
654 for( size_t i = 0; i < m_pins.size(); i++ )
655 {
656 SHEET_SIDE edge = m_pins[i]->GetSide();
657
658 if( edge == SHEET_SIDE::TOP || edge == SHEET_SIDE::BOTTOM )
659 {
660 BOX2I pinRect = m_pins[i]->GetBoundingBox();
661
662 pinsLeft = std::min( pinsLeft, pinRect.GetLeft() );
663 pinsRight = std::max( pinsRight, pinRect.GetRight() );
664 }
665 }
666
667 pinsLeft = bumpToNextGrid( pinsLeft, -1 );
668 pinsRight = bumpToNextGrid( pinsRight, 1 );
669
670 int pinMinWidth;
671
672 if( pinsLeft >= pinsRight )
673 pinMinWidth = 0;
674 else if( aFromLeft )
675 pinMinWidth = pinsRight - m_pos.x;
676 else
677 pinMinWidth = m_pos.x + m_size.x - pinsLeft;
678
679 return std::max( pinMinWidth, schIUScale.MilsToIU( MIN_SHEET_WIDTH ) );
680}
681
682
683int SCH_SHEET::GetMinHeight( bool aFromTop ) const
684{
685 int pinsTop = m_pos.y + m_size.y;
686 int pinsBottom = m_pos.y;
687
688 for( size_t i = 0; i < m_pins.size(); i++ )
689 {
690 SHEET_SIDE edge = m_pins[i]->GetSide();
691
692 if( edge == SHEET_SIDE::RIGHT || edge == SHEET_SIDE::LEFT )
693 {
694 BOX2I pinRect = m_pins[i]->GetBoundingBox();
695
696 pinsTop = std::min( pinsTop, pinRect.GetTop() );
697 pinsBottom = std::max( pinsBottom, pinRect.GetBottom() );
698 }
699 }
700
701 pinsTop = bumpToNextGrid( pinsTop, -1 );
702 pinsBottom = bumpToNextGrid( pinsBottom, 1 );
703
704 int pinMinHeight;
705
706 if( pinsTop >= pinsBottom )
707 pinMinHeight = 0;
708 else if( aFromTop )
709 pinMinHeight = pinsBottom - m_pos.y;
710 else
711 pinMinHeight = m_pos.y + m_size.y - pinsTop;
712
713 return std::max( pinMinHeight, schIUScale.MilsToIU( MIN_SHEET_HEIGHT ) );
714}
715
716
718{
719 std::vector<SCH_SHEET_PIN*> pins = m_pins;
720
721 m_pins.clear();
722
723 for( SCH_SHEET_PIN* pin : pins )
724 {
725 /* Search the schematic for a hierarchical label corresponding to this sheet label. */
726 const SCH_HIERLABEL* HLabel = nullptr;
727
728 for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_HIER_LABEL_T ) )
729 {
730 if( pin->GetText().CmpNoCase( static_cast<SCH_HIERLABEL*>( aItem )->GetText() ) == 0 )
731 {
732 HLabel = static_cast<SCH_HIERLABEL*>( aItem );
733 break;
734 }
735 }
736
737 if( HLabel )
738 m_pins.push_back( pin );
739 }
740}
741
742
744{
745 for( SCH_SHEET_PIN* pin : m_pins )
746 {
747 if( pin->HitTest( aPosition ) )
748 return pin;
749 }
750
751 return nullptr;
752}
753
754
756{
757 if( GetBorderWidth() > 0 )
758 return GetBorderWidth();
759
760 if( Schematic() )
762
763 return schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
764}
765
766
768{
769 SCH_FIELD* sheetNameField = GetField( FIELD_T::SHEET_NAME );
770 VECTOR2I textSize = sheetNameField->GetTextSize();
771 int borderMargin = KiROUND( GetPenWidth() / 2.0 ) + 4;
772 int margin = borderMargin + KiROUND( std::max( textSize.x, textSize.y ) * 0.5 );
773
775 {
776 sheetNameField->SetTextPos( m_pos + VECTOR2I( -margin, m_size.y ) );
777 sheetNameField->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
778 sheetNameField->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
779 sheetNameField->SetTextAngle( ANGLE_VERTICAL );
780 }
781 else
782 {
783 sheetNameField->SetTextPos( m_pos + VECTOR2I( 0, -margin ) );
784 sheetNameField->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
785 sheetNameField->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
786 sheetNameField->SetTextAngle( ANGLE_HORIZONTAL );
787 }
788
789 SCH_FIELD* sheetFilenameField = GetField( FIELD_T::SHEET_FILENAME );
790
791 textSize = sheetFilenameField->GetTextSize();
792 margin = borderMargin + KiROUND( std::max( textSize.x, textSize.y ) * 0.4 );
793
795 {
796 sheetFilenameField->SetTextPos( m_pos + VECTOR2I( m_size.x + margin, m_size.y ) );
797 sheetFilenameField->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
798 sheetFilenameField->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
799 sheetFilenameField->SetTextAngle( ANGLE_VERTICAL );
800 }
801 else
802 {
803 sheetFilenameField->SetTextPos( m_pos + VECTOR2I( 0, m_size.y + margin ) );
804 sheetFilenameField->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
805 sheetFilenameField->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
806 sheetFilenameField->SetTextAngle( ANGLE_HORIZONTAL );
807 }
808
809 if( aAlgo == AUTOPLACE_AUTO || aAlgo == AUTOPLACE_MANUAL )
810 m_fieldsAutoplaced = aAlgo;
811}
812
813
814std::vector<int> SCH_SHEET::ViewGetLayers() const
815{
816 // Sheet pins are drawn by their parent sheet, so the parent needs to draw to LAYER_DANGLING
819}
820
821
823{
825 BOX2I box( m_pos, m_size );
826 int lineWidth = GetPenWidth();
827 int textLength = 0;
828
829 // Calculate bounding box X size:
830 end.x = std::max( m_size.x, textLength );
831
832 // Calculate bounding box pos:
833 end.y = m_size.y;
834 end += m_pos;
835
836 box.SetEnd( end );
837 box.Inflate( lineWidth / 2 );
838
839 return box;
840}
841
842
844{
845 BOX2I bbox = GetBodyBoundingBox();
846
847 for( const SCH_FIELD& field : m_fields )
848 bbox.Merge( field.GetBoundingBox() );
849
850 return bbox;
851}
852
853
855{
856 BOX2I box( m_pos, m_size );
857 return box.GetCenter();
858}
859
860
862{
863 int n = 0;
864
865 if( m_screen )
866 {
867 for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_SYMBOL_T ) )
868 {
869 SCH_SYMBOL* symbol = (SCH_SYMBOL*) aItem;
870
871 if( !symbol->IsPower() )
872 n++;
873 }
874
875 for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_SHEET_T ) )
876 n += static_cast<const SCH_SHEET*>( aItem )->SymbolCount();
877 }
878
879 return n;
880}
881
882
883bool SCH_SHEET::SearchHierarchy( const wxString& aFilename, SCH_SCREEN** aScreen )
884{
885 if( m_screen )
886 {
887 // Only check the root sheet once and don't recurse.
888 if( !GetParent() )
889 {
890 if( m_screen && m_screen->GetFileName().Cmp( aFilename ) == 0 )
891 {
892 *aScreen = m_screen;
893 return true;
894 }
895 }
896
897 for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_SHEET_T ) )
898 {
899 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
900 SCH_SCREEN* screen = sheet->m_screen;
901
902 // Must use the screen's path (which is always absolute) rather than the
903 // sheet's (which could be relative).
904 if( screen && screen->GetFileName().Cmp( aFilename ) == 0 )
905 {
906 *aScreen = screen;
907 return true;
908 }
909
910 if( sheet->SearchHierarchy( aFilename, aScreen ) )
911 return true;
912 }
913 }
914
915 return false;
916}
917
918
920{
921 if( m_screen )
922 {
923 aList->push_back( this );
924
925 if( m_screen == aScreen )
926 return true;
927
928 for( EDA_ITEM* item : m_screen->Items().OfType( SCH_SHEET_T ) )
929 {
930 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
931
932 if( sheet->LocatePathOfScreen( aScreen, aList ) )
933 return true;
934 }
935
936 aList->pop_back();
937 }
938
939 return false;
940}
941
942
943int SCH_SHEET::CountSheets( const wxString& aFilename ) const
944{
945 int count = 0;
946
947 if( m_screen )
948 {
949 if( m_screen->GetFileName().Cmp( aFilename ) == 0 )
950 count++;
951
952 for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_SHEET_T ) )
953 count += static_cast<SCH_SHEET*>( aItem )->CountSheets( aFilename );
954 }
955
956 return count;
957}
958
959
961{
962 int count = 1; //1 = this!!
963
964 if( m_screen )
965 {
966 for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_SHEET_T ) )
967 count += static_cast<SCH_SHEET*>( aItem )->CountSheets();
968 }
969
970 return count;
971}
972
973
975{
976 int count = CountSheets();
977
978 if( IsVirtualRootSheet() )
979 count--;
980
981 return count;
982}
983
984
985void SCH_SHEET::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
986{
987 // Don't use GetShownText(); we want to see the variable references here
988 aList.emplace_back( _( "Sheet Name" ), KIUI::EllipsizeStatusText( aFrame, GetName() ) );
989
990 if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame ) )
991 {
992 SCH_SHEET_PATH path = schframe->GetCurrentSheet();
993 path.push_back( this );
994
995 aList.emplace_back( _( "Hierarchical Path" ), path.PathHumanReadable( false, true ) );
996 }
997
998 // Don't use GetShownText(); we want to see the variable references here
999 aList.emplace_back( _( "File Name" ), KIUI::EllipsizeStatusText( aFrame, GetFileName() ) );
1000
1001 wxArrayString msgs;
1002 wxString msg;
1003
1004 if( GetExcludedFromSim() )
1005 msgs.Add( _( "Simulation" ) );
1006
1007 if( GetExcludedFromBOM() )
1008 msgs.Add( _( "BOM" ) );
1009
1010 if( GetExcludedFromBoard() )
1011 msgs.Add( _( "Board" ) );
1012
1013 if( GetDNP() )
1014 msgs.Add( _( "DNP" ) );
1015
1016 msg = wxJoin( msgs, '|' );
1017 msg.Replace( '|', wxS( ", " ) );
1018
1019 if( !msg.empty() )
1020 aList.emplace_back( _( "Exclude from" ), msg );
1021}
1022
1023
1024std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> SCH_SHEET::GetNoConnects() const
1025{
1026 std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> noConnects;
1027
1028 if( SCH_SCREEN* screen = dynamic_cast<SCH_SCREEN*>( GetParent() ) )
1029 {
1030 for( SCH_SHEET_PIN* sheetPin : m_pins )
1031 {
1032 for( SCH_ITEM* noConnect : screen->Items().Overlapping( SCH_NO_CONNECT_T, sheetPin->GetTextPos() ) )
1033 noConnects[sheetPin] = static_cast<SCH_NO_CONNECT*>( noConnect );
1034 }
1035 }
1036
1037 return noConnects;
1038}
1039
1040
1042{
1043 VECTOR2I delta = aPosition - m_pos;
1044
1045 m_pos = aPosition;
1046
1047 for( SCH_FIELD& field : m_fields )
1048 field.Move( delta );
1049}
1050
1051
1052void SCH_SHEET::Move( const VECTOR2I& aMoveVector )
1053{
1054 m_pos += aMoveVector;
1055
1056 for( SCH_SHEET_PIN* pin : m_pins )
1057 pin->Move( aMoveVector );
1058
1059 for( SCH_FIELD& field : m_fields )
1060 field.Move( aMoveVector );
1061}
1062
1063
1064void SCH_SHEET::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
1065{
1066 VECTOR2I prev = m_pos;
1067
1068 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
1069 RotatePoint( &m_size.x, &m_size.y, aRotateCCW ? ANGLE_90 : ANGLE_270 );
1070
1071 if( m_size.x < 0 )
1072 {
1073 m_pos.x += m_size.x;
1074 m_size.x = -m_size.x;
1075 }
1076
1077 if( m_size.y < 0 )
1078 {
1079 m_pos.y += m_size.y;
1080 m_size.y = -m_size.y;
1081 }
1082
1083 // Pins must be rotated first as that's how we determine vertical vs horizontal
1084 // orientation for auto-placement
1085 for( SCH_SHEET_PIN* sheetPin : m_pins )
1086 sheetPin->Rotate( aCenter, aRotateCCW );
1087
1089 {
1091 }
1092 else
1093 {
1094 // Move the fields to the new position because the parent itself has moved.
1095 for( SCH_FIELD& field : m_fields )
1096 {
1097 VECTOR2I pos = field.GetTextPos();
1098 pos.x -= prev.x - m_pos.x;
1099 pos.y -= prev.y - m_pos.y;
1100 field.SetTextPos( pos );
1101 }
1102 }
1103}
1104
1105
1107{
1108 int dy = m_pos.y;
1109
1110 MIRROR( m_pos.y, aCenter );
1111 m_pos.y -= m_size.y;
1112 dy -= m_pos.y; // 0,dy is the move vector for this transform
1113
1114 for( SCH_SHEET_PIN* sheetPin : m_pins )
1115 sheetPin->MirrorVertically( aCenter );
1116
1117 for( SCH_FIELD& field : m_fields )
1118 {
1119 VECTOR2I pos = field.GetTextPos();
1120 pos.y -= dy;
1121 field.SetTextPos( pos );
1122 }
1123}
1124
1125
1127{
1128 int dx = m_pos.x;
1129
1130 MIRROR( m_pos.x, aCenter );
1131 m_pos.x -= m_size.x;
1132 dx -= m_pos.x; // dx,0 is the move vector for this transform
1133
1134 for( SCH_SHEET_PIN* sheetPin : m_pins )
1135 sheetPin->MirrorHorizontally( aCenter );
1136
1137 for( SCH_FIELD& field : m_fields )
1138 {
1139 VECTOR2I pos = field.GetTextPos();
1140 pos.x -= dx;
1141 field.SetTextPos( pos );
1142 }
1143}
1144
1145
1146void SCH_SHEET::SetPosition( const VECTOR2I& aPosition )
1147{
1148 // Remember the sheet and all pin sheet positions must be
1149 // modified. So use Move function to do that.
1150 Move( aPosition - m_pos );
1151}
1152
1153
1154void SCH_SHEET::Resize( const VECTOR2I& aSize )
1155{
1156 if( aSize == m_size )
1157 return;
1158
1159 m_size = aSize;
1160
1161 // Move the fields if we're in autoplace mode
1164
1165 // Move the sheet labels according to the new sheet size.
1166 for( SCH_SHEET_PIN* sheetPin : m_pins )
1167 sheetPin->ConstrainOnEdge( sheetPin->GetPosition(), false );
1168}
1169
1170
1171bool SCH_SHEET::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
1172{
1173 // Sheets are searchable via the child field and pin item text.
1174 return false;
1175}
1176
1177
1179{
1180 int id = 2;
1181
1182 for( SCH_SHEET_PIN* pin : m_pins )
1183 {
1184 pin->SetNumber( id );
1185 id++;
1186 }
1187}
1188
1189
1191{
1192 wxCHECK_MSG( Schematic(), SCH_SHEET_PATH(), "Can't call findSelf without a schematic" );
1193
1194 SCH_SHEET_PATH sheetPath = Schematic()->CurrentSheet();
1195
1196 while( !sheetPath.empty() && sheetPath.Last() != this )
1197 sheetPath.pop_back();
1198
1199 if( sheetPath.empty() )
1200 {
1201 // If we weren't in the hierarchy, then we must be a child of the current sheet.
1202 sheetPath = Schematic()->CurrentSheet();
1203 sheetPath.push_back( const_cast<SCH_SHEET*>( this ) );
1204 }
1205
1206 return sheetPath;
1207}
1208
1209
1210void SCH_SHEET::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
1211{
1212 for( SCH_SHEET_PIN* sheetPin : m_pins )
1213 {
1214 wxCHECK2_MSG( sheetPin->Type() == SCH_SHEET_PIN_T, continue,
1215 wxT( "Invalid item in schematic sheet pin list. Bad programmer!" ) );
1216
1217 sheetPin->GetEndPoints( aItemList );
1218 }
1219}
1220
1221
1222bool SCH_SHEET::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
1223 std::vector<DANGLING_END_ITEM>& aItemListByPos,
1224 const SCH_SHEET_PATH* aPath )
1225{
1226 bool changed = false;
1227
1228 for( SCH_SHEET_PIN* sheetPin : m_pins )
1229 changed |= sheetPin->UpdateDanglingState( aItemListByType, aItemListByPos );
1230
1231 return changed;
1232}
1233
1234
1236 const SCH_SHEET_PATH* aInstance ) const
1237{
1238 // Do not compare to ourself.
1239 if( aItem == this )
1240 return false;
1241
1242 const SCH_SHEET* sheet = dynamic_cast<const SCH_SHEET*>( aItem );
1243
1244 // Don't compare against a different SCH_ITEM.
1245 wxCHECK( sheet, false );
1246
1247 if( GetPosition() != sheet->GetPosition() )
1248 return true;
1249
1250 // Technically this cannot happen because undo/redo does not support reloading sheet
1251 // file association changes. This was just added so that it doesn't get missed should
1252 // we ever fix the undo/redo issue.
1253 if( ( GetFileName() != sheet->GetFileName() ) || ( GetName() != sheet->GetName() ) )
1254 return true;
1255
1256 if( m_pins.size() != sheet->m_pins.size() )
1257 return true;
1258
1259 for( size_t i = 0; i < m_pins.size(); i++ )
1260 {
1261 if( m_pins[i]->HasConnectivityChanges( sheet->m_pins[i] ) )
1262 return true;
1263 }
1264
1265 return false;
1266}
1267
1268
1269std::vector<VECTOR2I> SCH_SHEET::GetConnectionPoints() const
1270{
1271 std::vector<VECTOR2I> retval;
1272
1273 for( SCH_SHEET_PIN* sheetPin : m_pins )
1274 retval.push_back( sheetPin->GetPosition() );
1275
1276 return retval;
1277}
1278
1279
1280INSPECT_RESULT SCH_SHEET::Visit( INSPECTOR aInspector, void* testData,
1281 const std::vector<KICAD_T>& aScanTypes )
1282{
1283 for( KICAD_T scanType : aScanTypes )
1284 {
1285 // If caller wants to inspect my type
1286 if( scanType == SCH_LOCATE_ANY_T || scanType == Type() )
1287 {
1288 if( INSPECT_RESULT::QUIT == aInspector( this, nullptr ) )
1289 return INSPECT_RESULT::QUIT;
1290 }
1291
1292 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
1293 {
1294 // Test the sheet fields.
1295 for( SCH_FIELD& field : m_fields )
1296 {
1297 if( INSPECT_RESULT::QUIT == aInspector( &field, this ) )
1298 return INSPECT_RESULT::QUIT;
1299 }
1300 }
1301
1302 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_SHEET_PIN_T )
1303 {
1304 // Test the sheet labels.
1305 for( SCH_SHEET_PIN* sheetPin : m_pins )
1306 {
1307 if( INSPECT_RESULT::QUIT == aInspector( sheetPin, this ) )
1308 return INSPECT_RESULT::QUIT;
1309 }
1310 }
1311 }
1312
1314}
1315
1316
1317void SCH_SHEET::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
1318{
1319 for( SCH_FIELD& field : m_fields )
1320 aFunction( &field );
1321
1322 for( SCH_SHEET_PIN* pin : m_pins )
1323 aFunction( pin );
1324}
1325
1326
1327wxString SCH_SHEET::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1328{
1329 const SCH_FIELD* sheetnameField = GetField( FIELD_T::SHEET_NAME );
1330
1331 return wxString::Format( _( "Hierarchical Sheet '%s'" ),
1332 aFull ? sheetnameField->GetShownText( false )
1333 : KIUI::EllipsizeMenuText( sheetnameField->GetText() ) );
1334}
1335
1336
1341
1342
1343bool SCH_SHEET::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
1344{
1345 BOX2I rect = GetBodyBoundingBox();
1346
1347 rect.Inflate( aAccuracy );
1348
1349 return rect.Contains( aPosition );
1350}
1351
1352
1353bool SCH_SHEET::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
1354{
1355 BOX2I rect = aRect;
1356
1357 rect.Inflate( aAccuracy );
1358
1359 if( aContained )
1360 return rect.Contains( GetBodyBoundingBox() );
1361
1362 return rect.Intersects( GetBodyBoundingBox() );
1363}
1364
1365
1366bool SCH_SHEET::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
1367{
1368 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
1369}
1370
1371
1372void SCH_SHEET::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
1373 int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
1374{
1375 if( aBackground && !aPlotter->GetColorMode() )
1376 return;
1377
1378 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
1379 COLOR4D borderColor = GetBorderColor();
1380 COLOR4D backgroundColor = GetBackgroundColor();
1381
1382 if( renderSettings->m_OverrideItemColors || borderColor == COLOR4D::UNSPECIFIED )
1383 borderColor = aPlotter->RenderSettings()->GetLayerColor( LAYER_SHEET );
1384
1385 if( renderSettings->m_OverrideItemColors || backgroundColor == COLOR4D::UNSPECIFIED )
1386 backgroundColor = aPlotter->RenderSettings()->GetLayerColor( LAYER_SHEET_BACKGROUND );
1387
1388 if( borderColor.m_text.has_value() && Schematic() )
1389 borderColor = COLOR4D( ResolveText( borderColor.m_text.value(), &Schematic()->CurrentSheet() ) );
1390
1391 if( backgroundColor.m_text.has_value() && Schematic() )
1392 backgroundColor = COLOR4D( ResolveText( backgroundColor.m_text.value(), &Schematic()->CurrentSheet() ) );
1393
1394 if( aBackground && backgroundColor.a > 0.0 )
1395 {
1396 aPlotter->SetColor( backgroundColor );
1397 aPlotter->Rect( m_pos, m_pos + m_size, FILL_T::FILLED_SHAPE, 1, 0 );
1398 }
1399 else
1400 {
1401 aPlotter->SetColor( borderColor );
1402
1403 int penWidth = GetEffectivePenWidth( getRenderSettings( aPlotter ) );
1404 aPlotter->Rect( m_pos, m_pos + m_size, FILL_T::NO_FILL, penWidth, 0 );
1405 }
1406
1407 // Make the sheet object a clickable hyperlink (e.g. for PDF plotter)
1408 if( aPlotOpts.m_PDFHierarchicalLinks )
1409 {
1410 aPlotter->HyperlinkBox( GetBoundingBox(),
1411 EDA_TEXT::GotoPageHref( findSelf().GetPageNumber() ) );
1412 }
1413 else if( aPlotOpts.m_PDFPropertyPopups )
1414 {
1415 std::vector<wxString> properties;
1416
1417 properties.emplace_back( EDA_TEXT::GotoPageHref( findSelf().GetPageNumber() ) );
1418
1419 for( const SCH_FIELD& field : GetFields() )
1420 {
1421 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(),
1422 field.GetShownText( false ) ) );
1423 }
1424
1425 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
1426 }
1427
1428 // Plot sheet pins
1429 for( SCH_SHEET_PIN* sheetPin : m_pins )
1430 sheetPin->Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
1431
1432 // Plot the fields
1433 for( SCH_FIELD& field : m_fields )
1434 field.Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
1435
1436 SCH_SHEET_PATH instance;
1437 wxString variantName;
1438
1439 if( Schematic() )
1440 {
1441 instance = Schematic()->CurrentSheet();
1442 variantName = Schematic()->GetCurrentVariant();
1443 }
1444
1445 if( GetDNP( &instance, variantName) )
1446 {
1448 BOX2I bbox = GetBodyBoundingBox();
1449 BOX2I pins = GetBoundingBox();
1450 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(),
1451 pins.GetEnd().x - bbox.GetEnd().x ),
1452 std::max( bbox.GetY() - pins.GetY(),
1453 pins.GetEnd().y - bbox.GetEnd().y ) );
1454 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
1455
1456 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
1457 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
1458 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
1459
1460 aPlotter->SetColor( colors->GetColor( LAYER_DNP_MARKER ) );
1461
1462 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
1463
1464 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
1465 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ),
1466 strokeWidth, nullptr );
1467 }
1468}
1469
1470
1472{
1473 wxCHECK_MSG( Type() == aItem.Type(), *this,
1474 wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) +
1475 GetClass() );
1476
1477 if( &aItem != this )
1478 {
1479 SCH_ITEM::operator=( aItem );
1480
1481 SCH_SHEET* sheet = (SCH_SHEET*) &aItem;
1482
1483 m_pos = sheet->m_pos;
1484 m_size = sheet->m_size;
1485 m_fields = sheet->m_fields;
1486
1487 for( SCH_SHEET_PIN* pin : sheet->m_pins )
1488 {
1489 m_pins.emplace_back( new SCH_SHEET_PIN( *pin ) );
1490 m_pins.back()->SetParent( this );
1491 }
1492
1493 for( const SCH_SHEET_INSTANCE& instance : sheet->m_instances )
1494 m_instances.emplace_back( instance );
1495 }
1496
1497 return *this;
1498}
1499
1500
1501bool SCH_SHEET::operator <( const SCH_ITEM& aItem ) const
1502{
1503 if( Type() != aItem.Type() )
1504 return Type() < aItem.Type();
1505
1506 const SCH_SHEET* otherSheet = static_cast<const SCH_SHEET*>( &aItem );
1507
1508 if( GetName() != otherSheet->GetName() )
1509 return GetName() < otherSheet->GetName();
1510
1511 if( GetFileName() != otherSheet->GetFileName() )
1512 return GetFileName() < otherSheet->GetFileName();
1513
1514 return false;
1515}
1516
1517
1518void SCH_SHEET::RemoveInstance( const KIID_PATH& aInstancePath )
1519{
1520 // Search for an existing path and remove it if found (should not occur)
1521 // (search from back to avoid invalidating iterator on remove)
1522 for( int ii = m_instances.size() - 1; ii >= 0; --ii )
1523 {
1524 if( m_instances[ii].m_Path == aInstancePath )
1525 {
1526 wxLogTrace( traceSchSheetPaths, "Removing sheet instance:\n"
1527 " sheet path %s\n"
1528 " page %s, from project %s.",
1529 aInstancePath.AsString(),
1530 m_instances[ii].m_PageNumber,
1531 m_instances[ii].m_ProjectName );
1532
1533 m_instances.erase( m_instances.begin() + ii );
1534 }
1535 }
1536}
1537
1538
1540{
1541 SCH_SHEET_INSTANCE oldInstance;
1542
1543 if( getInstance( oldInstance, aInstance.m_Path ) )
1544 RemoveInstance( aInstance.m_Path );
1545
1546 m_instances.emplace_back( aInstance );
1547
1548}
1549
1550
1552{
1553 for( const SCH_SHEET_INSTANCE& instance : m_instances )
1554 {
1555 // if aSheetPath is found, nothing to do:
1556 if( instance.m_Path == aPath )
1557 return false;
1558 }
1559
1560 wxLogTrace( traceSchSheetPaths, wxT( "Adding instance `%s` to sheet `%s`." ),
1561 aPath.AsString(),
1562 ( GetName().IsEmpty() ) ? wxString( wxT( "root" ) ) : GetName() );
1563
1564 SCH_SHEET_INSTANCE instance;
1565
1566 instance.m_Path = aPath;
1567
1568 // This entry does not exist: add it with an empty page number.
1569 m_instances.emplace_back( instance );
1570 return true;
1571}
1572
1573
1574bool SCH_SHEET::getInstance( SCH_SHEET_INSTANCE& aInstance, const KIID_PATH& aSheetPath,
1575 bool aTestFromEnd ) const
1576{
1577 for( const SCH_SHEET_INSTANCE& instance : m_instances )
1578 {
1579 if( !aTestFromEnd )
1580 {
1581 if( instance.m_Path == aSheetPath )
1582 {
1583 aInstance = instance;
1584 return true;
1585 }
1586 }
1587 else if( instance.m_Path.EndsWith( aSheetPath ) )
1588 {
1589 aInstance = instance;
1590 return true;
1591 }
1592 }
1593
1594 return false;
1595}
1596
1597
1599{
1600 for( SCH_SHEET_INSTANCE& instance : m_instances )
1601 {
1602 if( instance.m_Path == aSheetPath )
1603 return &instance;
1604 }
1605
1606 return nullptr;
1607}
1608
1609
1610const SCH_SHEET_INSTANCE* SCH_SHEET::getInstance( const KIID_PATH& aSheetPath ) const
1611{
1612 for( const SCH_SHEET_INSTANCE& instance : m_instances )
1613 {
1614 if( instance.m_Path == aSheetPath )
1615 return &instance;
1616 }
1617
1618 return nullptr;
1619}
1620
1621
1623{
1624 for( const SCH_SHEET_INSTANCE& instance : m_instances )
1625 {
1626 if( instance.m_Path.size() == 0 )
1627 return true;
1628 }
1629
1630 return false;
1631}
1632
1633
1635{
1636 for( const SCH_SHEET_INSTANCE& instance : m_instances )
1637 {
1638 if( instance.m_Path.size() == 0 )
1639 return instance;
1640 }
1641
1642 wxFAIL;
1643
1645
1646 return dummy;
1647}
1648
1649
1650wxString SCH_SHEET::getPageNumber( const KIID_PATH& aParentPath ) const
1651{
1652 wxString pageNumber;
1653
1654 for( const SCH_SHEET_INSTANCE& instance : m_instances )
1655 {
1656 if( instance.m_Path == aParentPath )
1657 {
1658 pageNumber = instance.m_PageNumber;
1659 break;
1660 }
1661 }
1662
1663 return pageNumber;
1664}
1665
1666
1667void SCH_SHEET::setPageNumber( const KIID_PATH& aPath, const wxString& aPageNumber )
1668{
1669 for( SCH_SHEET_INSTANCE& instance : m_instances )
1670 {
1671 if( instance.m_Path == aPath )
1672 {
1673 instance.m_PageNumber = aPageNumber;
1674 break;
1675 }
1676 }
1677}
1678
1679
1681{
1682 // Avoid self comparison.
1683 if( &aOther == this )
1684 return false;
1685
1686 // A difference in the instance data count implies a page numbering change.
1687 if( GetInstances().size() != aOther.GetInstances().size() )
1688 return true;
1689
1690 std::vector<SCH_SHEET_INSTANCE> instances = GetInstances();
1691 std::vector<SCH_SHEET_INSTANCE> otherInstances = aOther.GetInstances();
1692
1693 // Sorting may not be necessary but there is no guarantee that sheet
1694 // instance data will be in the correct KIID_PATH order. We should
1695 // probably use a std::map instead of a std::vector to store the sheet
1696 // instance data.
1697 std::sort( instances.begin(), instances.end(),
1698 []( const SCH_SHEET_INSTANCE& aLhs, const SCH_SHEET_INSTANCE& aRhs )
1699 {
1700 if( aLhs.m_Path > aRhs.m_Path )
1701 return true;
1702
1703 return false;
1704 } );
1705 std::sort( otherInstances.begin(), otherInstances.end(),
1706 []( const SCH_SHEET_INSTANCE& aLhs, const SCH_SHEET_INSTANCE& aRhs )
1707 {
1708 if( aLhs.m_Path > aRhs.m_Path )
1709 return true;
1710
1711 return false;
1712 } );
1713
1714 auto itThis = instances.begin();
1715 auto itOther = otherInstances.begin();
1716
1717 while( itThis != instances.end() )
1718 {
1719 if( ( itThis->m_Path == itOther->m_Path )
1720 && ( itThis->m_PageNumber != itOther->m_PageNumber ) )
1721 {
1722 return true;
1723 }
1724
1725 itThis++;
1726 itOther++;
1727 }
1728
1729 return false;
1730}
1731
1732
1733int SCH_SHEET::ComparePageNum( const wxString& aPageNumberA, const wxString& aPageNumberB )
1734{
1735 if( aPageNumberA == aPageNumberB )
1736 return 0; // A == B
1737
1738 // First sort numerically if the page numbers are integers
1739 long pageA, pageB;
1740 bool isIntegerPageA = aPageNumberA.ToLong( &pageA );
1741 bool isIntegerPageB = aPageNumberB.ToLong( &pageB );
1742
1743 if( isIntegerPageA && isIntegerPageB )
1744 {
1745 if( pageA < pageB )
1746 return -1; //A < B
1747 else
1748 return 1; // A > B
1749 }
1750
1751 // Numerical page numbers always before strings
1752 if( isIntegerPageA )
1753 return -1; //A < B
1754 else if( isIntegerPageB )
1755 return 1; // A > B
1756
1757 // If not numeric, then sort as strings using natural sort
1758 int result = StrNumCmp( aPageNumberA, aPageNumberB );
1759
1760 // Divide by zero bad.
1761 wxCHECK( result != 0, 0 );
1762
1764
1765 return result;
1766}
1767
1768
1769bool SCH_SHEET::operator==( const SCH_ITEM& aOther ) const
1770{
1771 if( Type() != aOther.Type() )
1772 return false;
1773
1774 const SCH_SHEET* other = static_cast<const SCH_SHEET*>( &aOther );
1775
1776 if( m_pos != other->m_pos )
1777 return false;
1778
1779 if( m_size != other->m_size )
1780 return false;
1781
1782 if( GetExcludedFromSim() != other->GetExcludedFromSim() )
1783 return false;
1784
1785 if( GetExcludedFromBOM() != other->GetExcludedFromBOM() )
1786 return false;
1787
1788 if( GetExcludedFromBoard() != other->GetExcludedFromBoard() )
1789 return false;
1790
1791 if( GetDNP() != other->GetDNP() )
1792 return false;
1793
1794 if( GetBorderColor() != other->GetBorderColor() )
1795 return false;
1796
1797 if( GetBackgroundColor() != other->GetBackgroundColor() )
1798 return false;
1799
1800 if( GetBorderWidth() != other->GetBorderWidth() )
1801 return false;
1802
1803 if( GetFields().size() != other->GetFields().size() )
1804 return false;
1805
1806 for( size_t i = 0; i < GetFields().size(); ++i )
1807 {
1808 if( !( GetFields()[i] == other->GetFields()[i] ) )
1809 return false;
1810 }
1811
1812 return true;
1813}
1814
1815
1816double SCH_SHEET::Similarity( const SCH_ITEM& aOther ) const
1817{
1818 if( Type() != aOther.Type() )
1819 return 0.0;
1820
1821 const SCH_SHEET* other = static_cast<const SCH_SHEET*>( &aOther );
1822
1823 if( m_screen->GetFileName() == other->m_screen->GetFileName() )
1824 return 1.0;
1825
1826 return 0.0;
1827}
1828
1829
1830void SCH_SHEET::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SHEET_VARIANT& aVariant )
1831{
1832 SCH_SHEET_INSTANCE* instance = getInstance( aInstance );
1833
1834 // The instance path must already exist.
1835 if( !instance )
1836 return;
1837
1838 instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) );
1839}
1840
1841
1842void SCH_SHEET::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
1843{
1844 SCH_SHEET_INSTANCE* instance = getInstance( aPath );
1845
1846 // The instance path must already exist.
1847 if( !instance || !instance->m_Variants.contains( aVariantName ) )
1848 return;
1849
1850 instance->m_Variants.erase( aVariantName );
1851}
1852
1853
1854void SCH_SHEET::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
1855 const wxString& aNewName )
1856{
1857 SCH_SHEET_INSTANCE* instance = getInstance( aPath );
1858
1859 // The instance path must already exist and contain the old variant.
1860 if( !instance || !instance->m_Variants.contains( aOldName ) )
1861 return;
1862
1863 // Get the variant data, update the name, and re-insert with new key
1864 SCH_SHEET_VARIANT variant = instance->m_Variants[aOldName];
1865 variant.m_Name = aNewName;
1866 instance->m_Variants.erase( aOldName );
1867 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
1868}
1869
1870
1871void SCH_SHEET::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
1872 const wxString& aNewVariant )
1873{
1874 SCH_SHEET_INSTANCE* instance = getInstance( aPath );
1875
1876 // The instance path must already exist and contain the source variant.
1877 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
1878 return;
1879
1880 // Copy the variant data with a new name
1881 SCH_SHEET_VARIANT variant = instance->m_Variants[aSourceVariant];
1882 variant.m_Name = aNewVariant;
1883 instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) );
1884}
1885
1886
1887void SCH_SHEET::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1888{
1889 if( !aInstance || aVariantName.IsEmpty() )
1890 {
1891 m_DNP = aEnable;
1892 return;
1893 }
1894
1895 SCH_SHEET_INSTANCE* instance = getInstance( *aInstance );
1896
1897 wxCHECK_MSG( instance, /* void */,
1898 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1899 aInstance->PathHumanReadable() ) );
1900
1901 if( aVariantName.IsEmpty() )
1902 {
1903 m_DNP = aEnable;
1904 }
1905 else
1906 {
1907 if( instance->m_Variants.contains( aVariantName ) && ( aEnable != instance->m_Variants[aVariantName].m_DNP ) )
1908 {
1909 instance->m_Variants[aVariantName].m_DNP = aEnable;
1910 }
1911 else
1912 {
1913 SCH_SHEET_VARIANT variant( aVariantName );
1914
1915 variant.InitializeAttributes( *this );
1916 variant.m_DNP = aEnable;
1917 AddVariant( *aInstance, variant );
1918 }
1919 }
1920}
1921
1922
1923bool SCH_SHEET::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1924{
1925 if( !aInstance || aVariantName.IsEmpty() )
1926 return m_DNP;
1927
1928 SCH_SHEET_INSTANCE instance;
1929
1930 if( !getInstance( instance, aInstance->Path() ) )
1931 return m_DNP;
1932
1933 if( aVariantName.IsEmpty() )
1934 return m_DNP;
1935 else if( instance.m_Variants.contains( aVariantName ) )
1936 return instance.m_Variants[aVariantName].m_DNP;
1937
1938 // If the variant has not been defined, return the default DNP setting.
1939 return m_DNP;
1940}
1941
1942
1944{
1945 return GetDNP( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
1946}
1947
1948
1949void SCH_SHEET::SetDNPProp( bool aEnable )
1950{
1951 SetDNP( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
1952}
1953
1954
1955void SCH_SHEET::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1956{
1957 if( !aInstance || aVariantName.IsEmpty() )
1958 {
1959 m_excludedFromSim = aEnable;
1960 return;
1961 }
1962
1963 SCH_SHEET_INSTANCE* instance = getInstance( *aInstance );
1964
1965 wxCHECK_MSG( instance, /* void */,
1966 wxString::Format( wxS( "Cannot get m_excludedFromSim attribute for invalid sheet path '%s'." ),
1967 aInstance->PathHumanReadable() ) );
1968
1969 if( aVariantName.IsEmpty() )
1970 {
1971 m_excludedFromSim = aEnable;
1972 }
1973 else
1974 {
1975 if( instance->m_Variants.contains( aVariantName )
1976 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromSim ) )
1977 {
1978 instance->m_Variants[aVariantName].m_ExcludedFromSim = aEnable;
1979 }
1980 else
1981 {
1982 SCH_SHEET_VARIANT variant( aVariantName );
1983
1984 variant.InitializeAttributes( *this );
1985 variant.m_ExcludedFromSim = aEnable;
1986 AddVariant( *aInstance, variant );
1987 }
1988 }
1989}
1990
1991
1992bool SCH_SHEET::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1993{
1994 if( !aInstance || aVariantName.IsEmpty() )
1995 return m_excludedFromSim;
1996
1997 SCH_SHEET_INSTANCE instance;
1998
1999 if( !getInstance( instance, aInstance->Path() ) )
2000 return m_excludedFromSim;
2001
2002 if( aVariantName.IsEmpty() )
2003 return m_excludedFromSim;
2004 else if( instance.m_Variants.contains( aVariantName ) )
2005 return instance.m_Variants[aVariantName].m_ExcludedFromSim;
2006
2007 // If the variant has not been defined, return the default DNP setting.
2008 return m_excludedFromSim;
2009}
2010
2011
2013{
2014 return GetExcludedFromSim( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
2015}
2016
2017
2019{
2020 SetExcludedFromSim( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
2021}
2022
2023
2024void SCH_SHEET::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
2025{
2026 if( !aInstance || aVariantName.IsEmpty() )
2027 {
2028 m_excludedFromBOM = aEnable;
2029 return;
2030 }
2031
2032 SCH_SHEET_INSTANCE* instance = getInstance( *aInstance );
2033
2034 wxCHECK_MSG( instance, /* void */,
2035 wxString::Format( wxS( "Cannot get m_excludedFromBOM attribute for invalid sheet path '%s'." ),
2036 aInstance->PathHumanReadable() ) );
2037
2038 if( aVariantName.IsEmpty() )
2039 {
2040 m_excludedFromBOM = aEnable;
2041 }
2042 else
2043 {
2044 if( instance->m_Variants.contains( aVariantName )
2045 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromBOM ) )
2046 {
2047 instance->m_Variants[aVariantName].m_ExcludedFromBOM = aEnable;
2048 }
2049 else
2050 {
2051 SCH_SHEET_VARIANT variant( aVariantName );
2052
2053 variant.InitializeAttributes( *this );
2054 variant.m_ExcludedFromBOM = aEnable;
2055 AddVariant( *aInstance, variant );
2056 }
2057 }
2058}
2059
2060
2061bool SCH_SHEET::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
2062{
2063 if( !aInstance || aVariantName.IsEmpty() )
2064 return m_excludedFromBOM;
2065
2066 SCH_SHEET_INSTANCE instance;
2067
2068 if( !getInstance( instance, aInstance->Path() ) )
2069 return m_excludedFromBOM;
2070
2071 if( aVariantName.IsEmpty() )
2072 return m_excludedFromBOM;
2073 else if( instance.m_Variants.contains( aVariantName ) )
2074 return instance.m_Variants[aVariantName].m_ExcludedFromBOM;
2075
2076 // If the variant has not been defined, return the default DNP setting.
2077 return m_excludedFromBOM;
2078}
2079
2080
2082{
2083 return GetExcludedFromBOM( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
2084}
2085
2086
2088{
2089 SetExcludedFromBOM( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
2090}
2091
2092
2093#if defined(DEBUG)
2094
2095void SCH_SHEET::Show( int nestLevel, std::ostream& os ) const
2096{
2097 // XML output:
2098 wxString s = GetClass();
2099
2100 NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << ">" << " sheet_name=\""
2101 << TO_UTF8( GetName() ) << '"' << ">\n";
2102
2103 // show all the pins, and check the linked list integrity
2104 for( SCH_SHEET_PIN* sheetPin : m_pins )
2105 sheetPin->Show( nestLevel + 1, os );
2106
2107 NestedSpace( nestLevel, os ) << "</" << s.Lower().mb_str() << ">\n" << std::flush;
2108}
2109
2110#endif
2111
2112static struct SCH_SHEET_DESC
2113{
2115 {
2119
2120 propMgr.AddProperty( new PROPERTY<SCH_SHEET, wxString>( _HKI( "Sheet Name" ),
2122 .SetValidator( []( const wxAny&& aValue, EDA_ITEM* ) -> VALIDATOR_RESULT
2123 {
2124 wxString value;
2125
2126 if( !aValue.GetAs( &value ) )
2127 return {};
2128
2129 wxString msg = GetFieldValidationErrorMessage( FIELD_T::SHEET_NAME, value );
2130
2131 if( msg.empty() )
2132 return {};
2133
2134 return std::make_unique<VALIDATION_ERROR_MSG>( msg );
2135 } );
2136
2137 propMgr.AddProperty( new PROPERTY<SCH_SHEET, int>( _HKI( "Border Width" ),
2140
2141 propMgr.AddProperty( new PROPERTY<SCH_SHEET, COLOR4D>( _HKI( "Border Color" ),
2143
2144 propMgr.AddProperty( new PROPERTY<SCH_SHEET, COLOR4D>( _HKI( "Background Color" ),
2146
2147 const wxString groupAttributes = _HKI( "Attributes" );
2148
2149 propMgr.AddProperty( new PROPERTY<SCH_SHEET, bool>( _HKI( "Exclude From Board" ),
2151 groupAttributes );
2152 propMgr.AddProperty( new PROPERTY<SCH_SHEET, bool>( _HKI( "Exclude From Simulation" ),
2154 groupAttributes );
2155 propMgr.AddProperty(
2156 new PROPERTY<SCH_SHEET, bool>( _HKI( "Exclude From Bill of Materials" ),
2159 groupAttributes );
2160 propMgr.AddProperty( new PROPERTY<SCH_SHEET, bool>( _HKI( "Do not Populate" ),
2162 groupAttributes );
2163 }
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
BITMAPS
A list of all bitmap identifiers.
@ add_hierarchical_subsheet
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
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 const Vec GetEnd() const
Definition box2.h:212
constexpr coord_type GetY() const
Definition box2.h:208
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr coord_type GetX() const
Definition box2.h:207
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
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
constexpr coord_type GetTop() const
Definition box2.h:229
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
constexpr coord_type GetBottom() const
Definition box2.h:222
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
Color settings are a bit different than most of the settings objects in that there can be more than o...
COLOR4D GetColor(int aLayer) const
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:522
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
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
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:585
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:426
static wxString GotoPageHref(const wxString &aDestination)
Generate a href to a page in the current schematic.
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:308
VECTOR2I GetTextSize() const
Definition eda_text.h:261
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:418
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
std::optional< wxString > m_text
Definition color4d.h:399
double a
Alpha component.
Definition color4d.h:396
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
wxString AsString() const
Definition kiid.cpp:356
Definition kiid.h:49
Base plotter engine class.
Definition plotter.h:136
RENDER_SETTINGS * RenderSettings()
Definition plotter.h:167
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width, int aCornerRadius=0)=0
virtual void HyperlinkBox(const BOX2I &aBox, const wxString &aDestinationURL)
Create a clickable hyperlink with a rectangular click area.
Definition plotter.h:506
bool GetColorMode() const
Definition plotter.h:164
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:540
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition plotter.h:517
virtual void SetColor(const COLOR4D &color)=0
Container for project specific data.
Definition project.h:65
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:349
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.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
Holds all the data relating to one schematic.
Definition schematic.h:88
bool IsTopLevelSheet(const SCH_SHEET *aSheet) const
Check if a sheet is a top-level sheet (direct child of virtual root).
SCHEMATIC_SETTINGS & Settings() const
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:103
wxString GetCurrentVariant() const
Return the current variant being edited.
bool ResolveTextVar(const SCH_SHEET_PATH *aSheetPath, wxString *token, int aDepth) const
void GetContextualTextVars(wxArrayString *aVars) const
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:187
bool ResolveCrossReference(wxString *token, int aDepth) const
Resolves text vars that refer to other items.
Schematic editor (Eeschema) main window.
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:118
FIELD_T GetId() const
Definition sch_field.h:122
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) const
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
SCH_ITEM & operator=(const SCH_ITEM &aPin)
Definition sch_item.cpp:78
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.h:721
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:247
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:776
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:54
wxString ResolveText(const wxString &aText, const SCH_SHEET_PATH *aPath, int aDepth=0) const
Definition sch_item.cpp:356
wxString GetClass() const override
Return the class name.
Definition sch_item.h:177
int GetEffectivePenWidth(const SCH_RENDER_SETTINGS *aSettings) const
Definition sch_item.cpp:761
SCH_LAYER_ID m_layer
Definition sch_item.h:772
const wxString & GetFileName() const
Definition sch_screen.h:153
bool GetExcludedFromBOM() const
bool empty() const
Forwarded method from std::vector.
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
wxString GetPageNumber() const
bool GetExcludedFromSim() const
bool GetExcludedFromBoard() const
bool GetDNP() const
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
void pop_back()
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Variant information for a schematic sheet.
void InitializeAttributes(const SCH_SHEET &aSheet)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Add the schematic item end points to aItemList if the item has end points.
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this sheet.
friend SCH_SHEET_PATH
Definition sch_sheet.h:587
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition sch_sheet.h:154
friend class SCH_SHEET_PIN
Definition sch_sheet.h:659
VECTOR2I m_size
Definition sch_sheet.h:676
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:382
bool HasConnectivityChanges(const SCH_ITEM *aItem, const SCH_SHEET_PATH *aInstance=nullptr) const override
Check if aItem has connectivity changes against this object.
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:376
bool getInstance(SCH_SHEET_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void SetExcludedFromSim(bool aExcludeFromSim, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
void CopyVariant(const KIID_PATH &aPath, const wxString &aSourceVariant, const wxString &aNewVariant)
void RemoveInstance(const KIID_PATH &aInstancePath)
void SetDNP(bool aDNP, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
bool addInstance(const KIID_PATH &aInstance)
Add a new instance aSheetPath to the instance list.
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
bool HasRootInstance() const
Check to see if this sheet has a root sheet instance.
wxString GetClass() const override
Return the class name.
Definition sch_sheet.h:69
wxString getPageNumber(const KIID_PATH &aParentPath) const
Return the sheet page number for aParentPath.
void SetExcludedFromBOM(bool aExcludeFromBOM, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
int GetPenWidth() const override
std::map< SCH_SHEET_PIN *, SCH_NO_CONNECT * > GetNoConnects() const
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
bool IsTopLevelSheet() const
Check if this sheet is a top-level sheet.
SCH_SHEET_PATH findSelf() const
Get the sheetpath of this sheet.
bool GetDNPProp() const
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
bool GetExcludedFromBoardProp() const
Definition sch_sheet.h:473
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
bool GetExcludedFromBOMProp() const
VECTOR2I m_pos
Definition sch_sheet.h:675
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition sch_sheet.h:88
KIGFX::COLOR4D m_borderColor
Definition sch_sheet.h:678
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
bool m_excludedFromBOM
Definition sch_sheet.h:671
wxString GetName() const
Definition sch_sheet.h:142
void renumberPins()
Renumber the sheet pins in the sheet.
VECTOR2I GetRotationCenter() const
Rotating around the boundingBox's center can cause walking when the sheetname or filename is longer t...
SCH_SHEET_PIN * GetPin(const VECTOR2I &aPosition)
Return the sheet pin item found at aPosition in the sheet.
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool operator<(const SCH_ITEM &aItem) const override
void CleanupSheet()
Delete sheet label which do not have a corresponding hierarchical label.
void RemovePin(const SCH_SHEET_PIN *aSheetPin)
Remove aSheetPin from the sheet.
void SetPositionIgnoringPins(const VECTOR2I &aPosition)
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool LocatePathOfScreen(SCH_SCREEN *aScreen, SCH_SHEET_PATH *aList)
Search the existing hierarchy for an instance of screen loaded from aFileName.
std::vector< SCH_SHEET_INSTANCE > m_instances
Definition sch_sheet.h:681
bool HasUndefinedPins() const
Check all sheet labels against schematic for undefined hierarchical labels.
bool m_excludedFromSim
Definition sch_sheet.h:670
void SetPosition(const VECTOR2I &aPosition) override
wxString GetFieldText(const wxString &aFieldName, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString) const
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition sch_sheet.h:157
int SymbolCount() const
Count our own symbols, without the power symbols.
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.
void SetDNPProp(bool aEnable)
void AddInstance(const SCH_SHEET_INSTANCE &aInstance)
int GetMinWidth(bool aFromLeft) const
Return the minimum width of the sheet based on the widths of the sheet pin text.
bool operator==(const SCH_ITEM &aOther) const override
SCH_SCREEN * m_screen
Definition sch_sheet.h:663
std::vector< int > ViewGetLayers() const override
Return the layers the item is drawn on (which may be more than its "home" layer)
std::vector< SCH_FIELD > m_fields
Definition sch_sheet.h:668
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
KIGFX::COLOR4D m_backgroundColor
Definition sch_sheet.h:679
void DeleteVariant(const KIID_PATH &aPath, const wxString &aVariantName)
SCH_SHEET(EDA_ITEM *aParent=nullptr, const VECTOR2I &aPos=VECTOR2I(0, 0), VECTOR2I aSize=VECTOR2I(schIUScale.MilsToIU(MIN_SHEET_WIDTH), schIUScale.MilsToIU(MIN_SHEET_HEIGHT)))
Definition sch_sheet.cpp:55
void SetName(const wxString &aName)
Definition sch_sheet.h:143
int CountSheets() const
Count the number of sheets found in "this" sheet including all of the subsheets.
int GetNextFieldOrdinal() const
Return the next ordinal for a user field for this sheet.
void SetExcludedFromSimProp(bool aEnable)
VECTOR2I GetPosition() const override
Definition sch_sheet.h:496
const BOX2I GetBodyBoundingBox() const
Return a bounding box for the sheet body but not the fields.
bool HasPin(const wxString &aName) const
Check if the sheet already has a sheet pin named aName.
static int ComparePageNum(const wxString &aPageNumberA, const wxString &aPageNumberB)
Compare page numbers of schematic sheets.
void SetFieldText(const wxString &aFieldName, const wxString &aFieldText, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString)
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
void AddOptionalField(const SCH_FIELD &aField)
Add an optional @aField to the list of fields.
void SetFields(const std::vector< SCH_FIELD > &aFields)
Set multiple schematic fields.
int CountActiveSheets() const
Count the number of sheets found in "this" sheet including all of the subsheets.
int GetScreenCount() const
Return the number of times the associated screen for the sheet is being used.
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
SCH_SHEET & operator=(const SCH_ITEM &aSheet)
bool HasPageNumberChanges(const SCH_SHEET &aOther) const
Check if the instance data of this sheet has any changes compared to aOther.
const SCH_SHEET_INSTANCE & GetRootInstance() const
Return the root sheet instance data.
bool doIsConnected(const VECTOR2I &aPosition) const override
Provide the object specific test to see if it is connected to aPosition.
void swapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
bool m_excludedFromBoard
Definition sch_sheet.h:672
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
KIGFX::COLOR4D GetBorderColor() const
Definition sch_sheet.h:153
std::vector< SCH_SHEET_PIN * > m_pins
Definition sch_sheet.h:667
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, 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 SetBorderWidth(int aWidth)
Definition sch_sheet.h:151
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
void setPageNumber(const KIID_PATH &aInstance, const wxString &aPageNumber)
Set the page number for the sheet instance aInstance.
bool IsVirtualRootSheet() const
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
int GetMinHeight(bool aFromTop) const
Return the minimum height that the sheet can be resized based on the sheet pin positions.
bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flags.
bool GetExcludedFromSimProp() const
void SetExcludedFromBoardProp(bool aExclude)
Definition sch_sheet.h:474
int m_borderWidth
Definition sch_sheet.h:677
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos, const SCH_SHEET_PATH *aPath=nullptr) override
Test the schematic item to aItemList to check if it's dangling state has changed.
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition sch_sheet.h:467
void Resize(const VECTOR2I &aSize)
Resize this sheet to aSize and adjust all of the labels accordingly.
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
int GetBorderWidth() const
Definition sch_sheet.h:150
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.
bool m_DNP
Definition sch_sheet.h:673
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
void SetExcludedFromBOMProp(bool aEnable)
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
void AddVariant(const SCH_SHEET_PATH &aInstance, const SCH_SHEET_VARIANT &aVariant)
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the sheet.
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition sch_sheet.h:511
bool IsVerticalOrientation() const
bool HitTest(const VECTOR2I &aPosition, int aAccuracy) const override
Test if aPosition is inside or on the boundary of this item.
KIGFX::COLOR4D GetBackgroundColor() const
Definition sch_sheet.h:156
Schematic symbol object.
Definition sch_symbol.h:76
bool IsPower() const override
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
wxString m_Name
bool m_ExcludedFromBOM
std::map< wxString, wxString > m_Fields
bool m_ExcludedFromSim
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
RECURSE_MODE
Definition eda_item.h:50
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
@ NO_FILL
Definition eda_shape.h:57
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
a few functions useful in geometry calculations.
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
KIID niluuid(0)
@ LAYER_DANGLING
Definition layer_ids.h:477
@ LAYER_SHEETNAME
Definition layer_ids.h:472
@ LAYER_SHEET_BACKGROUND
Definition layer_ids.h:485
@ LAYER_HIERLABEL
Definition layer_ids.h:457
@ LAYER_SHEETFIELDS
Definition layer_ids.h:474
@ LAYER_SHEET
Definition layer_ids.h:471
@ LAYER_SELECTION_SHADOWS
Definition layer_ids.h:495
@ LAYER_SHEETFILENAME
Definition layer_ids.h:473
@ LAYER_DNP_MARKER
Definition layer_ids.h:478
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:45
Message panel definition file.
bool BoxHitTest(const VECTOR2I &aHitPoint, const BOX2I &aHittee, int aAccuracy)
Perform a point-to-box hit test.
KICOMMON_API wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
KICOMMON_API wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
#define _HKI(x)
Definition page_info.cpp:44
see class PGM_BASE
#define TYPE_HASH(x)
Definition property.h:74
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
const SCH_FIELD * FindField(const std::vector< SCH_FIELD > &aFields, FIELD_T aFieldId)
Definition sch_field.h:369
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:358
AUTOPLACE_ALGO
Definition sch_item.h:68
@ AUTOPLACE_MANUAL
Definition sch_item.h:71
@ AUTOPLACE_AUTO
Definition sch_item.h:70
int bumpToNextGrid(const int aVal, const int aDirection)
static struct SCH_SHEET_DESC _SCH_SHEET_DESC
#define MIN_SHEET_HEIGHT
Definition sch_sheet.h:41
#define MIN_SHEET_WIDTH
Definition sch_sheet.h:40
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
#define DEFAULT_THEME
COLOR_SETTINGS * GetColorSettings(const wxString &aName)
std::vector< FAB_LAYER_COLOR > dummy
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
bool m_PDFPropertyPopups
Definition sch_plotter.h:64
bool m_PDFHierarchicalLinks
Definition sch_plotter.h:65
A simple container for sheet instance information.
std::map< wxString, SCH_SHEET_VARIANT > m_Variants
A list of sheet variants.
wxString GetDefaultFieldName(FIELD_T aFieldId, bool aTranslateForHI)
Return a default symbol field name for a mandatory field type.
#define DO_TRANSLATE
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ REFERENCE
Field Reference of part, i.e. "IC21".
std::string path
KIBIS_PIN * pin
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
int delta
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_TOP
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ SCH_NO_CONNECT_T
Definition typeinfo.h:164
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_FIELD_T
Definition typeinfo.h:154
@ SCH_LOCATE_ANY_T
Definition typeinfo.h:203
@ SCH_SHEET_T
Definition typeinfo.h:179
@ SCH_HIER_LABEL_T
Definition typeinfo.h:173
@ SCH_SHEET_PIN_T
Definition typeinfo.h:178
wxString GetFieldValidationErrorMessage(FIELD_T aFieldId, const wxString &aValue)
Return the error message if aValue is invalid for aFieldId.
Custom text control validator definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694