diff --git a/api/proto/board/board_commands.proto b/api/proto/board/board_commands.proto index 088c04f5e1..33846c0e17 100644 --- a/api/proto/board/board_commands.proto +++ b/api/proto/board/board_commands.proto @@ -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 diff --git a/api/proto/board/board_types.proto b/api/proto/board/board_types.proto index 34f95a8a2d..ce8fe06c52 100644 --- a/api/proto/board/board_types.proto +++ b/api/proto/board/board_types.proto @@ -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 diff --git a/api/proto/common/commands/base_commands.proto b/api/proto/common/commands/base_commands.proto index 583a99d6b2..2e243b95cc 100644 --- a/api/proto/common/commands/base_commands.proto +++ b/api/proto/common/commands/base_commands.proto @@ -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; +} diff --git a/api/proto/common/types/base_types.proto b/api/proto/common/types/base_types.proto index 98e23cfb2c..ed2e3de89d 100644 --- a/api/proto/common/types/base_types.proto +++ b/api/proto/common/types/base_types.proto @@ -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 { diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index b6d9845052..5cca00ac7d 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -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() diff --git a/common/api/api_handler_common.cpp b/common/api/api_handler_common.cpp index 75abab1a2b..dd888c1857 100644 --- a/common/api/api_handler_common.cpp +++ b/common/api/api_handler_common.cpp @@ -22,6 +22,9 @@ #include #include +#include +#include +#include #include #include #include @@ -40,6 +43,9 @@ API_HANDLER_COMMON::API_HANDLER_COMMON() : registerHandler( &API_HANDLER_COMMON::handleGetVersion ); registerHandler( &API_HANDLER_COMMON::handleGetNetClasses ); registerHandler( &API_HANDLER_COMMON::handlePing ); + registerHandler( &API_HANDLER_COMMON::handleGetTextExtents ); + registerHandler( + &API_HANDLER_COMMON::handleGetTextAsShapes ); } @@ -80,3 +86,71 @@ HANDLER_RESULT API_HANDLER_COMMON::handlePing( Ping& aMsg, const HANDLER_ { return Empty(); } + + +HANDLER_RESULT 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 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 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; +} diff --git a/common/api/api_server.cpp b/common/api/api_server.cpp index 9469dea269..09f9316d58 100644 --- a/common/api/api_server.cpp +++ b/common/api/api_server.cpp @@ -18,15 +18,16 @@ * with this program. If not, see . */ +#include #include #include #include #include #include +#include #include // traceApi #include -#include #include #include #include @@ -50,9 +51,6 @@ KICAD_API_SERVER::KICAD_API_SERVER() : m_token( KIID().AsStdString() ), m_readyToReply( false ) { - m_commonHandler = std::make_unique(); - RegisterHandler( m_commonHandler.get() ); - if( !Pgm().GetCommonSettings()->m_Api.enable_server ) { wxLogTrace( traceApi, "Server: disabled by user preferences." ); diff --git a/common/api/api_utils.cpp b/common/api/api_utils.cpp index 7770645a00..05e54fa62d 100644 --- a/common/api/api_utils.cpp +++ b/common/api/api_utils.cpp @@ -31,8 +31,8 @@ std::optional 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 }, diff --git a/common/api/serializable.cpp b/common/api/serializable.cpp new file mode 100644 index 0000000000..6e8604b1cc --- /dev/null +++ b/common/api/serializable.cpp @@ -0,0 +1,34 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Jon Evans + * 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 . + */ + +#include + + +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; +} diff --git a/common/eda_shape.cpp b/common/eda_shape.cpp index b00be1510c..ece755e521 100644 --- a/common/eda_shape.cpp +++ b/common/eda_shape.cpp @@ -30,13 +30,18 @@ #include #include #include +#include +#include #include #include -#include +#include #include #include // for KiROUND #include #include +#include +#include +#include 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( aShape ); + m_shape = SHAPE_T::RECTANGLE; + SetStart( rect.GetPosition() ); + SetEnd( rect.GetPosition() + rect.GetSize() ); + break; + } + + case SH_SEGMENT: + { + auto seg = static_cast( 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( 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( aShape ); + m_shape = SHAPE_T::CIRCLE; + SetStart( circle.GetCenter() ); + SetEnd( circle.GetCenter() + circle.GetRadius() ); + break; + } + + case SH_ARC: + { + auto arc = static_cast( aShape ); + m_shape = SHAPE_T::ARC; + SetArcGeometry( arc.GetP0(), arc.GetArcMid(), arc.GetP1() ); + SetWidth( arc.GetWidth() ); + break; + } + + case SH_SIMPLE: + { + auto poly = static_cast( 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() ) diff --git a/common/eda_text.cpp b/common/eda_text.cpp index c3c8873759..49e1bb029e 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -49,6 +49,9 @@ #include #include #include // for CTL_OMIT_HIDE definition +#include +#include +#include #include // for wxASSERT #include @@ -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( GetHorizJustify() ) ); + + attrs->set_vertical_alignment( + ToProtoEnum( 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( + text.attributes().horizontal_alignment() ); + + attrs.m_Valign = FromProtoEnum( + text.attributes().vertical_alignment() ); + + SetAttributes( attrs ); + } + + return true; +} + + void EDA_TEXT::SetText( const wxString& aText ) { m_text = aText; diff --git a/include/api/api_handler_common.h b/include/api/api_handler_common.h index 57d2d34950..b4979984a0 100644 --- a/include/api/api_handler_common.h +++ b/include/api/api_handler_common.h @@ -27,15 +27,16 @@ #include #include -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 handleGetVersion( commands::GetVersion& aMsg, const HANDLER_CONTEXT& aCtx ); @@ -44,6 +45,12 @@ private: const HANDLER_CONTEXT& aCtx ); HANDLER_RESULT handlePing( commands::Ping& aMsg, const HANDLER_CONTEXT& aCtx ); + + HANDLER_RESULT handleGetTextExtents( commands::GetTextExtents& aMsg, + const HANDLER_CONTEXT& aCtx ); + + HANDLER_RESULT + handleGetTextAsShapes( commands::GetTextAsShapes& aMsg, const HANDLER_CONTEXT& aCtx ); }; #endif //KICAD_API_HANDLER_COMMON_H diff --git a/include/api/api_server.h b/include/api/api_server.h index 6c6a9c9289..f6692a8fd5 100644 --- a/include/api/api_server.h +++ b/include/api/api_server.h @@ -31,7 +31,6 @@ #include class API_HANDLER; -class API_HANDLER_COMMON; class KINNG_REQUEST_SERVER; class wxEvtHandler; @@ -99,8 +98,6 @@ private: bool m_readyToReply; - std::unique_ptr m_commonHandler; - static wxString s_logFileName; wxFileName m_logFilePath; diff --git a/include/api/serializable.h b/include/api/serializable.h index b38ff5d828..711806c6f1 100644 --- a/include/api/serializable.h +++ b/include/api/serializable.h @@ -22,6 +22,7 @@ #define KICAD_SERIALIZABLE_H #include +#include 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 diff --git a/include/eda_shape.h b/include/eda_shape.h index 87467675a6..c7102a74f9 100644 --- a/include/eda_shape.h +++ b/include/eda_shape.h @@ -30,6 +30,7 @@ #include #include #include +#include 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; diff --git a/include/eda_text.h b/include/eda_text.h index ace35040bd..107845572a 100644 --- a/include/eda_text.h +++ b/include/eda_text.h @@ -32,6 +32,7 @@ #include #include #include +#include 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. * diff --git a/kicad/kicad.cpp b/kicad/kicad.cpp index 707e31aa8b..bcaea8d420 100644 --- a/kicad/kicad.cpp +++ b/kicad/kicad.cpp @@ -243,6 +243,8 @@ bool PGM_KICAD::OnPgmInit() #ifdef KICAD_IPC_API m_api_server = std::make_unique(); + m_api_common_handler = std::make_unique(); + m_api_server->RegisterHandler( m_api_common_handler.get() ); #endif wxString projToLoad; diff --git a/kicad/pgm_kicad.h b/kicad/pgm_kicad.h index 12e98c7451..ea7829d963 100644 --- a/kicad/pgm_kicad.h +++ b/kicad/pgm_kicad.h @@ -28,6 +28,10 @@ #include #include +#ifdef KICAD_IPC_API +#include +#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 m_api_common_handler; +#endif }; diff --git a/pcbnew/api/api_handler_pcb.cpp b/pcbnew/api/api_handler_pcb.cpp index 3b09d6cbd1..e1b7fdad8a 100644 --- a/pcbnew/api/api_handler_pcb.cpp +++ b/pcbnew/api/api_handler_pcb.cpp @@ -65,8 +65,6 @@ API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) : &API_HANDLER_PCB::handleGetGraphicsDefaults ); registerHandler( &API_HANDLER_PCB::handleGetBoundingBox ); - registerHandler( - &API_HANDLER_PCB::handleGetTextExtents ); registerHandler( &API_HANDLER_PCB::handleGetPadShapeAsPolygon ); registerHandler( @@ -629,40 +627,6 @@ HANDLER_RESULT API_HANDLER_PCB::handleGetBoundingBox( Ge } -HANDLER_RESULT 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 API_HANDLER_PCB::handleGetPadShapeAsPolygon( GetPadShapeAsPolygon& aMsg, const HANDLER_CONTEXT& aCtx ) diff --git a/pcbnew/api/api_handler_pcb.h b/pcbnew/api/api_handler_pcb.h index 43af6c8ac9..872647831f 100644 --- a/pcbnew/api/api_handler_pcb.h +++ b/pcbnew/api/api_handler_pcb.h @@ -75,9 +75,6 @@ private: HANDLER_RESULT handleGetBoundingBox( commands::GetBoundingBox& aMsg, const HANDLER_CONTEXT& aCtx ); - HANDLER_RESULT handleGetTextExtents( GetTextExtents& aMsg, - const HANDLER_CONTEXT& aCtx ); - HANDLER_RESULT handleGetPadShapeAsPolygon( GetPadShapeAsPolygon& aMsg, const HANDLER_CONTEXT& aCtx ); diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 5bb95535a7..08cfab019e 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -120,6 +120,7 @@ #ifdef KICAD_IPC_API #include #include +#include #endif #include @@ -468,6 +469,12 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : #ifdef KICAD_IPC_API m_apiHandler = std::make_unique( this ); Pgm().GetApiServer().RegisterHandler( m_apiHandler.get() ); + + if( Kiface().IsSingle() ) + { + m_apiHandlerCommon = std::make_unique(); + Pgm().GetApiServer().RegisterHandler( m_apiHandlerCommon.get() ); + } #endif GetCanvas()->SwitchBackend( m_canvasType ); diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index 6685883836..9f99d585da 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -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 m_apiHandler; + std::unique_ptr m_apiHandlerCommon; #endif }; diff --git a/pcbnew/pcb_shape.cpp b/pcbnew/pcb_shape.cpp index ecb2126ca8..6cabf21cd8 100644 --- a/pcbnew/pcb_shape.cpp +++ b/pcbnew/pcb_shape.cpp @@ -75,92 +75,15 @@ void PCB_SHAPE::Serialize( google::protobuf::Any &aContainer ) const using namespace kiapi::board::types; BoardGraphicShape msg; - msg.set_layer( ToProtoEnum( GetLayer() ) ); + msg.set_layer( ToProtoEnum( 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( m_Uuid ) = KIID( shape.id().value() ); - SetLocked( shape.locked() == types::LS_LOCKED ); + const_cast( m_Uuid ) = KIID( msg.id().value() ); + SetLocked( msg.locked() == types::LS_LOCKED ); SetLayer( FromProtoEnum( 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 diff --git a/pcbnew/pcb_text.cpp b/pcbnew/pcb_text.cpp index 7dee6dee2d..1f1c7c4fc5 100644 --- a/pcbnew/pcb_text.cpp +++ b/pcbnew/pcb_text.cpp @@ -45,9 +45,6 @@ #include -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( 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( GetHorizJustify() ) ); - - attrs->set_vertical_alignment( - ToProtoEnum( 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( textWrapper.layer() ) ); + SetLayer( FromProtoEnum( boardText.layer() ) ); + const_cast( 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( 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( - text.attributes().horizontal_alignment() ); - - attrs.m_Valign = FromProtoEnum( - text.attributes().vertical_alignment() ); - - SetAttributes( attrs ); - } + SetPosition( UnpackVector2( text.position() ) ); + SetLocked( text.locked() == types::LockedState::LS_LOCKED ); return true; } diff --git a/pcbnew/pcb_textbox.cpp b/pcbnew/pcb_textbox.cpp index 468d43db14..eeb1cc3c5b 100644 --- a/pcbnew/pcb_textbox.cpp +++ b/pcbnew/pcb_textbox.cpp @@ -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( 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( textWrapper.layer() ) ); + const_cast( m_Uuid ) = KIID( boardText.id().value() ); + SetLayer( FromProtoEnum( boardText.layer() ) ); - const kiapi::common::types::TextBox& text = textWrapper.textbox(); + const kiapi::common::types::TextBox& text = boardText.textbox(); - const_cast( 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() ) {