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;
135 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
136 return tl::unexpected( *busy );
138 RunActionResponse response;
140 if(
frame()->GetToolManager()->RunAction( aCtx.
Request.action(),
true ) )
141 response.set_status( RunActionStatus::RAS_OK );
143 response.set_status( RunActionStatus::RAS_INVALID );
152 if( aCtx.
Request.type() != DocumentType::DOCTYPE_PCB )
156 e.set_status( ApiStatusCode::AS_UNHANDLED );
157 return tl::unexpected( e );
160 GetOpenDocumentsResponse response;
161 common::types::DocumentSpecifier doc;
163 wxFileName fn(
frame()->GetCurrentFileName() );
165 doc.set_type( DocumentType::DOCTYPE_PCB );
166 doc.set_board_filename( fn.GetFullName() );
168 doc.mutable_project()->set_name(
frame()->
Prj().GetProjectName().ToStdString() );
169 doc.mutable_project()->set_path(
frame()->
Prj().GetProjectDirectory().ToStdString() );
171 response.mutable_documents()->Add( std::move( doc ) );
179 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
180 return tl::unexpected( *busy );
184 if( !documentValidation )
185 return tl::unexpected( documentValidation.error() );
195 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
196 return tl::unexpected( *busy );
200 if( !documentValidation )
201 return tl::unexpected( documentValidation.error() );
203 wxFileName boardPath(
frame()->
Prj().AbsolutePath( wxString::FromUTF8( aCtx.
Request.path() ) ) );
205 if( !boardPath.IsOk() || !boardPath.IsDirWritable() )
208 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
209 e.set_error_message( fmt::format(
"save path '{}' could not be opened",
210 boardPath.GetFullPath().ToStdString() ) );
211 return tl::unexpected( e );
214 if( boardPath.FileExists()
215 && ( !boardPath.IsFileWritable() || !aCtx.
Request.options().overwrite() ) )
218 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
219 e.set_error_message( fmt::format(
"save path '{}' exists and cannot be overwritten",
220 boardPath.GetFullPath().ToStdString() ) );
221 return tl::unexpected( e );
227 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
228 e.set_error_message( fmt::format(
"save path '{}' must have a kicad_pcb extension",
229 boardPath.GetFullPath().ToStdString() ) );
230 return tl::unexpected( e );
235 if(
board->GetFileName().Matches( boardPath.GetFullPath() ) )
241 bool includeProject =
true;
243 if( aCtx.
Request.has_options() )
244 includeProject = aCtx.
Request.options().include_project();
255 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
256 return tl::unexpected( *busy );
260 if( !documentValidation )
261 return tl::unexpected( documentValidation.error() );
282 return std::make_unique<BOARD_COMMIT>(
frame() );
299 if( aDocument.type() != DocumentType::DOCTYPE_PCB )
302 wxFileName fn(
frame()->GetCurrentFileName() );
303 return 0 == aDocument.board_filename().compare( fn.GetFullName() );
313 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
314 e.set_error_message(
"Tried to create an item in a null container" );
315 return tl::unexpected( e );
321 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
322 e.set_error_message( fmt::format(
"Tried to create a pad in {}, which is not a footprint",
324 return tl::unexpected( e );
329 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
330 e.set_error_message( fmt::format(
"Tried to create a footprint in {}, which is not a board",
332 return tl::unexpected( e );
340 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
341 e.set_error_message( fmt::format(
"Tried to create an item of type {}, which is unhandled",
342 magic_enum::enum_name( aType ) ) );
343 return tl::unexpected( e );
351 const std::string& aClientName,
352 const types::ItemHeader &aHeader,
353 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
354 std::function<
void( ItemStatus, google::protobuf::Any )> aItemHandler )
360 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
363 e.set_status( ApiStatusCode::AS_UNHANDLED );
364 return tl::unexpected( e );
366 else if( !containerResult )
368 e.CopyFrom( containerResult.error() );
369 return tl::unexpected( e );
375 if( containerResult->has_value() )
377 const KIID& containerId = **containerResult;
378 std::optional<BOARD_ITEM*> optItem =
getItemById( containerId );
386 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
387 e.set_error_message( fmt::format(
388 "The requested container {} is not a valid board item container",
390 return tl::unexpected( e );
395 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
396 e.set_error_message( fmt::format(
397 "The requested container {} does not exist in this document",
399 return tl::unexpected( e );
405 for(
const google::protobuf::Any& anyItem : aItems )
412 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
413 status.set_error_message( fmt::format(
"Could not decode a valid type from {}",
414 anyItem.type_url() ) );
415 aItemHandler( status, anyItem );
421 board::types::Dimension dimension;
422 anyItem.UnpackTo( &dimension );
424 switch( dimension.dimension_style_case() )
431 case board::types::Dimension::DIMENSION_STYLE_NOT_SET:
break;
438 if( !creationResult )
440 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
441 status.set_error_message( creationResult.error().error_message() );
442 aItemHandler( status, anyItem );
446 std::unique_ptr<BOARD_ITEM> item( std::move( *creationResult ) );
448 if( !item->Deserialize( anyItem ) )
450 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
451 e.set_error_message( fmt::format(
"could not unpack {} from request",
452 item->GetClass().ToStdString() ) );
453 return tl::unexpected( e );
456 std::optional<BOARD_ITEM*> optItem =
getItemById( item->m_Uuid );
458 if( aCreate && optItem )
460 status.set_code( ItemStatusCode::ISC_EXISTING );
461 status.set_error_message( fmt::format(
"an item with UUID {} already exists",
462 item->m_Uuid.AsStdString() ) );
463 aItemHandler( status, anyItem );
466 else if( !aCreate && !optItem )
468 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
469 status.set_error_message( fmt::format(
"an item with UUID {} does not exist",
470 item->m_Uuid.AsStdString() ) );
471 aItemHandler( status, anyItem );
475 if( aCreate && !(
board->GetEnabledLayers() & item->GetLayerSet() ).any() )
477 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
478 status.set_error_message(
479 "attempted to add item with no overlapping layers with the board" );
480 aItemHandler( status, anyItem );
484 status.set_code( ItemStatusCode::ISC_OK );
485 google::protobuf::Any newItem;
501 item->Serialize( newItem );
502 commit->
Add( item.release() );
519 commit->
Remove( boardItem );
520 item->Serialize( newItem );
523 commit->
Add( newBoardItem );
527 parentGroup->
AddItem( newBoardItem );
531 commit->
Modify( boardItem );
537 aItemHandler( status, newItem );
543 :
_(
"Modified items via API" ) );
547 return ItemRequestStatus::IRS_OK;
553 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
554 return tl::unexpected( *busy );
560 e.set_status( ApiStatusCode::AS_UNHANDLED );
561 return tl::unexpected( e );
564 GetItemsResponse response;
567 std::vector<BOARD_ITEM*> items;
568 std::set<KICAD_T> typesRequested, typesInserted;
569 bool handledAnything =
false;
571 for(
int typeRaw : aCtx.
Request.types() )
573 auto typeMessage =
static_cast<common::types::KiCadObjectType
>( typeRaw );
579 typesRequested.emplace( type );
581 if( typesInserted.count( type ) )
589 handledAnything =
true;
590 std::copy(
board->Tracks().begin(),
board->Tracks().end(),
591 std::back_inserter( items ) );
597 handledAnything =
true;
601 std::copy( fp->Pads().begin(), fp->Pads().end(),
602 std::back_inserter( items ) );
611 handledAnything =
true;
613 std::copy(
board->Footprints().begin(),
board->Footprints().end(),
614 std::back_inserter( items ) );
625 handledAnything =
true;
626 bool inserted =
false;
630 if( item->Type() == type )
632 items.emplace_back( item );
638 typesInserted.insert( type );
645 handledAnything =
true;
647 std::copy(
board->Zones().begin(),
board->Zones().end(),
648 std::back_inserter( items ) );
656 handledAnything =
true;
658 std::copy(
board->Groups().begin(),
board->Groups().end(),
659 std::back_inserter( items ) );
669 if( !handledAnything )
672 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
673 e.set_error_message(
"none of the requested types are valid for a Board object" );
674 return tl::unexpected( e );
679 if( !typesRequested.count( item->Type() ) )
682 google::protobuf::Any itemBuf;
683 item->Serialize( itemBuf );
684 response.mutable_items()->Add( std::move( itemBuf ) );
687 response.set_status( ItemRequestStatus::IRS_OK );
695 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
696 return tl::unexpected( *busy );
701 e.set_status( ApiStatusCode::AS_UNHANDLED );
702 return tl::unexpected( e );
705 GetItemsResponse response;
707 std::vector<BOARD_ITEM*> items;
709 for(
const kiapi::common::types::KIID&
id : aCtx.
Request.items() )
711 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
712 items.emplace_back( *item );
718 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
719 e.set_error_message(
"none of the requested IDs were found or valid" );
720 return tl::unexpected( e );
725 google::protobuf::Any itemBuf;
726 item->Serialize( itemBuf );
727 response.mutable_items()->Add( std::move( itemBuf ) );
730 response.set_status( ItemRequestStatus::IRS_OK );
735 const std::string& aClientName )
738 std::vector<BOARD_ITEM*> validatedItems;
740 for( std::pair<const KIID, ItemDeletionStatus> pair : aItemsToDelete )
744 validatedItems.push_back( item );
745 aItemsToDelete[pair.first] = ItemDeletionStatus::IDS_OK;
779 e.set_status( ApiStatusCode::AS_UNHANDLED );
780 return tl::unexpected( e );
785 for(
int typeRaw : aCtx.
Request.types() )
787 auto typeMessage =
static_cast<types::KiCadObjectType
>( typeRaw );
799 SelectionResponse response;
804 item->Serialize( *response.add_items() );
814 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
815 return tl::unexpected( *busy );
821 e.set_status( ApiStatusCode::AS_UNHANDLED );
822 return tl::unexpected( e );
836 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
837 return tl::unexpected( *busy );
843 e.set_status( ApiStatusCode::AS_UNHANDLED );
844 return tl::unexpected( e );
850 std::vector<EDA_ITEM*> toAdd;
852 for(
const types::KIID&
id : aCtx.
Request.items() )
854 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
855 toAdd.emplace_back( *item );
861 SelectionResponse response;
864 item->Serialize( *response.add_items() );
873 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
874 return tl::unexpected( *busy );
880 e.set_status( ApiStatusCode::AS_UNHANDLED );
881 return tl::unexpected( e );
887 std::vector<EDA_ITEM*> toRemove;
889 for(
const types::KIID&
id : aCtx.
Request.items() )
891 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
892 toRemove.emplace_back( *item );
898 SelectionResponse response;
901 item->Serialize( *response.add_items() );
912 if( !documentValidation )
913 return tl::unexpected( documentValidation.error() );
915 BoardStackupResponse response;
916 google::protobuf::Any
any;
920 any.UnpackTo( response.mutable_stackup() );
923 for( board::BoardStackupLayer& layer : *response.mutable_stackup()->mutable_layers() )
925 if( layer.type() == board::BoardStackupLayerType::BSLT_DIELECTRIC )
931 layer.set_user_name(
frame()->
GetBoard()->GetLayerName(
id ) );
943 if( !documentValidation )
944 return tl::unexpected( documentValidation.error() );
946 BoardEnabledLayersResponse response;
949 int copperLayerCount =
board->GetCopperLayerCount();
951 response.set_copper_layer_count( copperLayerCount );
953 LSET enabled =
board->GetEnabledLayers();
972 if( !documentValidation )
973 return tl::unexpected( documentValidation.error() );
975 if( aCtx.
Request.copper_layer_count() % 2 != 0 )
978 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
979 e.set_error_message(
"copper_layer_count must be an even number" );
980 return tl::unexpected( e );
986 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
987 e.set_error_message( fmt::format(
"copper_layer_count must be below %d",
MAX_CU_LAYERS ) );
988 return tl::unexpected( e );
991 int copperLayerCount =
static_cast<int>( aCtx.
Request.copper_layer_count() );
996 enabled &=
~LSET::AllCuMask();
1001 LSET previousEnabled =
board->GetEnabledLayers();
1002 LSET changedLayers = enabled ^ previousEnabled;
1004 board->SetEnabledLayers( enabled );
1005 board->SetVisibleLayers(
board->GetVisibleLayers() | changedLayers );
1011 if( !enabled[layer_id] &&
board->HasItemsOnLayer( layer_id ) )
1012 removedLayers.push_back( layer_id );
1015 bool modified =
false;
1017 if( !removedLayers.empty() )
1022 modified |=
board->RemoveAllItemsOnLayer( layer_id );
1025 if( enabled != previousEnabled )
1031 BoardEnabledLayersResponse response;
1033 response.set_copper_layer_count( copperLayerCount );
1045 if( !documentValidation )
1046 return tl::unexpected( documentValidation.error() );
1049 GraphicsDefaultsResponse response;
1052 constexpr std::array<kiapi::board::BoardLayerClass, LAYER_CLASS_COUNT> classOrder = {
1053 kiapi::board::BLC_SILKSCREEN,
1054 kiapi::board::BLC_COPPER,
1055 kiapi::board::BLC_EDGES,
1056 kiapi::board::BLC_COURTYARD,
1057 kiapi::board::BLC_FABRICATION,
1058 kiapi::board::BLC_OTHER
1063 kiapi::board::BoardLayerGraphicsDefaults* l = response.mutable_defaults()->add_layers();
1065 l->set_layer( classOrder[i] );
1068 kiapi::common::types::TextAttributes*
text = l->mutable_text();
1084 !documentValidation )
1086 return tl::unexpected( documentValidation.error() );
1105 ApiResponseStatus e;
1106 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1107 e.set_error_message(
"Unexpected origin type" );
1108 return tl::unexpected( e );
1112 types::Vector2 reply;
1120 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1121 return tl::unexpected( *busy );
1124 !documentValidation )
1126 return tl::unexpected( documentValidation.error() );
1137 frame()->CallAfter( [f, origin]()
1152 frame()->CallAfter( [f, origin]()
1164 ApiResponseStatus e;
1165 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1166 e.set_error_message(
"Unexpected origin type" );
1167 return tl::unexpected( e );
1178 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1179 return tl::unexpected( *busy );
1183 ApiResponseStatus e;
1185 e.set_status( ApiStatusCode::AS_UNHANDLED );
1186 return tl::unexpected( e );
1189 GetBoundingBoxResponse response;
1190 bool includeText = aCtx.
Request.mode() == BoundingBoxMode::BBM_ITEM_AND_CHILD_TEXT;
1192 for(
const types::KIID& idMsg : aCtx.
Request.items() )
1194 KIID id( idMsg.value() );
1195 std::optional<BOARD_ITEM*> optItem =
getItemById(
id );
1204 bbox =
static_cast<FOOTPRINT*
>( item )->GetBoundingBox( includeText );
1208 response.add_items()->set_value( idMsg.value() );
1209 PackBox2( *response.add_boxes(), bbox );
1220 !documentValidation )
1222 return tl::unexpected( documentValidation.error() );
1225 PadShapeAsPolygonResponse response;
1228 for(
const types::KIID& padRequest : aCtx.
Request.pads() )
1230 KIID id( padRequest.value() );
1231 std::optional<BOARD_ITEM*> optPad =
getItemById(
id );
1233 if( !optPad || ( *optPad )->Type() !=
PCB_PAD_T )
1236 response.add_pads()->set_value( padRequest.value() );
1238 PAD*
pad =
static_cast<PAD*
>( *optPad );
1240 pad->TransformShapeToPolygon( poly,
pad->Padstack().EffectiveLayerFor( layer ), 0,
1243 types::PolygonWithHoles* polyMsg = response.mutable_polygons()->Add();
1254 using board::types::BoardLayer;
1257 !documentValidation )
1259 return tl::unexpected( documentValidation.error() );
1262 PadstackPresenceResponse response;
1266 for(
const int layer : aCtx.
Request.layers() )
1269 for(
const types::KIID& padRequest : aCtx.
Request.items() )
1271 KIID id( padRequest.value() );
1272 std::optional<BOARD_ITEM*> optItem =
getItemById(
id );
1277 switch( ( *optItem )->Type() )
1281 PAD*
pad =
static_cast<PAD*
>( *optItem );
1285 PadstackPresenceEntry* entry = response.add_entries();
1286 entry->mutable_item()->set_value(
pad->m_Uuid.AsStdString() );
1288 entry->set_presence(
pad->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1300 PadstackPresenceEntry* entry = response.add_entries();
1301 entry->mutable_item()->set_value(
via->m_Uuid.AsStdString() );
1303 entry->set_presence(
via->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1323 if( !documentValidation )
1324 return tl::unexpected( documentValidation.error() );
1329 types::TitleBlockInfo response;
1331 response.set_title( block.
GetTitle().ToUTF8() );
1332 response.set_date( block.
GetDate().ToUTF8() );
1333 response.set_revision( block.
GetRevision().ToUTF8() );
1334 response.set_company( block.
GetCompany().ToUTF8() );
1335 response.set_comment1( block.
GetComment( 0 ).ToUTF8() );
1336 response.set_comment2( block.
GetComment( 1 ).ToUTF8() );
1337 response.set_comment3( block.
GetComment( 2 ).ToUTF8() );
1338 response.set_comment4( block.
GetComment( 3 ).ToUTF8() );
1339 response.set_comment5( block.
GetComment( 4 ).ToUTF8() );
1340 response.set_comment6( block.
GetComment( 5 ).ToUTF8() );
1341 response.set_comment7( block.
GetComment( 6 ).ToUTF8() );
1342 response.set_comment8( block.
GetComment( 7 ).ToUTF8() );
1343 response.set_comment9( block.
GetComment( 8 ).ToUTF8() );
1354 if( !documentValidation )
1355 return tl::unexpected( documentValidation.error() );
1357 ExpandTextVariablesResponse reply;
1360 std::function<bool( wxString* )> textResolver =
1361 [&]( wxString* token ) ->
bool
1364 return board->ResolveTextVar( token, 0 );
1367 for(
const std::string& textMsg : aCtx.
Request.text() )
1370 reply.add_text(
text.ToUTF8() );
1380 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1381 return tl::unexpected( *busy );
1385 if( !documentValidation )
1386 return tl::unexpected( documentValidation.error() );
1389 std::vector<EDA_ITEM*> toSelect;
1391 for(
const kiapi::common::types::KIID&
id : aCtx.
Request.items() )
1393 if( std::optional<BOARD_ITEM*> item =
getItemById(
KIID(
id.value() ) ) )
1394 toSelect.emplace_back(
static_cast<EDA_ITEM*
>( *item ) );
1397 if( toSelect.empty() )
1399 ApiResponseStatus e;
1400 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1401 e.set_error_message( fmt::format(
"None of the given items exist on the board",
1402 aCtx.
Request.board().board_filename() ) );
1403 return tl::unexpected( e );
1423 if( !documentValidation )
1424 return tl::unexpected( documentValidation.error() );
1426 NetsResponse response;
1429 std::set<wxString> netclassFilter;
1431 for(
const std::string& nc : aCtx.
Request.netclass_filter() )
1432 netclassFilter.insert( wxString( nc.c_str(), wxConvUTF8 ) );
1438 if( !netclassFilter.empty() && nc && !netclassFilter.count( nc->
GetName() ) )
1441 board::types::Net* netProto = response.add_nets();
1442 netProto->set_name( net->GetNetname() );
1443 netProto->mutable_code()->set_value( net->GetNetCode() );
1453 NetClassForNetsResponse response;
1457 google::protobuf::Any
any;
1459 for(
const board::types::Net& net : aCtx.
Request.net() )
1467 auto [pair, rc] = response.mutable_classes()->insert( { net.name(), {} } );
1468 any.UnpackTo( &pair->second );
1477 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1478 return tl::unexpected( *busy );
1482 if( !documentValidation )
1483 return tl::unexpected( documentValidation.error() );
1485 if( aCtx.
Request.zones().empty() )
1488 frame()->CallAfter( [mgr]()
1496 ApiResponseStatus e;
1497 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
1498 return tl::unexpected( e );
1510 if( !documentValidation )
1511 return tl::unexpected( documentValidation.error() );
1513 SavedDocumentResponse response;
1514 response.mutable_document()->CopyFrom( aCtx.
Request.document() );
1518 [&](
const wxString& aData )
1520 response.set_contents( aData.ToUTF8() );
1532 SavedSelectionResponse response;
1540 [&](
const wxString& aData )
1542 response.set_contents( aData.ToUTF8() );
1555 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1556 return tl::unexpected( *busy );
1560 if( !documentValidation )
1561 return tl::unexpected( documentValidation.error() );
1563 CreateItemsResponse response;
1573 if( !documentValidation )
1574 return tl::unexpected( documentValidation.error() );
1576 BoardLayers response;
1588 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1589 return tl::unexpected( *busy );
1593 if( !documentValidation )
1594 return tl::unexpected( documentValidation.error() );
1599 for(
int layerIdx : aCtx.
Request.layers() )
1605 visible.
set( layer );
1621 if( !documentValidation )
1622 return tl::unexpected( documentValidation.error() );
1624 BoardLayerResponse response;
1635 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1636 return tl::unexpected( *busy );
1640 if( !documentValidation )
1641 return tl::unexpected( documentValidation.error() );
1645 if( !
frame()->
GetBoard()->GetEnabledLayers().Contains( layer ) )
1647 ApiResponseStatus err;
1648 err.set_status( ApiStatusCode::AS_BAD_REQUEST );
1649 err.set_error_message( fmt::format(
"Layer {} is not a valid layer for the given board",
1650 magic_enum::enum_name( layer ) ) );
1651 return tl::unexpected( err );
1662 BoardEditorAppearanceSettings reply;
1670 reply.set_net_color_display(
1673 reply.set_board_flip(
frame()->GetCanvas()->GetView()->IsMirroredX()
1674 ? BoardFlipMode::BFM_FLIPPED_X
1675 : BoardFlipMode::BFM_NORMAL );
1689 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1690 return tl::unexpected( *busy );
1695 const BoardEditorAppearanceSettings& newSettings = aCtx.
Request.settings();
1702 bool flip = newSettings.board_flip() == BoardFlipMode::BFM_FLIPPED_X;
1724 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
1725 return tl::unexpected( *busy );
1729 if( !documentValidation )
1730 return tl::unexpected( documentValidation.error() );
1738 drcItem->SetErrorMessage( wxString::FromUTF8( aCtx.
Request.message() ) );
1742 for(
const auto&
id : aCtx.
Request.items() )
1743 ids.emplace_back(
KIID(
id.value() ) );
1746 drcItem->SetItems( ids );
1748 const auto& pos = aCtx.
Request.position();
1749 VECTOR2I position(
static_cast<int>( pos.x_nm() ),
static_cast<int>( pos.y_nm() ) );
1754 commit->
Add( marker );
1755 commit->
Push( wxS(
"API injected DRC marker" ) );
1757 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< 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 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