23#include <fmt/ranges.h>
24#include <magic_enum.hpp>
53#include <api/common/types/base_types.pb.h>
55using namespace kiapi::common::commands;
56using types::CommandStatus;
58using types::DocumentType;
59using types::ItemRequestStatus;
112 const std::string& aCommandName )
const
118 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
119 e.set_error_message( fmt::format(
"{} is not available in headless mode", aCommandName ) );
131 const wxString& aMessage )
143 bool isFootprintEditor =
thisDocumentType() == kiapi::common::types::DOCTYPE_FOOTPRINT;
145 return std::make_unique<BOARD_COMMIT>(
toolManager(), !isFootprintEditor, isFootprintEditor );
166 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
167 e.set_error_message(
"Tried to create an item in a null container" );
168 return tl::unexpected( e );
174 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
175 e.set_error_message( fmt::format(
"Tried to create a pad in {}, which is not a footprint",
177 return tl::unexpected( e );
182 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
183 e.set_error_message( fmt::format(
"Tried to create a footprint in {}, which is not a board",
185 return tl::unexpected( e );
188 if(
dynamic_cast<FOOTPRINT*
>( aContainer ) )
190 static const std::set<KICAD_T> s_footprintItemTypes = {
197 if( !s_footprintItemTypes.contains( aType ) )
200 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
201 e.set_error_message( fmt::format(
"items of type {} cannot be created in a footprint",
202 magic_enum::enum_name( aType ) ) );
203 return tl::unexpected( e );
212 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
213 e.set_error_message( fmt::format(
"Tried to create an item of type {}, which is unhandled",
214 magic_enum::enum_name( aType ) ) );
215 return tl::unexpected( e );
223 const std::string& aClientName )
226 std::vector<BOARD_ITEM*> validatedItems;
228 for( std::pair<const KIID, ItemDeletionStatus> pair : aItemsToDelete )
236 aItemsToDelete[pair.first] = ItemDeletionStatus::IDS_IMMUTABLE;
240 validatedItems.push_back( item );
241 aItemsToDelete[pair.first] = ItemDeletionStatus::IDS_OK;
260 static_cast<PCB_TABLECELL*
>( item )->SetText( wxEmptyString );
302 const std::vector<PCB_GENERATOR*>& aGenerators,
303 std::function<
void(
const KIID&, ItemStatus )> aResultHandler )
const
313 generator->EditStart( aTool,
board, aCommit );
314 bool ok = generator->Update( aTool,
board, aCommit );
315 generator->EditFinish( aTool,
board, aCommit );
317 status.set_code( ok ? ItemStatusCode::ISC_OK : ItemStatusCode::ISC_INVALID_DATA );
320 status.set_error_message(
"the generator reported an update failure" );
322 catch(
const std::exception& exc )
324 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
325 status.set_error_message( fmt::format(
"regeneration exception: {}", exc.what() ) );
329 aResultHandler( generator->m_Uuid, status );
335 const DocumentSpecifier& aDocument,
const KIID& aId )
345 const std::string& aClientName,
346 const types::ItemHeader &aHeader,
347 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
348 std::function<
void( ItemStatus, google::protobuf::Any )> aItemHandler )
354 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
357 e.set_status( ApiStatusCode::AS_UNHANDLED );
358 return tl::unexpected( e );
360 else if( !containerResult )
362 e.CopyFrom( containerResult.error() );
363 return tl::unexpected( e );
369 if( containerResult->has_value() )
371 const KIID& containerId = **containerResult;
372 std::optional<BOARD_ITEM*> optItem =
getItemById( containerId );
380 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
381 e.set_error_message( fmt::format(
"The requested container {} is not a valid board item container",
383 return tl::unexpected( e );
388 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
389 e.set_error_message( fmt::format(
"The requested container {} does not exist in this document",
391 return tl::unexpected( e );
398 for(
const google::protobuf::Any& anyItem : aItems )
405 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
406 status.set_error_message( fmt::format(
"Could not decode a valid type from {}", anyItem.type_url() ) );
407 aItemHandler( status, anyItem );
413 board::types::Dimension dimension;
414 anyItem.UnpackTo( &dimension );
416 switch( dimension.dimension_style_case() )
423 case board::types::Dimension::DIMENSION_STYLE_NOT_SET:
break;
429 board::types::BoardGraphicShape shape;
430 anyItem.UnpackTo( &shape );
432 if( shape.has_pad_custom_shape_options() )
434 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
435 status.set_error_message(
"pad_custom_shape_options are only valid on shapes inside a pad's "
436 "padstack custom shapes" );
437 aItemHandler( status, anyItem );
451 ItemStatus genStatus;
452 genStatus.set_code( ItemStatusCode::ISC_INVALID_TYPE );
453 genStatus.set_error_message( fmt::format(
"could not decode a generator from {}",
454 anyItem.type_url() ) );
455 aItemHandler( genStatus, anyItem );
463 ItemStatus genStatus;
464 genStatus.set_code( ItemStatusCode::ISC_INVALID_TYPE );
465 genStatus.set_error_message( fmt::format(
"generator type {} is not registered",
466 generatorType->ToStdString() ) );
467 aItemHandler( genStatus, anyItem );
477 if( !creationResult || !creationResult.value() )
479 if( !creationResult )
481 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
482 status.set_error_message( creationResult.error().error_message() );
483 aItemHandler( status, anyItem );
489 std::unique_ptr<BOARD_ITEM> item( std::move( *creationResult ) );
491 bool unpacked =
false;
494 unpacked = item->Deserialize( anyItem );
496 unpacked =
group->DeserializeGroup( anyItem, commit );
498 unpacked = item->Deserialize( anyItem );
504 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
505 e.set_error_message( fmt::format(
"could not unpack {} from request",
506 item->GetClass().ToStdString() ) );
507 return tl::unexpected( e );
510 if( std::vector<wxString> removed = item->RemoveConflictingCustomProperties(); !removed.empty() )
513 [](
const wxString& aIn )
515 return std::string( aIn.ToUTF8() );
518 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
519 status.set_error_message( fmt::format(
"Invalid custom properties for item {}: property name(s) '{}' "
521 item->m_Uuid.AsStdString(),
522 fmt::join( std::views::transform( removed, as_str ),
", " ) ) );
524 aItemHandler( status, anyItem );
528 std::optional<BOARD_ITEM*> optItem =
getItemById( item->m_Uuid );
530 if( aCreate && optItem )
532 status.set_code( ItemStatusCode::ISC_EXISTING );
533 status.set_error_message( fmt::format(
"an item with UUID {} already exists",
534 item->m_Uuid.AsStdString() ) );
535 aItemHandler( status, anyItem );
538 else if( !aCreate && !optItem )
540 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
541 status.set_error_message( fmt::format(
"an item with UUID {} does not exist",
542 item->m_Uuid.AsStdString() ) );
543 aItemHandler( status, anyItem );
547 if( !aCreate && ( *optItem )->Type() != item->Type() )
549 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
550 status.set_error_message( fmt::format(
"item {} is of type {}, not {}",
551 item->m_Uuid.AsStdString(),
552 magic_enum::enum_name( ( *optItem )->Type() ),
553 magic_enum::enum_name( item->Type() ) ) );
554 aItemHandler( status, anyItem );
559 && !item->FitsEnabledLayers(
board->GetEnabledLayers(),
board->GetCopperLayerCount() ) )
561 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
562 status.set_error_message(
"attempted to add item with no overlapping layers with the board" );
563 aItemHandler( status, anyItem );
567 status.set_code( ItemStatusCode::ISC_OK );
568 google::protobuf::Any newItem;
581 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
582 status.set_error_message(
"a table cell must target a table container" );
583 aItemHandler( status, anyItem );
589 table->AddCell( cell );
607 item->Serialize( newItem );
608 commit->
Add( item.release() );
626 commit->
Modify( boardItem );
629 static_cast<PCB_GROUP*
>( boardItem )->FinalizeGroupDeserialization();
648 commit->
Remove( boardItem );
649 item->Serialize( newItem );
652 commit->
Add( newBoardItem );
656 parentGroup->
AddItem( newBoardItem );
663 commit->
Modify( boardItem );
676 aItemHandler( status, newItem );
682 :
_(
"Modified items via API" ) );
685 return ItemRequestStatus::IRS_OK;
690 const google::protobuf::RepeatedField<int>& aTypes )
692 std::vector<KICAD_T>
types;
694 for(
int typeRaw : aTypes )
696 auto typeMessage =
static_cast<common::types::KiCadObjectType
>( typeRaw );
700 types.emplace_back( type );
710 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"RunAction" ) )
711 return tl::unexpected( *headless );
713 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
714 return tl::unexpected( *busy );
716 RunActionResponse response;
719 response.set_status( RunActionStatus::RAS_OK );
721 response.set_status( RunActionStatus::RAS_INVALID );
733 e.set_status( ApiStatusCode::AS_UNHANDLED );
734 return tl::unexpected( e );
737 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
738 return tl::unexpected( *busy );
740 GetItemsResponse response;
742 std::vector<BOARD_ITEM*> items;
744 for(
const kiapi::common::types::KIID&
id : aCtx.
Request.items() )
746 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
747 items.emplace_back( *item );
753 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
754 e.set_error_message(
"none of the requested IDs were found or valid" );
755 return tl::unexpected( e );
760 google::protobuf::Any itemBuf;
761 item->Serialize( itemBuf );
762 response.mutable_items()->Add( std::move( itemBuf ) );
765 response.set_status( ItemRequestStatus::IRS_OK );
773 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"GetSelection" ) )
774 return tl::unexpected( *headless );
780 e.set_status( ApiStatusCode::AS_UNHANDLED );
781 return tl::unexpected( e );
803 SelectionResponse response;
808 item->Serialize( *response.add_items() );
818 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"ClearSelection" ) )
819 return tl::unexpected( *headless );
825 e.set_status( ApiStatusCode::AS_UNHANDLED );
826 return tl::unexpected( e );
829 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
830 return tl::unexpected( *busy );
843 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"AddToSelection" ) )
844 return tl::unexpected( *headless );
850 e.set_status( ApiStatusCode::AS_UNHANDLED );
851 return tl::unexpected( e );
854 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
855 return tl::unexpected( *busy );
860 std::vector<EDA_ITEM*> toAdd;
862 for(
const types::KIID&
id : aCtx.
Request.items() )
864 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
865 toAdd.emplace_back( *item );
871 SelectionResponse response;
874 item->Serialize( *response.add_items() );
882 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"FocusOnItems" ) )
883 return tl::unexpected( *headless );
886 return tl::unexpected( documentValidation.error() );
888 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
889 return tl::unexpected( *busy );
891 if( aCtx.
Request.items().empty() )
892 return tl::unexpected(
MakeResponseStatus( AS_BAD_REQUEST,
"no items were given to focus on" ) );
894 std::optional<BOX2I> bbox;
895 std::vector<std::string> missing;
897 for(
const types::KIID& idMsg : aCtx.
Request.items() )
899 std::optional<BOARD_ITEM*> item =
getItemById(
KIID( idMsg.value() ) );
903 missing.push_back( idMsg.value() );
908 bbox->Merge( ( *item )->GetBoundingBox() );
910 bbox = ( *item )->GetBoundingBox();
913 if( !missing.empty() )
915 return tl::unexpected(
916 MakeResponseStatus( AS_BAD_REQUEST, fmt::format(
"the items {} are not in the requested document",
917 fmt::join( missing,
", " ) ) ) );
920 if( aCtx.
Request.has_margin() )
932 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"RemoveFromSelection" ) )
933 return tl::unexpected( *headless );
939 e.set_status( ApiStatusCode::AS_UNHANDLED );
940 return tl::unexpected( e );
943 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
944 return tl::unexpected( *busy );
949 std::vector<EDA_ITEM*> toRemove;
951 for(
const types::KIID&
id : aCtx.
Request.items() )
953 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
954 toRemove.emplace_back( *item );
960 SelectionResponse response;
963 item->Serialize( *response.add_items() );
974 if( !documentValidation )
975 return tl::unexpected( documentValidation.error() );
977 BoardStackupResponse response;
990 if( !documentValidation )
991 return tl::unexpected( documentValidation.error() );
993 BoardEnabledLayersResponse response;
996 int copperLayerCount =
board->GetCopperLayerCount();
998 response.set_copper_layer_count( copperLayerCount );
1000 LSET enabled =
board->GetEnabledLayers();
1019 if( !documentValidation )
1020 return tl::unexpected( documentValidation.error() );
1023 GraphicsDefaultsResponse response;
1026 constexpr std::array<kiapi::board::BoardLayerClass, LAYER_CLASS_COUNT> classOrder = {
1027 kiapi::board::BLC_SILKSCREEN,
1028 kiapi::board::BLC_COPPER,
1029 kiapi::board::BLC_EDGES,
1030 kiapi::board::BLC_COURTYARD,
1031 kiapi::board::BLC_FABRICATION,
1032 kiapi::board::BLC_OTHER
1037 kiapi::board::BoardLayerGraphicsDefaults* l = response.mutable_defaults()->add_layers();
1039 l->set_layer( classOrder[i] );
1042 kiapi::common::types::TextAttributes*
text = l->mutable_text();
1059 ApiResponseStatus e;
1061 e.set_status( ApiStatusCode::AS_UNHANDLED );
1062 return tl::unexpected( e );
1065 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1066 return tl::unexpected( *busy );
1068 GetBoundingBoxResponse response;
1069 bool includeText = aCtx.
Request.mode() == BoundingBoxMode::BBM_ITEM_AND_CHILD_TEXT;
1071 for(
const types::KIID& idMsg : aCtx.
Request.items() )
1073 KIID id( idMsg.value() );
1074 std::optional<BOARD_ITEM*> optItem =
getItemById(
id );
1083 bbox =
static_cast<FOOTPRINT*
>( item )->GetBoundingBox( includeText );
1087 response.add_items()->set_value( idMsg.value() );
1088 PackBox2( *response.add_boxes(), bbox );
1099 return tl::unexpected( documentValidation.error() );
1101 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1102 return tl::unexpected( *busy );
1104 BoardBoundingBoxResponse response;
1110 case BoardBoundingBoxMode::BBBM_PHYSICAL_LAYERS_ONLY: bbox =
board()->
ComputeBoundingBox(
false,
true );
break;
1113 return tl::unexpected(
MakeResponseStatus( AS_BAD_REQUEST,
"invalid bounding box mode requested" ) );
1116 PackBox2( *response.mutable_box(), bbox );
1126 !documentValidation )
1128 return tl::unexpected( documentValidation.error() );
1131 PadShapeAsPolygonResponse response;
1134 for(
const types::KIID& padRequest : aCtx.
Request.pads() )
1136 KIID id( padRequest.value() );
1137 std::optional<BOARD_ITEM*> optPad =
getItemById(
id );
1139 if( !optPad || ( *optPad )->Type() !=
PCB_PAD_T )
1142 response.add_pads()->set_value( padRequest.value() );
1144 PAD*
pad =
static_cast<PAD*
>( *optPad );
1146 pad->TransformShapeToPolygon( poly,
pad->Padstack().EffectiveLayerFor( layer ), 0,
1149 types::PolygonWithHoles* polyMsg = response.mutable_polygons()->Add();
1160 using board::types::BoardLayer;
1163 !documentValidation )
1165 return tl::unexpected( documentValidation.error() );
1168 PadstackPresenceResponse response;
1172 for(
const int layer : aCtx.
Request.layers() )
1179 layers.
set( pcbLayer );
1182 for(
const types::KIID& padRequest : aCtx.
Request.items() )
1184 KIID id( padRequest.value() );
1185 std::optional<BOARD_ITEM*> optItem =
getItemById(
id );
1190 switch( ( *optItem )->Type() )
1194 PAD*
pad =
static_cast<PAD*
>( *optItem );
1198 PadstackPresenceEntry* entry = response.add_entries();
1199 entry->mutable_item()->set_value(
pad->m_Uuid.AsStdString() );
1201 entry->set_presence(
pad->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1213 PadstackPresenceEntry* entry = response.add_entries();
1214 entry->mutable_item()->set_value(
via->m_Uuid.AsStdString() );
1216 entry->set_presence(
via->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1236 if( !documentValidation )
1237 return tl::unexpected( documentValidation.error() );
1239 ExpandTextVariablesResponse reply;
1242 std::function<bool( wxString* )> textResolver =
1243 [&]( wxString* token ) ->
bool
1246 return board->ResolveTextVar( token, 0 );
1249 for(
const std::string& textMsg : aCtx.
Request.text() )
1253 if( aCtx.
Request.expand_env_vars() )
1256 reply.add_text(
text.ToUTF8() );
1266 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"InteractiveMoveItems" ) )
1267 return tl::unexpected( *headless );
1271 if( !documentValidation )
1272 return tl::unexpected( documentValidation.error() );
1274 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1275 return tl::unexpected( *busy );
1278 std::vector<EDA_ITEM*> toSelect;
1280 for(
const kiapi::common::types::KIID&
id : aCtx.
Request.items() )
1282 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
1283 toSelect.emplace_back(
static_cast<EDA_ITEM*
>( *item ) );
1286 if( toSelect.empty() )
1288 ApiResponseStatus e;
1289 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1290 e.set_error_message( fmt::format(
"None of the given items exist on the board",
1291 aCtx.
Request.board().board_filename() ) );
1292 return tl::unexpected( e );
1313 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
1316 ApiResponseStatus e;
1317 e.set_status( ApiStatusCode::AS_UNHANDLED );
1318 return tl::unexpected( e );
1320 else if( !containerResult )
1322 return tl::unexpected( containerResult.error() );
1325 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1326 return tl::unexpected( *busy );
1331 FlipItemsResponse response;
1332 response.mutable_header()->CopyFrom( aCtx.
Request.header() );
1336 bool anyModified =
false;
1338 for(
const types::KIID&
id : aCtx.
Request.items() )
1340 ItemFlipResult*
result = response.add_flipped_items();
1342 std::optional<BOARD_ITEM*> optItem =
getItemById(
KIID(
id.value() ) );
1346 result->mutable_status()->set_code( ItemStatusCode::ISC_NONEXISTENT );
1347 result->mutable_status()->set_error_message(
1348 fmt::format(
"an item with UUID {} does not exist",
id.value() ) );
1354 static const std::set<KICAD_T> flippableTypes = {
1383 if( !flippableTypes.contains( itemType ) )
1385 result->mutable_status()->set_code( ItemStatusCode::ISC_INVALID_TYPE );
1386 result->mutable_status()->set_error_message(
1387 fmt::format(
"items of type {} cannot be flipped",
1388 magic_enum::enum_name( itemType ) ) );
1398 static_cast<FOOTPRINT*
>( boardItem )->InvalidateComponentClassCache();
1402 google::protobuf::Any itemBuf;
1404 *
result->mutable_item() = std::move( itemBuf );
1406 result->mutable_status()->set_code( ItemStatusCode::ISC_OK );
1409 response.set_status( ItemRequestStatus::IRS_OK );
1423 if( !documentValidation )
1424 return tl::unexpected( documentValidation.error() );
1426 SavedDocumentResponse response;
1427 response.mutable_document()->CopyFrom( aCtx.
Request.document() );
1431 [&](
const wxString& aData )
1433 response.set_contents( aData.ToUTF8() );
1445 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"SaveSelectionToString" ) )
1446 return tl::unexpected( *headless );
1448 SavedSelectionResponse response;
1456 [&](
const wxString& aData )
1458 response.set_contents( aData.ToUTF8() );
1473 if( !documentValidation )
1474 return tl::unexpected( documentValidation.error() );
1476 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1477 return tl::unexpected( *busy );
1479 CreateItemsResponse response;
1487 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"GetVisibleLayers" ) )
1488 return tl::unexpected( *headless );
1492 if( !documentValidation )
1493 return tl::unexpected( documentValidation.error() );
1495 BoardLayers response;
1507 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"SetVisibleLayers" ) )
1508 return tl::unexpected( *headless );
1512 if( !documentValidation )
1513 return tl::unexpected( documentValidation.error() );
1515 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1516 return tl::unexpected( *busy );
1521 for(
int layerIdx : aCtx.
Request.layers() )
1527 visible.
set( layer );
1535 editFrame->Refresh();
1543 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"GetActiveLayer" ) )
1544 return tl::unexpected( *headless );
1548 if( !documentValidation )
1549 return tl::unexpected( documentValidation.error() );
1553 BoardLayerResponse response;
1564 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"SetActiveLayer" ) )
1565 return tl::unexpected( *headless );
1569 if( !documentValidation )
1570 return tl::unexpected( documentValidation.error() );
1572 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1573 return tl::unexpected( *busy );
1577 if( !
board()->GetEnabledLayers().Contains( layer ) )
1579 ApiResponseStatus err;
1580 err.set_status( ApiStatusCode::AS_BAD_REQUEST );
1581 err.set_error_message( fmt::format(
"Layer {} is not a valid layer for the given board",
1582 magic_enum::enum_name( layer ) ) );
1583 return tl::unexpected( err );
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
std::unique_ptr< BOARD_ITEM > CreateGeneratorForType(const wxString &aGeneratorType, BOARD_ITEM_CONTAINER *aContainer)
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
static TOOL_ACTION selectionClear
Clear the current selection.
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
API_HANDLER_BOARD(std::shared_ptr< BOARD_CONTEXT > aContext, EDA_BASE_FRAME *aFrame=nullptr)
HANDLER_RESULT< commands::ExpandTextVariablesResponse > handleExpandTextVariables(const HANDLER_CONTEXT< commands::ExpandTextVariables > &aCtx)
HANDLER_RESULT< BoardEnabledLayersResponse > handleGetBoardEnabledLayers(const HANDLER_CONTEXT< GetBoardEnabledLayers > &aCtx)
std::unique_ptr< COMMIT > createCommit() override
Override this to create an appropriate COMMIT subclass for the frame in question.
HANDLER_RESULT< commands::SelectionResponse > handleGetSelection(const HANDLER_CONTEXT< commands::GetSelection > &aCtx)
HANDLER_RESULT< commands::SavedSelectionResponse > handleSaveSelectionToString(const HANDLER_CONTEXT< commands::SaveSelectionToString > &aCtx)
HANDLER_RESULT< Empty > handleSetActiveLayer(const HANDLER_CONTEXT< SetActiveLayer > &aCtx)
HANDLER_RESULT< BoardLayers > handleGetVisibleLayers(const HANDLER_CONTEXT< GetVisibleLayers > &aCtx)
TOOL_MANAGER * toolManager() const
GENERATOR_TOOL * ensureGeneratorTool() const
Creates the generator tool if needed (e.g. in headless mode); returns it if available.
HANDLER_RESULT< commands::SelectionResponse > handleAddToSelection(const HANDLER_CONTEXT< commands::AddToSelection > &aCtx)
HANDLER_RESULT< commands::CreateItemsResponse > handleParseAndCreateItemsFromString(const HANDLER_CONTEXT< commands::ParseAndCreateItemsFromString > &aCtx)
HANDLER_RESULT< Empty > handleClearSelection(const HANDLER_CONTEXT< commands::ClearSelection > &aCtx)
std::vector< KICAD_T > parseRequestedItemTypes(const google::protobuf::RepeatedField< int > &aTypes)
HANDLER_RESULT< Empty > handleInteractiveMoveItems(const HANDLER_CONTEXT< InteractiveMoveItems > &aCtx)
HANDLER_RESULT< BoardBoundingBoxResponse > handleGetBoardBoundingBox(const HANDLER_CONTEXT< GetBoardBoundingBox > &aCtx)
HANDLER_RESULT< types::ItemRequestStatus > handleCreateUpdateItemsInternal(bool aCreate, const std::string &aClientName, const types::ItemHeader &aHeader, const google::protobuf::RepeatedPtrField< google::protobuf::Any > &aItems, std::function< void(commands::ItemStatus, google::protobuf::Any)> aItemHandler) override
HANDLER_RESULT< BoardStackupResponse > handleGetStackup(const HANDLER_CONTEXT< GetBoardStackup > &aCtx)
void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage) override
HANDLER_RESULT< commands::GetItemsResponse > handleGetItemsById(const HANDLER_CONTEXT< commands::GetItemsById > &aCtx)
std::optional< EDA_ITEM * > getItemFromDocument(const DocumentSpecifier &aDocument, const KIID &aId) override
void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName) override
HANDLER_RESULT< commands::SelectionResponse > handleRemoveFromSelection(const HANDLER_CONTEXT< commands::RemoveFromSelection > &aCtx)
HANDLER_RESULT< GraphicsDefaultsResponse > handleGetGraphicsDefaults(const HANDLER_CONTEXT< GetGraphicsDefaults > &aCtx)
HANDLER_RESULT< BoardLayerResponse > handleGetActiveLayer(const HANDLER_CONTEXT< GetActiveLayer > &aCtx)
HANDLER_RESULT< commands::GetBoundingBoxResponse > handleGetBoundingBox(const HANDLER_CONTEXT< commands::GetBoundingBox > &aCtx)
static HANDLER_RESULT< std::unique_ptr< BOARD_ITEM > > createItemForType(KICAD_T aType, BOARD_ITEM_CONTAINER *aContainer)
HANDLER_RESULT< commands::RunActionResponse > handleRunAction(const HANDLER_CONTEXT< commands::RunAction > &aCtx)
std::optional< ApiResponseStatus > checkForHeadless(const std::string &aCommandName) const
HANDLER_RESULT< commands::SavedDocumentResponse > handleSaveDocumentToString(const HANDLER_CONTEXT< commands::SaveDocumentToString > &aCtx)
HANDLER_RESULT< PadShapeAsPolygonResponse > handleGetPadShapeAsPolygon(const HANDLER_CONTEXT< GetPadShapeAsPolygon > &aCtx)
HANDLER_RESULT< Empty > handleFocusOnItems(const HANDLER_CONTEXT< commands::FocusOnItems > &aCtx)
std::shared_ptr< BOARD_CONTEXT > m_context
HANDLER_RESULT< PadstackPresenceResponse > handleCheckPadstackPresenceOnLayers(const HANDLER_CONTEXT< CheckPadstackPresenceOnLayers > &aCtx)
virtual BOARD_ITEM_CONTAINER * getDefaultContainer()
HANDLER_RESULT< Empty > handleSetVisibleLayers(const HANDLER_CONTEXT< SetVisibleLayers > &aCtx)
void regenerateGenerators(GENERATOR_TOOL *aTool, BOARD_COMMIT *aCommit, const std::vector< PCB_GENERATOR * > &aGenerators, std::function< void(const KIID &, commands::ItemStatus)> aResultHandler) const
std::optional< BOARD_ITEM * > getItemById(const KIID &aId) const
HANDLER_RESULT< FlipItemsResponse > handleFlipItems(const HANDLER_CONTEXT< FlipItems > &aCtx)
HANDLER_RESULT< bool > validateDocument(const DocumentSpecifier &aDocument)
HANDLER_RESULT< std::optional< KIID > > validateItemHeaderDocument(const kiapi::common::types::ItemHeader &aHeader)
If the header is valid, returns the item container.
API_HANDLER_EDITOR(EDA_BASE_FRAME *aFrame=nullptr)
COMMIT * getCurrentCommit(const std::string &aClientName)
virtual void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage)
std::set< std::string > m_activeClients
virtual std::optional< ApiResponseStatus > checkForBusy()
Checks if the editor can accept commands.
virtual types::DocumentType thisDocumentType() const =0
Override this to specify which document type this editor handles.
virtual void onModified()
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
void OnBoardChanged()
Update the panel contents from the application and board models.
BASE_SET & reset(size_t pos)
BASE_SET & set(size_t pos)
void RevertToCheckpoint(int aCheckpoint) override
Container for design settings for a BOARD object.
bool m_TextUpright[LAYER_CLASS_COUNT]
int m_TextThickness[LAYER_CLASS_COUNT]
int m_LineThickness[LAYER_CLASS_COUNT]
VECTOR2I m_TextSize[LAYER_CLASS_COUNT]
bool m_TextItalic[LAYER_CLASS_COUNT]
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void CopyFrom(const BOARD_ITEM *aOther)
BOARD_ITEM_CONTAINER * GetParent() const
virtual void Normalize()
Perform any normalization required after a user rotate and/or flip.
virtual void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
Flip this object, i.e.
Information pertinent to a Pcbnew printed circuit board.
void SetVisibleLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
const BOX2I GetBoardEdgesBoundingBox() const
Return the board bounding box calculated using exclusively the board edges (graphics on Edge....
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aPhysicalLayersOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
BOARD_DESIGN_SETTINGS & GetDesignSettings()
void SaveBoard(const wxString &aFileName, BOARD &aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
void SaveSelection(const PCB_SELECTION &selected, bool isFootprintEditor)
void SetWriter(std::function< void(const wxString &)> aWriter)
void SetBoard(BOARD *aBoard)
Represent a set of changes (additions, deletions or modifications) of a data model (e....
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
The base frame for deriving all KiCad main window classes.
The base class for create windows for drawing purpose.
A set of EDA_ITEMs (i.e., without duplicates).
virtual void FinalizeGroupDeserialization()
void AddItem(EDA_ITEM *aItem)
Add item to group.
A base class for most all the KiCad significant classes used in schematics and boards.
virtual VECTOR2I GetPosition() const
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
virtual EDA_GROUP * GetParentGroup() const
KICAD_T Type() const
Returns the type of object.
virtual void SetParentGroup(EDA_GROUP *aGroup)
virtual wxString GetFriendlyName() const
virtual void SetParent(EDA_ITEM *aParent)
std::string AsStdString() const
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
static TOOL_ACTION genRemove
static TOOL_ACTION move
move or drag an item
Common, abstract interface for edit frames.
APPEARANCE_CONTROLS * GetAppearancePanel()
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual PCB_LAYER_ID GetActiveLayer() const
void SyncLayersVisibility(const BOARD *aBoard)
Update "visibility" property of each layer of a given BOARD.
A set of BOARD_ITEMs (i.e., without duplicates).
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void SetReferencePoint(const VECTOR2I &aP)
virtual void Serialize(google::protobuf::Any &aContainer) const
Serializes this object to the given Any message.
virtual bool Deserialize(const google::protobuf::Any &aContainer)
Deserializes the given protobuf message into this object.
Represent a set of closed polygons.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject, bool aAllowEscapes)
Replace any environment variable & text variable references with their values.
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, RESOLUTION_CONTEXT aContext)
PCB_LAYER_ID
A quick note on layer IDs:
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
void PackBoardStackup(const BOARD &aBoard, BoardStackup &aOut)
KICOMMON_API int UnpackDistance(const types::Distance &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
KICOMMON_API ApiResponseStatus MakeResponseStatus(ApiStatusCode aCode, const std::string &aMessage)
KICOMMON_API void PackBox2(types::Box2 &aOutput, const BOX2I &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API std::optional< wxString > GeneratorTypeFromAny(const google::protobuf::Any &aMessage)
KICOMMON_API void PackPolyLine(types::PolyLine &aOutput, const SHAPE_LINE_CHAIN &aSlc, const EDA_IU_SCALE &aScale)
Class to handle a set of BOARD_ITEMs.
bool IsGeneratedTableCell(const EDA_ITEM *aItem)
True for a cell whose text is generated from the board, so only its formatting is the user's.
std::vector< EDA_ITEM * > EDA_ITEMS
RequestMessageType Request
wxString result
Test unit parsing edge cases and error handling.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
@ PCB_CONSTRAINT_T
a geometric constraint between board items
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_3D_BODY_T
class PCB_3D_BODY, a 3D body (extruded or model) on a footprint
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_GRID_ITEM_T
a subgrid placed on a board
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_POINT_T
class PCB_POINT, a 0-dimensional point
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension