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