kicad/eeschema/sch_symbol.cpp

2023 lines
56 KiB
C++
Raw Normal View History

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
2018-01-30 10:49:51 +00:00
#include <sch_edit_frame.h>
#include <widgets/msgpanel.h>
#include <bitmaps.h>
#include <core/mirror.h>
#include <lib_pin.h>
#include <lib_text.h>
#include <lib_shape.h>
#include <sch_symbol.h>
#include <sch_sheet_path.h>
#include <schematic.h>
#include <trace_helpers.h>
2020-10-14 03:37:48 +00:00
#include <trigo.h>
#include <refdes_utils.h>
2021-06-03 12:11:15 +00:00
#include <wx/log.h>
#include <string_utils.h>
/**
* Convert a wxString to UTF8 and replace any control characters with a ~,
* where a control character is one of the first ASCII values up to ' ' 32d.
*/
std::string toUTFTildaText( const wxString& txt )
{
std::string ret = TO_UTF8( txt );
for( std::string::iterator it = ret.begin(); it!=ret.end(); ++it )
{
if( (unsigned char) *it <= ' ' )
*it = '~';
}
return ret;
}
/**
2021-06-10 18:51:46 +00:00
* Used to draw a dummy shape when a LIB_SYMBOL is not found in library
2019-07-02 20:09:23 +00:00
*
2021-05-05 21:41:51 +00:00
* This symbol is a 400 mils square with the text "??"
* DEF DUMMY U 0 40 Y Y 1 0 N
* F0 "U" 0 -350 60 H V
* F1 "DUMMY" 0 350 60 H V
* DRAW
* T 0 0 0 150 0 0 0 ??
* S -200 200 200 -200 0 1 0
* ENDDRAW
* ENDDEF
*/
2021-06-10 18:51:46 +00:00
static LIB_SYMBOL* dummy()
{
2021-06-10 18:51:46 +00:00
static LIB_SYMBOL* symbol;
2021-06-10 18:51:46 +00:00
if( !symbol )
{
2021-06-10 18:51:46 +00:00
symbol = new LIB_SYMBOL( wxEmptyString );
LIB_SHAPE* square = new LIB_SHAPE( symbol, SHAPE_T::RECT );
square->MoveTo( wxPoint( Mils2iu( -200 ), Mils2iu( 200 ) ) );
square->SetEnd( wxPoint( Mils2iu( 200 ), Mils2iu( -200 ) ) );
2021-06-10 18:51:46 +00:00
LIB_TEXT* text = new LIB_TEXT( symbol );
text->SetTextSize( wxSize( Mils2iu( 150 ), Mils2iu( 150 ) ) );
text->SetText( wxString( wxT( "??" ) ) );
2021-06-10 18:51:46 +00:00
symbol->AddDrawItem( square );
symbol->AddDrawItem( text );
}
2021-06-10 18:51:46 +00:00
return symbol;
}
SCH_SYMBOL::SCH_SYMBOL( const wxPoint& aPosition, EDA_ITEM* aParent ) :
2021-06-10 14:10:55 +00:00
SCH_ITEM( aParent, SCH_SYMBOL_T )
{
Init( aPosition );
}
2021-06-10 18:51:46 +00:00
SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const LIB_ID& aLibId,
const SCH_SHEET_PATH* aSheet, int aUnit, int aConvert,
const wxPoint& aPosition, EDA_ITEM* aParent ) :
SCH_ITEM( aParent, SCH_SYMBOL_T )
{
Init( aPosition );
m_unit = aUnit;
m_convert = aConvert;
m_lib_id = aLibId;
2021-06-10 18:51:46 +00:00
std::unique_ptr< LIB_SYMBOL > part;
2021-06-10 18:51:46 +00:00
part = aSymbol.Flatten();
part->SetParent();
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
SetLibSymbol( part.release() );
2021-03-25 21:13:01 +00:00
// Copy fields from the library symbol
UpdateFields( aSheet,
2021-06-10 14:10:55 +00:00
true, /* update style */
false, /* update ref */
false, /* update other fields */
true, /* reset ref */
true /* reset other fields */ );
m_prefix = UTIL::GetRefDesPrefix( m_part->GetReferenceField().GetText() );
if( aSheet )
{
SetRef( aSheet, UTIL::GetRefDesUnannotated( m_prefix ) );
// Value and footprint name are stored in the SCH_SHEET_PATH path manager,
// if aSheet != nullptr, not in the symbol itself.
// Copy them to the currently displayed field texts
SetValue( GetValue( aSheet, false ) );
SetFootprint( GetFootprint( aSheet, false ) );
}
// Inherit the include in bill of materials and board netlist settings from library symbol.
2021-06-10 18:51:46 +00:00
m_inBom = aSymbol.GetIncludeInBom();
m_onBoard = aSymbol.GetIncludeOnBoard();
}
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
2021-06-10 18:51:46 +00:00
SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const SCH_SHEET_PATH* aSheet,
const PICKED_SYMBOL& aSel, const wxPoint& aPosition, EDA_ITEM* aParent ) :
SCH_SYMBOL( aSymbol, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, aPosition, aParent )
{
2021-03-25 21:13:01 +00:00
// Set any fields that were modified as part of the symbol selection
for( const std::pair<int, wxString>& i : aSel.Fields )
{
SCH_FIELD* field = GetFieldById( i.first );
if( field )
field->SetText( i.second );
}
}
2021-06-10 14:10:55 +00:00
SCH_SYMBOL::SCH_SYMBOL( const SCH_SYMBOL& aSymbol ) :
2021-03-25 21:13:01 +00:00
SCH_ITEM( aSymbol )
{
2021-03-25 21:13:01 +00:00
m_parent = aSymbol.m_parent;
m_pos = aSymbol.m_pos;
m_unit = aSymbol.m_unit;
m_convert = aSymbol.m_convert;
m_lib_id = aSymbol.m_lib_id;
m_isInNetlist = aSymbol.m_isInNetlist;
m_inBom = aSymbol.m_inBom;
m_onBoard = aSymbol.m_onBoard;
2021-03-25 21:13:01 +00:00
if( aSymbol.m_part )
2021-06-10 18:51:46 +00:00
SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part.get() ) );
2021-03-25 21:13:01 +00:00
const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
2021-03-25 21:13:01 +00:00
m_transform = aSymbol.m_transform;
m_prefix = aSymbol.m_prefix;
m_instanceReferences = aSymbol.m_instanceReferences;
m_fields = aSymbol.m_fields;
2021-03-25 21:13:01 +00:00
// Re-parent the fields, which before this had aSymbol as parent
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
field.SetParent( this );
2021-03-25 21:13:01 +00:00
m_fieldsAutoplaced = aSymbol.m_fieldsAutoplaced;
m_schLibSymbolName = aSymbol.m_schLibSymbolName;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::Init( const wxPoint& pos )
{
2020-11-16 13:15:54 +00:00
m_pos = pos;
m_unit = 1; // In multi unit chip - which unit to draw.
m_convert = LIB_ITEM::LIB_CONVERT::BASE; // De Morgan Handling
// The rotation/mirror transformation matrix. pos normal
m_transform = TRANSFORM();
// construct only the mandatory fields, which are the first 4 only.
for( int i = 0; i < MANDATORY_FIELDS; ++i )
{
2020-11-16 13:15:54 +00:00
m_fields.emplace_back( pos, i, this, TEMPLATE_FIELDNAME::GetDefaultFieldName( i ) );
2020-11-12 21:31:41 +00:00
if( i == REFERENCE_FIELD )
2020-11-16 13:15:54 +00:00
m_fields.back().SetLayer( LAYER_REFERENCEPART );
2020-11-12 21:31:41 +00:00
else if( i == VALUE_FIELD )
2020-11-16 13:15:54 +00:00
m_fields.back().SetLayer( LAYER_VALUEPART );
else
2020-11-16 13:15:54 +00:00
m_fields.back().SetLayer( LAYER_FIELDS );
}
m_prefix = wxString( wxT( "U" ) );
2019-04-09 01:54:41 +00:00
m_isInNetlist = true;
m_inBom = true;
m_onBoard = true;
}
2021-06-10 14:10:55 +00:00
EDA_ITEM* SCH_SYMBOL::Clone() const
{
2021-06-10 14:10:55 +00:00
return new SCH_SYMBOL( *this );
}
bool SCH_SYMBOL::IsMissingLibSymbol() const
{
if( !m_part )
return true;
return false;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::ViewGetLayers( int aLayers[], int& aCount ) const
{
aCount = 4;
aLayers[0] = LAYER_DANGLING; // Pins are drawn by their parent symbol, so the parent
// symbol needs to draw to LAYER_DANGLING
aLayers[1] = LAYER_DEVICE;
aLayers[2] = LAYER_DEVICE_BACKGROUND;
aLayers[3] = LAYER_SELECTION_SHADOWS;
}
bool SCH_SYMBOL::IsMovableFromAnchorPoint() const
{
// If a symbol's anchor is not grid-aligned to its pins then moving from the anchor is
// going to end up moving the symbol's pins off-grid.
// The minimal grid size allowed to place a pin is 25 mils
const int min_grid_size = Mils2iu( 25 );
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
{
if( ( ( pin->GetPosition().x - m_pos.x ) % min_grid_size ) != 0 )
return false;
if( ( ( pin->GetPosition().y - m_pos.y ) % min_grid_size ) != 0 )
return false;
}
return true;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
{
if( m_lib_id != aLibId )
{
m_lib_id = aLibId;
SetModified();
}
}
2021-06-10 14:10:55 +00:00
wxString SCH_SYMBOL::GetSchSymbolLibraryName() const
{
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
if( !m_schLibSymbolName.IsEmpty() )
return m_schLibSymbolName;
else
return m_lib_id.Format();
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
}
2021-06-10 18:51:46 +00:00
void SCH_SYMBOL::SetLibSymbol( LIB_SYMBOL* aLibSymbol )
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
{
wxCHECK2( ( aLibSymbol == nullptr ) || ( aLibSymbol->IsRoot() ), aLibSymbol = nullptr );
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
m_part.reset( aLibSymbol );
UpdatePins();
}
2021-06-10 14:10:55 +00:00
wxString SCH_SYMBOL::GetDescription() const
{
if( m_part )
return m_part->GetDescription();
return wxEmptyString;
}
2021-06-10 14:10:55 +00:00
wxString SCH_SYMBOL::GetDatasheet() const
{
if( m_part )
return m_part->GetDatasheetField().GetText();
return wxEmptyString;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::UpdatePins()
{
std::map<wxString, wxString> altPinMap;
std::map<wxString, KIID> pinUuidMap;
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
{
pinUuidMap[ pin->GetNumber() ] = pin->m_Uuid;
if( !pin->GetAlt().IsEmpty() )
altPinMap[ pin->GetNumber() ] = pin->GetAlt();
}
m_pins.clear();
m_pinMap.clear();
if( !m_part )
return;
unsigned i = 0;
for( LIB_PIN* libPin = m_part->GetNextPin(); libPin; libPin = m_part->GetNextPin( libPin ) )
{
wxASSERT( libPin->Type() == LIB_PIN_T );
if( libPin->GetConvert() && m_convert && ( m_convert != libPin->GetConvert() ) )
continue;
m_pins.push_back( std::make_unique<SCH_PIN>( libPin, this ) );
auto ii = pinUuidMap.find( libPin->GetNumber() );
if( ii != pinUuidMap.end() )
const_cast<KIID&>( m_pins.back()->m_Uuid ) = ii->second;
auto iii = altPinMap.find( libPin->GetNumber() );
if( iii != altPinMap.end() )
m_pins.back()->SetAlt( iii->second );
m_pinMap[ libPin ] = i;
++i;
}
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetUnit( int aUnit )
{
if( m_unit != aUnit )
{
m_unit = aUnit;
SetModified();
}
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::UpdateUnit( int aUnit )
{
m_unit = aUnit;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetConvert( int aConvert )
{
if( m_convert != aConvert )
{
m_convert = aConvert;
// The convert may have a different pin layout so the update the pin map.
UpdatePins();
SetModified();
}
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetTransform( const TRANSFORM& aTransform )
{
if( m_transform != aTransform )
{
m_transform = aTransform;
SetModified();
}
}
2021-06-10 14:10:55 +00:00
int SCH_SYMBOL::GetUnitCount() const
{
if( m_part )
return m_part->GetUnitCount();
return 0;
}
void SCH_SYMBOL::PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
{
LIB_SYMBOL_OPTIONS opts;
opts.transform = m_transform;
opts.draw_visible_fields = false;
opts.draw_hidden_fields = false;
if( m_part )
m_part->PrintBackground( aSettings, m_pos + aOffset, m_unit, m_convert, opts );
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
{
LIB_SYMBOL_OPTIONS opts;
opts.transform = m_transform;
opts.draw_visible_fields = false;
opts.draw_hidden_fields = false;
if( m_part )
{
2020-11-16 13:15:54 +00:00
m_part->Print( aSettings, m_pos + aOffset, m_unit, m_convert, opts );
}
else // Use dummy() part if the actual cannot be found.
{
2020-11-16 13:15:54 +00:00
dummy()->Print( aSettings, m_pos + aOffset, 0, 0, opts );
}
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
2020-04-14 12:25:00 +00:00
field.Print( aSettings, aOffset );
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef,
int aUnit, const wxString& aValue,
const wxString& aFootprint )
2008-04-12 18:39:20 +00:00
{
2008-04-15 19:38:19 +00:00
// Search for an existing path and remove it if found (should not occur)
for( unsigned ii = 0; ii < m_instanceReferences.size(); ii++ )
2008-04-15 19:38:19 +00:00
{
if( m_instanceReferences[ii].m_Path == aPath )
2008-04-15 19:38:19 +00:00
{
wxLogTrace( traceSchSheetPaths, wxT( "Removing symbol instance:\n" )
wxT( " sheet path %s\n" )
wxT( " reference %s, unit %d from symbol %s." ),
aPath.AsString(),
m_instanceReferences[ii].m_Reference,
m_instanceReferences[ii].m_Unit,
m_Uuid.AsString() );
m_instanceReferences.erase( m_instanceReferences.begin() + ii );
ii--;
2008-04-15 19:38:19 +00:00
}
}
2020-11-15 17:03:27 +00:00
SYMBOL_INSTANCE_REFERENCE instance;
instance.m_Path = aPath;
instance.m_Reference = aRef;
instance.m_Unit = aUnit;
instance.m_Value = aValue;
instance.m_Footprint = aFootprint;
wxLogTrace( traceSchSheetPaths, wxT( "Adding symbol instance:\n" )
wxT( " sheet path %s\n" )
wxT( " reference %s, unit %d to symbol %s." ),
aPath.AsString(),
aRef,
aUnit,
m_Uuid.AsString() );
m_instanceReferences.push_back( instance );
}
2021-06-10 14:10:55 +00:00
const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
{
KIID_PATH path = sheet->Path();
wxString ref;
2020-11-15 17:03:27 +00:00
for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
{
ref = instance.m_Reference;
break;
}
}
2019-07-02 20:09:23 +00:00
// If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
// use this as a default for this path. This will happen if we load a version 1 schematic
// file. It will also mean that multiple instances of the same sheet by default all have
2021-03-25 21:13:01 +00:00
// the same symbol references, but perhaps this is best.
2020-11-12 21:31:41 +00:00
if( ref.IsEmpty() && !GetField( REFERENCE_FIELD )->GetText().IsEmpty() )
{
2021-06-10 14:10:55 +00:00
const_cast<SCH_SYMBOL*>( this )->SetRef( sheet, GetField( REFERENCE_FIELD )->GetText() );
2020-11-12 21:31:41 +00:00
ref = GetField( REFERENCE_FIELD )->GetText();
}
2011-12-07 18:47:59 +00:00
if( ref.IsEmpty() )
ref = UTIL::GetRefDesUnannotated( m_prefix );
if( aIncludeUnit && GetUnitCount() > 1 )
2021-06-10 18:51:46 +00:00
ref += LIB_SYMBOL::SubReference( GetUnit() );
return ref;
}
2007-09-20 21:06:49 +00:00
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::IsReferenceStringValid( const wxString& aReferenceString )
{
return !UTIL::GetRefDesPrefix( aReferenceString ).IsEmpty();
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
{
KIID_PATH path = sheet->Path();
bool found = false;
2008-04-12 18:39:20 +00:00
// check to see if it is already there before inserting it
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
{
found = true;
instance.m_Reference = ref;
break;
}
}
if( !found )
AddHierarchicalReference( path, ref, m_unit, GetField( VALUE_FIELD )->GetText(),
GetField( FOOTPRINT_FIELD )->GetText() );
for( std::unique_ptr<SCH_PIN>& pin : m_pins )
pin->ClearDefaultNetName( sheet );
// Schematic() is null for new components just added
if( !Schematic() || *sheet == Schematic()->CurrentSheet() )
m_fields[ REFERENCE_FIELD ].SetText( ref );
// Reinit the m_prefix member if needed
m_prefix = UTIL::GetRefDesPrefix( ref );
if( m_prefix.IsEmpty() )
m_prefix = wxT( "U" );
2019-04-09 01:54:41 +00:00
2021-03-25 21:13:01 +00:00
// Power symbols have references starting with # and are not included in netlists
2019-04-09 01:54:41 +00:00
m_isInNetlist = ! ref.StartsWith( wxT( "#" ) );
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet )
{
KIID_PATH path = aSheet->Path();
2020-11-15 17:03:27 +00:00
for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
return instance.m_Reference.Last() != '?';
}
return false;
}
2021-06-10 14:10:55 +00:00
int SCH_SYMBOL::GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const
{
KIID_PATH path = aSheet->Path();
2020-11-15 17:03:27 +00:00
for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
return instance.m_Unit;
}
2019-07-02 20:09:23 +00:00
// If it was not found in m_Paths array, then use m_unit. This will happen if we load a
// version 1 schematic file.
return m_unit;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
{
KIID_PATH path = aSheet->Path();
// check to see if it is already there before inserting it
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
{
instance.m_Unit = aUnitSelection;
return;
}
}
// didn't find it; better add it
AddHierarchicalReference( path, UTIL::GetRefDesUnannotated( m_prefix ), aUnitSelection );
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
{
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
instance.m_Unit = aUnitSelection;
}
2021-06-10 14:10:55 +00:00
const wxString SCH_SYMBOL::GetValue( const SCH_SHEET_PATH* sheet, bool aResolve ) const
{
KIID_PATH path = sheet->Path();
2020-11-15 17:03:27 +00:00
for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path && !instance.m_Value.IsEmpty() )
{
// This can only be overridden by a new value but if we are resolving,
// make sure that the symbol returns the fully resolved text
if( aResolve )
{
SCH_SYMBOL new_sym( *this );
new_sym.GetField( VALUE_FIELD )->SetText( instance.m_Value );
return new_sym.GetField( VALUE_FIELD )->GetShownText();
}
return instance.m_Value;
}
}
if( !aResolve )
return GetField( VALUE_FIELD )->GetText();
2020-11-12 21:31:41 +00:00
return GetField( VALUE_FIELD )->GetShownText();
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue )
{
if( sheet == nullptr )
{
// Set all instances to the updated value
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
instance.m_Value = aValue;
2020-11-16 13:15:54 +00:00
m_fields[ VALUE_FIELD ].SetText( aValue );
return;
}
KIID_PATH path = sheet->Path();
bool found = false;
// check to see if it is already there before inserting it
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
{
found = true;
instance.m_Value = aValue;
break;
}
}
// didn't find it; better add it
if( !found )
{
AddHierarchicalReference( path, UTIL::GetRefDesUnannotated( m_prefix ), m_unit, aValue,
wxEmptyString );
}
if( Schematic() && *sheet == Schematic()->CurrentSheet() )
m_fields[ VALUE_FIELD ].SetText( aValue );
}
2021-06-10 14:10:55 +00:00
const wxString SCH_SYMBOL::GetFootprint( const SCH_SHEET_PATH* sheet, bool aResolve ) const
{
KIID_PATH path = sheet->Path();
2020-11-15 17:03:27 +00:00
for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path && !instance.m_Footprint.IsEmpty() )
{
// This can only be an override from an Update Schematic from PCB, and therefore
// will always be fully resolved.
return instance.m_Footprint;
}
}
if( !aResolve )
return GetField( FOOTPRINT_FIELD )->GetText();
2020-11-12 21:31:41 +00:00
return GetField( FOOTPRINT_FIELD )->GetShownText();
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint )
{
if( sheet == nullptr )
{
// Set all instances to new footprint value
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
instance.m_Footprint = aFootprint;
2020-11-16 13:15:54 +00:00
m_fields[ FOOTPRINT_FIELD ].SetText( aFootprint );
return;
}
KIID_PATH path = sheet->Path();
bool found = false;
// check to see if it is already there before inserting it
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
if( instance.m_Path == path )
{
found = true;
instance.m_Footprint = aFootprint;
break;
}
}
// didn't find it; better add it
if( !found )
{
AddHierarchicalReference( path, UTIL::GetRefDesUnannotated( m_prefix ), m_unit,
wxEmptyString, aFootprint );
}
if( Schematic() && *sheet == Schematic()->CurrentSheet() )
m_fields[ FOOTPRINT_FIELD ].SetText( aFootprint );
}
2021-06-10 14:10:55 +00:00
SCH_FIELD* SCH_SYMBOL::GetField( MANDATORY_FIELD_T aFieldType )
2007-09-20 21:06:49 +00:00
{
return &m_fields[aFieldType];
}
2021-06-10 14:10:55 +00:00
const SCH_FIELD* SCH_SYMBOL::GetField( MANDATORY_FIELD_T aFieldType ) const
{
return &m_fields[aFieldType];
}
2021-06-10 14:10:55 +00:00
SCH_FIELD* SCH_SYMBOL::GetFieldById( int aFieldId )
{
for( size_t ii = 0; ii < m_fields.size(); ++ii )
{
if( m_fields[ii].GetId() == aFieldId )
return &m_fields[ii];
}
return nullptr;
2007-05-06 16:03:28 +00:00
}
2021-06-10 14:10:55 +00:00
wxString SCH_SYMBOL::GetFieldText( const wxString& aFieldName, SCH_EDIT_FRAME* aFrame ) const
{
2020-11-16 13:15:54 +00:00
for( const SCH_FIELD& field : m_fields )
{
if( aFieldName == field.GetName() || aFieldName == field.GetCanonicalName() )
2019-07-02 20:09:23 +00:00
return field.GetText();
}
return wxEmptyString;
}
2007-05-06 16:03:28 +00:00
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly )
{
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
{
2019-07-02 20:09:23 +00:00
if( !aVisibleOnly || ( field.IsVisible() && !field.IsVoid() ) )
aVector.push_back( &field );
}
}
2021-06-10 14:10:55 +00:00
SCH_FIELD* SCH_SYMBOL::AddField( const SCH_FIELD& aField )
2007-05-06 16:03:28 +00:00
{
2020-11-16 13:15:54 +00:00
int newNdx = m_fields.size();
2020-11-16 13:15:54 +00:00
m_fields.push_back( aField );
return &m_fields[newNdx];
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
{
2020-11-16 13:15:54 +00:00
for( unsigned i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
{
2020-11-16 13:15:54 +00:00
if( aFieldName == m_fields[i].GetName( false ) )
{
2020-11-16 13:15:54 +00:00
m_fields.erase( m_fields.begin() + i );
return;
}
}
}
2021-06-10 14:10:55 +00:00
SCH_FIELD* SCH_SYMBOL::FindField( const wxString& aFieldName, bool aIncludeDefaultFields )
{
unsigned start = aIncludeDefaultFields ? 0 : MANDATORY_FIELDS;
2020-11-16 13:15:54 +00:00
for( unsigned i = start; i < m_fields.size(); ++i )
{
2020-11-16 13:15:54 +00:00
if( aFieldName == m_fields[i].GetName( false ) )
return &m_fields[i];
}
2021-07-16 20:13:26 +00:00
return nullptr;
2007-05-06 16:03:28 +00:00
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef,
bool aUpdateOtherFields, bool aResetRef, bool aResetOtherFields )
{
if( m_part )
{
wxString symbolName;
std::vector<LIB_FIELD*> fields;
m_part->GetFields( fields );
for( const LIB_FIELD* libField : fields )
{
int id = libField->GetId();
SCH_FIELD* schField;
if( id >= 0 && id < MANDATORY_FIELDS )
{
schField = GetFieldById( id );
}
else
{
schField = FindField( libField->GetCanonicalName() );
if( !schField )
{
wxString fieldName = libField->GetCanonicalName();
SCH_FIELD newField( wxPoint( 0, 0), GetFieldCount(), this, fieldName );
schField = AddField( newField );
}
}
if( aUpdateStyle )
{
schField->ImportValues( *libField );
schField->SetTextPos( m_pos + libField->GetTextPos() );
}
if( id == REFERENCE_FIELD && aPath )
{
if( aResetRef )
SetRef( aPath, m_part->GetReferenceField().GetText() );
else if( aUpdateRef )
SetRef( aPath, libField->GetText() );
}
else if( id == VALUE_FIELD )
{
if( aResetOtherFields )
SetValue( aPath, UnescapeString( m_lib_id.GetLibItemName() ) ); // alias-specific value
else
SetValue( aPath, UnescapeString( libField->GetText() ) );
}
else if( id == FOOTPRINT_FIELD )
{
if( aResetOtherFields || aUpdateOtherFields )
SetFootprint( aPath, libField->GetText() );
}
else if( id == DATASHEET_FIELD )
{
if( aResetOtherFields )
schField->SetText( GetDatasheet() ); // alias-specific value
else if( aUpdateOtherFields )
schField->SetText( libField->GetText() );
}
else
{
if( aResetOtherFields || aUpdateOtherFields )
schField->SetText( libField->GetText() );
}
}
}
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction )
{
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
aFunction( pin.get() );
for( SCH_FIELD& field : m_fields )
aFunction( &field );
}
2021-06-10 14:10:55 +00:00
SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
{
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
{
if( pin->GetNumber() == aNumber )
return pin.get();
}
return nullptr;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::GetLibPins( std::vector<LIB_PIN*>& aPinsList ) const
{
if( m_part )
m_part->GetPins( aPinsList, m_unit, m_convert );
}
SCH_PIN* SCH_SYMBOL::GetPin( LIB_PIN* aLibPin ) const
{
wxASSERT( m_pinMap.count( aLibPin ) );
return m_pins[ m_pinMap.at( aLibPin ) ].get();
}
2021-06-10 14:10:55 +00:00
std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
{
std::vector<SCH_PIN*> pins;
if( aSheet == nullptr )
{
wxCHECK_MSG( Schematic(), pins, wxT( "Can't call GetPins on a symbol with no schematic" ) );
aSheet = &Schematic()->CurrentSheet();
}
int unit = GetUnitSelection( aSheet );
for( const auto& p : m_pins )
{
if( unit && p->GetLibPin()->GetUnit() && ( p->GetLibPin()->GetUnit() != unit ) )
continue;
pins.push_back( p.get() );
}
return pins;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SwapData( SCH_ITEM* aItem )
2007-05-06 16:03:28 +00:00
{
2021-07-16 20:13:26 +00:00
wxCHECK_RET( (aItem != nullptr) && (aItem->Type() == SCH_SYMBOL_T),
2021-03-25 21:13:01 +00:00
wxT( "Cannot swap data with invalid symbol." ) );
2021-06-10 14:10:55 +00:00
SCH_SYMBOL* symbol = (SCH_SYMBOL*) aItem;
2021-05-05 21:41:51 +00:00
std::swap( m_lib_id, symbol->m_lib_id );
2021-06-10 18:51:46 +00:00
LIB_SYMBOL* libSymbol = symbol->m_part.release();
2021-05-05 21:41:51 +00:00
symbol->m_part.reset( m_part.release() );
symbol->UpdatePins();
2021-06-10 18:51:46 +00:00
m_part.reset( libSymbol );
UpdatePins();
2021-05-05 21:41:51 +00:00
std::swap( m_pos, symbol->m_pos );
std::swap( m_unit, symbol->m_unit );
std::swap( m_convert, symbol->m_convert );
2021-05-05 21:41:51 +00:00
m_fields.swap( symbol->m_fields ); // std::vector's swap()
2021-05-05 21:41:51 +00:00
for( SCH_FIELD& field : symbol->m_fields )
field.SetParent( symbol );
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
2020-03-06 20:02:58 +00:00
field.SetParent( this );
TRANSFORM tmp = m_transform;
2021-05-05 21:41:51 +00:00
m_transform = symbol->m_transform;
symbol->m_transform = tmp;
2021-05-05 21:41:51 +00:00
std::swap( m_instanceReferences, symbol->m_instanceReferences );
std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
2007-05-06 16:03:28 +00:00
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
{
for( int i = 0; i < MANDATORY_FIELDS; ++i )
2020-11-16 13:15:54 +00:00
aVars->push_back( m_fields[i].GetCanonicalName().Upper() );
2020-11-16 13:15:54 +00:00
for( size_t i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
aVars->push_back( m_fields[i].GetName() );
aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
aVars->push_back( wxT( "UNIT" ) );
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::ResolveTextVar( wxString* token, int aDepth ) const
{
SCHEMATIC* schematic = Schematic();
2021-07-06 17:32:34 +00:00
// SCH_SYMOL object has no context outside a schematic.
wxCHECK( schematic, false );
for( int i = 0; i < MANDATORY_FIELDS; ++i )
{
2020-11-16 13:15:54 +00:00
if( token->IsSameAs( m_fields[ i ].GetCanonicalName().Upper() ) )
{
2021-07-06 17:32:34 +00:00
if( i == REFERENCE_FIELD )
*token = GetRef( &schematic->CurrentSheet(), true );
2021-07-06 17:32:34 +00:00
else if( i == VALUE_FIELD )
*token = GetValue( &schematic->CurrentSheet(), true );
2021-07-06 17:32:34 +00:00
else if( i == FOOTPRINT_FIELD )
*token = GetFootprint( &schematic->CurrentSheet(), true );
else
2020-11-16 13:15:54 +00:00
*token = m_fields[ i ].GetShownText( aDepth + 1 );
return true;
}
}
2020-11-16 13:15:54 +00:00
for( size_t i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
{
2020-11-16 13:15:54 +00:00
if( token->IsSameAs( m_fields[ i ].GetName() )
|| token->IsSameAs( m_fields[ i ].GetName().Upper() ) )
{
2020-11-16 13:15:54 +00:00
*token = m_fields[ i ].GetShownText( aDepth + 1 );
return true;
}
}
for( const TEMPLATE_FIELDNAME& templateFieldname :
schematic->Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
{
if( token->IsSameAs( templateFieldname.m_Name )
|| token->IsSameAs( templateFieldname.m_Name.Upper() ) )
{
// If we didn't find it in the fields list then it isn't set on this symbol.
// Just return an empty string.
*token = wxEmptyString;
return true;
}
}
if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
{
wxString footprint;
2021-07-06 17:32:34 +00:00
footprint = GetFootprint( &schematic->CurrentSheet(), true );
wxArrayString parts = wxSplit( footprint, ':' );
*token = parts[ 0 ];
return true;
}
else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
{
wxString footprint;
2021-07-06 17:32:34 +00:00
footprint = GetFootprint( &schematic->CurrentSheet(), true );
wxArrayString parts = wxSplit( footprint, ':' );
*token = parts[ std::min( 1, (int) parts.size() - 1 ) ];
return true;
}
else if( token->IsSameAs( wxT( "UNIT" ) ) )
{
int unit;
2021-07-06 17:32:34 +00:00
unit = GetUnitSelection( &schematic->CurrentSheet() );
2021-06-10 18:51:46 +00:00
*token = LIB_SYMBOL::SubReference( unit );
return true;
}
return false;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath )
{
// Build a reference with no annotation, i.e. a reference ending with a single '?'
wxString defRef = UTIL::GetRefDesUnannotated( m_prefix );
2008-04-15 19:38:19 +00:00
if( aSheetPath )
{
KIID_PATH path = aSheetPath->Path();
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
2008-04-21 06:34:56 +00:00
{
if( instance.m_Path == path )
instance.m_Reference = defRef;
2008-04-21 06:34:56 +00:00
}
}
else
{
2020-11-15 17:03:27 +00:00
for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
instance.m_Reference = defRef;
}
for( std::unique_ptr<SCH_PIN>& pin : m_pins )
pin->ClearDefaultNetName( aSheetPath );
2008-04-21 06:34:56 +00:00
// These 2 changes do not work in complex hierarchy.
// When a clear annotation is made, the calling function must call a
// UpdateAllScreenReferences for the active sheet.
// But this call cannot made here.
2020-11-16 13:15:54 +00:00
m_fields[REFERENCE_FIELD].SetText( defRef ); //for drawing.
2007-05-06 16:03:28 +00:00
}
2007-09-20 21:06:49 +00:00
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::AddSheetPathReferenceEntryIfMissing( const KIID_PATH& aSheetPath )
{
// a empty sheet path is illegal:
wxCHECK( aSheetPath.size() > 0, false );
wxString reference_path;
2020-11-15 17:03:27 +00:00
for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
{
// if aSheetPath is found, nothing to do:
if( instance.m_Path == aSheetPath )
return false;
}
// This entry does not exist: add it, with its last-used reference
2020-11-16 13:15:54 +00:00
AddHierarchicalReference( aSheetPath, m_fields[REFERENCE_FIELD].GetText(), m_unit );
return true;
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::ReplaceInstanceSheetPath( const KIID_PATH& aOldSheetPath,
const KIID_PATH& aNewSheetPath )
{
auto it = std::find_if( m_instanceReferences.begin(), m_instanceReferences.end(),
2020-11-15 17:03:27 +00:00
[ aOldSheetPath ]( SYMBOL_INSTANCE_REFERENCE& r )->bool
{
return aOldSheetPath == r.m_Path;
}
);
if( it != m_instanceReferences.end() )
{
wxLogTrace( traceSchSheetPaths,
wxT( "Replacing sheet path %s\n with sheet path %s\n for symbol %s." ),
aOldSheetPath.AsString(), aNewSheetPath.AsString(), m_Uuid.AsString() );
it->m_Path = aNewSheetPath;
return true;
}
wxLogTrace( traceSchSheetPaths,
wxT( "Could not find sheet path %s\n to replace with sheet path %s\n for symbol %s." ),
aOldSheetPath.AsString(), aNewSheetPath.AsString(), m_Uuid.AsString() );
return false;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::SetOrientation( int aOrientation )
2007-05-06 16:03:28 +00:00
{
TRANSFORM temp = TRANSFORM();
bool transform = false;
2007-09-20 21:06:49 +00:00
switch( aOrientation )
2007-09-20 21:06:49 +00:00
{
2021-06-10 14:10:55 +00:00
case SYM_ORIENT_0:
case SYM_NORMAL: // default transform matrix
m_transform.x1 = 1;
m_transform.y2 = -1;
m_transform.x2 = m_transform.y1 = 0;
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
temp.x1 = temp.y2 = 0;
temp.y1 = 1;
temp.x2 = -1;
transform = true;
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
temp.x1 = temp.y2 = 0;
temp.y1 = -1;
temp.x2 = 1;
transform = true;
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case SYM_MIRROR_Y: // Mirror Y (incremental rotation)
temp.x1 = -1;
temp.y2 = 1;
temp.y1 = temp.x2 = 0;
transform = true;
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case SYM_MIRROR_X: // Mirror X (incremental rotation)
temp.x1 = 1;
temp.y2 = -1;
temp.y1 = temp.x2 = 0;
transform = true;
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case SYM_ORIENT_90:
SetOrientation( SYM_ORIENT_0 );
SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case SYM_ORIENT_180:
SetOrientation( SYM_ORIENT_0 );
SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case SYM_ORIENT_270:
SetOrientation( SYM_ORIENT_0 );
SetOrientation( SYM_ROTATE_CLOCKWISE );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_0 + SYM_MIRROR_X ):
SetOrientation( SYM_ORIENT_0 );
SetOrientation( SYM_MIRROR_X );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_0 + SYM_MIRROR_Y ):
SetOrientation( SYM_ORIENT_0 );
SetOrientation( SYM_MIRROR_Y );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_90 + SYM_MIRROR_X ):
SetOrientation( SYM_ORIENT_90 );
SetOrientation( SYM_MIRROR_X );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_90 + SYM_MIRROR_Y ):
SetOrientation( SYM_ORIENT_90 );
SetOrientation( SYM_MIRROR_Y );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_180 + SYM_MIRROR_X ):
SetOrientation( SYM_ORIENT_180 );
SetOrientation( SYM_MIRROR_X );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_180 + SYM_MIRROR_Y ):
SetOrientation( SYM_ORIENT_180 );
SetOrientation( SYM_MIRROR_Y );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_270 + SYM_MIRROR_X ):
SetOrientation( SYM_ORIENT_270 );
SetOrientation( SYM_MIRROR_X );
2007-09-20 21:06:49 +00:00
break;
2021-06-10 14:10:55 +00:00
case ( SYM_ORIENT_270 + SYM_MIRROR_Y ):
SetOrientation( SYM_ORIENT_270 );
SetOrientation( SYM_MIRROR_Y );
2007-09-20 21:06:49 +00:00
break;
default:
transform = false;
wxFAIL_MSG( wxT( "Invalid schematic symbol orientation type." ) );
2007-09-20 21:06:49 +00:00
break;
}
if( transform )
2008-04-12 18:39:20 +00:00
{
/* The new matrix transform is the old matrix transform modified by the
* requested transformation, which is the temp transform (rot,
* mirror ..) in order to have (in term of matrix transform):
* transform coord = new_m_transform * coord
* where transform coord is the coord modified by new_m_transform from
* the initial value coord.
* new_m_transform is computed (from old_m_transform and temp) to
* have:
* transform coord = old_m_transform * temp
2008-04-12 18:39:20 +00:00
*/
TRANSFORM newTransform;
2007-09-20 21:06:49 +00:00
newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
m_transform = newTransform;
2007-09-20 21:06:49 +00:00
}
2007-05-06 16:03:28 +00:00
}
2021-06-10 14:10:55 +00:00
int SCH_SYMBOL::GetOrientation()
2007-05-06 16:03:28 +00:00
{
int rotate_values[] =
2007-09-20 21:06:49 +00:00
{
2021-06-10 14:10:55 +00:00
SYM_ORIENT_0,
SYM_ORIENT_90,
SYM_ORIENT_180,
SYM_ORIENT_270,
SYM_MIRROR_X + SYM_ORIENT_0,
SYM_MIRROR_X + SYM_ORIENT_90,
SYM_MIRROR_X + SYM_ORIENT_270,
SYM_MIRROR_Y,
SYM_MIRROR_Y + SYM_ORIENT_0,
SYM_MIRROR_Y + SYM_ORIENT_90,
SYM_MIRROR_Y + SYM_ORIENT_180,
SYM_MIRROR_Y + SYM_ORIENT_270
};
2007-09-20 21:06:49 +00:00
// Try to find the current transform option:
TRANSFORM transform = m_transform;
2007-09-20 21:06:49 +00:00
for( int type_rotate : rotate_values )
2007-09-20 21:06:49 +00:00
{
SetOrientation( type_rotate );
if( transform == m_transform )
return type_rotate;
2007-09-20 21:06:49 +00:00
}
// Error: orientation not found in list (should not happen)
wxFAIL_MSG( wxT( "Schematic symbol orientation matrix internal error." ) );
m_transform = transform;
2021-06-10 14:10:55 +00:00
return SYM_NORMAL;
2007-05-06 16:03:28 +00:00
}
2007-09-20 21:06:49 +00:00
#if defined(DEBUG)
2007-09-20 21:06:49 +00:00
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
2007-05-06 16:03:28 +00:00
{
2007-09-20 21:06:49 +00:00
// for now, make it look like XML:
NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
<< " ref=\"" << TO_UTF8( GetField( REFERENCE_FIELD )->GetName() )
<< '"' << " chipName=\""
2020-11-16 13:15:54 +00:00
<< GetLibId().Format() << '"' << m_pos
2020-11-14 14:29:11 +00:00
<< " layer=\"" << m_layer
<< '"' << ">\n";
// skip the reference, it's been output already.
for( int i = 1; i < GetFieldCount(); ++i )
2007-09-20 21:06:49 +00:00
{
const wxString& value = GetFields()[i].GetText();
2007-09-20 21:06:49 +00:00
if( !value.IsEmpty() )
{
NestedSpace( nestLevel + 1, os ) << "<field" << " name=\""
<< TO_UTF8( GetFields()[i].GetName() )
<< '"' << " value=\""
<< TO_UTF8( value ) << "\"/>\n";
2007-09-20 21:06:49 +00:00
}
}
NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
2007-05-06 16:03:28 +00:00
}
2007-09-20 21:06:49 +00:00
#endif
2007-05-06 16:03:28 +00:00
EDA_RECT SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
2008-04-15 19:38:19 +00:00
{
EDA_RECT bBox;
if( m_part )
bBox = m_part->GetBodyBoundingBox( m_unit, m_convert, aIncludePins );
else
bBox = dummy()->GetBodyBoundingBox( m_unit, m_convert, aIncludePins );
int x0 = bBox.GetX();
int xm = bBox.GetRight();
// We must reverse Y values, because matrix orientation
// suppose Y axis normal for the library items coordinates,
// m_transform reverse Y values, but bBox is already reversed!
int y0 = -bBox.GetY();
int ym = -bBox.GetBottom();
// Compute the real Boundary box (rotated, mirrored ...)
int x1 = m_transform.x1 * x0 + m_transform.y1 * y0;
int y1 = m_transform.x2 * x0 + m_transform.y2 * y0;
int x2 = m_transform.x1 * xm + m_transform.y1 * ym;
int y2 = m_transform.x2 * xm + m_transform.y2 * ym;
bBox.SetX( x1 );
bBox.SetY( y1 );
bBox.SetWidth( x2 - x1 );
bBox.SetHeight( y2 - y1 );
bBox.Normalize();
2008-04-15 19:38:19 +00:00
2020-11-16 13:15:54 +00:00
bBox.Offset( m_pos );
if( aIncludeFields )
{
for( const SCH_FIELD& field : m_fields )
{
if( field.IsVisible() )
bBox.Merge( field.GetBoundingBox() );
}
}
return bBox;
}
EDA_RECT SCH_SYMBOL::GetBodyBoundingBox() const
{
return doGetBoundingBox( false, false );
2008-04-12 18:39:20 +00:00
}
EDA_RECT SCH_SYMBOL::GetBodyAndPinsBoundingBox() const
{
return doGetBoundingBox( true, false );
}
const EDA_RECT SCH_SYMBOL::GetBoundingBox() const
{
return doGetBoundingBox( true, true );
}
void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{
wxString msg;
SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
// part and alias can differ if alias is not the root
if( m_part )
{
if( m_part.get() != dummy() )
{
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
msg = m_part->IsPower() ? _( "Power symbol" ) : _( "Value" );
2021-09-28 13:28:35 +00:00
aList.emplace_back( msg, GetValue( currentSheet, true ) );
2021-03-25 21:13:01 +00:00
#if 0 // Display symbol flags, for debug only
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
#endif
2021-03-25 21:13:01 +00:00
// Display symbol reference in library and library
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Name" ), UnescapeString( GetLibId().GetLibItemName() ) );
if( !m_part->IsRoot() )
{
msg = _( "Missing parent" );
2021-06-10 18:51:46 +00:00
std::shared_ptr< LIB_SYMBOL > parent = m_part->GetParent().lock();
if( parent )
msg = parent->GetName();
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Alias of" ), UnescapeString( msg ) );
}
else if( !m_lib_id.GetLibNickname().empty() )
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
{
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
}
else
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
{
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
2020-04-16 16:43:50 +00:00
}
// Display the current associated footprint, if exists.
msg = GetFootprint( currentSheet, true );
if( msg.IsEmpty() )
msg = _( "<Unknown>" );
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Footprint" ), msg );
2021-03-25 21:13:01 +00:00
// Display description of the symbol, and keywords found in lib
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Description" ), m_part->GetDescription() );
aList.emplace_back( _( "Keywords" ), m_part->GetKeyWords() );
}
}
else
{
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Value" ), GetValue( currentSheet, true ) );
aList.emplace_back( _( "Name" ), GetLibId().GetLibItemName() );
wxString libNickname = GetLibId().GetLibNickname();
if( libNickname.empty() )
2021-09-28 13:28:35 +00:00
msg = _( "No library defined!" );
else
msg.Printf( _( "Symbol not found in %s!" ), libNickname );
2021-09-28 13:28:35 +00:00
aList.emplace_back( _( "Library" ), msg );
}
}
2021-06-10 14:10:55 +00:00
BITMAPS SCH_SYMBOL::GetMenuImage() const
{
return BITMAPS::add_component;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::MirrorHorizontally( int aCenter )
{
2020-11-16 13:15:54 +00:00
int dx = m_pos.x;
2021-06-10 14:10:55 +00:00
SetOrientation( SYM_MIRROR_Y );
MIRROR( m_pos.x, aCenter );
2020-11-16 13:15:54 +00:00
dx -= m_pos.x; // dx,0 is the move vector for this transform
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
{
2021-03-25 21:13:01 +00:00
// Move the fields to the new position because the symbol itself has moved.
2020-03-06 20:02:58 +00:00
wxPoint pos = field.GetTextPos();
pos.x -= dx;
2020-03-06 20:02:58 +00:00
field.SetTextPos( pos );
}
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::MirrorVertically( int aCenter )
{
2020-11-16 13:15:54 +00:00
int dy = m_pos.y;
2021-06-10 14:10:55 +00:00
SetOrientation( SYM_MIRROR_X );
MIRROR( m_pos.y, aCenter );
dy -= m_pos.y; // 0,dy is the move vector for this transform
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
{
2021-03-25 21:13:01 +00:00
// Move the fields to the new position because the symbol itself has moved.
2020-03-06 20:02:58 +00:00
wxPoint pos = field.GetTextPos();
pos.y -= dy;
2020-03-06 20:02:58 +00:00
field.SetTextPos( pos );
}
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::Rotate( const wxPoint& aCenter )
{
2020-11-16 13:15:54 +00:00
wxPoint prev = m_pos;
2021-03-19 19:55:59 +00:00
RotatePoint( &m_pos, aCenter, 900 );
2021-06-10 14:10:55 +00:00
SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
{
2021-03-25 21:13:01 +00:00
// Move the fields to the new position because the symbol itself has moved.
wxPoint pos = field.GetTextPos();
2020-11-16 13:15:54 +00:00
pos.x -= prev.x - m_pos.x;
pos.y -= prev.y - m_pos.y;
field.SetTextPos( pos );
}
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::Matches( const wxFindReplaceData& aSearchData, void* aAuxData ) const
{
2019-12-20 14:11:39 +00:00
wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText( EDA_UNITS::MILLIMETRES ) );
2021-03-25 21:13:01 +00:00
// Symbols are searchable via the child field and pin item text.
return false;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
{
for( auto& pin : m_pins )
{
LIB_PIN* lib_pin = pin->GetLibPin();
if( lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
continue;
DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
aItemList.push_back( item );
}
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath )
{
bool changed = false;
for( std::unique_ptr<SCH_PIN>& pin : m_pins )
{
bool previousState = pin->IsDangling();
pin->SetIsDangling( true );
2020-11-16 13:15:54 +00:00
wxPoint pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
for( DANGLING_END_ITEM& each_item : aItemList )
{
// Some people like to stack pins on top of each other in a symbol to indicate
// internal connection. While technically connected, it is not particularly useful
// to display them that way, so skip any pins that are in the same symbol as this
// one.
if( each_item.GetParent() == this )
continue;
switch( each_item.GetType() )
{
case PIN_END:
case LABEL_END:
case SHEET_LABEL_END:
case WIRE_END:
case NO_CONNECT_END:
case JUNCTION_END:
if( pos == each_item.GetPosition() )
pin->SetIsDangling( false );
break;
default:
break;
}
if( !pin->IsDangling() )
break;
}
changed = ( changed || ( previousState != pin->IsDangling() ) );
}
return changed;
}
2021-06-10 14:10:55 +00:00
wxPoint SCH_SYMBOL::GetPinPhysicalPosition( const LIB_PIN* Pin ) const
{
2021-07-16 20:13:26 +00:00
wxCHECK_MSG( Pin != nullptr && Pin->Type() == LIB_PIN_T, wxPoint( 0, 0 ),
wxT( "Cannot get physical position of pin." ) );
2020-11-16 13:15:54 +00:00
return m_transform.TransformCoordinate( Pin->GetPosition() ) + m_pos;
}
2021-06-10 14:10:55 +00:00
std::vector<wxPoint> SCH_SYMBOL::GetConnectionPoints() const
{
std::vector<wxPoint> retval;
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
{
// Collect only pins attached to the current unit and convert.
2021-03-25 21:13:01 +00:00
// others are not associated to this symbol instance
int pin_unit = pin->GetLibPin()->GetUnit();
int pin_convert = pin->GetLibPin()->GetConvert();
if( pin_unit > 0 && pin_unit != GetUnit() )
continue;
if( pin_convert > 0 && pin_convert != GetConvert() )
continue;
2020-11-16 13:15:54 +00:00
retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
}
return retval;
}
2021-06-10 14:10:55 +00:00
LIB_ITEM* SCH_SYMBOL::GetDrawItem( const wxPoint& aPosition, KICAD_T aType )
{
if( m_part )
{
2021-03-25 21:13:01 +00:00
// Calculate the position relative to the symbol.
2020-11-16 13:15:54 +00:00
wxPoint libPosition = aPosition - m_pos;
return m_part->LocateDrawItem( m_unit, m_convert, aType, libPosition, m_transform );
}
2021-07-16 20:13:26 +00:00
return nullptr;
}
2021-06-10 14:10:55 +00:00
wxString SCH_SYMBOL::GetSelectMenuText( EDA_UNITS aUnits ) const
{
return wxString::Format( _( "Symbol %s [%s]" ),
2020-11-12 21:31:41 +00:00
GetField( REFERENCE_FIELD )->GetShownText(),
UnescapeString( GetLibId().GetLibItemName() ) );
}
2021-06-10 14:10:55 +00:00
SEARCH_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData,
const KICAD_T aFilterTypes[] )
{
KICAD_T stype;
for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
{
if( stype == SCH_LOCATE_ANY_T
2021-06-10 14:10:55 +00:00
|| ( stype == SCH_SYMBOL_T )
|| ( stype == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
{
2019-12-28 00:55:11 +00:00
if( SEARCH_RESULT::QUIT == aInspector( this, aTestData ) )
return SEARCH_RESULT::QUIT;
}
2019-05-08 18:56:03 +00:00
if( stype == SCH_LOCATE_ANY_T || stype == SCH_FIELD_T )
{
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
{
2020-03-06 20:02:58 +00:00
if( SEARCH_RESULT::QUIT == aInspector( &field, (void*) this ) )
2019-12-28 00:55:11 +00:00
return SEARCH_RESULT::QUIT;
}
2019-05-08 18:56:03 +00:00
}
if( stype == SCH_FIELD_LOCATE_REFERENCE_T )
2019-05-08 18:56:03 +00:00
{
2020-11-12 21:31:41 +00:00
if( SEARCH_RESULT::QUIT == aInspector( GetField( REFERENCE_FIELD ), (void*) this ) )
2019-12-28 00:55:11 +00:00
return SEARCH_RESULT::QUIT;
2019-05-08 18:56:03 +00:00
}
if( stype == SCH_FIELD_LOCATE_VALUE_T
2021-06-10 14:10:55 +00:00
|| ( stype == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
2019-05-08 18:56:03 +00:00
{
2020-11-12 21:31:41 +00:00
if( SEARCH_RESULT::QUIT == aInspector( GetField( VALUE_FIELD ), (void*) this ) )
2019-12-28 00:55:11 +00:00
return SEARCH_RESULT::QUIT;
2019-05-08 18:56:03 +00:00
}
if( stype == SCH_FIELD_LOCATE_FOOTPRINT_T )
2019-05-08 18:56:03 +00:00
{
2020-11-12 21:31:41 +00:00
if( SEARCH_RESULT::QUIT == aInspector( GetField( FOOTPRINT_FIELD ), (void*) this ) )
2019-12-28 00:55:11 +00:00
return SEARCH_RESULT::QUIT;
2019-05-08 18:56:03 +00:00
}
if( stype == SCH_FIELD_LOCATE_DATASHEET_T )
2019-05-08 18:56:03 +00:00
{
2020-11-12 21:31:41 +00:00
if( SEARCH_RESULT::QUIT == aInspector( GetField( DATASHEET_FIELD ), (void*) this ) )
2019-12-28 00:55:11 +00:00
return SEARCH_RESULT::QUIT;
2019-05-08 18:56:03 +00:00
}
2019-05-08 18:56:03 +00:00
if( stype == SCH_LOCATE_ANY_T || stype == SCH_PIN_T )
{
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
{
// Collect only pins attached to the current unit and convert.
2021-03-25 21:13:01 +00:00
// others are not associated to this symbol instance
int pin_unit = pin->GetLibPin()->GetUnit();
int pin_convert = pin->GetLibPin()->GetConvert();
if( pin_unit > 0 && pin_unit != GetUnit() )
continue;
if( pin_convert > 0 && pin_convert != GetConvert() )
continue;
if( SEARCH_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
2019-12-28 00:55:11 +00:00
return SEARCH_RESULT::QUIT;
}
}
}
2019-12-28 00:55:11 +00:00
return SEARCH_RESULT::CONTINUE;
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::operator <( const SCH_ITEM& aItem ) const
{
if( Type() != aItem.Type() )
return Type() < aItem.Type();
2021-06-10 14:10:55 +00:00
auto symbol = static_cast<const SCH_SYMBOL*>( &aItem );
EDA_RECT rect = GetBodyAndPinsBoundingBox();
if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
2021-06-10 14:10:55 +00:00
if( m_pos.x != symbol->m_pos.x )
return m_pos.x < symbol->m_pos.x;
2021-06-10 14:10:55 +00:00
if( m_pos.y != symbol->m_pos.y )
return m_pos.y < symbol->m_pos.y;
2020-02-20 12:11:04 +00:00
return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
{
2021-03-25 21:13:01 +00:00
if( GetFieldCount() != aSymbol.GetFieldCount() )
return false;
2020-11-12 21:31:41 +00:00
for( int i = VALUE_FIELD; i < GetFieldCount(); i++ )
{
2021-03-25 21:13:01 +00:00
if( GetFields()[i].GetText().Cmp( aSymbol.GetFields()[i].GetText() ) != 0 )
return false;
}
return true;
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
{
2021-03-25 21:13:01 +00:00
return !( *this == aSymbol );
}
2021-06-10 14:10:55 +00:00
SCH_SYMBOL& SCH_SYMBOL::operator=( const SCH_ITEM& aItem )
{
wxCHECK_MSG( Type() == aItem.Type(), *this,
wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) +
GetClass() );
if( &aItem != this )
{
SCH_ITEM::operator=( aItem );
2021-06-10 14:10:55 +00:00
SCH_SYMBOL* c = (SCH_SYMBOL*) &aItem;
m_lib_id = c->m_lib_id;
2021-06-10 18:51:46 +00:00
LIB_SYMBOL* libSymbol = c->m_part ? new LIB_SYMBOL( *c->m_part.get() ) : nullptr;
m_part.reset( libSymbol );
2020-11-16 13:15:54 +00:00
m_pos = c->m_pos;
m_unit = c->m_unit;
m_convert = c->m_convert;
m_transform = c->m_transform;
m_instanceReferences = c->m_instanceReferences;
2020-11-16 13:15:54 +00:00
m_fields = c->m_fields; // std::vector's assignment operator
2021-03-25 21:13:01 +00:00
// Reparent fields after assignment to new symbol.
2020-11-16 13:15:54 +00:00
for( SCH_FIELD& field : m_fields )
field.SetParent( this );
UpdatePins();
}
return *this;
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::HitTest( const wxPoint& aPosition, int aAccuracy ) const
{
EDA_RECT bBox = GetBodyBoundingBox();
bBox.Inflate( aAccuracy / 2 );
if( bBox.Contains( aPosition ) )
return true;
return false;
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
2020-11-14 18:11:28 +00:00
if( m_flags & STRUCT_DELETED || m_flags & SKIP_STRUCT )
return false;
EDA_RECT rect = aRect;
rect.Inflate( aAccuracy / 2 );
if( aContained )
return rect.Contains( GetBodyBoundingBox() );
return rect.Intersects( GetBodyBoundingBox() );
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::doIsConnected( const wxPoint& aPosition ) const
{
2020-11-16 13:15:54 +00:00
wxPoint new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
for( const auto& pin : m_pins )
{
if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
continue;
// Collect only pins attached to the current unit and convert.
2021-03-25 21:13:01 +00:00
// others are not associated to this symbol instance
int pin_unit = pin->GetLibPin()->GetUnit();
int pin_convert = pin->GetLibPin()->GetConvert();
if( pin_unit > 0 && pin_unit != GetUnit() )
continue;
if( pin_convert > 0 && pin_convert != GetConvert() )
continue;
if( pin->GetLocalPosition() == new_pos )
return true;
}
return false;
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::IsInNetlist() const
{
2019-04-09 01:54:41 +00:00
return m_isInNetlist;
}
2013-09-28 22:53:55 +00:00
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::Plot( PLOTTER* aPlotter ) const
{
if( m_part )
{
LIB_PINS libPins;
m_part->GetPins( libPins, GetUnit(), GetConvert() );
// Copy the source so we can re-orient and translate it.
LIB_SYMBOL tempSymbol( *m_part );
LIB_PINS tempPins;
tempSymbol.GetPins( tempPins, GetUnit(), GetConvert() );
// Copy the pin info from the symbol to the temp pins
for( unsigned i = 0; i < tempPins.size(); ++ i )
{
SCH_PIN* symbolPin = GetPin( libPins[ i ] );
LIB_PIN* tempPin = tempPins[ i ];
tempPin->SetName( symbolPin->GetShownName() );
tempPin->SetType( symbolPin->GetType() );
tempPin->SetShape( symbolPin->GetShape() );
if( symbolPin->IsDangling() )
tempPin->SetFlags( IS_DANGLING );
}
2020-04-14 12:25:00 +00:00
TRANSFORM temp = GetTransform();
aPlotter->StartBlock( nullptr );
tempSymbol.Plot( aPlotter, GetUnit(), GetConvert(), m_pos, temp );
2020-11-16 13:15:54 +00:00
for( SCH_FIELD field : m_fields )
field.Plot( aPlotter );
aPlotter->EndBlock( nullptr );
}
}
void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter ) const
{
if( m_part )
{
LIB_PINS libPins;
m_part->GetPins( libPins, GetUnit(), GetConvert() );
// Copy the source to stay const
LIB_SYMBOL tempSymbol( *m_part );
LIB_PINS tempPins;
tempSymbol.GetPins( tempPins, GetUnit(), GetConvert() );
TRANSFORM transform = GetTransform();
// Copy the pin info from the symbol to the temp pins
for( unsigned i = 0; i < tempPins.size(); ++ i )
{
SCH_PIN* symbolPin = GetPin( libPins[ i ] );
LIB_PIN* tempPin = tempPins[ i ];
tempPin->SetName( symbolPin->GetShownName() );
tempPin->SetType( symbolPin->GetType() );
tempPin->SetShape( symbolPin->GetShape() );
tempPin->Plot( aPlotter, m_pos, false, transform);
}
}
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::HasBrightenedPins()
{
for( const auto& pin : m_pins )
{
if( pin->IsBrightened() )
return true;
}
return false;
}
2021-06-10 14:10:55 +00:00
void SCH_SYMBOL::ClearBrightenedPins()
{
for( auto& pin : m_pins )
pin->ClearBrightened();
}
2021-06-10 14:10:55 +00:00
bool SCH_SYMBOL::IsPointClickableAnchor( const wxPoint& aPos ) const
{
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
{
int pin_unit = pin->GetLibPin()->GetUnit();
int pin_convert = pin->GetLibPin()->GetConvert();
if( pin_unit > 0 && pin_unit != GetUnit() )
continue;
if( pin_convert > 0 && pin_convert != GetConvert() )
continue;
if( pin->IsPointClickableAnchor( aPos ) )
return true;
}
return false;
}