7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 21:43:43 +00:00

API: Move graphics and text handling to common

Required moving API_HANDLER_COMMON out of kicommon
This commit is contained in:
Jon Evans 2024-11-26 20:53:04 -05:00
parent 013f66adb4
commit 3129e072c4
25 changed files with 592 additions and 310 deletions

View File

@ -123,13 +123,6 @@ message RefillZones
* Utilities
*/
// returns kiapi.common.types.Box2
message GetTextExtents
{
// A temporary text item to calculate the bounding box for
kiapi.board.types.Text text = 1;
}
// Computes the polygon representation of a pad, merging any custom shapes together.
// This representation will approximate curves as a series of segments.
message GetPadShapeAsPolygon

View File

@ -376,20 +376,25 @@ message BoardGraphicShape
kiapi.common.types.GraphicShape shape = 1;
BoardLayer layer = 2;
Net net = 3;
kiapi.common.types.KIID id = 4;
kiapi.common.types.LockedState locked = 5;
}
// A board-specific text object, existing on a board layer
message Text
message BoardText
{
kiapi.common.types.Text text = 1;
BoardLayer layer = 2;
kiapi.common.types.KIID id = 1;
kiapi.common.types.Text text = 2;
BoardLayer layer = 3;
bool knockout = 4;
}
// A board-specific textbox, existing on a board layer
message TextBox
message BoardTextBox
{
kiapi.common.types.TextBox textbox = 1;
BoardLayer layer = 2;
kiapi.common.types.KIID id = 1;
kiapi.common.types.TextBox textbox = 2;
BoardLayer layer = 3;
}
// NOTE: There has been some discussion about what to do with pad attributes and properties.
@ -616,7 +621,7 @@ message Field
{
FieldId id = 1;
string name = 2;
Text text = 3;
BoardText text = 3;
}
message Model3D

View File

@ -36,3 +36,30 @@ message GetVersionResponse
message Ping
{
}
// returns kiapi.common.types.Box2
message GetTextExtents
{
// A temporary text item to calculate the bounding box for
kiapi.common.types.Text text = 1;
}
// Render the given text object(s) as shapes. Depending on whether the text is using
// the KiCad stroke font or a custom font, the response will be a compound shape containing
// a set of polygons or a set of segments.
message GetTextAsShapes
{
repeated kiapi.common.types.Text text = 1;
}
message TextWithShapes
{
kiapi.common.types.Text text = 1;
kiapi.common.types.CompoundShape shapes = 2;
}
message GetTextAsShapesResponse
{
repeated TextWithShapes text_with_shapes = 1;
}

View File

