ADDED: A new IPC API based on protobuf and nng
Details, documentation, and language bindings are works in progress and will be evolving over the course of KiCad 9 development.
This commit is contained in:
parent
77eaa75db1
commit
f613cd1cb4
|
@ -247,6 +247,10 @@ option( KICAD_GAL_PROFILE
|
|||
"Enable profiling info for GAL"
|
||||
OFF )
|
||||
|
||||
option( KICAD_IPC_API
|
||||
"Enable experimental IPC API"
|
||||
OFF )
|
||||
|
||||
# Global setting: exports are explicit
|
||||
set( CMAKE_CXX_VISIBILITY_PRESET "hidden" )
|
||||
set( CMAKE_VISIBILITY_INLINES_HIDDEN ON )
|
||||
|
@ -278,6 +282,10 @@ if( KICAD_WAYLAND )
|
|||
add_compile_definitions( KICAD_WAYLAND )
|
||||
endif()
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
add_definitions( -DKICAD_IPC_API )
|
||||
endif()
|
||||
|
||||
# Ensure DEBUG is defined for all platforms in Debug builds
|
||||
add_compile_definitions( $<$<CONFIG:Debug>:DEBUG> )
|
||||
|
||||
|
@ -842,6 +850,26 @@ if( OCC_VERSION_STRING VERSION_LESS 7.5.0 )
|
|||
endif()
|
||||
include_directories( SYSTEM ${OCC_INCLUDE_DIR} )
|
||||
|
||||
option( KICAD_USE_CMAKE_FINDPROTOBUF "Use FindProtobuf provided by CMake" OFF )
|
||||
mark_as_advanced( KICAD_USE_CMAKE_FINDPROTOBUF )
|
||||
|
||||
if( KICAD_USE_CMAKE_FINDPROTOBUF )
|
||||
include( FindProtobuf )
|
||||
find_package( Protobuf REQUIRED )
|
||||
else()
|
||||
find_package( Protobuf REQUIRED CONFIG )
|
||||
set( Protobuf_LIBRARY "protobuf::libprotobuf" )
|
||||
endif()
|
||||
|
||||
if( NOT Protobuf_PROTOC_EXECUTABLE )
|
||||
set( Protobuf_PROTOC_EXECUTABLE "protobuf::protoc" )
|
||||
endif()
|
||||
|
||||
if( NOT Protobuf_INCLUDE_DIR )
|
||||
get_target_property( Protobuf_INCLUDE_DIR protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES )
|
||||
endif()
|
||||
|
||||
|
||||
# Assist with header file searching optimization:
|
||||
# INC_BEFORE and INC_AFTER are two lists which go at the front and back of the
|
||||
# header file search lists, respectively.
|
||||
|
@ -1051,6 +1079,10 @@ if( KICAD_USE_SENTRY )
|
|||
add_compile_definitions( KICAD_USE_SENTRY )
|
||||
endif()
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
find_package( nng REQUIRED )
|
||||
endif()
|
||||
|
||||
#================================================
|
||||
# Add the doxygen target
|
||||
#================================================
|
||||
|
@ -1121,6 +1153,8 @@ if( KICAD_BUILD_I18N )
|
|||
add_subdirectory( translation )
|
||||
endif()
|
||||
|
||||
add_subdirectory( api )
|
||||
|
||||
if( APPLE )
|
||||
set( KICAD_OSX_CODESIGN ON
|
||||
CACHE BOOL "Sign KiCad.app on macOS" FORCE )
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
# 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/>.
|
||||
|
||||
# Search paths for protoc when generating code
|
||||
set( Protobuf_IMPORT_DIRS ${Protobuf_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/proto )
|
||||
|
||||
set( KIAPI_PROTO_SRCS
|
||||
common/envelope.proto
|
||||
|
||||
common/types/base_types.proto
|
||||
|
||||
common/commands/base_commands.proto
|
||||
common/commands/editor_commands.proto
|
||||
|
||||
board/board_types.proto
|
||||
)
|
||||
|
||||
# Generated C++ code must be in the build dir; it is dependent on the version of protoc installed
|
||||
set( KIAPI_CPP_BASEPATH ${CMAKE_CURRENT_BINARY_DIR}/cpp/api )
|
||||
|
||||
foreach( PROTO_SRC ${KIAPI_PROTO_SRCS} )
|
||||
string( REGEX REPLACE "\.proto$" ".pb.cc" CPP_SRC ${PROTO_SRC} )
|
||||
string( REGEX REPLACE "\.proto$" ".pb.h" CPP_HEADER ${PROTO_SRC} )
|
||||
set( KIAPI_CPP_SRCS ${KIAPI_CPP_SRCS} ${KIAPI_CPP_BASEPATH}/${CPP_SRC} )
|
||||
set( KIAPI_CPP_HEADERS ${KIAPI_CPP_HEADERS} ${KIAPI_CPP_BASEPATH}/${CPP_HEADER} )
|
||||
set( KIAPI_PROTO_SRC_FULLPATHS ${KIAPI_PROTO_SRC_FULLPATHS} ${CMAKE_CURRENT_SOURCE_DIR}/proto/${PROTO_SRC} )
|
||||
endforeach ()
|
||||
|
||||
add_custom_command( COMMAND ${CMAKE_COMMAND} -E make_directory ${KIAPI_CPP_BASEPATH}
|
||||
COMMAND ${Protobuf_PROTOC_EXECUTABLE}
|
||||
--cpp_out=dllexport_decl=KIAPI_IMPORTEXPORT:${KIAPI_CPP_BASEPATH}
|
||||
--proto_path=${CMAKE_CURRENT_SOURCE_DIR}/proto
|
||||
${KIAPI_PROTO_SRCS}
|
||||
COMMENT "Generating API protobuf source files from proto definitions..."
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${KIAPI_PROTO_SRC_FULLPATHS}
|
||||
OUTPUT ${KIAPI_CPP_SRCS} ${KIAPI_CPP_HEADERS}
|
||||
)
|
||||
|
||||
# kiapi must be a shared DLL because the protobuf messages can only be initialized once
|
||||
add_library( kiapi SHARED
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include/import_export.h
|
||||
${KIAPI_CPP_SRCS}
|
||||
${KIAPI_CPP_HEADERS}
|
||||
)
|
||||
|
||||
target_compile_definitions( kiapi PRIVATE KIAPI_IMPORTEXPORT=APIEXPORT )
|
||||
target_compile_definitions( kiapi INTERFACE KIAPI_IMPORTEXPORT=APIIMPORT )
|
||||
|
||||
# https://groups.google.com/g/protobuf/c/PDR1bqRazts
|
||||
if(MSVC)
|
||||
target_compile_options( kiapi PRIVATE /FI${CMAKE_CURRENT_SOURCE_DIR}/../include/import_export.h )
|
||||
else()
|
||||
add_definitions( -include ${CMAKE_CURRENT_SOURCE_DIR}/../include/import_export.h )
|
||||
endif()
|
||||
|
||||
if( APPLE )
|
||||
# puts library into the main kicad.app bundle in build tree
|
||||
set_target_properties( kiapi PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY "${OSX_BUNDLE_BUILD_LIB_DIR}"
|
||||
INSTALL_NAME_DIR "${OSX_BUNDLE_BUILD_LIB_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
install( TARGETS
|
||||
kiapi
|
||||
RUNTIME DESTINATION ${KICAD_LIB}
|
||||
LIBRARY DESTINATION ${KICAD_LIB}
|
||||
COMPONENT binary
|
||||
)
|
||||
|
||||
if( KICAD_WIN32_INSTALL_PDBS )
|
||||
# Get the PDBs to copy over for MSVC
|
||||
install(FILES $<TARGET_PDB_FILE:kiapi> DESTINATION ${KICAD_BIN})
|
||||
endif()
|
||||
|
||||
# Because CMake doesn't guess this from the .cc extension generated by protoc
|
||||
set_target_properties( kiapi PROPERTIES LINKER_LANGUAGE CXX )
|
||||
|
||||
target_include_directories( kiapi SYSTEM PUBLIC ${Protobuf_INCLUDE_DIRS} )
|
||||
|
||||
target_link_libraries( kiapi protobuf::libprotobuf )
|
||||
|
||||
target_include_directories( kiapi INTERFACE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cpp # Leaving off the /api/ to make #include statments less ambiguous
|
||||
)
|
||||
|
||||
# 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()
|
|
@ -0,0 +1,43 @@
|
|||
# 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_directories( BEFORE ${INC_BEFORE} )
|
||||
include_directories(
|
||||
${INC_AFTER}
|
||||
)
|
||||
|
||||
add_executable( enum_exporter WIN32
|
||||
enum_exporter.cpp
|
||||
)
|
||||
|
||||
target_link_libraries( enum_exporter
|
||||
common
|
||||
)
|
||||
|
||||
target_include_directories( enum_exporter PRIVATE
|
||||
$<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()
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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,110 @@
|
|||
/*
|
||||
* 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.board.types;
|
||||
|
||||
import "common/types/base_types.proto";
|
||||
|
||||
/// 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.Distance width = 4;
|
||||
kiapi.common.types.LockedState locked = 5;
|
||||
kiapi.common.types.BoardLayer layer = 6;
|
||||
kiapi.common.types.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.
|
||||
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.Distance width = 5;
|
||||
kiapi.common.types.LockedState locked = 6;
|
||||
kiapi.common.types.BoardLayer layer = 7;
|
||||
kiapi.common.types.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
|
||||
}
|
||||
|
||||
enum UnconnectedLayerRemoval
|
||||
{
|
||||
ULR_UNKNOWN = 0;
|
||||
|
||||
/// Keep annular rings on all layers
|
||||
ULR_KEEP = 1;
|
||||
|
||||
/// 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.
|
||||
ULR_REMOVE_EXCEPT_START_AND_END = 3;
|
||||
}
|
||||
|
||||
/// A pad stack definition for a multilayer pad or via.
|
||||
message PadStack
|
||||
{
|
||||
/// 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;
|
||||
|
||||
/// Highest (closest to B_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
|
||||
kiapi.common.types.BoardLayer end_layer = 3;
|
||||
|
||||
/// How to treat annular rings on unconnected layers.
|
||||
UnconnectedLayerRemoval unconnected_layer_removal = 4;
|
||||
}
|
||||
|
||||
/// Represents a via
|
||||
message 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 diameter of the via's circular copper pad
|
||||
kiapi.common.types.Distance pad_diameter = 4;
|
||||
|
||||
/// The diameter of the via's drilled hole
|
||||
kiapi.common.types.Distance drill_diameter = 5;
|
||||
|
||||
/// The pad stack definition for this via. The via's VIATYPE (blind/buried/normal) is inferred from this.
|
||||
PadStack pad_stack = 6;
|
||||
|
||||
kiapi.common.types.LockedState locked = 7;
|
||||
kiapi.common.types.Net net = 8;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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/base_types.proto";
|
||||
|
||||
message GetVersion
|
||||
{
|
||||
}
|
||||
|
||||
message GetVersionResponse
|
||||
{
|
||||
kiapi.common.types.KiCadVersion version = 1;
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Commands and responses related to manipulating editor windows
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.common.commands;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "common/types/base_types.proto";
|
||||
|
||||
/// 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
|
||||
message GetOpenDocuments
|
||||
{
|
||||
/// Which type of documents to query
|
||||
kiapi.common.types.DocumentType type = 1;
|
||||
}
|
||||
|
||||
message GetOpenDocumentsResponse
|
||||
{
|
||||
repeated kiapi.common.types.DocumentSpecifier documents = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs a TOOL_ACTION using the TOOL_MANAGER of a given frame.
|
||||
* WARNING: The TOOL_ACTIONs are specifically *not* an API.
|
||||
* Command names may change as code is refactored, and commands may disappear.
|
||||
* This API method is provided for low-level prototyping purposes only.
|
||||
*/
|
||||
message RunAction
|
||||
{
|
||||
string action = 1; // Action name, like "eeschema.InteractiveSelection.ClearSelection"
|
||||
}
|
||||
|
||||
enum RunActionStatus
|
||||
{
|
||||
RAS_UNKNOWN = 0;
|
||||
RAS_OK = 1; // The action was submitted successfully.
|
||||
RAS_INVALID = 2; // The action was unknown for the targeted frame.
|
||||
RAS_FRAME_NOT_OPEN = 3; // The targeted frame was not open when the call was submitted.
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: At the moment, RAS_FRAME_NOT_OPEN won't be returned as the handler is inside the frame.
|
||||
*/
|
||||
message RunActionResponse
|
||||
{
|
||||
RunActionStatus status = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Begins a staged set of changes. Any modifications made to a document through the API after this
|
||||
* call will be saved to a pending commit, and will not appear in KiCad until a matching call to
|
||||
* END_COMMIT.
|
||||
*/
|
||||
message BeginCommit
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
message BeginCommitResponse
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
enum CommitResult
|
||||
{
|
||||
CR_UNKNOWN = 0;
|
||||
CR_OK = 1; // Commit was pushed successfully
|
||||
CR_NO_COMMIT = 2; // There was no commit started
|
||||
}
|
||||
|
||||
|
||||
message EndCommit
|
||||
{
|
||||
// Optional message describing this changeset
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
|
||||
message EndCommitResponse
|
||||
{
|
||||
CommitResult result = 1;
|
||||
}
|
||||
|
||||
/// Creates new items on a given document
|
||||
message CreateItems
|
||||
{
|
||||
/// Specifies which document to create on, which fields are included, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// 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.
|
||||
kiapi.common.types.KIID container = 3;
|
||||
}
|
||||
|
||||
enum ItemCreationStatus
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
message ItemCreationResult
|
||||
{
|
||||
ItemCreationStatus status = 1;
|
||||
|
||||
/// 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.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// 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
|
||||
repeated ItemCreationResult created_items = 3;
|
||||
}
|
||||
|
||||
message GetItems
|
||||
{
|
||||
/// 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;
|
||||
}
|
||||
|
||||
message GetItemsResponse
|
||||
{
|
||||
/// 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
|
||||
kiapi.common.types.ItemRequestStatus status = 2;
|
||||
|
||||
repeated google.protobuf.Any items = 3;
|
||||
}
|
||||
|
||||
/// Updates items in a given document
|
||||
message UpdateItems
|
||||
{
|
||||
/// Specifies which document to modify, which fields are included, etc.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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.
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// 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
|
||||
repeated ItemUpdateResult updated_items = 3;
|
||||
}
|
||||
|
||||
/// Deletes items in a given document
|
||||
message DeleteItems
|
||||
{
|
||||
/// Specifies which document to modify
|
||||
kiapi.common.types.ItemHeader header = 1;
|
||||
|
||||
/// List of item KIIDs to delete
|
||||
repeated kiapi.common.types.KIID item_ids = 2;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
message ItemDeletionResult
|
||||
{
|
||||
kiapi.common.types.KIID id = 1;
|
||||
|
||||
ItemDeletionStatus status = 2;
|
||||
}
|
||||
|
||||
message DeleteItemsResponse
|
||||
{
|
||||
/// 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
|
||||
kiapi.common.types.ItemRequestStatus status = 2;
|
||||
|
||||
/// Status of each item requested to be deleted
|
||||
repeated ItemDeletionResult deleted_items = 3;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
enum ApiStatusCode
|
||||
{
|
||||
AS_UNKNOWN = 0;
|
||||
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_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
|
||||
}
|
||||
|
||||
/*
|
||||
* For future expansion: any header fields that should be sent with a request
|
||||
*/
|
||||
message ApiRequestHeader
|
||||
{
|
||||
// An opaque string identifying a running instance of KiCad. If this is set to a non-empty
|
||||
// string in an API request, KiCad will reject the request if the value doesn't match its own
|
||||
// token. This can be used to let API clients make sure they are still talking to the same
|
||||
// instance of KiCad if they are long-running.
|
||||
string kicad_token = 1;
|
||||
|
||||
// A string identifying an API client. Should be set by the client to a value that is unique
|
||||
// to a specific instance of a client, for example the package name of the client plus its
|
||||
// process ID or a random string, e.g. "com.github.me.my_awesome_plugin-73951". The main purpose
|
||||
// of this name is to identify the client in debug logs.
|
||||
string client_name = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The top-level envelope container for an API request (message from a client to the KiCad API server)
|
||||
*/
|
||||
message ApiRequest
|
||||
{
|
||||
ApiRequestHeader header = 1;
|
||||
|
||||
google.protobuf.Any message = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* For future expansion: any header fields that should be sent with a response
|
||||
*/
|
||||
message ApiResponseHeader
|
||||
{
|
||||
/// An opaque string identifying a running instance of KiCad.
|
||||
string kicad_token = 1;
|
||||
}
|
||||
|
||||
message ApiResponse
|
||||
{
|
||||
ApiResponseHeader header = 1;
|
||||
|
||||
ApiResponseStatus status = 2;
|
||||
|
||||
google.protobuf.Any message = 3;
|
||||
}
|
||||
|
||||
message ApiResponseStatus
|
||||
{
|
||||
/// A code describing the category of error (or AS_OK if no error)
|
||||
ApiStatusCode status = 1;
|
||||
|
||||
/// A human-readable description of the error, if any
|
||||
string error_message = 2;
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* base_types.proto
|
||||
* Includes types used in many parts of the API
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package kiapi.common.types;
|
||||
|
||||
import "google/protobuf/field_mask.proto";
|
||||
|
||||
enum CommandStatus
|
||||
{
|
||||
CS_UNKNOWN = 0;
|
||||
CS_OK = 1; // Command succeeded
|
||||
CS_FAILED = 2; // Command failed
|
||||
}
|
||||
|
||||
message CommandStatusResponse
|
||||
{
|
||||
CommandStatus status = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a particular version of KiCad
|
||||
*/
|
||||
message KiCadVersion
|
||||
{
|
||||
uint32 major = 1;
|
||||
uint32 minor = 2;
|
||||
uint32 patch = 3;
|
||||
|
||||
// Full identifier string, potentially containing git hashes, packager-added info, etc.
|
||||
string full_version = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some commands are specific to a KiCad window (frame). This list contains all addressable frames.
|
||||
*/
|
||||
enum FrameType
|
||||
{
|
||||
FT_UNKNOWN = 0;
|
||||
FT_PROJECT_MANAGER = 1;
|
||||
FT_SCHEMATIC_EDITOR = 2;
|
||||
FT_PCB_EDITOR = 3;
|
||||
FT_SPICE_SIMULATOR = 4;
|
||||
FT_SYMBOL_EDITOR = 5;
|
||||
FT_FOOTPRINT_EDITOR = 6;
|
||||
FT_DRAWING_SHEET_EDITOR = 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a KIID, or UUID of an object in a KiCad editor model.
|
||||
*/
|
||||
message KIID
|
||||
{
|
||||
// The KIID's value in standard UUID format, stored as a string for easy portability
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifier for the type of document being targeted by a request
|
||||
*/
|
||||
enum DocumentType
|
||||
{
|
||||
DOCTYPE_UNKNOWN = 0;
|
||||
DOCTYPE_SCHEMATIC = 1;
|
||||
DOCTYPE_SYMBOL = 2;
|
||||
DOCTYPE_PCB = 3;
|
||||
DOCTYPE_FOOTPRINT = 4;
|
||||
DOCTYPE_DRAWING_SHEET = 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a KiCad LIB_ID; a unique identifier for a loaded symbol or footprint
|
||||
*/
|
||||
message LibraryIdentifier
|
||||
{
|
||||
/// The library portion of the LIB_ID
|
||||
string library_nickname = 1;
|
||||
|
||||
/// The symbol or footprint name
|
||||
string entry_name = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a unique sheet in a schematic
|
||||
*/
|
||||
message SheetPath
|
||||
{
|
||||
/// 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"
|
||||
string path_human_readable = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a document that will be the target of a request
|
||||
*/
|
||||
message DocumentSpecifier
|
||||
{
|
||||
DocumentType type = 1;
|
||||
|
||||
oneof identifier
|
||||
{
|
||||
/// 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
|
||||
SheetPath sheet_path = 3;
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This header is included in requests and responses about item(s) in a document
|
||||
*/
|
||||
message ItemHeader
|
||||
{
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of a request that included an ItemHeader
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
/// Describes a point in 2D space. All coordinates are in nanometers.
|
||||
message Point2D
|
||||
{
|
||||
int64 x_nm = 1;
|
||||
int64 y_nm = 2;
|
||||
}
|
||||
|
||||
/// Describes a point in 3D space. All coordinates are in nanometers.
|
||||
message Point3D
|
||||
{
|
||||
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.
|
||||
message Distance
|
||||
{
|
||||
int64 value_nm = 1;
|
||||
}
|
||||
|
||||
/// Describes whether or not an item is locked for editing or movement
|
||||
enum LockedState
|
||||
{
|
||||
LS_UNKNOWN = 0;
|
||||
LS_UNLOCKED = 1;
|
||||
LS_LOCKED = 2;
|
||||
}
|
||||
|
||||
message BoardLayer
|
||||
{
|
||||
int32 layer_id = 1; /// From PCB_LAYER_T
|
||||
}
|
||||
|
||||
/// Describes a copper item's net
|
||||
message Net
|
||||
{
|
||||
/// A unique code representing this net
|
||||
int32 code = 1;
|
||||
|
||||
/// Human-readable net name
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
/// Describes a net class (a grouping of nets)
|
||||
message NetClass
|
||||
{
|
||||
string name = 1;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
find_package(PkgConfig)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(_NNG nng)
|
||||
endif (PKG_CONFIG_FOUND)
|
||||
|
||||
FIND_PATH(NNG_INCLUDE_DIR
|
||||
NAMES
|
||||
nng/nng.h
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(NNG_LIBRARY
|
||||
NAMES
|
||||
nng
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"local/lib"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(nng
|
||||
REQUIRED_VARS NNG_INCLUDE_DIR NNG_LIBRARY)
|
||||
|
||||
MARK_AS_ADVANCED(NNG_INCLUDE_DIR NNG_LIBRARY)
|
|
@ -186,6 +186,7 @@ set_target_properties(kicommon PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
|||
|
||||
target_link_libraries( kicommon
|
||||
core
|
||||
kiapi
|
||||
kimath
|
||||
kiplatform
|
||||
nlohmann_json
|
||||
|
@ -254,6 +255,7 @@ target_include_directories( kicommon
|
|||
.
|
||||
${CMAKE_BINARY_DIR}
|
||||
$<TARGET_PROPERTY:pegtl,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:kiapi,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
||||
add_dependencies( kicommon pegtl version_header )
|
||||
|
@ -335,6 +337,8 @@ set( COMMON_DLG_SRCS
|
|||
dialogs/panel_mouse_settings_base.cpp
|
||||
dialogs/panel_packages_and_updates.cpp
|
||||
dialogs/panel_packages_and_updates_base.cpp
|
||||
dialogs/panel_python_settings.cpp
|
||||
dialogs/panel_python_settings_base.cpp
|
||||
dialogs/panel_setup_netclasses.cpp
|
||||
dialogs/panel_setup_netclasses_base.cpp
|
||||
dialogs/panel_setup_severities.cpp
|
||||
|
@ -608,6 +612,15 @@ set( COMMON_SRCS
|
|||
|
||||
)
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
set( COMMON_SRCS
|
||||
${COMMON_SRCS}
|
||||
api/api_server.cpp
|
||||
api/api_handler.cpp
|
||||
api/api_handler_common.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library( common STATIC
|
||||
${COMMON_SRCS}
|
||||
)
|
||||
|
@ -647,6 +660,12 @@ if( KICAD_USE_SENTRY )
|
|||
sentry )
|
||||
endif()
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
target_link_libraries( common
|
||||
kinng
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories( common
|
||||
PUBLIC
|
||||
.
|
||||
|
@ -656,19 +675,17 @@ target_include_directories( common
|
|||
|
||||
# text markup support
|
||||
add_dependencies( common pegtl )
|
||||
|
||||
target_include_directories( common PUBLIC
|
||||
$<TARGET_PROPERTY:pegtl,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:magic_enum,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:expected,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
||||
target_include_directories( common SYSTEM PUBLIC
|
||||
$<TARGET_PROPERTY:nanodbc,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
||||
target_include_directories( common PUBLIC
|
||||
$<TARGET_PROPERTY:magic_enum,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
)
|
||||
|
||||
|
||||
set( PCB_COMMON_SRCS
|
||||
fp_lib_table.cpp
|
||||
hash_eda.cpp
|
||||
|
|
|
@ -110,6 +110,7 @@ static const wxChar OcePluginAngularDeflection[] = wxT( "OcePluginAngularDeflect
|
|||
static const wxChar TriangulateSimplificationLevel[] = wxT( "TriangulateSimplificationLevel" );
|
||||
static const wxChar TriangulateMinimumArea[] = wxT( "TriangulateMinimumArea" );
|
||||
static const wxChar EnableCacheFriendlyFracture[] = wxT( "EnableCacheFriendlyFracture" );
|
||||
static const wxChar EnableAPILogging[] = wxT( "EnableAPILogging" );
|
||||
} // namespace KEYS
|
||||
|
||||
|
||||
|
@ -244,6 +245,7 @@ ADVANCED_CFG::ADVANCED_CFG()
|
|||
m_3DRT_BevelExtentFactor = 1.0 / 16.0;
|
||||
|
||||
m_UseClipper2 = true;
|
||||
m_EnableAPILogging = false;
|
||||
|
||||
m_Use3DConnexionDriver = true;
|
||||
|
||||
|
@ -444,6 +446,9 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
|
|||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableGenerators,
|
||||
&m_EnableGenerators, m_EnableGenerators ) );
|
||||
|
||||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableAPILogging,
|
||||
&m_EnableAPILogging, m_EnableAPILogging ) );
|
||||
|
||||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableGit,
|
||||
&m_EnableGit, m_EnableGit ) );
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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_handler.h>
|
||||
|
||||
using kiapi::common::ApiRequest, kiapi::common::ApiResponse, kiapi::common::ApiResponseStatus;
|
||||
|
||||
|
||||
API_RESULT API_HANDLER::Handle( ApiRequest& aMsg )
|
||||
{
|
||||
ApiResponseStatus status;
|
||||
|
||||
if( !aMsg.has_message() )
|
||||
{
|
||||
status.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
status.set_error_message( "request has no inner message" );
|
||||
return tl::unexpected( status );
|
||||
}
|
||||
|
||||
std::string typeName;
|
||||
|
||||
if( !google::protobuf::Any::ParseAnyTypeUrl( aMsg.message().type_url(), &typeName ) )
|
||||
{
|
||||
status.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
status.set_error_message( "could not parse inner message type" );
|
||||
return tl::unexpected( status );
|
||||
}
|
||||
|
||||
auto it = m_handlers.find( typeName );
|
||||
|
||||
if( it != m_handlers.end() )
|
||||
{
|
||||
REQUEST_HANDLER& handler = it->second;
|
||||
return handler( aMsg );
|
||||
}
|
||||
|
||||
status.set_status( ApiStatusCode::AS_UNHANDLED );
|
||||
// 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;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 <tuple>
|
||||
|
||||
#include <api/api_handler_common.h>
|
||||
#include <build_version.h>
|
||||
#include <pgm_base.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
using namespace kiapi::common::commands;
|
||||
using namespace kiapi::common::types;
|
||||
using google::protobuf::Empty;
|
||||
|
||||
|
||||
API_HANDLER_COMMON::API_HANDLER_COMMON() :
|
||||
API_HANDLER()
|
||||
{
|
||||
registerHandler<GetVersion, GetVersionResponse>( &API_HANDLER_COMMON::handleGetVersion );
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVersion& aMsg )
|
||||
{
|
||||
GetVersionResponse reply;
|
||||
|
||||
reply.mutable_version()->set_full_version( GetBuildVersion().ToStdString() );
|
||||
|
||||
std::tuple<int, int, int> version = GetMajorMinorPatchTuple();
|
||||
reply.mutable_version()->set_major( std::get<0>( version ) );
|
||||
reply.mutable_version()->set_minor( std::get<1>( version ) );
|
||||
reply.mutable_version()->set_patch( std::get<2>( version ) );
|
||||
|
||||
return reply;
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* 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 <wx/app.h>
|
||||
#include <wx/datetime.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <api/api_server.h>
|
||||
#include <api/api_handler_common.h>
|
||||
#include <kiid.h>
|
||||
#include <kinng.h>
|
||||
#include <paths.h>
|
||||
#include <pgm_base.h>
|
||||
#include <string_utils.h>
|
||||
|
||||
#include <api/common/envelope.pb.h>
|
||||
|
||||
using kiapi::common::ApiRequest, kiapi::common::ApiResponse, kiapi::common::ApiStatusCode;
|
||||
|
||||
|
||||
wxString KICAD_API_SERVER::s_logFileName = "api.log";
|
||||
|
||||
|
||||
wxDEFINE_EVENT( API_REQUEST_EVENT, wxCommandEvent );
|
||||
|
||||
|
||||
KICAD_API_SERVER::KICAD_API_SERVER() :
|
||||
wxEvtHandler(),
|
||||
m_token( KIID().AsStdString() ),
|
||||
m_readyToReply( false )
|
||||
{
|
||||
m_server = std::make_unique<KINNG_REQUEST_SERVER>();
|
||||
m_server->SetCallback( [&]( std::string* aRequest ) { onApiRequest( aRequest ); } );
|
||||
|
||||
m_commonHandler = std::make_unique<API_HANDLER_COMMON>();
|
||||
RegisterHandler( m_commonHandler.get() );
|
||||
|
||||
m_logFilePath.AssignDir( PATHS::GetLogsPath() );
|
||||
m_logFilePath.SetName( s_logFileName );
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
|
||||
PATHS::EnsurePathExists( PATHS::GetLogsPath() );
|
||||
|
||||
log( "--- KiCad API server started ---\n" );
|
||||
|
||||
Bind( API_REQUEST_EVENT, &KICAD_API_SERVER::handleApiEvent, this );
|
||||
}
|
||||
|
||||
|
||||
KICAD_API_SERVER::~KICAD_API_SERVER()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void KICAD_API_SERVER::RegisterHandler( API_HANDLER* aHandler )
|
||||
{
|
||||
wxCHECK( aHandler, /* void */ );
|
||||
m_handlers.insert( aHandler );
|
||||
}
|
||||
|
||||
|
||||
void KICAD_API_SERVER::DeregisterHandler( API_HANDLER* aHandler )
|
||||
{
|
||||
m_handlers.erase( aHandler );
|
||||
}
|
||||
|
||||
|
||||
void KICAD_API_SERVER::onApiRequest( std::string* aRequest )
|
||||
{
|
||||
if( !m_readyToReply )
|
||||
{
|
||||
ApiResponse notHandled;
|
||||
notHandled.mutable_status()->set_status( ApiStatusCode::AS_NOT_READY );
|
||||
notHandled.mutable_status()->set_error_message( "KiCad is not ready to reply" );
|
||||
m_server->Reply( notHandled.SerializeAsString() );
|
||||
log( "Got incoming request but was not yet ready to reply." );
|
||||
return;
|
||||
}
|
||||
|
||||
wxCommandEvent* evt = new wxCommandEvent( API_REQUEST_EVENT );
|
||||
|
||||
// We don't actually need write access to this string, but client data is non-const
|
||||
evt->SetClientData( static_cast<void*>( aRequest ) );
|
||||
|
||||
// Takes ownership and frees the wxCommandEvent
|
||||
QueueEvent( evt );
|
||||
}
|
||||
|
||||
|
||||
void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
|
||||
{
|
||||
std::string& requestString = *static_cast<std::string*>( aEvent.GetClientData() );
|
||||
ApiRequest request;
|
||||
|
||||
if( !request.ParseFromString( requestString ) )
|
||||
{
|
||||
ApiResponse error;
|
||||
error.mutable_header()->set_kicad_token( m_token );
|
||||
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() );
|
||||
}
|
||||
|
||||
log( "Request: " + request.Utf8DebugString() );
|
||||
|
||||
if( !request.header().kicad_token().empty() &&
|
||||
request.header().kicad_token().compare( m_token ) != 0 )
|
||||
{
|
||||
ApiResponse error;
|
||||
error.mutable_header()->set_kicad_token( m_token );
|
||||
error.mutable_status()->set_status( ApiStatusCode::AS_TOKEN_MISMATCH );
|
||||
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() );
|
||||
}
|
||||
|
||||
API_RESULT result;
|
||||
|
||||
for( API_HANDLER* handler : m_handlers )
|
||||
{
|
||||
result = handler->Handle( request );
|
||||
|
||||
if( result.has_value() )
|
||||
break;
|
||||
else if( result.error().status() != ApiStatusCode::AS_UNHANDLED )
|
||||
break;
|
||||
}
|
||||
|
||||
// Note: at the point we call Reply(), we no longer own requestString.
|
||||
|
||||
if( result.has_value() )
|
||||
{
|
||||
result->mutable_header()->set_kicad_token( m_token );
|
||||
m_server->Reply( result->SerializeAsString() );
|
||||
log( "Response: " + result->Utf8DebugString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ApiResponse error;
|
||||
error.mutable_status()->CopyFrom( result.error() );
|
||||
error.mutable_header()->set_kicad_token( m_token );
|
||||
|
||||
if( result.error().status() == ApiStatusCode::AS_UNHANDLED )
|
||||
{
|
||||
std::string type = "<unparseable Any>";
|
||||
google::protobuf::Any::ParseAnyTypeUrl( request.message().type_url(), &type );
|
||||
std::string msg = fmt::format( "no handler available for request of type {}", type );
|
||||
error.mutable_status()->set_error_message( msg );
|
||||
}
|
||||
|
||||
m_server->Reply( error.SerializeAsString() );
|
||||
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 )
|
||||
return;
|
||||
|
||||
wxString out;
|
||||
wxDateTime now = wxDateTime::Now();
|
||||
|
||||
fprintf( fp, "%s", TO_UTF8( out.Format( wxS( "%s: %s" ),
|
||||
now.FormatISOCombined(), aOutput ) ) );
|
||||
fclose( fp );
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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 <dialogs/panel_python_settings.h>
|
||||
#include <widgets/ui_common.h>
|
||||
#include <pgm_base.h>
|
||||
#include <python_manager.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <settings/settings_manager.h>
|
||||
|
||||
|
||||
PANEL_PYTHON_SETTINGS::PANEL_PYTHON_SETTINGS( wxWindow* aParent ) :
|
||||
PANEL_PYTHON_SETTINGS_BASE( aParent )
|
||||
{
|
||||
wxFont helpFont = KIUI::GetInfoFont( this ).Italic();
|
||||
m_stPythonStatus->SetFont( helpFont );
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PYTHON_SETTINGS::ResetPanel()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PANEL_PYTHON_SETTINGS::TransferDataToWindow()
|
||||
{
|
||||
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
|
||||
COMMON_SETTINGS* settings = mgr.GetCommonSettings();
|
||||
|
||||
m_pickerPythonInterpreter->SetFileName( settings->m_Python.interpreter_path );
|
||||
validateInterpreter();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PANEL_PYTHON_SETTINGS::TransferDataFromWindow()
|
||||
{
|
||||
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
|
||||
COMMON_SETTINGS* settings = mgr.GetCommonSettings();
|
||||
|
||||
if( m_interpreterValid )
|
||||
settings->m_Python.interpreter_path = m_pickerPythonInterpreter->GetTextCtrlValue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PYTHON_SETTINGS::OnPythonInterpreterChanged( wxFileDirPickerEvent& event )
|
||||
{
|
||||
validateInterpreter();
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PYTHON_SETTINGS::OnBtnDetectAutomaticallyClicked( wxCommandEvent& aEvent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PYTHON_SETTINGS::validateInterpreter()
|
||||
{
|
||||
m_interpreterValid = false;
|
||||
|
||||
wxFileName pythonExe( m_pickerPythonInterpreter->GetTextCtrlValue() );
|
||||
|
||||
if( !pythonExe.FileExists() )
|
||||
{
|
||||
m_stPythonStatus->SetLabel( _( "No valid Python interpreter chosen; external Python "
|
||||
"plugins will not be available" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
PYTHON_MANAGER manager( pythonExe.GetFullPath() );
|
||||
|
||||
manager.Execute( wxS( "--version" ),
|
||||
[&]( int aRetCode, const wxString& aStdOut )
|
||||
{
|
||||
wxString msg;
|
||||
|
||||
if( aRetCode == 0 && aStdOut.Contains( wxS( "Python 3" ) ) )
|
||||
{
|
||||
msg = wxString::Format( _( "Found %s" ), aStdOut );
|
||||
m_interpreterValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = _( "Not a valid Python 3 interpreter" );
|
||||
}
|
||||
|
||||
m_stPythonStatus->SetLabel( msg );
|
||||
} );
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "panel_python_settings_base.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PANEL_PYTHON_SETTINGS_BASE::PANEL_PYTHON_SETTINGS_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : RESETTABLE_PANEL( parent, id, pos, size, style, name )
|
||||
{
|
||||
wxBoxSizer* bPanelSizer;
|
||||
bPanelSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxBoxSizer* bSizer8;
|
||||
bSizer8 = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxStaticBoxSizer* sbSizer1;
|
||||
sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Python Interpreter") ), wxVERTICAL );
|
||||
|
||||
wxBoxSizer* bSizer4;
|
||||
bSizer4 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_staticText2 = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Path to Python interpreter:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText2->Wrap( -1 );
|
||||
bSizer4->Add( m_staticText2, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
m_pickerPythonInterpreter = new wxFilePickerCtrl( sbSizer1->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select the path to a Python interpreter"), _("*.*"), wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL );
|
||||
bSizer4->Add( m_pickerPythonInterpreter, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
m_btnDetectAutomatically = new wxButton( sbSizer1->GetStaticBox(), wxID_ANY, _("Detect Automatically"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizer4->Add( m_btnDetectAutomatically, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
|
||||
sbSizer1->Add( bSizer4, 0, wxEXPAND, 5 );
|
||||
|
||||
m_stPythonStatus = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("No Python interpreter chosen; external Python plugins will not be available"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_stPythonStatus->Wrap( -1 );
|
||||
m_stPythonStatus->SetToolTip( _("Python interpreter status") );
|
||||
|
||||
sbSizer1->Add( m_stPythonStatus, 0, wxALL, 5 );
|
||||
|
||||
|
||||
bSizer8->Add( sbSizer1, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
bSizer8->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
bPanelSizer->Add( bSizer8, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bPanelSizer );
|
||||
this->Layout();
|
||||
bPanelSizer->Fit( this );
|
||||
|
||||
// Connect Events
|
||||
m_pickerPythonInterpreter->Connect( wxEVT_COMMAND_FILEPICKER_CHANGED, wxFileDirPickerEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnPythonInterpreterChanged ), NULL, this );
|
||||
m_btnDetectAutomatically->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnBtnDetectAutomaticallyClicked ), NULL, this );
|
||||
}
|
||||
|
||||
PANEL_PYTHON_SETTINGS_BASE::~PANEL_PYTHON_SETTINGS_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
m_pickerPythonInterpreter->Disconnect( wxEVT_COMMAND_FILEPICKER_CHANGED, wxFileDirPickerEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnPythonInterpreterChanged ), NULL, this );
|
||||
m_btnDetectAutomatically->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnBtnDetectAutomaticallyClicked ), NULL, this );
|
||||
|
||||
}
|
|
@ -0,0 +1,371 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="16" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">panel_python_settings_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">PanelPythonSettings</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">1</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Panel" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">PANEL_PYTHON_SETTINGS_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">-1,-1</property>
|
||||
<property name="subclass">RESETTABLE_PANEL; widgets/resettable_panel.h; Not forward_declare</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bPanelSizer</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer8</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticBoxSizer" expanded="1">
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Python Interpreter</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">sbSizer1</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="parent">1</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizer4</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Path to Python interpreter:</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticText2</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxFilePickerCtrl" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="message">Select the path to a Python interpreter</property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_pickerPythonInterpreter</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="wildcard">*.*</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnFileChanged">OnPythonInterpreterChanged</event>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="auth_needed">0</property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Detect Automatically</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_btnDetectAutomatically</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnButtonClick">OnBtnDetectAutomaticallyClicked</event>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">No Python interpreter chosen; external Python plugins will not be available</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_stPythonStatus</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">public</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip">Python interpreter status</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="spacer" expanded="1">
|
||||
<property name="height">0</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="width">0</property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
|
@ -0,0 +1,56 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
#include "widgets/resettable_panel.h"
|
||||
#include <wx/string.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/filepicker.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class PANEL_PYTHON_SETTINGS_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class PANEL_PYTHON_SETTINGS_BASE : public RESETTABLE_PANEL
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_staticText2;
|
||||
wxFilePickerCtrl* m_pickerPythonInterpreter;
|
||||
wxButton* m_btnDetectAutomatically;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
virtual void OnPythonInterpreterChanged( wxFileDirPickerEvent& event ) { event.Skip(); }
|
||||
virtual void OnBtnDetectAutomaticallyClicked( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
wxStaticText* m_stPythonStatus;
|
||||
|
||||
PANEL_PYTHON_SETTINGS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
|
||||
|
||||
~PANEL_PYTHON_SETTINGS_BASE();
|
||||
|
||||
};
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include <dialogs/panel_common_settings.h>
|
||||
#include <dialogs/panel_mouse_settings.h>
|
||||
#include <dialogs/panel_data_collection.h>
|
||||
#include <dialogs/panel_python_settings.h>
|
||||
#include <eda_dde.h>
|
||||
#include <file_history.h>
|
||||
#include <id.h>
|
||||
|
@ -1235,6 +1236,10 @@ void EDA_BASE_FRAME::ShowPreferences( wxString aStartPage, wxString aStartParent
|
|||
{
|
||||
}
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
book->AddPage( new PANEL_PYTHON_SETTINGS( book ), _( "Python Scripting" ) );
|
||||
#endif
|
||||
|
||||
// Update all of the action hotkeys. The process of loading the actions through
|
||||
// the KiFACE will only get us the default hotkeys
|
||||
ReadHotKeyConfigIntoActions( wxEmptyString, hotkeysPanel->ActionsList() );
|
||||
|
|
|
@ -260,6 +260,12 @@ wxString KIID::AsString() const
|
|||
}
|
||||
|
||||
|
||||
std::string KIID::AsStdString() const
|
||||
{
|
||||
return boost::uuids::to_string( m_uuid );
|
||||
}
|
||||
|
||||
|
||||
wxString KIID::AsLegacyTimestampString() const
|
||||
{
|
||||
return wxString::Format( "%8.8lX", (unsigned long) AsLegacyTimestamp() );
|
||||
|
|
|
@ -399,6 +399,17 @@ wxString PATHS::GetInstanceCheckerPath()
|
|||
}
|
||||
|
||||
|
||||
wxString PATHS::GetLogsPath()
|
||||
{
|
||||
wxFileName tmp;
|
||||
getUserDocumentPath( tmp );
|
||||
|
||||
tmp.AppendDir( wxT( "logs" ) );
|
||||
|
||||
return tmp.GetPath();
|
||||
}
|
||||
|
||||
|
||||
bool PATHS::EnsurePathExists( const wxString& aPath )
|
||||
{
|
||||
wxFileName path( aPath );
|
||||
|
|
|
@ -74,6 +74,10 @@
|
|||
#include <build_version.h>
|
||||
#endif
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_server.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Current list of languages supported by KiCad.
|
||||
*
|
||||
|
|
|
@ -53,7 +53,8 @@ COMMON_SETTINGS::COMMON_SETTINGS() :
|
|||
m_System(),
|
||||
m_DoNotShowAgain(),
|
||||
m_NetclassPanel(),
|
||||
m_PackageManager()
|
||||
m_PackageManager(),
|
||||
m_Python()
|
||||
{
|
||||
/*
|
||||
* Automatic dark mode detection works fine on Mac.
|
||||
|
@ -397,7 +398,8 @@ COMMON_SETTINGS::COMMON_SETTINGS() :
|
|||
m_params.emplace_back( new PARAM<bool>( "git.useDefaultAuthor",
|
||||
&m_Git.useDefaultAuthor, true ) );
|
||||
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "python.interpreter_path",
|
||||
&m_Python.interpreter_path, wxS( "" ) ) );
|
||||
|
||||
registerMigration( 0, 1, std::bind( &COMMON_SETTINGS::migrateSchema0to1, this ) );
|
||||
registerMigration( 1, 2, std::bind( &COMMON_SETTINGS::migrateSchema1to2, this ) );
|
||||
|
|
|
@ -58,6 +58,10 @@
|
|||
#include <sentry.h>
|
||||
#endif
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_server.h>
|
||||
#endif
|
||||
|
||||
// Only a single KIWAY is supported in this single_top top level component,
|
||||
// which is dedicated to loading only a single DSO.
|
||||
KIWAY Kiway( KFCTL_STANDALONE );
|
||||
|
@ -78,6 +82,10 @@ static struct PGM_SINGLE_TOP : public PGM_BASE
|
|||
|
||||
Kiway.OnKiwayEnd();
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_api_server.reset();
|
||||
#endif
|
||||
|
||||
if( m_settings_manager && m_settings_manager->IsOK() )
|
||||
{
|
||||
SaveCommonSettings();
|
||||
|
@ -350,6 +358,11 @@ bool PGM_SINGLE_TOP::OnPgmInit()
|
|||
|
||||
GetSettingsManager().RegisterSettings( new KICAD_SETTINGS );
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
// Create the API server thread once the app event loop exists
|
||||
m_api_server = std::make_unique<KICAD_API_SERVER>();
|
||||
#endif
|
||||
|
||||
// Use KIWAY to create a top window, which registers its existence also.
|
||||
// "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
|
||||
// and is one of the types in FRAME_T.
|
||||
|
@ -424,5 +437,9 @@ bool PGM_SINGLE_TOP::OnPgmInit()
|
|||
frame->OpenProjectFiles( fileArgs );
|
||||
}
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_api_server->SetReadyToReply();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -302,7 +302,7 @@ bool TOOL_MANAGER::doRunAction( const std::string& aActionName, bool aNow, const
|
|||
|
||||
doRunAction( *action, aNow, aParam, aCommit );
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ void SCH_MARKER::SwapData( SCH_ITEM* aItem )
|
|||
}
|
||||
|
||||
|
||||
wxString SCH_MARKER::Serialize() const
|
||||
wxString SCH_MARKER::SerializeToString() const
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> erc = std::static_pointer_cast<ERC_ITEM>( m_rcItem );
|
||||
wxString sheetSpecificPath, mainItemPath, auxItemPath;
|
||||
|
@ -109,7 +109,7 @@ wxString SCH_MARKER::Serialize() const
|
|||
}
|
||||
|
||||
|
||||
SCH_MARKER* SCH_MARKER::Deserialize( SCHEMATIC* schematic, const wxString& data )
|
||||
SCH_MARKER* SCH_MARKER::DeserializeFromString( SCHEMATIC* schematic, const wxString& data )
|
||||
{
|
||||
wxArrayString props = wxSplit( data, '|' );
|
||||
VECTOR2I markerPos( (int) strtol( props[1].c_str(), nullptr, 10 ),
|
||||
|
|
|
@ -53,8 +53,8 @@ public:
|
|||
|
||||
void SwapData( SCH_ITEM* aItem ) override;
|
||||
|
||||
wxString Serialize() const;
|
||||
static SCH_MARKER* Deserialize( SCHEMATIC* schematic, const wxString& data );
|
||||
wxString SerializeToString() const;
|
||||
static SCH_MARKER* DeserializeFromString( SCHEMATIC* schematic, const wxString& data );
|
||||
|
||||
void ViewGetLayers( int aLayers[], int& aCount ) const override;
|
||||
|
||||
|
|
|
@ -312,7 +312,7 @@ std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
|
|||
|
||||
for( auto it = settings.m_ErcExclusions.begin(); it != settings.m_ErcExclusions.end(); )
|
||||
{
|
||||
SCH_MARKER* testMarker = SCH_MARKER::Deserialize( this, *it );
|
||||
SCH_MARKER* testMarker = SCH_MARKER::DeserializeFromString( this, *it );
|
||||
|
||||
if( testMarker->IsLegacyMarker() )
|
||||
{
|
||||
|
@ -322,7 +322,7 @@ std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
|
|||
&& settingsKey != wxT( "hier_label_mismatch" )
|
||||
&& settingsKey != wxT( "different_unit_net" ) )
|
||||
{
|
||||
migratedExclusions.insert( testMarker->Serialize() );
|
||||
migratedExclusions.insert( testMarker->SerializeToString() );
|
||||
}
|
||||
|
||||
it = settings.m_ErcExclusions.erase( it );
|
||||
|
@ -344,7 +344,7 @@ std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
|
|||
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_MARKER_T ) )
|
||||
{
|
||||
SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
std::set<wxString>::iterator it = settings.m_ErcExclusions.find( serialized );
|
||||
|
||||
if( it != settings.m_ErcExclusions.end() )
|
||||
|
@ -359,7 +359,7 @@ std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
|
|||
|
||||
for( const wxString& serialized : settings.m_ErcExclusions )
|
||||
{
|
||||
SCH_MARKER* marker = SCH_MARKER::Deserialize( this, serialized );
|
||||
SCH_MARKER* marker = SCH_MARKER::DeserializeFromString( this, serialized );
|
||||
|
||||
if( marker )
|
||||
{
|
||||
|
@ -811,7 +811,7 @@ void SCHEMATIC::RecordERCExclusions()
|
|||
|
||||
if( marker->IsExcluded() )
|
||||
{
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
ercSettings.m_ErcExclusions.insert( serialized );
|
||||
ercSettings.m_ErcExclusionComments[ serialized ] = marker->GetComment();
|
||||
}
|
||||
|
|
|
@ -576,8 +576,11 @@ public:
|
|||
*/
|
||||
bool m_EnableCacheFriendlyFracture;
|
||||
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Log IPC API requests and responses
|
||||
*/
|
||||
bool m_EnableAPILogging;
|
||||
///@}
|
||||
|
||||
private:
|
||||
ADVANCED_CFG();
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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_HANDLER_H
|
||||
#define KICAD_API_HANDLER_H
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
#include <wx/debug.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#include <import_export.h>
|
||||
#include <api/common/envelope.pb.h>
|
||||
#include <core/typeinfo.h>
|
||||
|
||||
using kiapi::common::ApiRequest, kiapi::common::ApiResponse;
|
||||
using kiapi::common::ApiResponseStatus, kiapi::common::ApiStatusCode;
|
||||
|
||||
typedef tl::expected<ApiResponse, ApiResponseStatus> API_RESULT;
|
||||
|
||||
template <typename T>
|
||||
using HANDLER_RESULT = tl::expected<T, ApiResponseStatus>;
|
||||
|
||||
class API_HANDLER
|
||||
{
|
||||
public:
|
||||
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
|
||||
* @return a response to send to the client, or an appropriate error
|
||||
*/
|
||||
API_RESULT Handle( ApiRequest& aMsg );
|
||||
|
||||
static std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* A handler for outer messages (envelopes) that will unpack to inner messages and call a
|
||||
* specific handler function. @see registerHandler.
|
||||
*/
|
||||
typedef std::function<HANDLER_RESULT<ApiResponse>( ApiRequest& )> REQUEST_HANDLER;
|
||||
|
||||
/**
|
||||
* Registers an API command handler for the given message types.
|
||||
*
|
||||
* When an API request matching the given type comes in, the handler will be called and its
|
||||
* response will be packed into an envelope for sending back to the API client.
|
||||
*
|
||||
* If the given message does not unpack into the request type, an envelope is returned with
|
||||
* status AS_BAD_REQUEST, which probably indicates corruption in the message.
|
||||
*
|
||||
* @tparam RequestType is a protobuf message type containing a command
|
||||
* @tparam ResponseType is a protobuf message type containing a command response
|
||||
* @tparam HandlerType is the implied type of the API_HANDLER subclass
|
||||
* @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& ) )
|
||||
{
|
||||
std::string typeName = RequestType().GetTypeName();
|
||||
|
||||
wxASSERT_MSG( !m_handlers.count( typeName ),
|
||||
wxString::Format( "Duplicate API handler for type %s", typeName ) );
|
||||
|
||||
m_handlers[typeName] =
|
||||
[=]( ApiRequest& aRequest ) -> API_RESULT
|
||||
{
|
||||
RequestType command;
|
||||
ApiResponse envelope;
|
||||
|
||||
if( !tryUnpack( aRequest, envelope, command ) )
|
||||
return envelope;
|
||||
|
||||
HANDLER_RESULT<ResponseType> response =
|
||||
std::invoke( aHandler, static_cast<HandlerType*>( this ), command );
|
||||
|
||||
if( response.has_value() )
|
||||
{
|
||||
envelope.mutable_status()->set_status( ApiStatusCode::AS_OK );
|
||||
envelope.mutable_message()->PackFrom( *response );
|
||||
return envelope;
|
||||
}
|
||||
else
|
||||
{
|
||||
return tl::unexpected( response.error() );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Maps type name (without the URL prefix) to a handler method
|
||||
std::map<std::string, REQUEST_HANDLER> m_handlers;
|
||||
|
||||
private:
|
||||
|
||||
template<typename MessageType>
|
||||
bool tryUnpack( ApiRequest& aRequest, ApiResponse& aReply, MessageType& aDest )
|
||||
{
|
||||
if( !aRequest.message().UnpackTo( &aDest ) )
|
||||
{
|
||||
std::string msg = fmt::format( "could not unpack message of type {} from request",
|
||||
aDest.GetTypeName() );
|
||||
aReply.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
aReply.mutable_status()->set_error_message( msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //KICAD_API_HANDLER_H
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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_HANDLER_COMMON_H
|
||||
#define KICAD_API_HANDLER_COMMON_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>
|
||||
|
||||
using namespace kiapi;
|
||||
using namespace kiapi::common;
|
||||
|
||||
class API_HANDLER_COMMON : public API_HANDLER
|
||||
{
|
||||
public:
|
||||
API_HANDLER_COMMON();
|
||||
|
||||
private:
|
||||
HANDLER_RESULT<commands::GetVersionResponse> handleGetVersion( commands::GetVersion& aMsg );
|
||||
};
|
||||
|
||||
#endif //KICAD_API_HANDLER_COMMON_H
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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_SERVER_H
|
||||
#define KICAD_API_SERVER_H
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/filename.h>
|
||||
|
||||
class API_HANDLER;
|
||||
class API_HANDLER_COMMON;
|
||||
class KINNG_REQUEST_SERVER;
|
||||
class wxEvtHandler;
|
||||
|
||||
|
||||
wxDECLARE_EVENT( API_REQUEST_EVENT, wxCommandEvent );
|
||||
|
||||
|
||||
class KICAD_API_SERVER : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
KICAD_API_SERVER();
|
||||
|
||||
~KICAD_API_SERVER();
|
||||
|
||||
/**
|
||||
* Adds a new request handler to the server. Each handler maintains its own list of API
|
||||
* messages that it knows how to handle, and the server will pass every incoming message to all
|
||||
* handlers in succession until one of them handles it.
|
||||
*
|
||||
* The caller is responsible for the lifetime of the handler and must call DeregisterHandler
|
||||
* before the pointer is freed.
|
||||
*
|
||||
* @param aHandler is a pointer (non-owned) to API_HANDLER
|
||||
*/
|
||||
void RegisterHandler( API_HANDLER* aHandler );
|
||||
|
||||
void DeregisterHandler( API_HANDLER* aHandler );
|
||||
|
||||
void SetReadyToReply( bool aReady = true ) { m_readyToReply = aReady; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Callback that executes on the server thread and generates an event that will be handled by
|
||||
* the wxWidgets event loop to process an incoming request. Temporarily takes ownership of the
|
||||
* request pointer so that it can be passed through the event system.
|
||||
*
|
||||
* @param aRequest is a pointer to a string containing bytes that came in over the wire
|
||||
*/
|
||||
void onApiRequest( std::string* aRequest );
|
||||
|
||||
/**
|
||||
* Event handler that receives the event on the main thread sent by onApiRequest
|
||||
* @param aEvent will contain a pointer to an incoming API request string in the client data
|
||||
*/
|
||||
void handleApiEvent( wxCommandEvent& aEvent );
|
||||
|
||||
void log( const std::string& aOutput );
|
||||
|
||||
std::unique_ptr<KINNG_REQUEST_SERVER> m_server;
|
||||
|
||||
std::set<API_HANDLER*> m_handlers;
|
||||
|
||||
std::string m_token;
|
||||
|
||||
bool m_readyToReply;
|
||||
|
||||
std::unique_ptr<API_HANDLER_COMMON> m_commonHandler;
|
||||
|
||||
static wxString s_logFileName;
|
||||
|
||||
wxFileName m_logFilePath;
|
||||
};
|
||||
|
||||
#endif //KICAD_API_SERVER_H
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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_PANEL_PYTHON_SETTINGS_H
|
||||
#define KICAD_PANEL_PYTHON_SETTINGS_H
|
||||
|
||||
#include <dialogs/panel_python_settings_base.h>
|
||||
|
||||
class PAGED_DIALOG;
|
||||
|
||||
|
||||
class PANEL_PYTHON_SETTINGS : public PANEL_PYTHON_SETTINGS_BASE
|
||||
{
|
||||
public:
|
||||
PANEL_PYTHON_SETTINGS( wxWindow* aParent );
|
||||
|
||||
void ResetPanel() override;
|
||||
|
||||
protected:
|
||||
bool TransferDataFromWindow() override;
|
||||
bool TransferDataToWindow() override;
|
||||
|
||||
void OnPythonInterpreterChanged( wxFileDirPickerEvent& event ) override;
|
||||
void OnBtnDetectAutomaticallyClicked( wxCommandEvent& aEvent ) override;
|
||||
|
||||
private:
|
||||
void validateInterpreter();
|
||||
|
||||
bool m_interpreterValid;
|
||||
};
|
||||
|
||||
#endif //KICAD_PANEL_PYTHON_SETTINGS_H
|
|
@ -52,6 +52,8 @@ class UNITS_PROVIDER;
|
|||
class EDA_DRAW_FRAME;
|
||||
class MSG_PANEL_ITEM;
|
||||
|
||||
namespace google { namespace protobuf { class Any; } }
|
||||
|
||||
|
||||
/**
|
||||
* Used to inspect and possibly collect the (search) results of iterating over a list or
|
||||
|
@ -436,6 +438,10 @@ 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)
|
||||
|
||||
/**
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
|
||||
wxString AsString() const;
|
||||
wxString AsLegacyTimestampString() const;
|
||||
std::string AsStdString() const;
|
||||
|
||||
/**
|
||||
* Returns true if a string has the correct formatting to be a KIID.
|
||||
|
|
|
@ -61,8 +61,7 @@ enum PCB_LAYER_ID: int
|
|||
UNDEFINED_LAYER = -1,
|
||||
UNSELECTED_LAYER = -2,
|
||||
|
||||
PCBNEW_LAYER_ID_START = 0,
|
||||
F_Cu = PCBNEW_LAYER_ID_START,
|
||||
F_Cu = 0,
|
||||
In1_Cu,
|
||||
In2_Cu,
|
||||
In3_Cu,
|
||||
|
@ -138,6 +137,8 @@ enum PCB_LAYER_ID: int
|
|||
PCB_LAYER_ID_COUNT
|
||||
};
|
||||
|
||||
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START = F_Cu;
|
||||
|
||||
#define MAX_CU_LAYERS (B_Cu - F_Cu + 1)
|
||||
|
||||
/**
|
||||
|
|
|
@ -153,6 +153,11 @@ public:
|
|||
*/
|
||||
static wxString GetInstanceCheckerPath();
|
||||
|
||||
/**
|
||||
* Gets a path to use for user-visible log files
|
||||
*/
|
||||
static wxString GetLogsPath();
|
||||
|
||||
/**
|
||||
* Attempts to create a given path if it does not exist
|
||||
*/
|
||||
|
|
|
@ -52,6 +52,10 @@ class COMMON_SETTINGS;
|
|||
class SETTINGS_MANAGER;
|
||||
class SCRIPTING;
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
class KICAD_API_SERVER;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A small class to handle the list of existing translations.
|
||||
*
|
||||
|
@ -142,6 +146,10 @@ public:
|
|||
|
||||
virtual NOTIFICATIONS_MANAGER& GetNotificationsManager() const { return *m_notifications_manager; }
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
KICAD_API_SERVER& GetApiServer() { return *m_api_server; }
|
||||
#endif
|
||||
|
||||
virtual void SetTextEditor( const wxString& aFileName );
|
||||
|
||||
/**
|
||||
|
@ -403,6 +411,9 @@ protected:
|
|||
/// Checks if there is another copy of Kicad running at the same time
|
||||
std::unique_ptr<wxSingleInstanceChecker> m_pgm_checker;
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
std::unique_ptr<KICAD_API_SERVER> m_api_server;
|
||||
#endif
|
||||
|
||||
wxString m_kicad_env; /// The KICAD system environment variable.
|
||||
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
#include <wx/validate.h> // required for propgrid
|
||||
#include <wx/propgrid/property.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <wx/wxcrt.h>
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
|
|
@ -166,6 +166,11 @@ public:
|
|||
wxString authorEmail;
|
||||
};
|
||||
|
||||
struct PYTHON
|
||||
{
|
||||
wxString interpreter_path;
|
||||
};
|
||||
|
||||
COMMON_SETTINGS();
|
||||
|
||||
virtual ~COMMON_SETTINGS() {}
|
||||
|
@ -217,6 +222,8 @@ public:
|
|||
PACKAGE_MANAGER m_PackageManager;
|
||||
|
||||
GIT m_Git;
|
||||
|
||||
PYTHON m_Python;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -108,6 +108,11 @@ if( MSVC )
|
|||
set_target_properties(kicad-cli PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(kicad-cli PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(kicad-cli PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
||||
|
||||
# Allow running from build dir
|
||||
add_custom_command( TARGET kicad POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:kiapi>" "$<TARGET_FILE_DIR:kicad>"
|
||||
)
|
||||
endif()
|
||||
|
||||
if( UNIX )
|
||||
|
|
|
@ -57,6 +57,10 @@
|
|||
#include <kiplatform/app.h>
|
||||
#include <kiplatform/environment.h>
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_server.h>
|
||||
#endif
|
||||
|
||||
|
||||
// a dummy to quiet linking with EDA_BASE_FRAME::config();
|
||||
#include <kiface_base.h>
|
||||
|
@ -237,6 +241,10 @@ bool PGM_KICAD::OnPgmInit()
|
|||
|
||||
KICAD_SETTINGS* settings = static_cast<KICAD_SETTINGS*>( PgmSettings() );
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_api_server = std::make_unique<KICAD_API_SERVER>();
|
||||
#endif
|
||||
|
||||
wxString projToLoad;
|
||||
|
||||
HideSplash();
|
||||
|
@ -348,6 +356,10 @@ bool PGM_KICAD::OnPgmInit()
|
|||
frame->Show( true );
|
||||
frame->Raise();
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_api_server->SetReadyToReply();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -362,6 +374,10 @@ void PGM_KICAD::OnPgmExit()
|
|||
{
|
||||
Kiway.OnKiwayEnd();
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_api_server.reset();
|
||||
#endif
|
||||
|
||||
if( m_settings_manager && m_settings_manager->IsOK() )
|
||||
{
|
||||
SaveCommonSettings();
|
||||
|
|
|
@ -26,3 +26,7 @@ add_subdirectory( core )
|
|||
add_subdirectory( kimath )
|
||||
add_subdirectory( kiplatform )
|
||||
add_subdirectory( sexpr )
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
add_subdirectory( kinng )
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# 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/>.
|
||||
|
||||
set( KINNG_SRCS
|
||||
src/kinng.cpp
|
||||
)
|
||||
|
||||
add_library( kinng STATIC
|
||||
${KINNG_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries( kinng
|
||||
${NNG_LIBRARY}
|
||||
)
|
||||
|
||||
target_include_directories( kinng PUBLIC
|
||||
${PROJECT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_include_directories( kinng PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${NNG_INCLUDE_DIR}
|
||||
)
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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_KINNG_H
|
||||
#define KICAD_KINNG_H
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
|
||||
class KINNG_REQUEST_SERVER
|
||||
{
|
||||
public:
|
||||
KINNG_REQUEST_SERVER();
|
||||
|
||||
~KINNG_REQUEST_SERVER();
|
||||
|
||||
bool Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
void SetCallback( std::function<void(std::string*)> aFunc ) { m_callback = aFunc; }
|
||||
|
||||
void Reply( const std::string& aReply );
|
||||
|
||||
private:
|
||||
void listenThread();
|
||||
|
||||
std::thread m_thread;
|
||||
|
||||
std::atomic<bool> m_shutdown;
|
||||
|
||||
std::string m_socketUrl;
|
||||
|
||||
std::function<void(std::string*)> m_callback;
|
||||
|
||||
std::string m_pendingReply;
|
||||
|
||||
std::condition_variable m_replyReady;
|
||||
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
#endif //KICAD_KINNG_H
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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 <kinng.h>
|
||||
#include <nng/nng.h>
|
||||
#include <nng/protocol/reqrep0/rep.h>
|
||||
#include <nng/protocol/reqrep0/req.h>
|
||||
|
||||
|
||||
KINNG_REQUEST_SERVER::KINNG_REQUEST_SERVER() :
|
||||
m_callback()
|
||||
{
|
||||
#ifdef WIN32
|
||||
m_socketUrl = "ipc://\\.\\pipe\\kicad";
|
||||
#else
|
||||
m_socketUrl = "ipc:///tmp/kicad.sock";
|
||||
#endif
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
|
||||
KINNG_REQUEST_SERVER::~KINNG_REQUEST_SERVER()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
bool KINNG_REQUEST_SERVER::Start()
|
||||
{
|
||||
m_shutdown.store( false );
|
||||
m_thread = std::thread( [&]() { listenThread(); } );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void KINNG_REQUEST_SERVER::Stop()
|
||||
{
|
||||
if( !m_thread.joinable() )
|
||||
return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( m_mutex );
|
||||
m_replyReady.notify_all();
|
||||
}
|
||||
|
||||
m_shutdown.store( true );
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
|
||||
void KINNG_REQUEST_SERVER::Reply( const std::string& aReply )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( m_mutex );
|
||||
m_pendingReply = aReply;
|
||||
m_replyReady.notify_all();
|
||||
}
|
||||
|
||||
|
||||
void KINNG_REQUEST_SERVER::listenThread()
|
||||
{
|
||||
nng_socket socket;
|
||||
nng_listener listener;
|
||||
int retCode = 0;
|
||||
|
||||
retCode = nng_rep0_open( &socket );
|
||||
|
||||
if( retCode != 0 )
|
||||
return;
|
||||
|
||||
retCode = nng_listener_create( &listener, socket, m_socketUrl.c_str() );
|
||||
|
||||
if( retCode != 0 )
|
||||
return;
|
||||
|
||||
nng_socket_set_ms( socket, NNG_OPT_RECVTIMEO, 500 );
|
||||
|
||||
nng_listener_start( listener, 0 );
|
||||
|
||||
while( !m_shutdown.load() )
|
||||
{
|
||||
char* buf = nullptr;
|
||||
size_t sz;
|
||||
uint64_t val;
|
||||
|
||||
retCode = nng_recv( socket, &buf, &sz, NNG_FLAG_ALLOC );
|
||||
|
||||
if( retCode == NNG_ETIMEDOUT )
|
||||
continue;
|
||||
|
||||
if( retCode != 0 )
|
||||
{
|
||||
nng_free( buf, sz );
|
||||
break;
|
||||
}
|
||||
|
||||
std::string message( buf, sz );
|
||||
|
||||
if( m_callback )
|
||||
m_callback( &message );
|
||||
|
||||
std::unique_lock<std::mutex> lock( m_mutex );
|
||||
m_replyReady.wait( lock, [&]() { return !m_pendingReply.empty(); } );
|
||||
|
||||
retCode = nng_send( socket, const_cast<std::string::value_type*>( m_pendingReply.c_str() ),
|
||||
m_pendingReply.length(), 0 );
|
||||
|
||||
m_pendingReply.clear();
|
||||
}
|
||||
|
||||
nng_close( socket );
|
||||
}
|
|
@ -425,6 +425,12 @@ set( PCBNEW_SCRIPTING_PYTHON_HELPERS
|
|||
python/scripting/pcb_scripting_tool.cpp
|
||||
)
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
set( PCBNEW_SRCS ${PCBNEW_SRCS}
|
||||
api/api_handler_pcb.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
if( COMPILER_SUPPORTS_WARNINGS )
|
||||
# Only compile our source files with the warnings, since the SWIG generated
|
||||
|
@ -719,7 +725,6 @@ set( PCBNEW_KIFACE_LIBRARIES
|
|||
${PCBNEW_EXTRA_LIBS} # -lrt must follow Boost
|
||||
)
|
||||
|
||||
|
||||
target_link_libraries( pcbnew_kiface
|
||||
PRIVATE
|
||||
${PCBNEW_KIFACE_LIBRARIES}
|
||||
|
@ -742,6 +747,9 @@ if( WIN32 )
|
|||
add_custom_command( TARGET pcbnew POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:kicad_3dsg>" "$<TARGET_FILE_DIR:pcbnew>"
|
||||
)
|
||||
add_custom_command( TARGET pcbnew POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:kiapi>" "$<TARGET_FILE_DIR:pcbnew>"
|
||||
)
|
||||
endif()
|
||||
|
||||
# these 2 binaries are a matched set, keep them together:
|
||||
|
|
|
@ -0,0 +1,493 @@
|
|||
/*
|
||||
* 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_handler_pcb.h>
|
||||
#include <board_commit.h>
|
||||
#include <pcb_edit_frame.h>
|
||||
#include <pcb_track.h>
|
||||
#include <tool/tool_manager.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;
|
||||
|
||||
static const wxString s_defaultCommitMessage = wxS( "Modification from API" );
|
||||
|
||||
|
||||
API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) :
|
||||
API_HANDLER(),
|
||||
m_frame( 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 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<RunActionResponse> API_HANDLER_PCB::handleRunAction( RunAction& aRequest )
|
||||
{
|
||||
RunActionResponse response;
|
||||
|
||||
if( m_frame->GetToolManager()->RunAction( aRequest.action(), true ) )
|
||||
response.set_status( RunActionStatus::RAS_OK );
|
||||
else
|
||||
response.set_status( RunActionStatus::RAS_INVALID );
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<GetOpenDocumentsResponse> API_HANDLER_PCB::handleGetOpenDocuments(
|
||||
GetOpenDocuments& aMsg )
|
||||
{
|
||||
if( aMsg.type() != DocumentType::DOCTYPE_PCB )
|
||||
{
|
||||
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_PCB );
|
||||
doc.set_board_filename( fn.GetFullName() );
|
||||
|
||||
response.mutable_documents()->Add( std::move( doc ) );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<BeginCommitResponse> API_HANDLER_PCB::handleBeginCommit( BeginCommit& aMsg )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<EndCommitResponse> API_HANDLER_PCB::handleEndCommit( EndCommit& aMsg )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
BOARD_COMMIT* API_HANDLER_PCB::getCurrentCommit()
|
||||
{
|
||||
if( !m_commit )
|
||||
m_commit.reset( new BOARD_COMMIT( m_frame ) );
|
||||
|
||||
return m_commit.get();
|
||||
}
|
||||
|
||||
|
||||
void API_HANDLER_PCB::pushCurrentCommit( const std::string& aMessage )
|
||||
{
|
||||
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 )
|
||||
return false;
|
||||
|
||||
wxFileName fn( m_frame->GetCurrentFileName() );
|
||||
|
||||
return aHeader.document().board_filename().compare( fn.GetFullName() ) == 0;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> API_HANDLER_PCB::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 );
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<CreateItemsResponse> API_HANDLER_PCB::handleCreateItems( CreateItems& aMsg )
|
||||
{
|
||||
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();
|
||||
|
||||
CreateItemsResponse response;
|
||||
|
||||
for( const google::protobuf::Any& anyItem : aMsg.items() )
|
||||
{
|
||||
ItemCreationResult itemResult;
|
||||
std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
|
||||
|
||||
if( !type )
|
||||
{
|
||||
itemResult.set_status( ItemCreationStatus::ICS_INVALID_TYPE );
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<BOARD_ITEM> item = createItemForType( *type, board );
|
||||
|
||||
if( !item )
|
||||
{
|
||||
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 ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
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( itemUuidMap.count( item->m_Uuid ) )
|
||||
{
|
||||
itemResult.set_status( ItemCreationStatus::ICS_EXISTING );
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
itemResult.set_status( ItemCreationStatus::ICS_OK );
|
||||
item->Serialize( *itemResult.mutable_item() );
|
||||
commit->Add( item.release() );
|
||||
|
||||
response.mutable_created_items()->Add( std::move( itemResult ) );
|
||||
}
|
||||
|
||||
pushCurrentCommit( "Added items via API" );
|
||||
response.set_status( ItemRequestStatus::IRS_OK );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<GetItemsResponse> API_HANDLER_PCB::handleGetItems( GetItems& 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 );
|
||||
}
|
||||
|
||||
GetItemsResponse response;
|
||||
|
||||
BOARD* board = m_frame->GetBoard();
|
||||
std::vector<BOARD_ITEM*> items;
|
||||
std::set<KICAD_T> typesRequested, typesInserted;
|
||||
bool handledAnything = false;
|
||||
|
||||
for( const common::types::ItemType& typeMessage : aMsg.types() )
|
||||
{
|
||||
KICAD_T type;
|
||||
|
||||
if( std::optional<KICAD_T> opt_type = magic_enum::enum_cast<KICAD_T>( typeMessage.type() ) )
|
||||
type = *opt_type;
|
||||
else
|
||||
continue;
|
||||
|
||||
typesRequested.emplace( type );
|
||||
|
||||
if( typesInserted.count( type ) )
|
||||
continue;
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
handledAnything = true;
|
||||
std::copy( board->Tracks().begin(), board->Tracks().end(),
|
||||
std::back_inserter( items ) );
|
||||
typesInserted.insert( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !handledAnything )
|
||||
{
|
||||
ApiResponseStatus e;
|
||||
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
|
||||
e.set_error_message( "none of the requested types are valid for a Board object" );
|
||||
return tl::unexpected( e );
|
||||
}
|
||||
|
||||
for( const BOARD_ITEM* item : items )
|
||||
{
|
||||
if( !typesRequested.count( item->Type() ) )
|
||||
continue;
|
||||
|
||||
google::protobuf::Any itemBuf;
|
||||
item->Serialize( itemBuf );
|
||||
response.mutable_items()->Add( std::move( itemBuf ) );
|
||||
}
|
||||
|
||||
response.set_status( ItemRequestStatus::IRS_OK );
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
HANDLER_RESULT<UpdateItemsResponse> API_HANDLER_PCB::handleUpdateItems( UpdateItems& aMsg )
|
||||
{
|
||||
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();
|
||||
std::vector<BOARD_ITEM*> validatedItems;
|
||||
|
||||
for( BOARD_ITEM* item : items )
|
||||
{
|
||||
if( itemsToDelete.count( item->m_Uuid ) )
|
||||
{
|
||||
validatedItems.push_back( item );
|
||||
itemsToDelete[item->m_Uuid] = 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();
|
||||
|
||||
for( BOARD_ITEM* item : validatedItems )
|
||||
commit->Remove( item );
|
||||
|
||||
if( !m_transactionInProgress )
|
||||
pushCurrentCommit( "Deleted items via API" );
|
||||
|
||||
DeleteItemsResponse response;
|
||||
|
||||
for( const auto& [id, status] : itemsToDelete )
|
||||
{
|
||||
ItemDeletionResult result;
|
||||
result.mutable_id()->set_value( id.AsStdString() );
|
||||
result.set_status( status );
|
||||
}
|
||||
|
||||
response.set_status( ItemRequestStatus::IRS_OK );
|
||||
return response;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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_HANDLER_PCB_H
|
||||
#define KICAD_API_HANDLER_PCB_H
|
||||
|
||||
#include <google/protobuf/empty.pb.h>
|
||||
|
||||
#include <api/api_handler.h>
|
||||
|
||||
#include <api/common/commands/editor_commands.pb.h>
|
||||
|
||||
#include <properties/property_mgr.h>
|
||||
|
||||
using namespace kiapi;
|
||||
using namespace kiapi::common;
|
||||
|
||||
using google::protobuf::Empty;
|
||||
|
||||
|
||||
class BOARD_COMMIT;
|
||||
class BOARD_ITEM;
|
||||
class BOARD_ITEM_CONTAINER;
|
||||
class EDA_ITEM;
|
||||
class PCB_EDIT_FRAME;
|
||||
class PCB_TRACK;
|
||||
class PROPERTY_BASE;
|
||||
|
||||
|
||||
class API_HANDLER_PCB : public API_HANDLER
|
||||
{
|
||||
public:
|
||||
API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame );
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, PROPERTY_BASE*> PROTO_PROPERTY_MAP;
|
||||
|
||||
static std::unique_ptr<BOARD_ITEM> createItemForType( KICAD_T aType,
|
||||
BOARD_ITEM_CONTAINER* aContainer );
|
||||
|
||||
HANDLER_RESULT<commands::RunActionResponse> handleRunAction( commands::RunAction& aMsg );
|
||||
|
||||
HANDLER_RESULT<commands::GetOpenDocumentsResponse> handleGetOpenDocuments(
|
||||
commands::GetOpenDocuments& aMsg );
|
||||
|
||||
HANDLER_RESULT<commands::BeginCommitResponse> handleBeginCommit( commands::BeginCommit& aMsg );
|
||||
HANDLER_RESULT<commands::EndCommitResponse> handleEndCommit( commands::EndCommit& aMsg );
|
||||
|
||||
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 );
|
||||
|
||||
private:
|
||||
|
||||
bool validateItemHeaderDocument( const common::types::ItemHeader& aHeader );
|
||||
|
||||
BOARD_COMMIT* getCurrentCommit();
|
||||
|
||||
void pushCurrentCommit( const std::string& aMessage );
|
||||
|
||||
PCB_EDIT_FRAME* m_frame;
|
||||
|
||||
std::unique_ptr<BOARD_COMMIT> m_commit;
|
||||
|
||||
bool m_transactionInProgress;
|
||||
};
|
||||
|
||||
#endif //KICAD_API_HANDLER_PCB_H
|
|
@ -337,7 +337,7 @@ void BOARD::RecordDRCExclusions()
|
|||
{
|
||||
if( marker->IsExcluded() )
|
||||
{
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
m_designSettings->m_DrcExclusions.insert( serialized );
|
||||
m_designSettings->m_DrcExclusionComments[ serialized ] = marker->GetComment();
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ std::vector<PCB_MARKER*> BOARD::ResolveDRCExclusions( bool aCreateMarkers )
|
|||
|
||||
for( PCB_MARKER* marker : GetBoard()->Markers() )
|
||||
{
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
std::set<wxString>::iterator it = exclusions.find( serialized );
|
||||
|
||||
if( it != exclusions.end() )
|
||||
|
@ -376,7 +376,7 @@ std::vector<PCB_MARKER*> BOARD::ResolveDRCExclusions( bool aCreateMarkers )
|
|||
{
|
||||
for( const wxString& serialized : exclusions )
|
||||
{
|
||||
PCB_MARKER* marker = PCB_MARKER::Deserialize( serialized );
|
||||
PCB_MARKER* marker = PCB_MARKER::DeserializeFromString( serialized );
|
||||
|
||||
if( !marker )
|
||||
continue;
|
||||
|
|
|
@ -710,7 +710,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
|
|||
|
||||
marker->SetExcluded( true, dlg.GetValue() );
|
||||
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
m_frame->GetDesignSettings().m_DrcExclusions.insert( serialized );
|
||||
m_frame->GetDesignSettings().m_DrcExclusionComments[ serialized ] = dlg.GetValue();
|
||||
|
||||
|
@ -726,7 +726,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
|
|||
{
|
||||
marker->SetExcluded( false );
|
||||
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
m_frame->GetDesignSettings().m_DrcExclusions.erase( serialized );
|
||||
m_frame->GetDesignSettings().m_DrcExclusionComments.erase( serialized );
|
||||
|
||||
|
@ -758,7 +758,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
|
|||
|
||||
marker->SetExcluded( true, dlg.GetValue() );
|
||||
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
m_frame->GetDesignSettings().m_DrcExclusions.insert( serialized );
|
||||
m_frame->GetDesignSettings().m_DrcExclusionComments[ serialized ] = dlg.GetValue();
|
||||
|
||||
|
@ -792,7 +792,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
|
|||
{
|
||||
marker->SetExcluded( false );
|
||||
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
m_frame->GetDesignSettings().m_DrcExclusions.erase( serialized );
|
||||
m_frame->GetDesignSettings().m_DrcExclusionComments.erase( serialized );
|
||||
}
|
||||
|
@ -812,7 +812,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
|
|||
{
|
||||
marker->SetExcluded( true );
|
||||
|
||||
wxString serialized = marker->Serialize();
|
||||
wxString serialized = marker->SerializeToString();
|
||||
m_frame->GetDesignSettings().m_DrcExclusions.insert( serialized );
|
||||
}
|
||||
}
|
||||
|
@ -1082,7 +1082,7 @@ void DIALOG_DRC::ExcludeMarker()
|
|||
if( marker && marker->GetSeverity() != RPT_SEVERITY_EXCLUSION )
|
||||
{
|
||||
marker->SetExcluded( true );
|
||||
m_frame->GetDesignSettings().m_DrcExclusions.insert( marker->Serialize() );
|
||||
m_frame->GetDesignSettings().m_DrcExclusions.insert( marker->SerializeToString() );
|
||||
m_frame->GetCanvas()->GetView()->Update( marker );
|
||||
|
||||
// Update view
|
||||
|
|
|
@ -109,6 +109,11 @@
|
|||
#include <footprint_viewer_frame.h>
|
||||
#include <footprint_chooser_frame.h>
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_server.h>
|
||||
#include <api/api_handler_pcb.h>
|
||||
#endif
|
||||
|
||||
#include <action_plugin.h>
|
||||
#include <pcbnew_scripting_helpers.h>
|
||||
#include "../scripting/python_scripting.h"
|
||||
|
@ -426,6 +431,11 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
// Sync action plugins in case they changed since the last time the frame opened
|
||||
GetToolManager()->RunAction( PCB_ACTIONS::pluginsReload );
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
m_apiHandler = std::make_unique<API_HANDLER_PCB>( this );
|
||||
Pgm().GetApiServer().RegisterHandler( m_apiHandler.get() );
|
||||
#endif
|
||||
|
||||
GetCanvas()->SwitchBackend( m_canvasType );
|
||||
ActivateGalCanvas();
|
||||
|
||||
|
@ -517,6 +527,16 @@ PCB_EDIT_FRAME::~PCB_EDIT_FRAME()
|
|||
delete m_eventCounterTimer;
|
||||
}
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
Pgm().GetApiServer().DeregisterHandler( m_apiHandler.get() );
|
||||
#endif
|
||||
|
||||
// Close modeless dialogs
|
||||
wxWindow* open_dlg = wxWindow::FindWindowByName( DIALOG_DRC_WINDOW_NAME );
|
||||
|
||||
if( open_dlg )
|
||||
open_dlg->Close( true );
|
||||
|
||||
// Shutdown all running tools
|
||||
if( m_toolManager )
|
||||
m_toolManager->ShutdownAllTools();
|
||||
|
|
|
@ -58,6 +58,11 @@ class ACTION_MENU;
|
|||
class TOOL_ACTION;
|
||||
class STRING_UTF8_MAP;
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
class KICAD_API_SERVER;
|
||||
class API_HANDLER_PCB;
|
||||
#endif
|
||||
|
||||
enum LAST_PATH_TYPE : unsigned int;
|
||||
|
||||
namespace PCB { struct IFACE; } // KIFACE is in pcbnew.cpp
|
||||
|
@ -856,6 +861,10 @@ private:
|
|||
wxTimer m_redrawNetnamesTimer;
|
||||
|
||||
wxTimer* m_eventCounterTimer;
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
std::unique_ptr<API_HANDLER_PCB> m_apiHandler;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // __PCB_EDIT_FRAME_H__
|
||||
|
|
|
@ -93,7 +93,7 @@ PCB_MARKER::~PCB_MARKER()
|
|||
}
|
||||
|
||||
|
||||
wxString PCB_MARKER::Serialize() const
|
||||
wxString PCB_MARKER::SerializeToString() const
|
||||
{
|
||||
if( m_rcItem->GetErrorCode() == DRCE_COPPER_SLIVER )
|
||||
{
|
||||
|
@ -137,7 +137,7 @@ wxString PCB_MARKER::Serialize() const
|
|||
}
|
||||
|
||||
|
||||
PCB_MARKER* PCB_MARKER::Deserialize( const wxString& data )
|
||||
PCB_MARKER* PCB_MARKER::DeserializeFromString( const wxString& data )
|
||||
{
|
||||
auto getMarkerLayer =
|
||||
[]( const wxString& layerName ) -> int
|
||||
|
@ -367,4 +367,4 @@ static struct PCB_MARKER_DESC
|
|||
_HKI( "Locked" ),
|
||||
[]( INSPECTABLE* aItem ) { return false; } );
|
||||
}
|
||||
} _PCB_MARKER_DESC;
|
||||
} _PCB_MARKER_DESC;
|
||||
|
|
|
@ -52,9 +52,9 @@ public:
|
|||
|
||||
const KIID GetUUID() const override { return m_Uuid; }
|
||||
|
||||
wxString Serialize() const;
|
||||
wxString SerializeToString() const;
|
||||
|
||||
static PCB_MARKER* Deserialize( const wxString& data );
|
||||
static PCB_MARKER* DeserializeFromString( const wxString& data );
|
||||
|
||||
void Move( const VECTOR2I& aMoveVector ) override
|
||||
{
|
||||
|
|
|
@ -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 <pcb_base_frame.h>
|
||||
#include <core/mirror.h>
|
||||
|
@ -44,6 +45,9 @@
|
|||
#include <pcb_painter.h>
|
||||
#include <trigo.h>
|
||||
|
||||
#include <google/protobuf/any.pb.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
|
||||
using KIGFX::PCB_PAINTER;
|
||||
using KIGFX::PCB_RENDER_SETTINGS;
|
||||
|
||||
|
@ -287,6 +291,196 @@ double PCB_VIA::Similarity( const BOARD_ITEM& aOther ) const
|
|||
}
|
||||
|
||||
|
||||
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_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_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
track.mutable_net()->set_code( GetNetCode() );
|
||||
track.mutable_net()->set_name( GetNetname() );
|
||||
|
||||
aContainer.PackFrom( track );
|
||||
}
|
||||
|
||||
|
||||
bool PCB_TRACK::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::Track track;
|
||||
|
||||
if( !aContainer.UnpackTo( &track ) )
|
||||
return false;
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = KIID( track.id().value() );
|
||||
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() );
|
||||
SetLocked( track.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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_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_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
arc.mutable_net()->set_code( GetNetCode() );
|
||||
arc.mutable_net()->set_name( GetNetname() );
|
||||
|
||||
aContainer.PackFrom( arc );
|
||||
}
|
||||
|
||||
|
||||
bool PCB_ARC::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::Arc arc;
|
||||
|
||||
if( !aContainer.UnpackTo( &arc ) )
|
||||
return false;
|
||||
|
||||
const_cast<KIID&>( m_Uuid ) = KIID( arc.id().value() );
|
||||
SetStart( VECTOR2I( arc.start().x_nm(), arc.start().y_nm() ) );
|
||||
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() );
|
||||
SetLocked( arc.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
kiapi::board::types::Via via;
|
||||
|
||||
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 );
|
||||
|
||||
kiapi::board::types::UnconnectedLayerRemoval ulr;
|
||||
|
||||
if( m_removeUnconnectedLayer )
|
||||
{
|
||||
if( m_keepStartEndLayer )
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: Microvia status is ignored here. Do we still need it?
|
||||
|
||||
padstack->set_unconnected_layer_removal( ulr );
|
||||
|
||||
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()->set_name( GetNetname() );
|
||||
|
||||
aContainer.PackFrom( via );
|
||||
}
|
||||
|
||||
|
||||
bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
|
||||
{
|
||||
kiapi::board::types::Via via;
|
||||
|
||||
if( !aContainer.UnpackTo( &via ) )
|
||||
return false;
|
||||
|
||||
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() );
|
||||
|
||||
const kiapi::board::types::PadStack& padstack = via.pad_stack();
|
||||
|
||||
switch( padstack.type() )
|
||||
{
|
||||
case kiapi::board::types::PadStackType::PST_BLIND_BURIED:
|
||||
SetViaType( VIATYPE::BLIND_BURIED );
|
||||
break;
|
||||
|
||||
default:
|
||||
SetViaType( VIATYPE::THROUGH );
|
||||
break;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_layer = F_Cu;
|
||||
m_bottomLayer = B_Cu;
|
||||
}
|
||||
|
||||
switch( padstack.unconnected_layer_removal() )
|
||||
{
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepStartEndLayer = false;
|
||||
break;
|
||||
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepStartEndLayer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP:
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepStartEndLayer = false;
|
||||
break;
|
||||
}
|
||||
|
||||
SetNetCode( via.net().code() );
|
||||
SetLocked( via.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PCB_TRACK::ApproxCollinear( const PCB_TRACK& aTrack )
|
||||
{
|
||||
SEG a( m_Start, m_End );
|
||||
|
|
|
@ -260,6 +260,9 @@ public:
|
|||
bool operator()( const PCB_TRACK* aFirst, const PCB_TRACK* aSecond ) const;
|
||||
};
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
#if defined (DEBUG)
|
||||
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
|
||||
#endif
|
||||
|
@ -361,6 +364,9 @@ public:
|
|||
|
||||
bool operator==( const BOARD_ITEM& aOther ) const override;
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
protected:
|
||||
virtual void swapData( BOARD_ITEM* aImage ) override;
|
||||
|
||||
|
@ -595,6 +601,9 @@ public:
|
|||
|
||||
bool operator==( const BOARD_ITEM& aOther ) const override;
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
protected:
|
||||
void swapData( BOARD_ITEM* aImage ) override;
|
||||
|
||||
|
|
|
@ -23,3 +23,7 @@
|
|||
|
||||
add_subdirectory( sexpr )
|
||||
add_subdirectory( kimath )
|
||||
|
||||
if( KICAD_IPC_API )
|
||||
add_subdirectory( kinng )
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# 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/>.
|
||||
|
||||
set( QA_KINNG_SRCS
|
||||
kinng_test_module.cpp
|
||||
test_kinng.cpp
|
||||
)
|
||||
|
||||
add_executable( qa_kinng
|
||||
${QA_KINNG_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries( qa_kinng
|
||||
qa_utils
|
||||
kinng
|
||||
kiapi
|
||||
${NNG_LIBRARY}
|
||||
${wxWidgets_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories( qa_kinng PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/qa/mocks/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
kicad_add_boost_test( qa_kinng qa_kinng )
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define BOOST_TEST_MODULE KiNNG
|
||||
#include <boost/test/unit_test.hpp>
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 <qa_utils/wx_utils/unit_test_utils.h>
|
||||
#include <kinng.h>
|
||||
|
||||
#include <import_export.h>
|
||||
#include <api/common/envelope.pb.h>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( KiNNG )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( CreateIPCResponder )
|
||||
{
|
||||
KINNG_REQUEST_SERVER server;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -67,7 +67,7 @@ BOOST_FIXTURE_TEST_CASE( DRCCustomRuleSeverityTest, DRC_REGRESSION_TEST_FIXTURE
|
|||
{
|
||||
PCB_MARKER temp( aItem, aPos );
|
||||
|
||||
if( bds.m_DrcExclusions.find( temp.Serialize() ) == bds.m_DrcExclusions.end() )
|
||||
if( bds.m_DrcExclusions.find( temp.SerializeToString() ) == bds.m_DrcExclusions.end() )
|
||||
violations.push_back( *aItem );
|
||||
} );
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ BOOST_FIXTURE_TEST_CASE( DRCCopperGraphicsTest, DRC_COPPER_GRAPHICS_TEST_FIXTURE
|
|||
{
|
||||
PCB_MARKER temp( aItem, aPos );
|
||||
|
||||
if( bds.m_DrcExclusions.find( temp.Serialize() ) == bds.m_DrcExclusions.end() )
|
||||
if( bds.m_DrcExclusions.find( temp.SerializeToString() ) == bds.m_DrcExclusions.end() )
|
||||
violations.push_back( *aItem );
|
||||
} );
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ BOOST_FIXTURE_TEST_CASE( DRCFalseNegativeRegressions, DRC_REGRESSION_TEST_FIXTUR
|
|||
{
|
||||
PCB_MARKER temp( aItem, aPos );
|
||||
|
||||
if( bds.m_DrcExclusions.find( temp.Serialize() ) == bds.m_DrcExclusions.end() )
|
||||
if( bds.m_DrcExclusions.find( temp.SerializeToString() ) == bds.m_DrcExclusions.end() )
|
||||
violations.push_back( *aItem );
|
||||
} );
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ BOOST_FIXTURE_TEST_CASE( DRCSolderMaskBridgingTest, DRC_SOLDER_MASK_BRIDGING_TES
|
|||
{
|
||||
PCB_MARKER temp( aItem, aPos );
|
||||
|
||||
if( bds.m_DrcExclusions.find( temp.Serialize() ) == bds.m_DrcExclusions.end() )
|
||||
if( bds.m_DrcExclusions.find( temp.SerializeToString() ) == bds.m_DrcExclusions.end() )
|
||||
violations.push_back( *aItem );
|
||||
} );
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
set( KIPYTHON_SRCS
|
||||
kipython_settings.cpp
|
||||
python_manager.cpp
|
||||
)
|
||||
|
||||
add_library( scripting STATIC
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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 <wx/process.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "python_manager.h"
|
||||
|
||||
class PYTHON_PROCESS : public wxProcess
|
||||
{
|
||||
public:
|
||||
PYTHON_PROCESS( std::function<void(int, const wxString&)> aCallback ) :
|
||||
wxProcess(),
|
||||
m_callback( std::move( aCallback ) )
|
||||
{}
|
||||
|
||||
void OnTerminate( int aPid, int aStatus ) override
|
||||
{
|
||||
if( m_callback )
|
||||
{
|
||||
wxString output;
|
||||
wxInputStream* processOut = GetInputStream();
|
||||
size_t bytesRead = 0;
|
||||
|
||||
while( processOut->CanRead() && bytesRead < MAX_OUTPUT_LEN )
|
||||
{
|
||||
char buffer[4096];
|
||||
buffer[ processOut->Read( buffer, sizeof( buffer ) - 1 ).LastRead() ] = '\0';
|
||||
output.append( buffer, sizeof( buffer ) );
|
||||
bytesRead += processOut->LastRead();
|
||||
}
|
||||
|
||||
m_callback( aStatus, output );
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr size_t MAX_OUTPUT_LEN = 1024L * 1024L;
|
||||
|
||||
private:
|
||||
std::function<void(int, const wxString&)> m_callback;
|
||||
};
|
||||
|
||||
|
||||
void PYTHON_MANAGER::Execute( const wxString& aArgs,
|
||||
const std::function<void( int, const wxString& )>& aCallback )
|
||||
{
|
||||
PYTHON_PROCESS* process = new PYTHON_PROCESS( aCallback );
|
||||
process->Redirect();
|
||||
|
||||
wxString cmd = wxString::Format( wxS( "%s %s" ), m_interpreterPath, aArgs );
|
||||
long pid = wxExecute( cmd, wxEXEC_ASYNC, process );
|
||||
|
||||
if( pid == 0 )
|
||||
aCallback( -1, wxEmptyString );
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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_PYTHON_MANAGER_H
|
||||
#define KICAD_PYTHON_MANAGER_H
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include <wx/wx.h>
|
||||
|
||||
|
||||
class PYTHON_MANAGER
|
||||
{
|
||||
public:
|
||||
PYTHON_MANAGER( const wxString& aInterpreterPath ) :
|
||||
m_interpreterPath( aInterpreterPath )
|
||||
{}
|
||||
|
||||
void Execute( const wxString& aArgs,
|
||||
const std::function<void(int, const wxString&)>& aCallback );
|
||||
|
||||
wxString GetInterpreterPath() const { return m_interpreterPath; }
|
||||
void SetInterpreterPath( const wxString& aPath ) { m_interpreterPath = aPath; }
|
||||
|
||||
private:
|
||||
wxString m_interpreterPath;
|
||||
};
|
||||
|
||||
|
||||
#endif //KICAD_PYTHON_MANAGER_H
|
|
@ -39,6 +39,7 @@ add_subdirectory( clipper2 )
|
|||
add_subdirectory( compoundfilereader )
|
||||
add_subdirectory( delaunator )
|
||||
add_subdirectory( dxflib_qcad )
|
||||
add_subdirectory( expected )
|
||||
set( FMT_INSTALL OFF )
|
||||
add_subdirectory( fmt )
|
||||
add_subdirectory( gzip-hpp )
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
add_library( expected INTERFACE )
|
||||
|
||||
target_include_directories( expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include )
|
||||
|
||||
target_sources( expected INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/tl/expected.hpp
|
||||
)
|
|
@ -0,0 +1,121 @@
|
|||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
|
@ -0,0 +1,4 @@
|
|||
This directory contains the expected library from https://github.com/TartanLlama/expected
|
||||
|
||||
It is licensed under CC0-1.0, with the license text in the COPYING file in this directory.
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -40,7 +40,9 @@
|
|||
"icu",
|
||||
"ngspice",
|
||||
"wxpython",
|
||||
"libgit2"
|
||||
"libgit2",
|
||||
"nng",
|
||||
"protobuf"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue