Add QA tests and expand serialization for API
This commit is contained in:
parent
6bd02cae6d
commit
1dbe78c68b
|
@ -22,11 +22,19 @@ set( KIAPI_PROTO_SRCS
|
|||
common/envelope.proto
|
||||
|
||||
common/types/base_types.proto
|
||||
common/types/enums.proto
|
||||
common/types/project_settings.proto
|
||||
|
||||
common/commands/base_commands.proto
|
||||
common/commands/editor_commands.proto
|
||||
common/commands/project_commands.proto
|
||||
|
||||
board/board.proto
|
||||
board/board_commands.proto
|
||||
board/board_types.proto
|
||||
|
||||
schematic/schematic_types.proto
|
||||
schematic/schematic_commands.proto
|
||||
)
|
||||
|
||||
# Generated C++ code must be in the build dir; it is dependent on the version of protoc installed
|
||||
|
@ -101,18 +109,3 @@ target_include_directories( kiapi INTERFACE
|
|||
|
||||
# Because when building internally, the generated files do not include the "api" base path
|
||||
target_include_directories( kiapi PUBLIC ${KIAPI_CPP_BASEPATH} )
|
||||
|
||||
option( KICAD_BUILD_ENUM_EXPORTER
|
||||
"Build the enum exporter used as part of generating the IPC APIs"
|
||||
OFF )
|
||||
|
||||
if( KICAD_BUILD_ENUM_EXPORTER )
|
||||
add_subdirectory( enums )
|
||||
|
||||
add_custom_target( enum_definitions
|
||||
COMMAND $<TARGET_FILE:enum_exporter> ${CMAKE_CURRENT_BINARY_DIR}/enums.json
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating API definitions from KiCad enums..."
|
||||
DEPENDS enum_exporter
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 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 <filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <argparse/argparse.hpp>
|
||||
#include <fmt.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define MAGIC_ENUM_RANGE_MAX 1024
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include <layer_ids.h>
|
||||
#include <eda_shape.h>
|
||||
#include <core/typeinfo.h>
|
||||
|
||||
|
||||
template<typename T>
|
||||
nlohmann::json FormatEnum()
|
||||
{
|
||||
nlohmann::json js;
|
||||
|
||||
js["type"] = magic_enum::enum_type_name<T>();
|
||||
js["values"] = nlohmann::json::array();
|
||||
|
||||
for( const std::pair<T, std::string_view>& entry : magic_enum::enum_entries<T>() )
|
||||
{
|
||||
js["values"].emplace_back( nlohmann::json( {
|
||||
{ "key", entry.second },
|
||||
{ "value", static_cast<int>( entry.first ) }
|
||||
} ) );
|
||||
}
|
||||
|
||||
return js;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
argparse::ArgumentParser args( "enum_exporter" );
|
||||
|
||||
args.add_argument( "output_dir" ).default_value( std::string() );
|
||||
|
||||
try
|
||||
{
|
||||
args.parse_args( argc, argv );
|
||||
}
|
||||
catch( const std::runtime_error& err )
|
||||
{
|
||||
std::cerr << err.what() << std::endl;
|
||||
std::cerr << args;
|
||||
std::exit( 1 );
|
||||
}
|
||||
|
||||
std::filesystem::path path( args.get<std::string>( "output_dir" ) );
|
||||
std::ofstream outfile;
|
||||
|
||||
if( !path.empty() )
|
||||
{
|
||||
path = std::filesystem::absolute( path );
|
||||
outfile.open( path );
|
||||
}
|
||||
|
||||
std::ostream& out = outfile.is_open() ? outfile : std::cout;
|
||||
|
||||
nlohmann::json js = nlohmann::json::array();
|
||||
|
||||
js += FormatEnum<PCB_LAYER_ID>();
|
||||
js += FormatEnum<SHAPE_T>();
|
||||
js += FormatEnum<KICAD_T>();
|
||||
|
||||
out << js.dump( 4 ) << std::endl;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.board;
|
||||
|
||||
import "common/types/base_types.proto";
|
||||
import "board/board_types.proto";
|
||||
|
||||
message BoardFinish
|
||||
{
|
||||
string type_name = 1;
|
||||
}
|
||||
|
||||
message BoardImpedanceControl
|
||||
{
|
||||
bool is_controlled = 1;
|
||||
}
|
||||
|
||||
message BoardEdgeConnector
|
||||
{
|
||||
}
|
||||
|
||||
message Castellation
|
||||
{
|
||||
bool has_castellated_pads = 1;
|
||||
}
|
||||
|
||||
message EdgePlating
|
||||
{
|
||||
bool has_edge_plating = 1;
|
||||
}
|
||||
|
||||
message BoardEdgeSettings
|
||||
{
|
||||
BoardEdgeConnector connector = 1;
|
||||
Castellation castellation = 2;
|
||||
EdgePlating plating = 3;
|
||||
}
|
||||
|
||||
message BoardStackupCopperLayer
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
message BoardStackupLayer
|
||||
{
|
||||
kiapi.common.types.Distance thickness = 1;
|
||||
kiapi.board.types.BoardLayer layer = 2;
|
||||
bool enabled = 3;
|
||||
oneof item {
|
||||
BoardStackupCopperLayer copper = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message BoardStackup
|
||||
{
|
||||
BoardFinish finish = 1;
|
||||
BoardImpedanceControl impedance = 2;
|
||||
// NOTE: m_HasThicknessConstrains appears to be unused
|
||||
BoardEdgeSettings edge = 3;
|
||||
repeated BoardStackupLayer layers = 4;
|
||||
}
|
||||
|
||||
// LAYER_CLASS_* in BOARD_DESIGN_SETTINGS -- needs to become an enum class
|
||||
enum BoardLayerClass
|
||||
{
|
||||
BLC_UNKNOWN = 0;
|
||||
BLC_SILKSCREEN = 1;
|
||||
BLC_COPPER = 2;
|
||||
BLC_EDGES = 3;
|
||||
BLC_COURTYARD = 4;
|
||||
BLC_FABRICATION = 5;
|
||||
BLC_OTHER = 6;
|
||||
}
|
||||
|
||||
message BoardLayerGraphicsDefaults
|
||||
{
|
||||
BoardLayerClass layer = 1;
|
||||
kiapi.common.types.TextAttributes text = 2;
|
||||
kiapi.common.types.Distance line_thickness = 3;
|
||||
}
|
||||
|
||||
message GraphicsDefaults
|
||||
{
|
||||
repeated BoardLayerGraphicsDefaults layers = 1;
|
||||
}
|
||||
|
||||
// Anything that isn't stackup or design rules
|
||||
message BoardSettings
|
||||
{
|
||||
GraphicsDefaults graphics_defaults = 1;
|
||||
// Dimension default settings
|
||||
}
|
||||
|
||||
message BoardDesignRules
|
||||
{
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.board.commands;
|
||||
|
||||
import "common/types/base_types.proto";
|
||||
import "common/types/enums.proto";
|
||||
import "board/board.proto";
|
||||
import "board/board_types.proto";
|
||||
|
||||
/*
|
||||
* Board stackup and properties
|
||||
*/
|
||||
|
||||
message GetBoardStackup
|
||||
{
|
||||
kiapi.common.types.DocumentSpecifier board = 1;
|
||||
}
|
||||
|
||||
message BoardStackupResponse
|
||||
{
|
||||
kiapi.board.BoardStackup stackup = 1;
|
||||
}
|
||||
|
||||
message UpdateBoardStackup
|
||||
{
|
||||
kiapi.common.types.DocumentSpecifier board = 1;
|
||||
kiapi.board.BoardStackup stackup = 2;
|
||||
}
|
||||
|
||||
message GetGraphicsDefaults
|
||||
{
|
||||
kiapi.common.types.DocumentSpecifier board = 1;
|
||||
}
|
||||
|
||||
message GraphicsDefaultsResponse
|
||||
{
|
||||
kiapi.board.GraphicsDefaults defaults = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Net management
|
||||
*/
|
||||
|
||||
message GetNets
|
||||
{
|
||||
kiapi.common.types.DocumentSpecifier board = 1;
|
||||
|
||||
// If provided, will only return nets that belong to the given netclass.
|
||||
// If more than one netclass_filter is given, nets belonging to any of the given classes will
|
||||
// be returned.
|
||||
repeated string netclass_filter = 2;
|
||||
}
|
||||
|
||||
message NetsResponse
|
||||
{
|
||||
repeated kiapi.board.types.Net nets = 1;
|
||||
}
|
||||
|
||||
// Retrieve all the copper items belonging to a certain net or set of nets
|
||||
// returns kiapi.common.commands.GetItemsResponse
|
||||
message GetItemsByNet
|
||||
{
|
||||
// Specifies which document to query, which fields to return, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
// List of one or more types of items to retreive
|
||||
repeated kiapi.common.types.KiCadObjectType types = 2;
|
||||
|
||||
// A list of net codes to filter items by
|
||||
repeated kiapi.board.types.NetCode net_codes = 3;
|
||||
}
|
||||
|
||||
// Retrieve all the copper items belonging to a certain net class or set of net classes
|
||||
// returns kiapi.common.commands.GetItemsResponse
|
||||
message GetItemsByNetClass
|
||||
{
|
||||
// Specifies which document to query, which fields to return, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
// List of one or more types of items to retreive
|
||||
repeated kiapi.common.types.KiCadObjectType types = 2;
|
||||
|
||||
// A list of net class names to filter items by
|
||||
repeated string net_classes = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Blocking operations
|
||||
*/
|
||||
|
||||
// Refills some or all zones on the board.
|
||||
// This is a blocking operation; it will return Empty immediately, but KiCad will return
|
||||
// ApiStatusCode.AS_BUSY to all future API requests until the zone fill has completed.
|
||||
message RefillZones
|
||||
{
|
||||
kiapi.common.types.DocumentSpecifier board = 1;
|
||||
|
||||
// A list of zones to refill. If empty, all zones are refilled.
|
||||
repeated kiapi.common.types.KIID zones = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
// returns kiapi.common.commands.BoundingBoxResponse
|
||||
message GetTextExtents
|
||||
{
|
||||
// A temporary text item to calculate the bounding box for
|
||||
kiapi.board.types.Text text = 1;
|
||||
}
|
||||
|
||||
//// Interactive commands ////
|
||||
// These commands begin an interactive operation in the editor.
|
||||
// They return a response immediately, but the editor will become busy
|
||||
// and will not reply to further API commands until the user has finished
|
||||
// the operation.
|
||||
// These commands will return an error if received in a non-interactive context.
|
||||
|
||||
// Selects and begins an interactive move of the given item(s).
|
||||
// NOTE: Takes ownership of the active commit, if one exists:
|
||||
// the move tool will push the commit when the user confirms the move,
|
||||
// or roll back the commit if the user cancels the move. Keep this in
|
||||
// mind if using this command in combination with commands that create
|
||||
// or modify items using an explicit commit.
|
||||
message InteractiveMoveItems
|
||||
{
|
||||
kiapi.common.types.DocumentSpecifier board = 1;
|
||||
|
||||
repeated kiapi.common.types.KIID items = 2;
|
||||
}
|
|
@ -21,90 +21,467 @@ syntax = "proto3";
|
|||
|
||||
package kiapi.board.types;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "common/types/base_types.proto";
|
||||
|
||||
/// Represents a track segment on a board
|
||||
enum BoardLayer
|
||||
{
|
||||
BL_UNKNOWN = 0;
|
||||
BL_UNDEFINED = 1;
|
||||
BL_UNSELECTED = 2;
|
||||
BL_F_Cu = 3;
|
||||
BL_In1_Cu = 4;
|
||||
BL_In2_Cu = 5;
|
||||
BL_In3_Cu = 6;
|
||||
BL_In4_Cu = 7;
|
||||
BL_In5_Cu = 8;
|
||||
BL_In6_Cu = 9;
|
||||
BL_In7_Cu = 10;
|
||||
BL_In8_Cu = 11;
|
||||
BL_In9_Cu = 12;
|
||||
BL_In10_Cu = 13;
|
||||
BL_In11_Cu = 14;
|
||||
BL_In12_Cu = 15;
|
||||
BL_In13_Cu = 16;
|
||||
BL_In14_Cu = 17;
|
||||
BL_In15_Cu = 18;
|
||||
BL_In16_Cu = 19;
|
||||
BL_In17_Cu = 20;
|
||||
BL_In18_Cu = 21;
|
||||
BL_In19_Cu = 22;
|
||||
BL_In20_Cu = 23;
|
||||
BL_In21_Cu = 24;
|
||||
BL_In22_Cu = 25;
|
||||
BL_In23_Cu = 26;
|
||||
BL_In24_Cu = 27;
|
||||
BL_In25_Cu = 28;
|
||||
BL_In26_Cu = 29;
|
||||
BL_In27_Cu = 30;
|
||||
BL_In28_Cu = 31;
|
||||
BL_In29_Cu = 32;
|
||||
BL_In30_Cu = 33;
|
||||
BL_B_Cu = 34;
|
||||
BL_B_Adhes = 35;
|
||||
BL_F_Adhes = 36;
|
||||
BL_B_Paste = 37;
|
||||
BL_F_Paste = 38;
|
||||
BL_B_SilkS = 39;
|
||||
BL_F_SilkS = 40;
|
||||
BL_B_Mask = 41;
|
||||
BL_F_Mask = 42;
|
||||
BL_Dwgs_User = 43;
|
||||
BL_Cmts_User = 44;
|
||||
BL_Eco1_User = 45;
|
||||
BL_Eco2_User = 46;
|
||||
BL_Edge_Cuts = 47;
|
||||
BL_Margin = 48;
|
||||
BL_B_CrtYd = 49;
|
||||
BL_F_CrtYd = 50;
|
||||
BL_B_Fab = 51;
|
||||
BL_F_Fab = 52;
|
||||
BL_User_1 = 53;
|
||||
BL_User_2 = 54;
|
||||
BL_User_3 = 55;
|
||||
BL_User_4 = 56;
|
||||
BL_User_5 = 57;
|
||||
BL_User_6 = 58;
|
||||
BL_User_7 = 59;
|
||||
BL_User_8 = 60;
|
||||
BL_User_9 = 61;
|
||||
}
|
||||
|
||||
message NetCode
|
||||
{
|
||||
int32 value = 1;
|
||||
}
|
||||
|
||||
// Describes a copper item's net
|
||||
message Net
|
||||
{
|
||||
// A unique code representing this net
|
||||
NetCode code = 1;
|
||||
|
||||
// Human-readable net name
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
// Represents a track segment on a board
|
||||
message Track
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Point2D start = 2;
|
||||
kiapi.common.types.Point2D end = 3;
|
||||
kiapi.common.types.Vector2 start = 2;
|
||||
kiapi.common.types.Vector2 end = 3;
|
||||
kiapi.common.types.Distance width = 4;
|
||||
kiapi.common.types.LockedState locked = 5;
|
||||
kiapi.common.types.BoardLayer layer = 6;
|
||||
kiapi.common.types.Net net = 7;
|
||||
BoardLayer layer = 6;
|
||||
Net net = 7;
|
||||
}
|
||||
|
||||
/// Represents an arc track (not a PCB_SHAPE in arc shape)
|
||||
/// Arc tracks in KiCad store start, midpoint, and end.
|
||||
/// All other values (center point, angles, etc) are inferred.
|
||||
// Represents an arc track (not a PCB_SHAPE in arc shape)
|
||||
// Arc tracks in KiCad store start, midpoint, and end.
|
||||
// All other values (center point, angles, etc) are inferred.
|
||||
message Arc
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Point2D start = 2;
|
||||
kiapi.common.types.Point2D mid = 3; /// Arc midpoint
|
||||
kiapi.common.types.Point2D end = 4;
|
||||
kiapi.common.types.Vector2 start = 2;
|
||||
kiapi.common.types.Vector2 mid = 3; // Arc midpoint
|
||||
kiapi.common.types.Vector2 end = 4;
|
||||
kiapi.common.types.Distance width = 5;
|
||||
kiapi.common.types.LockedState locked = 6;
|
||||
kiapi.common.types.BoardLayer layer = 7;
|
||||
kiapi.common.types.Net net = 8;
|
||||
BoardLayer layer = 7;
|
||||
Net net = 8;
|
||||
}
|
||||
|
||||
enum PadStackType
|
||||
{
|
||||
PST_UNKNOWN = 0;
|
||||
PST_THROUGH = 1; /// Through all layers; same shape on all layers
|
||||
PST_BLIND_BURIED = 2; /// From a start layer to end layer (inclusive); same shape on all included layers
|
||||
PST_THROUGH = 1; // Through all layers; same shape on all layers
|
||||
PST_BLIND_BURIED = 2; // From a start layer to end layer (inclusive); same shape on all included layers
|
||||
}
|
||||
|
||||
enum UnconnectedLayerRemoval
|
||||
{
|
||||
ULR_UNKNOWN = 0;
|
||||
|
||||
/// Keep annular rings on all layers
|
||||
// Keep annular rings on all layers
|
||||
ULR_KEEP = 1;
|
||||
|
||||
/// Remove annular rings on unconnected layers, including start and end layers.
|
||||
// Remove annular rings on unconnected layers, including start and end layers.
|
||||
ULR_REMOVE = 2;
|
||||
|
||||
/// Remove annular rings on unconnected layers, but preserve start and end layers even if unconnected.
|
||||
// Remove annular rings on unconnected layers, but preserve start and end layers even if unconnected.
|
||||
ULR_REMOVE_EXCEPT_START_AND_END = 3;
|
||||
}
|
||||
|
||||
/// A pad stack definition for a multilayer pad or via.
|
||||
// The shape of a pad on a given layer
|
||||
enum PadStackShape
|
||||
{
|
||||
PSS_UNKNOWN = 0;
|
||||
PSS_CIRCLE = 1;
|
||||
PSS_RECTANGLE = 2;
|
||||
PSS_OVAL = 3;
|
||||
PSS_TRAPEZOID = 4;
|
||||
PSS_ROUNDRECT = 5;
|
||||
PSS_CHAMFEREDRECT = 6;
|
||||
PSS_CUSTOM = 7;
|
||||
}
|
||||
|
||||
// Which corners are chamfered in a PSS_CHAMFEREDRECT
|
||||
message ChamferedRectCorners
|
||||
{
|
||||
bool top_left = 1;
|
||||
bool top_right = 2;
|
||||
bool bottom_left = 3;
|
||||
bool bottom_right = 4;
|
||||
}
|
||||
|
||||
// The defintion of a padstack on a single layer
|
||||
message PadStackLayer
|
||||
{
|
||||
// The board layers of this padstack entry
|
||||
repeated BoardLayer layers = 1;
|
||||
|
||||
// The shape of the pad on this layer
|
||||
PadStackShape shape = 2;
|
||||
|
||||
// The size (x and y) of the shape on this layer
|
||||
kiapi.common.types.Vector2 size = 3;
|
||||
|
||||
// How much to round the corners of the shape by, as a fraction of min(size.x, size.y)
|
||||
// Only used for PSS_ROUNDRECT or PSS_CHAMFEREDRECT
|
||||
float corner_rounding_ratio = 4;
|
||||
|
||||
// How much to round the corners of the shape by, as a fraction of min(size.x, size.y)
|
||||
// Only used for PSS_CHAMFEREDRECT
|
||||
float chamfer_ratio = 5;
|
||||
|
||||
ChamferedRectCorners chamfered_corners = 6;
|
||||
|
||||
repeated GraphicShape custom_shapes = 7;
|
||||
}
|
||||
|
||||
// A pad stack definition for a multilayer pad or via.
|
||||
message PadStack
|
||||
{
|
||||
/// What type of pad stack this represents.
|
||||
// What type of pad stack this represents.
|
||||
PadStackType type = 1;
|
||||
|
||||
/// Lowest (closest to F_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
|
||||
kiapi.common.types.BoardLayer start_layer = 2;
|
||||
// Lowest (closest to F_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
|
||||
BoardLayer start_layer = 2;
|
||||
|
||||
/// Highest (closest to B_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
|
||||
kiapi.common.types.BoardLayer end_layer = 3;
|
||||
// Highest (closest to B_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
|
||||
BoardLayer end_layer = 3;
|
||||
|
||||
/// How to treat annular rings on unconnected layers.
|
||||
// How to treat pad shapes on unconnected layers.
|
||||
UnconnectedLayerRemoval unconnected_layer_removal = 4;
|
||||
|
||||
// The diameter, in x and y, of the pad's drilled hole, if this pad has a hole.
|
||||
// x and y will be the same value if the hole is round.
|
||||
kiapi.common.types.Vector2 drill_diameter = 5;
|
||||
|
||||
repeated PadStackLayer layers = 6;
|
||||
|
||||
// The overall rotation of this padstack (affects all layers)
|
||||
kiapi.common.types.Angle angle = 7;
|
||||
}
|
||||
|
||||
/// Represents a via
|
||||
// Represents a via
|
||||
message Via
|
||||
{
|
||||
/// The unique identifier of the via
|
||||
// The unique identifier of the via
|
||||
kiapi.common.types.KIID id = 1;
|
||||
|
||||
/// The location of the via's center point
|
||||
kiapi.common.types.Point2D position = 2;
|
||||
// The location of the via's center point
|
||||
kiapi.common.types.Vector2 position = 2;
|
||||
|
||||
/// The diameter of the via's circular copper pad
|
||||
kiapi.common.types.Distance pad_diameter = 4;
|
||||
// The pad stack definition for this via. The via's VIATYPE (blind/buried/normal) is inferred from this.
|
||||
PadStack pad_stack = 3;
|
||||
|
||||
/// The diameter of the via's drilled hole
|
||||
kiapi.common.types.Distance drill_diameter = 5;
|
||||
kiapi.common.types.LockedState locked = 4;
|
||||
|
||||
/// The pad stack definition for this via. The via's VIATYPE (blind/buried/normal) is inferred from this.
|
||||
Net net = 5;
|
||||
}
|
||||
|
||||
message GraphicSegmentAttributes
|
||||
{
|
||||
kiapi.common.types.Vector2 start = 1;
|
||||
kiapi.common.types.Vector2 end = 2;
|
||||
}
|
||||
|
||||
message GraphicRectangleAttributes
|
||||
{
|
||||
kiapi.common.types.Vector2 top_left = 1;
|
||||
kiapi.common.types.Vector2 bottom_right = 2;
|
||||
}
|
||||
|
||||
message GraphicArcAttributes
|
||||
{
|
||||
kiapi.common.types.Vector2 start = 1;
|
||||
kiapi.common.types.Vector2 mid = 2;
|
||||
kiapi.common.types.Vector2 end = 3;
|
||||
}
|
||||
|
||||
message GraphicCircleAttributes
|
||||
{
|
||||
kiapi.common.types.Vector2 center = 1;
|
||||
|
||||
// A point on the radius of the circle. This is stored instead of just a radius so that the point
|
||||
// by which the user can adjust the circle radius is persisted.
|
||||
kiapi.common.types.Vector2 radius_point = 2;
|
||||
}
|
||||
|
||||
message GraphicBezierAttributes
|
||||
{
|
||||
kiapi.common.types.Vector2 start = 1;
|
||||
kiapi.common.types.Vector2 control1 = 2;
|
||||
kiapi.common.types.Vector2 control2 = 3;
|
||||
kiapi.common.types.Vector2 end = 4;
|
||||
}
|
||||
|
||||
message GraphicShape
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.LockedState locked = 2;
|
||||
BoardLayer layer = 3;
|
||||
Net net = 4;
|
||||
kiapi.common.types.GraphicAttributes attributes = 5;
|
||||
|
||||
oneof geometry {
|
||||
GraphicSegmentAttributes segment = 6;
|
||||
GraphicRectangleAttributes rectangle = 7;
|
||||
GraphicArcAttributes arc = 8;
|
||||
GraphicCircleAttributes circle = 9;
|
||||
kiapi.common.types.PolySet polygon = 10;
|
||||
GraphicBezierAttributes bezier = 11;
|
||||
}
|
||||
}
|
||||
|
||||
// A board-specific text object, existing on a board layer
|
||||
message Text
|
||||
{
|
||||
kiapi.common.types.Text text = 1;
|
||||
BoardLayer layer = 2;
|
||||
}
|
||||
|
||||
// A board-specific textbox, existing on a board layer
|
||||
message TextBox
|
||||
{
|
||||
kiapi.common.types.TextBox textbox = 1;
|
||||
BoardLayer layer = 2;
|
||||
}
|
||||
|
||||
// NOTE: There has been some discussion about what to do with pad attributes and properties.
|
||||
// This may be considered somewhat unstable until we decide what to do with the KiCad side.
|
||||
// It is not clear what the set of mutually-exclusive pad types will be at the end of the day,
|
||||
// versus what will be non-exclusive attributes/properties.
|
||||
// For now, this maps to PAD_ATTRIB in KiCad.
|
||||
enum PadType
|
||||
{
|
||||
PT_UNKNOWN = 0;
|
||||
PT_PTH = 1;
|
||||
PT_SMD = 2;
|
||||
PT_EDGE_CONNECTOR = 3;
|
||||
PT_NPTH = 4;
|
||||
}
|
||||
|
||||
enum CustomPadShapeZoneFillStrategy
|
||||
{
|
||||
CPSZ_UNKNOWN = 0;
|
||||
CPSZ_OUTLINE = 1;
|
||||
CPSZ_CONVEXHULL = 2;
|
||||
}
|
||||
|
||||
message ThermalSpokeSettings
|
||||
{
|
||||
int64 width = 1;
|
||||
kiapi.common.types.Angle angle = 2;
|
||||
int64 gap = 3;
|
||||
}
|
||||
|
||||
message Pad
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.LockedState locked = 2;
|
||||
string number = 3;
|
||||
Net net = 4;
|
||||
PadType type = 5;
|
||||
PadStack pad_stack = 6;
|
||||
|
||||
kiapi.common.types.LockedState locked = 7;
|
||||
kiapi.common.types.Net net = 8;
|
||||
// A pad's position is always relative to the parent footprint's origin
|
||||
kiapi.common.types.Vector2 position = 7;
|
||||
|
||||
DesignRuleOverrides overrides = 8;
|
||||
|
||||
ThermalSpokeSettings thermal_spokes = 9;
|
||||
}
|
||||
|
||||
// Copper zone, non-copper zone, or rule area
|
||||
message Zone
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
message Dimension
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
message ReferenceImage
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
message Group
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
message FieldId
|
||||
{
|
||||
int32 id = 1;
|
||||
}
|
||||
|
||||
message Field
|
||||
{
|
||||
FieldId id = 1;
|
||||
string name = 2;
|
||||
Text text = 3;
|
||||
}
|
||||
|
||||
message Model3D
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
enum FootprintMountingStyle
|
||||
{
|
||||
FMS_UNKNOWN = 0;
|
||||
FMS_THROUGH_HOLE = 1;
|
||||
FMS_SMD = 2;
|
||||
FMS_UNSPECIFIED = 3;
|
||||
}
|
||||
|
||||
|
||||
message FootprintAttributes
|
||||
{
|
||||
string description = 1;
|
||||
string keywords = 2;
|
||||
bool not_in_schematic = 3;
|
||||
bool exclude_from_position_files = 4;
|
||||
bool exclude_from_bill_of_materials = 5;
|
||||
bool exempt_from_courtyard_requirement = 6;
|
||||
bool do_not_populate = 7;
|
||||
FootprintMountingStyle mounting_style = 8;
|
||||
}
|
||||
|
||||
// enum class ZONE_CONNECTION
|
||||
enum ZoneConnectionStyle
|
||||
{
|
||||
ZCS_UNKNOWN = 0;
|
||||
ZCS_INHERITED = 1;
|
||||
ZCS_NONE = 2;
|
||||
ZCS_THERMAL = 3;
|
||||
ZCS_FULL = 4;
|
||||
ZCS_PTH_THERMAL = 5; // Thermal reliefs for plated through holes, solid for SMD pads
|
||||
}
|
||||
|
||||
message DesignRuleOverrides
|
||||
{
|
||||
// Copper-to-copper clearance override
|
||||
kiapi.common.types.Distance clearance = 1;
|
||||
|
||||
// Solder mask expansion/contraction
|
||||
kiapi.common.types.Distance solder_mask_margin = 2;
|
||||
|
||||
// Solder paste expansion/contraction
|
||||
kiapi.common.types.Distance solder_paste_margin = 3;
|
||||
|
||||
// Solder paste expansion/contraction ratio
|
||||
kiapi.common.types.Ratio solder_paste_margin_ratio = 4;
|
||||
|
||||
ZoneConnectionStyle zone_connection = 5;
|
||||
}
|
||||
|
||||
message NetTieDefinition
|
||||
{
|
||||
repeated string pad_number = 1;
|
||||
}
|
||||
|
||||
// A footprint definition (i.e. what would be in a library)
|
||||
message Footprint
|
||||
{
|
||||
kiapi.common.types.LibraryIdentifier id = 1;
|
||||
kiapi.common.types.Vector2 anchor = 2;
|
||||
FootprintAttributes attributes = 3;
|
||||
DesignRuleOverrides overrides = 4;
|
||||
repeated NetTieDefinition net_ties = 5;
|
||||
repeated BoardLayer private_layers = 6;
|
||||
|
||||
Field reference_field = 7;
|
||||
Field value_field = 8;
|
||||
Field datasheet_field = 9;
|
||||
Field description_field = 10;
|
||||
|
||||
// All footprint items except for mandatory fields
|
||||
repeated google.protobuf.Any items = 11;
|
||||
}
|
||||
|
||||
// An instance of a footprint on a board
|
||||
message FootprintInstance
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Vector2 position = 2;
|
||||
kiapi.common.types.Angle orientation = 3;
|
||||
BoardLayer layer = 4;
|
||||
kiapi.common.types.LockedState locked = 5;
|
||||
Footprint definition = 6;
|
||||
|
||||
Field reference_field = 7;
|
||||
Field value_field = 8;
|
||||
Field datasheet_field = 9;
|
||||
Field description_field = 10;
|
||||
|
||||
FootprintAttributes attributes = 11;
|
||||
DesignRuleOverrides overrides = 12;
|
||||
}
|
||||
|
|
|
@ -31,3 +31,8 @@ message GetVersionResponse
|
|||
{
|
||||
kiapi.common.types.KiCadVersion version = 1;
|
||||
}
|
||||
|
||||
// A command to check if the connection to KiCad is OK
|
||||
message Ping
|
||||
{
|
||||
}
|
||||
|
|
|
@ -27,17 +27,18 @@ package kiapi.common.commands;
|
|||
|
||||
import "google/protobuf/any.proto";
|
||||
import "common/types/base_types.proto";
|
||||
import "common/types/enums.proto";
|
||||
|
||||
/// Refreshes the given frame, if that frame is open
|
||||
// Refreshes the given frame, if that frame is open
|
||||
message RefreshEditor
|
||||
{
|
||||
kiapi.common.types.FrameType frame = 1;
|
||||
}
|
||||
|
||||
/// Retrieves a list of open documents of the given type
|
||||
// Retrieves a list of open documents of the given type
|
||||
message GetOpenDocuments
|
||||
{
|
||||
/// Which type of documents to query
|
||||
// Which type of documents to query
|
||||
kiapi.common.types.DocumentType type = 1;
|
||||
}
|
||||
|
||||
|
@ -86,140 +87,150 @@ message BeginCommit
|
|||
|
||||
message BeginCommitResponse
|
||||
{
|
||||
// Opaque identifier tracking a commit
|
||||
kiapi.common.types.KIID id = 1;
|
||||
}
|
||||
|
||||
|
||||
enum CommitResult
|
||||
enum CommitAction
|
||||
{
|
||||
CR_UNKNOWN = 0;
|
||||
CR_OK = 1; // Commit was pushed successfully
|
||||
CR_NO_COMMIT = 2; // There was no commit started
|
||||
CMA_UNKNOWN = 0;
|
||||
CMA_COMMIT = 1; // Commit the changes to the design
|
||||
CMA_DROP = 2; // Cancel this commit
|
||||
}
|
||||
|
||||
|
||||
message EndCommit
|
||||
{
|
||||
// The ID that was given by BeginCommit
|
||||
kiapi.common.types.KIID id = 1;
|
||||
|
||||
// What to do with this commit
|
||||
CommitAction action = 2;
|
||||
|
||||
// Optional message describing this changeset
|
||||
string message = 1;
|
||||
string message = 3;
|
||||
}
|
||||
|
||||
|
||||
message EndCommitResponse
|
||||
{
|
||||
CommitResult result = 1;
|
||||
}
|
||||
|
||||
/// Creates new items on a given document
|
||||
// Creates new items on a given document
|
||||
message CreateItems
|
||||
{
|
||||
/// Specifies which document to create on, which fields are included, etc.
|
||||
// Specifies which document to create on, which fields are included, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// List of items to create
|
||||
// List of items to create
|
||||
repeated google.protobuf.Any items = 2;
|
||||
|
||||
/// Items may be created on a top-level document (sheet, board, etc) or inside a container
|
||||
/// (symbol, footprint). If this field is not empty, it holds the ID of a symbol or footprint
|
||||
/// that the items should be added to. This ID must be an existing symbol (for schematic
|
||||
/// documents) or footprint (for board documents). If the given container does not exist or is
|
||||
/// not the correct item type, the CreateItems call will fail.
|
||||
// Items may be created on a top-level document (sheet, board, etc) or inside a container
|
||||
// (symbol, footprint). If this field is not empty, it holds the ID of a symbol or footprint
|
||||
// that the items should be added to. This ID must be an existing symbol (for schematic
|
||||
// documents) or footprint (for board documents). If the given container does not exist or is
|
||||
// not the correct item type, the CreateItems call will fail.
|
||||
kiapi.common.types.KIID container = 3;
|
||||
}
|
||||
|
||||
enum ItemCreationStatus
|
||||
enum ItemStatusCode
|
||||
{
|
||||
ICS_UNKNOWN = 0;
|
||||
ICS_OK = 1; /// The item was created
|
||||
ICS_INVALID_TYPE = 2; /// The item's type is not valid for the given document
|
||||
ICS_EXISTING = 3; /// The item had a specified KIID and that KIID was already in use
|
||||
ISC_UNKNOWN = 0;
|
||||
ISC_OK = 1; // The item was created or updated
|
||||
ISC_INVALID_TYPE = 2; // The item's type is not valid for the given document
|
||||
ISC_EXISTING = 3; // The item to be created had a specified KIID and that KIID was already in use
|
||||
ISC_NONEXISTENT = 4; // The item to be updated did not exist in the given document
|
||||
ISC_IMMUTABLE = 5; // The item to be updated is not allowed to be modified by the API
|
||||
ISC_INVALID_DATA = 7; // The item to be created does not have valid data for the given document
|
||||
}
|
||||
|
||||
// Per-item status feedback for creation and update calls
|
||||
message ItemStatus
|
||||
{
|
||||
ItemStatusCode code = 1;
|
||||
|
||||
string error_message = 2;
|
||||
}
|
||||
|
||||
message ItemCreationResult
|
||||
{
|
||||
ItemCreationStatus status = 1;
|
||||
ItemStatus status = 1;
|
||||
|
||||
/// The created version of the item, including an updated KIID as applicable
|
||||
// The created version of the item, including an updated KIID as applicable
|
||||
google.protobuf.Any item = 2;
|
||||
}
|
||||
|
||||
message CreateItemsResponse
|
||||
{
|
||||
/// Specifies which document was modified, which fields are included in created_items, etc.
|
||||
// Specifies which document was modified, which fields are included in created_items, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// Status of the overall request; may return IRS_OK even if no items were created
|
||||
// Status of the overall request; may return IRS_OK even if no items were created
|
||||
kiapi.common.types.ItemRequestStatus status = 2;
|
||||
|
||||
/// Status of each item to be created
|
||||
// Status of each item to be created
|
||||
repeated ItemCreationResult created_items = 3;
|
||||
}
|
||||
|
||||
message GetItems
|
||||
{
|
||||
/// Specifies which document to query, which fields to return, etc.
|
||||
// Specifies which document to query, which fields to return, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// List of one or more types of items to retreive
|
||||
repeated kiapi.common.types.ItemType types = 2;
|
||||
// List of one or more types of items to retreive
|
||||
repeated kiapi.common.types.KiCadObjectType types = 2;
|
||||
}
|
||||
|
||||
message GetItemsResponse
|
||||
{
|
||||
/// Specifies which document was modified, which fields are included in items, etc.
|
||||
// Specifies which document was modified, which fields are included in items, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// Status of the overall request; may return IRS_OK even if no items were retrieved
|
||||
// Status of the overall request; may return IRS_OK even if no items were retrieved
|
||||
kiapi.common.types.ItemRequestStatus status = 2;
|
||||
|
||||
repeated google.protobuf.Any items = 3;
|
||||
}
|
||||
|
||||
/// Updates items in a given document
|
||||
// Updates items in a given document
|
||||
message UpdateItems
|
||||
{
|
||||
/// Specifies which document to modify, which fields are included, etc.
|
||||
// Specifies which document to modify, which fields are included, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// List of items to modify
|
||||
// List of items to modify
|
||||
repeated google.protobuf.Any items = 2;
|
||||
}
|
||||
|
||||
enum ItemUpdateStatus
|
||||
{
|
||||
IUS_UNKNOWN = 0;
|
||||
IUS_OK = 1; /// The item was updated
|
||||
IUS_INVALID_TYPE = 2; /// The item's type is not valid for the given document
|
||||
IUS_NONEXISTENT = 3; /// The item did not exist in the given document
|
||||
IUS_IMMUTABLE = 4; /// The item is not allowed to be modified by the API
|
||||
}
|
||||
|
||||
message ItemUpdateResult
|
||||
{
|
||||
ItemUpdateStatus status = 1;
|
||||
ItemStatus status = 1;
|
||||
|
||||
/// The update version of the item
|
||||
// The update version of the item
|
||||
google.protobuf.Any item = 2;
|
||||
}
|
||||
|
||||
message UpdateItemsResponse
|
||||
{
|
||||
/// Specifies which document was modified, which fields are included in updated_items, etc.
|
||||
// Specifies which document was modified, which fields are included in updated_items, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// Status of the overall request; may return IRS_OK even if no items were modified
|
||||
// Status of the overall request; may return IRS_OK even if no items were modified
|
||||
kiapi.common.types.ItemRequestStatus status = 2;
|
||||
|
||||
/// Status of each item to be created
|
||||
// Status of each item to be created
|
||||
repeated ItemUpdateResult updated_items = 3;
|
||||
}
|
||||
|
||||
/// Deletes items in a given document
|
||||
// Deletes items in a given document
|
||||
message DeleteItems
|
||||
{
|
||||
/// Specifies which document to modify
|
||||
// Specifies which document to modify
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// List of item KIIDs to delete
|
||||
// List of item KIIDs to delete
|
||||
repeated kiapi.common.types.KIID item_ids = 2;
|
||||
}
|
||||
|
||||
|
@ -227,8 +238,8 @@ enum ItemDeletionStatus
|
|||
{
|
||||
IDS_UNKNOWN = 0;
|
||||
IDS_OK = 1;
|
||||
IDS_NONEXISTENT = 2; /// The item did not exist in the given document
|
||||
IDS_IMMUTABLE = 3; /// The item is not allowed to be modified by the API
|
||||
IDS_NONEXISTENT = 2; // The item did not exist in the given document
|
||||
IDS_IMMUTABLE = 3; // The item is not allowed to be modified by the API
|
||||
}
|
||||
|
||||
message ItemDeletionResult
|
||||
|
@ -240,12 +251,49 @@ message ItemDeletionResult
|
|||
|
||||
message DeleteItemsResponse
|
||||
{
|
||||
/// Specifies which document was modified, etc.
|
||||
// Specifies which document was modified, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// Status of the overall request; may return IRS_OK even if no items were deleted
|
||||
// Status of the overall request; may return IRS_OK even if no items were deleted
|
||||
kiapi.common.types.ItemRequestStatus status = 2;
|
||||
|
||||
/// Status of each item requested to be deleted
|
||||
// Status of each item requested to be deleted
|
||||
repeated ItemDeletionResult deleted_items = 3;
|
||||
}
|
||||
|
||||
message GetItemBoundingBox
|
||||
{
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
kiapi.common.types.KIID id = 2;
|
||||
}
|
||||
|
||||
message BoundingBoxResponse
|
||||
{
|
||||
kiapi.common.types.Vector2 position = 1;
|
||||
kiapi.common.types.Vector2 size = 2;
|
||||
}
|
||||
|
||||
// Tests if a certain point falls within tolerance of an item's geometry
|
||||
message HitTest
|
||||
{
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
kiapi.common.types.KIID id = 2;
|
||||
|
||||
kiapi.common.types.Vector2 position = 3;
|
||||
|
||||
int32 tolerance = 4;
|
||||
}
|
||||
|
||||
enum HitTestResult
|
||||
{
|
||||
HTR_UNKNOWN = 0;
|
||||
HTR_NO_HIT = 1;
|
||||
HTR_HIT = 2;
|
||||
}
|
||||
|
||||
message HitTestResponse
|
||||
{
|
||||
HitTestResult result = 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.common.commands;
|
||||
|
||||
import "common/types/project_settings.proto";
|
||||
|
||||
|
||||
message GetNetClasses
|
||||
{
|
||||
}
|
||||
|
||||
message NetClassesResponse
|
||||
{
|
||||
repeated kiapi.common.project.NetClass net_classes = 1;
|
||||
}
|
|
@ -29,9 +29,11 @@ enum ApiStatusCode
|
|||
AS_OK = 1; // Request succeeded
|
||||
AS_TIMEOUT = 2; // Request timed out
|
||||
AS_BAD_REQUEST = 3; // The request had invalid parameters or otherwise was illegal
|
||||
AS_NOT_READY = 4; // KiCad was not (yet) in a state where it could handle API requests
|
||||
AS_NOT_READY = 4; // KiCad has recently started and cannot handle API requests yet
|
||||
AS_UNHANDLED = 5; // The request was not handled by KiCad
|
||||
AS_TOKEN_MISMATCH = 6; // The kicad_token in the request didn't match this KiCad's token
|
||||
AS_BUSY = 7; // KiCad is busy performing an operation and can't accept API commands
|
||||
AS_UNIMPLEMENTED = 8; // The requested API call has not yet been implemented
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -27,6 +27,7 @@ syntax = "proto3";
|
|||
package kiapi.common.types;
|
||||
|
||||
import "google/protobuf/field_mask.proto";
|
||||
import "common/types/enums.proto";
|
||||
|
||||
enum CommandStatus
|
||||
{
|
||||
|
@ -95,10 +96,10 @@ enum DocumentType
|
|||
*/
|
||||
message LibraryIdentifier
|
||||
{
|
||||
/// The library portion of the LIB_ID
|
||||
// The library portion of the LIB_ID
|
||||
string library_nickname = 1;
|
||||
|
||||
/// The symbol or footprint name
|
||||
// The symbol or footprint name
|
||||
string entry_name = 2;
|
||||
}
|
||||
|
||||
|
@ -107,13 +108,25 @@ message LibraryIdentifier
|
|||
*/
|
||||
message SheetPath
|
||||
{
|
||||
/// The canonical path to the sheet. The first KIID will be the root sheet, etc.
|
||||
// The canonical path to the sheet. The first KIID will be the root sheet, etc.
|
||||
repeated KIID path = 1;
|
||||
|
||||
/// The path converted to a human readable form such as "/", "/child", or "/child/grandchild"
|
||||
// The path converted to a human readable form such as "/", "/child", or "/child/grandchild"
|
||||
string path_human_readable = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a KiCad project
|
||||
*/
|
||||
message ProjectSpecifier
|
||||
{
|
||||
// The name of the project (without the kicad_pro extension)
|
||||
string name = 1;
|
||||
|
||||
// The path to the project directory
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a document that will be the target of a request
|
||||
*/
|
||||
|
@ -123,24 +136,17 @@ message DocumentSpecifier
|
|||
|
||||
oneof identifier
|
||||
{
|
||||
/// If type == DT_SYMBOL or DT_FOOTPRINT, identifies a certain library entry
|
||||
// If type == DT_SYMBOL or DT_FOOTPRINT, identifies a certain library entry
|
||||
LibraryIdentifier lib_id = 2;
|
||||
|
||||
/// If type == DT_SCHEMATIC, identifies a sheet with a given path
|
||||
// If type == DT_SCHEMATIC, identifies a sheet with a given path
|
||||
SheetPath sheet_path = 3;
|
||||
|
||||
/// If type == DT_PCB, identifies a PCB with a given filename, e.g. "board.kicad_pcb"
|
||||
// If type == DT_PCB, identifies a PCB with a given filename, e.g. "board.kicad_pcb"
|
||||
string board_filename = 4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the type of a KiCad item (wrapper for KICAD_T)
|
||||
*/
|
||||
message ItemType
|
||||
{
|
||||
/// Must be a valid value in the KICAD_T C++ enum (see typeinfo.h)
|
||||
int32 type = 1;
|
||||
ProjectSpecifier project = 5;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,11 +154,15 @@ message ItemType
|
|||
*/
|
||||
message ItemHeader
|
||||
{
|
||||
/// Which document is this request targeting?
|
||||
// Which document is this request targeting?
|
||||
DocumentSpecifier document = 1;
|
||||
|
||||
/// Which fields on the item(s) are included with this request or response
|
||||
google.protobuf.FieldMask field_mask = 2;
|
||||
// Which container within the document is this request targeting?
|
||||
// If container is omitted or empty, the document is used as the container.
|
||||
KIID container = 2;
|
||||
|
||||
// Which fields on the item(s) are included with this request or response
|
||||
google.protobuf.FieldMask field_mask = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,32 +172,93 @@ enum ItemRequestStatus
|
|||
{
|
||||
IRS_UNKNOWN = 0;
|
||||
IRS_OK = 1;
|
||||
IRS_DOCUMENT_NOT_FOUND = 2; /// The given document is not open in KiCad
|
||||
IRS_FIELD_MASK_INVALID = 3; /// The given field_mask contains invalid specifiers
|
||||
IRS_DOCUMENT_NOT_FOUND = 2; // The given document is not open in KiCad
|
||||
IRS_FIELD_MASK_INVALID = 3; // The given field_mask contains invalid specifiers
|
||||
}
|
||||
|
||||
/// Describes a point in 2D space. All coordinates are in nanometers.
|
||||
message Point2D
|
||||
// Describes a point or distance in 2D space. All coordinates are in nanometers.
|
||||
message Vector2
|
||||
{
|
||||
int64 x_nm = 1;
|
||||
int64 y_nm = 2;
|
||||
}
|
||||
|
||||
/// Describes a point in 3D space. All coordinates are in nanometers.
|
||||
message Point3D
|
||||
// Describes a point or distance in 3D space. All coordinates are in nanometers.
|
||||
message Vector3
|
||||
{
|
||||
int64 x_nm = 1;
|
||||
int64 y_nm = 2;
|
||||
int64 z_nm = 3;
|
||||
}
|
||||
|
||||
/// Describes a quantity of distance (size, length, etc). All coordinates are in nanometers.
|
||||
// Describes a quantity of distance (size, length, etc). All coordinates are in nanometers.
|
||||
message Distance
|
||||
{
|
||||
int64 value_nm = 1;
|
||||
}
|
||||
|
||||
/// Describes whether or not an item is locked for editing or movement
|
||||
// Corresponds to EDA_ANGLE, where the underlying storage is degrees
|
||||
message Angle
|
||||
{
|
||||
double value_degrees = 1;
|
||||
}
|
||||
|
||||
// Represents a value from 0.0 to 1.0
|
||||
message Ratio
|
||||
{
|
||||
double value = 1;
|
||||
}
|
||||
|
||||
// Corresponds to COLOR4D. Each color channel is a double from 0.0 to 1.0.
|
||||
message Color
|
||||
{
|
||||
double r = 1;
|
||||
double g = 2;
|
||||
double b = 3;
|
||||
double a = 4;
|
||||
}
|
||||
|
||||
// The formulation of arc that is used in KiCad core geometry code.
|
||||
// Start, midpoint (on the arc) and end are stored. Angle, center point, etc are calculated.
|
||||
message ArcStartMidEnd
|
||||
{
|
||||
Vector2 start = 1;
|
||||
Vector2 mid = 2;
|
||||
Vector2 end = 3;
|
||||
}
|
||||
|
||||
message PolyLineNode
|
||||
{
|
||||
oneof geometry {
|
||||
Vector2 point = 1;
|
||||
ArcStartMidEnd arc = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Corresponds to class SHAPE_LINE_CHAIN: A closed or open polyline that can include arcs.
|
||||
// For non-arc cases, each node is a point along the line. An implicit line segment exists
|
||||
// between the last and first node if closed is true. When arcs are present, the arc start and
|
||||
// end points are not duplicated by point nodes (meaning, for example, a rectangle with rounded
|
||||
// corners could be represented with four arc nodes and no point nodes).
|
||||
message PolyLine
|
||||
{
|
||||
repeated PolyLineNode nodes = 1;
|
||||
bool closed = 2;
|
||||
}
|
||||
|
||||
message PolygonWithHoles
|
||||
{
|
||||
PolyLine outline = 1;
|
||||
repeated PolyLine holes = 2;
|
||||
}
|
||||
|
||||
// Corresponds to SHAPE_POLY_SET: a set of polygons or polylines
|
||||
message PolySet
|
||||
{
|
||||
repeated PolygonWithHoles polygons = 1;
|
||||
}
|
||||
|
||||
// Describes whether or not an item is locked for editing or movement
|
||||
enum LockedState
|
||||
{
|
||||
LS_UNKNOWN = 0;
|
||||
|
@ -195,23 +266,69 @@ enum LockedState
|
|||
LS_LOCKED = 2;
|
||||
}
|
||||
|
||||
message BoardLayer
|
||||
message TextAttributes
|
||||
{
|
||||
int32 layer_id = 1; /// From PCB_LAYER_T
|
||||
string font_name = 1;
|
||||
HorizontalAlignment horizontal_alignment = 2;
|
||||
VerticalAlignment vertical_alignment = 3;
|
||||
kiapi.common.types.Angle angle = 4;
|
||||
double line_spacing = 5;
|
||||
kiapi.common.types.Distance stroke_width = 6;
|
||||
bool italic = 7;
|
||||
bool bold = 8;
|
||||
bool underlined = 9;
|
||||
bool visible = 10;
|
||||
bool mirrored = 11;
|
||||
bool multiline = 12;
|
||||
bool keep_upright = 13;
|
||||
kiapi.common.types.Vector2 size = 14;
|
||||
}
|
||||
|
||||
/// Describes a copper item's net
|
||||
message Net
|
||||
message Text
|
||||
{
|
||||
/// A unique code representing this net
|
||||
int32 code = 1;
|
||||
|
||||
/// Human-readable net name
|
||||
string name = 2;
|
||||
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;
|
||||
}
|
||||
|
||||
/// Describes a net class (a grouping of nets)
|
||||
message NetClass
|
||||
message TextBox
|
||||
{
|
||||
string name = 1;
|
||||
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;
|
||||
kiapi.common.types.LockedState locked = 5;
|
||||
string text = 6;
|
||||
}
|
||||
|
||||
message StrokeAttributes
|
||||
{
|
||||
Distance width = 1;
|
||||
StrokeLineStyle style = 2;
|
||||
Color color = 3;
|
||||
}
|
||||
|
||||
enum GraphicFillType
|
||||
{
|
||||
GFT_UNKNOWN = 0;
|
||||
GFT_UNFILLED = 1;
|
||||
GFT_FILLED = 2;
|
||||
}
|
||||
|
||||
message GraphicFillAttributes
|
||||
{
|
||||
GraphicFillType fill_type = 1;
|
||||
|
||||
// Color of the fill (not used in board and footprints)
|
||||
Color color = 2;
|
||||
}
|
||||
|
||||
message GraphicAttributes
|
||||
{
|
||||
StrokeAttributes stroke = 1;
|
||||
GraphicFillAttributes fill = 2;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* enums.proto
|
||||
* Includes protobuf versions of common KiCad enums
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.common.types;
|
||||
|
||||
// The set of object types (from KICAD_T) that are exposed to the API.
|
||||
enum KiCadObjectType
|
||||
{
|
||||
KOT_UNKNOWN = 0;
|
||||
|
||||
KOT_PCB_FOOTPRINT = 1;
|
||||
KOT_PCB_PAD = 2;
|
||||
KOT_PCB_SHAPE = 3;
|
||||
KOT_PCB_REFERENCE_IMAGE = 4;
|
||||
KOT_PCB_FIELD = 5;
|
||||
KOT_PCB_GENERATOR = 6;
|
||||
KOT_PCB_TEXT = 7;
|
||||
KOT_PCB_TEXTBOX = 8;
|
||||
KOT_PCB_TABLE = 9;
|
||||
KOT_PCB_TABLECELL = 10;
|
||||
KOT_PCB_TRACE = 11;
|
||||
KOT_PCB_VIA = 12;
|
||||
KOT_PCB_ARC = 13;
|
||||
KOT_PCB_MARKER = 14;
|
||||
KOT_PCB_DIMENSION = 15;
|
||||
KOT_PCB_ZONE = 16;
|
||||
KOT_PCB_GROUP = 17;
|
||||
|
||||
KOT_SCH_MARKER = 18;
|
||||
KOT_SCH_JUNCTION = 19;
|
||||
KOT_SCH_NO_CONNECT = 20;
|
||||
KOT_SCH_BUS_WIRE_ENTRY = 21;
|
||||
KOT_SCH_BUS_BUS_ENTRY = 22;
|
||||
KOT_SCH_LINE = 23;
|
||||
KOT_SCH_SHAPE = 24;
|
||||
KOT_SCH_BITMAP = 25;
|
||||
KOT_SCH_TEXTBOX = 26;
|
||||
KOT_SCH_TEXT = 27;
|
||||
KOT_SCH_TABLE = 28;
|
||||
KOT_SCH_TABLECELL = 29;
|
||||
KOT_SCH_LABEL = 30;
|
||||
KOT_SCH_GLOBAL_LABEL = 31;
|
||||
KOT_SCH_HIER_LABEL = 32;
|
||||
KOT_SCH_DIRECTIVE_LABEL = 33;
|
||||
KOT_SCH_FIELD = 34;
|
||||
KOT_SCH_SYMBOL = 35;
|
||||
KOT_SCH_SHEET_PIN = 36;
|
||||
KOT_SCH_SHEET = 37;
|
||||
KOT_SCH_PIN = 38;
|
||||
|
||||
KOT_LIB_SYMBOL = 39;
|
||||
KOT_LIB_SHAPE = 40;
|
||||
KOT_LIB_TEXT = 41;
|
||||
KOT_LIB_TEXTBOX = 42;
|
||||
KOT_LIB_PIN = 43;
|
||||
KOT_LIB_FIELD = 44;
|
||||
|
||||
KOT_WSG_LINE = 45;
|
||||
KOT_WSG_RECT = 46;
|
||||
KOT_WSG_POLY = 47;
|
||||
KOT_WSG_TEXT = 48;
|
||||
KOT_WSG_BITMAP = 49;
|
||||
KOT_WSG_PAGE = 50;
|
||||
}
|
||||
|
||||
// Mapped to GR_TEXT_H_ALIGN_T
|
||||
enum HorizontalAlignment
|
||||
{
|
||||
HA_UNKNOWN = 0;
|
||||
HA_LEFT = 1;
|
||||
HA_CENTER = 2;
|
||||
HA_RIGHT = 3;
|
||||
HA_INDETERMINATE = 4;
|
||||
}
|
||||
|
||||
// Mapped to GR_TEXT_V_ALIGN_T
|
||||
enum VerticalAlignment
|
||||
{
|
||||
VA_UNKNOWN = 0;
|
||||
VA_TOP = 1;
|
||||
VA_CENTER = 2;
|
||||
VA_BOTTOM = 3;
|
||||
VA_INDETERMINATE = 4;
|
||||
}
|
||||
|
||||
// Mapped to LINE_STYLE
|
||||
enum StrokeLineStyle
|
||||
{
|
||||
SLS_UNKNOWN = 0;
|
||||
SLS_DEFAULT = 1;
|
||||
SLS_SOLID = 2;
|
||||
SLS_DASH = 3;
|
||||
SLS_DOT = 4;
|
||||
SLS_DASHDOT = 5;
|
||||
SLS_DASHDOTDOT = 6;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* project_settings.proto
|
||||
* Messages that describes project settings shared between schematics and boards
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.common.project;
|
||||
|
||||
|
||||
message NetClass
|
||||
{
|
||||
// The name of the netclass (the literal string "Default" for the default netclass)
|
||||
string name = 1;
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.schematic.types;
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.schematic.types;
|
||||
|
||||
import "common/types/base_types.proto";
|
||||
|
||||
enum SchematicLayer
|
||||
{
|
||||
SL_UNKNOWN = 0;
|
||||
}
|
||||
|
||||
/// Represents a schematic line segment, which may be a wire, bus, or graphical line
|
||||
message Line
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Vector2 start = 2;
|
||||
kiapi.common.types.Vector2 end = 3;
|
||||
|
||||
/**
|
||||
* One of: LAYER_BUS, LAYER_WIRE, LAYER_NOTES
|
||||
*/
|
||||
SchematicLayer layer = 4;
|
||||
}
|
||||
|
||||
message Text
|
||||
{
|
||||
kiapi.common.types.Text text = 1;
|
||||
}
|
||||
|
||||
message LocalLabel
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Vector2 position = 2;
|
||||
Text text = 3;
|
||||
}
|
||||
|
||||
message GlobalLabel
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Vector2 position = 2;
|
||||
Text text = 3;
|
||||
}
|
||||
|
||||
message HierarchicalLabel
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Vector2 position = 2;
|
||||
Text text = 3;
|
||||
}
|
||||
|
||||
message DirectiveLabel
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
kiapi.common.types.Vector2 position = 2;
|
||||
Text text = 3;
|
||||
}
|
|
@ -41,8 +41,7 @@ add_custom_target(
|
|||
-DSRC_PATH=${PROJECT_SOURCE_DIR}
|
||||
-DKICAD_CMAKE_MODULE_PATH=${KICAD_CMAKE_MODULE_PATH}
|
||||
-P ${KICAD_CMAKE_MODULE_PATH}/BuildSteps/WriteVersionHeader.cmake
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/kicad_build_version.h
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} BYPRODUCTS ${CMAKE_BINARY_DIR}/kicad_build_version.h
|
||||
DEPENDS ${KICAD_CMAKE_MODULE_PATH}/BuildSteps/WriteVersionHeader.cmake
|
||||
COMMENT "Generating version string header"
|
||||
)
|
||||
|
@ -632,14 +631,14 @@ set( COMMON_SRCS
|
|||
http_lib/http_lib_connection.cpp
|
||||
http_lib/http_lib_settings.cpp
|
||||
|
||||
api/api_enums.cpp
|
||||
api/api_utils.cpp
|
||||
)
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
set( COMMON_SRCS
|
||||
${COMMON_SRCS}
|
||||
api/api_server.cpp
|
||||
api/api_handler.cpp
|
||||
api/api_handler_common.cpp
|
||||
api/api_handler_editor.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -693,6 +692,7 @@ target_include_directories( common
|
|||
.
|
||||
${CMAKE_BINARY_DIR}
|
||||
$<TARGET_PROPERTY:argparse::argparse,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:kiapi,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
||||
# text markup support
|
||||
|
@ -794,6 +794,12 @@ set( PCB_COMMON_SRCS
|
|||
widgets/net_selector.cpp
|
||||
)
|
||||
|
||||
set( PCB_COMMON_SRCS
|
||||
${PCB_COMMON_SRCS}
|
||||
${CMAKE_SOURCE_DIR}/pcbnew/api/api_pcb_enums.cpp
|
||||
${CMAKE_SOURCE_DIR}/pcbnew/api/api_pcb_utils.cpp
|
||||
)
|
||||
|
||||
# add -DPCBNEW to compilation of these PCBNEW sources
|
||||
set_source_files_properties( ${PCB_COMMON_SRCS} PROPERTIES
|
||||
COMPILE_DEFINITIONS "PCBNEW"
|
||||
|
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* 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/api_enums.h>
|
||||
#include <import_export.h>
|
||||
#include <api/common/types/enums.pb.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
#include <api/schematic/schematic_types.pb.h>
|
||||
|
||||
#include <core/typeinfo.h>
|
||||
#include <font/text_attributes.h>
|
||||
#include <layer_ids.h>
|
||||
#include <stroke_params.h>
|
||||
|
||||
using namespace kiapi;
|
||||
using namespace kiapi::common;
|
||||
|
||||
template<>
|
||||
KICAD_T FromProtoEnum( types::KiCadObjectType aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case types::KiCadObjectType::KOT_PCB_FOOTPRINT: return PCB_FOOTPRINT_T;
|
||||
case types::KiCadObjectType::KOT_PCB_PAD: return PCB_PAD_T;
|
||||
case types::KiCadObjectType::KOT_PCB_SHAPE: return PCB_SHAPE_T;
|
||||
case types::KiCadObjectType::KOT_PCB_REFERENCE_IMAGE: return PCB_REFERENCE_IMAGE_T;
|
||||
case types::KiCadObjectType::KOT_PCB_FIELD: return PCB_FIELD_T;
|
||||
case types::KiCadObjectType::KOT_PCB_GENERATOR: return PCB_GENERATOR_T;
|
||||
case types::KiCadObjectType::KOT_PCB_TEXT: return PCB_TEXT_T;
|
||||
case types::KiCadObjectType::KOT_PCB_TEXTBOX: return PCB_TEXTBOX_T;
|
||||
case types::KiCadObjectType::KOT_PCB_TABLE: return PCB_TABLE_T;
|
||||
case types::KiCadObjectType::KOT_PCB_TABLECELL: return PCB_TABLECELL_T;
|
||||
case types::KiCadObjectType::KOT_PCB_TRACE: return PCB_TRACE_T;
|
||||
case types::KiCadObjectType::KOT_PCB_VIA: return PCB_VIA_T;
|
||||
case types::KiCadObjectType::KOT_PCB_ARC: return PCB_ARC_T;
|
||||
case types::KiCadObjectType::KOT_PCB_MARKER: return PCB_MARKER_T;
|
||||
case types::KiCadObjectType::KOT_PCB_DIMENSION: return PCB_DIMENSION_T;
|
||||
case types::KiCadObjectType::KOT_PCB_ZONE: return PCB_ZONE_T;
|
||||
case types::KiCadObjectType::KOT_PCB_GROUP: return PCB_GROUP_T;
|
||||
case types::KiCadObjectType::KOT_SCH_MARKER: return SCH_MARKER_T;
|
||||
case types::KiCadObjectType::KOT_SCH_JUNCTION: return SCH_JUNCTION_T;
|
||||
case types::KiCadObjectType::KOT_SCH_NO_CONNECT: return SCH_NO_CONNECT_T;
|
||||
case types::KiCadObjectType::KOT_SCH_BUS_WIRE_ENTRY: return SCH_BUS_WIRE_ENTRY_T;
|
||||
case types::KiCadObjectType::KOT_SCH_BUS_BUS_ENTRY: return SCH_BUS_BUS_ENTRY_T;
|
||||
case types::KiCadObjectType::KOT_SCH_LINE: return SCH_LINE_T;
|
||||
case types::KiCadObjectType::KOT_SCH_SHAPE: return SCH_SHAPE_T;
|
||||
case types::KiCadObjectType::KOT_SCH_BITMAP: return SCH_BITMAP_T;
|
||||
case types::KiCadObjectType::KOT_SCH_TEXTBOX: return SCH_TEXTBOX_T;
|
||||
case types::KiCadObjectType::KOT_SCH_TEXT: return SCH_TEXT_T;
|
||||
case types::KiCadObjectType::KOT_SCH_TABLE: return SCH_TABLE_T;
|
||||
case types::KiCadObjectType::KOT_SCH_TABLECELL: return SCH_TABLECELL_T;
|
||||
case types::KiCadObjectType::KOT_SCH_LABEL: return SCH_LABEL_T;
|
||||
case types::KiCadObjectType::KOT_SCH_GLOBAL_LABEL: return SCH_GLOBAL_LABEL_T;
|
||||
case types::KiCadObjectType::KOT_SCH_HIER_LABEL: return SCH_HIER_LABEL_T;
|
||||
case types::KiCadObjectType::KOT_SCH_DIRECTIVE_LABEL: return SCH_DIRECTIVE_LABEL_T;
|
||||
case types::KiCadObjectType::KOT_SCH_FIELD: return SCH_FIELD_T;
|
||||
case types::KiCadObjectType::KOT_SCH_SYMBOL: return SCH_SYMBOL_T;
|
||||
case types::KiCadObjectType::KOT_SCH_SHEET_PIN: return SCH_SHEET_PIN_T;
|
||||
case types::KiCadObjectType::KOT_SCH_SHEET: return SCH_SHEET_T;
|
||||
case types::KiCadObjectType::KOT_SCH_PIN: return SCH_PIN_T;
|
||||
case types::KiCadObjectType::KOT_LIB_SYMBOL: return LIB_SYMBOL_T;
|
||||
case types::KiCadObjectType::KOT_LIB_SHAPE: return LIB_SHAPE_T;
|
||||
case types::KiCadObjectType::KOT_LIB_TEXT: return LIB_TEXT_T;
|
||||
case types::KiCadObjectType::KOT_LIB_TEXTBOX: return LIB_TEXTBOX_T;
|
||||
case types::KiCadObjectType::KOT_LIB_PIN: return LIB_PIN_T;
|
||||
case types::KiCadObjectType::KOT_LIB_FIELD: return LIB_FIELD_T;
|
||||
case types::KiCadObjectType::KOT_WSG_LINE: return WSG_LINE_T;
|
||||
case types::KiCadObjectType::KOT_WSG_RECT: return WSG_RECT_T;
|
||||
case types::KiCadObjectType::KOT_WSG_POLY: return WSG_POLY_T;
|
||||
case types::KiCadObjectType::KOT_WSG_TEXT: return WSG_TEXT_T;
|
||||
case types::KiCadObjectType::KOT_WSG_BITMAP: return WSG_BITMAP_T;
|
||||
case types::KiCadObjectType::KOT_WSG_PAGE: return WSG_PAGE_T;
|
||||
|
||||
case types::KiCadObjectType::KOT_UNKNOWN: return TYPE_NOT_INIT;
|
||||
default:
|
||||
wxCHECK_MSG( false, TYPE_NOT_INIT,
|
||||
"Unhandled case in FromProtoEnum<types::KiCadObjectType>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
types::KiCadObjectType ToProtoEnum( KICAD_T aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case PCB_FOOTPRINT_T: return types::KiCadObjectType::KOT_PCB_FOOTPRINT;
|
||||
case PCB_PAD_T: return types::KiCadObjectType::KOT_PCB_PAD;
|
||||
case PCB_SHAPE_T: return types::KiCadObjectType::KOT_PCB_SHAPE;
|
||||
case PCB_REFERENCE_IMAGE_T: return types::KiCadObjectType::KOT_PCB_REFERENCE_IMAGE;
|
||||
case PCB_FIELD_T: return types::KiCadObjectType::KOT_PCB_FIELD;
|
||||
case PCB_GENERATOR_T: return types::KiCadObjectType::KOT_PCB_GENERATOR;
|
||||
case PCB_TEXT_T: return types::KiCadObjectType::KOT_PCB_TEXT;
|
||||
case PCB_TEXTBOX_T: return types::KiCadObjectType::KOT_PCB_TEXTBOX;
|
||||
case PCB_TABLE_T: return types::KiCadObjectType::KOT_PCB_TABLE;
|
||||
case PCB_TABLECELL_T: return types::KiCadObjectType::KOT_PCB_TABLECELL;
|
||||
case PCB_TRACE_T: return types::KiCadObjectType::KOT_PCB_TRACE;
|
||||
case PCB_VIA_T: return types::KiCadObjectType::KOT_PCB_VIA;
|
||||
case PCB_ARC_T: return types::KiCadObjectType::KOT_PCB_ARC;
|
||||
case PCB_MARKER_T: return types::KiCadObjectType::KOT_PCB_MARKER;
|
||||
case PCB_DIMENSION_T: return types::KiCadObjectType::KOT_PCB_DIMENSION;
|
||||
case PCB_ZONE_T: return types::KiCadObjectType::KOT_PCB_ZONE;
|
||||
case PCB_GROUP_T: return types::KiCadObjectType::KOT_PCB_GROUP;
|
||||
case SCH_MARKER_T: return types::KiCadObjectType::KOT_SCH_MARKER;
|
||||
case SCH_JUNCTION_T: return types::KiCadObjectType::KOT_SCH_JUNCTION;
|
||||
case SCH_NO_CONNECT_T: return types::KiCadObjectType::KOT_SCH_NO_CONNECT;
|
||||
case SCH_BUS_WIRE_ENTRY_T: return types::KiCadObjectType::KOT_SCH_BUS_WIRE_ENTRY;
|
||||
case SCH_BUS_BUS_ENTRY_T: return types::KiCadObjectType::KOT_SCH_BUS_BUS_ENTRY;
|
||||
case SCH_LINE_T: return types::KiCadObjectType::KOT_SCH_LINE;
|
||||
case SCH_SHAPE_T: return types::KiCadObjectType::KOT_SCH_SHAPE;
|
||||
case SCH_BITMAP_T: return types::KiCadObjectType::KOT_SCH_BITMAP;
|
||||
case SCH_TEXTBOX_T: return types::KiCadObjectType::KOT_SCH_TEXTBOX;
|
||||
case SCH_TEXT_T: return types::KiCadObjectType::KOT_SCH_TEXT;
|
||||
case SCH_TABLE_T: return types::KiCadObjectType::KOT_SCH_TABLE;
|
||||
case SCH_TABLECELL_T: return types::KiCadObjectType::KOT_SCH_TABLECELL;
|
||||
case SCH_LABEL_T: return types::KiCadObjectType::KOT_SCH_LABEL;
|
||||
case SCH_GLOBAL_LABEL_T: return types::KiCadObjectType::KOT_SCH_GLOBAL_LABEL;
|
||||
case SCH_HIER_LABEL_T: return types::KiCadObjectType::KOT_SCH_HIER_LABEL;
|
||||
case SCH_DIRECTIVE_LABEL_T: return types::KiCadObjectType::KOT_SCH_DIRECTIVE_LABEL;
|
||||
case SCH_FIELD_T: return types::KiCadObjectType::KOT_SCH_FIELD;
|
||||
case SCH_SYMBOL_T: return types::KiCadObjectType::KOT_SCH_SYMBOL;
|
||||
case SCH_SHEET_PIN_T: return types::KiCadObjectType::KOT_SCH_SHEET_PIN;
|
||||
case SCH_SHEET_T: return types::KiCadObjectType::KOT_SCH_SHEET;
|
||||
case SCH_PIN_T: return types::KiCadObjectType::KOT_SCH_PIN;
|
||||
case LIB_SYMBOL_T: return types::KiCadObjectType::KOT_LIB_SYMBOL;
|
||||
case LIB_SHAPE_T: return types::KiCadObjectType::KOT_LIB_SHAPE;
|
||||
case LIB_TEXT_T: return types::KiCadObjectType::KOT_LIB_TEXT;
|
||||
case LIB_TEXTBOX_T: return types::KiCadObjectType::KOT_LIB_TEXTBOX;
|
||||
case LIB_PIN_T: return types::KiCadObjectType::KOT_LIB_PIN;
|
||||
case LIB_FIELD_T: return types::KiCadObjectType::KOT_LIB_FIELD;
|
||||
case WSG_LINE_T: return types::KiCadObjectType::KOT_WSG_LINE;
|
||||
case WSG_RECT_T: return types::KiCadObjectType::KOT_WSG_RECT;
|
||||
case WSG_POLY_T: return types::KiCadObjectType::KOT_WSG_POLY;
|
||||
case WSG_TEXT_T: return types::KiCadObjectType::KOT_WSG_TEXT;
|
||||
case WSG_BITMAP_T: return types::KiCadObjectType::KOT_WSG_BITMAP;
|
||||
case WSG_PAGE_T: return types::KiCadObjectType::KOT_WSG_PAGE;
|
||||
default:
|
||||
wxCHECK_MSG( false, types::KiCadObjectType::KOT_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<KICAD_T>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
PCB_LAYER_ID FromProtoEnum( board::types::BoardLayer aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case board::types::BoardLayer::BL_UNDEFINED: return UNDEFINED_LAYER;
|
||||
case board::types::BoardLayer::BL_UNSELECTED: return UNSELECTED_LAYER;
|
||||
case board::types::BoardLayer::BL_F_Cu: return F_Cu;
|
||||
case board::types::BoardLayer::BL_In1_Cu: return In1_Cu;
|
||||
case board::types::BoardLayer::BL_In2_Cu: return In2_Cu;
|
||||
case board::types::BoardLayer::BL_In3_Cu: return In3_Cu;
|
||||
case board::types::BoardLayer::BL_In4_Cu: return In4_Cu;
|
||||
case board::types::BoardLayer::BL_In5_Cu: return In5_Cu;
|
||||
case board::types::BoardLayer::BL_In6_Cu: return In6_Cu;
|
||||
case board::types::BoardLayer::BL_In7_Cu: return In7_Cu;
|
||||
case board::types::BoardLayer::BL_In8_Cu: return In8_Cu;
|
||||
case board::types::BoardLayer::BL_In9_Cu: return In9_Cu;
|
||||
case board::types::BoardLayer::BL_In10_Cu: return In10_Cu;
|
||||
case board::types::BoardLayer::BL_In11_Cu: return In11_Cu;
|
||||
case board::types::BoardLayer::BL_In12_Cu: return In12_Cu;
|
||||
case board::types::BoardLayer::BL_In13_Cu: return In13_Cu;
|
||||
case board::types::BoardLayer::BL_In14_Cu: return In14_Cu;
|
||||
case board::types::BoardLayer::BL_In15_Cu: return In15_Cu;
|
||||
case board::types::BoardLayer::BL_In16_Cu: return In16_Cu;
|
||||
case board::types::BoardLayer::BL_In17_Cu: return In17_Cu;
|
||||
case board::types::BoardLayer::BL_In18_Cu: return In18_Cu;
|
||||
case board::types::BoardLayer::BL_In19_Cu: return In19_Cu;
|
||||
case board::types::BoardLayer::BL_In20_Cu: return In20_Cu;
|
||||
case board::types::BoardLayer::BL_In21_Cu: return In21_Cu;
|
||||
case board::types::BoardLayer::BL_In22_Cu: return In22_Cu;
|
||||
case board::types::BoardLayer::BL_In23_Cu: return In23_Cu;
|
||||
case board::types::BoardLayer::BL_In24_Cu: return In24_Cu;
|
||||
case board::types::BoardLayer::BL_In25_Cu: return In25_Cu;
|
||||
case board::types::BoardLayer::BL_In26_Cu: return In26_Cu;
|
||||
case board::types::BoardLayer::BL_In27_Cu: return In27_Cu;
|
||||
case board::types::BoardLayer::BL_In28_Cu: return In28_Cu;
|
||||
case board::types::BoardLayer::BL_In29_Cu: return In29_Cu;
|
||||
case board::types::BoardLayer::BL_In30_Cu: return In30_Cu;
|
||||
case board::types::BoardLayer::BL_B_Cu: return B_Cu;
|
||||
case board::types::BoardLayer::BL_B_Adhes: return B_Adhes;
|
||||
case board::types::BoardLayer::BL_F_Adhes: return F_Adhes;
|
||||
case board::types::BoardLayer::BL_B_Paste: return B_Paste;
|
||||
case board::types::BoardLayer::BL_F_Paste: return F_Paste;
|
||||
case board::types::BoardLayer::BL_B_SilkS: return B_SilkS;
|
||||
case board::types::BoardLayer::BL_F_SilkS: return F_SilkS;
|
||||
case board::types::BoardLayer::BL_B_Mask: return B_Mask;
|
||||
case board::types::BoardLayer::BL_F_Mask: return F_Mask;
|
||||
case board::types::BoardLayer::BL_Dwgs_User: return Dwgs_User;
|
||||
case board::types::BoardLayer::BL_Cmts_User: return Cmts_User;
|
||||
case board::types::BoardLayer::BL_Eco1_User: return Eco1_User;
|
||||
case board::types::BoardLayer::BL_Eco2_User: return Eco2_User;
|
||||
case board::types::BoardLayer::BL_Edge_Cuts: return Edge_Cuts;
|
||||
case board::types::BoardLayer::BL_Margin: return Margin;
|
||||
case board::types::BoardLayer::BL_B_CrtYd: return B_CrtYd;
|
||||
case board::types::BoardLayer::BL_F_CrtYd: return F_CrtYd;
|
||||
case board::types::BoardLayer::BL_B_Fab: return B_Fab;
|
||||
case board::types::BoardLayer::BL_F_Fab: return F_Fab;
|
||||
case board::types::BoardLayer::BL_User_1: return User_1;
|
||||
case board::types::BoardLayer::BL_User_2: return User_2;
|
||||
case board::types::BoardLayer::BL_User_3: return User_3;
|
||||
case board::types::BoardLayer::BL_User_4: return User_4;
|
||||
case board::types::BoardLayer::BL_User_5: return User_5;
|
||||
case board::types::BoardLayer::BL_User_6: return User_6;
|
||||
case board::types::BoardLayer::BL_User_7: return User_7;
|
||||
case board::types::BoardLayer::BL_User_8: return User_8;
|
||||
case board::types::BoardLayer::BL_User_9: return User_9;
|
||||
|
||||
case board::types::BoardLayer::BL_UNKNOWN: return UNDEFINED_LAYER;
|
||||
default:
|
||||
wxCHECK_MSG( false, UNDEFINED_LAYER,
|
||||
"Unhandled case in FromProtoEnum<board::types::BoardLayer>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
board::types::BoardLayer ToProtoEnum( PCB_LAYER_ID aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case UNDEFINED_LAYER: return board::types::BoardLayer::BL_UNDEFINED;
|
||||
case UNSELECTED_LAYER: return board::types::BoardLayer::BL_UNSELECTED;
|
||||
case F_Cu: return board::types::BoardLayer::BL_F_Cu;
|
||||
case In1_Cu: return board::types::BoardLayer::BL_In1_Cu;
|
||||
case In2_Cu: return board::types::BoardLayer::BL_In2_Cu;
|
||||
case In3_Cu: return board::types::BoardLayer::BL_In3_Cu;
|
||||
case In4_Cu: return board::types::BoardLayer::BL_In4_Cu;
|
||||
case In5_Cu: return board::types::BoardLayer::BL_In5_Cu;
|
||||
case In6_Cu: return board::types::BoardLayer::BL_In6_Cu;
|
||||
case In7_Cu: return board::types::BoardLayer::BL_In7_Cu;
|
||||
case In8_Cu: return board::types::BoardLayer::BL_In8_Cu;
|
||||
case In9_Cu: return board::types::BoardLayer::BL_In9_Cu;
|
||||
case In10_Cu: return board::types::BoardLayer::BL_In10_Cu;
|
||||
case In11_Cu: return board::types::BoardLayer::BL_In11_Cu;
|
||||
case In12_Cu: return board::types::BoardLayer::BL_In12_Cu;
|
||||
case In13_Cu: return board::types::BoardLayer::BL_In13_Cu;
|
||||
case In14_Cu: return board::types::BoardLayer::BL_In14_Cu;
|
||||
case In15_Cu: return board::types::BoardLayer::BL_In15_Cu;
|
||||
case In16_Cu: return board::types::BoardLayer::BL_In16_Cu;
|
||||
case In17_Cu: return board::types::BoardLayer::BL_In17_Cu;
|
||||
case In18_Cu: return board::types::BoardLayer::BL_In18_Cu;
|
||||
case In19_Cu: return board::types::BoardLayer::BL_In19_Cu;
|
||||
case In20_Cu: return board::types::BoardLayer::BL_In20_Cu;
|
||||
case In21_Cu: return board::types::BoardLayer::BL_In21_Cu;
|
||||
case In22_Cu: return board::types::BoardLayer::BL_In22_Cu;
|
||||
case In23_Cu: return board::types::BoardLayer::BL_In23_Cu;
|
||||
case In24_Cu: return board::types::BoardLayer::BL_In24_Cu;
|
||||
case In25_Cu: return board::types::BoardLayer::BL_In25_Cu;
|
||||
case In26_Cu: return board::types::BoardLayer::BL_In26_Cu;
|
||||
case In27_Cu: return board::types::BoardLayer::BL_In27_Cu;
|
||||
case In28_Cu: return board::types::BoardLayer::BL_In28_Cu;
|
||||
case In29_Cu: return board::types::BoardLayer::BL_In29_Cu;
|
||||
case In30_Cu: return board::types::BoardLayer::BL_In30_Cu;
|
||||
case B_Cu: return board::types::BoardLayer::BL_B_Cu;
|
||||
case B_Adhes: return board::types::BoardLayer::BL_B_Adhes;
|
||||
case F_Adhes: return board::types::BoardLayer::BL_F_Adhes;
|
||||
case B_Paste: return board::types::BoardLayer::BL_B_Paste;
|
||||
case F_Paste: return board::types::BoardLayer::BL_F_Paste;
|
||||
case B_SilkS: return board::types::BoardLayer::BL_B_SilkS;
|
||||
case F_SilkS: return board::types::BoardLayer::BL_F_SilkS;
|
||||
case B_Mask: return board::types::BoardLayer::BL_B_Mask;
|
||||
case F_Mask: return board::types::BoardLayer::BL_F_Mask;
|
||||
case Dwgs_User: return board::types::BoardLayer::BL_Dwgs_User;
|
||||
case Cmts_User: return board::types::BoardLayer::BL_Cmts_User;
|
||||
case Eco1_User: return board::types::BoardLayer::BL_Eco1_User;
|
||||
case Eco2_User: return board::types::BoardLayer::BL_Eco2_User;
|
||||
case Edge_Cuts: return board::types::BoardLayer::BL_Edge_Cuts;
|
||||
case Margin: return board::types::BoardLayer::BL_Margin;
|
||||
case B_CrtYd: return board::types::BoardLayer::BL_B_CrtYd;
|
||||
case F_CrtYd: return board::types::BoardLayer::BL_F_CrtYd;
|
||||
case B_Fab: return board::types::BoardLayer::BL_B_Fab;
|
||||
case F_Fab: return board::types::BoardLayer::BL_F_Fab;
|
||||
case User_1: return board::types::BoardLayer::BL_User_1;
|
||||
case User_2: return board::types::BoardLayer::BL_User_2;
|
||||
case User_3: return board::types::BoardLayer::BL_User_3;
|
||||
case User_4: return board::types::BoardLayer::BL_User_4;
|
||||
case User_5: return board::types::BoardLayer::BL_User_5;
|
||||
case User_6: return board::types::BoardLayer::BL_User_6;
|
||||
case User_7: return board::types::BoardLayer::BL_User_7;
|
||||
case User_8: return board::types::BoardLayer::BL_User_8;
|
||||
case User_9: return board::types::BoardLayer::BL_User_9;
|
||||
default:
|
||||
wxCHECK_MSG( false, board::types::BoardLayer::BL_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<PCB_LAYER_ID>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
SCH_LAYER_ID FromProtoEnum( schematic::types::SchematicLayer aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, SCH_LAYER_ID_START,
|
||||
"Unhandled case in FromProtoEnum<schematic::types::SchematicLayer>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
schematic::types::SchematicLayer ToProtoEnum( SCH_LAYER_ID aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, schematic::types::SchematicLayer::SL_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<SCH_LAYER_ID>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
GR_TEXT_H_ALIGN_T FromProtoEnum( types::HorizontalAlignment aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case types::HorizontalAlignment::HA_LEFT: return GR_TEXT_H_ALIGN_LEFT;
|
||||
case types::HorizontalAlignment::HA_CENTER: return GR_TEXT_H_ALIGN_CENTER;
|
||||
case types::HorizontalAlignment::HA_RIGHT: return GR_TEXT_H_ALIGN_RIGHT;
|
||||
case types::HorizontalAlignment::HA_INDETERMINATE: return GR_TEXT_H_ALIGN_INDETERMINATE;
|
||||
|
||||
case types::HorizontalAlignment::HA_UNKNOWN: return GR_TEXT_H_ALIGN_CENTER;
|
||||
default:
|
||||
wxCHECK_MSG( false, GR_TEXT_H_ALIGN_CENTER,
|
||||
"Unhandled case in FromProtoEnum<types::HorizontalAlignment>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
types::HorizontalAlignment ToProtoEnum( GR_TEXT_H_ALIGN_T aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: return types::HorizontalAlignment::HA_LEFT;
|
||||
case GR_TEXT_H_ALIGN_CENTER: return types::HorizontalAlignment::HA_CENTER;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: return types::HorizontalAlignment::HA_RIGHT;
|
||||
case GR_TEXT_H_ALIGN_INDETERMINATE: return types::HorizontalAlignment::HA_INDETERMINATE;
|
||||
default:
|
||||
wxCHECK_MSG( false, types::HorizontalAlignment::HA_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<GR_TEXT_H_ALIGN_T>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
GR_TEXT_V_ALIGN_T FromProtoEnum( types::VerticalAlignment aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case types::VerticalAlignment::VA_TOP: return GR_TEXT_V_ALIGN_TOP;
|
||||
case types::VerticalAlignment::VA_CENTER: return GR_TEXT_V_ALIGN_CENTER;
|
||||
case types::VerticalAlignment::VA_BOTTOM: return GR_TEXT_V_ALIGN_BOTTOM;
|
||||
case types::VerticalAlignment::VA_INDETERMINATE: return GR_TEXT_V_ALIGN_INDETERMINATE;
|
||||
|
||||
case types::VerticalAlignment::VA_UNKNOWN: return GR_TEXT_V_ALIGN_CENTER;
|
||||
default:
|
||||
wxCHECK_MSG( false, GR_TEXT_V_ALIGN_CENTER,
|
||||
"Unhandled case in FromProtoEnum<types::VerticalAlignment>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
types::VerticalAlignment ToProtoEnum( GR_TEXT_V_ALIGN_T aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: return types::VerticalAlignment::VA_TOP;
|
||||
case GR_TEXT_V_ALIGN_CENTER: return types::VerticalAlignment::VA_CENTER;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: return types::VerticalAlignment::VA_BOTTOM;
|
||||
case GR_TEXT_V_ALIGN_INDETERMINATE: return types::VerticalAlignment::VA_INDETERMINATE;
|
||||
default:
|
||||
wxCHECK_MSG( false, types::VerticalAlignment::VA_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<GR_TEXT_V_ALIGN_T>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
LINE_STYLE FromProtoEnum( types::StrokeLineStyle aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case types::StrokeLineStyle::SLS_DEFAULT: return LINE_STYLE::DEFAULT;
|
||||
case types::StrokeLineStyle::SLS_SOLID: return LINE_STYLE::SOLID;
|
||||
case types::StrokeLineStyle::SLS_DASH: return LINE_STYLE::DASH;
|
||||
case types::StrokeLineStyle::SLS_DOT: return LINE_STYLE::DOT;
|
||||
case types::StrokeLineStyle::SLS_DASHDOT: return LINE_STYLE::DASHDOT;
|
||||
case types::StrokeLineStyle::SLS_DASHDOTDOT: return LINE_STYLE::DASHDOTDOT;
|
||||
case types::StrokeLineStyle::SLS_UNKNOWN:
|
||||
default:
|
||||
wxCHECK_MSG( false, LINE_STYLE::DEFAULT,
|
||||
"Unhandled case in FromProtoEnum<types::StrokeLineStyle>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
types::StrokeLineStyle ToProtoEnum( LINE_STYLE aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case LINE_STYLE::DEFAULT: return types::StrokeLineStyle::SLS_DEFAULT;
|
||||
case LINE_STYLE::SOLID: return types::StrokeLineStyle::SLS_SOLID;
|
||||
case LINE_STYLE::DASH: return types::StrokeLineStyle::SLS_DASH;
|
||||
case LINE_STYLE::DOT: return types::StrokeLineStyle::SLS_DOT;
|
||||
case LINE_STYLE::DASHDOT: return types::StrokeLineStyle::SLS_DASHDOT;
|
||||
case LINE_STYLE::DASHDOTDOT: return types::StrokeLineStyle::SLS_DASHDOTDOT;
|
||||
default:
|
||||
wxCHECK_MSG( false, types::StrokeLineStyle::SLS_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<LINE_STYLE>");
|
||||
}
|
||||
}
|
|
@ -19,10 +19,14 @@
|
|||
*/
|
||||
|
||||
#include <api/api_handler.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
using kiapi::common::ApiRequest, kiapi::common::ApiResponse, kiapi::common::ApiResponseStatus;
|
||||
|
||||
|
||||
const wxString API_HANDLER::m_defaultCommitMessage = _( "Modification from API" );
|
||||
|
||||
|
||||
API_RESULT API_HANDLER::Handle( ApiRequest& aMsg )
|
||||
{
|
||||
ApiResponseStatus status;
|
||||
|
@ -55,20 +59,3 @@ API_RESULT API_HANDLER::Handle( ApiRequest& aMsg )
|
|||
// This response is used internally; no need for an error message
|
||||
return tl::unexpected( status );
|
||||
}
|
||||
|
||||
|
||||
std::optional<KICAD_T> API_HANDLER::TypeNameFromAny( const google::protobuf::Any& aMessage )
|
||||
{
|
||||
static const std::map<std::string, KICAD_T> s_types = {
|
||||
{ "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 },
|
||||
};
|
||||
|
||||
auto it = s_types.find( aMessage.type_url() );
|
||||
|
||||
if( it != s_types.end() )
|
||||
return it->second;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
|
||||
#include <api/api_handler_common.h>
|
||||
#include <build_version.h>
|
||||
#include <google/protobuf/empty.pb.h>
|
||||
#include <pgm_base.h>
|
||||
#include <project/net_settings.h>
|
||||
#include <project/project_file.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
using namespace kiapi::common::commands;
|
||||
|
@ -34,10 +38,13 @@ API_HANDLER_COMMON::API_HANDLER_COMMON() :
|
|||
API_HANDLER()
|
||||
{
|
||||
registerHandler<GetVersion, GetVersionResponse>( &API_HANDLER_COMMON::handleGetVersion );
|
||||
registerHandler<GetNetClasses, NetClassesResponse>( &API_HANDLER_COMMON::handleGetNetClasses );
|
||||
registerHandler<Ping, Empty>( &API_HANDLER_COMMON::handlePing );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVersion& aMsg )
|
||||
HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVersion&,
|
||||
const HANDLER_CONTEXT& )
|
||||
{
|
||||
GetVersionResponse reply;
|
||||
|
||||
|
@ -50,3 +57,26 @@ HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVers
|
|||
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<NetClassesResponse> API_HANDLER_COMMON::handleGetNetClasses( GetNetClasses& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
NetClassesResponse reply;
|
||||
|
||||
std::shared_ptr<NET_SETTINGS>& netSettings =
|
||||
Pgm().GetSettingsManager().Prj().GetProjectFile().m_NetSettings;
|
||||
|
||||
for( const auto& [name, netClass] : netSettings->m_NetClasses )
|
||||
{
|
||||
reply.add_net_classes()->set_name( name.ToStdString() );
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<Empty> API_HANDLER_COMMON::handlePing( Ping& aMsg, const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
return Empty();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* 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/api_handler_editor.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <eda_base_frame.h>
|
||||
#include <eda_item.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
using namespace kiapi::common::commands;
|
||||
|
||||
|
||||
API_HANDLER_EDITOR::API_HANDLER_EDITOR( EDA_BASE_FRAME* aFrame ) :
|
||||
API_HANDLER(),
|
||||
m_frame( aFrame )
|
||||
{
|
||||
registerHandler<BeginCommit, BeginCommitResponse>( &API_HANDLER_EDITOR::handleBeginCommit );
|
||||
registerHandler<EndCommit, EndCommitResponse>( &API_HANDLER_EDITOR::handleEndCommit );
|
||||
registerHandler<CreateItems, CreateItemsResponse>( &API_HANDLER_EDITOR::handleCreateItems );
|
||||
registerHandler<UpdateItems, UpdateItemsResponse>( &API_HANDLER_EDITOR::handleUpdateItems );
|
||||
registerHandler<DeleteItems, DeleteItemsResponse>( &API_HANDLER_EDITOR::handleDeleteItems );
|
||||
registerHandler<HitTest, HitTestResponse>( &API_HANDLER_EDITOR::handleHitTest );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<BeginCommitResponse> API_HANDLER_EDITOR::handleBeginCommit( BeginCommit& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
if( m_commits.count( aCtx.ClientName ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "the client {} already has a commit in progress",
|
||||
aCtx.ClientName ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
wxASSERT( !m_activeClients.count( aCtx.ClientName ) );
|
||||
|
||||
BeginCommitResponse response;
|
||||
|
||||
KIID id;
|
||||
m_commits[aCtx.ClientName] = std::make_pair( id, createCommit() );
|
||||
response.mutable_id()->set_value( id.AsStdString() );
|
||||
|
||||
m_activeClients.insert( aCtx.ClientName );
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<EndCommitResponse> API_HANDLER_EDITOR::handleEndCommit( EndCommit& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
if( !m_commits.count( aCtx.ClientName ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "the client {} does not has a commit in progress",
|
||||
aCtx.ClientName ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
wxASSERT( m_activeClients.count( aCtx.ClientName ) );
|
||||
|
||||
const std::pair<KIID, std::unique_ptr<COMMIT>>& pair = m_commits.at( aCtx.ClientName );
|
||||
const KIID& id = pair.first;
|
||||
const std::unique_ptr<COMMIT>& commit = pair.second;
|
||||
|
||||
EndCommitResponse response;
|
||||
|
||||
// Do not check IDs with drop; it is a safety net in case the id was lost on the client side
|
||||
switch( aMsg.action() )
|
||||
{
|
||||
case kiapi::common::commands::CMA_DROP:
|
||||
{
|
||||
commit->Revert();
|
||||
m_commits.erase( aCtx.ClientName );
|
||||
m_activeClients.erase( aCtx.ClientName );
|
||||
break;
|
||||
}
|
||||
|
||||
case kiapi::common::commands::CMA_COMMIT:
|
||||
{
|
||||
if( aMsg.id().value().compare( id.AsStdString() ) != 0 )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "the id {} does not match the commit in progress",
|
||||
aMsg.id().value() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
pushCurrentCommit( aCtx, wxString( aMsg.message().c_str(), wxConvUTF8 ) );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
COMMIT* API_HANDLER_EDITOR::getCurrentCommit( const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( !m_commits.count( aCtx.ClientName ) )
|
||||
{
|
||||
KIID id;
|
||||
m_commits[aCtx.ClientName] = std::make_pair( id, createCommit() );
|
||||
}
|
||||
|
||||
return m_commits.at( aCtx.ClientName ).second.get();
|
||||
}
|
||||
|
||||
|
||||
void API_HANDLER_EDITOR::pushCurrentCommit( const HANDLER_CONTEXT& aCtx, const wxString& aMessage )
|
||||
{
|
||||
auto it = m_commits.find( aCtx.ClientName );
|
||||
|
||||
if( it == m_commits.end() )
|
||||
return;
|
||||
|
||||
it->second.second->Push( aMessage.IsEmpty() ? m_defaultCommitMessage : aMessage );
|
||||
m_commits.erase( it );
|
||||
m_activeClients.erase( aCtx.ClientName );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<bool> API_HANDLER_EDITOR::validateDocument(
|
||||
const kiapi::common::types::DocumentSpecifier& aDocument )
|
||||
{
|
||||
if( !validateDocumentInternal( aDocument ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "the requested document {} is not open",
|
||||
aDocument.board_filename() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<std::optional<KIID>> API_HANDLER_EDITOR::validateItemHeaderDocument(
|
||||
const kiapi::common::types::ItemHeader& aHeader )
|
||||
{
|
||||
if( !aHeader.has_document() || aHeader.document().type() != thisDocumentType() )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
// No error message, this is a flag that the server should try a different handler
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
HANDLER_RESULT<bool> documentValidation = validateDocument( aHeader.document() );
|
||||
|
||||
if( !documentValidation )
|
||||
return tl::unexpected( documentValidation.error() );
|
||||
|
||||
if( !validateDocumentInternal( aHeader.document() ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "the requested document {} is not open",
|
||||
aHeader.document().board_filename() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
if( aHeader.has_container() )
|
||||
{
|
||||
return KIID( aHeader.container().value() );
|
||||
}
|
||||
|
||||
// Valid header, but no container provided
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
std::optional<ApiResponseStatus> API_HANDLER_EDITOR::checkForBusy()
|
||||
{
|
||||
if( !m_frame->CanAcceptApiCommands() )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BUSY );
|
||||
e.set_error_message( "KiCad is busy and cannot respond to API requests right now" );
|
||||
return e;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<CreateItemsResponse> API_HANDLER_EDITOR::handleCreateItems( CreateItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
CreateItemsResponse response;
|
||||
|
||||
HANDLER_RESULT<ItemRequestStatus> result = handleCreateUpdateItemsInternal( true, aCtx,
|
||||
aMsg.header(), aMsg.items(),
|
||||
[&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
|
||||
{
|
||||
ItemCreationResult itemResult;
|
||||
itemResult.mutable_status()->CopyFrom( aStatus );
|
||||
itemResult.mutable_item()->CopyFrom( aItem );
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
} );
|
||||
|
||||
if( !result.has_value() )
|
||||
return tl::unexpected( result.error() );
|
||||
|
||||
response.set_status( *result );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<UpdateItemsResponse> API_HANDLER_EDITOR::handleUpdateItems( UpdateItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
UpdateItemsResponse response;
|
||||
|
||||
HANDLER_RESULT<ItemRequestStatus> result = handleCreateUpdateItemsInternal( false, aCtx,
|
||||
aMsg.header(), aMsg.items(),
|
||||
[&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
|
||||
{
|
||||
ItemUpdateResult itemResult;
|
||||
itemResult.mutable_status()->CopyFrom( aStatus );
|
||||
itemResult.mutable_item()->CopyFrom( aItem );
|
||||
response.mutable_updated_items()->Add( std::move( itemResult ) );
|
||||
} );
|
||||
|
||||
if( !result.has_value() )
|
||||
return tl::unexpected( result.error() );
|
||||
|
||||
response.set_status( *result );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<DeleteItemsResponse> API_HANDLER_EDITOR::handleDeleteItems( DeleteItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
if( !validateItemHeaderDocument( aMsg.header() ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
std::map<KIID, ItemDeletionStatus> itemsToDelete;
|
||||
|
||||
for( const kiapi::common::types::KIID& kiidBuf : aMsg.item_ids() )
|
||||
{
|
||||
if( !kiidBuf.value().empty() )
|
||||
{
|
||||
KIID kiid( kiidBuf.value() );
|
||||
itemsToDelete[kiid] = ItemDeletionStatus::IDS_NONEXISTENT;
|
||||
}
|
||||
}
|
||||
|
||||
if( itemsToDelete.empty() )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( "no valid items to delete were given" );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
deleteItemsInternal( itemsToDelete, aCtx );
|
||||
|
||||
DeleteItemsResponse response;
|
||||
|
||||
for( const auto& [id, status] : itemsToDelete )
|
||||
{
|
||||
ItemDeletionResult result;
|
||||
result.mutable_id()->set_value( id.AsStdString() );
|
||||
result.set_status( status );
|
||||
}
|
||||
|
||||
response.set_status( kiapi::common::types::ItemRequestStatus::IRS_OK );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<HitTestResponse> API_HANDLER_EDITOR::handleHitTest( HitTest& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
if( !validateItemHeaderDocument( aMsg.header() ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
HitTestResponse response;
|
||||
|
||||
std::optional<EDA_ITEM*> item = getItemFromDocument( aMsg.header().document(),
|
||||
KIID( aMsg.id().value() ) );
|
||||
|
||||
if( !item )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( "the requested item ID is not present in the given document" );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
if( ( *item )->HitTest( kiapi::common::UnpackVector2( aMsg.position() ), aMsg.tolerance() ) )
|
||||
response.set_result( HitTestResult::HTR_HIT );
|
||||
else
|
||||
response.set_result( HitTestResult::HTR_NO_HIT );
|
||||
|
||||
return response;
|
||||
}
|
|
@ -312,7 +312,8 @@ std::optional<PLUGIN_ACTION> API_PLUGIN::createActionFromJson( const nlohmann::j
|
|||
}
|
||||
|
||||
wxBitmap bmp;
|
||||
bmp.LoadFile( iconFile.GetFullPath() );
|
||||
// TODO: If necessary; support types other than PNG
|
||||
bmp.LoadFile( iconFile.GetFullPath(), wxBITMAP_TYPE_PNG );
|
||||
|
||||
if( bmp.IsOk() )
|
||||
bitmaps.push_back( bmp );
|
||||
|
|
|
@ -303,10 +303,15 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
|
|||
return;
|
||||
}
|
||||
|
||||
wxLogTrace( traceApi, wxString::Format( "Manager: begin processing; %zu jobs left in queue",
|
||||
m_jobs.size() ) );
|
||||
|
||||
JOB& job = m_jobs.front();
|
||||
|
||||
if( job.type == JOB_TYPE::CREATE_ENV )
|
||||
{
|
||||
wxLogTrace( traceApi, "Manager: Python exe '%s'",
|
||||
Pgm().GetCommonSettings()->m_Api.python_interpreter );
|
||||
wxLogTrace( traceApi, wxString::Format( "Manager: creating Python env at %s",
|
||||
job.env_path ) );
|
||||
PYTHON_MANAGER manager( Pgm().GetCommonSettings()->m_Api.python_interpreter );
|
||||
|
@ -330,6 +335,7 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
|
|||
wxLogTrace( traceApi, wxString::Format( "Manager: installing dependencies for %s",
|
||||
job.plugin_path ) );
|
||||
|
||||
std::optional<wxString> pythonHome = PYTHON_MANAGER::GetPythonEnvironment( job.identifier );
|
||||
std::optional<wxString> python = PYTHON_MANAGER::GetVirtualPython( job.identifier );
|
||||
wxFileName reqs = wxFileName( job.plugin_path, "requirements.txt" );
|
||||
|
||||
|
@ -337,28 +343,46 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
|
|||
{
|
||||
wxLogTrace( traceApi, wxString::Format( "Manager: error: python not found at %s",
|
||||
job.env_path ) );
|
||||
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_PLUGIN_MANAGER_JOB_FINISHED,
|
||||
wxID_ANY );
|
||||
QueueEvent( evt );
|
||||
}
|
||||
else if( !reqs.IsFileReadable() )
|
||||
{
|
||||
wxLogTrace( traceApi,
|
||||
wxString::Format( "Manager: error: requirements.txt not found at %s",
|
||||
job.plugin_path ) );
|
||||
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_PLUGIN_MANAGER_JOB_FINISHED,
|
||||
wxID_ANY );
|
||||
QueueEvent( evt );
|
||||
}
|
||||
else
|
||||
{
|
||||
PYTHON_MANAGER manager( *python );
|
||||
wxLogTrace( traceApi, "Manager: Python exe '%s'", *python );
|
||||
|
||||
wxString cmd = wxString::Format(
|
||||
PYTHON_MANAGER manager( *python );
|
||||
wxExecuteEnv env;
|
||||
|
||||
if( pythonHome )
|
||||
env.env[wxS( "VIRTUAL_ENV" )] = *pythonHome;
|
||||
|
||||
wxString cmd = wxS( "-m ensurepip" );
|
||||
wxLogTrace( traceApi, "Manager: calling python `%s`", cmd );
|
||||
|
||||
manager.Execute( cmd,
|
||||
[=]( int aRetVal, const wxString& aOutput, const wxString& aError )
|
||||
{
|
||||
wxLogTrace( traceApi, wxString::Format( "Manager: ensurepip (%d): %s",
|
||||
aRetVal, aOutput ) );
|
||||
|
||||
if( !aError.IsEmpty() )
|
||||
{
|
||||
wxLogTrace( traceApi,
|
||||
wxString::Format( "Manager: ensurepip err: %s", aError ) );
|
||||
}
|
||||
}, &env );
|
||||
|
||||
cmd = wxString::Format(
|
||||
wxS( "-m pip install --no-input --isolated --require-virtualenv "
|
||||
"--exists-action i -r '%s'" ),
|
||||
reqs.GetFullPath() );
|
||||
|
||||
wxLogTrace( traceApi, "Manager: calling python `%s`", cmd );
|
||||
|
||||
manager.Execute( cmd,
|
||||
[=]( int aRetVal, const wxString& aOutput, const wxString& aError )
|
||||
{
|
||||
|
@ -382,10 +406,14 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
|
|||
wxID_ANY );
|
||||
|
||||
QueueEvent( evt );
|
||||
} );
|
||||
}, &env );
|
||||
}
|
||||
|
||||
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_PLUGIN_MANAGER_JOB_FINISHED, wxID_ANY );
|
||||
QueueEvent( evt );
|
||||
}
|
||||
|
||||
m_jobs.pop_front();
|
||||
wxLogTrace( traceApi, wxString::Format( "Manager: %zu jobs left in queue", m_jobs.size() ) );
|
||||
wxLogTrace( traceApi, wxString::Format( "Manager: done processing; %zu jobs left in queue",
|
||||
m_jobs.size() ) );
|
||||
}
|
||||
|
|
|
@ -95,9 +95,11 @@ KICAD_API_SERVER::KICAD_API_SERVER() :
|
|||
m_logFilePath.SetName( s_logFileName );
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
{
|
||||
PATHS::EnsurePathExists( PATHS::GetLogsPath() );
|
||||
log( fmt::format( "--- KiCad API server started at {} ---\n", SocketPath() ) );
|
||||
}
|
||||
|
||||
log( fmt::format( "--- KiCad API server started at {} ---\n", SocketPath() ) );
|
||||
wxLogTrace( traceApi, wxString::Format( "Server: listening at %s", SocketPath() ) );
|
||||
|
||||
Bind( API_REQUEST_EVENT, &KICAD_API_SERVER::handleApiEvent, this );
|
||||
|
@ -168,10 +170,13 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
|
|||
error.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
error.mutable_status()->set_error_message( "request could not be parsed" );
|
||||
m_server->Reply( error.SerializeAsString() );
|
||||
log( "Response (ERROR): " + error.Utf8DebugString() );
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
log( "Response (ERROR): " + error.Utf8DebugString() );
|
||||
}
|
||||
|
||||
log( "Request: " + request.Utf8DebugString() );
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
log( "Request: " + request.Utf8DebugString() );
|
||||
|
||||
if( !request.header().kicad_token().empty() &&
|
||||
request.header().kicad_token().compare( m_token ) != 0 )
|
||||
|
@ -182,7 +187,9 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
|
|||
error.mutable_status()->set_error_message(
|
||||
"the provided kicad_token did not match this KiCad instance's token" );
|
||||
m_server->Reply( error.SerializeAsString() );
|
||||
log( "Response (ERROR): " + error.Utf8DebugString() );
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
log( "Response (ERROR): " + error.Utf8DebugString() );
|
||||
}
|
||||
|
||||
API_RESULT result;
|
||||
|
@ -203,7 +210,9 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
|
|||
{
|
||||
result->mutable_header()->set_kicad_token( m_token );
|
||||
m_server->Reply( result->SerializeAsString() );
|
||||
log( "Response: " + result->Utf8DebugString() );
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
log( "Response: " + result->Utf8DebugString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -220,16 +229,15 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
|
|||
}
|
||||
|
||||
m_server->Reply( error.SerializeAsString() );
|
||||
log( "Response (ERROR): " + error.Utf8DebugString() );
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
log( "Response (ERROR): " + error.Utf8DebugString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void KICAD_API_SERVER::log( const std::string& aOutput )
|
||||
{
|
||||
if( !ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
return;
|
||||
|
||||
FILE* fp = wxFopen( m_logFilePath.GetFullPath(), wxT( "a" ) );
|
||||
|
||||
if( !fp )
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2023 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 <magic_enum.hpp>
|
||||
#include <api/api_utils.h>
|
||||
|
||||
namespace kiapi::common
|
||||
{
|
||||
|
||||
std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage )
|
||||
{
|
||||
static const std::map<std::string, KICAD_T> s_types = {
|
||||
{ "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.GraphicShape", PCB_SHAPE_T },
|
||||
{ "type.googleapis.com/kiapi.board.types.Pad", PCB_PAD_T },
|
||||
{ "type.googleapis.com/kiapi.board.types.Zone", PCB_ZONE_T },
|
||||
{ "type.googleapis.com/kiapi.board.types.Dimension", PCB_DIMENSION_T },
|
||||
{ "type.googleapis.com/kiapi.board.types.ReferenceImage", PCB_REFERENCE_IMAGE_T },
|
||||
{ "type.googleapis.com/kiapi.board.types.Group", PCB_GROUP_T },
|
||||
{ "type.googleapis.com/kiapi.board.types.Field", PCB_FIELD_T },
|
||||
{ "type.googleapis.com/kiapi.board.types.FootprintInstance", PCB_FOOTPRINT_T },
|
||||
};
|
||||
|
||||
auto it = s_types.find( aMessage.type_url() );
|
||||
|
||||
if( it != s_types.end() )
|
||||
return it->second;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
LIB_ID LibIdFromProto( const types::LibraryIdentifier& aId )
|
||||
{
|
||||
return LIB_ID( aId.library_nickname(), aId.entry_name() );
|
||||
}
|
||||
|
||||
|
||||
types::LibraryIdentifier LibIdToProto( const LIB_ID& aId )
|
||||
{
|
||||
types::LibraryIdentifier msg;
|
||||
msg.set_library_nickname( aId.GetLibNickname() );
|
||||
msg.set_entry_name( aId.GetLibItemName() );
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
void PackVector2( kiapi::common::types::Vector2& aOutput, const VECTOR2I aInput )
|
||||
{
|
||||
aOutput.set_x_nm( aInput.x );
|
||||
aOutput.set_y_nm( aInput.y );
|
||||
}
|
||||
|
||||
VECTOR2I UnpackVector2( const types::Vector2& aInput )
|
||||
{
|
||||
return VECTOR2I( aInput.x_nm(), aInput.y_nm() );
|
||||
}
|
||||
|
||||
} // namespace kiapi::common
|
|
@ -97,6 +97,7 @@ void PANEL_PLUGIN_SETTINGS::OnEnableApiChecked( wxCommandEvent& aEvent )
|
|||
|
||||
void PANEL_PLUGIN_SETTINGS::updateApiStatusText()
|
||||
{
|
||||
#ifdef KICAD_IPC_API
|
||||
if( m_cbEnableApi->GetValue() && Pgm().GetApiServer().Running() )
|
||||
{
|
||||
m_stApiStatus->SetLabel( wxString::Format( _( "Listening at %s" ),
|
||||
|
@ -106,6 +107,9 @@ void PANEL_PLUGIN_SETTINGS::updateApiStatusText()
|
|||
{
|
||||
m_stApiStatus->SetLabel( wxEmptyString );
|
||||
}
|
||||
#else
|
||||
m_stApiStatus->SetLabel( _( "This installation of KiCad does not have API support enabled." ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <api/api_plugin_manager.h>
|
||||
#include <base_screen.h>
|
||||
#include <bitmaps.h>
|
||||
#include <confirm.h>
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <id.h>
|
||||
#include <kiface_base.h>
|
||||
#include <kiplatform/ui.h>
|
||||
#include <lockfile.h>
|
||||
#include <macros.h>
|
||||
#include <math/vector2wx.h>
|
||||
|
@ -1343,3 +1345,45 @@ bool EDA_DRAW_FRAME::SaveCanvasImageToFile( const wxString& aFileName,
|
|||
image.Destroy();
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
void EDA_DRAW_FRAME::addApiPluginTools()
|
||||
{
|
||||
#ifdef KICAD_IPC_API
|
||||
// TODO: Add user control over visibility and order
|
||||
API_PLUGIN_MANAGER& mgr = Pgm().GetPluginManager();
|
||||
|
||||
mgr.ButtonBindings().clear();
|
||||
|
||||
std::vector<const PLUGIN_ACTION*> actions = mgr.GetActionsForScope( PluginActionScope() );
|
||||
|
||||
for( auto& action : actions )
|
||||
{
|
||||
if( !action->show_button )
|
||||
continue;
|
||||
|
||||
const wxBitmapBundle& icon = KIPLATFORM::UI::IsDarkTheme() && action->icon_dark.IsOk()
|
||||
? action->icon_dark
|
||||
: action->icon_light;
|
||||
|
||||
wxAuiToolBarItem* button = m_mainToolBar->AddTool( wxID_ANY, wxEmptyString, icon,
|
||||
action->name );
|
||||
|
||||
Connect( button->GetId(), wxEVT_COMMAND_MENU_SELECTED,
|
||||
wxCommandEventHandler( EDA_DRAW_FRAME::OnApiPluginInvoke ) );
|
||||
|
||||
mgr.ButtonBindings().insert( { button->GetId(), action->identifier } );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void EDA_DRAW_FRAME::OnApiPluginInvoke( wxCommandEvent& aEvent )
|
||||
{
|
||||
#ifdef KICAD_IPC_API
|
||||
API_PLUGIN_MANAGER& mgr = Pgm().GetPluginManager();
|
||||
|
||||
if( mgr.ButtonBindings().count( aEvent.GetId() ) )
|
||||
mgr.InvokeAction( mgr.ButtonBindings().at( aEvent.GetId() ) );
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ wxString EDA_SHAPE::SHAPE_T_asString() const
|
|||
case SHAPE_T::CIRCLE: return wxS( "S_CIRCLE" );
|
||||
case SHAPE_T::POLY: return wxS( "S_POLYGON" );
|
||||
case SHAPE_T::BEZIER: return wxS( "S_CURVE" );
|
||||
case SHAPE_T::UNDEFINED: return wxS( "UNDEFINED" );
|
||||
}
|
||||
|
||||
return wxEmptyString; // Just to quiet GCC.
|
||||
|
@ -243,12 +244,14 @@ void EDA_SHAPE::move( const VECTOR2I& aMoveVector )
|
|||
switch ( m_shape )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
m_arcCenter += aMoveVector;
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::RECTANGLE:
|
||||
case SHAPE_T::CIRCLE:
|
||||
m_start += aMoveVector;
|
||||
m_end += aMoveVector;
|
||||
m_arcCenter += aMoveVector;
|
||||
break;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
|
@ -284,11 +287,13 @@ void EDA_SHAPE::scale( double aScale )
|
|||
switch( m_shape )
|
||||
{
|
||||
case SHAPE_T::ARC:
|
||||
scalePt( m_arcCenter );
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
case SHAPE_T::SEGMENT:
|
||||
case SHAPE_T::RECTANGLE:
|
||||
scalePt( m_start );
|
||||
scalePt( m_end );
|
||||
scalePt( m_arcCenter );
|
||||
break;
|
||||
|
||||
case SHAPE_T::CIRCLE: // ring or circle
|
||||
|
|
|
@ -558,7 +558,10 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
|
|||
m_settings_manager = std::make_unique<SETTINGS_MANAGER>( aHeadless );
|
||||
m_background_jobs_monitor = std::make_unique<BACKGROUND_JOBS_MONITOR>();
|
||||
m_notifications_manager = std::make_unique<NOTIFICATIONS_MANAGER>();
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_plugin_manager = std::make_unique<API_PLUGIN_MANAGER>( &App() );
|
||||
#endif
|
||||
|
||||
// Our unit test mocks break if we continue
|
||||
// A bug caused InitPgm to terminate early in unit tests and the mocks are...simplistic
|
||||
|
@ -613,7 +616,9 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
|
|||
// Need to create a project early for now (it can have an empty path for the moment)
|
||||
GetSettingsManager().LoadProject( "" );
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_plugin_manager->ReloadPlugins();
|
||||
#endif
|
||||
|
||||
// This sets the maximum tooltip display duration to 10s (up from 5) but only affects
|
||||
// Windows as other platforms display tooltips while the mouse is not moving
|
||||
|
|
|
@ -1143,6 +1143,15 @@ TOOL_ACTION ACTIONS::ddAddLibrary( TOOL_ACTION_ARGS()
|
|||
.Name( "common.Control.ddaddLibrary" )
|
||||
.Scope( AS_GLOBAL ) );
|
||||
|
||||
// API
|
||||
|
||||
TOOL_ACTION ACTIONS::pluginsReload( TOOL_ACTION_ARGS()
|
||||
.Name( "common.API.pluginsReload" )
|
||||
.Scope( AS_GLOBAL )
|
||||
.FriendlyName( _( "Refresh Plugins" ) )
|
||||
.Tooltip( _( "Reload all python plugins and refresh plugin menus" ) )
|
||||
.Icon( BITMAPS::reload ) );
|
||||
|
||||
// System-wide selection Events
|
||||
|
||||
const TOOL_EVENT EVENTS::PointSelectedEvent( TC_MESSAGE, TA_ACTION, "common.Interactive.pointSelected" );
|
||||
|
|
|
@ -422,6 +422,8 @@ set( EESCHEMA_SRCS
|
|||
toolbars_sch_editor.cpp
|
||||
toolbars_symbol_viewer.cpp
|
||||
|
||||
api/api_sch_utils.cpp
|
||||
|
||||
netlist_exporters/netlist_exporter_allegro.cpp
|
||||
netlist_exporters/netlist_exporter_base.cpp
|
||||
netlist_exporters/netlist_exporter_cadstar.cpp
|
||||
|
@ -457,6 +459,13 @@ set( EESCHEMA_SRCS
|
|||
tools/symbol_editor_pin_tool.cpp
|
||||
)
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
set( EESCHEMA_SRCS
|
||||
${EESCHEMA_SRCS}
|
||||
api/api_handler_sch.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if( WIN32 )
|
||||
if( MINGW )
|
||||
# EESCHEMA_RESOURCES variable is set by the macro.
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* 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/api_handler_sch.h>
|
||||
#include <api/api_sch_utils.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include <sch_commit.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <wx/filename.h>
|
||||
|
||||
#include <api/common/types/base_types.pb.h>
|
||||
|
||||
using namespace kiapi::common::commands;
|
||||
using kiapi::common::types::CommandStatus;
|
||||
using kiapi::common::types::DocumentType;
|
||||
using kiapi::common::types::ItemRequestStatus;
|
||||
|
||||
|
||||
API_HANDLER_SCH::API_HANDLER_SCH( SCH_EDIT_FRAME* aFrame ) :
|
||||
API_HANDLER_EDITOR(),
|
||||
m_frame( aFrame )
|
||||
{
|
||||
registerHandler<GetOpenDocuments, GetOpenDocumentsResponse>(
|
||||
&API_HANDLER_SCH::handleGetOpenDocuments );
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<COMMIT> API_HANDLER_SCH::createCommit()
|
||||
{
|
||||
return std::make_unique<SCH_COMMIT>( m_frame );
|
||||
}
|
||||
|
||||
|
||||
bool API_HANDLER_SCH::validateDocumentInternal( const DocumentSpecifier& aDocument ) const
|
||||
{
|
||||
if( aDocument.type() != DocumentType::DOCTYPE_SCHEMATIC )
|
||||
return false;
|
||||
|
||||
// TODO(JE) need serdes for SCH_SHEET_PATH <> SheetPath
|
||||
return true;
|
||||
//wxString currentPath = m_frame->GetCurrentSheet().PathAsString();
|
||||
//return 0 == aDocument.sheet_path().compare( currentPath.ToStdString() );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<GetOpenDocumentsResponse> API_HANDLER_SCH::handleGetOpenDocuments(
|
||||
GetOpenDocuments& aMsg, const HANDLER_CONTEXT& )
|
||||
{
|
||||
if( aMsg.type() != DocumentType::DOCTYPE_SCHEMATIC )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
GetOpenDocumentsResponse response;
|
||||
common::types::DocumentSpecifier doc;
|
||||
|
||||
wxFileName fn( m_frame->GetCurrentFileName() );
|
||||
|
||||
doc.set_type( DocumentType::DOCTYPE_SCHEMATIC );
|
||||
doc.set_board_filename( fn.GetFullName() );
|
||||
|
||||
response.mutable_documents()->Add( std::move( doc ) );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<std::unique_ptr<EDA_ITEM>> API_HANDLER_SCH::createItemForType( KICAD_T aType,
|
||||
EDA_ITEM* aContainer )
|
||||
{
|
||||
if( !aContainer )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( "Tried to create an item in a null container" );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
if( aType == SCH_PIN_T && !dynamic_cast<SCH_SYMBOL*>( aContainer ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "Tried to create a pin in {}, which is not a symbol",
|
||||
aContainer->GetFriendlyName().ToStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
else if( aType == SCH_SYMBOL_T && !dynamic_cast<SCHEMATIC*>( aContainer ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "Tried to create a symbol in {}, which is not a schematic",
|
||||
aContainer->GetFriendlyName().ToStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
std::unique_ptr<EDA_ITEM> created = CreateItemForType( aType, aContainer );
|
||||
|
||||
if( !created )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "Tried to create an item of type {}, which is unhandled",
|
||||
magic_enum::enum_name( aType ) ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<ItemRequestStatus> API_HANDLER_SCH::handleCreateUpdateItemsInternal( bool aCreate,
|
||||
const HANDLER_CONTEXT& aCtx,
|
||||
const types::ItemHeader &aHeader,
|
||||
const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
|
||||
std::function<void( ItemStatus, google::protobuf::Any )> aItemHandler )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
|
||||
auto containerResult = validateItemHeaderDocument( aHeader );
|
||||
|
||||
if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
|
||||
{
|
||||
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
else if( !containerResult )
|
||||
{
|
||||
e.CopyFrom( containerResult.error() );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
SCH_SCREEN* screen = m_frame->GetScreen();
|
||||
EE_RTREE& screenItems = screen->Items();
|
||||
|
||||
std::map<KIID, EDA_ITEM*> itemUuidMap;
|
||||
|
||||
std::for_each( screenItems.begin(), screenItems.end(),
|
||||
[&]( EDA_ITEM* aItem )
|
||||
{
|
||||
itemUuidMap[aItem->m_Uuid] = aItem;
|
||||
} );
|
||||
|
||||
EDA_ITEM* container = nullptr;
|
||||
|
||||
if( containerResult->has_value() )
|
||||
{
|
||||
const KIID& containerId = **containerResult;
|
||||
|
||||
if( itemUuidMap.count( containerId ) )
|
||||
{
|
||||
container = itemUuidMap.at( containerId );
|
||||
|
||||
if( !container )
|
||||
{
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format(
|
||||
"The requested container {} is not a valid schematic item container",
|
||||
containerId.AsStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format(
|
||||
"The requested container {} does not exist in this document",
|
||||
containerId.AsStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
}
|
||||
|
||||
COMMIT* commit = getCurrentCommit( aCtx );
|
||||
|
||||
for( const google::protobuf::Any& anyItem : aItems )
|
||||
{
|
||||
ItemStatus status;
|
||||
std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
|
||||
|
||||
if( !type )
|
||||
{
|
||||
status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
|
||||
status.set_error_message( fmt::format( "Could not decode a valid type from {}",
|
||||
anyItem.type_url() ) );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
HANDLER_RESULT<std::unique_ptr<EDA_ITEM>> creationResult =
|
||||
createItemForType( *type, container );
|
||||
|
||||
if( !creationResult )
|
||||
{
|
||||
status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
|
||||
status.set_error_message( creationResult.error().error_message() );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<EDA_ITEM> item( std::move( *creationResult ) );
|
||||
|
||||
if( !item->Deserialize( anyItem ) )
|
||||
{
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "could not unpack {} from request",
|
||||
item->GetClass().ToStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
if( aCreate && itemUuidMap.count( item->m_Uuid ) )
|
||||
{
|
||||
status.set_code( ItemStatusCode::ISC_EXISTING );
|
||||
status.set_error_message( fmt::format( "an item with UUID {} already exists",
|
||||
item->m_Uuid.AsStdString() ) );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
else if( !aCreate && !itemUuidMap.count( item->m_Uuid ) )
|
||||
{
|
||||
status.set_code( ItemStatusCode::ISC_NONEXISTENT );
|
||||
status.set_error_message( fmt::format( "an item with UUID {} does not exist",
|
||||
item->m_Uuid.AsStdString() ) );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
status.set_code( ItemStatusCode::ISC_OK );
|
||||
google::protobuf::Any newItem;
|
||||
|
||||
if( aCreate )
|
||||
{
|
||||
item->Serialize( newItem );
|
||||
commit->Add( item.release() );
|
||||
|
||||
if( !m_activeClients.count( aCtx.ClientName ) )
|
||||
pushCurrentCommit( aCtx, _( "Added items via API" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
EDA_ITEM* edaItem = itemUuidMap[item->m_Uuid];
|
||||
|
||||
if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( edaItem ) )
|
||||
{
|
||||
schItem->SwapData( static_cast<SCH_ITEM*>( item.get() ) );
|
||||
schItem->Serialize( newItem );
|
||||
commit->Modify( schItem );
|
||||
}
|
||||
else if( LIB_ITEM* libItem = dynamic_cast<LIB_ITEM*>( edaItem ) )
|
||||
{
|
||||
// TODO: there is not currently a way to do this, haha
|
||||
}
|
||||
else
|
||||
{
|
||||
wxASSERT( false );
|
||||
}
|
||||
|
||||
if( !m_activeClients.count( aCtx.ClientName ) )
|
||||
pushCurrentCommit( aCtx, _( "Created items via API" ) );
|
||||
}
|
||||
|
||||
aItemHandler( status, newItem );
|
||||
}
|
||||
|
||||
|
||||
return ItemRequestStatus::IRS_OK;
|
||||
}
|
||||
|
||||
|
||||
void API_HANDLER_SCH::deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
std::optional<EDA_ITEM*> API_HANDLER_SCH::getItemFromDocument( const DocumentSpecifier& aDocument,
|
||||
const KIID& aId )
|
||||
{
|
||||
if( !validateDocument( aDocument ) )
|
||||
return std::nullopt;
|
||||
|
||||
// TODO
|
||||
|
||||
return std::nullopt;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KICAD_API_HANDLER_SCH_H
|
||||
#define KICAD_API_HANDLER_SCH_H
|
||||
|
||||
#include <api/api_handler_editor.h>
|
||||
#include <api/common/commands/editor_commands.pb.h>
|
||||
#include <kiid.h>
|
||||
|
||||
using namespace kiapi;
|
||||
using namespace kiapi::common;
|
||||
|
||||
class SCH_EDIT_FRAME;
|
||||
class SCH_ITEM;
|
||||
|
||||
|
||||
class API_HANDLER_SCH : public API_HANDLER_EDITOR
|
||||
{
|
||||
public:
|
||||
API_HANDLER_SCH( SCH_EDIT_FRAME* aFrame );
|
||||
|
||||
protected:
|
||||
std::unique_ptr<COMMIT> createCommit() override;
|
||||
|
||||
kiapi::common::types::DocumentType thisDocumentType() const override
|
||||
{
|
||||
return kiapi::common::types::DOCTYPE_SCHEMATIC;
|
||||
}
|
||||
|
||||
bool validateDocumentInternal( const DocumentSpecifier& aDocument ) const override;
|
||||
|
||||
HANDLER_RESULT<std::unique_ptr<EDA_ITEM>> createItemForType( KICAD_T aType,
|
||||
EDA_ITEM* aContainer );
|
||||
|
||||
HANDLER_RESULT<types::ItemRequestStatus> handleCreateUpdateItemsInternal( bool aCreate,
|
||||
const HANDLER_CONTEXT& aCtx,
|
||||
const types::ItemHeader &aHeader,
|
||||
const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
|
||||
std::function<void(commands::ItemStatus, google::protobuf::Any)> aItemHandler )
|
||||
override;
|
||||
|
||||
void deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
|
||||
const HANDLER_CONTEXT& aCtx ) override;
|
||||
|
||||
std::optional<EDA_ITEM*> getItemFromDocument( const DocumentSpecifier& aDocument,
|
||||
const KIID& aId ) override;
|
||||
|
||||
private:
|
||||
HANDLER_RESULT<commands::GetOpenDocumentsResponse> handleGetOpenDocuments(
|
||||
commands::GetOpenDocuments& aMsg, const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
SCH_EDIT_FRAME* m_frame;
|
||||
};
|
||||
|
||||
|
||||
#endif //KICAD_API_HANDLER_SCH_H
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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 <lib_field.h>
|
||||
#include <lib_pin.h>
|
||||
#include <lib_shape.h>
|
||||
#include <lib_symbol.h>
|
||||
#include <lib_text.h>
|
||||
#include <lib_textbox.h>
|
||||
|
||||
#include <sch_bitmap.h>
|
||||
#include <sch_bus_entry.h>
|
||||
#include <sch_field.h>
|
||||
#include <sch_junction.h>
|
||||
#include <sch_label.h>
|
||||
#include <sch_line.h>
|
||||
#include <sch_no_connect.h>
|
||||
#include <sch_pin.h>
|
||||
#include <sch_shape.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <sch_sheet_pin.h>
|
||||
#include <sch_table.h>
|
||||
#include <sch_tablecell.h>
|
||||
#include <sch_text.h>
|
||||
#include <sch_textbox.h>
|
||||
|
||||
#include "api_sch_utils.h"
|
||||
|
||||
|
||||
std::unique_ptr<EDA_ITEM> CreateItemForType( KICAD_T aType, EDA_ITEM* aContainer )
|
||||
{
|
||||
SCH_ITEM* parentSchItem = dynamic_cast<SCH_ITEM*>( aContainer );
|
||||
LIB_SYMBOL* parentLibSymbol = nullptr;
|
||||
|
||||
if( aContainer && aContainer->Type() == LIB_SYMBOL_T )
|
||||
parentLibSymbol = static_cast<LIB_SYMBOL*>( aContainer );
|
||||
|
||||
switch( aType )
|
||||
{
|
||||
case SCH_JUNCTION_T: return std::make_unique<SCH_JUNCTION>();
|
||||
case SCH_NO_CONNECT_T: return std::make_unique<SCH_NO_CONNECT>();
|
||||
case SCH_BUS_WIRE_ENTRY_T: return std::make_unique<SCH_BUS_WIRE_ENTRY>();
|
||||
case SCH_BUS_BUS_ENTRY_T: return std::make_unique<SCH_BUS_BUS_ENTRY>();
|
||||
case SCH_LINE_T: return std::make_unique<SCH_LINE>();
|
||||
case SCH_SHAPE_T: return std::make_unique<SCH_SHAPE>();
|
||||
case SCH_BITMAP_T: return std::make_unique<SCH_BITMAP>();
|
||||
case SCH_TEXTBOX_T: return std::make_unique<SCH_TEXTBOX>();
|
||||
case SCH_TEXT_T: return std::make_unique<SCH_TEXT>();
|
||||
case SCH_TABLE_T: return std::make_unique<SCH_TABLE>();
|
||||
case SCH_TABLECELL_T: return std::make_unique<SCH_TABLECELL>();
|
||||
case SCH_LABEL_T: return std::make_unique<SCH_LABEL>();
|
||||
case SCH_GLOBAL_LABEL_T: return std::make_unique<SCH_GLOBALLABEL>();
|
||||
case SCH_HIER_LABEL_T: return std::make_unique<SCH_HIERLABEL>();
|
||||
case SCH_DIRECTIVE_LABEL_T: return std::make_unique<SCH_DIRECTIVE_LABEL>();
|
||||
case SCH_FIELD_T: return std::make_unique<SCH_FIELD>( parentSchItem );
|
||||
|
||||
case SCH_SYMBOL_T:
|
||||
{
|
||||
// TODO: constructing currently requires more than just a "container" LIB_SYMBOL
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case SCH_SHEET_PIN_T:
|
||||
{
|
||||
if( aContainer && aContainer->Type() == SCH_SHEET_T )
|
||||
return std::make_unique<SCH_SHEET_PIN>( static_cast<SCH_SHEET*>( aContainer ) );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case SCH_SHEET_T: return std::make_unique<SCH_SHEET>();
|
||||
|
||||
case SCH_PIN_T:
|
||||
{
|
||||
// TODO: constructing currently requires LIB_PIN and SCH_SYMBOL ptr,
|
||||
// or SCH_SYMBOL and number+alt. Need to determine ideal default ctor.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case LIB_SYMBOL_T: return nullptr; // TODO: ctor currently requires non-null name
|
||||
case LIB_SHAPE_T: return std::make_unique<LIB_SHAPE>( parentLibSymbol );
|
||||
case LIB_TEXT_T: return std::make_unique<LIB_TEXT>( parentLibSymbol );
|
||||
case LIB_TEXTBOX_T: return std::make_unique<LIB_TEXTBOX>( parentLibSymbol );
|
||||
case LIB_PIN_T: return std::make_unique<LIB_PIN>( parentLibSymbol );
|
||||
case LIB_FIELD_T: return std::make_unique<LIB_FIELD>( parentLibSymbol );
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KICAD_API_SCH_UTILS_H
|
||||
#define KICAD_API_SCH_UTILS_H
|
||||
|
||||
#include <memory>
|
||||
#include <core/typeinfo.h>
|
||||
|
||||
class EDA_ITEM;
|
||||
|
||||
std::unique_ptr<EDA_ITEM> CreateItemForType( KICAD_T aType, EDA_ITEM* aContainer );
|
||||
|
||||
#endif //KICAD_API_SCH_UTILS_H
|
|
@ -32,7 +32,7 @@
|
|||
class LIB_SHAPE : public LIB_ITEM, public EDA_SHAPE
|
||||
{
|
||||
public:
|
||||
LIB_SHAPE( LIB_SYMBOL* aParent, SHAPE_T aShape, int aLineWidth = 0,
|
||||
LIB_SHAPE( LIB_SYMBOL* aParent, SHAPE_T aShape = SHAPE_T::UNDEFINED, int aLineWidth = 0,
|
||||
FILL_T aFillType = FILL_T::NO_FILL, KICAD_T aType = LIB_SHAPE_T );
|
||||
|
||||
// Do not create a copy constructor. The one generated by the compiler is adequate.
|
||||
|
|
|
@ -326,6 +326,11 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
|
|||
update = toolsMenu->Add( ACTIONS::updateSchematicFromPcb );
|
||||
update->Enable( !Kiface().IsSingle() );
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
toolsMenu->AppendSeparator();
|
||||
toolsMenu->Add( ACTIONS::pluginsReload );
|
||||
#endif
|
||||
|
||||
//-- Preferences menu -----------------------------------------------
|
||||
//
|
||||
ACTION_MENU* prefsMenu = new ACTION_MENU( false, selTool );
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
class PICKED_ITEMS_LIST;
|
||||
class TOOL_MANAGER;
|
||||
class SCH_EDIT_FRAME;
|
||||
class SCH_BASE_FRAME;
|
||||
class EDA_DRAW_FRAME;
|
||||
class TOOL_BASE;
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <api/api_handler_sch.h>
|
||||
#include <api/api_server.h>
|
||||
#include <base_units.h>
|
||||
#include <bitmaps.h>
|
||||
#include <symbol_library.h>
|
||||
|
@ -97,6 +99,10 @@
|
|||
#include <widgets/wx_aui_utils.h>
|
||||
#include <drawing_sheet/ds_proxy_view_item.h>
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_plugin_manager.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define DIFF_SYMBOLS_DIALOG_NAME wxT( "DiffSymbolsDialog" )
|
||||
|
||||
|
@ -177,6 +183,16 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
ReCreateVToolbar();
|
||||
ReCreateOptToolbar();
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
wxTheApp->Bind( EDA_EVT_PLUGIN_AVAILABILITY_CHANGED,
|
||||
[&]( wxCommandEvent& aEvt )
|
||||
{
|
||||
wxLogTrace( traceApi, "SCH frame: EDA_EVT_PLUGIN_AVAILABILITY_CHANGED" );
|
||||
ReCreateHToolbar();
|
||||
aEvt.Skip();
|
||||
} );
|
||||
#endif
|
||||
|
||||
m_hierarchy = new HIERARCHY_PANE( this );
|
||||
|
||||
// Initialize common print setup dialog settings.
|
||||
|
@ -380,6 +396,11 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
updateTitle();
|
||||
m_toolManager->GetTool<SCH_NAVIGATE_TOOL>()->ResetHistory();
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_apiHandler = std::make_unique<API_HANDLER_SCH>( this );
|
||||
Pgm().GetApiServer().RegisterHandler( m_apiHandler.get() );
|
||||
#endif
|
||||
|
||||
// Default shutdown reason until a file is loaded
|
||||
KIPLATFORM::APP::SetShutdownBlockReason( this, _( "New schematic file is unsaved" ) );
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ class DIALOG_SYMBOL_FIELDS_TABLE;
|
|||
class DIALOG_SCH_FIND;
|
||||
class RESCUER;
|
||||
class HIERARCHY_PANE;
|
||||
class API_HANDLER_SCH;
|
||||
|
||||
|
||||
/// Schematic search type used by the socket link with Pcbnew
|
||||
|
@ -872,6 +873,11 @@ public:
|
|||
|
||||
void ToggleNetNavigator();
|
||||
|
||||
PLUGIN_ACTION_SCOPE PluginActionScope() const override
|
||||
{
|
||||
return PLUGIN_ACTION_SCOPE::SCHEMATIC;
|
||||
}
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
protected:
|
||||
|
@ -1016,6 +1022,10 @@ private:
|
|||
bool m_highlightedConnChanged;
|
||||
|
||||
std::vector<wxEvtHandler*> m_schematicChangeListeners;
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
std::unique_ptr<API_HANDLER_SCH> m_apiHandler;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ public:
|
|||
SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent,
|
||||
const wxString& aName = wxEmptyString );
|
||||
|
||||
SCH_FIELD( SCH_ITEM* aParent, int aFieldId, const wxString& aName = wxEmptyString );
|
||||
SCH_FIELD( SCH_ITEM* aParent, int aFieldId = INVALID_FIELD,
|
||||
const wxString& aName = wxEmptyString );
|
||||
|
||||
SCH_FIELD( const SCH_FIELD& aText );
|
||||
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
#include <core/mirror.h>
|
||||
#include <trigo.h>
|
||||
#include <sch_label.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/schematic/schematic_types.pb.h>
|
||||
|
||||
using KIGFX::SCH_RENDER_SETTINGS;
|
||||
|
||||
|
@ -1470,6 +1473,31 @@ SCH_LABEL::SCH_LABEL( const VECTOR2I& pos, const wxString& text ) :
|
|||
}
|
||||
|
||||
|
||||
void SCH_LABEL::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::schematic::types::LocalLabel label;
|
||||
|
||||
label.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
kiapi::common::PackVector2( *label.mutable_position(), GetPosition() );
|
||||
|
||||
aContainer.PackFrom( label );
|
||||
}
|
||||
|
||||
|
||||
bool SCH_LABEL::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::schematic::types::LocalLabel label;
|
||||
|
||||
if( !aContainer.UnpackTo( &label ) )
|
||||
return false;
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = KIID( label.id().value() );
|
||||
SetPosition( kiapi::common::UnpackVector2( label.position() ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const BOX2I SCH_LABEL::GetBodyBoundingBox() const
|
||||
{
|
||||
BOX2I rect = GetTextBox();
|
||||
|
@ -1542,6 +1570,19 @@ SCH_DIRECTIVE_LABEL::SCH_DIRECTIVE_LABEL( const SCH_DIRECTIVE_LABEL& aClassLabel
|
|||
}
|
||||
|
||||
|
||||
void SCH_DIRECTIVE_LABEL::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
bool SCH_DIRECTIVE_LABEL::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int SCH_DIRECTIVE_LABEL::GetPenWidth() const
|
||||
{
|
||||
int pen = 0;
|
||||
|
@ -1791,6 +1832,19 @@ SCH_GLOBALLABEL::SCH_GLOBALLABEL( const SCH_GLOBALLABEL& aGlobalLabel ) :
|
|||
}
|
||||
|
||||
|
||||
void SCH_GLOBALLABEL::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
bool SCH_GLOBALLABEL::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I SCH_GLOBALLABEL::GetSchematicTextOffset( const RENDER_SETTINGS* aSettings ) const
|
||||
{
|
||||
int horiz = GetLabelBoxExpansion( aSettings );
|
||||
|
@ -1991,6 +2045,19 @@ SCH_HIERLABEL::SCH_HIERLABEL( const VECTOR2I& pos, const wxString& text, KICAD_T
|
|||
}
|
||||
|
||||
|
||||
void SCH_HIERLABEL::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
bool SCH_HIERLABEL::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SCH_HIERLABEL::SetSpinStyle( SPIN_STYLE aSpinStyle )
|
||||
{
|
||||
SCH_LABEL_BASE::SetSpinStyle( aSpinStyle );
|
||||
|
|
|
@ -377,6 +377,9 @@ public:
|
|||
|
||||
~SCH_LABEL() { }
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||
{
|
||||
return aItem && SCH_LABEL_T == aItem->Type();
|
||||
|
@ -426,6 +429,9 @@ public:
|
|||
|
||||
~SCH_DIRECTIVE_LABEL() { }
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||
{
|
||||
return aItem && SCH_DIRECTIVE_LABEL_T == aItem->Type();
|
||||
|
@ -483,6 +489,9 @@ public:
|
|||
|
||||
~SCH_GLOBALLABEL() { }
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||
{
|
||||
return aItem && SCH_GLOBAL_LABEL_T == aItem->Type();
|
||||
|
@ -542,6 +551,9 @@ public:
|
|||
|
||||
~SCH_HIERLABEL() { }
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||
{
|
||||
return aItem && SCH_HIER_LABEL_T == aItem->Type();
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
#include <project/net_settings.h>
|
||||
#include <trigo.h>
|
||||
#include <board_item.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/schematic/schematic_types.pb.h>
|
||||
|
||||
|
||||
SCH_LINE::SCH_LINE( const VECTOR2I& pos, int layer ) :
|
||||
|
@ -90,6 +93,49 @@ SCH_LINE::SCH_LINE( const SCH_LINE& aLine ) :
|
|||
}
|
||||
|
||||
|
||||
void SCH_LINE::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::schematic::types::Line line;
|
||||
|
||||
line.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
kiapi::common::PackVector2( *line.mutable_start(), GetStartPoint() );
|
||||
kiapi::common::PackVector2( *line.mutable_end(), GetEndPoint() );
|
||||
line.set_layer(
|
||||
ToProtoEnum<SCH_LAYER_ID, kiapi::schematic::types::SchematicLayer>( GetLayer() ) );
|
||||
|
||||
aContainer.PackFrom( line );
|
||||
}
|
||||
|
||||
|
||||
bool SCH_LINE::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::schematic::types::Line line;
|
||||
|
||||
if( !aContainer.UnpackTo( &line ) )
|
||||
return false;
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = KIID( line.id().value() );
|
||||
SetStartPoint( kiapi::common::UnpackVector2( line.start() ) );
|
||||
SetEndPoint( kiapi::common::UnpackVector2( line.end() ) );
|
||||
SCH_LAYER_ID layer =
|
||||
FromProtoEnum<SCH_LAYER_ID, kiapi::schematic::types::SchematicLayer>( line.layer() );
|
||||
|
||||
switch( layer )
|
||||
{
|
||||
case LAYER_WIRE:
|
||||
case LAYER_BUS:
|
||||
case LAYER_NOTES:
|
||||
SetLayer( layer );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
wxString SCH_LINE::GetFriendlyName() const
|
||||
{
|
||||
switch( GetLayer() )
|
||||
|
|
|
@ -51,6 +51,9 @@ public:
|
|||
|
||||
~SCH_LINE() { }
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||
{
|
||||
return aItem && SCH_LINE_T == aItem->Type();
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
class SCH_SHAPE : public SCH_ITEM, public EDA_SHAPE
|
||||
{
|
||||
public:
|
||||
SCH_SHAPE( SHAPE_T aShape, int aLineWidth = 0, FILL_T aFillType = FILL_T::NO_FILL,
|
||||
SCH_SHAPE( SHAPE_T aShape = SHAPE_T::UNDEFINED, int aLineWidth = 0,
|
||||
FILL_T aFillType = FILL_T::NO_FILL,
|
||||
KICAD_T aType = SCH_SHAPE_T );
|
||||
|
||||
// Do not create a copy constructor. The one generated by the compiler is adequate.
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
class SCH_TABLE : public SCH_ITEM
|
||||
{
|
||||
public:
|
||||
SCH_TABLE( int aLineWidth );
|
||||
SCH_TABLE( int aLineWidth = 0 );
|
||||
|
||||
SCH_TABLE( const SCH_TABLE& aTable );
|
||||
|
||||
|
|
|
@ -25,11 +25,13 @@
|
|||
*/
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <api/api_plugin_manager.h>
|
||||
#include <sch_draw_panel.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <kiface_base.h>
|
||||
#include <bitmaps.h>
|
||||
#include <eeschema_id.h>
|
||||
#include <pgm_base.h>
|
||||
#include <python_scripting.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tool/action_toolbar.h>
|
||||
|
@ -119,11 +121,24 @@ void SCH_EDIT_FRAME::ReCreateHToolbar()
|
|||
m_mainToolBar->AddScaledSeparator( this );
|
||||
m_mainToolBar->Add( EE_ACTIONS::showPcbNew );
|
||||
|
||||
// Access to the scripting console
|
||||
if( SCRIPTING::IsWxAvailable() )
|
||||
// Add scripting console and API plugins
|
||||
bool scriptingAvailable = SCRIPTING::IsWxAvailable();
|
||||
#ifdef KICAD_IPC_API
|
||||
bool haveApiPlugins = Pgm().GetCommonSettings()->m_Api.enable_server &&
|
||||
!Pgm().GetPluginManager().GetActionsForScope( PLUGIN_ACTION_SCOPE::SCHEMATIC ).empty();
|
||||
#else
|
||||
bool haveApiPlugins = false;
|
||||
#endif
|
||||
|
||||
if( scriptingAvailable || haveApiPlugins )
|
||||
{
|
||||
m_mainToolBar->AddScaledSeparator( this );
|
||||
m_mainToolBar->Add( EE_ACTIONS::showPythonConsole, ACTION_TOOLBAR::TOGGLE );
|
||||
|
||||
if( scriptingAvailable )
|
||||
m_mainToolBar->Add( EE_ACTIONS::showPythonConsole, ACTION_TOOLBAR::TOGGLE );
|
||||
|
||||
if( haveApiPlugins )
|
||||
addApiPluginTools();
|
||||
}
|
||||
|
||||
// after adding the tools to the toolbar, must call Realize() to reflect the changes
|
||||
|
|
|
@ -80,6 +80,10 @@
|
|||
#include <wx/treectrl.h>
|
||||
#include "sch_edit_table_tool.h"
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_plugin_manager.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Flag to enable schematic paste debugging output.
|
||||
|
@ -2537,6 +2541,15 @@ int SCH_EDITOR_CONTROL::TogglePythonConsole( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
int SCH_EDITOR_CONTROL::ReloadPlugins( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
#ifdef KICAD_IPC_API
|
||||
Pgm().GetPluginManager().ReloadPlugins();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int SCH_EDITOR_CONTROL::RepairSchematic( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
int errors = 0;
|
||||
|
@ -2731,6 +2744,7 @@ void SCH_EDITOR_CONTROL::setTransitions()
|
|||
Go( &SCH_EDITOR_CONTROL::ToggleAnnotateAuto, EE_ACTIONS::toggleAnnotateAuto.MakeEvent() );
|
||||
|
||||
Go( &SCH_EDITOR_CONTROL::TogglePythonConsole, EE_ACTIONS::showPythonConsole.MakeEvent() );
|
||||
Go( &SCH_EDITOR_CONTROL::ReloadPlugins, ACTIONS::pluginsReload.MakeEvent() );
|
||||
|
||||
Go( &SCH_EDITOR_CONTROL::RepairSchematic, EE_ACTIONS::repairSchematic.MakeEvent() );
|
||||
|
||||
|
|
|
@ -143,6 +143,7 @@ public:
|
|||
int ToggleAnnotateAuto( const TOOL_EVENT& aEvent );
|
||||
int ToggleAnnotateRecursive( const TOOL_EVENT& aEvent );
|
||||
int TogglePythonConsole( const TOOL_EVENT& aEvent );
|
||||
int ReloadPlugins( const TOOL_EVENT& aEvent );
|
||||
|
||||
int GridFeedback( const TOOL_EVENT& aEvent );
|
||||
|
||||
|
|
|
@ -467,6 +467,10 @@ int SYMBOL_EDITOR_MOVE_TOOL::AlignElements( const TOOL_EVENT& aEvent )
|
|||
doMoveItem( shape, newStart - shape->GetStart() );
|
||||
|
||||
break;
|
||||
|
||||
case SHAPE_T::UNDEFINED:
|
||||
wxASSERT_MSG( false, wxT( "Undefined shape in AlignElements" ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KICAD_API_ENUMS_H
|
||||
#define KICAD_API_ENUMS_H
|
||||
|
||||
template<typename KiCadEnum, typename ProtoEnum>
|
||||
KiCadEnum FromProtoEnum( ProtoEnum aEnumValue );
|
||||
|
||||
template<typename KiCadEnum, typename ProtoEnum>
|
||||
ProtoEnum ToProtoEnum( KiCadEnum aEnumValue );
|
||||
|
||||
#endif //KICAD_API_ENUMS_H
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#include <import_export.h>
|
||||
#include <kicommon.h>
|
||||
#include <api/common/envelope.pb.h>
|
||||
#include <core/typeinfo.h>
|
||||
|
||||
|
@ -44,11 +44,20 @@ typedef tl::expected<ApiResponse, ApiResponseStatus> API_RESULT;
|
|||
template <typename T>
|
||||
using HANDLER_RESULT = tl::expected<T, ApiResponseStatus>;
|
||||
|
||||
class API_HANDLER
|
||||
|
||||
struct HANDLER_CONTEXT
|
||||
{
|
||||
std::string ClientName;
|
||||
};
|
||||
|
||||
|
||||
class KICOMMON_API API_HANDLER
|
||||
{
|
||||
public:
|
||||
API_HANDLER() {}
|
||||
|
||||
virtual ~API_HANDLER() {}
|
||||
|
||||
/**
|
||||
* Attempt to handle the given API request, if a handler exists in this class for the message.
|
||||
* @param aMsg is a request to attempt to handle
|
||||
|
@ -56,8 +65,6 @@ public:
|
|||
*/
|
||||
API_RESULT Handle( ApiRequest& aMsg );
|
||||
|
||||
static std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
@ -81,7 +88,9 @@ protected:
|
|||
* @param aHandler is the handler function for the given request and response types
|
||||
*/
|
||||
template <class RequestType, class ResponseType, class HandlerType>
|
||||
void registerHandler( HANDLER_RESULT<ResponseType>( HandlerType::* aHandler )( RequestType& ) )
|
||||
void registerHandler(
|
||||
HANDLER_RESULT<ResponseType>( HandlerType::* aHandler )( RequestType&,
|
||||
const HANDLER_CONTEXT& ) )
|
||||
{
|
||||
std::string typeName = RequestType().GetTypeName();
|
||||
|
||||
|
@ -91,14 +100,17 @@ protected:
|
|||
m_handlers[typeName] =
|
||||
[=]( ApiRequest& aRequest ) -> API_RESULT
|
||||
{
|
||||
RequestType command;
|
||||
RequestType cmd;
|
||||
ApiResponse envelope;
|
||||
|
||||
if( !tryUnpack( aRequest, envelope, command ) )
|
||||
if( !tryUnpack( aRequest, envelope, cmd ) )
|
||||
return envelope;
|
||||
|
||||
HANDLER_CONTEXT ctx;
|
||||
ctx.ClientName = aRequest.header().client_name();
|
||||
|
||||
HANDLER_RESULT<ResponseType> response =
|
||||
std::invoke( aHandler, static_cast<HandlerType*>( this ), command );
|
||||
std::invoke( aHandler, static_cast<HandlerType*>( this ), cmd, ctx );
|
||||
|
||||
if( response.has_value() )
|
||||
{
|
||||
|
@ -116,6 +128,8 @@ protected:
|
|||
/// Maps type name (without the URL prefix) to a handler method
|
||||
std::map<std::string, REQUEST_HANDLER> m_handlers;
|
||||
|
||||
static const wxString m_defaultCommitMessage;
|
||||
|
||||
private:
|
||||
|
||||
template<typename MessageType>
|
||||
|
|
|
@ -21,22 +21,29 @@
|
|||
#ifndef KICAD_API_HANDLER_COMMON_H
|
||||
#define KICAD_API_HANDLER_COMMON_H
|
||||
|
||||
#include <google/protobuf/empty.pb.h>
|
||||
|
||||
#include <api/api_handler.h>
|
||||
#include <api/common/commands/base_commands.pb.h>
|
||||
#include <api/common/commands/editor_commands.pb.h>
|
||||
|
||||
#include <google/protobuf/empty.pb.h>
|
||||
#include <api/common/commands/project_commands.pb.h>
|
||||
|
||||
using namespace kiapi;
|
||||
using namespace kiapi::common;
|
||||
using google::protobuf::Empty;
|
||||
|
||||
class API_HANDLER_COMMON : public API_HANDLER
|
||||
class KICOMMON_API API_HANDLER_COMMON : public API_HANDLER
|
||||
{
|
||||
public:
|
||||
API_HANDLER_COMMON();
|
||||
|
||||
private:
|
||||
HANDLER_RESULT<commands::GetVersionResponse> handleGetVersion( commands::GetVersion& aMsg );
|
||||
HANDLER_RESULT<commands::GetVersionResponse> handleGetVersion( commands::GetVersion& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::NetClassesResponse> handleGetNetClasses( commands::GetNetClasses& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<Empty> handlePing( commands::Ping& aMsg, const HANDLER_CONTEXT& aCtx );
|
||||
};
|
||||
|
||||
#endif //KICAD_API_HANDLER_COMMON_H
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KICAD_API_HANDLER_EDITOR_H
|
||||
#define KICAD_API_HANDLER_EDITOR_H
|
||||
|
||||
#include <api/api_handler.h>
|
||||
#include <api/common/commands/editor_commands.pb.h>
|
||||
#include <commit.h>
|
||||
#include <kiid.h>
|
||||
|
||||
using namespace kiapi::common;
|
||||
using kiapi::common::types::DocumentSpecifier;
|
||||
using kiapi::common::types::ItemRequestStatus;
|
||||
using kiapi::common::commands::ItemDeletionStatus;
|
||||
|
||||
class EDA_BASE_FRAME;
|
||||
|
||||
/**
|
||||
* Base class for API handlers related to editor frames
|
||||
*/
|
||||
class API_HANDLER_EDITOR : public API_HANDLER
|
||||
{
|
||||
public:
|
||||
API_HANDLER_EDITOR( EDA_BASE_FRAME* aFrame = nullptr );
|
||||
|
||||
protected:
|
||||
/// If the header is valid, returns the item container
|
||||
HANDLER_RESULT<std::optional<KIID>> validateItemHeaderDocument(
|
||||
const kiapi::common::types::ItemHeader& aHeader );
|
||||
|
||||
HANDLER_RESULT<bool> validateDocument( const DocumentSpecifier& aDocument );
|
||||
|
||||
/**
|
||||
* Checks if the editor can accept commands
|
||||
* @return an error status if busy, std::nullopt if not busy
|
||||
*/
|
||||
virtual std::optional<ApiResponseStatus> checkForBusy();
|
||||
|
||||
HANDLER_RESULT<commands::BeginCommitResponse> handleBeginCommit( commands::BeginCommit& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::EndCommitResponse> handleEndCommit( commands::EndCommit& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
COMMIT* getCurrentCommit( const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
virtual void pushCurrentCommit( const HANDLER_CONTEXT& aCtx, const wxString& aMessage );
|
||||
|
||||
HANDLER_RESULT<commands::CreateItemsResponse> handleCreateItems( commands::CreateItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::UpdateItemsResponse> handleUpdateItems( commands::UpdateItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::DeleteItemsResponse> handleDeleteItems( commands::DeleteItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::HitTestResponse> handleHitTest( commands::HitTest& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
/**
|
||||
* Override this to create an appropriate COMMIT subclass for the frame in question
|
||||
* @return a new COMMIT, bound to the editor frame
|
||||
*/
|
||||
virtual std::unique_ptr<COMMIT> createCommit() = 0;
|
||||
|
||||
/**
|
||||
* Override this to specify which document type this editor handles
|
||||
*/
|
||||
virtual kiapi::common::types::DocumentType thisDocumentType() const = 0;
|
||||
|
||||
/**
|
||||
* @return true if the given document is valid for this editor and is currently open
|
||||
*/
|
||||
virtual bool validateDocumentInternal( const DocumentSpecifier& aDocument ) const = 0;
|
||||
|
||||
virtual HANDLER_RESULT<ItemRequestStatus> handleCreateUpdateItemsInternal( bool aCreate,
|
||||
const HANDLER_CONTEXT& aCtx,
|
||||
const types::ItemHeader &aHeader,
|
||||
const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
|
||||
std::function<void( commands::ItemStatus, google::protobuf::Any )> aItemHandler ) = 0;
|
||||
|
||||
virtual void deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
|
||||
const HANDLER_CONTEXT& aCtx ) = 0;
|
||||
|
||||
virtual std::optional<EDA_ITEM*> getItemFromDocument( const DocumentSpecifier& aDocument,
|
||||
const KIID& aId ) = 0;
|
||||
|
||||
protected:
|
||||
std::map<std::string, std::pair<KIID, std::unique_ptr<COMMIT>>> m_commits;
|
||||
|
||||
std::set<std::string> m_activeClients;
|
||||
|
||||
EDA_BASE_FRAME* m_frame;
|
||||
};
|
||||
|
||||
#endif //KICAD_API_HANDLER_EDITOR_H
|
|
@ -58,7 +58,7 @@ enum class PLUGIN_ACTION_SCOPE
|
|||
SCHEMATIC,
|
||||
FOOTPRINT,
|
||||
SYMBOL,
|
||||
KICAD
|
||||
PROJECT_MANAGER
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
*
|
||||
* Use "KICAD_API" to enable.
|
||||
*
|
||||
* @ingroup traceApi
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
extern const KICOMMON_API wxChar* const traceApi;
|
||||
|
||||
|
@ -41,6 +41,7 @@ wxDECLARE_EVENT( EDA_EVT_PLUGIN_MANAGER_JOB_FINISHED, wxCommandEvent );
|
|||
|
||||
/// Notifies other parts of KiCad when plugin availability changes
|
||||
extern const KICOMMON_API wxEventTypeTag<wxCommandEvent> EDA_EVT_PLUGIN_AVAILABILITY_CHANGED;
|
||||
|
||||
/**
|
||||
* Responsible for loading plugin definitions for API-based plugins (ones that do not run inside
|
||||
* KiCad itself, but instead are launched as external processes by KiCad)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* 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
|
||||
|
@ -28,6 +28,8 @@
|
|||
#include <wx/event.h>
|
||||
#include <wx/filename.h>
|
||||
|
||||
#include <kicommon.h>
|
||||
|
||||
class API_HANDLER;
|
||||
class API_HANDLER_COMMON;
|
||||
class KINNG_REQUEST_SERVER;
|
||||
|
@ -37,7 +39,7 @@ class wxEvtHandler;
|
|||
wxDECLARE_EVENT( API_REQUEST_EVENT, wxCommandEvent );
|
||||
|
||||
|
||||
class KICAD_API_SERVER : public wxEvtHandler
|
||||
class KICOMMON_API KICAD_API_SERVER : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
KICAD_API_SERVER();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KICAD_API_UTILS_H
|
||||
#define KICAD_API_UTILS_H
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <core/typeinfo.h>
|
||||
#include <lib_id.h>
|
||||
#include <api/common/types/base_types.pb.h>
|
||||
#include <google/protobuf/any.pb.h>
|
||||
#include <layer_ids.h>
|
||||
#include <math/vector2d.h>
|
||||
|
||||
namespace kiapi::common
|
||||
{
|
||||
|
||||
std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage );
|
||||
|
||||
LIB_ID LibIdFromProto( const types::LibraryIdentifier& aId );
|
||||
|
||||
types::LibraryIdentifier LibIdToProto( const LIB_ID& aId );
|
||||
|
||||
void PackVector2( kiapi::common::types::Vector2& aOutput, const VECTOR2I aInput );
|
||||
|
||||
VECTOR2I UnpackVector2( const types::Vector2& aInput );
|
||||
|
||||
} // namespace kiapi::common
|
||||
|
||||
#endif //KICAD_API_UTILS_H
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KICAD_SERIALIZABLE_H
|
||||
#define KICAD_SERIALIZABLE_H
|
||||
|
||||
#include <wx/debug.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class Any;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for objects that can be serialized to Protobuf messages
|
||||
*/
|
||||
class SERIALIZABLE
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* 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!" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //KICAD_SERIALIZABLE_H
|
|
@ -600,6 +600,13 @@ public:
|
|||
*/
|
||||
virtual void HandleSystemColorChange();
|
||||
|
||||
/**
|
||||
* Checks if this frame is ready to accept API commands.
|
||||
* A frame might not accept commands if a long-running process is underway, a dialog is open,
|
||||
* the user is interacting with a tool, etc.
|
||||
*/
|
||||
virtual bool CanAcceptApiCommands() { return IsEnabled(); }
|
||||
|
||||
protected:
|
||||
///< Default style flags used for wxAUI toolbars.
|
||||
static constexpr int KICAD_AUI_TB_STYLE = wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_PLAIN_BACKGROUND;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#ifndef DRAW_FRAME_H_
|
||||
#define DRAW_FRAME_H_
|
||||
|
||||
#include <api/api_plugin.h>
|
||||
#include <eda_base_frame.h>
|
||||
#include <kiway_player.h>
|
||||
#include <gal/gal_display_options.h>
|
||||
|
@ -490,6 +491,13 @@ public:
|
|||
*/
|
||||
bool SaveCanvasImageToFile( const wxString& aFileName, BITMAP_TYPE aBitmapType );
|
||||
|
||||
/**
|
||||
* Handler for activating an API plugin (via toolbar or menu)
|
||||
*/
|
||||
virtual void OnApiPluginInvoke( wxCommandEvent& aEvent );
|
||||
|
||||
virtual PLUGIN_ACTION_SCOPE PluginActionScope() const { return PLUGIN_ACTION_SCOPE::INVALID; }
|
||||
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
|
@ -525,6 +533,11 @@ protected:
|
|||
virtual void handleActivateEvent( wxActivateEvent& aEvent );
|
||||
void onActivate( wxActivateEvent& aEvent );
|
||||
|
||||
/**
|
||||
* Append actions from API plugins to the main toolbar
|
||||
*/
|
||||
virtual void addApiPluginTools();
|
||||
|
||||
|
||||
wxSocketServer* m_socketServer;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <deque>
|
||||
|
||||
#include <api/serializable.h>
|
||||
#include <core/typeinfo.h>
|
||||
#include <eda_item_flags.h>
|
||||
#include <eda_search_data.h>
|
||||
|
@ -83,7 +84,7 @@ typedef const INSPECTOR_FUNC& INSPECTOR;
|
|||
/**
|
||||
* A base class for most all the KiCad significant classes used in schematics and boards.
|
||||
*/
|
||||
class EDA_ITEM : public KIGFX::VIEW_ITEM
|
||||
class EDA_ITEM : public KIGFX::VIEW_ITEM, public SERIALIZABLE
|
||||
{
|
||||
public:
|
||||
virtual ~EDA_ITEM() { };
|
||||
|
@ -438,10 +439,6 @@ public:
|
|||
|
||||
virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;
|
||||
|
||||
virtual void Serialize( google::protobuf::Any &aContainer ) const {}
|
||||
|
||||
virtual bool Deserialize( const google::protobuf::Any &aContainer ) { return false; }
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,6 +40,7 @@ using KIGFX::COLOR4D;
|
|||
|
||||
enum class SHAPE_T : int
|
||||
{
|
||||
UNDEFINED = -1,
|
||||
SEGMENT = 0,
|
||||
RECTANGLE, /// use RECTANGLE instead of RECT to avoid collision in a Windows header
|
||||
ARC,
|
||||
|
|
|
@ -38,6 +38,7 @@ class FONT;
|
|||
// NB: values -1,0,1 are used in computations, do not change them
|
||||
//
|
||||
|
||||
// This is API surface mapped to common.types.HorizontalAlignment
|
||||
enum GR_TEXT_H_ALIGN_T
|
||||
{
|
||||
GR_TEXT_H_ALIGN_LEFT = -1,
|
||||
|
@ -46,6 +47,7 @@ enum GR_TEXT_H_ALIGN_T
|
|||
GR_TEXT_H_ALIGN_INDETERMINATE
|
||||
};
|
||||
|
||||
// This is API surface mapped to common.types.VertialAlignment
|
||||
enum GR_TEXT_V_ALIGN_T
|
||||
{
|
||||
GR_TEXT_V_ALIGN_TOP = -1,
|
||||
|
|
|
@ -40,6 +40,7 @@ class TEMPLATE_FIELDNAMES_LEXER;
|
|||
* an unlimited number of user defined fields, only some of which have indices defined here.
|
||||
*/
|
||||
enum MANDATORY_FIELD_T {
|
||||
INVALID_FIELD = -1, ///< The field ID hasn't been set yet; field is invalid
|
||||
REFERENCE_FIELD = 0, ///< Field Reference of part, i.e. "IC21"
|
||||
VALUE_FIELD, ///< Field Value of part, i.e. "3.3K"
|
||||
FOOTPRINT_FIELD, ///< Field Name Module PCB, i.e. "16DIP300"
|
||||
|
|
|
@ -220,6 +220,9 @@ public:
|
|||
static TOOL_ACTION getInvolved;
|
||||
static TOOL_ACTION reportBug;
|
||||
|
||||
// API
|
||||
static TOOL_ACTION pluginsReload;
|
||||
|
||||
///< Cursor control event types
|
||||
enum CURSOR_EVENT_TYPE
|
||||
{
|
||||
|
|
|
@ -270,6 +270,14 @@ public:
|
|||
doRunAction( aAction, false, a, nullptr );
|
||||
}
|
||||
|
||||
bool PostAction( const TOOL_ACTION& aAction, COMMIT* aCommit )
|
||||
{
|
||||
// Default initialize the parameter argument to an empty std::any
|
||||
std::any a;
|
||||
|
||||
return doRunAction( aAction, false, a, aCommit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a cancel event to the tool currently at the top of the tool stack.
|
||||
*/
|
||||
|
|
|
@ -21,10 +21,26 @@
|
|||
#include <magic_enum.hpp>
|
||||
|
||||
#include <api/api_handler_pcb.h>
|
||||
#include <api/api_pcb_utils.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <board_commit.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <footprint.h>
|
||||
#include <netinfo.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_edit_frame.h>
|
||||
#include <pcb_group.h>
|
||||
#include <pcb_reference_image.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <pcb_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <pcb_track.h>
|
||||
#include <project.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tools/pcb_actions.h>
|
||||
#include <tools/pcb_selection_tool.h>
|
||||
#include <zone.h>
|
||||
|
||||
#include <api/common/types/base_types.pb.h>
|
||||
|
||||
|
@ -33,34 +49,44 @@ using kiapi::common::types::CommandStatus;
|
|||
using kiapi::common::types::DocumentType;
|
||||
using kiapi::common::types::ItemRequestStatus;
|
||||
|
||||
static const wxString s_defaultCommitMessage = wxS( "Modification from API" );
|
||||
|
||||
|
||||
API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) :
|
||||
API_HANDLER(),
|
||||
m_frame( aFrame ),
|
||||
m_transactionInProgress( false )
|
||||
API_HANDLER_EDITOR( aFrame )
|
||||
{
|
||||
registerHandler<RunAction, RunActionResponse>( &API_HANDLER_PCB::handleRunAction );
|
||||
registerHandler<GetOpenDocuments, GetOpenDocumentsResponse>(
|
||||
&API_HANDLER_PCB::handleGetOpenDocuments );
|
||||
|
||||
registerHandler<BeginCommit, BeginCommitResponse>( &API_HANDLER_PCB::handleBeginCommit );
|
||||
registerHandler<EndCommit, EndCommitResponse>( &API_HANDLER_PCB::handleEndCommit );
|
||||
|
||||
registerHandler<CreateItems, CreateItemsResponse>( &API_HANDLER_PCB::handleCreateItems );
|
||||
registerHandler<GetItems, GetItemsResponse>( &API_HANDLER_PCB::handleGetItems );
|
||||
registerHandler<UpdateItems, UpdateItemsResponse>( &API_HANDLER_PCB::handleUpdateItems );
|
||||
registerHandler<DeleteItems, DeleteItemsResponse>( &API_HANDLER_PCB::handleDeleteItems );
|
||||
|
||||
registerHandler<GetBoardStackup, BoardStackupResponse>( &API_HANDLER_PCB::handleGetStackup );
|
||||
registerHandler<GetGraphicsDefaults, GraphicsDefaultsResponse>(
|
||||
&API_HANDLER_PCB::handleGetGraphicsDefaults );
|
||||
registerHandler<GetTextExtents, commands::BoundingBoxResponse>(
|
||||
&API_HANDLER_PCB::handleGetTextExtents );
|
||||
|
||||
registerHandler<InteractiveMoveItems, Empty>( &API_HANDLER_PCB::handleInteractiveMoveItems );
|
||||
registerHandler<GetNets, NetsResponse>( &API_HANDLER_PCB::handleGetNets );
|
||||
registerHandler<RefillZones, Empty>( &API_HANDLER_PCB::handleRefillZones );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<RunActionResponse> API_HANDLER_PCB::handleRunAction( RunAction& aRequest )
|
||||
PCB_EDIT_FRAME* API_HANDLER_PCB::frame() const
|
||||
{
|
||||
return static_cast<PCB_EDIT_FRAME*>( m_frame );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<RunActionResponse> API_HANDLER_PCB::handleRunAction( RunAction& aRequest,
|
||||
const HANDLER_CONTEXT& )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
RunActionResponse response;
|
||||
|
||||
if( m_frame->GetToolManager()->RunAction( aRequest.action(), true ) )
|
||||
if( frame()->GetToolManager()->RunAction( aRequest.action(), true ) )
|
||||
response.set_status( RunActionStatus::RAS_OK );
|
||||
else
|
||||
response.set_status( RunActionStatus::RAS_INVALID );
|
||||
|
@ -70,7 +96,7 @@ HANDLER_RESULT<RunActionResponse> API_HANDLER_PCB::handleRunAction( RunAction& a
|
|||
|
||||
|
||||
HANDLER_RESULT<GetOpenDocumentsResponse> API_HANDLER_PCB::handleGetOpenDocuments(
|
||||
GetOpenDocuments& aMsg )
|
||||
GetOpenDocuments& aMsg, const HANDLER_CONTEXT& )
|
||||
{
|
||||
if( aMsg.type() != DocumentType::DOCTYPE_PCB )
|
||||
{
|
||||
|
@ -83,166 +109,178 @@ HANDLER_RESULT<GetOpenDocumentsResponse> API_HANDLER_PCB::handleGetOpenDocuments
|
|||
GetOpenDocumentsResponse response;
|
||||
common::types::DocumentSpecifier doc;
|
||||
|
||||
wxFileName fn( m_frame->GetCurrentFileName() );
|
||||
wxFileName fn( frame()->GetCurrentFileName() );
|
||||
|
||||
doc.set_type( DocumentType::DOCTYPE_PCB );
|
||||
doc.set_board_filename( fn.GetFullName() );
|
||||
|
||||
doc.mutable_project()->set_name( frame()->Prj().GetProjectName().ToStdString() );
|
||||
doc.mutable_project()->set_path( frame()->Prj().GetProjectDirectory().ToStdString() );
|
||||
|
||||
response.mutable_documents()->Add( std::move( doc ) );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<BeginCommitResponse> API_HANDLER_PCB::handleBeginCommit( BeginCommit& aMsg )
|
||||
void API_HANDLER_PCB::pushCurrentCommit( const HANDLER_CONTEXT& aCtx, const wxString& aMessage )
|
||||
{
|
||||
BeginCommitResponse response;
|
||||
|
||||
if( m_commit )
|
||||
{
|
||||
// TODO: right now there is no way for m_transactionInProgress to be true here, but
|
||||
// we should still check it as a safety measure and return a specific error
|
||||
//if( !m_transactionInProgress )
|
||||
|
||||
m_commit->Revert();
|
||||
}
|
||||
|
||||
m_commit.reset( new BOARD_COMMIT( m_frame ) );
|
||||
|
||||
// TODO: return an opaque ID for this new commit to make this more robust
|
||||
m_transactionInProgress = true;
|
||||
|
||||
return response;
|
||||
API_HANDLER_EDITOR::pushCurrentCommit( aCtx, aMessage );
|
||||
frame()->Refresh();
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<EndCommitResponse> API_HANDLER_PCB::handleEndCommit( EndCommit& aMsg )
|
||||
std::unique_ptr<COMMIT> API_HANDLER_PCB::createCommit()
|
||||
{
|
||||
EndCommitResponse response;
|
||||
|
||||
// TODO: return more specific error if m_transactionInProgress is false
|
||||
if( !m_transactionInProgress )
|
||||
{
|
||||
// Make sure we don't get stuck with a commit we can never push
|
||||
m_commit.reset();
|
||||
response.set_result( CommitResult::CR_NO_COMMIT );
|
||||
return response;
|
||||
}
|
||||
|
||||
if( !m_commit )
|
||||
{
|
||||
response.set_result( CommitResult::CR_NO_COMMIT );
|
||||
return response;
|
||||
}
|
||||
|
||||
pushCurrentCommit( aMsg.message() );
|
||||
m_transactionInProgress = false;
|
||||
|
||||
response.set_result( CommitResult::CR_OK );
|
||||
return response;
|
||||
return std::make_unique<BOARD_COMMIT>( frame() );
|
||||
}
|
||||
|
||||
|
||||
BOARD_COMMIT* API_HANDLER_PCB::getCurrentCommit()
|
||||
std::optional<BOARD_ITEM*> API_HANDLER_PCB::getItemById( const KIID& aId ) const
|
||||
{
|
||||
if( !m_commit )
|
||||
m_commit.reset( new BOARD_COMMIT( m_frame ) );
|
||||
BOARD_ITEM* item = frame()->GetBoard()->GetItem( aId );
|
||||
|
||||
return m_commit.get();
|
||||
if( item == DELETED_BOARD_ITEM::GetInstance() )
|
||||
return std::nullopt;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
void API_HANDLER_PCB::pushCurrentCommit( const std::string& aMessage )
|
||||
bool API_HANDLER_PCB::validateDocumentInternal( const DocumentSpecifier& aDocument ) const
|
||||
{
|
||||
wxCHECK( m_commit, /* void */ );
|
||||
|
||||
wxString msg( aMessage.c_str(), wxConvUTF8 );
|
||||
|
||||
if( msg.IsEmpty() )
|
||||
msg = s_defaultCommitMessage;
|
||||
|
||||
m_commit->Push( msg );
|
||||
m_commit.reset();
|
||||
|
||||
m_frame->Refresh();
|
||||
}
|
||||
|
||||
|
||||
bool API_HANDLER_PCB::validateItemHeaderDocument( const common::types::ItemHeader& aHeader )
|
||||
{
|
||||
// TODO: this should return a more complex error type.
|
||||
// We should provide detailed feedback when a header fails validation, and distinguish between
|
||||
// "skip this handler" and "this is the right handler, but the request is invalid"
|
||||
if( !aHeader.has_document() || aHeader.document().type() != DocumentType::DOCTYPE_PCB )
|
||||
if( aDocument.type() != DocumentType::DOCTYPE_PCB )
|
||||
return false;
|
||||
|
||||
wxFileName fn( m_frame->GetCurrentFileName() );
|
||||
|
||||
return aHeader.document().board_filename().compare( fn.GetFullName() ) == 0;
|
||||
wxFileName fn( frame()->GetCurrentFileName() );
|
||||
return 0 == aDocument.board_filename().compare( fn.GetFullName() );
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> API_HANDLER_PCB::createItemForType( KICAD_T aType,
|
||||
BOARD_ITEM_CONTAINER* aContainer )
|
||||
HANDLER_RESULT<std::unique_ptr<BOARD_ITEM>> API_HANDLER_PCB::createItemForType( KICAD_T aType,
|
||||
BOARD_ITEM_CONTAINER* aContainer )
|
||||
{
|
||||
switch( aType )
|
||||
if( !aContainer )
|
||||
{
|
||||
case PCB_TRACE_T: return std::make_unique<PCB_TRACK>( aContainer );
|
||||
case PCB_ARC_T: return std::make_unique<PCB_ARC>( aContainer );
|
||||
case PCB_VIA_T: return std::make_unique<PCB_VIA>( aContainer );
|
||||
default: return nullptr;
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( "Tried to create an item in a null container" );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
if( aType == PCB_PAD_T && !dynamic_cast<FOOTPRINT*>( aContainer ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "Tried to create a pad in {}, which is not a footprint",
|
||||
aContainer->GetFriendlyName().ToStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
else if( aType == PCB_FOOTPRINT_T && !dynamic_cast<BOARD*>( aContainer ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "Tried to create a footprint in {}, which is not a board",
|
||||
aContainer->GetFriendlyName().ToStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> created = CreateItemForType( aType, aContainer );
|
||||
|
||||
if( !created )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "Tried to create an item of type {}, which is unhandled",
|
||||
magic_enum::enum_name( aType ) ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<CreateItemsResponse> API_HANDLER_PCB::handleCreateItems( CreateItems& aMsg )
|
||||
HANDLER_RESULT<ItemRequestStatus> API_HANDLER_PCB::handleCreateUpdateItemsInternal( bool aCreate,
|
||||
const HANDLER_CONTEXT& aCtx,
|
||||
const types::ItemHeader &aHeader,
|
||||
const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
|
||||
std::function<void( ItemStatus, google::protobuf::Any )> aItemHandler )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
|
||||
if( !validateItemHeaderDocument( aMsg.header() ) )
|
||||
auto containerResult = validateItemHeaderDocument( aHeader );
|
||||
|
||||
if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
|
||||
{
|
||||
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
BOARD* board = m_frame->GetBoard();
|
||||
BOARD_ITEM_SET boardItems = board->GetItemSet();
|
||||
|
||||
std::map<KIID, BOARD_ITEM*> itemUuidMap;
|
||||
|
||||
std::for_each( boardItems.begin(), boardItems.end(),
|
||||
[&]( BOARD_ITEM* aItem )
|
||||
{
|
||||
itemUuidMap[aItem->m_Uuid] = aItem;
|
||||
} );
|
||||
|
||||
BOARD_COMMIT* commit = getCurrentCommit();
|
||||
|
||||
CreateItemsResponse response;
|
||||
|
||||
for( const google::protobuf::Any& anyItem : aMsg.items() )
|
||||
else if( !containerResult )
|
||||
{
|
||||
ItemCreationResult itemResult;
|
||||
e.CopyFrom( containerResult.error() );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
BOARD* board = frame()->GetBoard();
|
||||
BOARD_ITEM_CONTAINER* container = board;
|
||||
|
||||
if( containerResult->has_value() )
|
||||
{
|
||||
const KIID& containerId = **containerResult;
|
||||
std::optional<BOARD_ITEM*> optItem = getItemById( containerId );
|
||||
|
||||
if( optItem )
|
||||
{
|
||||
container = dynamic_cast<BOARD_ITEM_CONTAINER*>( *optItem );
|
||||
|
||||
if( !container )
|
||||
{
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format(
|
||||
"The requested container {} is not a valid board item container",
|
||||
containerId.AsStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format(
|
||||
"The requested container {} does not exist in this document",
|
||||
containerId.AsStdString() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
}
|
||||
|
||||
BOARD_COMMIT* commit = static_cast<BOARD_COMMIT*>( getCurrentCommit( aCtx ) );
|
||||
|
||||
for( const google::protobuf::Any& anyItem : aItems )
|
||||
{
|
||||
ItemStatus status;
|
||||
std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
|
||||
|
||||
if( !type )
|
||||
{
|
||||
itemResult.set_status( ItemCreationStatus::ICS_INVALID_TYPE );
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
|
||||
status.set_error_message( fmt::format( "Could not decode a valid type from {}",
|
||||
anyItem.type_url() ) );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> item = createItemForType( *type, board );
|
||||
HANDLER_RESULT<std::unique_ptr<BOARD_ITEM>> creationResult =
|
||||
createItemForType( *type, container );
|
||||
|
||||
if( !item )
|
||||
if( !creationResult )
|
||||
{
|
||||
itemResult.set_status( ItemCreationStatus::ICS_INVALID_TYPE );
|
||||
e.set_error_message( fmt::format( "item type {} not supported for board",
|
||||
magic_enum::enum_name( *type ) ) );
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
|
||||
status.set_error_message( creationResult.error().error_message() );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> item( std::move( *creationResult ) );
|
||||
|
||||
if( !item->Deserialize( anyItem ) )
|
||||
{
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
|
@ -251,28 +289,70 @@ HANDLER_RESULT<CreateItemsResponse> API_HANDLER_PCB::handleCreateItems( CreateIt
|
|||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
if( itemUuidMap.count( item->m_Uuid ) )
|
||||
std::optional<BOARD_ITEM*> optItem = getItemById( item->m_Uuid );
|
||||
|
||||
if( aCreate && optItem )
|
||||
{
|
||||
itemResult.set_status( ItemCreationStatus::ICS_EXISTING );
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
status.set_code( ItemStatusCode::ISC_EXISTING );
|
||||
status.set_error_message( fmt::format( "an item with UUID {} already exists",
|
||||
item->m_Uuid.AsStdString() ) );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
else if( !aCreate && !optItem )
|
||||
{
|
||||
status.set_code( ItemStatusCode::ISC_NONEXISTENT );
|
||||
status.set_error_message( fmt::format( "an item with UUID {} does not exist",
|
||||
item->m_Uuid.AsStdString() ) );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
itemResult.set_status( ItemCreationStatus::ICS_OK );
|
||||
item->Serialize( *itemResult.mutable_item() );
|
||||
commit->Add( item.release() );
|
||||
if( aCreate && !board->GetEnabledLayers().Contains( item->GetLayer() ) )
|
||||
{
|
||||
status.set_code( ItemStatusCode::ISC_INVALID_DATA );
|
||||
status.set_error_message( fmt::format( "attempted to add item on disabled layer {}",
|
||||
LayerName( item->GetLayer() ).ToStdString() ) );
|
||||
aItemHandler( status, anyItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
status.set_code( ItemStatusCode::ISC_OK );
|
||||
google::protobuf::Any newItem;
|
||||
|
||||
if( aCreate )
|
||||
{
|
||||
item->Serialize( newItem );
|
||||
commit->Add( item.release() );
|
||||
}
|
||||
else
|
||||
{
|
||||
BOARD_ITEM* boardItem = *optItem;
|
||||
commit->Modify( boardItem );
|
||||
boardItem->SwapItemData( item.get() );
|
||||
boardItem->Serialize( newItem );
|
||||
}
|
||||
|
||||
aItemHandler( status, newItem );
|
||||
}
|
||||
|
||||
pushCurrentCommit( "Added items via API" );
|
||||
response.set_status( ItemRequestStatus::IRS_OK );
|
||||
return response;
|
||||
if( !m_activeClients.count( aCtx.ClientName ) )
|
||||
{
|
||||
pushCurrentCommit( aCtx, aCreate ? _( "Created items via API" )
|
||||
: _( "Added items via API" ) );
|
||||
}
|
||||
|
||||
|
||||
return ItemRequestStatus::IRS_OK;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<GetItemsResponse> API_HANDLER_PCB::handleGetItems( GetItems& aMsg )
|
||||
HANDLER_RESULT<GetItemsResponse> API_HANDLER_PCB::handleGetItems( GetItems& aMsg,
|
||||
const HANDLER_CONTEXT& )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
if( !validateItemHeaderDocument( aMsg.header() ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
|
@ -283,18 +363,17 @@ HANDLER_RESULT<GetItemsResponse> API_HANDLER_PCB::handleGetItems( GetItems& aMsg
|
|||
|
||||
GetItemsResponse response;
|
||||
|
||||
BOARD* board = m_frame->GetBoard();
|
||||
BOARD* board = frame()->GetBoard();
|
||||
std::vector<BOARD_ITEM*> items;
|
||||
std::set<KICAD_T> typesRequested, typesInserted;
|
||||
bool handledAnything = false;
|
||||
|
||||
for( const common::types::ItemType& typeMessage : aMsg.types() )
|
||||
for( int typeRaw : aMsg.types() )
|
||||
{
|
||||
KICAD_T type;
|
||||
auto typeMessage = static_cast<common::types::KiCadObjectType>( typeRaw );
|
||||
KICAD_T type = FromProtoEnum<KICAD_T>( typeMessage );
|
||||
|
||||
if( std::optional<KICAD_T> opt_type = magic_enum::enum_cast<KICAD_T>( typeMessage.type() ) )
|
||||
type = *opt_type;
|
||||
else
|
||||
if( type == TYPE_NOT_INIT )
|
||||
continue;
|
||||
|
||||
typesRequested.emplace( type );
|
||||
|
@ -313,6 +392,31 @@ HANDLER_RESULT<GetItemsResponse> API_HANDLER_PCB::handleGetItems( GetItems& aMsg
|
|||
typesInserted.insert( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } );
|
||||
break;
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
handledAnything = true;
|
||||
|
||||
for( FOOTPRINT* fp : board->Footprints() )
|
||||
{
|
||||
std::copy( fp->Pads().begin(), fp->Pads().end(),
|
||||
std::back_inserter( items ) );
|
||||
}
|
||||
|
||||
typesInserted.insert( PCB_PAD_T );
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_FOOTPRINT_T:
|
||||
{
|
||||
handledAnything = true;
|
||||
|
||||
std::copy( board->Footprints().begin(), board->Footprints().end(),
|
||||
std::back_inserter( items ) );
|
||||
|
||||
typesInserted.insert( PCB_FOOTPRINT_T );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -341,154 +445,259 @@ HANDLER_RESULT<GetItemsResponse> API_HANDLER_PCB::handleGetItems( GetItems& aMsg
|
|||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<UpdateItemsResponse> API_HANDLER_PCB::handleUpdateItems( UpdateItems& aMsg )
|
||||
void API_HANDLER_PCB::deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
|
||||
if( !validateItemHeaderDocument( aMsg.header() ) )
|
||||
{
|
||||
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
BOARD* board = m_frame->GetBoard();
|
||||
BOARD_ITEM_SET boardItems = board->GetItemSet();
|
||||
|
||||
std::map<KIID, BOARD_ITEM*> itemUuidMap;
|
||||
|
||||
std::for_each( boardItems.begin(), boardItems.end(),
|
||||
[&]( BOARD_ITEM* aItem )
|
||||
{
|
||||
itemUuidMap[aItem->m_Uuid] = aItem;
|
||||
} );
|
||||
|
||||
BOARD_COMMIT* commit = getCurrentCommit();
|
||||
|
||||
UpdateItemsResponse response;
|
||||
|
||||
for( const google::protobuf::Any& anyItem : aMsg.items() )
|
||||
{
|
||||
ItemUpdateResult itemResult;
|
||||
std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
|
||||
|
||||
if( !type )
|
||||
{
|
||||
itemResult.set_status( ItemUpdateStatus::IUS_INVALID_TYPE );
|
||||
response.mutable_updated_items()->Add( std::move( itemResult ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> temporaryItem = createItemForType( *type, board );
|
||||
|
||||
if( !temporaryItem )
|
||||
{
|
||||
itemResult.set_status( ItemUpdateStatus::IUS_INVALID_TYPE );
|
||||
response.mutable_updated_items()->Add( std::move( itemResult ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !temporaryItem->Deserialize( anyItem ) )
|
||||
{
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "could not unpack {} from request",
|
||||
magic_enum::enum_name( *type ) ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
if( !itemUuidMap.count( temporaryItem->m_Uuid ) )
|
||||
{
|
||||
itemResult.set_status( ItemUpdateStatus::IUS_NONEXISTENT );
|
||||
response.mutable_updated_items()->Add( std::move( itemResult ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
BOARD_ITEM* boardItem = itemUuidMap[temporaryItem->m_Uuid];
|
||||
|
||||
boardItem->SwapItemData( temporaryItem.get() );
|
||||
|
||||
itemResult.set_status( ItemUpdateStatus::IUS_OK );
|
||||
boardItem->Serialize( *itemResult.mutable_item() );
|
||||
commit->Modify( boardItem );
|
||||
|
||||
itemResult.set_status( ItemUpdateStatus::IUS_OK );
|
||||
response.mutable_updated_items()->Add( std::move( itemResult ) );
|
||||
}
|
||||
|
||||
response.set_status( ItemRequestStatus::IRS_OK );
|
||||
pushCurrentCommit( "Updated items via API" );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<DeleteItemsResponse> API_HANDLER_PCB::handleDeleteItems( DeleteItems& aMsg )
|
||||
{
|
||||
if( !validateItemHeaderDocument( aMsg.header() ) )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
e.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
std::map<KIID, ItemDeletionStatus> itemsToDelete;
|
||||
|
||||
for( const common::types::KIID& kiidBuf : aMsg.item_ids() )
|
||||
{
|
||||
if( !kiidBuf.value().empty() )
|
||||
{
|
||||
KIID kiid( kiidBuf.value() );
|
||||
itemsToDelete[kiid] = ItemDeletionStatus::IDS_NONEXISTENT;
|
||||
}
|
||||
}
|
||||
|
||||
if( itemsToDelete.empty() )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( "no valid items to delete were given" );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
BOARD* board = m_frame->GetBoard();
|
||||
|
||||
// This is somewhat inefficient on paper, but the total number of items on a board is
|
||||
// not computationally-speaking very high even on what we'd consider a large design.
|
||||
// If this ends up not being the case, we should consider doing something like refactoring
|
||||
// BOARD to contain all items in a contiguous memory arena and constructing views over it
|
||||
// when we want to filter to just tracks, etc.
|
||||
BOARD_ITEM_SET items = board->GetItemSet();
|
||||
BOARD* board = frame()->GetBoard();
|
||||
std::vector<BOARD_ITEM*> validatedItems;
|
||||
|
||||
for( BOARD_ITEM* item : items )
|
||||
for( std::pair<const KIID, ItemDeletionStatus> pair : aItemsToDelete )
|
||||
{
|
||||
if( itemsToDelete.count( item->m_Uuid ) )
|
||||
if( BOARD_ITEM* item = board->GetItem( pair.first ) )
|
||||
{
|
||||
validatedItems.push_back( item );
|
||||
itemsToDelete[item->m_Uuid] = ItemDeletionStatus::IDS_OK;
|
||||
aItemsToDelete[pair.first] = ItemDeletionStatus::IDS_OK;
|
||||
}
|
||||
|
||||
// Note: we don't currently support locking items from API modification, but here is where
|
||||
// to add it in the future (and return IDS_IMMUTABLE)
|
||||
}
|
||||
|
||||
BOARD_COMMIT* commit = getCurrentCommit();
|
||||
COMMIT* commit = getCurrentCommit( aCtx );
|
||||
|
||||
for( BOARD_ITEM* item : validatedItems )
|
||||
commit->Remove( item );
|
||||
|
||||
if( !m_transactionInProgress )
|
||||
pushCurrentCommit( "Deleted items via API" );
|
||||
if( !m_activeClients.count( aCtx.ClientName ) )
|
||||
pushCurrentCommit( aCtx, _( "Deleted items via API" ) );
|
||||
}
|
||||
|
||||
DeleteItemsResponse response;
|
||||
|
||||
for( const auto& [id, status] : itemsToDelete )
|
||||
std::optional<EDA_ITEM*> API_HANDLER_PCB::getItemFromDocument( const DocumentSpecifier& aDocument,
|
||||
const KIID& aId )
|
||||
{
|
||||
if( !validateDocument( aDocument ) )
|
||||
return std::nullopt;
|
||||
|
||||
return getItemById( aId );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<BoardStackupResponse> API_HANDLER_PCB::handleGetStackup( GetBoardStackup& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
HANDLER_RESULT<bool> documentValidation = validateDocument( aMsg.board() );
|
||||
|
||||
if( !documentValidation )
|
||||
return tl::unexpected( documentValidation.error() );
|
||||
|
||||
const BOARD* board = frame()->GetBoard();
|
||||
BoardStackupResponse response;
|
||||
google::protobuf::Any any;
|
||||
const BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
|
||||
|
||||
if( frame()->GetBoard()->GetDesignSettings().m_HasStackup )
|
||||
{
|
||||
ItemDeletionResult result;
|
||||
result.mutable_id()->set_value( id.AsStdString() );
|
||||
result.set_status( status );
|
||||
const BOARD_STACKUP& stackup = bds.GetStackupDescriptor();
|
||||
stackup.Serialize( any );
|
||||
}
|
||||
else
|
||||
{
|
||||
BOARD_STACKUP stackup;
|
||||
stackup.BuildDefaultStackupList( &bds, board->GetCopperLayerCount() );
|
||||
stackup.Serialize( any );
|
||||
}
|
||||
|
||||
response.set_status( ItemRequestStatus::IRS_OK );
|
||||
any.UnpackTo( response.mutable_stackup() );
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<GraphicsDefaultsResponse> API_HANDLER_PCB::handleGetGraphicsDefaults(
|
||||
GetGraphicsDefaults& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
HANDLER_RESULT<bool> documentValidation = validateDocument( aMsg.board() );
|
||||
|
||||
if( !documentValidation )
|
||||
return tl::unexpected( documentValidation.error() );
|
||||
|
||||
const BOARD_DESIGN_SETTINGS& bds = frame()->GetBoard()->GetDesignSettings();
|
||||
GraphicsDefaultsResponse response;
|
||||
|
||||
// TODO: This should change to be an enum class
|
||||
constexpr std::array<kiapi::board::BoardLayerClass, LAYER_CLASS_COUNT> classOrder = {
|
||||
kiapi::board::BLC_SILKSCREEN,
|
||||
kiapi::board::BLC_COPPER,
|
||||
kiapi::board::BLC_EDGES,
|
||||
kiapi::board::BLC_COURTYARD,
|
||||
kiapi::board::BLC_FABRICATION,
|
||||
kiapi::board::BLC_OTHER
|
||||
};
|
||||
|
||||
for( int i = 0; i < LAYER_CLASS_COUNT; ++i )
|
||||
{
|
||||
kiapi::board::BoardLayerGraphicsDefaults* l = response.mutable_defaults()->add_layers();
|
||||
|
||||
l->set_layer( classOrder[i] );
|
||||
l->mutable_line_thickness()->set_value_nm( bds.m_LineThickness[i] );
|
||||
|
||||
kiapi::common::types::TextAttributes* text = l->mutable_text();
|
||||
text->mutable_size()->set_x_nm( bds.m_TextSize[i].x );
|
||||
text->mutable_size()->set_y_nm( bds.m_TextSize[i].y );
|
||||
text->mutable_stroke_width()->set_value_nm( bds.m_TextThickness[i] );
|
||||
text->set_italic( bds.m_TextItalic[i] );
|
||||
text->set_keep_upright( bds.m_TextUpright[i] );
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<commands::BoundingBoxResponse> 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 );
|
||||
}
|
||||
|
||||
commands::BoundingBoxResponse 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<Empty> API_HANDLER_PCB::handleInteractiveMoveItems( InteractiveMoveItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
HANDLER_RESULT<bool> documentValidation = validateDocument( aMsg.board() );
|
||||
|
||||
if( !documentValidation )
|
||||
return tl::unexpected( documentValidation.error() );
|
||||
|
||||
TOOL_MANAGER* mgr = frame()->GetToolManager();
|
||||
std::vector<EDA_ITEM*> toSelect;
|
||||
|
||||
for( const kiapi::common::types::KIID& id : aMsg.items() )
|
||||
{
|
||||
if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
|
||||
toSelect.emplace_back( static_cast<EDA_ITEM*>( *item ) );
|
||||
}
|
||||
|
||||
if( toSelect.empty() )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( fmt::format( "None of the given items exist on the board",
|
||||
aMsg.board().board_filename() ) );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
selectionTool->GetSelection().SetReferencePoint( toSelect[0]->GetPosition() );
|
||||
|
||||
mgr->RunAction( PCB_ACTIONS::selectionClear );
|
||||
mgr->RunAction<EDA_ITEMS*>( PCB_ACTIONS::selectItems, &toSelect );
|
||||
|
||||
COMMIT* commit = getCurrentCommit( aCtx );
|
||||
mgr->PostAction( PCB_ACTIONS::move, commit );
|
||||
|
||||
return Empty();
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<NetsResponse> API_HANDLER_PCB::handleGetNets( GetNets& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
HANDLER_RESULT<bool> documentValidation = validateDocument( aMsg.board() );
|
||||
|
||||
if( !documentValidation )
|
||||
return tl::unexpected( documentValidation.error() );
|
||||
|
||||
NetsResponse response;
|
||||
BOARD* board = frame()->GetBoard();
|
||||
|
||||
std::set<wxString> netclassFilter;
|
||||
|
||||
for( const std::string& nc : aMsg.netclass_filter() )
|
||||
netclassFilter.insert( wxString( nc.c_str(), wxConvUTF8 ) );
|
||||
|
||||
for( NETINFO_ITEM* net : board->GetNetInfo() )
|
||||
{
|
||||
NETCLASS* nc = net->GetNetClass();
|
||||
|
||||
if( !netclassFilter.empty() && nc && !netclassFilter.count( nc->GetName() ) )
|
||||
continue;
|
||||
|
||||
board::types::Net* netProto = response.add_nets();
|
||||
netProto->set_name( net->GetNetname() );
|
||||
netProto->mutable_code()->set_value( net->GetNetCode() );
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<Empty> API_HANDLER_PCB::handleRefillZones( RefillZones& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx )
|
||||
{
|
||||
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
|
||||
return tl::unexpected( *busy );
|
||||
|
||||
HANDLER_RESULT<bool> documentValidation = validateDocument( aMsg.board() );
|
||||
|
||||
if( !documentValidation )
|
||||
return tl::unexpected( documentValidation.error() );
|
||||
|
||||
if( aMsg.zones().empty() )
|
||||
{
|
||||
TOOL_MANAGER* mgr = frame()->GetToolManager();
|
||||
frame()->CallAfter( [mgr]()
|
||||
{
|
||||
mgr->RunAction( PCB_ACTIONS::zoneFillAll );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
return Empty();
|
||||
}
|
||||
|
|
|
@ -23,14 +23,16 @@
|
|||
|
||||
#include <google/protobuf/empty.pb.h>
|
||||
|
||||
#include <api/api_handler.h>
|
||||
|
||||
#include <api/api_handler_editor.h>
|
||||
#include <api/board/board_commands.pb.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
#include <api/common/commands/editor_commands.pb.h>
|
||||
|
||||
#include <kiid.h>
|
||||
#include <properties/property_mgr.h>
|
||||
|
||||
using namespace kiapi;
|
||||
using namespace kiapi::common;
|
||||
using namespace kiapi::board::commands;
|
||||
|
||||
using google::protobuf::Empty;
|
||||
|
||||
|
@ -44,7 +46,7 @@ class PCB_TRACK;
|
|||
class PROPERTY_BASE;
|
||||
|
||||
|
||||
class API_HANDLER_PCB : public API_HANDLER
|
||||
class API_HANDLER_PCB : public API_HANDLER_EDITOR
|
||||
{
|
||||
public:
|
||||
API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame );
|
||||
|
@ -52,35 +54,64 @@ public:
|
|||
private:
|
||||
typedef std::map<std::string, PROPERTY_BASE*> PROTO_PROPERTY_MAP;
|
||||
|
||||
static std::unique_ptr<BOARD_ITEM> createItemForType( KICAD_T aType,
|
||||
static HANDLER_RESULT<std::unique_ptr<BOARD_ITEM>> createItemForType( KICAD_T aType,
|
||||
BOARD_ITEM_CONTAINER* aContainer );
|
||||
|
||||
HANDLER_RESULT<commands::RunActionResponse> handleRunAction( commands::RunAction& aMsg );
|
||||
HANDLER_RESULT<commands::RunActionResponse> handleRunAction( commands::RunAction& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::GetOpenDocumentsResponse> handleGetOpenDocuments(
|
||||
commands::GetOpenDocuments& aMsg );
|
||||
commands::GetOpenDocuments& aMsg, const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::BeginCommitResponse> handleBeginCommit( commands::BeginCommit& aMsg );
|
||||
HANDLER_RESULT<commands::EndCommitResponse> handleEndCommit( commands::EndCommit& aMsg );
|
||||
HANDLER_RESULT<commands::GetItemsResponse> handleGetItems( commands::GetItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::CreateItemsResponse> handleCreateItems( commands::CreateItems& aMsg );
|
||||
HANDLER_RESULT<commands::GetItemsResponse> handleGetItems( commands::GetItems& aMsg );
|
||||
HANDLER_RESULT<commands::UpdateItemsResponse> handleUpdateItems( commands::UpdateItems& aMsg );
|
||||
HANDLER_RESULT<commands::DeleteItemsResponse> handleDeleteItems( commands::DeleteItems& aMsg );
|
||||
HANDLER_RESULT<BoardStackupResponse> handleGetStackup( GetBoardStackup& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<GraphicsDefaultsResponse> handleGetGraphicsDefaults( GetGraphicsDefaults& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<commands::BoundingBoxResponse> handleGetTextExtents( GetTextExtents& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<Empty> handleInteractiveMoveItems( InteractiveMoveItems& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<NetsResponse> handleGetNets( GetNets& aMsg,
|
||||
const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
HANDLER_RESULT<Empty> handleRefillZones( RefillZones& aMsg, const HANDLER_CONTEXT& aCtx );
|
||||
|
||||
protected:
|
||||
std::unique_ptr<COMMIT> createCommit() override;
|
||||
|
||||
kiapi::common::types::DocumentType thisDocumentType() const override
|
||||
{
|
||||
return kiapi::common::types::DOCTYPE_PCB;
|
||||
}
|
||||
|
||||
bool validateDocumentInternal( const DocumentSpecifier& aDocument ) const override;
|
||||
|
||||
void deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
|
||||
const HANDLER_CONTEXT& aCtx ) override;
|
||||
|
||||
std::optional<EDA_ITEM*> getItemFromDocument( const DocumentSpecifier& aDocument,
|
||||
const KIID& aId ) override;
|
||||
|
||||
private:
|
||||
PCB_EDIT_FRAME* frame() const;
|
||||
|
||||
bool validateItemHeaderDocument( const common::types::ItemHeader& aHeader );
|
||||
void pushCurrentCommit( const HANDLER_CONTEXT& aCtx, const wxString& aMessage ) override;
|
||||
|
||||
BOARD_COMMIT* getCurrentCommit();
|
||||
std::optional<BOARD_ITEM*> getItemById( const KIID& aId ) const;
|
||||
|
||||
void pushCurrentCommit( const std::string& aMessage );
|
||||
|
||||
PCB_EDIT_FRAME* m_frame;
|
||||
|
||||
std::unique_ptr<BOARD_COMMIT> m_commit;
|
||||
|
||||
bool m_transactionInProgress;
|
||||
HANDLER_RESULT<types::ItemRequestStatus> handleCreateUpdateItemsInternal( bool aCreate,
|
||||
const HANDLER_CONTEXT& aCtx,
|
||||
const types::ItemHeader &aHeader,
|
||||
const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
|
||||
std::function<void(commands::ItemStatus, google::protobuf::Any)> aItemHandler )
|
||||
override;
|
||||
};
|
||||
|
||||
#endif //KICAD_API_HANDLER_PCB_H
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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 <import_export.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include <pad_shapes.h>
|
||||
#include <zones.h>
|
||||
|
||||
using namespace kiapi::board;
|
||||
|
||||
template<>
|
||||
types::PadStackShape ToProtoEnum( PAD_SHAPE aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case PAD_SHAPE::CIRCLE: return types::PadStackShape::PSS_CIRCLE;
|
||||
case PAD_SHAPE::RECTANGLE: return types::PadStackShape::PSS_RECTANGLE;
|
||||
case PAD_SHAPE::OVAL: return types::PadStackShape::PSS_OVAL;
|
||||
case PAD_SHAPE::TRAPEZOID: return types::PadStackShape::PSS_TRAPEZOID;
|
||||
case PAD_SHAPE::ROUNDRECT: return types::PadStackShape::PSS_ROUNDRECT;
|
||||
case PAD_SHAPE::CHAMFERED_RECT: return types::PadStackShape::PSS_CHAMFEREDRECT;
|
||||
case PAD_SHAPE::CUSTOM: return types::PadStackShape::PSS_CUSTOM;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, types::PadStackShape::PSS_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<PAD_SHAPE>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
PAD_SHAPE FromProtoEnum( types::PadStackShape aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case types::PadStackShape::PSS_CIRCLE: return PAD_SHAPE::CIRCLE;
|
||||
case types::PadStackShape::PSS_RECTANGLE: return PAD_SHAPE::RECTANGLE;
|
||||
case types::PadStackShape::PSS_OVAL: return PAD_SHAPE::OVAL;
|
||||
case types::PadStackShape::PSS_TRAPEZOID: return PAD_SHAPE::TRAPEZOID;
|
||||
case types::PadStackShape::PSS_ROUNDRECT: return PAD_SHAPE::ROUNDRECT;
|
||||
case types::PadStackShape::PSS_CHAMFEREDRECT: return PAD_SHAPE::CHAMFERED_RECT;
|
||||
case types::PadStackShape::PSS_CUSTOM: return PAD_SHAPE::CUSTOM;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, PAD_SHAPE::CIRCLE,
|
||||
"Unhandled case in FromProtoEnum<types::PadStackShape>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
types::ZoneConnectionStyle ToProtoEnum( ZONE_CONNECTION aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case ZONE_CONNECTION::INHERITED: return types::ZoneConnectionStyle::ZCS_INHERITED;
|
||||
case ZONE_CONNECTION::NONE: return types::ZoneConnectionStyle::ZCS_NONE;
|
||||
case ZONE_CONNECTION::THERMAL: return types::ZoneConnectionStyle::ZCS_THERMAL;
|
||||
case ZONE_CONNECTION::FULL: return types::ZoneConnectionStyle::ZCS_FULL;
|
||||
case ZONE_CONNECTION::THT_THERMAL: return types::ZoneConnectionStyle::ZCS_PTH_THERMAL;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, types::ZoneConnectionStyle::ZCS_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<ZONE_CONNECTION>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
ZONE_CONNECTION FromProtoEnum( types::ZoneConnectionStyle aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case types::ZoneConnectionStyle::ZCS_UNKNOWN: return ZONE_CONNECTION::INHERITED;
|
||||
case types::ZoneConnectionStyle::ZCS_INHERITED: return ZONE_CONNECTION::INHERITED;
|
||||
case types::ZoneConnectionStyle::ZCS_NONE: return ZONE_CONNECTION::NONE;
|
||||
case types::ZoneConnectionStyle::ZCS_THERMAL: return ZONE_CONNECTION::THERMAL;
|
||||
case types::ZoneConnectionStyle::ZCS_FULL: return ZONE_CONNECTION::FULL;
|
||||
case types::ZoneConnectionStyle::ZCS_PTH_THERMAL: return ZONE_CONNECTION::THT_THERMAL;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, ZONE_CONNECTION::INHERITED,
|
||||
"Unhandled case in FromProtoEnum<types::ZoneConnectionStyle>" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2023 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/api_pcb_utils.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <board.h>
|
||||
#include <board_item_container.h>
|
||||
#include <footprint.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_group.h>
|
||||
#include <pcb_reference_image.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pcb_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <zone.h>
|
||||
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> CreateItemForType( KICAD_T aType, BOARD_ITEM_CONTAINER* aContainer )
|
||||
{
|
||||
switch( aType )
|
||||
{
|
||||
case PCB_TRACE_T: return std::make_unique<PCB_TRACK>( aContainer );
|
||||
case PCB_ARC_T: return std::make_unique<PCB_ARC>( aContainer );
|
||||
case PCB_VIA_T: return std::make_unique<PCB_VIA>( aContainer );
|
||||
case PCB_TEXT_T: return std::make_unique<PCB_TEXT>( aContainer );
|
||||
case PCB_TEXTBOX_T: return std::make_unique<PCB_TEXTBOX>( aContainer );
|
||||
case PCB_SHAPE_T: return std::make_unique<PCB_SHAPE>( aContainer );
|
||||
case PCB_ZONE_T: return std::make_unique<ZONE>( aContainer );
|
||||
case PCB_GROUP_T: return std::make_unique<PCB_GROUP>( aContainer );
|
||||
case PCB_REFERENCE_IMAGE_T: return std::make_unique<PCB_REFERENCE_IMAGE>( aContainer );
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aContainer );
|
||||
|
||||
if( !footprint )
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<PAD>( footprint );
|
||||
}
|
||||
|
||||
case PCB_FOOTPRINT_T:
|
||||
{
|
||||
BOARD* board = dynamic_cast<BOARD*>( aContainer );
|
||||
|
||||
if( !board )
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<FOOTPRINT>( board );
|
||||
}
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace kiapi::board
|
||||
{
|
||||
|
||||
void PackLayerSet( google::protobuf::RepeatedField<int>& aOutput, const LSET& aLayerSet )
|
||||
{
|
||||
for( const PCB_LAYER_ID& layer : aLayerSet.Seq() )
|
||||
aOutput.Add( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
|
||||
}
|
||||
|
||||
|
||||
LSET UnpackLayerSet( const google::protobuf::RepeatedField<int>& aProtoLayerSet )
|
||||
{
|
||||
LSET set;
|
||||
|
||||
for( int layer : aProtoLayerSet )
|
||||
{
|
||||
wxCHECK2( layer >= F_Cu && layer < PCB_LAYER_ID_COUNT, continue );
|
||||
PCB_LAYER_ID boardLayer =
|
||||
FromProtoEnum<PCB_LAYER_ID>( static_cast<types::BoardLayer>( layer ) );
|
||||
set.set( boardLayer );
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
} // namespace kiapi::board
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2023 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/>.
|
||||
*/
|
||||
|
||||
#ifndef KICAD_API_PCB_UTLIS_H
|
||||
#define KICAD_API_PCB_UTLIS_H
|
||||
|
||||
#include <memory>
|
||||
#include <core/typeinfo.h>
|
||||
#include <import_export.h>
|
||||
#include <layer_ids.h>
|
||||
#include <api/common/types/base_types.pb.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
|
||||
class BOARD_ITEM;
|
||||
class BOARD_ITEM_CONTAINER;
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> CreateItemForType( KICAD_T aType, BOARD_ITEM_CONTAINER* aContainer );
|
||||
|
||||
namespace kiapi::board
|
||||
{
|
||||
|
||||
void PackLayerSet( google::protobuf::RepeatedField<int>& aOutput, const LSET& aLayerSet );
|
||||
|
||||
LSET UnpackLayerSet( const google::protobuf::RepeatedField<int>& aInput );
|
||||
|
||||
} // namespace kiapi::board
|
||||
|
||||
#endif //KICAD_API_PCB_UTLIS_H
|
|
@ -154,37 +154,26 @@ BOARD::~BOARD()
|
|||
// Clean up the owned elements
|
||||
DeleteMARKERs();
|
||||
|
||||
for( ZONE* zone : m_zones )
|
||||
delete zone;
|
||||
|
||||
m_zones.clear();
|
||||
|
||||
delete m_SolderMaskBridges;
|
||||
|
||||
for( FOOTPRINT* footprint : m_footprints )
|
||||
delete footprint;
|
||||
BOARD_ITEM_SET ownedItems = GetItemSet();
|
||||
|
||||
m_zones.clear();
|
||||
m_footprints.clear();
|
||||
|
||||
for( PCB_TRACK* t : m_tracks )
|
||||
delete t;
|
||||
|
||||
m_tracks.clear();
|
||||
|
||||
for( BOARD_ITEM* d : m_drawings )
|
||||
delete d;
|
||||
|
||||
m_drawings.clear();
|
||||
|
||||
for( PCB_GROUP* g : m_groups )
|
||||
delete g;
|
||||
|
||||
m_groups.clear();
|
||||
|
||||
// Generators not currently returned by GetItemSet
|
||||
for( PCB_GENERATOR* g : m_generators )
|
||||
delete g;
|
||||
ownedItems.insert( g );
|
||||
|
||||
m_generators.clear();
|
||||
|
||||
// Delete the owned items after clearing the containers, because some item dtors
|
||||
// cause call chains that query the containers
|
||||
for( BOARD_ITEM* item : ownedItems )
|
||||
delete item;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#include <board.h>
|
||||
#include <i18n_utility.h> // For _HKI definition
|
||||
#include "stackup_predefined_prms.h"
|
||||
#include <google/protobuf/any.pb.h>
|
||||
#include <api/board/board.pb.h>
|
||||
#include <api/api_enums.h>
|
||||
|
||||
|
||||
bool DIELECTRIC_PRMS::operator==( const DIELECTRIC_PRMS& aOther ) const
|
||||
|
@ -418,6 +421,44 @@ bool BOARD_STACKUP::operator==( const BOARD_STACKUP& aOther ) const
|
|||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP::Serialize( google::protobuf::Any& aContainer ) const
|
||||
{
|
||||
kiapi::board::BoardStackup stackup;
|
||||
|
||||
for( const BOARD_STACKUP_ITEM* item : m_list )
|
||||
{
|
||||
kiapi::board::BoardStackupLayer* layer = stackup.mutable_layers()->Add();
|
||||
|
||||
// TODO dielectric sub-layers
|
||||
layer->mutable_thickness()->set_value_nm( item->GetThickness() );
|
||||
layer->set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
item->GetBrdLayerId() ) );
|
||||
|
||||
switch( item->GetType() )
|
||||
{
|
||||
case BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER:
|
||||
{
|
||||
layer->mutable_copper()->New();
|
||||
// (no copper params yet...)
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aContainer.PackFrom( stackup );
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_STACKUP::Deserialize( const google::protobuf::Any& aContainer )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP::RemoveAll()
|
||||
{
|
||||
for( BOARD_STACKUP_ITEM* item : m_list )
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
#include <layer_ids.h>
|
||||
#include <api/serializable.h>
|
||||
|
||||
class BOARD;
|
||||
class BOARD_DESIGN_SETTINGS;
|
||||
|
@ -213,7 +214,7 @@ private:
|
|||
* @note There are a few other parameters related to the physical stackup like finish type,
|
||||
* impedance control and a few others.
|
||||
*/
|
||||
class BOARD_STACKUP
|
||||
class BOARD_STACKUP : public SERIALIZABLE
|
||||
{
|
||||
public:
|
||||
BOARD_STACKUP();
|
||||
|
@ -225,6 +226,10 @@ public:
|
|||
|
||||
~BOARD_STACKUP() { RemoveAll(); }
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
const std::vector<BOARD_STACKUP_ITEM*>& GetList() const { return m_list; }
|
||||
|
||||
/// @return a reference to the layer aIndex, or nullptr if not exists
|
||||
|
|
|
@ -719,7 +719,7 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
|||
}
|
||||
|
||||
case MAIL_RELOAD_PLUGINS:
|
||||
GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload );
|
||||
GetToolManager()->RunAction( ACTIONS::pluginsReload );
|
||||
break;
|
||||
|
||||
// many many others.
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include <core/mirror.h>
|
||||
#include <confirm.h>
|
||||
|
@ -53,6 +54,12 @@
|
|||
#include <geometry/convex_hull.h>
|
||||
#include "convert_basic_shapes_to_polygon.h"
|
||||
|
||||
#include <google/protobuf/any.pb.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/api_pcb_utils.h>
|
||||
|
||||
|
||||
FOOTPRINT::FOOTPRINT( BOARD* parent ) :
|
||||
BOARD_ITEM_CONTAINER((BOARD_ITEM*) parent, PCB_FOOTPRINT_T ),
|
||||
|
@ -253,6 +260,248 @@ FOOTPRINT::~FOOTPRINT()
|
|||
}
|
||||
|
||||
|
||||
void FOOTPRINT::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::board::types::FootprintInstance footprint;
|
||||
|
||||
footprint.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
footprint.mutable_position()->set_x_nm( GetPosition().x );
|
||||
footprint.mutable_position()->set_y_nm( GetPosition().y );
|
||||
footprint.mutable_orientation()->set_value_degrees( GetOrientationDegrees() );
|
||||
footprint.set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( GetLayer() ) );
|
||||
footprint.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
|
||||
google::protobuf::Any buf;
|
||||
GetField( REFERENCE_FIELD )->Serialize( buf );
|
||||
buf.UnpackTo( footprint.mutable_reference_field() );
|
||||
GetField( VALUE_FIELD )->Serialize( buf );
|
||||
buf.UnpackTo( footprint.mutable_value_field() );
|
||||
GetField( DATASHEET_FIELD )->Serialize( buf );
|
||||
buf.UnpackTo( footprint.mutable_datasheet_field() );
|
||||
GetField( DESCRIPTION_FIELD )->Serialize( buf );
|
||||
buf.UnpackTo( footprint.mutable_description_field() );
|
||||
|
||||
kiapi::board::types::FootprintAttributes* attrs = footprint.mutable_attributes();
|
||||
|
||||
attrs->set_not_in_schematic( IsBoardOnly() );
|
||||
attrs->set_exclude_from_position_files( IsExcludedFromPosFiles() );
|
||||
attrs->set_exclude_from_bill_of_materials( IsExcludedFromBOM() );
|
||||
attrs->set_exempt_from_courtyard_requirement( AllowMissingCourtyard() );
|
||||
attrs->set_do_not_populate( IsDNP() );
|
||||
|
||||
kiapi::board::types::Footprint* def = footprint.mutable_definition();
|
||||
|
||||
def->mutable_id()->CopyFrom( kiapi::common::LibIdToProto( GetFPID() ) );
|
||||
// anchor?
|
||||
def->mutable_attributes()->set_description( GetLibDescription().ToStdString() );
|
||||
def->mutable_attributes()->set_keywords( GetKeywords().ToStdString() );
|
||||
|
||||
// TODO: serialize library mandatory fields
|
||||
|
||||
kiapi::board::types::DesignRuleOverrides* overrides = def->mutable_overrides();
|
||||
|
||||
if( GetLocalClearance().has_value() )
|
||||
overrides->mutable_clearance()->set_value_nm( *GetLocalClearance() );
|
||||
|
||||
if( GetLocalSolderMaskMargin().has_value() )
|
||||
overrides->mutable_solder_mask_margin()->set_value_nm( *GetLocalSolderMaskMargin() );
|
||||
|
||||
if( GetLocalSolderPasteMargin().has_value() )
|
||||
overrides->mutable_solder_paste_margin()->set_value_nm( *GetLocalSolderPasteMargin() );
|
||||
|
||||
if( GetLocalSolderPasteMarginRatio().has_value() )
|
||||
overrides->mutable_solder_paste_margin_ratio()->set_value( *GetLocalSolderPasteMarginRatio() );
|
||||
|
||||
overrides->set_zone_connection(
|
||||
ToProtoEnum<ZONE_CONNECTION,
|
||||
kiapi::board::types::ZoneConnectionStyle>( GetLocalZoneConnection() ) );
|
||||
|
||||
for( const wxString& group : GetNetTiePadGroups() )
|
||||
{
|
||||
kiapi::board::types::NetTieDefinition* netTie = def->add_net_ties();
|
||||
wxStringTokenizer tokenizer( group, " " );
|
||||
|
||||
while( tokenizer.HasMoreTokens() )
|
||||
netTie->add_pad_number( tokenizer.GetNextToken().ToStdString() );
|
||||
}
|
||||
|
||||
for( PCB_LAYER_ID layer : GetPrivateLayers().Seq() )
|
||||
{
|
||||
def->add_private_layers(
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( layer ) );
|
||||
}
|
||||
|
||||
for( const PCB_FIELD* item : Fields() )
|
||||
{
|
||||
if( item->GetId() < MANDATORY_FIELDS )
|
||||
continue;
|
||||
|
||||
google::protobuf::Any* itemMsg = def->add_items();
|
||||
item->Serialize( *itemMsg );
|
||||
}
|
||||
|
||||
for( const PAD* item : Pads() )
|
||||
{
|
||||
google::protobuf::Any* itemMsg = def->add_items();
|
||||
item->Serialize( *itemMsg );
|
||||
}
|
||||
|
||||
for( const BOARD_ITEM* item : GraphicalItems() )
|
||||
{
|
||||
google::protobuf::Any* itemMsg = def->add_items();
|
||||
item->Serialize( *itemMsg );
|
||||
}
|
||||
|
||||
for( const ZONE* item : Zones() )
|
||||
{
|
||||
google::protobuf::Any* itemMsg = def->add_items();
|
||||
item->Serialize( *itemMsg );
|
||||
}
|
||||
|
||||
// TODO: 3D models
|
||||
|
||||
aContainer.PackFrom( footprint );
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::FootprintInstance footprint;
|
||||
|
||||
if( !aContainer.UnpackTo( &footprint ) )
|
||||
return false;
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = KIID( footprint.id().value() );
|
||||
SetPosition( VECTOR2I( footprint.position().x_nm(), footprint.position().y_nm() ) );
|
||||
SetOrientationDegrees( footprint.orientation().value_degrees() );
|
||||
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( footprint.layer() ) );
|
||||
SetLocked( footprint.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
google::protobuf::Any buf;
|
||||
kiapi::board::types::Field mandatoryField;
|
||||
|
||||
if( footprint.has_reference_field() )
|
||||
{
|
||||
mandatoryField = footprint.reference_field();
|
||||
mandatoryField.mutable_id()->set_id( REFERENCE_FIELD );
|
||||
buf.PackFrom( mandatoryField );
|
||||
GetField( REFERENCE_FIELD )->Deserialize( buf );
|
||||
}
|
||||
|
||||
if( footprint.has_value_field() )
|
||||
{
|
||||
mandatoryField = footprint.value_field();
|
||||
mandatoryField.mutable_id()->set_id( VALUE_FIELD );
|
||||
buf.PackFrom( mandatoryField );
|
||||
GetField( VALUE_FIELD )->Deserialize( buf );
|
||||
}
|
||||
|
||||
if( footprint.has_datasheet_field() )
|
||||
{
|
||||
mandatoryField = footprint.datasheet_field();
|
||||
mandatoryField.mutable_id()->set_id( DATASHEET_FIELD );
|
||||
buf.PackFrom( mandatoryField );
|
||||
GetField( DATASHEET_FIELD )->Deserialize( buf );
|
||||
}
|
||||
|
||||
if( footprint.has_description_field() )
|
||||
{
|
||||
mandatoryField = footprint.description_field();
|
||||
mandatoryField.mutable_id()->set_id( DESCRIPTION_FIELD );
|
||||
buf.PackFrom( mandatoryField );
|
||||
GetField( DESCRIPTION_FIELD )->Deserialize( buf );
|
||||
}
|
||||
|
||||
SetBoardOnly( footprint.attributes().not_in_schematic() );
|
||||
SetExcludedFromBOM( footprint.attributes().exclude_from_bill_of_materials() );
|
||||
SetExcludedFromPosFiles( footprint.attributes().exclude_from_position_files() );
|
||||
SetAllowMissingCourtyard( footprint.attributes().exempt_from_courtyard_requirement() );
|
||||
SetDNP( footprint.attributes().do_not_populate() );
|
||||
|
||||
// Definition
|
||||
SetFPID( kiapi::common::LibIdFromProto( footprint.definition().id() ) );
|
||||
// TODO: how should anchor be handled?
|
||||
SetLibDescription( footprint.definition().attributes().description() );
|
||||
SetKeywords( footprint.definition().attributes().keywords() );
|
||||
|
||||
const kiapi::board::types::DesignRuleOverrides& overrides = footprint.overrides();
|
||||
|
||||
if( overrides.has_clearance() )
|
||||
SetLocalClearance( overrides.clearance().value_nm() );
|
||||
else
|
||||
SetLocalClearance( std::nullopt );
|
||||
|
||||
if( overrides.has_solder_mask_margin() )
|
||||
SetLocalSolderMaskMargin( overrides.solder_mask_margin().value_nm() );
|
||||
else
|
||||
SetLocalSolderMaskMargin( std::nullopt );
|
||||
|
||||
if( overrides.has_solder_paste_margin() )
|
||||
SetLocalSolderPasteMargin( overrides.solder_paste_margin().value_nm() );
|
||||
else
|
||||
SetLocalSolderPasteMargin( std::nullopt );
|
||||
|
||||
if( overrides.has_solder_paste_margin_ratio() )
|
||||
SetLocalSolderPasteMarginRatio( overrides.solder_paste_margin_ratio().value() );
|
||||
else
|
||||
SetLocalSolderPasteMarginRatio( std::nullopt );
|
||||
|
||||
SetLocalZoneConnection( FromProtoEnum<ZONE_CONNECTION>( overrides.zone_connection() ) );
|
||||
|
||||
for( const kiapi::board::types::NetTieDefinition& netTieMsg : footprint.definition().net_ties() )
|
||||
{
|
||||
wxString group;
|
||||
|
||||
for( const std::string& pad : netTieMsg.pad_number() )
|
||||
group.Append( wxString::Format( wxT( "%s " ), pad ) );
|
||||
|
||||
group.Trim();
|
||||
AddNetTiePadGroup( group );
|
||||
}
|
||||
|
||||
LSET privateLayers;
|
||||
|
||||
for( int layerMsg : footprint.definition().private_layers() )
|
||||
{
|
||||
auto layer = static_cast<kiapi::board::types::BoardLayer>( layerMsg );
|
||||
privateLayers.set( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( layer ) );
|
||||
}
|
||||
|
||||
SetPrivateLayers( privateLayers );
|
||||
|
||||
// Footprint items
|
||||
for( PCB_FIELD* field : Fields() )
|
||||
{
|
||||
if( field->GetId() >= MANDATORY_FIELDS )
|
||||
Remove( field );
|
||||
}
|
||||
|
||||
Pads().clear();
|
||||
GraphicalItems().clear();
|
||||
Zones().clear();
|
||||
Groups().clear();
|
||||
Models().clear();
|
||||
|
||||
for( const google::protobuf::Any& itemMsg : footprint.definition().items() )
|
||||
{
|
||||
std::optional<KICAD_T> type = kiapi::common::TypeNameFromAny( itemMsg );
|
||||
|
||||
if( !type )
|
||||
continue;
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> item = CreateItemForType( *type, this );
|
||||
|
||||
if( item && item->Deserialize( itemMsg ) )
|
||||
Add( item.release(), ADD_MODE::APPEND );
|
||||
}
|
||||
|
||||
// TODO: 3D models
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PCB_FIELD* FOOTPRINT::GetField( MANDATORY_FIELD_T aFieldType )
|
||||
{
|
||||
return m_fields[aFieldType];
|
||||
|
|
|
@ -117,6 +117,9 @@ public:
|
|||
FOOTPRINT& operator=( const FOOTPRINT& aOther );
|
||||
FOOTPRINT& operator=( FOOTPRINT&& aOther );
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||
{
|
||||
return aItem && aItem->Type() == PCB_FOOTPRINT_T;
|
||||
|
|
|
@ -1151,9 +1151,9 @@ void FOOTPRINT_EDIT_FRAME::setupTools()
|
|||
PCB_EDIT_FRAME* pcbframe = static_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
|
||||
|
||||
if( pcbframe )
|
||||
pcbframe->GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload );
|
||||
pcbframe->GetToolManager()->RunAction( ACTIONS::pluginsReload );
|
||||
else
|
||||
m_toolManager->RunAction( PCB_ACTIONS::pluginsReload );
|
||||
m_toolManager->RunAction( ACTIONS::pluginsReload );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -643,7 +643,7 @@ void FOOTPRINT_WIZARD_FRAME::PythonPluginsReload()
|
|||
PCB_EDIT_FRAME* pcbframe = static_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
|
||||
|
||||
if( pcbframe )
|
||||
pcbframe->GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload );
|
||||
pcbframe->GetToolManager()->RunAction( ACTIONS::pluginsReload );
|
||||
else
|
||||
GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload );
|
||||
GetToolManager()->RunAction( ACTIONS::pluginsReload );
|
||||
}
|
||||
|
|
|
@ -436,7 +436,7 @@ void PCB_EDIT_FRAME::doReCreateMenuBar()
|
|||
submenuActionPlugins->SetTitle( _( "External Plugins" ) );
|
||||
submenuActionPlugins->SetIcon( BITMAPS::puzzle_piece );
|
||||
|
||||
submenuActionPlugins->Add( PCB_ACTIONS::pluginsReload );
|
||||
submenuActionPlugins->Add( ACTIONS::pluginsReload );
|
||||
submenuActionPlugins->Add( PCB_ACTIONS::pluginsShowFolder );
|
||||
|
||||
// Populate the Action Plugin sub-menu: Must be done before Add
|
||||
|
|
158
pcbnew/pad.cpp
158
pcbnew/pad.cpp
|
@ -50,6 +50,10 @@
|
|||
#include <pcb_painter.h>
|
||||
#include <properties/property_validators.h>
|
||||
#include <wx/log.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/api_pcb_utils.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
|
||||
#include <memory>
|
||||
#include <macros.h>
|
||||
|
@ -135,6 +139,160 @@ PAD& PAD::operator=( const PAD &aOther )
|
|||
}
|
||||
|
||||
|
||||
void PAD::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::board::types::Pad pad;
|
||||
|
||||
pad.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
kiapi::common::PackVector2( *pad.mutable_position(), GetPosition() );
|
||||
pad.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
pad.mutable_net()->mutable_code()->set_value( GetNetCode() );
|
||||
pad.mutable_net()->set_name( GetNetname() );
|
||||
|
||||
kiapi::board::types::PadStack* padstack = pad.mutable_pad_stack();
|
||||
padstack->set_type( kiapi::board::types::PadStackType::PST_THROUGH );
|
||||
padstack->set_start_layer(
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( m_layer ) );
|
||||
padstack->set_end_layer(
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( FlipLayer( m_layer ) ) );
|
||||
kiapi::common::PackVector2( *padstack->mutable_drill_diameter(),
|
||||
{ GetDrillSizeX(), GetDrillSizeY() } );
|
||||
padstack->mutable_angle()->set_value_degrees( GetOrientationDegrees() );
|
||||
|
||||
kiapi::board::types::PadStackLayer* stackLayer = padstack->add_layers();
|
||||
kiapi::board::PackLayerSet( *stackLayer->mutable_layers(), GetLayerSet() );
|
||||
kiapi::common::PackVector2( *stackLayer->mutable_size(),
|
||||
{ GetSizeX(), GetSizeY() } );
|
||||
stackLayer->set_shape(
|
||||
ToProtoEnum<PAD_SHAPE, kiapi::board::types::PadStackShape>( GetShape() ) );
|
||||
|
||||
kiapi::board::types::UnconnectedLayerRemoval ulr;
|
||||
|
||||
if( m_removeUnconnectedLayer )
|
||||
{
|
||||
if( m_keepTopBottomLayer )
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END;
|
||||
else
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP;
|
||||
}
|
||||
|
||||
padstack->set_unconnected_layer_removal( ulr );
|
||||
|
||||
kiapi::board::types::DesignRuleOverrides* overrides = pad.mutable_overrides();
|
||||
|
||||
if( GetLocalClearance().has_value() )
|
||||
overrides->mutable_clearance()->set_value_nm( *GetLocalClearance() );
|
||||
|
||||
if( GetLocalSolderMaskMargin().has_value() )
|
||||
overrides->mutable_solder_mask_margin()->set_value_nm( *GetLocalSolderMaskMargin() );
|
||||
|
||||
if( GetLocalSolderPasteMargin().has_value() )
|
||||
overrides->mutable_solder_paste_margin()->set_value_nm( *GetLocalSolderPasteMargin() );
|
||||
|
||||
if( GetLocalSolderPasteMarginRatio().has_value() )
|
||||
overrides->mutable_solder_paste_margin_ratio()->set_value( *GetLocalSolderPasteMarginRatio() );
|
||||
|
||||
overrides->set_zone_connection(
|
||||
ToProtoEnum<ZONE_CONNECTION,
|
||||
kiapi::board::types::ZoneConnectionStyle>( GetLocalZoneConnection() ) );
|
||||
|
||||
kiapi::board::types::ThermalSpokeSettings* thermals = pad.mutable_thermal_spokes();
|
||||
|
||||
thermals->set_width( GetThermalSpokeWidth() );
|
||||
thermals->set_gap( GetThermalGap() );
|
||||
thermals->mutable_angle()->set_value_degrees( GetThermalSpokeAngleDegrees() );
|
||||
|
||||
aContainer.PackFrom( pad );
|
||||
}
|
||||
|
||||
|
||||
bool PAD::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::Pad pad;
|
||||
|
||||
if( !aContainer.UnpackTo( &pad ) )
|
||||
return false;
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = KIID( pad.id().value() );
|
||||
SetPosition( kiapi::common::UnpackVector2( pad.position() ) );
|
||||
SetNetCode( pad.net().code().value() );
|
||||
SetLocked( pad.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
const kiapi::board::types::PadStack& padstack = pad.pad_stack();
|
||||
|
||||
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
padstack.start_layer() ) );
|
||||
|
||||
SetDrillSize( kiapi::common::UnpackVector2( padstack.drill_diameter() ) );
|
||||
SetOrientationDegrees( padstack.angle().value_degrees() );
|
||||
|
||||
// We don't yet support complex padstacks
|
||||
if( padstack.layers_size() == 1 )
|
||||
{
|
||||
const kiapi::board::types::PadStackLayer& layer = padstack.layers( 0 );
|
||||
SetSize( kiapi::common::UnpackVector2( layer.size() ) );
|
||||
SetLayerSet( kiapi::board::UnpackLayerSet( layer.layers() ) );
|
||||
SetShape( FromProtoEnum<PAD_SHAPE>( layer.shape() ) );
|
||||
}
|
||||
|
||||
switch( padstack.unconnected_layer_removal() )
|
||||
{
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepTopBottomLayer = false;
|
||||
break;
|
||||
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepTopBottomLayer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP:
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepTopBottomLayer = false;
|
||||
break;
|
||||
}
|
||||
|
||||
const kiapi::board::types::DesignRuleOverrides& overrides = pad.overrides();
|
||||
|
||||
if( overrides.has_clearance() )
|
||||
SetLocalClearance( overrides.clearance().value_nm() );
|
||||
else
|
||||
SetLocalClearance( std::nullopt );
|
||||
|
||||
if( overrides.has_solder_mask_margin() )
|
||||
SetLocalSolderMaskMargin( overrides.solder_mask_margin().value_nm() );
|
||||
else
|
||||
SetLocalSolderMaskMargin( std::nullopt );
|
||||
|
||||
if( overrides.has_solder_paste_margin() )
|
||||
SetLocalSolderPasteMargin( overrides.solder_paste_margin().value_nm() );
|
||||
else
|
||||
SetLocalSolderPasteMargin( std::nullopt );
|
||||
|
||||
if( overrides.has_solder_paste_margin_ratio() )
|
||||
SetLocalSolderPasteMarginRatio( overrides.solder_paste_margin_ratio().value() );
|
||||
else
|
||||
SetLocalSolderPasteMarginRatio( std::nullopt );
|
||||
|
||||
SetLocalZoneConnection( FromProtoEnum<ZONE_CONNECTION>( overrides.zone_connection() ) );
|
||||
|
||||
const kiapi::board::types::ThermalSpokeSettings& thermals = pad.thermal_spokes();
|
||||
|
||||
SetThermalGap( thermals.gap() );
|
||||
SetThermalSpokeWidth( thermals.width() );
|
||||
SetThermalSpokeAngleDegrees( thermals.angle().value_degrees() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PAD::CanHaveNumber() const
|
||||
{
|
||||
// Aperture pads don't get a number
|
||||
|
|
|
@ -65,6 +65,9 @@ public:
|
|||
PAD( const PAD& aPad );
|
||||
PAD& operator=( const PAD &aOther );
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
/*
|
||||
* Default layers used for pads, according to the pad type.
|
||||
*
|
||||
|
|
|
@ -266,6 +266,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
ReCreateVToolbar();
|
||||
ReCreateOptToolbar();
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
wxTheApp->Bind( EDA_EVT_PLUGIN_AVAILABILITY_CHANGED,
|
||||
[&]( wxCommandEvent& aEvt )
|
||||
{
|
||||
|
@ -273,7 +274,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
ReCreateHToolbar();
|
||||
aEvt.Skip();
|
||||
} );
|
||||
|
||||
#endif
|
||||
|
||||
m_propertiesPanel = new PCB_PROPERTIES_PANEL( this, this );
|
||||
|
||||
|
@ -438,7 +439,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
PythonSyncProjectName();
|
||||
|
||||
// Sync action plugins in case they changed since the last time the frame opened
|
||||
GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload );
|
||||
GetToolManager()->RunAction( ACTIONS::pluginsReload );
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_apiHandler = std::make_unique<API_HANDLER_PCB>( this );
|
||||
|
@ -2062,24 +2063,6 @@ void PCB_EDIT_FRAME::PythonSyncProjectName()
|
|||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::OnApiPluginMenu( wxCommandEvent& aEvent )
|
||||
{
|
||||
API_PLUGIN_MANAGER& mgr = Pgm().GetPluginManager();
|
||||
|
||||
if( mgr.MenuBindings().count( aEvent.GetId() ) )
|
||||
mgr.InvokeAction( mgr.MenuBindings().at( aEvent.GetId() ) );
|
||||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::OnApiPluginButton( wxCommandEvent& aEvent )
|
||||
{
|
||||
API_PLUGIN_MANAGER& mgr = Pgm().GetPluginManager();
|
||||
|
||||
if( mgr.ButtonBindings().count( aEvent.GetId() ) )
|
||||
mgr.InvokeAction( mgr.ButtonBindings().at( aEvent.GetId() ) );
|
||||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::ShowFootprintPropertiesDialog( FOOTPRINT* aFootprint )
|
||||
{
|
||||
if( aFootprint == nullptr )
|
||||
|
@ -2496,6 +2479,26 @@ void PCB_EDIT_FRAME::ProjectChanged()
|
|||
}
|
||||
|
||||
|
||||
bool PCB_EDIT_FRAME::CanAcceptApiCommands()
|
||||
{
|
||||
// For now, be conservative: Don't allow any API use while the user is changing things
|
||||
if( GetToolManager()->GetCurrentTool() != GetToolManager()->GetTool<PCB_SELECTION_TOOL>() )
|
||||
return false;
|
||||
|
||||
ZONE_FILLER_TOOL* zoneFillerTool = m_toolManager->GetTool<ZONE_FILLER_TOOL>();
|
||||
|
||||
if( zoneFillerTool->IsBusy() )
|
||||
return false;
|
||||
|
||||
ROUTER_TOOL* routerTool = m_toolManager->GetTool<ROUTER_TOOL>();
|
||||
|
||||
if( routerTool->RoutingInProgress() )
|
||||
return false;
|
||||
|
||||
return EDA_BASE_FRAME::CanAcceptApiCommands();
|
||||
}
|
||||
|
||||
|
||||
bool ExportBoardToHyperlynx( BOARD* aBoard, const wxFileName& aPath );
|
||||
|
||||
|
||||
|
|
|
@ -699,6 +699,8 @@ public:
|
|||
|
||||
void ProjectChanged() override;
|
||||
|
||||
bool CanAcceptApiCommands() override;
|
||||
|
||||
wxString GetCurrentFileName() const override;
|
||||
|
||||
SELECTION& GetCurrentSelection() override;
|
||||
|
@ -760,11 +762,6 @@ protected:
|
|||
*/
|
||||
void AddActionPluginTools();
|
||||
|
||||
/**
|
||||
* Append actions from API plugins to the main toolbar
|
||||
*/
|
||||
void AddApiPluginTools();
|
||||
|
||||
/**
|
||||
* Execute action plugin's Run() method and updates undo buffer.
|
||||
*
|
||||
|
@ -786,8 +783,7 @@ protected:
|
|||
*/
|
||||
void OnActionPluginButton( wxCommandEvent& aEvent );
|
||||
|
||||
void OnApiPluginMenu( wxCommandEvent& aEvent );
|
||||
void OnApiPluginButton( wxCommandEvent& aEvent );
|
||||
PLUGIN_ACTION_SCOPE PluginActionScope() const override { return PLUGIN_ACTION_SCOPE::PCB; }
|
||||
|
||||
/**
|
||||
* Update the state of the GUI after a new board is loaded or created.
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <board_design_settings.h>
|
||||
#include <i18n_utility.h>
|
||||
#include <pcb_painter.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
|
||||
|
||||
PCB_FIELD::PCB_FIELD( FOOTPRINT* aParent, int aFieldId, const wxString& aName ) :
|
||||
PCB_TEXT( aParent, PCB_FIELD_T ),
|
||||
|
@ -44,6 +46,49 @@ PCB_FIELD::PCB_FIELD( const PCB_TEXT& aText, int aFieldId, const wxString& aName
|
|||
}
|
||||
|
||||
|
||||
void PCB_FIELD::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::board::types::Field field;
|
||||
|
||||
google::protobuf::Any anyText;
|
||||
PCB_TEXT::Serialize( anyText );
|
||||
anyText.UnpackTo( field.mutable_text() );
|
||||
|
||||
field.set_name( GetCanonicalName().ToStdString() );
|
||||
field.mutable_id()->set_id( GetId() );
|
||||
|
||||
aContainer.PackFrom( field );
|
||||
}
|
||||
|
||||
|
||||
bool PCB_FIELD::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::Field field;
|
||||
|
||||
if( !aContainer.UnpackTo( &field ) )
|
||||
return false;
|
||||
|
||||
if( field.has_id() )
|
||||
setId( field.id().id() );
|
||||
|
||||
// Mandatory fields have a blank Name in the KiCad object
|
||||
if( m_id >= MANDATORY_FIELDS )
|
||||
SetName( wxString( field.name().c_str(), wxConvUTF8 ) );
|
||||
|
||||
if( field.has_text() )
|
||||
{
|
||||
google::protobuf::Any anyText;
|
||||
anyText.PackFrom( field.text() );
|
||||
PCB_TEXT::Deserialize( anyText );
|
||||
}
|
||||
|
||||
if( field.text().layer() == kiapi::board::types::BoardLayer::BL_UNKNOWN )
|
||||
SetLayer( F_SilkS );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
wxString PCB_FIELD::GetName( bool aUseDefaultName ) const
|
||||
{
|
||||
if( m_parent && m_parent->Type() == PCB_FOOTPRINT_T )
|
||||
|
|
|
@ -37,6 +37,9 @@ public:
|
|||
|
||||
PCB_FIELD( const PCB_TEXT& aText, int aFieldId, const wxString& aName = wxEmptyString );
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||
{
|
||||
return aItem && PCB_FIELD_T == aItem->Type();
|
||||
|
@ -114,6 +117,8 @@ protected:
|
|||
void swapData( BOARD_ITEM* aImage ) override;
|
||||
|
||||
private:
|
||||
void setId( int aId ) { m_id = aId; }
|
||||
|
||||
int m_id; ///< Field index, @see enum MANDATORY_FIELD_T
|
||||
|
||||
wxString m_name;
|
||||
|
|
|
@ -1944,6 +1944,9 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
|
|||
}
|
||||
|
||||
break;
|
||||
|
||||
case SHAPE_T::UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <google/protobuf/any.pb.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include <bitmaps.h>
|
||||
#include <core/mirror.h>
|
||||
#include <macros.h>
|
||||
|
@ -35,6 +38,10 @@
|
|||
#include <geometry/shape_compound.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <pcb_painter.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
|
||||
|
||||
PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T aItemType, SHAPE_T aShapeType ) :
|
||||
BOARD_CONNECTED_ITEM( aParent, aItemType ),
|
||||
|
@ -54,6 +61,270 @@ PCB_SHAPE::~PCB_SHAPE()
|
|||
{
|
||||
}
|
||||
|
||||
// TODO: lift out
|
||||
kiapi::common::types::PolyLine lineChainToProto( const SHAPE_LINE_CHAIN& aSlc )
|
||||
{
|
||||
kiapi::common::types::PolyLine msg;
|
||||
|
||||
for( int vertex = 0; vertex < aSlc.PointCount(); vertex = aSlc.NextShape( vertex ) )
|
||||
{
|
||||
kiapi::common::types::PolyLineNode* node = msg.mutable_nodes()->Add();
|
||||
|
||||
if( aSlc.IsPtOnArc( vertex ) )
|
||||
{
|
||||
const SHAPE_ARC& arc = aSlc.Arc( aSlc.ArcIndex( vertex ) );
|
||||
node->mutable_arc()->mutable_start()->set_x_nm( arc.GetP0().x );
|
||||
node->mutable_arc()->mutable_start()->set_y_nm( arc.GetP0().y );
|
||||
node->mutable_arc()->mutable_mid()->set_x_nm( arc.GetArcMid().x );
|
||||
node->mutable_arc()->mutable_mid()->set_y_nm( arc.GetArcMid().y );
|
||||
node->mutable_arc()->mutable_end()->set_x_nm( arc.GetP1().x );
|
||||
node->mutable_arc()->mutable_end()->set_y_nm( arc.GetP1().y );
|
||||
}
|
||||
else
|
||||
{
|
||||
node->mutable_point()->set_x_nm( aSlc.CPoint( vertex ).x );
|
||||
node->mutable_point()->set_y_nm( aSlc.CPoint( vertex ).y );
|
||||
}
|
||||
}
|
||||
|
||||
msg.set_closed( aSlc.IsClosed() );
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
void PCB_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::board::types::GraphicShape msg;
|
||||
|
||||
msg.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
msg.set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( GetLayer() ) );
|
||||
msg.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
msg.mutable_net()->mutable_code()->set_value( GetNetCode() );
|
||||
msg.mutable_net()->set_name( GetNetname() );
|
||||
|
||||
kiapi::common::types::StrokeAttributes* stroke
|
||||
= msg.mutable_attributes()->mutable_stroke();
|
||||
kiapi::common::types::GraphicFillAttributes* fill = msg.mutable_attributes()->mutable_fill();
|
||||
|
||||
stroke->mutable_width()->set_value_nm( GetWidth() );
|
||||
|
||||
switch( GetLineStyle() )
|
||||
{
|
||||
case LINE_STYLE::DEFAULT: stroke->set_style( kiapi::common::types::SLS_DEFAULT ); break;
|
||||
case LINE_STYLE::SOLID: stroke->set_style( kiapi::common::types::SLS_SOLID ); break;
|
||||
case LINE_STYLE::DASH: stroke->set_style( kiapi::common::types::SLS_DASH ); break;
|
||||
case LINE_STYLE::DOT: stroke->set_style( kiapi::common::types::SLS_DOT ); break;
|
||||
case LINE_STYLE::DASHDOT: stroke->set_style( kiapi::common::types::SLS_DASHDOT ); break;
|
||||
case LINE_STYLE::DASHDOTDOT: stroke->set_style( kiapi::common::types::SLS_DASHDOTDOT ); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch( GetFillMode() )
|
||||
{
|
||||
case FILL_T::FILLED_SHAPE: fill->set_fill_type( kiapi::common::types::GFT_FILLED ); break;
|
||||
default: fill->set_fill_type( kiapi::common::types::GFT_UNFILLED ); break;
|
||||
}
|
||||
|
||||
switch( GetShape() )
|
||||
{
|
||||
case SHAPE_T::SEGMENT:
|
||||
{
|
||||
kiapi::board::types::GraphicSegmentAttributes* segment = msg.mutable_segment();
|
||||
kiapi::common::PackVector2( *segment->mutable_start(), GetStart() );
|
||||
kiapi::common::PackVector2( *segment->mutable_end(), GetEnd() );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::RECTANGLE:
|
||||
{
|
||||
kiapi::board::types::GraphicRectangleAttributes* rectangle = msg.mutable_rectangle();
|
||||
kiapi::common::PackVector2( *rectangle->mutable_top_left(), GetStart() );
|
||||
kiapi::common::PackVector2( *rectangle->mutable_bottom_right(), GetEnd() );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
kiapi::board::types::GraphicArcAttributes* arc = msg.mutable_arc();
|
||||
kiapi::common::PackVector2( *arc->mutable_start(), GetStart() );
|
||||
kiapi::common::PackVector2( *arc->mutable_mid(), GetArcMid() );
|
||||
kiapi::common::PackVector2( *arc->mutable_end(), GetEnd() );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::CIRCLE:
|
||||
{
|
||||
kiapi::board::types::GraphicCircleAttributes* circle = msg.mutable_circle();
|
||||
kiapi::common::PackVector2( *circle->mutable_center(), GetStart() );
|
||||
kiapi::common::PackVector2( *circle->mutable_radius_point(), GetEnd() );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
{
|
||||
kiapi::common::types::PolySet* polyset = msg.mutable_polygon();
|
||||
|
||||
for( int idx = 0; idx < GetPolyShape().OutlineCount(); ++idx )
|
||||
{
|
||||
const SHAPE_POLY_SET::POLYGON& poly = GetPolyShape().Polygon( idx );
|
||||
|
||||
if( poly.empty() )
|
||||
continue;
|
||||
|
||||
kiapi::common::types::PolygonWithHoles* polyMsg = polyset->mutable_polygons()->Add();
|
||||
polyMsg->mutable_outline()->CopyFrom( lineChainToProto( poly.front() ) );
|
||||
|
||||
if( poly.size() > 1 )
|
||||
{
|
||||
for( size_t hole = 1; hole < poly.size(); ++hole )
|
||||
polyMsg->mutable_holes()->Add( lineChainToProto( poly[hole] ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
{
|
||||
kiapi::board::types::GraphicBezierAttributes* bezier = msg.mutable_bezier();
|
||||
kiapi::common::PackVector2( *bezier->mutable_start(), GetStart() );
|
||||
kiapi::common::PackVector2( *bezier->mutable_control1(), GetBezierC1() );
|
||||
kiapi::common::PackVector2( *bezier->mutable_control2(), GetBezierC2() );
|
||||
kiapi::common::PackVector2( *bezier->mutable_end(), GetEnd() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxASSERT_MSG( false, "Unhandled shape in PCB_SHAPE::Serialize" );
|
||||
}
|
||||
|
||||
aContainer.PackFrom( msg );
|
||||
}
|
||||
|
||||
|
||||
// TODO(JE) lift out
|
||||
SHAPE_LINE_CHAIN lineChainFromProto( const kiapi::common::types::PolyLine& aProto )
|
||||
{
|
||||
SHAPE_LINE_CHAIN slc;
|
||||
|
||||
for( const kiapi::common::types::PolyLineNode& node : aProto.nodes() )
|
||||
{
|
||||
if( node.has_point() )
|
||||
{
|
||||
slc.Append( VECTOR2I( node.point().x_nm(), node.point().y_nm() ) );
|
||||
}
|
||||
else if( node.has_arc() )
|
||||
{
|
||||
slc.Append( SHAPE_ARC( VECTOR2I( node.arc().start().x_nm(), node.arc().start().y_nm() ),
|
||||
VECTOR2I( node.arc().mid().x_nm(), node.arc().mid().y_nm() ),
|
||||
VECTOR2I( node.arc().end().x_nm(), node.arc().end().y_nm() ),
|
||||
0 /* don't care about width here */ ) );
|
||||
}
|
||||
}
|
||||
|
||||
slc.SetClosed( aProto.closed() );
|
||||
|
||||
return slc;
|
||||
}
|
||||
|
||||
|
||||
bool PCB_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::GraphicShape msg;
|
||||
|
||||
if( !aContainer.UnpackTo( &msg ) )
|
||||
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;
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = KIID( msg.id().value() );
|
||||
SetLocked( msg.locked() == kiapi::common::types::LS_LOCKED );
|
||||
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( msg.layer() ) );
|
||||
SetNetCode( msg.net().code().value() );
|
||||
|
||||
SetFilled( msg.attributes().fill().fill_type() == kiapi::common::types::GFT_FILLED );
|
||||
SetWidth( msg.attributes().stroke().width().value_nm() );
|
||||
|
||||
switch( msg.attributes().stroke().style() )
|
||||
{
|
||||
case kiapi::common::types::SLS_DEFAULT: SetLineStyle( LINE_STYLE::DEFAULT ); break;
|
||||
case kiapi::common::types::SLS_SOLID: SetLineStyle( LINE_STYLE::SOLID ); break;
|
||||
case kiapi::common::types::SLS_DASH: SetLineStyle( LINE_STYLE::DASH ); break;
|
||||
case kiapi::common::types::SLS_DOT: SetLineStyle( LINE_STYLE::DOT ); break;
|
||||
case kiapi::common::types::SLS_DASHDOT: SetLineStyle( LINE_STYLE::DASHDOT ); break;
|
||||
case kiapi::common::types::SLS_DASHDOTDOT: SetLineStyle( LINE_STYLE::DASHDOTDOT ); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if( msg.has_segment() )
|
||||
{
|
||||
SetShape( SHAPE_T::SEGMENT );
|
||||
SetStart( kiapi::common::UnpackVector2( msg.segment().start() ) );
|
||||
SetEnd( kiapi::common::UnpackVector2( msg.segment().end() ) );
|
||||
}
|
||||
else if( msg.has_rectangle() )
|
||||
{
|
||||
SetShape( SHAPE_T::RECTANGLE );
|
||||
SetStart( kiapi::common::UnpackVector2( msg.rectangle().top_left() ) );
|
||||
SetEnd( kiapi::common::UnpackVector2( msg.rectangle().bottom_right() ) );
|
||||
}
|
||||
else if( msg.has_arc() )
|
||||
{
|
||||
SetShape( SHAPE_T::ARC );
|
||||
SetArcGeometry( kiapi::common::UnpackVector2( msg.arc().start() ),
|
||||
kiapi::common::UnpackVector2( msg.arc().mid() ),
|
||||
kiapi::common::UnpackVector2( msg.arc().end() ) );
|
||||
}
|
||||
else if( msg.has_circle() )
|
||||
{
|
||||
SetShape( SHAPE_T::CIRCLE );
|
||||
SetStart( kiapi::common::UnpackVector2( msg.circle().center() ) );
|
||||
SetEnd( kiapi::common::UnpackVector2( msg.circle().radius_point() ) );
|
||||
}
|
||||
else if( msg.has_polygon() )
|
||||
{
|
||||
SetShape( SHAPE_T::POLY );
|
||||
const auto& polyMsg = msg.polygon().polygons();
|
||||
|
||||
SHAPE_POLY_SET sps;
|
||||
|
||||
for( const kiapi::common::types::PolygonWithHoles& polygonWithHoles : polyMsg )
|
||||
{
|
||||
SHAPE_POLY_SET::POLYGON polygon;
|
||||
|
||||
polygon.emplace_back( lineChainFromProto( polygonWithHoles.outline() ) );
|
||||
|
||||
for( const kiapi::common::types::PolyLine& holeMsg : polygonWithHoles.holes() )
|
||||
polygon.emplace_back( lineChainFromProto( holeMsg ) );
|
||||
|
||||
sps.AddPolygon( polygon );
|
||||
}
|
||||
|
||||
SetPolyShape( sps );
|
||||
}
|
||||
else if( msg.has_bezier() )
|
||||
{
|
||||
SetShape( SHAPE_T::BEZIER );
|
||||
SetStart( kiapi::common::UnpackVector2( msg.bezier().start() ) );
|
||||
SetBezierC1( kiapi::common::UnpackVector2( msg.bezier().control1() ) );
|
||||
SetBezierC2( kiapi::common::UnpackVector2( msg.bezier().control2() ) );
|
||||
SetEnd( kiapi::common::UnpackVector2( msg.bezier().end() ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PCB_SHAPE::IsType( const std::vector<KICAD_T>& aScanTypes ) const
|
||||
{
|
||||
|
|
|
@ -57,6 +57,9 @@ public:
|
|||
return wxT( "PCB_SHAPE" );
|
||||
}
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
bool IsConnected() const override;
|
||||
|
||||
wxString GetFriendlyName() const override { return EDA_SHAPE::GetFriendlyName(); }
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <google/protobuf/any.pb.h>
|
||||
|
||||
#include <pcb_edit_frame.h>
|
||||
#include <base_units.h>
|
||||
#include <bitmaps.h>
|
||||
|
@ -37,6 +39,12 @@
|
|||
#include <geometry/shape_compound.h>
|
||||
#include <callback_gal.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
|
||||
|
||||
using namespace kiapi::common;
|
||||
|
||||
|
||||
PCB_TEXT::PCB_TEXT( BOARD_ITEM* parent, KICAD_T idtype ) :
|
||||
|
@ -75,6 +83,106 @@ PCB_TEXT::~PCB_TEXT()
|
|||
}
|
||||
|
||||
|
||||
void PCB_TEXT::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::board::types::Text boardText;
|
||||
boardText.set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( GetLayer() ) );
|
||||
|
||||
kiapi::common::types::Text& text = *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 );
|
||||
|
||||
kiapi::common::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 );
|
||||
|
||||
text.set_knockout( IsKnockout() );
|
||||
|
||||
aContainer.PackFrom( boardText );
|
||||
}
|
||||
|
||||
|
||||
bool PCB_TEXT::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::Text textWrapper;
|
||||
|
||||
if( !aContainer.UnpackTo( &textWrapper ) )
|
||||
return false;
|
||||
|
||||
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( textWrapper.layer() ) );
|
||||
|
||||
const kiapi::common::types::Text& text = textWrapper.text();
|
||||
|
||||
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() );
|
||||
|
||||
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();
|
||||
SetTextThickness( 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;
|
||||
}
|
||||
|
||||
|
||||
wxString PCB_TEXT::GetShownText( bool aAllowExtraText, int aDepth ) const
|
||||
{
|
||||
const FOOTPRINT* parentFootprint = GetParentFootprint();
|
||||
|
|
|
@ -65,6 +65,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
void StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings ) override;
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include <pcb_base_frame.h>
|
||||
#include <core/mirror.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
|
@ -46,6 +44,9 @@
|
|||
#include <trigo.h>
|
||||
|
||||
#include <google/protobuf/any.pb.h>
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/api_pcb_utils.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
|
||||
using KIGFX::PCB_PAINTER;
|
||||
|
@ -296,15 +297,15 @@ void PCB_TRACK::Serialize( google::protobuf::Any &aContainer ) const
|
|||
kiapi::board::types::Track track;
|
||||
|
||||
track.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
track.mutable_start()->set_x_nm( GetPosition().x );
|
||||
track.mutable_start()->set_y_nm( GetPosition().y );
|
||||
track.mutable_start()->set_x_nm( GetStart().x );
|
||||
track.mutable_start()->set_y_nm( GetStart().y );
|
||||
track.mutable_end()->set_x_nm( GetEnd().x );
|
||||
track.mutable_end()->set_y_nm( GetEnd().y );
|
||||
track.mutable_width()->set_value_nm( GetWidth() );
|
||||
track.mutable_layer()->set_layer_id( GetLayer() );
|
||||
track.set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( GetLayer() ) );
|
||||
track.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
track.mutable_net()->set_code( GetNetCode() );
|
||||
track.mutable_net()->mutable_code()->set_value( GetNetCode() );
|
||||
track.mutable_net()->set_name( GetNetname() );
|
||||
|
||||
aContainer.PackFrom( track );
|
||||
|
@ -322,8 +323,8 @@ bool PCB_TRACK::Deserialize( const google::protobuf::Any &aContainer )
|
|||
SetStart( VECTOR2I( track.start().x_nm(), track.start().y_nm() ) );
|
||||
SetEnd( VECTOR2I( track.end().x_nm(), track.end().y_nm() ) );
|
||||
SetWidth( track.width().value_nm() );
|
||||
SetLayer( magic_enum::enum_cast<PCB_LAYER_ID>( track.layer().layer_id() ).value_or( F_Cu ) );
|
||||
SetNetCode( track.net().code() );
|
||||
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( track.layer() ) );
|
||||
SetNetCode( track.net().code().value() );
|
||||
SetLocked( track.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
return true;
|
||||
|
@ -335,17 +336,17 @@ void PCB_ARC::Serialize( google::protobuf::Any &aContainer ) const
|
|||
kiapi::board::types::Arc arc;
|
||||
|
||||
arc.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
arc.mutable_start()->set_x_nm( GetPosition().x );
|
||||
arc.mutable_start()->set_y_nm( GetPosition().y );
|
||||
arc.mutable_start()->set_x_nm( GetStart().x );
|
||||
arc.mutable_start()->set_y_nm( GetStart().y );
|
||||
arc.mutable_mid()->set_x_nm( GetMid().x );
|
||||
arc.mutable_mid()->set_y_nm( GetMid().y );
|
||||
arc.mutable_end()->set_x_nm( GetEnd().x );
|
||||
arc.mutable_end()->set_y_nm( GetEnd().y );
|
||||
arc.mutable_width()->set_value_nm( GetWidth() );
|
||||
arc.mutable_layer()->set_layer_id( GetLayer() );
|
||||
arc.set_layer( ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( GetLayer() ) );
|
||||
arc.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
arc.mutable_net()->set_code( GetNetCode() );
|
||||
arc.mutable_net()->mutable_code()->set_value( GetNetCode() );
|
||||
arc.mutable_net()->set_name( GetNetname() );
|
||||
|
||||
aContainer.PackFrom( arc );
|
||||
|
@ -364,8 +365,8 @@ bool PCB_ARC::Deserialize( const google::protobuf::Any &aContainer )
|
|||
SetMid( VECTOR2I( arc.mid().x_nm(), arc.mid().y_nm() ) );
|
||||
SetEnd( VECTOR2I( arc.end().x_nm(), arc.end().y_nm() ) );
|
||||
SetWidth( arc.width().value_nm() );
|
||||
SetLayer( magic_enum::enum_cast<PCB_LAYER_ID>( arc.layer().layer_id() ).value_or( F_Cu ) );
|
||||
SetNetCode( arc.net().code() );
|
||||
SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( arc.layer() ) );
|
||||
SetNetCode( arc.net().code().value() );
|
||||
SetLocked( arc.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
return true;
|
||||
|
@ -379,15 +380,22 @@ void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
|
|||
via.mutable_id()->set_value( m_Uuid.AsStdString() );
|
||||
via.mutable_position()->set_x_nm( GetPosition().x );
|
||||
via.mutable_position()->set_y_nm( GetPosition().y );
|
||||
via.mutable_pad_diameter()->set_value_nm( GetWidth() );
|
||||
via.mutable_drill_diameter()->set_value_nm( GetDrillValue() );
|
||||
|
||||
kiapi::board::types::PadStack* padstack = via.mutable_pad_stack();
|
||||
padstack->set_type( GetViaType() == VIATYPE::BLIND_BURIED
|
||||
? kiapi::board::types::PadStackType::PST_BLIND_BURIED
|
||||
: kiapi::board::types::PadStackType::PST_THROUGH );
|
||||
padstack->mutable_start_layer()->set_layer_id( m_layer );
|
||||
padstack->mutable_end_layer()->set_layer_id( m_bottomLayer );
|
||||
padstack->set_start_layer(
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( m_layer ) );
|
||||
padstack->set_end_layer(
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( m_bottomLayer ) );
|
||||
kiapi::common::PackVector2( *padstack->mutable_drill_diameter(),
|
||||
{ GetDrillValue(), GetDrillValue() } );
|
||||
|
||||
kiapi::board::types::PadStackLayer* stackLayer = padstack->add_layers();
|
||||
kiapi::board::PackLayerSet( *stackLayer->mutable_layers(), GetLayerSet() );
|
||||
kiapi::common::PackVector2( *stackLayer->mutable_size(),
|
||||
{ GetWidth(), GetWidth() } );
|
||||
|
||||
kiapi::board::types::UnconnectedLayerRemoval ulr;
|
||||
|
||||
|
@ -409,7 +417,7 @@ void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
|
|||
|
||||
via.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
via.mutable_net()->set_code( GetNetCode() );
|
||||
via.mutable_net()->mutable_code()->set_value( GetNetCode() );
|
||||
via.mutable_net()->set_name( GetNetname() );
|
||||
|
||||
aContainer.PackFrom( via );
|
||||
|
@ -426,11 +434,17 @@ bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
|
|||
const_cast<KIID&>( m_Uuid ) = KIID( via.id().value() );
|
||||
SetStart( VECTOR2I( via.position().x_nm(), via.position().y_nm() ) );
|
||||
SetEnd( GetStart() );
|
||||
SetWidth( via.pad_diameter().value_nm() );
|
||||
SetDrill( via.drill_diameter().value_nm() );
|
||||
SetDrill( via.pad_stack().drill_diameter().x_nm() );
|
||||
|
||||
const kiapi::board::types::PadStack& padstack = via.pad_stack();
|
||||
|
||||
// We don't yet support complex padstacks for vias
|
||||
if( padstack.layers_size() == 1 )
|
||||
{
|
||||
const kiapi::board::types::PadStackLayer& layer = padstack.layers( 0 );
|
||||
SetWidth( layer.size().x_nm() );
|
||||
}
|
||||
|
||||
switch( padstack.type() )
|
||||
{
|
||||
case kiapi::board::types::PadStackType::PST_BLIND_BURIED:
|
||||
|
@ -444,10 +458,11 @@ bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
|
|||
|
||||
if( GetViaType() != VIATYPE::THROUGH )
|
||||
{
|
||||
m_layer = magic_enum::enum_cast<PCB_LAYER_ID>( padstack.start_layer().layer_id() )
|
||||
.value_or( F_Cu );
|
||||
m_bottomLayer = magic_enum::enum_cast<PCB_LAYER_ID>( padstack.end_layer().layer_id() )
|
||||
.value_or( B_Cu );
|
||||
m_layer = FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
padstack.start_layer() );
|
||||
|
||||
m_bottomLayer = FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
padstack.end_layer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -474,7 +489,7 @@ bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
|
|||
break;
|
||||
}
|
||||
|
||||
SetNetCode( via.net().code() );
|
||||
SetNetCode( via.net().code().value() );
|
||||
SetLocked( via.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
return true;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "pcb_scripting_tool.h"
|
||||
|
||||
#include <action_plugin.h>
|
||||
#include <api/api_plugin_manager.h>
|
||||
#include <kiface_ids.h>
|
||||
#include <kiway.h>
|
||||
#include <macros.h>
|
||||
|
@ -38,6 +37,10 @@
|
|||
#include <wx/string.h>
|
||||
#include <launch_ext.h>
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_plugin_manager.h>
|
||||
#endif
|
||||
|
||||
using initfunc = PyObject* (*)(void);
|
||||
|
||||
SCRIPTING_TOOL::SCRIPTING_TOOL() :
|
||||
|
@ -108,8 +111,10 @@ int SCRIPTING_TOOL::reloadPlugins( const TOOL_EVENT& aEvent )
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
// TODO move this elsewhere when SWIG plugins are removed
|
||||
Pgm().GetPluginManager().ReloadPlugins();
|
||||
#endif
|
||||
|
||||
if( !m_isFootprintEditor )
|
||||
{
|
||||
|
@ -161,6 +166,6 @@ int SCRIPTING_TOOL::showPluginFolder( const TOOL_EVENT& aEvent )
|
|||
|
||||
void SCRIPTING_TOOL::setTransitions()
|
||||
{
|
||||
Go( &SCRIPTING_TOOL::reloadPlugins, PCB_ACTIONS::pluginsReload.MakeEvent() );
|
||||
Go( &SCRIPTING_TOOL::reloadPlugins, ACTIONS::pluginsReload.MakeEvent() );
|
||||
Go( &SCRIPTING_TOOL::showPluginFolder, PCB_ACTIONS::pluginsShowFolder.MakeEvent() );
|
||||
}
|
||||
|
|
|
@ -284,8 +284,12 @@ void PCB_EDIT_FRAME::ReCreateHToolbar()
|
|||
|
||||
// Add SWIG and API plugins
|
||||
bool scriptingAvailable = SCRIPTING::IsWxAvailable();
|
||||
#ifdef KICAD_IPC_API
|
||||
bool haveApiPlugins = Pgm().GetCommonSettings()->m_Api.enable_server &&
|
||||
!Pgm().GetPluginManager().GetActionsForScope( PLUGIN_ACTION_SCOPE::PCB ).empty();
|
||||
#else
|
||||
bool haveApiPlugins = false;
|
||||
#endif
|
||||
|
||||
if( scriptingAvailable || haveApiPlugins )
|
||||
{
|
||||
|
@ -298,7 +302,7 @@ void PCB_EDIT_FRAME::ReCreateHToolbar()
|
|||
}
|
||||
|
||||
if( haveApiPlugins )
|
||||
AddApiPluginTools();
|
||||
addApiPluginTools();
|
||||
}
|
||||
|
||||
// after adding the buttons to the toolbar, must call Realize() to reflect the changes
|
||||
|
@ -306,35 +310,6 @@ void PCB_EDIT_FRAME::ReCreateHToolbar()
|
|||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::AddApiPluginTools()
|
||||
{
|
||||
// TODO: Add user control over visibility and order
|
||||
API_PLUGIN_MANAGER& mgr = Pgm().GetPluginManager();
|
||||
|
||||
mgr.ButtonBindings().clear();
|
||||
|
||||
std::vector<const PLUGIN_ACTION*> actions = mgr.GetActionsForScope( PLUGIN_ACTION_SCOPE::PCB );
|
||||
|
||||
for( auto& action : actions )
|
||||
{
|
||||
if( !action->show_button )
|
||||
continue;
|
||||
|
||||
const wxBitmapBundle& icon = KIPLATFORM::UI::IsDarkTheme() && action->icon_dark.IsOk()
|
||||
? action->icon_dark
|
||||
: action->icon_light;
|
||||
|
||||
wxAuiToolBarItem* button = m_mainToolBar->AddTool( wxID_ANY, wxEmptyString, icon,
|
||||
action->name );
|
||||
|
||||
Connect( button->GetId(), wxEVT_COMMAND_MENU_SELECTED,
|
||||
wxCommandEventHandler( PCB_EDIT_FRAME::OnApiPluginButton ) );
|
||||
|
||||
mgr.ButtonBindings().insert( { button->GetId(), action->identifier } );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::ReCreateOptToolbar()
|
||||
{
|
||||
// Note:
|
||||
|
|
|
@ -985,12 +985,6 @@ TOOL_ACTION PCB_ACTIONS::defaultPadProperties( TOOL_ACTION_ARGS()
|
|||
|
||||
// SCRIPTING TOOL
|
||||
//
|
||||
TOOL_ACTION PCB_ACTIONS::pluginsReload( TOOL_ACTION_ARGS()
|
||||
.Name( "pcbnew.ScriptingTool.pluginsReload" )
|
||||
.Scope( AS_GLOBAL )
|
||||
.FriendlyName( _( "Refresh Plugins" ) )
|
||||
.Tooltip( _( "Reload all python plugins and refresh plugin menus" ) )
|
||||
.Icon( BITMAPS::reload ) );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::pluginsShowFolder( TOOL_ACTION_ARGS()
|
||||
.Name( "pcbnew.ScriptingTool.pluginsShowFolder" )
|
||||
|
|
|
@ -399,7 +399,6 @@ public:
|
|||
static TOOL_ACTION zoneDuplicate;
|
||||
|
||||
/// Scripting Actions
|
||||
static TOOL_ACTION pluginsReload;
|
||||
static TOOL_ACTION pluginsShowFolder;
|
||||
|
||||
// Global edit tool
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,272 @@
|
|||
{
|
||||
"board": {
|
||||
"3dviewports": [],
|
||||
"design_settings": {
|
||||
"defaults": {
|
||||
"apply_defaults_to_fp_fields": false,
|
||||
"apply_defaults_to_fp_shapes": false,
|
||||
"apply_defaults_to_fp_text": false,
|
||||
"board_outline_line_width": 0.05,
|
||||
"copper_line_width": 0.2,
|
||||
"copper_text_italic": false,
|
||||
"copper_text_size_h": 1.5,
|
||||
"copper_text_size_v": 1.5,
|
||||
"copper_text_thickness": 0.3,
|
||||
"copper_text_upright": false,
|
||||
"courtyard_line_width": 0.05,
|
||||
"dimension_precision": 4,
|
||||
"dimension_units": 3,
|
||||
"dimensions": {
|
||||
"arrow_length": 1270000,
|
||||
"extension_offset": 500000,
|
||||
"keep_text_aligned": true,
|
||||
"suppress_zeroes": false,
|
||||
"text_position": 0,
|
||||
"units_format": 1
|
||||
},
|
||||
"fab_line_width": 0.1,
|
||||
"fab_text_italic": false,
|
||||
"fab_text_size_h": 1.0,
|
||||
"fab_text_size_v": 1.0,
|
||||
"fab_text_thickness": 0.15,
|
||||
"fab_text_upright": false,
|
||||
"other_line_width": 0.1,
|
||||
"other_text_italic": false,
|
||||
"other_text_size_h": 1.0,
|
||||
"other_text_size_v": 1.0,
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": false,
|
||||
"pads": {
|
||||
"drill": 1.143,
|
||||
"height": 2.032,
|
||||
"width": 2.032
|
||||
},
|
||||
"silk_line_width": 0.1,
|
||||
"silk_text_italic": false,
|
||||
"silk_text_size_h": 1.0,
|
||||
"silk_text_size_v": 1.0,
|
||||
"silk_text_thickness": 0.1,
|
||||
"silk_text_upright": false,
|
||||
"zones": {
|
||||
"min_clearance": 0.5
|
||||
}
|
||||
},
|
||||
"diff_pair_dimensions": [],
|
||||
"drc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"rule_severities": {
|
||||
"annular_width": "error",
|
||||
"clearance": "error",
|
||||
"connection_width": "warning",
|
||||
"copper_edge_clearance": "error",
|
||||
"copper_sliver": "warning",
|
||||
"courtyards_overlap": "error",
|
||||
"diff_pair_gap_out_of_range": "error",
|
||||
"diff_pair_uncoupled_length_too_long": "error",
|
||||
"drill_out_of_range": "error",
|
||||
"duplicate_footprints": "warning",
|
||||
"extra_footprint": "warning",
|
||||
"footprint": "error",
|
||||
"footprint_symbol_mismatch": "warning",
|
||||
"footprint_type_mismatch": "ignore",
|
||||
"hole_clearance": "error",
|
||||
"hole_near_hole": "error",
|
||||
"invalid_outline": "error",
|
||||
"isolated_copper": "warning",
|
||||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "warning",
|
||||
"lib_footprint_mismatch": "warning",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
"missing_footprint": "warning",
|
||||
"net_conflict": "warning",
|
||||
"npth_inside_courtyard": "ignore",
|
||||
"padstack": "warning",
|
||||
"pth_inside_courtyard": "ignore",
|
||||
"shorting_items": "error",
|
||||
"silk_edge_clearance": "warning",
|
||||
"silk_over_copper": "warning",
|
||||
"silk_overlap": "warning",
|
||||
"skew_out_of_range": "error",
|
||||
"solder_mask_bridge": "error",
|
||||
"starved_thermal": "error",
|
||||
"text_height": "warning",
|
||||
"text_thickness": "warning",
|
||||
"through_hole_pad_without_hole": "error",
|
||||
"too_many_vias": "error",
|
||||
"track_dangling": "warning",
|
||||
"track_width": "error",
|
||||
"tracks_crossing": "error",
|
||||
"unconnected_items": "error",
|
||||
"unresolved_variable": "error",
|
||||
"via_dangling": "warning",
|
||||
"zones_intersect": "error"
|
||||
},
|
||||
"rules": {
|
||||
"max_error": 0.005,
|
||||
"min_clearance": 0.0,
|
||||
"min_connection": 0.0,
|
||||
"min_copper_edge_clearance": 0.5,
|
||||
"min_hole_clearance": 0.25,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.2,
|
||||
"min_microvia_drill": 0.1,
|
||||
"min_resolved_spokes": 2,
|
||||
"min_silk_clearance": 0.0,
|
||||
"min_text_height": 0.8,
|
||||
"min_text_thickness": 0.08,
|
||||
"min_through_hole_diameter": 0.3,
|
||||
"min_track_width": 0.0,
|
||||
"min_via_annular_width": 0.1,
|
||||
"min_via_diameter": 0.5,
|
||||
"solder_mask_to_copper_clearance": 0.0,
|
||||
"use_height_for_length_calcs": true
|
||||
},
|
||||
"teardrop_options": [
|
||||
{
|
||||
"td_onpadsmd": true,
|
||||
"td_onroundshapesonly": false,
|
||||
"td_ontrackend": false,
|
||||
"td_onviapad": true
|
||||
}
|
||||
],
|
||||
"teardrop_parameters": [
|
||||
{
|
||||
"td_allow_use_two_tracks": true,
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_on_pad_in_zone": false,
|
||||
"td_target_name": "td_round_shape",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
},
|
||||
{
|
||||
"td_allow_use_two_tracks": true,
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_on_pad_in_zone": false,
|
||||
"td_target_name": "td_rect_shape",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
},
|
||||
{
|
||||
"td_allow_use_two_tracks": true,
|
||||
"td_curve_segcount": 0,
|
||||
"td_height_ratio": 1.0,
|
||||
"td_length_ratio": 0.5,
|
||||
"td_maxheight": 2.0,
|
||||
"td_maxlen": 1.0,
|
||||
"td_on_pad_in_zone": false,
|
||||
"td_target_name": "td_track_end",
|
||||
"td_width_to_size_filter_ratio": 0.9
|
||||
}
|
||||
],
|
||||
"track_widths": [],
|
||||
"tuning_pattern_settings": {
|
||||
"diff_pair_defaults": {
|
||||
"corner_radius_percentage": 80,
|
||||
"corner_style": 1,
|
||||
"max_amplitude": 1.0,
|
||||
"min_amplitude": 0.2,
|
||||
"single_sided": false,
|
||||
"spacing": 1.0
|
||||
},
|
||||
"diff_pair_skew_defaults": {
|
||||
"corner_radius_percentage": 80,
|
||||
"corner_style": 1,
|
||||
"max_amplitude": 1.0,
|
||||
"min_amplitude": 0.2,
|
||||
"single_sided": false,
|
||||
"spacing": 0.6
|
||||
},
|
||||
"single_track_defaults": {
|
||||
"corner_radius_percentage": 80,
|
||||
"corner_style": 1,
|
||||
"max_amplitude": 1.0,
|
||||
"min_amplitude": 0.2,
|
||||
"single_sided": false,
|
||||
"spacing": 0.6
|
||||
}
|
||||
},
|
||||
"via_dimensions": [],
|
||||
"zones_allow_external_fillets": false
|
||||
},
|
||||
"ipc2581": {
|
||||
"dist": "",
|
||||
"distpn": "",
|
||||
"internal_id": "",
|
||||
"mfg": "",
|
||||
"mpn": ""
|
||||
},
|
||||
"layer_presets": [],
|
||||
"viewports": []
|
||||
},
|
||||
"boards": [],
|
||||
"cvpcb": {
|
||||
"equivalence_files": []
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "api_kitchen_sink.kicad_pro",
|
||||
"version": 1
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12,
|
||||
"clearance": 0.2,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.2,
|
||||
"via_diameter": 0.6,
|
||||
"via_drill": 0.3,
|
||||
"wire_width": 6
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 3
|
||||
},
|
||||
"net_colors": null,
|
||||
"netclass_assignments": null,
|
||||
"netclass_patterns": []
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "",
|
||||
"plot": "",
|
||||
"pos_files": "",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"svg": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": []
|
||||
},
|
||||
"sheets": [],
|
||||
"text_variables": {}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
## Unit tests
|
||||
add_subdirectory( api )
|
||||
add_subdirectory( common )
|
||||
add_subdirectory( gerbview )
|
||||
add_subdirectory( eeschema )
|
||||
|
|
|
@ -15,29 +15,45 @@
|
|||
# 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_directories( BEFORE ${INC_BEFORE} )
|
||||
include_directories(
|
||||
${INC_AFTER}
|
||||
set( QA_API_SRCS
|
||||
test_api_module.cpp
|
||||
test_api_enums.cpp
|
||||
test_api_proto.cpp
|
||||
)
|
||||
|
||||
add_executable( enum_exporter WIN32
|
||||
enum_exporter.cpp
|
||||
add_executable( qa_api
|
||||
${QA_API_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries( enum_exporter
|
||||
add_dependencies( qa_api pcbnew )
|
||||
|
||||
target_link_libraries( qa_api
|
||||
kiapi
|
||||
qa_utils
|
||||
qa_pcbnew_utils
|
||||
pcbnew_kiface_objects
|
||||
3d-viewer
|
||||
connectivity
|
||||
pcbcommon
|
||||
pnsrouter
|
||||
gal
|
||||
common
|
||||
idf3
|
||||
markdown_lib
|
||||
${PCBNEW_IO_LIBRARIES}
|
||||
${wxWidgets_LIBRARIES}
|
||||
Boost::headers
|
||||
Boost::unit_test_framework
|
||||
${PCBNEW_EXTRA_LIBS} # -lrt must follow Boost
|
||||
)
|
||||
|
||||
target_include_directories( enum_exporter PRIVATE
|
||||
target_include_directories( qa_api PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/common
|
||||
${CMAKE_SOURCE_DIR}/qa/mocks/include
|
||||
${CMAKE_SOURCE_DIR}/pcbnew
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
$<TARGET_PROPERTY:magic_enum,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
||||
if( MSVC )
|
||||
# The cli needs subsystem:console or else we can't link wmain/main
|
||||
set_target_properties(enum_exporter PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
|
||||
set_target_properties(enum_exporter PROPERTIES COMPILE_DEFINITIONS_RELWITHDEBINFO "_CONSOLE")
|
||||
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
||||
endif()
|
||||
kicad_add_boost_test( qa_api qa_api )
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue