2023-05-24 07:43:32 -04:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2023 Mike Williams, mike@mikebwilliams.com
|
2025-01-01 13:30:11 -08:00
|
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
2023-05-24 07:43:32 -04:00
|
|
|
*
|
|
|
|
* 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>
|
2023-05-24 08:39:25 -04:00
|
|
|
#include <footprint.h>
|
|
|
|
#include <board_design_settings.h>
|
2023-06-13 12:56:24 -04:00
|
|
|
#include <i18n_utility.h>
|
2023-08-20 17:08:51 +01:00
|
|
|
#include <pcb_painter.h>
|
2024-01-20 18:35:29 -05:00
|
|
|
#include <api/board/board_types.pb.h>
|
2025-02-17 12:13:28 +00:00
|
|
|
#include <string_utils.h>
|
2024-01-20 18:35:29 -05:00
|
|
|
|
2023-05-24 07:43:32 -04:00
|
|
|
|
2025-02-08 13:45:57 +00:00
|
|
|
PCB_FIELD::PCB_FIELD( FOOTPRINT* aParent, FIELD_T aFieldId, const wxString& aName ) :
|
2023-07-07 22:42:29 +01:00
|
|
|
PCB_TEXT( aParent, PCB_FIELD_T ),
|
|
|
|
m_id( aFieldId ),
|
2025-02-24 15:11:05 -08:00
|
|
|
m_ordinal( static_cast<int>( aFieldId ) ),
|
2023-07-07 22:42:29 +01:00
|
|
|
m_name( aName )
|
2023-05-24 07:43:32 -04:00
|
|
|
{
|
2025-02-08 13:45:57 +00:00
|
|
|
if( m_id == FIELD_T::USER )
|
|
|
|
m_ordinal = aParent->GetNextFieldOrdinal();
|
2025-02-24 17:39:38 -05:00
|
|
|
else
|
|
|
|
m_ordinal = 0;
|
2023-05-24 07:43:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-08 13:45:57 +00:00
|
|
|
PCB_FIELD::PCB_FIELD( const PCB_TEXT& aText, FIELD_T aFieldId, const wxString& aName ) :
|
2023-07-07 22:42:29 +01:00
|
|
|
PCB_TEXT( aText ),
|
|
|
|
m_id( aFieldId ),
|
2025-02-24 15:11:05 -08:00
|
|
|
m_ordinal( static_cast<int>( aFieldId ) ),
|
2023-07-07 22:42:29 +01:00
|
|
|
m_name( aName )
|
2023-05-24 07:43:32 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-05-24 08:39:25 -04:00
|
|
|
|
2024-01-20 18:35:29 -05:00
|
|
|
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() );
|
2025-02-08 13:45:57 +00:00
|
|
|
field.mutable_id()->set_id( (int) GetId() );
|
2025-02-11 12:55:33 +00:00
|
|
|
field.set_visible( IsVisible() );
|
2024-01-20 18:35:29 -05:00
|
|
|
|
|
|
|
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() )
|
2025-02-08 13:45:57 +00:00
|
|
|
setId( (FIELD_T) field.id().id() );
|
2024-01-20 18:35:29 -05:00
|
|
|
|
|
|
|
// Mandatory fields have a blank Name in the KiCad object
|
2025-01-22 14:26:57 +00:00
|
|
|
if( !IsMandatory() )
|
2024-01-20 18:35:29 -05:00
|
|
|
SetName( wxString( field.name().c_str(), wxConvUTF8 ) );
|
|
|
|
|
|
|
|
if( field.has_text() )
|
|
|
|
{
|
|
|
|
google::protobuf::Any anyText;
|
|
|
|
anyText.PackFrom( field.text() );
|
|
|
|
PCB_TEXT::Deserialize( anyText );
|
|
|
|
}
|
|
|
|
|
2025-02-11 12:55:33 +00:00
|
|
|
SetVisible( field.visible() );
|
|
|
|
|
2024-01-20 18:35:29 -05:00
|
|
|
if( field.text().layer() == kiapi::board::types::BoardLayer::BL_UNKNOWN )
|
|
|
|
SetLayer( F_SilkS );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-24 07:43:32 -04:00
|
|
|
wxString PCB_FIELD::GetName( bool aUseDefaultName ) const
|
|
|
|
{
|
2025-02-08 13:45:57 +00:00
|
|
|
if( IsMandatory() )
|
|
|
|
return GetCanonicalFieldName( m_id );
|
|
|
|
else if( m_name.IsEmpty() && aUseDefaultName )
|
|
|
|
return GetUserFieldName( m_ordinal, !DO_TRANSLATE );
|
2023-05-24 07:43:32 -04:00
|
|
|
else
|
|
|
|
return m_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
wxString PCB_FIELD::GetCanonicalName() const
|
|
|
|
{
|
2025-02-08 13:45:57 +00:00
|
|
|
return GetName( true );
|
2023-05-24 07:43:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-01-22 14:26:57 +00:00
|
|
|
bool PCB_FIELD::IsMandatory() const
|
|
|
|
{
|
2025-02-08 13:45:57 +00:00
|
|
|
return m_id == FIELD_T::REFERENCE
|
|
|
|
|| m_id == FIELD_T::VALUE
|
|
|
|
|| m_id == FIELD_T::DATASHEET
|
|
|
|
|| m_id == FIELD_T::DESCRIPTION;
|
2025-01-22 14:26:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-17 12:13:28 +00:00
|
|
|
bool PCB_FIELD::IsHypertext() const
|
|
|
|
{
|
|
|
|
return IsURL( GetShownText( false ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-06-06 13:30:03 -04:00
|
|
|
wxString PCB_FIELD::GetTextTypeDescription() const
|
2023-05-24 07:43:32 -04:00
|
|
|
{
|
2025-01-22 14:26:57 +00:00
|
|
|
if( IsMandatory() )
|
2025-01-21 16:48:13 +00:00
|
|
|
return GetCanonicalFieldName( m_id );
|
2023-06-19 13:08:18 -04:00
|
|
|
else
|
|
|
|
return _( "User Field" );
|
2023-06-06 13:30:03 -04:00
|
|
|
}
|
2023-05-24 07:43:32 -04:00
|
|
|
|
2023-06-06 13:30:03 -04:00
|
|
|
|
2024-06-27 10:11:55 +01:00
|
|
|
wxString PCB_FIELD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
|
2023-06-06 13:30:03 -04:00
|
|
|
{
|
2024-06-27 10:11:55 +01:00
|
|
|
wxString content = aFull ? GetShownText( false ) : KIUI::EllipsizeMenuText( GetText() );
|
|
|
|
wxString ref = GetParentFootprint()->GetReference();
|
|
|
|
|
2023-06-06 13:30:03 -04:00
|
|
|
switch( m_id )
|
2023-05-24 07:43:32 -04:00
|
|
|
{
|
2025-02-08 13:45:57 +00:00
|
|
|
case FIELD_T::REFERENCE:
|
2024-06-27 10:11:55 +01:00
|
|
|
return wxString::Format( _( "Reference field of %s" ), ref );
|
2023-06-06 13:30:03 -04:00
|
|
|
|
2025-02-08 13:45:57 +00:00
|
|
|
case FIELD_T::VALUE:
|
2024-06-27 10:11:55 +01:00
|
|
|
return wxString::Format( _( "Value field of %s (%s)" ), ref, content );
|
2023-06-06 13:30:03 -04:00
|
|
|
|
2025-02-08 13:45:57 +00:00
|
|
|
case FIELD_T::FOOTPRINT:
|
2024-06-27 10:11:55 +01:00
|
|
|
return wxString::Format( _( "Footprint field of %s (%s)" ), ref, content );
|
|
|
|
|
2025-02-08 13:45:57 +00:00
|
|
|
case FIELD_T::DATASHEET:
|
2024-06-27 10:11:55 +01:00
|
|
|
return wxString::Format( _( "Datasheet field of %s (%s)" ), ref, content );
|
2023-07-16 15:40:44 +02:00
|
|
|
|
2023-09-14 14:39:42 -07:00
|
|
|
default:
|
2024-06-27 10:11:55 +01:00
|
|
|
if( GetName().IsEmpty() )
|
|
|
|
return wxString::Format( _( "Field of %s (%s)" ), ref, content );
|
|
|
|
else
|
|
|
|
return wxString::Format( _( "%s field of %s (%s)" ), GetName(), ref, content );
|
2023-05-24 07:43:32 -04:00
|
|
|
}
|
2023-06-06 13:30:03 -04:00
|
|
|
}
|
|
|
|
|
2023-07-07 22:42:29 +01:00
|
|
|
|
2025-01-02 19:24:39 +08:00
|
|
|
double PCB_FIELD::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
|
2023-06-06 13:30:03 -04:00
|
|
|
{
|
|
|
|
if( !aView )
|
2025-01-02 05:52:01 +08:00
|
|
|
return LOD_SHOW;
|
2023-06-06 13:30:03 -04:00
|
|
|
|
2023-08-20 17:08:51 +01:00
|
|
|
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 )
|
|
|
|
{
|
2025-01-02 05:52:01 +08:00
|
|
|
return LOD_SHOW;
|
2023-08-20 17:08:51 +01:00
|
|
|
}
|
|
|
|
|
2023-06-06 13:30:03 -04:00
|
|
|
// Handle Render tab switches
|
2023-08-04 11:13:20 +01:00
|
|
|
if( IsValue() && !aView->IsLayerVisible( LAYER_FP_VALUES ) )
|
2025-01-02 05:52:01 +08:00
|
|
|
return LOD_HIDE;
|
2023-06-06 13:30:03 -04:00
|
|
|
|
2023-08-04 11:13:20 +01:00
|
|
|
if( IsReference() && !aView->IsLayerVisible( LAYER_FP_REFERENCES ) )
|
2025-01-02 05:52:01 +08:00
|
|
|
return LOD_HIDE;
|
2023-06-06 13:30:03 -04:00
|
|
|
|
|
|
|
return PCB_TEXT::ViewGetLOD( aLayer, aView );
|
2023-05-24 07:43:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EDA_ITEM* PCB_FIELD::Clone() const
|
|
|
|
{
|
|
|
|
return new PCB_FIELD( *this );
|
|
|
|
}
|
2023-06-12 11:55:27 -04:00
|
|
|
|
|
|
|
|
2024-01-27 23:15:53 +00:00
|
|
|
void PCB_FIELD::swapData( BOARD_ITEM* aImage )
|
|
|
|
{
|
|
|
|
assert( aImage->Type() == PCB_FIELD_T );
|
|
|
|
|
|
|
|
std::swap( *((PCB_FIELD*) this), *((PCB_FIELD*) aImage) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-09-14 14:39:42 -07:00
|
|
|
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 );
|
|
|
|
|
2024-04-12 23:05:00 -04:00
|
|
|
return *this == other;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCB_FIELD::operator==( const PCB_FIELD& aOther ) const
|
|
|
|
{
|
2025-02-08 13:45:57 +00:00
|
|
|
return m_id == aOther.m_id
|
|
|
|
&& m_ordinal == aOther.m_ordinal
|
|
|
|
&& m_name == aOther.m_name
|
|
|
|
&& EDA_TEXT::operator==( aOther );
|
2023-09-14 14:39:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
2025-01-22 14:26:57 +00:00
|
|
|
if( IsMandatory() || other.IsMandatory() )
|
2023-09-14 14:39:42 -07:00
|
|
|
{
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2023-06-12 11:55:27 -04:00
|
|
|
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 ) );
|
2023-06-13 12:56:24 -04:00
|
|
|
|
2025-02-17 20:25:07 +00:00
|
|
|
propMgr.AddProperty( new PROPERTY<PCB_FIELD, wxString>( _HKI( "Name" ),
|
|
|
|
NO_SETTER( PCB_FIELD, wxString ), &PCB_FIELD::GetCanonicalName ) )
|
|
|
|
.SetIsHiddenFromLibraryEditors()
|
|
|
|
.SetIsHiddenFromPropertiesManager();
|
|
|
|
|
2024-07-14 11:48:11 +02:00
|
|
|
// 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" ) );
|
2023-06-12 11:55:27 -04:00
|
|
|
}
|
|
|
|
} _PCB_FIELD_DESC;
|