21#include <magic_enum.hpp>
52#include <api/common/types/base_types.pb.h>
56using namespace kiapi::common::commands;
57using types::CommandStatus;
58using types::DocumentType;
59using types::ItemRequestStatus;
136 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
137 return tl::unexpected( *busy );
139 RunActionResponse response;
141 if(
frame()->GetToolManager()->RunAction( aCtx.
Request.action(),
true ) )
142 response.set_status( RunActionStatus::RAS_OK );
144 response.set_status( RunActionStatus::RAS_INVALID );
153 if( aCtx.
Request.type() != DocumentType::DOCTYPE_PCB )
157 e.set_status( ApiStatusCode::AS_UNHANDLED );
158 return tl::unexpected( e );
161 GetOpenDocumentsResponse response;
162 common::types::DocumentSpecifier doc;
164 wxFileName fn(
frame()->GetCurrentFileName() );
166 doc.set_type( DocumentType::DOCTYPE_PCB );
167 doc.set_board_filename( fn.GetFullName() );
169 doc.mutable_project()->set_name(
frame()->
Prj().GetProjectName().ToStdString() );
170 doc.mutable_project()->set_path(
frame()->
Prj().GetProjectDirectory().ToStdString() );
172 response.mutable_documents()->Add( std::move( doc ) );
180 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
181 return tl::unexpected( *busy );
185 if( !documentValidation )
186 return tl::unexpected( documentValidation.error() );
196 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
197 return tl::unexpected( *busy );
201 if( !documentValidation )
202 return tl::unexpected( documentValidation.error() );
204 wxFileName boardPath(
frame()->
Prj().AbsolutePath( wxString::FromUTF8( aCtx.
Request.path() ) ) );
206 if( !boardPath.IsOk() || !boardPath.IsDirWritable() )
209 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
210 e.set_error_message( fmt::format(
"save path '{}' could not be opened",
211 boardPath.GetFullPath().ToStdString() ) );
212 return tl::unexpected( e );
215 if( boardPath.FileExists()
216 && ( !boardPath.IsFileWritable() || !aCtx.
Request.options().overwrite() ) )
219 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
220 e.set_error_message( fmt::format(
"save path '{}' exists and cannot be overwritten",
221 boardPath.GetFullPath().ToStdString() ) );
222 return tl::unexpected( e );
228 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
229 e.set_error_message( fmt::format(
"save path '{}' must have a kicad_pcb extension",
230 boardPath.GetFullPath().ToStdString() ) );
231 return tl::unexpected( e );
236 if(
board->GetFileName().Matches( boardPath.GetFullPath() ) )
242 bool includeProject =
true;
244 if( aCtx.
Request.has_options() )
245 includeProject = aCtx.
Request.options().include_project();
256 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
257 return tl::unexpected( *busy );
261 if( !documentValidation )
262 return tl::unexpected( documentValidation.error() );
283 return std::make_unique<BOARD_COMMIT>(
frame() );
300 if( aDocument.type() != DocumentType::DOCTYPE_PCB )
303 wxFileName fn(
frame()->GetCurrentFileName() );
304 return 0 == aDocument.board_filename().compare( fn.GetFullName() );
314 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
315 e.set_error_message(
"Tried to create an item in a null container" );
316 return tl::unexpected( e );
322 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
323 e.set_error_message( fmt::format(
"Tried to create a pad in {}, which is not a footprint",
325 return tl::unexpected( e );
330 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
331 e.set_error_message( fmt::format(
"Tried to create a footprint in {}, which is not a board",
333 return tl::unexpected( e );
341 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
342 e.set_error_message( fmt::format(
"Tried to create an item of type {}, which is unhandled",
343 magic_enum::enum_name( aType ) ) );
344 return tl::unexpected( e );
352 const std::string& aClientName,
353 const types::ItemHeader &aHeader,
354 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
355 std::function<
void( ItemStatus, google::protobuf::Any )> aItemHandler )
361 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
364 e.set_status( ApiStatusCode::AS_UNHANDLED );
365 return tl::unexpected( e );
367 else if( !containerResult )
369 e.CopyFrom( containerResult.error() );
370 return tl::unexpected( e );
376 if( containerResult->has_value() )
378 const KIID& containerId = **containerResult;
379 std::optional<BOARD_ITEM*> optItem =
getItemById( containerId );
387 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
388 e.set_error_message( fmt::format(
389 "The requested container {} is not a valid board item container",
391 return tl::unexpected( e );
396 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
397 e.set_error_message( fmt::format(
398 "The requested container {} does not exist in this document",
400 return tl::unexpected( e );
406 for(
const google::protobuf::Any& anyItem : aItems )
413 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
414 status.set_error_message( fmt::format(
"Could not decode a valid type from {}",
415 anyItem.type_url() ) );
416 aItemHandler( status, anyItem );
422 board::types::Dimension dimension;
423 anyItem.UnpackTo( &dimension );
425 switch( dimension.dimension_style_case() )
432 case board::types::Dimension::DIMENSION_STYLE_NOT_SET:
break;
439 if( !creationResult )
441 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
442 status.set_error_message( creationResult.error().error_message() );
443 aItemHandler( status, anyItem );
447 std::unique_ptr<BOARD_ITEM> item( std::move( *creationResult ) );
449 if( !item->Deserialize( anyItem ) )
451 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
452 e.set_error_message( fmt::format(
"could not unpack {} from request",
453 item->GetClass().ToStdString() ) );
454 return tl::unexpected( e );
457 std::optional<BOARD_ITEM*> optItem =
getItemById( item->m_Uuid );
459 if( aCreate && optItem )
461 status.set_code( ItemStatusCode::ISC_EXISTING );
462 status.set_error_message( fmt::format(
"an item with UUID {} already exists",
463 item->m_Uuid.AsStdString() ) );
464 aItemHandler( status, anyItem );
467 else if( !aCreate && !optItem )
469 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
470 status.set_error_message( fmt::format(
"an item with UUID {} does not exist",
471 item->m_Uuid.AsStdString() ) );
472 aItemHandler( status, anyItem );
476 if( aCreate && !(
board->GetEnabledLayers() & item->GetLayerSet() ).any() )
478 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
479 status.set_error_message(
480 "attempted to add item with no overlapping layers with the board" );
481 aItemHandler( status, anyItem );
485 status.set_code( ItemStatusCode::ISC_OK );
486 google::protobuf::Any newItem;
502 item->Serialize( newItem );
503 commit->
Add( item.release() );
520 commit->
Remove( boardItem );
521 item->Serialize( newItem );
524 commit->
Add( newBoardItem );
528 parentGroup->
AddItem( newBoardItem );
532 commit->
Modify( boardItem );
538 aItemHandler( status, newItem );
544 :
_(
"Modified items via API" ) );
548 return ItemRequestStatus::IRS_OK;
554 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
555 return tl::unexpected( *busy );
561 e.set_status( ApiStatusCode::AS_UNHANDLED );
562 return tl::unexpected( e );
565 GetItemsResponse response;
568 std::vector<BOARD_ITEM*> items;
569 std::set<KICAD_T> typesRequested, typesInserted;
570 bool handledAnything =
false;
572 for(
int typeRaw : aCtx.
Request.types() )
574 auto typeMessage =
static_cast<common::types::KiCadObjectType
>( typeRaw );
580 typesRequested.emplace( type );
582 if( typesInserted.count( type ) )
590 handledAnything =
true;
591 std::copy(
board->Tracks().begin(),
board->Tracks().end(),
592 std::back_inserter( items ) );
598 handledAnything =
true;
602 std::copy( fp->Pads().begin(), fp->Pads().end(),
603 std::back_inserter( items ) );
612 handledAnything =
true;
614 std::copy(
board->Footprints().begin(),
board->Footprints().end(),
615 std::back_inserter( items ) );
626 handledAnything =
true;
627 bool inserted =
false;
631 if( item->Type() == type )
633 items.emplace_back( item );
639 typesInserted.insert( type );
646 handledAnything =
true;
648 std::copy(
board->Zones().begin(),
board->Zones().end(),
649 std::back_inserter( items ) );
657 handledAnything =
true;
659 std::copy(
board->Groups().begin(),
board->Groups().end(),
660 std::back_inserter( items ) );
670 if( !handledAnything )
673 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
674 e.set_error_message(
"none of the requested types are valid for a Board object" );
675 return tl::unexpected( e );
680 if( !typesRequested.count( item->Type() ) )
683 google::protobuf::Any itemBuf;
684 item->Serialize( itemBuf );
685 response.mutable_items()->Add( std::move( itemBuf ) );
688 response.set_status( ItemRequestStatus::IRS_OK );
696 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
697 return tl::unexpected( *busy );
702 e.set_status( ApiStatusCode::AS_UNHANDLED );
703 return tl::unexpected( e );
706 GetItemsResponse response;
708 std::vector<BOARD_ITEM*> items;
710 for(
const kiapi::common::types::KIID&
id : aCtx.
Request.items() )
712 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
713 items.emplace_back( *item );
719 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
720 e.set_error_message(
"none of the requested IDs were found or valid" );
721 return tl::unexpected( e );
726 google::protobuf::Any itemBuf;
727 item->Serialize( itemBuf );
728 response.mutable_items()->Add( std::move( itemBuf ) );
731 response.set_status( ItemRequestStatus::IRS_OK );
736 const std::string& aClientName )
739 std::vector<BOARD_ITEM*> validatedItems;
741 for( std::pair<const KIID, ItemDeletionStatus> pair : aItemsToDelete )
745 validatedItems.push_back( item );
746 aItemsToDelete[pair.first] = ItemDeletionStatus::IDS_OK;
780 e.set_status( ApiStatusCode::AS_UNHANDLED );
781 return tl::unexpected( e );
786 for(
int typeRaw : aCtx.
Request.types() )
788 auto typeMessage =
static_cast<types::KiCadObjectType
>( typeRaw );
800 SelectionResponse response;
805 item->Serialize( *response.add_items() );
815 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
816 return tl::unexpected( *busy );
822 e.set_status( ApiStatusCode::AS_UNHANDLED );
823 return tl::unexpected( e );
837 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
838 return tl::unexpected( *busy );
844 e.set_status( ApiStatusCode::AS_UNHANDLED );
845 return tl::unexpected( e );
851 std::vector<EDA_ITEM*> toAdd;
853 for(
const types::KIID&
id : aCtx.
Request.items() )
855 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
856 toAdd.emplace_back( *item );
862 SelectionResponse response;
865 item->Serialize( *response.add_items() );
874 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
875 return tl::unexpected( *busy );
881 e.set_status( ApiStatusCode::AS_UNHANDLED );
882 return tl::unexpected( e );
888 std::vector<EDA_ITEM*> toRemove;
890 for(
const types::KIID&
id : aCtx.
Request.items() )
892 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
893 toRemove.emplace_back( *item );
899 SelectionResponse response;
902 item->Serialize( *response.add_items() );
913 if( !documentValidation )
914 return tl::unexpected( documentValidation.error() );
916 BoardStackupResponse response;
917 google::protobuf::Any
any;
921 any.UnpackTo( response.mutable_stackup() );
924 for( board::BoardStackupLayer& layer : *response.mutable_stackup()->mutable_layers() )
926 if( layer.type() == board::BoardStackupLayerType::BSLT_DIELECTRIC )
932 layer.set_user_name(
frame()->
GetBoard()->GetLayerName(
id ) );
944 if( !documentValidation )
945 return tl::unexpected( documentValidation.error() );
947 BoardEnabledLayersResponse response;
950 int copperLayerCount =
board->GetCopperLayerCount();
952 response.set_copper_layer_count( copperLayerCount );
954 LSET enabled =
board->GetEnabledLayers();
973 if( !documentValidation )
974 return tl::unexpected( documentValidation.error() );
976 if( aCtx.
Request.copper_layer_count() % 2 != 0 )
979 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
980 e.set_error_message(
"copper_layer_count must be an even number" );
981 return tl::unexpected( e );
987 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
988 e.set_error_message( fmt::format(
"copper_layer_count must be below %d",
MAX_CU_LAYERS ) );
989 return tl::unexpected( e );
992 int copperLayerCount =
static_cast<int>( aCtx.
Request.copper_layer_count() );
997 enabled &=
~LSET::AllCuMask();
1002 LSET previousEnabled =
board->GetEnabledLayers();
1003 LSET changedLayers = enabled ^ previousEnabled;
1005 board->SetEnabledLayers( enabled );
1006 board->SetVisibleLayers(
board->GetVisibleLayers() | changedLayers );
1012 if( !enabled[layer_id] &&
board->HasItemsOnLayer( layer_id ) )
1013 removedLayers.push_back( layer_id );
1016 bool modified =
false;
1018 if( !removedLayers.empty() )
1023 modified |=
board->RemoveAllItemsOnLayer( layer_id );
1026 if( enabled != previousEnabled )
1032 BoardEnabledLayersResponse response;
1034 response.set_copper_layer_count( copperLayerCount );
1046 if( !documentValidation )
1047 return tl::unexpected( documentValidation.error() );
1050 GraphicsDefaultsResponse response;
1053 constexpr std::array<kiapi::board::BoardLayerClass, LAYER_CLASS_COUNT> classOrder = {
1054 kiapi::board::BLC_SILKSCREEN,
1055 kiapi::board::BLC_COPPER,
1056 kiapi::board::BLC_EDGES,
1057 kiapi::board::BLC_COURTYARD,
1058 kiapi::board::BLC_FABRICATION,
1059 kiapi::board::BLC_OTHER
1064 kiapi::board::BoardLayerGraphicsDefaults* l = response.mutable_defaults()->add_layers();
1066 l->set_layer( classOrder[i] );
1069 kiapi::common::types::TextAttributes*
text = l->mutable_text();
1085 !documentValidation )
1087 return tl::unexpected( documentValidation.error() );
1106 ApiResponseStatus e;
1107 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1108 e.set_error_message(
"Unexpected origin type" );
1109 return tl::unexpected( e );
1113 types::Vector2 reply;
1121 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1122 return tl::unexpected( *busy );
1125 !documentValidation )
1127 return tl::unexpected( documentValidation.error() );
1138 frame()->CallAfter( [f, origin]()
1153 frame()->CallAfter( [f, origin]()
1165 ApiResponseStatus e;
1166 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1167 e.set_error_message(
"Unexpected origin type" );
1168 return tl::unexpected( e );
1180 !documentValidation )
1182 return tl::unexpected( documentValidation.error() );
1185 BoardLayerNameResponse response;
1189 response.set_name(
frame()->
GetBoard()->GetLayerName(
id ) );
1198 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1199 return tl::unexpected( *busy );
1203 ApiResponseStatus e;
1205 e.set_status( ApiStatusCode::AS_UNHANDLED );
1206 return tl::unexpected( e );
1209 GetBoundingBoxResponse response;
1210 bool includeText = aCtx.
Request.mode() == BoundingBoxMode::BBM_ITEM_AND_CHILD_TEXT;
1212 for(
const types::KIID& idMsg : aCtx.
Request.items() )
1214 KIID id( idMsg.value() );
1215 std::optional<BOARD_ITEM*> optItem =
getItemById(
id );
1224 bbox =
static_cast<FOOTPRINT*
>( item )->GetBoundingBox( includeText );
1228 response.add_items()->set_value( idMsg.value() );
1229 PackBox2( *response.add_boxes(), bbox );
1240 !documentValidation )
1242 return tl::unexpected( documentValidation.error() );
1245 PadShapeAsPolygonResponse response;
1248 for(
const types::KIID& padRequest : aCtx.
Request.pads() )
1250 KIID id( padRequest.value() );
1251 std::optional<BOARD_ITEM*> optPad =
getItemById(
id );
1253 if( !optPad || ( *optPad )->Type() !=
PCB_PAD_T )
1256 response.add_pads()->set_value( padRequest.value() );
1258 PAD*
pad =
static_cast<PAD*
>( *optPad );
1260 pad->TransformShapeToPolygon( poly,
pad->Padstack().EffectiveLayerFor( layer ), 0,
1263 types::PolygonWithHoles* polyMsg = response.mutable_polygons()->Add();
1274 using board::types::BoardLayer;
1277 !documentValidation )
1279 return tl::unexpected( documentValidation.error() );
1282 PadstackPresenceResponse response;
1286 for(
const int layer : aCtx.
Request.layers() )
1289 for(
const types::KIID& padRequest : aCtx.
Request.items() )
1291 KIID id( padRequest.value() );
1292 std::optional<BOARD_ITEM*> optItem =
getItemById(
id );
1297 switch( ( *optItem )->Type() )
1301 PAD*
pad =
static_cast<PAD*
>( *optItem );
1305 PadstackPresenceEntry* entry = response.add_entries();
1306 entry->mutable_item()->set_value(
pad->m_Uuid.AsStdString() );
1308 entry->set_presence(
pad->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1320 PadstackPresenceEntry* entry = response.add_entries();
1321 entry->mutable_item()->set_value(
via->m_Uuid.AsStdString() );
1323 entry->set_presence(
via->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1343 if( !documentValidation )
1344 return tl::unexpected( documentValidation.error() );
1349 types::TitleBlockInfo response;
1351 response.set_title( block.
GetTitle().ToUTF8() );
1352 response.set_date( block.
GetDate().ToUTF8() );
1353 response.set_revision( block.
GetRevision().ToUTF8() );
1354 response.set_company( block.
GetCompany().ToUTF8() );
1355 response.set_comment1( block.
GetComment( 0 ).ToUTF8() );
1356 response.set_comment2( block.
GetComment( 1 ).ToUTF8() );
1357 response.set_comment3( block.
GetComment( 2 ).ToUTF8() );
1358 response.set_comment4( block.
GetComment( 3 ).ToUTF8() );
1359 response.set_comment5( block.
GetComment( 4 ).ToUTF8() );
1360 response.set_comment6( block.
GetComment( 5 ).ToUTF8() );
1361 response.set_comment7( block.
GetComment( 6 ).ToUTF8() );
1362 response.set_comment8( block.
GetComment( 7 ).ToUTF8() );
1363 response.set_comment9( block.
GetComment( 8 ).ToUTF8() );
1374 if( !documentValidation )
1375 return tl::unexpected( documentValidation.error() );
1377 ExpandTextVariablesResponse reply;
1380 std::function<bool( wxString* )> textResolver =
1381 [&]( wxString* token ) ->
bool
1384 return board->ResolveTextVar( token, 0 );
1387 for(
const std::string& textMsg : aCtx.
Request.text() )
1390 reply.add_text(
text.ToUTF8() );
1400 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1401 return tl::unexpected( *busy );
1405 if( !documentValidation )
1406 return tl::unexpected( documentValidation.error() );
1409 std::vector<EDA_ITEM*> toSelect;
1411 for(
const kiapi::common::types::KIID&
id : aCtx.
Request.items() )
1413 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
1414 toSelect.emplace_back(
static_cast<EDA_ITEM*
>( *item ) );
1417 if( toSelect.empty() )
1419 ApiResponseStatus e;
1420 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1421 e.set_error_message( fmt::format(
"None of the given items exist on the board",
1422 aCtx.
Request.board().board_filename() ) );
1423 return tl::unexpected( e );
1443 if( !documentValidation )
1444 return tl::unexpected( documentValidation.error() );
1446 NetsResponse response;
1449 std::set<wxString> netclassFilter;
1451 for(
const std::string& nc : aCtx.
Request.netclass_filter() )
1452 netclassFilter.insert( wxString( nc.c_str(), wxConvUTF8 ) );
1458 if( !netclassFilter.empty() && nc && !netclassFilter.count( nc->
GetName() ) )
1461 board::types::Net* netProto = response.add_nets();
1462 netProto->set_name( net->GetNetname() );
1463 netProto->mutable_code()->set_value( net->GetNetCode() );
1473 NetClassForNetsResponse response;
1477 google::protobuf::Any
any;
1479 for(
const board::types::Net& net : aCtx.
Request.net() )
1487 auto [pair, rc] = response.mutable_classes()->insert( { net.name(), {} } );
1488 any.UnpackTo( &pair->second );
1497 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1498 return tl::unexpected( *busy );
1502 if( !documentValidation )
1503 return tl::unexpected( documentValidation.error() );
1505 if( aCtx.
Request.zones().empty() )
1508 frame()->CallAfter( [mgr]()
1516 ApiResponseStatus e;
1517 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
1518 return tl::unexpected( e );
1530 if( !documentValidation )
1531 return tl::unexpected( documentValidation.error() );
1533 SavedDocumentResponse response;
1534 response.mutable_document()->CopyFrom( aCtx.
Request.document() );
1538 [&](
const wxString& aData )
1540 response.set_contents( aData.ToUTF8() );
1552 SavedSelectionResponse response;
1560 [&](
const wxString& aData )
1562 response.set_contents( aData.ToUTF8() );
1575 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1576 return tl::unexpected( *busy );
1580 if( !documentValidation )
1581 return tl::unexpected( documentValidation.error() );
1583 CreateItemsResponse response;
1593 if( !documentValidation )
1594 return tl::unexpected( documentValidation.error() );
1596 BoardLayers response;
1608 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1609 return tl::unexpected( *busy );
1613 if( !documentValidation )
1614 return tl::unexpected( documentValidation.error() );
1619 for(
int layerIdx : aCtx.
Request.layers() )
1625 visible.
set( layer );
1641 if( !documentValidation )
1642 return tl::unexpected( documentValidation.error() );
1644 BoardLayerResponse response;
1655 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1656 return tl::unexpected( *busy );
1660 if( !documentValidation )
1661 return tl::unexpected( documentValidation.error() );
1665 if( !
frame()->
GetBoard()->GetEnabledLayers().Contains( layer ) )
1667 ApiResponseStatus err;
1668 err.set_status( ApiStatusCode::AS_BAD_REQUEST );
1669 err.set_error_message( fmt::format(
"Layer {} is not a valid layer for the given board",
1670 magic_enum::enum_name( layer ) ) );
1671 return tl::unexpected( err );
1682 BoardEditorAppearanceSettings reply;
1690 reply.set_net_color_display(
1693 reply.set_board_flip(
frame()->GetCanvas()->GetView()->IsMirroredX()
1694 ? BoardFlipMode::BFM_FLIPPED_X
1695 : BoardFlipMode::BFM_NORMAL );
1709 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1710 return tl::unexpected( *busy );
1715 const BoardEditorAppearanceSettings& newSettings = aCtx.
Request.settings();
1722 bool flip = newSettings.board_flip() == BoardFlipMode::BFM_FLIPPED_X;
1744 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1745 return tl::unexpected( *busy );
1749 if( !documentValidation )
1750 return tl::unexpected( documentValidation.error() );
1758 drcItem->SetErrorMessage( wxString::FromUTF8( aCtx.
Request.message() ) );
1762 for(
const auto&
id : aCtx.
Request.items() )
1763 ids.emplace_back(
KIID(
id.value() ) );
1766 drcItem->SetItems( ids );
1768 const auto& pos = aCtx.
Request.position();
1769 VECTOR2I position(
static_cast<int>( pos.x_nm() ),
static_cast<int>( pos.y_nm() ) );
1774 commit->
Add( marker );
1775 commit->
Push( wxS(
"API injected DRC marker" ) );
1777 InjectDrcErrorResponse response;
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
static TOOL_ACTION selectionClear
Clear the current selection.
static TOOL_ACTION gridSetOrigin
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
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.
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 > handleInteractiveMoveItems(const HANDLER_CONTEXT< InteractiveMoveItems > &aCtx)
bool validateDocumentInternal(const DocumentSpecifier &aDocument) const override
HANDLER_RESULT< Empty > handleSetActiveLayer(const HANDLER_CONTEXT< SetActiveLayer > &aCtx)
API_HANDLER_PCB(PCB_EDIT_FRAME *aFrame)
static HANDLER_RESULT< std::unique_ptr< BOARD_ITEM > > createItemForType(KICAD_T aType, BOARD_ITEM_CONTAINER *aContainer)
std::optional< BOARD_ITEM * > getItemById(const KIID &aId) const
HANDLER_RESULT< types::Vector2 > handleGetBoardOrigin(const HANDLER_CONTEXT< GetBoardOrigin > &aCtx)
std::unique_ptr< COMMIT > createCommit() override
Override this to create an appropriate COMMIT subclass for the frame in question.
HANDLER_RESULT< BoardStackupResponse > handleGetStackup(const HANDLER_CONTEXT< GetBoardStackup > &aCtx)
HANDLER_RESULT< types::TitleBlockInfo > handleGetTitleBlockInfo(const HANDLER_CONTEXT< commands::GetTitleBlockInfo > &aCtx)
HANDLER_RESULT< commands::SelectionResponse > handleGetSelection(const HANDLER_CONTEXT< commands::GetSelection > &aCtx)
HANDLER_RESULT< NetClassForNetsResponse > handleGetNetClassForNets(const HANDLER_CONTEXT< GetNetClassForNets > &aCtx)
std::optional< EDA_ITEM * > getItemFromDocument(const DocumentSpecifier &aDocument, const KIID &aId) override
HANDLER_RESULT< commands::ExpandTextVariablesResponse > handleExpandTextVariables(const HANDLER_CONTEXT< commands::ExpandTextVariables > &aCtx)
HANDLER_RESULT< Empty > handleSetVisibleLayers(const HANDLER_CONTEXT< SetVisibleLayers > &aCtx)
HANDLER_RESULT< Empty > handleSaveCopyOfDocument(const HANDLER_CONTEXT< commands::SaveCopyOfDocument > &aCtx)
HANDLER_RESULT< GraphicsDefaultsResponse > handleGetGraphicsDefaults(const HANDLER_CONTEXT< GetGraphicsDefaults > &aCtx)
HANDLER_RESULT< commands::GetItemsResponse > handleGetItemsById(const HANDLER_CONTEXT< commands::GetItemsById > &aCtx)
HANDLER_RESULT< Empty > handleSetBoardOrigin(const HANDLER_CONTEXT< SetBoardOrigin > &aCtx)
HANDLER_RESULT< BoardLayerNameResponse > handleGetBoardLayerName(const HANDLER_CONTEXT< GetBoardLayerName > &aCtx)
HANDLER_RESULT< Empty > handleClearSelection(const HANDLER_CONTEXT< commands::ClearSelection > &aCtx)
HANDLER_RESULT< commands::RunActionResponse > handleRunAction(const HANDLER_CONTEXT< commands::RunAction > &aCtx)
HANDLER_RESULT< BoardLayers > handleGetVisibleLayers(const HANDLER_CONTEXT< GetVisibleLayers > &aCtx)
HANDLER_RESULT< PadstackPresenceResponse > handleCheckPadstackPresenceOnLayers(const HANDLER_CONTEXT< CheckPadstackPresenceOnLayers > &aCtx)
HANDLER_RESULT< commands::SelectionResponse > handleRemoveFromSelection(const HANDLER_CONTEXT< commands::RemoveFromSelection > &aCtx)
HANDLER_RESULT< commands::GetOpenDocumentsResponse > handleGetOpenDocuments(const HANDLER_CONTEXT< commands::GetOpenDocuments > &aCtx)
HANDLER_RESULT< BoardEditorAppearanceSettings > handleGetBoardEditorAppearanceSettings(const HANDLER_CONTEXT< GetBoardEditorAppearanceSettings > &aCtx)
HANDLER_RESULT< NetsResponse > handleGetNets(const HANDLER_CONTEXT< GetNets > &aCtx)
HANDLER_RESULT< commands::SavedDocumentResponse > handleSaveDocumentToString(const HANDLER_CONTEXT< commands::SaveDocumentToString > &aCtx)
HANDLER_RESULT< commands::GetBoundingBoxResponse > handleGetBoundingBox(const HANDLER_CONTEXT< commands::GetBoundingBox > &aCtx)
HANDLER_RESULT< Empty > handleSaveDocument(const HANDLER_CONTEXT< commands::SaveDocument > &aCtx)
void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName) override
HANDLER_RESULT< BoardEnabledLayersResponse > handleGetBoardEnabledLayers(const HANDLER_CONTEXT< GetBoardEnabledLayers > &aCtx)
HANDLER_RESULT< commands::GetItemsResponse > handleGetItems(const HANDLER_CONTEXT< commands::GetItems > &aCtx)
HANDLER_RESULT< PadShapeAsPolygonResponse > handleGetPadShapeAsPolygon(const HANDLER_CONTEXT< GetPadShapeAsPolygon > &aCtx)
HANDLER_RESULT< InjectDrcErrorResponse > handleInjectDrcError(const HANDLER_CONTEXT< InjectDrcError > &aCtx)
PCB_EDIT_FRAME * frame() const
HANDLER_RESULT< BoardEnabledLayersResponse > handleSetBoardEnabledLayers(const HANDLER_CONTEXT< SetBoardEnabledLayers > &aCtx)
HANDLER_RESULT< Empty > handleSetBoardEditorAppearanceSettings(const HANDLER_CONTEXT< SetBoardEditorAppearanceSettings > &aCtx)
HANDLER_RESULT< Empty > handleRefillZones(const HANDLER_CONTEXT< RefillZones > &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< BoardLayerResponse > handleGetActiveLayer(const HANDLER_CONTEXT< GetActiveLayer > &aCtx)
HANDLER_RESULT< Empty > handleRevertDocument(const HANDLER_CONTEXT< commands::RevertDocument > &aCtx)
HANDLER_RESULT< commands::SavedSelectionResponse > handleSaveSelectionToString(const HANDLER_CONTEXT< commands::SaveSelectionToString > &aCtx)
void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage) override
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
void SetContentModified(bool aModified=true)
BASE_SET & reset(size_t pos)
BASE_SET & set(size_t pos)
Container for design settings for a BOARD object.
bool m_TextUpright[LAYER_CLASS_COUNT]
const VECTOR2I & GetGridOrigin() const
const VECTOR2I & GetAuxOrigin() const
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)
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Information pertinent to a Pcbnew printed circuit board.
BOARD_STACKUP GetStackupOrDefault() const
void SetVisibleLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
void SaveSelection(const PCB_SELECTION &selected, bool isFootprintEditor)
void SetWriter(std::function< void(const wxString &)> aWriter)
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 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.
virtual void Push(const wxString &aMessage=wxT("A commit"), int aFlags=0)=0
Execute the changes.
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.
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
void ReleaseFile()
Release the current file marked in use.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
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 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 wxString GetFriendlyName() const
void SetMirror(bool aMirrorX, bool aMirrorY)
Control the mirroring of the VIEW.
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
bool IsMirroredX() const
Return true if view is flipped across the X axis.
void RecacheAllItems()
Rebuild GAL display lists.
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
std::string AsStdString() const
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
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.
A collection of nets and the parameters used to route or test these nets.
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Handle the data for a net.
Container for NETINFO_ITEM elements, which are the nets.
NETINFO_ITEM * GetNetItem(int aNetCode) const
DISPLAY_OPTIONS m_Display
static TOOL_ACTION zoneFillAll
static TOOL_ACTION move
move or drag an item
static TOOL_ACTION drillSetOrigin
APPEARANCE_CONTROLS * GetAppearancePanel()
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
PCBNEW_SETTINGS * GetPcbNewSettings() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SetDisplayOptions(const PCB_DISPLAY_OPTIONS &aOptions, bool aRefresh=true)
Update the current display options.
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
NET_COLOR_MODE m_NetColorMode
How to use color overrides on specific nets and netclasses.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void SyncLayersVisibility(const BOARD *aBoard)
Update "visibility" property of each layer of a given BOARD.
The main frame for Pcbnew.
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
void OnModify() override
Must be called after a board change to set the modified flag.
bool SaveBoard(bool aSaveAs=false, bool aSaveCopy=false)
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Load a KiCad board (.kicad_pcb) from aFileName.
void UpdateUserInterface()
Update the layer manager and other widgets from the board setup (layer and items visibility,...
bool SavePcbCopy(const wxString &aFileName, bool aCreateProject=false, bool aHeadless=false)
Write the board data structures to aFileName.
A set of BOARD_ITEMs (i.e., without duplicates).
const KIID GetUUID() const override
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
std::vector< KIID > KIIDS
void SetReferencePoint(const VECTOR2I &aP)
virtual void Serialize(google::protobuf::Any &aContainer) const
Serializes this object to the given Any message.
Represent a set of closed polygons.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Hold the information shown in the lower right corner of a plot, printout, or editing view.
const wxString & GetCompany() const
const wxString & GetRevision() const
const wxString & GetDate() const
const wxString & GetComment(int aIdx) const
const wxString & GetTitle() const
A type-safe container of any type.
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
static const std::string KiCadPcbFileExtension
#define KICTL_REVERT
reverting to a previously-saved (KiCad) file.
@ LAYER_DRC_WARNING
Layer for DRC markers with #SEVERITY_WARNING.
@ LAYER_DRC_ERROR
Layer for DRC markers with #SEVERITY_ERROR.
PCB_LAYER_ID
A quick note on layer IDs:
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
LSET UnpackLayerSet(const google::protobuf::RepeatedField< int > &aProtoLayerSet)
KICOMMON_API void PackBox2(types::Box2 &aOutput, const BOX2I &aInput)
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput)
KICOMMON_API void PackPolyLine(types::PolyLine &aOutput, const SHAPE_LINE_CHAIN &aSlc)
Class to handle a set of BOARD_ITEMs.
std::vector< EDA_ITEM * > EDA_ITEMS
RequestMessageType Request
RATSNEST_MODE m_RatsnestMode
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
@ 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_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_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ 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_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
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D