KiCad PCB EDA Suite
Loading...
Searching...
No Matches
api_handler_pcb.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 Jon Evans <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <magic_enum.hpp>
22
23#include <api/api_handler_pcb.h>
24#include <api/api_pcb_utils.h>
25#include <api/api_enums.h>
26#include <api/api_utils.h>
27#include <board_commit.h>
29#include <footprint.h>
30#include <kicad_clipboard.h>
31#include <netinfo.h>
32#include <pad.h>
33#include <pcb_edit_frame.h>
34#include <pcb_group.h>
35#include <pcb_reference_image.h>
36#include <pcb_shape.h>
37#include <pcb_text.h>
38#include <pcb_textbox.h>
39#include <pcb_track.h>
40#include <pcbnew_id.h>
41#include <pcb_marker.h>
42#include <drc/drc_item.h>
43#include <layer_ids.h>
44#include <project.h>
45#include <tool/tool_manager.h>
46#include <tools/pcb_actions.h>
48#include <zone.h>
49
50#include <api/common/types/base_types.pb.h>
53
54using namespace kiapi::common::commands;
55using types::CommandStatus;
56using types::DocumentType;
57using types::ItemRequestStatus;
58
59
61 API_HANDLER_EDITOR( aFrame )
62{
69
72
78
98
104
121}
122
123
125{
126 return static_cast<PCB_EDIT_FRAME*>( m_frame );
127}
128
129
131 const HANDLER_CONTEXT<RunAction>& aCtx )
132{
133 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
134 return tl::unexpected( *busy );
135
136 RunActionResponse response;
137
138 if( frame()->GetToolManager()->RunAction( aCtx.Request.action(), true ) )
139 response.set_status( RunActionStatus::RAS_OK );
140 else
141 response.set_status( RunActionStatus::RAS_INVALID );
142
143 return response;
144}
145
146
149{
150 if( aCtx.Request.type() != DocumentType::DOCTYPE_PCB )
151 {
152 ApiResponseStatus e;
153 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
154 e.set_status( ApiStatusCode::AS_UNHANDLED );
155 return tl::unexpected( e );
156 }
157
158 GetOpenDocumentsResponse response;
159 common::types::DocumentSpecifier doc;
160
161 wxFileName fn( frame()->GetCurrentFileName() );
162
163 doc.set_type( DocumentType::DOCTYPE_PCB );
164 doc.set_board_filename( fn.GetFullName() );
165
166 doc.mutable_project()->set_name( frame()->Prj().GetProjectName().ToStdString() );
167 doc.mutable_project()->set_path( frame()->Prj().GetProjectDirectory().ToStdString() );
168
169 response.mutable_documents()->Add( std::move( doc ) );
170 return response;
171}
172
173
176{
177 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
178 return tl::unexpected( *busy );
179
180 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
181
182 if( !documentValidation )
183 return tl::unexpected( documentValidation.error() );
184
185 frame()->SaveBoard();
186 return Empty();
187}
188
189
192{
193 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
194 return tl::unexpected( *busy );
195
196 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
197
198 if( !documentValidation )
199 return tl::unexpected( documentValidation.error() );
200
201 wxFileName boardPath( frame()->Prj().AbsolutePath( wxString::FromUTF8( aCtx.Request.path() ) ) );
202
203 if( !boardPath.IsOk() || !boardPath.IsDirWritable() )
204 {
205 ApiResponseStatus e;
206 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
207 e.set_error_message( fmt::format( "save path '{}' could not be opened",
208 boardPath.GetFullPath().ToStdString() ) );
209 return tl::unexpected( e );
210 }
211
212 if( boardPath.FileExists()
213 && ( !boardPath.IsFileWritable() || !aCtx.Request.options().overwrite() ) )
214 {
215 ApiResponseStatus e;
216 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
217 e.set_error_message( fmt::format( "save path '{}' exists and cannot be overwritten",
218 boardPath.GetFullPath().ToStdString() ) );
219 return tl::unexpected( e );
220 }
221
222 if( boardPath.GetExt() != FILEEXT::KiCadPcbFileExtension )
223 {
224 ApiResponseStatus e;
225 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
226 e.set_error_message( fmt::format( "save path '{}' must have a kicad_pcb extension",
227 boardPath.GetFullPath().ToStdString() ) );
228 return tl::unexpected( e );
229 }
230
231 BOARD* board = frame()->GetBoard();
232
233 if( board->GetFileName().Matches( boardPath.GetFullPath() ) )
234 {
235 frame()->SaveBoard();
236 return Empty();
237 }
238
239 bool includeProject = true;
240
241 if( aCtx.Request.has_options() )
242 includeProject = aCtx.Request.options().include_project();
243
244 frame()->SavePcbCopy( boardPath.GetFullPath(), includeProject, /* aHeadless = */ true );
245
246 return Empty();
247}
248
249
252{
253 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
254 return tl::unexpected( *busy );
255
256 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
257
258 if( !documentValidation )
259 return tl::unexpected( documentValidation.error() );
260
261 wxFileName fn = frame()->Prj().AbsolutePath( frame()->GetBoard()->GetFileName() );
262
263 frame()->GetScreen()->SetContentModified( false );
264 frame()->ReleaseFile();
265 frame()->OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ), KICTL_REVERT );
266
267 return Empty();
268}
269
270
271void API_HANDLER_PCB::pushCurrentCommit( const std::string& aClientName, const wxString& aMessage )
272{
273 API_HANDLER_EDITOR::pushCurrentCommit( aClientName, aMessage );
274 frame()->Refresh();
275}
276
277
278std::unique_ptr<COMMIT> API_HANDLER_PCB::createCommit()
279{
280 return std::make_unique<BOARD_COMMIT>( frame() );
281}
282
283
284std::optional<BOARD_ITEM*> API_HANDLER_PCB::getItemById( const KIID& aId ) const
285{
286 BOARD_ITEM* item = frame()->GetBoard()->ResolveItem( aId, true );
287
288 if( !item )
289 return std::nullopt;
290
291 return item;
292}
293
294
295bool API_HANDLER_PCB::validateDocumentInternal( const DocumentSpecifier& aDocument ) const
296{
297 if( aDocument.type() != DocumentType::DOCTYPE_PCB )
298 return false;
299
300 wxFileName fn( frame()->GetCurrentFileName() );
301 return 0 == aDocument.board_filename().compare( fn.GetFullName() );
302}
303
304
306 BOARD_ITEM_CONTAINER* aContainer )
307{
308 if( !aContainer )
309 {
310 ApiResponseStatus e;
311 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
312 e.set_error_message( "Tried to create an item in a null container" );
313 return tl::unexpected( e );
314 }
315
316 if( aType == PCB_PAD_T && !dynamic_cast<FOOTPRINT*>( aContainer ) )
317 {
318 ApiResponseStatus e;
319 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
320 e.set_error_message( fmt::format( "Tried to create a pad in {}, which is not a footprint",
321 aContainer->GetFriendlyName().ToStdString() ) );
322 return tl::unexpected( e );
323 }
324 else if( aType == PCB_FOOTPRINT_T && !dynamic_cast<BOARD*>( aContainer ) )
325 {
326 ApiResponseStatus e;
327 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
328 e.set_error_message( fmt::format( "Tried to create a footprint in {}, which is not a board",
329 aContainer->GetFriendlyName().ToStdString() ) );
330 return tl::unexpected( e );
331 }
332
333 std::unique_ptr<BOARD_ITEM> created = CreateItemForType( aType, aContainer );
334
335 if( !created )
336 {
337 ApiResponseStatus e;
338 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
339 e.set_error_message( fmt::format( "Tried to create an item of type {}, which is unhandled",
340 magic_enum::enum_name( aType ) ) );
341 return tl::unexpected( e );
342 }
343
344 return created;
345}
346
347
349 const std::string& aClientName,
350 const types::ItemHeader &aHeader,
351 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
352 std::function<void( ItemStatus, google::protobuf::Any )> aItemHandler )
353{
354 ApiResponseStatus e;
355
356 auto containerResult = validateItemHeaderDocument( aHeader );
357
358 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
359 {
360 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
361 e.set_status( ApiStatusCode::AS_UNHANDLED );
362 return tl::unexpected( e );
363 }
364 else if( !containerResult )
365 {
366 e.CopyFrom( containerResult.error() );
367 return tl::unexpected( e );
368 }
369
370 BOARD* board = frame()->GetBoard();
371 BOARD_ITEM_CONTAINER* container = board;
372
373 if( containerResult->has_value() )
374 {
375 const KIID& containerId = **containerResult;
376 std::optional<BOARD_ITEM*> optItem = getItemById( containerId );
377
378 if( optItem )
379 {
380 container = dynamic_cast<BOARD_ITEM_CONTAINER*>( *optItem );
381
382 if( !container )
383 {
384 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
385 e.set_error_message( fmt::format(
386 "The requested container {} is not a valid board item container",
387 containerId.AsStdString() ) );
388 return tl::unexpected( e );
389 }
390 }
391 else
392 {
393 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
394 e.set_error_message( fmt::format(
395 "The requested container {} does not exist in this document",
396 containerId.AsStdString() ) );
397 return tl::unexpected( e );
398 }
399 }
400
401 BOARD_COMMIT* commit = static_cast<BOARD_COMMIT*>( getCurrentCommit( aClientName ) );
402
403 for( const google::protobuf::Any& anyItem : aItems )
404 {
405 ItemStatus status;
406 std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
407
408 if( !type )
409 {
410 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
411 status.set_error_message( fmt::format( "Could not decode a valid type from {}",
412 anyItem.type_url() ) );
413 aItemHandler( status, anyItem );
414 continue;
415 }
416
417 if( type == PCB_DIMENSION_T )
418 {
419 board::types::Dimension dimension;
420 anyItem.UnpackTo( &dimension );
421
422 switch( dimension.dimension_style_case() )
423 {
424 case board::types::Dimension::kAligned: type = PCB_DIM_ALIGNED_T; break;
425 case board::types::Dimension::kOrthogonal: type = PCB_DIM_ORTHOGONAL_T; break;
426 case board::types::Dimension::kRadial: type = PCB_DIM_RADIAL_T; break;
427 case board::types::Dimension::kLeader: type = PCB_DIM_LEADER_T; break;
428 case board::types::Dimension::kCenter: type = PCB_DIM_CENTER_T; break;
429 case board::types::Dimension::DIMENSION_STYLE_NOT_SET: break;
430 }
431 }
432
434 createItemForType( *type, container );
435
436 if( !creationResult )
437 {
438 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
439 status.set_error_message( creationResult.error().error_message() );
440 aItemHandler( status, anyItem );
441 continue;
442 }
443
444 std::unique_ptr<BOARD_ITEM> item( std::move( *creationResult ) );
445
446 if( !item->Deserialize( anyItem ) )
447 {
448 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
449 e.set_error_message( fmt::format( "could not unpack {} from request",
450 item->GetClass().ToStdString() ) );
451 return tl::unexpected( e );
452 }
453
454 std::optional<BOARD_ITEM*> optItem = getItemById( item->m_Uuid );
455
456 if( aCreate && optItem )
457 {
458 status.set_code( ItemStatusCode::ISC_EXISTING );
459 status.set_error_message( fmt::format( "an item with UUID {} already exists",
460 item->m_Uuid.AsStdString() ) );
461 aItemHandler( status, anyItem );
462 continue;
463 }
464 else if( !aCreate && !optItem )
465 {
466 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
467 status.set_error_message( fmt::format( "an item with UUID {} does not exist",
468 item->m_Uuid.AsStdString() ) );
469 aItemHandler( status, anyItem );
470 continue;
471 }
472
473 if( aCreate && !( board->GetEnabledLayers() & item->GetLayerSet() ).any() )
474 {
475 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
476 status.set_error_message(
477 "attempted to add item with no overlapping layers with the board" );
478 aItemHandler( status, anyItem );
479 continue;
480 }
481
482 status.set_code( ItemStatusCode::ISC_OK );
483 google::protobuf::Any newItem;
484
485 if( aCreate )
486 {
487 if( item->Type() == PCB_FOOTPRINT_T )
488 {
489 // Ensure children have unique identifiers; in case the API client created this new
490 // footprint by cloning an existing one and only changing the parent UUID.
491 item->RunOnChildren(
492 []( BOARD_ITEM* aChild )
493 {
494 const_cast<KIID&>( aChild->m_Uuid ) = KIID();
495 },
496 RECURSE );
497 }
498
499 item->Serialize( newItem );
500 commit->Add( item.release() );
501 }
502 else
503 {
504 BOARD_ITEM* boardItem = *optItem;
505
506 // Footprints can't be modified by CopyFrom at the moment because the commit system
507 // doesn't currently know what to do with a footprint that has had its children
508 // replaced with other children; which results in things like the view not having its
509 // cached geometry for footprint children updated when you move a footprint around.
510 // And also, groups are special because they can contain any item type, so we
511 // can't use CopyFrom on them either.
512 if( boardItem->Type() == PCB_FOOTPRINT_T || boardItem->Type() == PCB_GROUP_T )
513 {
514 // Save group membership before removal, since Remove() severs the relationship
515 PCB_GROUP* parentGroup = dynamic_cast<PCB_GROUP*>( boardItem->GetParentGroup() );
516
517 commit->Remove( boardItem );
518 item->Serialize( newItem );
519
520 BOARD_ITEM* newBoardItem = item.release();
521 commit->Add( newBoardItem );
522
523 // Restore group membership for the newly added item
524 if( parentGroup )
525 parentGroup->AddItem( newBoardItem );
526 }
527 else
528 {
529 commit->Modify( boardItem );
530 boardItem->CopyFrom( item.get() );
531 boardItem->Serialize( newItem );
532 }
533 }
534
535 aItemHandler( status, newItem );
536 }
537
538 if( !m_activeClients.count( aClientName ) )
539 {
540 pushCurrentCommit( aClientName, aCreate ? _( "Created items via API" )
541 : _( "Modified items via API" ) );
542 }
543
544
545 return ItemRequestStatus::IRS_OK;
546}
547
548
550{
551 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
552 return tl::unexpected( *busy );
553
554 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
555 {
556 ApiResponseStatus e;
557 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
558 e.set_status( ApiStatusCode::AS_UNHANDLED );
559 return tl::unexpected( e );
560 }
561
562 GetItemsResponse response;
563
564 BOARD* board = frame()->GetBoard();
565 std::vector<BOARD_ITEM*> items;
566 std::set<KICAD_T> typesRequested, typesInserted;
567 bool handledAnything = false;
568
569 for( int typeRaw : aCtx.Request.types() )
570 {
571 auto typeMessage = static_cast<common::types::KiCadObjectType>( typeRaw );
572 KICAD_T type = FromProtoEnum<KICAD_T>( typeMessage );
573
574 if( type == TYPE_NOT_INIT )
575 continue;
576
577 typesRequested.emplace( type );
578
579 if( typesInserted.count( type ) )
580 continue;
581
582 switch( type )
583 {
584 case PCB_TRACE_T:
585 case PCB_ARC_T:
586 case PCB_VIA_T:
587 handledAnything = true;
588 std::copy( board->Tracks().begin(), board->Tracks().end(),
589 std::back_inserter( items ) );
590 typesInserted.insert( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } );
591 break;
592
593 case PCB_PAD_T:
594 {
595 handledAnything = true;
596
597 for( FOOTPRINT* fp : board->Footprints() )
598 {
599 std::copy( fp->Pads().begin(), fp->Pads().end(),
600 std::back_inserter( items ) );
601 }
602
603 typesInserted.insert( PCB_PAD_T );
604 break;
605 }
606
607 case PCB_FOOTPRINT_T:
608 {
609 handledAnything = true;
610
611 std::copy( board->Footprints().begin(), board->Footprints().end(),
612 std::back_inserter( items ) );
613
614 typesInserted.insert( PCB_FOOTPRINT_T );
615 break;
616 }
617
618 case PCB_SHAPE_T:
619 case PCB_TEXT_T:
620 case PCB_TEXTBOX_T:
621 case PCB_BARCODE_T:
622 {
623 handledAnything = true;
624 bool inserted = false;
625
626 for( BOARD_ITEM* item : board->Drawings() )
627 {
628 if( item->Type() == type )
629 {
630 items.emplace_back( item );
631 inserted = true;
632 }
633 }
634
635 if( inserted )
636 typesInserted.insert( type );
637
638 break;
639 }
640
641 case PCB_ZONE_T:
642 {
643 handledAnything = true;
644
645 std::copy( board->Zones().begin(), board->Zones().end(),
646 std::back_inserter( items ) );
647
648 typesInserted.insert( PCB_ZONE_T );
649 break;
650 }
651
652 case PCB_GROUP_T:
653 {
654 handledAnything = true;
655
656 std::copy( board->Groups().begin(), board->Groups().end(),
657 std::back_inserter( items ) );
658
659 typesInserted.insert( PCB_GROUP_T );
660 break;
661 }
662 default:
663 break;
664 }
665 }
666
667 if( !handledAnything )
668 {
669 ApiResponseStatus e;
670 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
671 e.set_error_message( "none of the requested types are valid for a Board object" );
672 return tl::unexpected( e );
673 }
674
675 for( const BOARD_ITEM* item : items )
676 {
677 if( !typesRequested.count( item->Type() ) )
678 continue;
679
680 google::protobuf::Any itemBuf;
681 item->Serialize( itemBuf );
682 response.mutable_items()->Add( std::move( itemBuf ) );
683 }
684
685 response.set_status( ItemRequestStatus::IRS_OK );
686 return response;
687}
688
689
692{
693 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
694 return tl::unexpected( *busy );
695
696 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
697 {
698 ApiResponseStatus e;
699 e.set_status( ApiStatusCode::AS_UNHANDLED );
700 return tl::unexpected( e );
701 }
702
703 GetItemsResponse response;
704
705 std::vector<BOARD_ITEM*> items;
706
707 for( const kiapi::common::types::KIID& id : aCtx.Request.items() )
708 {
709 if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
710 items.emplace_back( *item );
711 }
712
713 if( items.empty() )
714 {
715 ApiResponseStatus e;
716 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
717 e.set_error_message( "none of the requested IDs were found or valid" );
718 return tl::unexpected( e );
719 }
720
721 for( const BOARD_ITEM* item : items )
722 {
723 google::protobuf::Any itemBuf;
724 item->Serialize( itemBuf );
725 response.mutable_items()->Add( std::move( itemBuf ) );
726 }
727
728 response.set_status( ItemRequestStatus::IRS_OK );
729 return response;
730}
731
732void API_HANDLER_PCB::deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
733 const std::string& aClientName )
734{
735 BOARD* board = frame()->GetBoard();
736 std::vector<BOARD_ITEM*> validatedItems;
737
738 for( std::pair<const KIID, ItemDeletionStatus> pair : aItemsToDelete )
739 {
740 if( BOARD_ITEM* item = board->ResolveItem( pair.first, true ) )
741 {
742 validatedItems.push_back( item );
743 aItemsToDelete[pair.first] = ItemDeletionStatus::IDS_OK;
744 }
745
746 // Note: we don't currently support locking items from API modification, but here is where
747 // to add it in the future (and return IDS_IMMUTABLE)
748 }
749
750 COMMIT* commit = getCurrentCommit( aClientName );
751
752 for( BOARD_ITEM* item : validatedItems )
753 commit->Remove( item );
754
755 if( !m_activeClients.count( aClientName ) )
756 pushCurrentCommit( aClientName, _( "Deleted items via API" ) );
757}
758
759
760std::optional<EDA_ITEM*> API_HANDLER_PCB::getItemFromDocument( const DocumentSpecifier& aDocument,
761 const KIID& aId )
762{
763 if( !validateDocument( aDocument ) )
764 return std::nullopt;
765
766 return getItemById( aId );
767}
768
769
772{
773 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
774 {
775 ApiResponseStatus e;
776 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
777 e.set_status( ApiStatusCode::AS_UNHANDLED );
778 return tl::unexpected( e );
779 }
780
781 std::set<KICAD_T> filter;
782
783 for( int typeRaw : aCtx.Request.types() )
784 {
785 auto typeMessage = static_cast<types::KiCadObjectType>( typeRaw );
786 KICAD_T type = FromProtoEnum<KICAD_T>( typeMessage );
787
788 if( type == TYPE_NOT_INIT )
789 continue;
790
791 filter.insert( type );
792 }
793
795 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
796
797 SelectionResponse response;
798
799 for( EDA_ITEM* item : selectionTool->GetSelection() )
800 {
801 if( filter.empty() || filter.contains( item->Type() ) )
802 item->Serialize( *response.add_items() );
803 }
804
805 return response;
806}
807
808
811{
812 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
813 return tl::unexpected( *busy );
814
815 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
816 {
817 ApiResponseStatus e;
818 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
819 e.set_status( ApiStatusCode::AS_UNHANDLED );
820 return tl::unexpected( e );
821 }
822
825 frame()->Refresh();
826
827 return Empty();
828}
829
830
833{
834 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
835 return tl::unexpected( *busy );
836
837 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
838 {
839 ApiResponseStatus e;
840 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
841 e.set_status( ApiStatusCode::AS_UNHANDLED );
842 return tl::unexpected( e );
843 }
844
846 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
847
848 std::vector<EDA_ITEM*> toAdd;
849
850 for( const types::KIID& id : aCtx.Request.items() )
851 {
852 if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
853 toAdd.emplace_back( *item );
854 }
855
856 selectionTool->AddItemsToSel( &toAdd );
857 frame()->Refresh();
858
859 SelectionResponse response;
860
861 for( EDA_ITEM* item : selectionTool->GetSelection() )
862 item->Serialize( *response.add_items() );
863
864 return response;
865}
866
867
870{
871 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
872 return tl::unexpected( *busy );
873
874 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
875 {
876 ApiResponseStatus e;
877 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
878 e.set_status( ApiStatusCode::AS_UNHANDLED );
879 return tl::unexpected( e );
880 }
881
883 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
884
885 std::vector<EDA_ITEM*> toRemove;
886
887 for( const types::KIID& id : aCtx.Request.items() )
888 {
889 if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
890 toRemove.emplace_back( *item );
891 }
892
893 selectionTool->RemoveItemsFromSel( &toRemove );
894 frame()->Refresh();
895
896 SelectionResponse response;
897
898 for( EDA_ITEM* item : selectionTool->GetSelection() )
899 item->Serialize( *response.add_items() );
900
901 return response;
902}
903
904
907{
908 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
909
910 if( !documentValidation )
911 return tl::unexpected( documentValidation.error() );
912
913 BoardStackupResponse response;
914 google::protobuf::Any any;
915
917
918 any.UnpackTo( response.mutable_stackup() );
919
920 // User-settable layer names are not stored in BOARD_STACKUP at the moment
921 for( board::BoardStackupLayer& layer : *response.mutable_stackup()->mutable_layers() )
922 {
923 if( layer.type() == board::BoardStackupLayerType::BSLT_DIELECTRIC )
924 continue;
925
926 PCB_LAYER_ID id = FromProtoEnum<PCB_LAYER_ID>( layer.layer() );
927 wxCHECK2( id != UNDEFINED_LAYER, continue );
928
929 layer.set_user_name( frame()->GetBoard()->GetLayerName( id ) );
930 }
931
932 return response;
933}
934
935
938{
939 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
940
941 if( !documentValidation )
942 return tl::unexpected( documentValidation.error() );
943
944 BoardEnabledLayersResponse response;
945
946 BOARD* board = frame()->GetBoard();
947 int copperLayerCount = board->GetCopperLayerCount();
948
949 response.set_copper_layer_count( copperLayerCount );
950
951 LSET enabled = board->GetEnabledLayers();
952
953 // The Rescue layer is an internal detail and should be hidden from the API
954 enabled.reset( Rescue );
955
956 // Just in case this is out of sync; the API should always return the expected copper layers
957 enabled |= LSET::AllCuMask( copperLayerCount );
958
959 board::PackLayerSet( *response.mutable_layers(), enabled );
960
961 return response;
962}
963
964
967{
968 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
969
970 if( !documentValidation )
971 return tl::unexpected( documentValidation.error() );
972
973 if( aCtx.Request.copper_layer_count() % 2 != 0 )
974 {
975 ApiResponseStatus e;
976 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
977 e.set_error_message( "copper_layer_count must be an even number" );
978 return tl::unexpected( e );
979 }
980
981 if( aCtx.Request.copper_layer_count() > MAX_CU_LAYERS )
982 {
983 ApiResponseStatus e;
984 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
985 e.set_error_message( fmt::format( "copper_layer_count must be below %d", MAX_CU_LAYERS ) );
986 return tl::unexpected( e );
987 }
988
989 int copperLayerCount = static_cast<int>( aCtx.Request.copper_layer_count() );
990 LSET enabled = board::UnpackLayerSet( aCtx.Request.layers() );
991
992 // Sanitize the input
993 enabled |= LSET( { Edge_Cuts, Margin, F_CrtYd, B_CrtYd } );
994 enabled &= ~LSET::AllCuMask();
995 enabled |= LSET::AllCuMask( copperLayerCount );
996
997 BOARD* board = frame()->GetBoard();
998
999 LSET previousEnabled = board->GetEnabledLayers();
1000 LSET changedLayers = enabled ^ previousEnabled;
1001
1002 board->SetEnabledLayers( enabled );
1003 board->SetVisibleLayers( board->GetVisibleLayers() | changedLayers );
1004
1005 LSEQ removedLayers;
1006
1007 for( PCB_LAYER_ID layer_id : previousEnabled )
1008 {
1009 if( !enabled[layer_id] && board->HasItemsOnLayer( layer_id ) )
1010 removedLayers.push_back( layer_id );
1011 }
1012
1013 bool modified = false;
1014
1015 if( !removedLayers.empty() )
1016 {
1017 m_frame->GetToolManager()->RunAction( PCB_ACTIONS::selectionClear );
1018
1019 for( PCB_LAYER_ID layer_id : removedLayers )
1020 modified |= board->RemoveAllItemsOnLayer( layer_id );
1021 }
1022
1023 if( enabled != previousEnabled )
1025
1026 if( modified )
1027 frame()->OnModify();
1028
1029 BoardEnabledLayersResponse response;
1030
1031 response.set_copper_layer_count( copperLayerCount );
1032 board::PackLayerSet( *response.mutable_layers(), enabled );
1033
1034 return response;
1035}
1036
1037
1040{
1041 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1042
1043 if( !documentValidation )
1044 return tl::unexpected( documentValidation.error() );
1045
1047 GraphicsDefaultsResponse response;
1048
1049 // TODO: This should change to be an enum class
1050 constexpr std::array<kiapi::board::BoardLayerClass, LAYER_CLASS_COUNT> classOrder = {
1051 kiapi::board::BLC_SILKSCREEN,
1052 kiapi::board::BLC_COPPER,
1053 kiapi::board::BLC_EDGES,
1054 kiapi::board::BLC_COURTYARD,
1055 kiapi::board::BLC_FABRICATION,
1056 kiapi::board::BLC_OTHER
1057 };
1058
1059 for( int i = 0; i < LAYER_CLASS_COUNT; ++i )
1060 {
1061 kiapi::board::BoardLayerGraphicsDefaults* l = response.mutable_defaults()->add_layers();
1062
1063 l->set_layer( classOrder[i] );
1064 l->mutable_line_thickness()->set_value_nm( bds.m_LineThickness[i] );
1065
1066 kiapi::common::types::TextAttributes* text = l->mutable_text();
1067 text->mutable_size()->set_x_nm( bds.m_TextSize[i].x );
1068 text->mutable_size()->set_y_nm( bds.m_TextSize[i].y );
1069 text->mutable_stroke_width()->set_value_nm( bds.m_TextThickness[i] );
1070 text->set_italic( bds.m_TextItalic[i] );
1071 text->set_keep_upright( bds.m_TextUpright[i] );
1072 }
1073
1074 return response;
1075}
1076
1077
1080{
1081 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1082 !documentValidation )
1083 {
1084 return tl::unexpected( documentValidation.error() );
1085 }
1086
1087 VECTOR2I origin;
1088 const BOARD_DESIGN_SETTINGS& settings = frame()->GetBoard()->GetDesignSettings();
1089
1090 switch( aCtx.Request.type() )
1091 {
1092 case BOT_GRID:
1093 origin = settings.GetGridOrigin();
1094 break;
1095
1096 case BOT_DRILL:
1097 origin = settings.GetAuxOrigin();
1098 break;
1099
1100 default:
1101 case BOT_UNKNOWN:
1102 {
1103 ApiResponseStatus e;
1104 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1105 e.set_error_message( "Unexpected origin type" );
1106 return tl::unexpected( e );
1107 }
1108 }
1109
1110 types::Vector2 reply;
1111 PackVector2( reply, origin );
1112 return reply;
1113}
1114
1117{
1118 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1119 return tl::unexpected( *busy );
1120
1121 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1122 !documentValidation )
1123 {
1124 return tl::unexpected( documentValidation.error() );
1125 }
1126
1127 VECTOR2I origin = UnpackVector2( aCtx.Request.origin() );
1128
1129 switch( aCtx.Request.type() )
1130 {
1131 case BOT_GRID:
1132 {
1133 PCB_EDIT_FRAME* f = frame();
1134
1135 frame()->CallAfter( [f, origin]()
1136 {
1137 // gridSetOrigin takes ownership and frees this
1138 VECTOR2D* dorigin = new VECTOR2D( origin );
1139 TOOL_MANAGER* mgr = f->GetToolManager();
1140 mgr->RunAction( PCB_ACTIONS::gridSetOrigin, dorigin );
1141 f->Refresh();
1142 } );
1143 break;
1144 }
1145
1146 case BOT_DRILL:
1147 {
1148 PCB_EDIT_FRAME* f = frame();
1149
1150 frame()->CallAfter( [f, origin]()
1151 {
1152 TOOL_MANAGER* mgr = f->GetToolManager();
1153 mgr->RunAction( PCB_ACTIONS::drillSetOrigin, origin );
1154 f->Refresh();
1155 } );
1156 break;
1157 }
1158
1159 default:
1160 case BOT_UNKNOWN:
1161 {
1162 ApiResponseStatus e;
1163 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1164 e.set_error_message( "Unexpected origin type" );
1165 return tl::unexpected( e );
1166 }
1167 }
1168
1169 return Empty();
1170}
1171
1172
1175{
1176 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1177 return tl::unexpected( *busy );
1178
1179 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
1180 {
1181 ApiResponseStatus e;
1182 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
1183 e.set_status( ApiStatusCode::AS_UNHANDLED );
1184 return tl::unexpected( e );
1185 }
1186
1187 GetBoundingBoxResponse response;
1188 bool includeText = aCtx.Request.mode() == BoundingBoxMode::BBM_ITEM_AND_CHILD_TEXT;
1189
1190 for( const types::KIID& idMsg : aCtx.Request.items() )
1191 {
1192 KIID id( idMsg.value() );
1193 std::optional<BOARD_ITEM*> optItem = getItemById( id );
1194
1195 if( !optItem )
1196 continue;
1197
1198 BOARD_ITEM* item = *optItem;
1199 BOX2I bbox;
1200
1201 if( item->Type() == PCB_FOOTPRINT_T )
1202 bbox = static_cast<FOOTPRINT*>( item )->GetBoundingBox( includeText );
1203 else
1204 bbox = item->GetBoundingBox();
1205
1206 response.add_items()->set_value( idMsg.value() );
1207 PackBox2( *response.add_boxes(), bbox );
1208 }
1209
1210 return response;
1211}
1212
1213
1216{
1217 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1218 !documentValidation )
1219 {
1220 return tl::unexpected( documentValidation.error() );
1221 }
1222
1223 PadShapeAsPolygonResponse response;
1225
1226 for( const types::KIID& padRequest : aCtx.Request.pads() )
1227 {
1228 KIID id( padRequest.value() );
1229 std::optional<BOARD_ITEM*> optPad = getItemById( id );
1230
1231 if( !optPad || ( *optPad )->Type() != PCB_PAD_T )
1232 continue;
1233
1234 response.add_pads()->set_value( padRequest.value() );
1235
1236 PAD* pad = static_cast<PAD*>( *optPad );
1237 SHAPE_POLY_SET poly;
1238 pad->TransformShapeToPolygon( poly, pad->Padstack().EffectiveLayerFor( layer ), 0,
1239 pad->GetMaxError(), ERROR_INSIDE );
1240
1241 types::PolygonWithHoles* polyMsg = response.mutable_polygons()->Add();
1242 PackPolyLine( *polyMsg->mutable_outline(), poly.COutline( 0 ) );
1243 }
1244
1245 return response;
1246}
1247
1248
1251{
1252 using board::types::BoardLayer;
1253
1254 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1255 !documentValidation )
1256 {
1257 return tl::unexpected( documentValidation.error() );
1258 }
1259
1260 PadstackPresenceResponse response;
1261
1262 LSET layers;
1263
1264 for( const int layer : aCtx.Request.layers() )
1265 layers.set( FromProtoEnum<PCB_LAYER_ID, BoardLayer>( static_cast<BoardLayer>( layer ) ) );
1266
1267 for( const types::KIID& padRequest : aCtx.Request.items() )
1268 {
1269 KIID id( padRequest.value() );
1270 std::optional<BOARD_ITEM*> optItem = getItemById( id );
1271
1272 if( !optItem )
1273 continue;
1274
1275 switch( ( *optItem )->Type() )
1276 {
1277 case PCB_PAD_T:
1278 {
1279 PAD* pad = static_cast<PAD*>( *optItem );
1280
1281 for( PCB_LAYER_ID layer : layers )
1282 {
1283 PadstackPresenceEntry* entry = response.add_entries();
1284 entry->mutable_item()->set_value( pad->m_Uuid.AsStdString() );
1285 entry->set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( layer ) );
1286 entry->set_presence( pad->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1287 }
1288
1289 break;
1290 }
1291
1292 case PCB_VIA_T:
1293 {
1294 PCB_VIA* via = static_cast<PCB_VIA*>( *optItem );
1295
1296 for( PCB_LAYER_ID layer : layers )
1297 {
1298 PadstackPresenceEntry* entry = response.add_entries();
1299 entry->mutable_item()->set_value( via->m_Uuid.AsStdString() );
1300 entry->set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( layer ) );
1301 entry->set_presence( via->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
1302 }
1303
1304 break;
1305 }
1306
1307 default:
1308 break;
1309 }
1310 }
1311
1312 return response;
1313}
1314
1315
1318{
1319 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1320
1321 if( !documentValidation )
1322 return tl::unexpected( documentValidation.error() );
1323
1324 BOARD* board = frame()->GetBoard();
1325 const TITLE_BLOCK& block = board->GetTitleBlock();
1326
1327 types::TitleBlockInfo response;
1328
1329 response.set_title( block.GetTitle().ToUTF8() );
1330 response.set_date( block.GetDate().ToUTF8() );
1331 response.set_revision( block.GetRevision().ToUTF8() );
1332 response.set_company( block.GetCompany().ToUTF8() );
1333 response.set_comment1( block.GetComment( 0 ).ToUTF8() );
1334 response.set_comment2( block.GetComment( 1 ).ToUTF8() );
1335 response.set_comment3( block.GetComment( 2 ).ToUTF8() );
1336 response.set_comment4( block.GetComment( 3 ).ToUTF8() );
1337 response.set_comment5( block.GetComment( 4 ).ToUTF8() );
1338 response.set_comment6( block.GetComment( 5 ).ToUTF8() );
1339 response.set_comment7( block.GetComment( 6 ).ToUTF8() );
1340 response.set_comment8( block.GetComment( 7 ).ToUTF8() );
1341 response.set_comment9( block.GetComment( 8 ).ToUTF8() );
1342
1343 return response;
1344}
1345
1346
1349{
1350 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1351
1352 if( !documentValidation )
1353 return tl::unexpected( documentValidation.error() );
1354
1355 ExpandTextVariablesResponse reply;
1356 BOARD* board = frame()->GetBoard();
1357
1358 std::function<bool( wxString* )> textResolver =
1359 [&]( wxString* token ) -> bool
1360 {
1361 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
1362 return board->ResolveTextVar( token, 0 );
1363 };
1364
1365 for( const std::string& textMsg : aCtx.Request.text() )
1366 {
1367 wxString text = ExpandTextVars( wxString::FromUTF8( textMsg ), &textResolver );
1368 reply.add_text( text.ToUTF8() );
1369 }
1370
1371 return reply;
1372}
1373
1374
1377{
1378 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1379 return tl::unexpected( *busy );
1380
1381 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1382
1383 if( !documentValidation )
1384 return tl::unexpected( documentValidation.error() );
1385
1386 TOOL_MANAGER* mgr = frame()->GetToolManager();
1387 std::vector<EDA_ITEM*> toSelect;
1388
1389 for( const kiapi::common::types::KIID& id : aCtx.Request.items() )
1390 {
1391 if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
1392 toSelect.emplace_back( static_cast<EDA_ITEM*>( *item ) );
1393 }
1394
1395 if( toSelect.empty() )
1396 {
1397 ApiResponseStatus e;
1398 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1399 e.set_error_message( fmt::format( "None of the given items exist on the board",
1400 aCtx.Request.board().board_filename() ) );
1401 return tl::unexpected( e );
1402 }
1403
1404 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
1405 selectionTool->GetSelection().SetReferencePoint( toSelect[0]->GetPosition() );
1406
1408 mgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSelect );
1409
1410 COMMIT* commit = getCurrentCommit( aCtx.ClientName );
1411 mgr->PostAPIAction( PCB_ACTIONS::move, commit );
1412
1413 return Empty();
1414}
1415
1416
1418{
1419 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1420
1421 if( !documentValidation )
1422 return tl::unexpected( documentValidation.error() );
1423
1424 NetsResponse response;
1425 BOARD* board = frame()->GetBoard();
1426
1427 std::set<wxString> netclassFilter;
1428
1429 for( const std::string& nc : aCtx.Request.netclass_filter() )
1430 netclassFilter.insert( wxString( nc.c_str(), wxConvUTF8 ) );
1431
1432 for( NETINFO_ITEM* net : board->GetNetInfo() )
1433 {
1434 NETCLASS* nc = net->GetNetClass();
1435
1436 if( !netclassFilter.empty() && nc && !netclassFilter.count( nc->GetName() ) )
1437 continue;
1438
1439 board::types::Net* netProto = response.add_nets();
1440 netProto->set_name( net->GetNetname() );
1441 netProto->mutable_code()->set_value( net->GetNetCode() );
1442 }
1443
1444 return response;
1445}
1446
1447
1450{
1451 NetClassForNetsResponse response;
1452
1453 BOARD* board = frame()->GetBoard();
1454 const NETINFO_LIST& nets = board->GetNetInfo();
1455 google::protobuf::Any any;
1456
1457 for( const board::types::Net& net : aCtx.Request.net() )
1458 {
1459 NETINFO_ITEM* netInfo = nets.GetNetItem( wxString::FromUTF8( net.name() ) );
1460
1461 if( !netInfo )
1462 continue;
1463
1464 netInfo->GetNetClass()->Serialize( any );
1465 auto [pair, rc] = response.mutable_classes()->insert( { net.name(), {} } );
1466 any.UnpackTo( &pair->second );
1467 }
1468
1469 return response;
1470}
1471
1472
1474{
1475 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1476 return tl::unexpected( *busy );
1477
1478 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1479
1480 if( !documentValidation )
1481 return tl::unexpected( documentValidation.error() );
1482
1483 if( aCtx.Request.zones().empty() )
1484 {
1485 TOOL_MANAGER* mgr = frame()->GetToolManager();
1486 frame()->CallAfter( [mgr]()
1487 {
1489 } );
1490 }
1491 else
1492 {
1493 // TODO
1494 ApiResponseStatus e;
1495 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
1496 return tl::unexpected( e );
1497 }
1498
1499 return Empty();
1500}
1501
1502
1505{
1506 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1507
1508 if( !documentValidation )
1509 return tl::unexpected( documentValidation.error() );
1510
1511 SavedDocumentResponse response;
1512 response.mutable_document()->CopyFrom( aCtx.Request.document() );
1513
1514 CLIPBOARD_IO io;
1515 io.SetWriter(
1516 [&]( const wxString& aData )
1517 {
1518 response.set_contents( aData.ToUTF8() );
1519 } );
1520
1521 io.SaveBoard( wxEmptyString, frame()->GetBoard(), nullptr );
1522
1523 return response;
1524}
1525
1526
1529{
1530 SavedSelectionResponse response;
1531
1532 TOOL_MANAGER* mgr = frame()->GetToolManager();
1533 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
1534 PCB_SELECTION& selection = selectionTool->GetSelection();
1535
1536 CLIPBOARD_IO io;
1537 io.SetWriter(
1538 [&]( const wxString& aData )
1539 {
1540 response.set_contents( aData.ToUTF8() );
1541 } );
1542
1543 io.SetBoard( frame()->GetBoard() );
1544 io.SaveSelection( selection, false );
1545
1546 return response;
1547}
1548
1549
1552{
1553 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1554 return tl::unexpected( *busy );
1555
1556 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1557
1558 if( !documentValidation )
1559 return tl::unexpected( documentValidation.error() );
1560
1561 CreateItemsResponse response;
1562 return response;
1563}
1564
1565
1568{
1569 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1570
1571 if( !documentValidation )
1572 return tl::unexpected( documentValidation.error() );
1573
1574 BoardLayers response;
1575
1576 for( PCB_LAYER_ID layer : frame()->GetBoard()->GetVisibleLayers() )
1577 response.add_layers( ToProtoEnum<PCB_LAYER_ID, board::types::BoardLayer>( layer ) );
1578
1579 return response;
1580}
1581
1582
1585{
1586 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1587 return tl::unexpected( *busy );
1588
1589 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1590
1591 if( !documentValidation )
1592 return tl::unexpected( documentValidation.error() );
1593
1594 LSET visible;
1595 LSET enabled = frame()->GetBoard()->GetEnabledLayers();
1596
1597 for( int layerIdx : aCtx.Request.layers() )
1598 {
1599 PCB_LAYER_ID layer =
1600 FromProtoEnum<PCB_LAYER_ID>( static_cast<board::types::BoardLayer>( layerIdx ) );
1601
1602 if( enabled.Contains( layer ) )
1603 visible.set( layer );
1604 }
1605
1606 frame()->GetBoard()->SetVisibleLayers( visible );
1609 frame()->Refresh();
1610 return Empty();
1611}
1612
1613
1616{
1617 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1618
1619 if( !documentValidation )
1620 return tl::unexpected( documentValidation.error() );
1621
1622 BoardLayerResponse response;
1623 response.set_layer(
1625
1626 return response;
1627}
1628
1629
1632{
1633 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1634 return tl::unexpected( *busy );
1635
1636 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1637
1638 if( !documentValidation )
1639 return tl::unexpected( documentValidation.error() );
1640
1641 PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( aCtx.Request.layer() );
1642
1643 if( !frame()->GetBoard()->GetEnabledLayers().Contains( layer ) )
1644 {
1645 ApiResponseStatus err;
1646 err.set_status( ApiStatusCode::AS_BAD_REQUEST );
1647 err.set_error_message( fmt::format( "Layer {} is not a valid layer for the given board",
1648 magic_enum::enum_name( layer ) ) );
1649 return tl::unexpected( err );
1650 }
1651
1652 frame()->SetActiveLayer( layer );
1653 return Empty();
1654}
1655
1656
1659{
1660 BoardEditorAppearanceSettings reply;
1661
1662 // TODO: might be nice to put all these things in one place and have it derive SERIALIZABLE
1663
1664 const PCB_DISPLAY_OPTIONS& displayOptions = frame()->GetDisplayOptions();
1665
1666 reply.set_inactive_layer_display( ToProtoEnum<HIGH_CONTRAST_MODE, InactiveLayerDisplayMode>(
1667 displayOptions.m_ContrastModeDisplay ) );
1668 reply.set_net_color_display(
1670
1671 reply.set_board_flip( frame()->GetCanvas()->GetView()->IsMirroredX()
1672 ? BoardFlipMode::BFM_FLIPPED_X
1673 : BoardFlipMode::BFM_NORMAL );
1674
1675 PCBNEW_SETTINGS* editorSettings = frame()->GetPcbNewSettings();
1676
1677 reply.set_ratsnest_display( ToProtoEnum<RATSNEST_MODE, RatsnestDisplayMode>(
1678 editorSettings->m_Display.m_RatsnestMode ) );
1679
1680 return reply;
1681}
1682
1683
1686{
1687 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1688 return tl::unexpected( *busy );
1689
1691 KIGFX::PCB_VIEW* view = frame()->GetCanvas()->GetView();
1692 PCBNEW_SETTINGS* editorSettings = frame()->GetPcbNewSettings();
1693 const BoardEditorAppearanceSettings& newSettings = aCtx.Request.settings();
1694
1695 options.m_ContrastModeDisplay =
1696 FromProtoEnum<HIGH_CONTRAST_MODE>( newSettings.inactive_layer_display() );
1697 options.m_NetColorMode =
1698 FromProtoEnum<NET_COLOR_MODE>( newSettings.net_color_display() );
1699
1700 bool flip = newSettings.board_flip() == BoardFlipMode::BFM_FLIPPED_X;
1701
1702 if( flip != view->IsMirroredX() )
1703 {
1704 view->SetMirror( !view->IsMirroredX(), view->IsMirroredY() );
1705 view->RecacheAllItems();
1706 }
1707
1708 editorSettings->m_Display.m_RatsnestMode =
1709 FromProtoEnum<RATSNEST_MODE>( newSettings.ratsnest_display() );
1710
1711 frame()->SetDisplayOptions( options );
1713 frame()->GetCanvas()->Refresh();
1714
1715 return Empty();
1716}
1717
1718
1721{
1722 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1723 return tl::unexpected( *busy );
1724
1725 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1726
1727 if( !documentValidation )
1728 return tl::unexpected( documentValidation.error() );
1729
1730 SEVERITY severity = FromProtoEnum<SEVERITY>( aCtx.Request.severity() );
1731 int layer = severity == RPT_SEVERITY_WARNING ? LAYER_DRC_WARNING : LAYER_DRC_ERROR;
1733
1734 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( code );
1735
1736 drcItem->SetErrorMessage( wxString::FromUTF8( aCtx.Request.message() ) );
1737
1738 RC_ITEM::KIIDS ids;
1739
1740 for( const auto& id : aCtx.Request.items() )
1741 ids.emplace_back( KIID( id.value() ) );
1742
1743 if( !ids.empty() )
1744 drcItem->SetItems( ids );
1745
1746 const auto& pos = aCtx.Request.position();
1747 VECTOR2I position( static_cast<int>( pos.x_nm() ), static_cast<int>( pos.y_nm() ) );
1748
1749 PCB_MARKER* marker = new PCB_MARKER( drcItem, position, layer );
1750
1751 COMMIT* commit = getCurrentCommit( aCtx.ClientName );
1752 commit->Add( marker );
1753 commit->Push( wxS( "API injected DRC marker" ) );
1754
1755 InjectDrcErrorResponse response;
1756 response.mutable_marker()->set_value( marker->GetUUID().AsStdString() );
1757
1758 return response;
1759}
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
Definition api_enums.cpp:97
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:36
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
Definition api_handler.h:45
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
@ ERROR_INSIDE
@ LAYER_CLASS_COUNT
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION gridSetOrigin
Definition actions.h:195
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:232
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.
EDA_BASE_FRAME * m_frame
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.
Definition api_handler.h:93
void SetContentModified(bool aModified=true)
Definition base_screen.h:59
BASE_SET & reset(size_t pos)
Definition base_set.h:143
BASE_SET & set(size_t pos)
Definition base_set.h:116
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...
Definition board_item.h:83
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.
Definition board.h:322
BOARD_STACKUP GetStackupOrDefault() const
Definition board.cpp:2887
void SetVisibleLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition board.cpp:999
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1082
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:967
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:1775
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....
Definition commit.h:72
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:90
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.
Definition commit.h:106
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition drc_item.cpp:400
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.
Definition eda_group.cpp:27
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:110
const KIID m_Uuid
Definition eda_item.h:522
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual wxString GetFriendlyName() const
Definition eda_item.cpp:401
void SetMirror(bool aMirrorX, bool aMirrorY)
Control the mirroring of the VIEW.
Definition view.cpp:557
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition view.cpp:775
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition view.h:250
void RecacheAllItems()
Rebuild GAL display lists.
Definition view.cpp:1451
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition view.h:258
Definition kiid.h:49
std::string AsStdString() const
Definition kiid.cpp:252
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.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition netclass.cpp:328
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition netclass.cpp:136
Handle the data for a net.
Definition netinfo.h:54
NETCLASS * GetNetClass()
Definition netinfo.h:99
Container for NETINFO_ITEM elements, which are the nets.
Definition netinfo.h:212
NETINFO_ITEM * GetNetItem(int aNetCode) const
Definition pad.h:55
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.
BOARD * GetBoard() const
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).
Definition pcb_group.h:53
const KIID GetUUID() const override
Definition pcb_marker.h:49
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
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.
Definition project.cpp:391
std::vector< KIID > KIIDS
Definition rc_item.h:83
int AddItemsToSel(const TOOL_EVENT &aEvent)
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
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.
Definition title_block.h:41
const wxString & GetCompany() const
Definition title_block.h:96
const wxString & GetRevision() const
Definition title_block.h:86
const wxString & GetDate() const
Definition title_block.h:76
const wxString & GetComment(int aIdx) const
const wxString & GetTitle() const
Definition title_block.h:63
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Master controller class:
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
bool PostAPIAction(const TOOL_ACTION &aAction, COMMIT *aCommit)
A type-safe container of any type.
Definition ki_any.h:93
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:61
@ DRCE_GENERIC_ERROR
Definition drc_item.h:91
@ DRCE_GENERIC_WARNING
Definition drc_item.h:90
#define _(s)
@ RECURSE
Definition eda_item.h:51
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition eda_item.h:575
static const std::string KiCadPcbFileExtension
PROJECT & Prj()
Definition kicad.cpp:637
#define KICTL_REVERT
reverting to a previously-saved (KiCad) file.
#define MAX_CU_LAYERS
Definition layer_ids.h:176
@ LAYER_DRC_WARNING
Layer for DRC markers with #SEVERITY_WARNING.
Definition layer_ids.h:301
@ LAYER_DRC_ERROR
Layer for DRC markers with #SEVERITY_ERROR.
Definition layer_ids.h:277
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ Edge_Cuts
Definition layer_ids.h:112
@ Margin
Definition layer_ids.h:113
@ B_CrtYd
Definition layer_ids.h:115
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ Rescue
Definition layer_ids.h:121
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)
Definition api_utils.cpp:33
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition api_utils.cpp:86
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput)
Definition api_utils.cpp:79
KICOMMON_API void PackPolyLine(types::PolyLine &aOutput, const SHAPE_LINE_CHAIN &aSlc)
Class to handle a set of BOARD_ITEMs.
BOARD * GetBoard()
SEVERITY
@ RPT_SEVERITY_WARNING
std::string ClientName
Definition api_handler.h:51
RequestMessageType Request
Definition api_handler.h:52
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:106
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:103
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ TYPE_NOT_INIT
Definition typeinfo.h:81
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:104
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:111
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:108
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:101
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:102
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:100
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:105
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694