@ -299,18 +299,17 @@ message TextAttributes
message Text
{
kiapi.common.types.KIID id = 1;
// Reserved for future use; base text objects don't have IDs right now
// kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 position = 2;
kiapi.common.types.TextAttributes attributes = 3;
kiapi.common.types.LockedState locked = 4;
string text = 5;
string hyperlink = 6;
bool knockout = 7;
}
message TextBox
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 top_left = 2;
kiapi.common.types.Vector2 bottom_right = 3;
kiapi.common.types.TextAttributes attributes = 4;
@ -384,8 +383,9 @@ message GraphicBezierAttributes
message GraphicShape
{
KIID id = 1;
LockedState locked = 2;
// Reserved for future use; base EDA_SHAPE doesn't have an ID or locked state right now
// KIID id = 1;
// LockedState locked = 2;
GraphicAttributes attributes = 3;
oneof geometry {

View File

@ -57,6 +57,7 @@ set( KICOMMON_SRCS
newstroke_font.cpp
font/fontconfig.cpp
font/version_info.cpp
# Gal
gal/color4d.cpp
# Jobs
@ -189,13 +190,14 @@ set( KICOMMON_SRCS
io/kicad/kicad_io_utils.cpp # needed by richio
io/io_base.cpp
io/io_utils.cpp
api/serializable.cpp
)
if( KICAD_IPC_API )
set( KICOMMON_SRCS
${KICOMMON_SRCS}
api/api_handler.cpp
api/api_handler_common.cpp
api/api_plugin.cpp
api/api_plugin_manager.cpp
api/api_server.cpp
@ -670,6 +672,7 @@ set( COMMON_SRCS
if( KICAD_IPC_API )
set( COMMON_SRCS
${COMMON_SRCS}
api/api_handler_common.cpp
api/api_handler_editor.cpp
)
endif()

View File

@ -22,6 +22,9 @@
#include <api/api_handler_common.h>
#include <build_version.h>
#include <eda_shape.h>
#include <eda_text.h>
#include <geometry/shape_compound.h>
#include <google/protobuf/empty.pb.h>
#include <pgm_base.h>
#include <project/net_settings.h>
@ -40,6 +43,9 @@ API_HANDLER_COMMON::API_HANDLER_COMMON() :
registerHandler<commands::GetVersion, GetVersionResponse>( &API_HANDLER_COMMON::handleGetVersion );
registerHandler<GetNetClasses, NetClassesResponse>( &API_HANDLER_COMMON::handleGetNetClasses );
registerHandler<Ping, Empty>( &API_HANDLER_COMMON::handlePing );
registerHandler<GetTextExtents, types::Box2>( &API_HANDLER_COMMON::handleGetTextExtents );
registerHandler<GetTextAsShapes, GetTextAsShapesResponse>(
&API_HANDLER_COMMON::handleGetTextAsShapes );
}
@ -80,3 +86,71 @@ HANDLER_RESULT<Empty> API_HANDLER_COMMON::handlePing( Ping& aMsg, const HANDLER_
{
return Empty();
}
HANDLER_RESULT<types::Box2> API_HANDLER_COMMON::handleGetTextExtents( GetTextExtents& aMsg,
const HANDLER_CONTEXT& aCtx )
{
EDA_TEXT text( pcbIUScale );
google::protobuf::Any any;
any.PackFrom( aMsg.text() );
if( !text.Deserialize( any ) )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( "Could not decode text in GetTextExtents message" );
return tl::unexpected( e );
}
types::Box2 response;
BOX2I bbox = text.GetTextBox();
EDA_ANGLE angle = text.GetTextAngle();
if( !angle.IsZero() )
bbox = bbox.GetBoundingBoxRotated( text.GetTextPos(), text.GetTextAngle() );
response.mutable_position()->set_x_nm( bbox.GetPosition().x );
response.mutable_position()->set_y_nm( bbox.GetPosition().y );
response.mutable_size()->set_x_nm( bbox.GetSize().x );
response.mutable_size()->set_y_nm( bbox.GetSize().y );
return response;
}
HANDLER_RESULT<GetTextAsShapesResponse> API_HANDLER_COMMON::handleGetTextAsShapes(
GetTextAsShapes& aMsg, const HANDLER_CONTEXT& aCtx )
{
GetTextAsShapesResponse reply;
for( const Text& textMsg : aMsg.text() )
{
EDA_TEXT text( pcbIUScale );
google::protobuf::Any any;
any.PackFrom( textMsg );
if( !text.Deserialize( any ) )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( "Could not decode text in GetTextAsShapes message" );
return tl::unexpected( e );
}
std::shared_ptr<SHAPE_COMPOUND> shapes = text.GetEffectiveTextShape( false );
TextWithShapes* entry = reply.add_text_with_shapes();
entry->mutable_text()->CopyFrom( textMsg );
for( SHAPE* subshape : shapes->Shapes() )
{
EDA_SHAPE proxy( *subshape );
proxy.Serialize( any );
any.UnpackTo( entry->mutable_shapes() );
}
}
return reply;
}

View File

@ -18,15 +18,16 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fmt/format.h>
#include <wx/app.h>
#include <wx/datetime.h>
#include <wx/event.h>
#include <wx/stdpaths.h>
#include <advanced_config.h>
#include <api/api_handler.h>
#include <api/api_plugin_manager.h> // traceApi
#include <api/api_server.h>
#include <api/api_handler_common.h>
#include <kiid.h>
#include <kinng.h>
#include <paths.h>
@ -50,9 +51,6 @@ KICAD_API_SERVER::KICAD_API_SERVER() :
m_token( KIID().AsStdString() ),
m_readyToReply( false )
{
m_commonHandler = std::make_unique<API_HANDLER_COMMON>();
RegisterHandler( m_commonHandler.get() );
if( !Pgm().GetCommonSettings()->m_Api.enable_server )
{
wxLogTrace( traceApi, "Server: disabled by user preferences." );

View File

@ -31,8 +31,8 @@ std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage )
{ "type.googleapis.com/kiapi.board.types.Track", PCB_TRACE_T },
{ "type.googleapis.com/kiapi.board.types.Arc", PCB_ARC_T },
{ "type.googleapis.com/kiapi.board.types.Via", PCB_VIA_T },
{ "type.googleapis.com/kiapi.board.types.Text", PCB_TEXT_T },
{ "type.googleapis.com/kiapi.board.types.TextBox", PCB_TEXTBOX_T },
{ "type.googleapis.com/kiapi.board.types.BoardText", PCB_TEXT_T },
{ "type.googleapis.com/kiapi.board.types.BoardTextBox", PCB_TEXTBOX_T },
{ "type.googleapis.com/kiapi.board.types.BoardGraphicShape", PCB_SHAPE_T },
{ "type.googleapis.com/kiapi.board.types.Pad", PCB_PAD_T },
{ "type.googleapis.com/kiapi.board.types.Zone", PCB_ZONE_T },

View File

@ -0,0 +1,34 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 Jon Evans <jon@craftyjon.com>
* Copyright (C) 2024 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <api/serializable.h>
void SERIALIZABLE::Serialize( google::protobuf::Any &aContainer ) const
{
wxASSERT_MSG( false, wxS( "Serialize called on an object that doesn't implement it!" ) );
}
bool SERIALIZABLE::Deserialize( const google::protobuf::Any &aContainer )
{
wxASSERT_MSG( false, wxS( "Deserialize called on an object that doesn't implement it!" ) );
return false;
}

View File

@ -30,13 +30,18 @@
#include <bezier_curves.h>
#include <convert_basic_shapes_to_polygon.h>
#include <eda_draw_frame.h>
#include <geometry/shape_arc.h>
#include <geometry/shape_circle.h>
#include <geometry/shape_simple.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_circle.h>
#include <geometry/shape_rect.h>
#include <macros.h>
#include <math/util.h> // for KiROUND
#include <eda_item.h>
#include <plotters/plotter.h>
#include <api/api_enums.h>
#include <api/api_utils.h>
#include <api/common/types/base_types.pb.h>
EDA_SHAPE::EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill ) :
@ -59,6 +64,252 @@ EDA_SHAPE::~EDA_SHAPE()
}
EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) :
m_endsSwapped( false ),
m_stroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
m_fill(),
m_rectangleHeight( 0 ),
m_rectangleWidth( 0 ),
m_segmentLength( 0 ),
m_editState( 0 ),
m_proxyItem( false )
{
switch( aShape.Type() )
{
case SH_RECT:
{
auto rect = static_cast<const SHAPE_RECT&>( aShape );
m_shape = SHAPE_T::RECTANGLE;
SetStart( rect.GetPosition() );
SetEnd( rect.GetPosition() + rect.GetSize() );
break;
}
case SH_SEGMENT:
{
auto seg = static_cast<const SHAPE_SEGMENT&>( aShape );
m_shape = SHAPE_T::SEGMENT;
SetStart( seg.GetSeg().A );
SetEnd( seg.GetSeg().B );
SetWidth( seg.GetWidth() );
break;
}
case SH_LINE_CHAIN:
{
auto line = static_cast<const SHAPE_LINE_CHAIN&>( aShape );
m_shape = SHAPE_T::POLY;
m_poly = SHAPE_POLY_SET();
m_poly.AddOutline( line );
SetWidth( line.Width() );
break;
}
case SH_CIRCLE:
{
auto circle = static_cast<const SHAPE_CIRCLE&>( aShape );
m_shape = SHAPE_T::CIRCLE;
SetStart( circle.GetCenter() );
SetEnd( circle.GetCenter() + circle.GetRadius() );
break;
}
case SH_ARC:
{
auto arc = static_cast<const SHAPE_ARC&>( aShape );
m_shape = SHAPE_T::ARC;
SetArcGeometry( arc.GetP0(), arc.GetArcMid(), arc.GetP1() );
SetWidth( arc.GetWidth() );
break;
}
case SH_SIMPLE:
{
auto poly = static_cast<const SHAPE_SIMPLE&>( aShape );
m_shape = SHAPE_T::POLY;
poly.TransformToPolygon( m_poly, 0, ERROR_INSIDE );
break;
}
// currently unhandled
case SH_POLY_SET:
case SH_COMPOUND:
case SH_NULL:
case SH_POLY_SET_TRIANGLE:
default:
m_shape = SHAPE_T::UNDEFINED;
break;
}
}
void EDA_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
{
using namespace kiapi::common;
types::GraphicShape shape;
types::StrokeAttributes* stroke = shape.mutable_attributes()->mutable_stroke();
types::GraphicFillAttributes* fill = shape.mutable_attributes()->mutable_fill();
stroke->mutable_width()->set_value_nm( GetWidth() );
switch( GetLineStyle() )
{
case LINE_STYLE::DEFAULT: stroke->set_style( types::SLS_DEFAULT ); break;
case LINE_STYLE::SOLID: stroke->set_style( types::SLS_SOLID ); break;
case LINE_STYLE::DASH: stroke->set_style( types::SLS_DASH ); break;
case LINE_STYLE::DOT: stroke->set_style( types::SLS_DOT ); break;
case LINE_STYLE::DASHDOT: stroke->set_style( types::SLS_DASHDOT ); break;
case LINE_STYLE::DASHDOTDOT: stroke->set_style( types::SLS_DASHDOTDOT ); break;
default: break;
}
switch( GetFillMode() )
{
case FILL_T::FILLED_SHAPE: fill->set_fill_type( types::GFT_FILLED ); break;
default: fill->set_fill_type( types::GFT_UNFILLED ); break;
}
switch( GetShape() )
{
case SHAPE_T::SEGMENT:
{
types::GraphicSegmentAttributes* segment = shape.mutable_segment();
PackVector2( *segment->mutable_start(), GetStart() );
PackVector2( *segment->mutable_end(), GetEnd() );
break;
}
case SHAPE_T::RECTANGLE:
{
types::GraphicRectangleAttributes* rectangle = shape.mutable_rectangle();
PackVector2( *rectangle->mutable_top_left(), GetStart() );
PackVector2( *rectangle->mutable_bottom_right(), GetEnd() );
break;
}
case SHAPE_T::ARC:
{
types::GraphicArcAttributes* arc = shape.mutable_arc();
PackVector2( *arc->mutable_start(), GetStart() );
PackVector2( *arc->mutable_mid(), GetArcMid() );
PackVector2( *arc->mutable_end(), GetEnd() );
break;
}
case SHAPE_T::CIRCLE:
{
types::GraphicCircleAttributes* circle = shape.mutable_circle();
PackVector2( *circle->mutable_center(), GetStart() );
PackVector2( *circle->mutable_radius_point(), GetEnd() );
break;
}
case SHAPE_T::POLY:
{
PackPolySet( *shape.mutable_polygon(), GetPolyShape() );
break;
}
case SHAPE_T::BEZIER:
{
types::GraphicBezierAttributes* bezier = shape.mutable_bezier();
PackVector2( *bezier->mutable_start(), GetStart() );
PackVector2( *bezier->mutable_control1(), GetBezierC1() );
PackVector2( *bezier->mutable_control2(), GetBezierC2() );
PackVector2( *bezier->mutable_end(), GetEnd() );
break;
}
default:
wxASSERT_MSG( false, "Unhandled shape in PCB_SHAPE::Serialize" );
}
// TODO m_hasSolderMask and m_solderMaskMargin
aContainer.PackFrom( shape );
}
bool EDA_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
{
using namespace kiapi::common;
types::GraphicShape shape;
if( !aContainer.UnpackTo( &shape ) )
return false;
// Initialize everything to a known state that doesn't get touched by every
// codepath below, to make sure the equality operator is consistent
m_start = {};
m_end = {};
m_arcCenter = {};
m_arcMidData = {};
m_bezierC1 = {};
m_bezierC2 = {};
m_editState = 0;
m_proxyItem = false;
m_endsSwapped = false;
SetFilled( shape.attributes().fill().fill_type() == types::GFT_FILLED );
SetWidth( shape.attributes().stroke().width().value_nm() );
switch( shape.attributes().stroke().style() )
{
case types::SLS_DEFAULT: SetLineStyle( LINE_STYLE::DEFAULT ); break;
case types::SLS_SOLID: SetLineStyle( LINE_STYLE::SOLID ); break;
case types::SLS_DASH: SetLineStyle( LINE_STYLE::DASH ); break;
case types::SLS_DOT: SetLineStyle( LINE_STYLE::DOT ); break;
case types::SLS_DASHDOT: SetLineStyle( LINE_STYLE::DASHDOT ); break;
case types::SLS_DASHDOTDOT: SetLineStyle( LINE_STYLE::DASHDOTDOT ); break;
default: break;
}
if( shape.has_segment() )
{
SetShape( SHAPE_T::SEGMENT );
SetStart( UnpackVector2( shape.segment().start() ) );
SetEnd( UnpackVector2( shape.segment().end() ) );
}
else if( shape.has_rectangle() )
{
SetShape( SHAPE_T::RECTANGLE );
SetStart( UnpackVector2( shape.rectangle().top_left() ) );
SetEnd( UnpackVector2( shape.rectangle().bottom_right() ) );
}
else if( shape.has_arc() )
{
SetShape( SHAPE_T::ARC );
SetArcGeometry( UnpackVector2( shape.arc().start() ),
UnpackVector2( shape.arc().mid() ),
UnpackVector2( shape.arc().end() ) );
}
else if( shape.has_circle() )
{
SetShape( SHAPE_T::CIRCLE );
SetStart( UnpackVector2( shape.circle().center() ) );
SetEnd( UnpackVector2( shape.circle().radius_point() ) );
}
else if( shape.has_polygon() )
{
SetShape( SHAPE_T::POLY );
SetPolyShape( UnpackPolySet( shape.polygon() ) );
}
else if( shape.has_bezier() )
{
SetShape( SHAPE_T::BEZIER );
SetStart( UnpackVector2( shape.bezier().start() ) );
SetBezierC1( UnpackVector2( shape.bezier().control1() ) );
SetBezierC2( UnpackVector2( shape.bezier().control2() ) );
SetEnd( UnpackVector2( shape.bezier().end() ) );
RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF );
}
return true;
}
wxString EDA_SHAPE::ShowShape() const
{
if( IsProxyItem() )

View File

@ -49,6 +49,9 @@
#include <geometry/shape_poly_set.h>
#include <properties/property_validators.h>
#include <ctl_flags.h> // for CTL_OMIT_HIDE definition
#include <api/api_enums.h>
#include <api/api_utils.h>
#include <api/common/types/base_types.pb.h>
#include <wx/debug.h> // for wxASSERT
#include <wx/string.h>
@ -179,6 +182,89 @@ EDA_TEXT& EDA_TEXT::operator=( const EDA_TEXT& aText )
}
void EDA_TEXT::Serialize( google::protobuf::Any &aContainer ) const
{
using namespace kiapi::common;
types::Text text;
text.set_text( GetText().ToStdString() );
text.set_hyperlink( GetHyperlink().ToStdString() );
types::TextAttributes* attrs = text.mutable_attributes();
if( GetFont() )
attrs->set_font_name( GetFont()->GetName().ToStdString() );
attrs->set_horizontal_alignment(
ToProtoEnum<GR_TEXT_H_ALIGN_T, types::HorizontalAlignment>( GetHorizJustify() ) );
attrs->set_vertical_alignment(
ToProtoEnum<GR_TEXT_V_ALIGN_T, types::VerticalAlignment>( GetVertJustify() ) );
attrs->mutable_angle()->set_value_degrees( GetTextAngleDegrees() );
attrs->set_line_spacing( GetLineSpacing() );
attrs->mutable_stroke_width()->set_value_nm( GetTextThickness() );
attrs->set_italic( IsItalic() );
attrs->set_bold( IsBold() );
attrs->set_underlined( GetAttributes().m_Underlined );
attrs->set_visible( IsVisible() );
attrs->set_mirrored( IsMirrored() );
attrs->set_multiline( IsMultilineAllowed() );
attrs->set_keep_upright( IsKeepUpright() );
attrs->mutable_size()->set_x_nm( GetTextSize().x );
attrs->mutable_size()->set_y_nm( GetTextSize().y );
aContainer.PackFrom( text );
}
bool EDA_TEXT::Deserialize( const google::protobuf::Any &aContainer )
{
using namespace kiapi::common;
types::Text text;
if( !aContainer.UnpackTo( &text ) )
return false;
SetText( wxString( text.text().c_str(), wxConvUTF8 ) );
SetHyperlink( wxString( text.hyperlink().c_str(), wxConvUTF8 ) );
if( text.has_attributes() )
{
TEXT_ATTRIBUTES attrs = GetAttributes();
attrs.m_Bold = text.attributes().bold();
attrs.m_Italic = text.attributes().italic();
attrs.m_Underlined = text.attributes().underlined();
attrs.m_Visible = text.attributes().visible();
attrs.m_Mirrored = text.attributes().mirrored();
attrs.m_Multiline = text.attributes().multiline();
attrs.m_KeepUpright = text.attributes().keep_upright();
attrs.m_Size = VECTOR2I( text.attributes().size().x_nm(), text.attributes().size().y_nm() );
if( !text.attributes().font_name().empty() )
{
attrs.m_Font = KIFONT::FONT::GetFont(
wxString( text.attributes().font_name().c_str(), wxConvUTF8 ), attrs.m_Bold,
attrs.m_Italic );
}
attrs.m_Angle = EDA_ANGLE( text.attributes().angle().value_degrees(), DEGREES_T );
attrs.m_LineSpacing = text.attributes().line_spacing();
attrs.m_StrokeWidth = text.attributes().stroke_width().value_nm();
attrs.m_Halign = FromProtoEnum<GR_TEXT_H_ALIGN_T, types::HorizontalAlignment>(
text.attributes().horizontal_alignment() );
attrs.m_Valign = FromProtoEnum<GR_TEXT_V_ALIGN_T, types::VerticalAlignment>(
text.attributes().vertical_alignment() );
SetAttributes( attrs );
}
return true;
}
void EDA_TEXT::SetText( const wxString& aText )
{
m_text = aText;

View File

@ -27,15 +27,16 @@
#include <api/common/commands/base_commands.pb.h>
#include <api/common/commands/project_commands.pb.h>
using namespace kiapi;
using namespace kiapi::common;
using google::protobuf::Empty;
class KICOMMON_API API_HANDLER_COMMON : public API_HANDLER
class API_HANDLER_COMMON : public API_HANDLER
{
public:
API_HANDLER_COMMON();
~API_HANDLER_COMMON() override {}
private:
HANDLER_RESULT<commands::GetVersionResponse> handleGetVersion( commands::GetVersion& aMsg,
const HANDLER_CONTEXT& aCtx );
@ -44,6 +45,12 @@ private:
const HANDLER_CONTEXT& aCtx );
HANDLER_RESULT<Empty> handlePing( commands::Ping& aMsg, const HANDLER_CONTEXT& aCtx );
HANDLER_RESULT<types::Box2> handleGetTextExtents( commands::GetTextExtents& aMsg,
const HANDLER_CONTEXT& aCtx );
HANDLER_RESULT<commands::GetTextAsShapesResponse>
handleGetTextAsShapes( commands::GetTextAsShapes& aMsg, const HANDLER_CONTEXT& aCtx );
};
#endif //KICAD_API_HANDLER_COMMON_H

