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