kicad-source/pcbnew/pcb_field.cpp
Seth Hillbrand afec66d478 Fix usage of PCB_FIELD( PCB_TEXT& )
Passing a pointer to the CTOR invokes the PCB_FIELD( BOARD_ITEM* ) ctor,
which is not what is intended.  Passing just the reference is better but
still ends up creating a PCB_FIELD class with type PCB_TEXT because it
didn't correctly set the type.  So we need to properly set our type and
our parent, then copy the text attributes over.  We can't use the
default copy operator because this also copies the struct_id of PCB_TEXT

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20875

(cherry picked from commit 750dbe633675acef64427383b7fc777e2c945b1d)
2025-05-13 17:51:08 -07:00

307 lines
8.4 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 Mike Williams, mike@mikebwilliams.com
* Copyright The 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
*/
#include <pcb_field.h>
#include <footprint.h>
#include <board_design_settings.h>
#include <i18n_utility.h>
#include <pcb_painter.h>
#include <api/board/board_types.pb.h>
#include <string_utils.h>
PCB_FIELD::PCB_FIELD( FOOTPRINT* aParent, int aFieldId, const wxString& aName ) :
PCB_TEXT( aParent, PCB_FIELD_T ),
m_id( aFieldId ),
m_name( aName )
{
}
PCB_FIELD::PCB_FIELD( const PCB_TEXT& aText, int aFieldId, const wxString& aName ) :
PCB_TEXT( aText.GetParent(), PCB_FIELD_T ),
m_id( aFieldId ),
m_name( aName )
{
// Copy the text properties from the PCB_TEXT
SetText( aText.GetText() );
SetVisible( aText.IsVisible() );
SetLayer( aText.GetLayer() );
SetPosition( aText.GetPosition() );
SetAttributes( aText.GetAttributes() );
}
void PCB_FIELD::Serialize( google::protobuf::Any &aContainer ) const
{
kiapi::board::types::Field field;
google::protobuf::Any anyText;
PCB_TEXT::Serialize( anyText );
anyText.UnpackTo( field.mutable_text() );
field.set_name( GetCanonicalName().ToStdString() );
field.mutable_id()->set_id( GetId() );
field.set_visible( IsVisible() );
aContainer.PackFrom( field );
}
bool PCB_FIELD::Deserialize( const google::protobuf::Any &aContainer )
{
kiapi::board::types::Field field;
if( !aContainer.UnpackTo( &field ) )
return false;
if( field.has_id() )
setId( field.id().id() );
// Mandatory fields have a blank Name in the KiCad object
if( !IsMandatory() )
SetName( wxString( field.name().c_str(), wxConvUTF8 ) );
if( field.has_text() )
{
google::protobuf::Any anyText;
anyText.PackFrom( field.text() );
PCB_TEXT::Deserialize( anyText );
}
SetVisible( field.visible() );
if( field.text().layer() == kiapi::board::types::BoardLayer::BL_UNKNOWN )
SetLayer( F_SilkS );
return true;
}
wxString PCB_FIELD::GetName( bool aUseDefaultName ) const
{
if( m_parent && m_parent->Type() == PCB_FOOTPRINT_T )
{
if( IsMandatory() )
return GetCanonicalFieldName( m_id );
else if( m_name.IsEmpty() && aUseDefaultName )
return GetUserFieldName( m_id, !DO_TRANSLATE );
else
return m_name;
}
else
{
wxFAIL_MSG( "Unhandled field owner type." );
return m_name;
}
}
wxString PCB_FIELD::GetCanonicalName() const
{
if( m_parent && m_parent->Type() == PCB_FOOTPRINT_T )
{
if( IsMandatory() )
return GetCanonicalFieldName( m_id );
else
return m_name;
}
else
{
if( m_parent )
{
wxFAIL_MSG( wxString::Format( "Unhandled field owner type (id %d, parent type %d).",
m_id, m_parent->Type() ) );
}
return m_name;
}
}
bool PCB_FIELD::IsMandatory() const
{
return m_id == REFERENCE_FIELD
|| m_id == VALUE_FIELD
|| m_id == DATASHEET_FIELD
|| m_id == DESCRIPTION_FIELD;
}
bool PCB_FIELD::IsHypertext() const
{
return IsURL( GetShownText( false ) );
}
wxString PCB_FIELD::GetTextTypeDescription() const
{
if( IsMandatory() )
return GetCanonicalFieldName( m_id );
else
return _( "User Field" );
}
bool PCB_FIELD::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
{
if( !IsVisible() && !aSearchData.searchAllFields )
return false;
return PCB_TEXT::Matches( aSearchData, aAuxData );
}
wxString PCB_FIELD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
{
wxString content = aFull ? GetShownText( false ) : KIUI::EllipsizeMenuText( GetText() );
wxString ref = GetParentFootprint()->GetReference();
switch( m_id )
{
case REFERENCE_FIELD:
return wxString::Format( _( "Reference field of %s" ), ref );
case VALUE_FIELD:
return wxString::Format( _( "Value field of %s (%s)" ), ref, content );
case FOOTPRINT_FIELD:
return wxString::Format( _( "Footprint field of %s (%s)" ), ref, content );
case DATASHEET_FIELD:
return wxString::Format( _( "Datasheet field of %s (%s)" ), ref, content );
default:
if( GetName().IsEmpty() )
return wxString::Format( _( "Field of %s (%s)" ), ref, content );
else
return wxString::Format( _( "%s field of %s (%s)" ), GetName(), ref, content );
}
}
double PCB_FIELD::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
{
if( !aView )
return LOD_SHOW;
KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( aView->GetPainter() );
KIGFX::PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
if( GetParentFootprint() && GetParentFootprint()->IsSelected()
&& renderSettings->m_ForceShowFieldsWhenFPSelected )
{
return LOD_SHOW;
}
// Handle Render tab switches
if( IsValue() && !aView->IsLayerVisible( LAYER_FP_VALUES ) )
return LOD_HIDE;
if( IsReference() && !aView->IsLayerVisible( LAYER_FP_REFERENCES ) )
return LOD_HIDE;
return PCB_TEXT::ViewGetLOD( aLayer, aView );
}
EDA_ITEM* PCB_FIELD::Clone() const
{
return new PCB_FIELD( *this );
}
void PCB_FIELD::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_FIELD_T );
std::swap( *((PCB_FIELD*) this), *((PCB_FIELD*) aImage) );
}
bool PCB_FIELD::operator==( const BOARD_ITEM& aOther ) const
{
if( aOther.Type() != Type() )
return false;
const PCB_FIELD& other = static_cast<const PCB_FIELD&>( aOther );
return *this == other;
}
bool PCB_FIELD::operator==( const PCB_FIELD& aOther ) const
{
return m_id == aOther.m_id && m_name == aOther.m_name && EDA_TEXT::operator==( aOther );
}
double PCB_FIELD::Similarity( const BOARD_ITEM& aOther ) const
{
if( m_Uuid == aOther.m_Uuid )
return 1.0;
if( aOther.Type() != Type() )
return 0.0;
const PCB_FIELD& other = static_cast<const PCB_FIELD&>( aOther );
if( IsMandatory() || other.IsMandatory() )
{
if( m_id == other.m_id )
return 1.0;
else
return 0.0;
}
if( m_name == other.m_name )
return 1.0;
return EDA_TEXT::Similarity( other );
}
static struct PCB_FIELD_DESC
{
PCB_FIELD_DESC()
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
REGISTER_TYPE( PCB_FIELD );
propMgr.AddTypeCast( new TYPE_CAST<PCB_FIELD, PCB_TEXT> );
propMgr.AddTypeCast( new TYPE_CAST<PCB_FIELD, BOARD_ITEM> );
propMgr.AddTypeCast( new TYPE_CAST<PCB_FIELD, EDA_TEXT> );
propMgr.InheritsAfter( TYPE_HASH( PCB_FIELD ), TYPE_HASH( BOARD_ITEM ) );
propMgr.InheritsAfter( TYPE_HASH( PCB_FIELD ), TYPE_HASH( PCB_TEXT ) );
propMgr.InheritsAfter( TYPE_HASH( PCB_FIELD ), TYPE_HASH( EDA_TEXT ) );
propMgr.AddProperty( new PROPERTY<PCB_FIELD, wxString>( _HKI( "Name" ),
NO_SETTER( PCB_FIELD, wxString ), &PCB_FIELD::GetCanonicalName ) )
.SetIsHiddenFromLibraryEditors()
.SetIsHiddenFromPropertiesManager();
// These properties, inherited from EDA_TEXT, have no sense for the board editor
propMgr.Mask( TYPE_HASH( PCB_FIELD ), TYPE_HASH( EDA_TEXT ), _HKI( "Hyperlink" ) );
propMgr.Mask( TYPE_HASH( PCB_FIELD ), TYPE_HASH( EDA_TEXT ), _HKI( "Color" ) );
}
} _PCB_FIELD_DESC;