View File

@ -31,7 +31,6 @@
#include <kicommon.h>
class API_HANDLER;
class API_HANDLER_COMMON;
class KINNG_REQUEST_SERVER;
class wxEvtHandler;
@ -99,8 +98,6 @@ private:
bool m_readyToReply;
std::unique_ptr<API_HANDLER_COMMON> m_commonHandler;
static wxString s_logFileName;
wxFileName m_logFilePath;

View File

@ -22,6 +22,7 @@
#define KICAD_SERIALIZABLE_H
#include <wx/debug.h>
#include <kicommon.h>
namespace google {
namespace protobuf {
@ -32,29 +33,24 @@ namespace google {
/**
* Interface for objects that can be serialized to Protobuf messages
*/
class SERIALIZABLE
class KICOMMON_API SERIALIZABLE
{
public:
virtual ~SERIALIZABLE() = default;
/**
* Serializes this object to the given Any message.
* The Any message's concrete type will be specific to the object in question.
* @param aContainer will be filled with a message describing this object
*/
virtual void Serialize( google::protobuf::Any &aContainer ) const
{
wxASSERT_MSG( false, wxS( "Serialize called on an object that doesn't implement it!" ) );
}
virtual void Serialize( google::protobuf::Any &aContainer ) const;
/**
* Deserializes the given protobuf message into this object.
* @param aContainer is an Any which should have a concrete type matching this object
* @return true if unpacking and deserialization succeeded
*/
virtual bool Deserialize( const google::protobuf::Any &aContainer )
{
wxASSERT_MSG( false, wxS( "Deserialize called on an object that doesn't implement it!" ) );
return false;
}
virtual bool Deserialize( const google::protobuf::Any &aContainer );
};
#endif //KICAD_SERIALIZABLE_H

View File

@ -30,6 +30,7 @@
#include <properties/property.h>
#include <stroke_params.h>
#include <trigo.h>
#include <api/serializable.h>
class LINE_READER;
class EDA_DRAW_FRAME;
@ -69,11 +70,14 @@ struct ARC_MID
VECTOR2I center;
};
class EDA_SHAPE
class EDA_SHAPE : public SERIALIZABLE
{
public:
EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill );
// Construct an EDA_SHAPE from an abstract SHAPE geometry
EDA_SHAPE( const SHAPE& aShape );
// Do not create a copy constructor & operator=.
// The ones generated by the compiler are adequate.
@ -81,6 +85,9 @@ public:
void SwapShape( EDA_SHAPE* aImage );
void Serialize( google::protobuf::Any &aContainer ) const override;
bool Deserialize( const google::protobuf::Any &aContainer ) override;
wxString ShowShape() const;
wxString SHAPE_T_asString() const;

View File

@ -32,6 +32,7 @@
#include <eda_search_data.h>
#include <font/glyph.h>
#include <font/text_attributes.h>
#include <api/serializable.h>
class OUTPUTFORMATTER;
@ -75,7 +76,7 @@ using KIGFX::COLOR4D;
* function names (accessors) that to not collide with function names likely to be seen
* in the combined derived classes.
*/
class EDA_TEXT
class EDA_TEXT : public SERIALIZABLE
{
public:
EDA_TEXT( const EDA_IU_SCALE& aIuScale, const wxString& aText = wxEmptyString );
@ -86,6 +87,9 @@ public:
EDA_TEXT& operator=( const EDA_TEXT& aItem );
void Serialize( google::protobuf::Any &aContainer ) const override;
bool Deserialize( const google::protobuf::Any &aContainer ) override;
/**
* Return the string associated with the text object.
*

View File

@ -243,6 +243,8 @@ bool PGM_KICAD::OnPgmInit()
#ifdef KICAD_IPC_API
m_api_server = std::make_unique<KICAD_API_SERVER>();
m_api_common_handler = std::make_unique<API_HANDLER_COMMON>();
m_api_server->RegisterHandler( m_api_common_handler.get() );
#endif
wxString projToLoad;

View File

@ -28,6 +28,10 @@
#include <pgm_base.h>
#include <bin_mod.h>
#ifdef KICAD_IPC_API
#include <api/api_handler_common.h>
#endif
/**
* PGM_KICAD
* extends PGM_BASE to bring in FileHistory() and PdfBrowser() which were moved from EDA_APP
@ -66,6 +70,12 @@ public:
protected:
BIN_MOD m_bm;
#ifdef KICAD_IPC_API
// In PGM_SINGLE_TOP because PGM_BASE is in kicommon, and this can't be in the DLL
// because it depends on things like EDA_TEXT and EDA_SHAPE that aren't in the DLL
std::unique_ptr<API_HANDLER_COMMON> m_api_common_handler;
#endif
};

View File

@ -65,8 +65,6 @@ API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) :
&API_HANDLER_PCB::handleGetGraphicsDefaults );
registerHandler<GetBoundingBox, GetBoundingBoxResponse>(
&API_HANDLER_PCB::handleGetBoundingBox );
registerHandler<GetTextExtents, types::Box2>(
&API_HANDLER_PCB::handleGetTextExtents );
registerHandler<GetPadShapeAsPolygon, PadShapeAsPolygonResponse>(
&API_HANDLER_PCB::handleGetPadShapeAsPolygon );
registerHandler<GetTitleBlockInfo, types::TitleBlockInfo>(
@ -629,40 +627,6 @@ HANDLER_RESULT<GetBoundingBoxResponse> API_HANDLER_PCB::handleGetBoundingBox( Ge
}
HANDLER_RESULT<types::Box2> API_HANDLER_PCB::handleGetTextExtents(
GetTextExtents& aMsg,
const HANDLER_CONTEXT& aCtx )
{
PCB_TEXT text( frame()->GetBoard() );
google::protobuf::Any any;
any.PackFrom( aMsg.text() );
if( !text.Deserialize( any ) )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( "Could not decode text in GetTextExtents message" );
return tl::unexpected( e );
}
types::Box2 response;
BOX2I bbox = text.GetTextBox();
EDA_ANGLE angle = text.GetTextAngle();
if( !angle.IsZero() )
bbox = bbox.GetBoundingBoxRotated( text.GetTextPos(), text.GetTextAngle() );
response.mutable_position()->set_x_nm( bbox.GetPosition().x );
response.mutable_position()->set_y_nm( bbox.GetPosition().y );
response.mutable_size()->set_x_nm( bbox.GetSize().x );
response.mutable_size()->set_y_nm( bbox.GetSize().y );
return response;
}
HANDLER_RESULT<PadShapeAsPolygonResponse> API_HANDLER_PCB::handleGetPadShapeAsPolygon(
GetPadShapeAsPolygon& aMsg,
const HANDLER_CONTEXT& aCtx )

View File

@ -75,9 +75,6 @@ private:
HANDLER_RESULT<commands::GetBoundingBoxResponse> handleGetBoundingBox( commands::GetBoundingBox& aMsg,
const HANDLER_CONTEXT& aCtx );
HANDLER_RESULT<types::Box2> handleGetTextExtents( GetTextExtents& aMsg,
const HANDLER_CONTEXT& aCtx );
HANDLER_RESULT<PadShapeAsPolygonResponse> handleGetPadShapeAsPolygon( GetPadShapeAsPolygon& aMsg,
const HANDLER_CONTEXT& aCtx );

View File

@ -120,6 +120,7 @@
#ifdef KICAD_IPC_API
#include <api/api_server.h>
#include <api/api_handler_pcb.h>
#include <api/api_handler_common.h>
#endif
#include <action_plugin.h>
@ -468,6 +469,12 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
#ifdef KICAD_IPC_API
m_apiHandler = std::make_unique<API_HANDLER_PCB>( this );
Pgm().GetApiServer().RegisterHandler( m_apiHandler.get() );
if( Kiface().IsSingle() )
{
m_apiHandlerCommon = std::make_unique<API_HANDLER_COMMON>();
Pgm().GetApiServer().RegisterHandler( m_apiHandlerCommon.get() );
}
#endif
GetCanvas()->SwitchBackend( m_canvasType );

View File

@ -61,6 +61,7 @@ class DIALOG_BOARD_SETUP;
#ifdef KICAD_IPC_API
class KICAD_API_SERVER;
class API_HANDLER_PCB;
class API_HANDLER_COMMON;
#endif
enum LAST_PATH_TYPE : unsigned int;
@ -888,6 +889,7 @@ private:
#ifdef KICAD_IPC_API
std::unique_ptr<API_HANDLER_PCB> m_apiHandler;
std::unique_ptr<API_HANDLER_COMMON> m_apiHandlerCommon;
#endif
};

View File

@ -75,92 +75,15 @@ void PCB_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
using namespace kiapi::board::types;
BoardGraphicShape msg;
msg.set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( GetLayer() ) );
msg.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
msg.mutable_net()->mutable_code()->set_value( GetNetCode() );
msg.mutable_net()->set_name( GetNetname() );
msg.mutable_id()->set_value( m_Uuid.AsStdString() );
msg.set_locked( IsLocked() ? types::LockedState::LS_LOCKED : types::LockedState::LS_UNLOCKED );
types::GraphicShape* shape = msg.mutable_shape();
shape->mutable_id()->set_value( m_Uuid.AsStdString() );
shape->set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
: kiapi::common::types::LockedState::LS_UNLOCKED );
types::StrokeAttributes* stroke = shape->mutable_attributes()->mutable_stroke();
types::GraphicFillAttributes* fill = shape->mutable_attributes()->mutable_fill();
stroke->mutable_width()->set_value_nm( GetWidth() );
switch( GetLineStyle() )
{
case LINE_STYLE::DEFAULT: stroke->set_style( types::SLS_DEFAULT ); break;
case LINE_STYLE::SOLID: stroke->set_style( types::SLS_SOLID ); break;
case LINE_STYLE::DASH: stroke->set_style( types::SLS_DASH ); break;
case LINE_STYLE::DOT: stroke->set_style( types::SLS_DOT ); break;
case LINE_STYLE::DASHDOT: stroke->set_style( types::SLS_DASHDOT ); break;
case LINE_STYLE::DASHDOTDOT: stroke->set_style( types::SLS_DASHDOTDOT ); break;
default: break;
}
switch( GetFillMode() )
{
case FILL_T::FILLED_SHAPE: fill->set_fill_type( types::GFT_FILLED ); break;
default: fill->set_fill_type( types::GFT_UNFILLED ); break;
}
switch( GetShape() )
{
case SHAPE_T::SEGMENT:
{
types::GraphicSegmentAttributes* segment = shape->mutable_segment();
PackVector2( *segment->mutable_start(), GetStart() );
PackVector2( *segment->mutable_end(), GetEnd() );
break;
}
case SHAPE_T::RECTANGLE:
{
types::GraphicRectangleAttributes* rectangle = shape->mutable_rectangle();
PackVector2( *rectangle->mutable_top_left(), GetStart() );
PackVector2( *rectangle->mutable_bottom_right(), GetEnd() );
break;
}
case SHAPE_T::ARC:
{
types::GraphicArcAttributes* arc = shape->mutable_arc();
PackVector2( *arc->mutable_start(), GetStart() );
PackVector2( *arc->mutable_mid(), GetArcMid() );
PackVector2( *arc->mutable_end(), GetEnd() );
break;
}
case SHAPE_T::CIRCLE:
{
types::GraphicCircleAttributes* circle = shape->mutable_circle();
PackVector2( *circle->mutable_center(), GetStart() );
PackVector2( *circle->mutable_radius_point(), GetEnd() );
break;
}
case SHAPE_T::POLY:
{
PackPolySet( *shape->mutable_polygon(), GetPolyShape() );
break;
}
case SHAPE_T::BEZIER:
{
types::GraphicBezierAttributes* bezier = shape->mutable_bezier();
PackVector2( *bezier->mutable_start(), GetStart() );
PackVector2( *bezier->mutable_control1(), GetBezierC1() );
PackVector2( *bezier->mutable_control2(), GetBezierC2() );
PackVector2( *bezier->mutable_end(), GetEnd() );
break;
}
default:
wxASSERT_MSG( false, "Unhandled shape in PCB_SHAPE::Serialize" );
}
google::protobuf::Any any;
EDA_SHAPE::Serialize( any );
any.UnpackTo( msg.mutable_shape() );
// TODO m_hasSolderMask and m_solderMaskMargin
@ -190,66 +113,14 @@ bool PCB_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
m_proxyItem = false;
m_endsSwapped = false;
const types::GraphicShape& shape = msg.shape();
const_cast<KIID&>( m_Uuid ) = KIID( shape.id().value() );
SetLocked( shape.locked() == types::LS_LOCKED );
const_cast<KIID&>( m_Uuid ) = KIID( msg.id().value() );
SetLocked( msg.locked() == types::LS_LOCKED );
SetLayer( FromProtoEnum<PCB_LAYER_ID, BoardLayer>( msg.layer() ) );
SetNetCode( msg.net().code().value() );
SetFilled( shape.attributes().fill().fill_type() == types::GFT_FILLED );
SetWidth( shape.attributes().stroke().width().value_nm() );
switch( shape.attributes().stroke().style() )
{
case types::SLS_DEFAULT: SetLineStyle( LINE_STYLE::DEFAULT ); break;
case types::SLS_SOLID: SetLineStyle( LINE_STYLE::SOLID ); break;
case types::SLS_DASH: SetLineStyle( LINE_STYLE::DASH ); break;
case types::SLS_DOT: SetLineStyle( LINE_STYLE::DOT ); break;
case types::SLS_DASHDOT: SetLineStyle( LINE_STYLE::DASHDOT ); break;
case types::SLS_DASHDOTDOT: SetLineStyle( LINE_STYLE::DASHDOTDOT ); break;
default: break;
}
if( shape.has_segment() )
{
SetShape( SHAPE_T::SEGMENT );
SetStart( UnpackVector2( shape.segment().start() ) );
SetEnd( UnpackVector2( shape.segment().end() ) );
}
else if( shape.has_rectangle() )
{
SetShape( SHAPE_T::RECTANGLE );
SetStart( UnpackVector2( shape.rectangle().top_left() ) );
SetEnd( UnpackVector2( shape.rectangle().bottom_right() ) );
}
else if( shape.has_arc() )
{
SetShape( SHAPE_T::ARC );
SetArcGeometry( UnpackVector2( shape.arc().start() ),
UnpackVector2( shape.arc().mid() ),
UnpackVector2( shape.arc().end() ) );
}
else if( shape.has_circle() )
{
SetShape( SHAPE_T::CIRCLE );
SetStart( UnpackVector2( shape.circle().center() ) );
SetEnd( UnpackVector2( shape.circle().radius_point() ) );
}
else if( shape.has_polygon() )
{
SetShape( SHAPE_T::POLY );
SetPolyShape( UnpackPolySet( shape.polygon() ) );
}
else if( shape.has_bezier() )
{
SetShape( SHAPE_T::BEZIER );
SetStart( UnpackVector2( shape.bezier().start() ) );
SetBezierC1( UnpackVector2( shape.bezier().control1() ) );
SetBezierC2( UnpackVector2( shape.bezier().control2() ) );
SetEnd( UnpackVector2( shape.bezier().end() ) );
RebuildBezierToSegmentsPointsList( ARC_HIGH_DEF );
}
google::protobuf::Any any;
any.PackFrom( msg.shape() );
EDA_SHAPE::Deserialize( any );
// TODO m_hasSolderMask and m_solderMaskMargin

View File

@ -45,9 +45,6 @@
#include <api/board/board_types.pb.h>
using namespace kiapi::common;
PCB_TEXT::PCB_TEXT( BOARD_ITEM* parent, KICAD_T idtype ) :
BOARD_ITEM( parent, idtype ),
EDA_TEXT( pcbIUScale )
@ -86,44 +83,24 @@ PCB_TEXT::~PCB_TEXT()
void PCB_TEXT::Serialize( google::protobuf::Any &aContainer ) const
{
kiapi::board::types::Text boardText;
using namespace kiapi::common;
kiapi::board::types::BoardText boardText;
boardText.mutable_id()->set_value( m_Uuid.AsStdString() );
boardText.set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( GetLayer() ) );
boardText.set_knockout( IsKnockout() );
kiapi::common::types::Text& text = *boardText.mutable_text();
google::protobuf::Any any;
EDA_TEXT::Serialize( any );
any.UnpackTo( boardText.mutable_text() );
text.mutable_id()->set_value( m_Uuid.AsStdString() );
text.mutable_position()->set_x_nm( GetPosition().x );
text.mutable_position()->set_y_nm( GetPosition().y );
text.set_text( GetText().ToStdString() );
text.set_hyperlink( GetHyperlink().ToStdString() );
text.set_locked( IsLocked() ? types::LockedState::LS_LOCKED
: types::LockedState::LS_UNLOCKED );
// Some of the common Text message fields are not stored in EDA_TEXT
types::Text* text = boardText.mutable_text();
kiapi::common::types::TextAttributes* attrs = text.mutable_attributes();
PackVector2( *text->mutable_position(), GetPosition() );
if( GetFont() )
attrs->set_font_name( GetFont()->GetName().ToStdString() );
attrs->set_horizontal_alignment(
ToProtoEnum<GR_TEXT_H_ALIGN_T, types::HorizontalAlignment>( GetHorizJustify() ) );
attrs->set_vertical_alignment(
ToProtoEnum<GR_TEXT_V_ALIGN_T, types::VerticalAlignment>( GetVertJustify() ) );
attrs->mutable_angle()->set_value_degrees( GetTextAngleDegrees() );
attrs->set_line_spacing( GetLineSpacing() );
attrs->mutable_stroke_width()->set_value_nm( GetTextThickness() );
attrs->set_italic( IsItalic() );
attrs->set_bold( IsBold() );
attrs->set_underlined( GetAttributes().m_Underlined );
attrs->set_visible( IsVisible() );
attrs->set_mirrored( IsMirrored() );
attrs->set_multiline( IsMultilineAllowed() );
attrs->set_keep_upright( IsKeepUpright() );
attrs->mutable_size()->set_x_nm( GetTextSize().x );
attrs->mutable_size()->set_y_nm( GetTextSize().y );
text.set_knockout( IsKnockout() );
text->set_locked( IsLocked() ? types::LockedState::LS_LOCKED
: types::LockedState::LS_UNLOCKED );
aContainer.PackFrom( boardText );
}
@ -131,53 +108,24 @@ void PCB_TEXT::Serialize( google::protobuf::Any &aContainer ) const
bool PCB_TEXT::Deserialize( const google::protobuf::Any &aContainer )
{
kiapi::board::types::Text textWrapper;
using namespace kiapi::common;
kiapi::board::types::BoardText boardText;
if( !aContainer.UnpackTo( &textWrapper ) )
if( !aContainer.UnpackTo( &boardText ) )
return false;
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( textWrapper.layer() ) );
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( boardText.layer() ) );
const_cast<KIID&>( m_Uuid ) = KIID( boardText.id().value() );
SetIsKnockout( boardText.knockout() );
const kiapi::common::types::Text& text = textWrapper.text();
google::protobuf::Any any;
any.PackFrom( boardText.text() );
EDA_TEXT::Deserialize( any );
const_cast<KIID&>( m_Uuid ) = KIID( text.id().value() );
SetPosition( VECTOR2I( text.position().x_nm(), text.position().y_nm() ) );
SetLocked( text.locked() == kiapi::common::types::LockedState::LS_LOCKED );
SetText( wxString( text.text().c_str(), wxConvUTF8 ) );
SetHyperlink( wxString( text.hyperlink().c_str(), wxConvUTF8 ) );
SetIsKnockout( text.knockout() );
const types::Text& text = boardText.text();
if( text.has_attributes() )
{
TEXT_ATTRIBUTES attrs = GetAttributes();
attrs.m_Bold = text.attributes().bold();
attrs.m_Italic = text.attributes().italic();
attrs.m_Underlined = text.attributes().underlined();
attrs.m_Visible = text.attributes().visible();
attrs.m_Mirrored = text.attributes().mirrored();
attrs.m_Multiline = text.attributes().multiline();
attrs.m_KeepUpright = text.attributes().keep_upright();
attrs.m_Size = VECTOR2I( text.attributes().size().x_nm(), text.attributes().size().y_nm() );
if( !text.attributes().font_name().empty() )
{
attrs.m_Font = KIFONT::FONT::GetFont(
wxString( text.attributes().font_name().c_str(), wxConvUTF8 ), attrs.m_Bold,
attrs.m_Italic );
}
attrs.m_Angle = EDA_ANGLE( text.attributes().angle().value_degrees(), DEGREES_T );
attrs.m_LineSpacing = text.attributes().line_spacing();
attrs.m_StrokeWidth = text.attributes().stroke_width().value_nm();
attrs.m_Halign = FromProtoEnum<GR_TEXT_H_ALIGN_T, types::HorizontalAlignment>(
text.attributes().horizontal_alignment() );
attrs.m_Valign = FromProtoEnum<GR_TEXT_V_ALIGN_T, types::VerticalAlignment>(
text.attributes().vertical_alignment() );
SetAttributes( attrs );
}
SetPosition( UnpackVector2( text.position() ) );
SetLocked( text.locked() == types::LockedState::LS_LOCKED );
return true;
}

View File

@ -68,12 +68,12 @@ void PCB_TEXTBOX::Serialize( google::protobuf::Any &aContainer ) const
{
using namespace kiapi::common::types;
using namespace kiapi::board;
types::TextBox boardText;
types::BoardTextBox boardText;
boardText.set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( GetLayer() ) );
boardText.mutable_id()->set_value( m_Uuid.AsStdString() );
TextBox& text = *boardText.mutable_textbox();
text.mutable_id()->set_value( m_Uuid.AsStdString() );
kiapi::common::PackVector2( *text.mutable_top_left(), GetPosition() );
kiapi::common::PackVector2( *text.mutable_bottom_right(), GetEnd() );
text.set_text( GetText().ToStdString() );
@ -101,8 +101,7 @@ void PCB_TEXTBOX::Serialize( google::protobuf::Any &aContainer ) const
attrs->set_mirrored( IsMirrored() );
attrs->set_multiline( IsMultilineAllowed() );
attrs->set_keep_upright( IsKeepUpright() );
attrs->mutable_size()->set_x_nm( GetTextSize().x );
attrs->mutable_size()->set_y_nm( GetTextSize().y );
kiapi::common::PackVector2( *attrs->mutable_size(), GetTextSize() );
aContainer.PackFrom( boardText );
}
@ -111,16 +110,16 @@ void PCB_TEXTBOX::Serialize( google::protobuf::Any &aContainer ) const
bool PCB_TEXTBOX::Deserialize( const google::protobuf::Any &aContainer )
{
using namespace kiapi::board;
types::TextBox textWrapper;
types::BoardTextBox boardText;
if( !aContainer.UnpackTo( &textWrapper ) )
if( !aContainer.UnpackTo( &boardText ) )
return false;
SetLayer( FromProtoEnum<PCB_LAYER_ID, types::BoardLayer>( textWrapper.layer() ) );
const_cast<KIID&>( m_Uuid ) = KIID( boardText.id().value() );
SetLayer( FromProtoEnum<PCB_LAYER_ID, types::BoardLayer>( boardText.layer() ) );
const kiapi::common::types::TextBox& text = textWrapper.textbox();
const kiapi::common::types::TextBox& text = boardText.textbox();
const_cast<KIID&>( m_Uuid ) = KIID( text.id().value() );
SetPosition( kiapi::common::UnpackVector2( text.top_left() ) );
SetEnd( kiapi::common::UnpackVector2( text.bottom_right() ) );
SetLocked( text.locked() == kiapi::common::types::LockedState::LS_LOCKED );
@ -138,7 +137,7 @@ bool PCB_TEXTBOX::Deserialize( const google::protobuf::Any &aContainer )
attrs.m_Mirrored = text.attributes().mirrored();
attrs.m_Multiline = text.attributes().multiline();
attrs.m_KeepUpright = text.attributes().keep_upright();
attrs.m_Size = VECTOR2I( text.attributes().size().x_nm(), text.attributes().size().y_nm() );
attrs.m_Size = kiapi::common::UnpackVector2( text.attributes().size() );
if( !text.attributes().font_name().empty() )
{