KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <jon@craftyjon.com>
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 <project.h>
42#include <tool/tool_manager.h>
43#include <tools/pcb_actions.h>
45#include <zone.h>
46
47#include <api/common/types/base_types.pb.h>
49
50using namespace kiapi::common::commands;
51using types::CommandStatus;
52using types::DocumentType;
53using types::ItemRequestStatus;
54
55
57 API_HANDLER_EDITOR( aFrame )
58{
59 registerHandler<RunAction, RunActionResponse>( &API_HANDLER_PCB::handleRunAction );
60 registerHandler<GetOpenDocuments, GetOpenDocumentsResponse>(
62 registerHandler<SaveDocument, Empty>( &API_HANDLER_PCB::handleSaveDocument );
63 registerHandler<SaveCopyOfDocument, Empty>( &API_HANDLER_PCB::handleSaveCopyOfDocument );
64 registerHandler<RevertDocument, Empty>( &API_HANDLER_PCB::handleRevertDocument );
65
66 registerHandler<GetItems, GetItemsResponse>( &API_HANDLER_PCB::handleGetItems );
67
68 registerHandler<GetSelection, SelectionResponse>( &API_HANDLER_PCB::handleGetSelection );
69 registerHandler<ClearSelection, Empty>( &API_HANDLER_PCB::handleClearSelection );
70 registerHandler<AddToSelection, SelectionResponse>( &API_HANDLER_PCB::handleAddToSelection );
71 registerHandler<RemoveFromSelection, SelectionResponse>(
73
74 registerHandler<GetBoardStackup, BoardStackupResponse>( &API_HANDLER_PCB::handleGetStackup );
75 registerHandler<GetGraphicsDefaults, GraphicsDefaultsResponse>(
77 registerHandler<GetBoundingBox, GetBoundingBoxResponse>(
79 registerHandler<GetPadShapeAsPolygon, PadShapeAsPolygonResponse>(
81 registerHandler<GetTitleBlockInfo, types::TitleBlockInfo>(
83 registerHandler<ExpandTextVariables, ExpandTextVariablesResponse>(
85 registerHandler<GetBoardOrigin, types::Vector2>( &API_HANDLER_PCB::handleGetBoardOrigin );
86 registerHandler<SetBoardOrigin, Empty>( &API_HANDLER_PCB::handleSetBoardOrigin );
87
88 registerHandler<InteractiveMoveItems, Empty>( &API_HANDLER_PCB::handleInteractiveMoveItems );
89 registerHandler<GetNets, NetsResponse>( &API_HANDLER_PCB::handleGetNets );
90 registerHandler<GetNetClassForNets, NetClassForNetsResponse>(
92 registerHandler<RefillZones, Empty>( &API_HANDLER_PCB::handleRefillZones );
93
94 registerHandler<SaveDocumentToString, SavedDocumentResponse>(
96 registerHandler<SaveSelectionToString, SavedSelectionResponse>(
98 registerHandler<ParseAndCreateItemsFromString, CreateItemsResponse>(
100 registerHandler<GetVisibleLayers, BoardLayers>( &API_HANDLER_PCB::handleGetVisibleLayers );
101 registerHandler<SetVisibleLayers, Empty>( &API_HANDLER_PCB::handleSetVisibleLayers );
102 registerHandler<GetActiveLayer, BoardLayerResponse>( &API_HANDLER_PCB::handleGetActiveLayer );
103 registerHandler<SetActiveLayer, Empty>( &API_HANDLER_PCB::handleSetActiveLayer );
104 registerHandler<GetBoardEditorAppearanceSettings, BoardEditorAppearanceSettings>(
106 registerHandler<SetBoardEditorAppearanceSettings, Empty>(
108}
109
110
112{
113 return static_cast<PCB_EDIT_FRAME*>( m_frame );
114}
115
116
118 const HANDLER_CONTEXT<RunAction>& aCtx )
119{
120 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
121 return tl::unexpected( *busy );
122
123 RunActionResponse response;
124
125 if( frame()->GetToolManager()->RunAction( aCtx.Request.action(), true ) )
126 response.set_status( RunActionStatus::RAS_OK );
127 else
128 response.set_status( RunActionStatus::RAS_INVALID );
129
130 return response;
131}
132
133
136{
137 if( aCtx.Request.type() != DocumentType::DOCTYPE_PCB )
138 {
139 ApiResponseStatus e;
140 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
141 e.set_status( ApiStatusCode::AS_UNHANDLED );
142 return tl::unexpected( e );
143 }
144
145 GetOpenDocumentsResponse response;
146 common::types::DocumentSpecifier doc;
147
148 wxFileName fn( frame()->GetCurrentFileName() );
149
150 doc.set_type( DocumentType::DOCTYPE_PCB );
151 doc.set_board_filename( fn.GetFullName() );
152
153 doc.mutable_project()->set_name( frame()->Prj().GetProjectName().ToStdString() );
154 doc.mutable_project()->set_path( frame()->Prj().GetProjectDirectory().ToStdString() );
155
156 response.mutable_documents()->Add( std::move( doc ) );
157 return response;
158}
159
160
163{
164 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
165 return tl::unexpected( *busy );
166
167 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
168
169 if( !documentValidation )
170 return tl::unexpected( documentValidation.error() );
171
173 return Empty();
174}
175
176
179{
180 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
181 return tl::unexpected( *busy );
182
183 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
184
185 if( !documentValidation )
186 return tl::unexpected( documentValidation.error() );
187
188 wxFileName boardPath( frame()->Prj().AbsolutePath( wxString::FromUTF8( aCtx.Request.path() ) ) );
189
190 if( !boardPath.IsOk() || !boardPath.IsDirWritable() )
191 {
192 ApiResponseStatus e;
193 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
194 e.set_error_message( fmt::format( "save path '{}' could not be opened",
195 boardPath.GetFullPath().ToStdString() ) );
196 return tl::unexpected( e );
197 }
198
199 if( boardPath.FileExists()
200 && ( !boardPath.IsFileWritable() || !aCtx.Request.options().overwrite() ) )
201 {
202 ApiResponseStatus e;
203 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
204 e.set_error_message( fmt::format( "save path '{}' exists and cannot be overwritten",
205 boardPath.GetFullPath().ToStdString() ) );
206 return tl::unexpected( e );
207 }
208
209 if( boardPath.GetExt() != FILEEXT::KiCadPcbFileExtension )
210 {
211 ApiResponseStatus e;
212 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
213 e.set_error_message( fmt::format( "save path '{}' must have a kicad_pcb extension",
214 boardPath.GetFullPath().ToStdString() ) );
215 return tl::unexpected( e );
216 }
217
218 BOARD* board = frame()->GetBoard();
219
220 if( board->GetFileName().Matches( boardPath.GetFullPath() ) )
221 {
223 return Empty();
224 }
225
226 bool includeProject = true;
227
228 if( aCtx.Request.has_options() )
229 includeProject = aCtx.Request.options().include_project();
230
231 frame()->SavePcbCopy( boardPath.GetFullPath(), includeProject, /* aHeadless = */ true );
232
233 return Empty();
234}
235
236
239{
240 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
241 return tl::unexpected( *busy );
242
243 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
244
245 if( !documentValidation )
246 return tl::unexpected( documentValidation.error() );
247
248 wxFileName fn = frame()->Prj().AbsolutePath( frame()->GetBoard()->GetFileName() );
249
250 frame()->GetScreen()->SetContentModified( false );
251 frame()->ReleaseFile();
252 frame()->OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ), KICTL_REVERT );
253
254 return Empty();
255}
256
257
258void API_HANDLER_PCB::pushCurrentCommit( const std::string& aClientName, const wxString& aMessage )
259{
260 API_HANDLER_EDITOR::pushCurrentCommit( aClientName, aMessage );
261 frame()->Refresh();
262}
263
264
265std::unique_ptr<COMMIT> API_HANDLER_PCB::createCommit()
266{
267 return std::make_unique<BOARD_COMMIT>( frame() );
268}
269
270
271std::optional<BOARD_ITEM*> API_HANDLER_PCB::getItemById( const KIID& aId ) const
272{
273 BOARD_ITEM* item = frame()->GetBoard()->GetItem( aId );
274
275 if( item == DELETED_BOARD_ITEM::GetInstance() )
276 return std::nullopt;
277
278 return item;
279}
280
281
282bool API_HANDLER_PCB::validateDocumentInternal( const DocumentSpecifier& aDocument ) const
283{
284 if( aDocument.type() != DocumentType::DOCTYPE_PCB )
285 return false;
286
287 wxFileName fn( frame()->GetCurrentFileName() );
288 return 0 == aDocument.board_filename().compare( fn.GetFullName() );
289}
290
291
293 BOARD_ITEM_CONTAINER* aContainer )
294{
295 if( !aContainer )
296 {
297 ApiResponseStatus e;
298 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
299 e.set_error_message( "Tried to create an item in a null container" );
300 return tl::unexpected( e );
301 }
302
303 if( aType == PCB_PAD_T && !dynamic_cast<FOOTPRINT*>( aContainer ) )
304 {
305 ApiResponseStatus e;
306 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
307 e.set_error_message( fmt::format( "Tried to create a pad in {}, which is not a footprint",
308 aContainer->GetFriendlyName().ToStdString() ) );
309 return tl::unexpected( e );
310 }
311 else if( aType == PCB_FOOTPRINT_T && !dynamic_cast<BOARD*>( aContainer ) )
312 {
313 ApiResponseStatus e;
314 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
315 e.set_error_message( fmt::format( "Tried to create a footprint in {}, which is not a board",
316 aContainer->GetFriendlyName().ToStdString() ) );
317 return tl::unexpected( e );
318 }
319
320 std::unique_ptr<BOARD_ITEM> created = CreateItemForType( aType, aContainer );
321
322 if( !created )
323 {
324 ApiResponseStatus e;
325 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
326 e.set_error_message( fmt::format( "Tried to create an item of type {}, which is unhandled",
327 magic_enum::enum_name( aType ) ) );
328 return tl::unexpected( e );
329 }
330
331 return created;
332}
333
334
336 const std::string& aClientName,
337 const types::ItemHeader &aHeader,
338 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
339 std::function<void( ItemStatus, google::protobuf::Any )> aItemHandler )
340{
341 ApiResponseStatus e;
342
343 auto containerResult = validateItemHeaderDocument( aHeader );
344
345 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
346 {
347 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
348 e.set_status( ApiStatusCode::AS_UNHANDLED );
349 return tl::unexpected( e );
350 }
351 else if( !containerResult )
352 {
353 e.CopyFrom( containerResult.error() );
354 return tl::unexpected( e );
355 }
356
357 BOARD* board = frame()->GetBoard();
358 BOARD_ITEM_CONTAINER* container = board;
359
360 if( containerResult->has_value() )
361 {
362 const KIID& containerId = **containerResult;
363 std::optional<BOARD_ITEM*> optItem = getItemById( containerId );
364
365 if( optItem )
366 {
367 container = dynamic_cast<BOARD_ITEM_CONTAINER*>( *optItem );
368
369 if( !container )
370 {
371 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
372 e.set_error_message( fmt::format(
373 "The requested container {} is not a valid board item container",
374 containerId.AsStdString() ) );
375 return tl::unexpected( e );
376 }
377 }
378 else
379 {
380 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
381 e.set_error_message( fmt::format(
382 "The requested container {} does not exist in this document",
383 containerId.AsStdString() ) );
384 return tl::unexpected( e );
385 }
386 }
387
388 BOARD_COMMIT* commit = static_cast<BOARD_COMMIT*>( getCurrentCommit( aClientName ) );
389
390 for( const google::protobuf::Any& anyItem : aItems )
391 {
392 ItemStatus status;
393 std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
394
395 if( !type )
396 {
397 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
398 status.set_error_message( fmt::format( "Could not decode a valid type from {}",
399 anyItem.type_url() ) );
400 aItemHandler( status, anyItem );
401 continue;
402 }
403
404 if( type == PCB_DIMENSION_T )
405 {
406 board::types::Dimension dimension;
407 anyItem.UnpackTo( &dimension );
408
409 switch( dimension.dimension_style_case() )
410 {
411 case board::types::Dimension::kAligned: type = PCB_DIM_ALIGNED_T; break;
412 case board::types::Dimension::kOrthogonal: type = PCB_DIM_ORTHOGONAL_T; break;
413 case board::types::Dimension::kRadial: type = PCB_DIM_RADIAL_T; break;
414 case board::types::Dimension::kLeader: type = PCB_DIM_LEADER_T; break;
415 case board::types::Dimension::kCenter: type = PCB_DIM_CENTER_T; break;
416 case board::types::Dimension::DIMENSION_STYLE_NOT_SET: break;
417 }
418 }
419
421 createItemForType( *type, container );
422
423 if( !creationResult )
424 {
425 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
426 status.set_error_message( creationResult.error().error_message() );
427 aItemHandler( status, anyItem );
428 continue;
429 }
430
431 std::unique_ptr<BOARD_ITEM> item( std::move( *creationResult ) );
432
433 if( !item->Deserialize( anyItem ) )
434 {
435 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
436 e.set_error_message( fmt::format( "could not unpack {} from request",
437 item->GetClass().ToStdString() ) );
438 return tl::unexpected( e );
439 }
440
441 std::optional<BOARD_ITEM*> optItem = getItemById( item->m_Uuid );
442
443 if( aCreate && optItem )
444 {
445 status.set_code( ItemStatusCode::ISC_EXISTING );
446 status.set_error_message( fmt::format( "an item with UUID {} already exists",
447 item->m_Uuid.AsStdString() ) );
448 aItemHandler( status, anyItem );
449 continue;
450 }
451 else if( !aCreate && !optItem )
452 {
453 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
454 status.set_error_message( fmt::format( "an item with UUID {} does not exist",
455 item->m_Uuid.AsStdString() ) );
456 aItemHandler( status, anyItem );
457 continue;
458 }
459
460 if( aCreate && !( board->GetEnabledLayers() & item->GetLayerSet() ).any() )
461 {
462 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
463 status.set_error_message(
464 "attempted to add item with no overlapping layers with the board" );
465 aItemHandler( status, anyItem );
466 continue;
467 }
468
469 status.set_code( ItemStatusCode::ISC_OK );
470 google::protobuf::Any newItem;
471
472 if( aCreate )
473 {
474 item->Serialize( newItem );
475 commit->Add( item.release() );
476 }
477 else
478 {
479 BOARD_ITEM* boardItem = *optItem;
480
481 // Footprints can't be modified by CopyFrom at the moment because the commit system
482 // doesn't currently know what to do with a footprint that has had its children
483 // replaced with other children; which results in things like the view not having its
484 // cached geometry for footprint children updated when you move a footprint around.
485 if( boardItem->Type() == PCB_FOOTPRINT_T )
486 {
487 commit->Remove( boardItem );
488 item->Serialize( newItem );
489 commit->Add( item.release() );
490 }
491 else
492 {
493 commit->Modify( boardItem );
494 boardItem->CopyFrom( item.get() );
495 boardItem->Serialize( newItem );
496 }
497 }
498
499 aItemHandler( status, newItem );
500 }
501
502 if( !m_activeClients.count( aClientName ) )
503 {
504 pushCurrentCommit( aClientName, aCreate ? _( "Created items via API" )
505 : _( "Modified items via API" ) );
506 }
507
508
509 return ItemRequestStatus::IRS_OK;
510}
511
512
514 const HANDLER_CONTEXT<GetItems>& aCtx )
515{
516 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
517 return tl::unexpected( *busy );
518
519 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
520 {
521 ApiResponseStatus e;
522 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
523 e.set_status( ApiStatusCode::AS_UNHANDLED );
524 return tl::unexpected( e );
525 }
526
527 GetItemsResponse response;
528
529 BOARD* board = frame()->GetBoard();
530 std::vector<BOARD_ITEM*> items;
531 std::set<KICAD_T> typesRequested, typesInserted;
532 bool handledAnything = false;
533
534 for( int typeRaw : aCtx.Request.types() )
535 {
536 auto typeMessage = static_cast<common::types::KiCadObjectType>( typeRaw );
537 KICAD_T type = FromProtoEnum<KICAD_T>( typeMessage );
538
539 if( type == TYPE_NOT_INIT )
540 continue;
541
542 typesRequested.emplace( type );
543
544 if( typesInserted.count( type ) )
545 continue;
546
547 switch( type )
548 {
549 case PCB_TRACE_T:
550 case PCB_ARC_T:
551 case PCB_VIA_T:
552 handledAnything = true;
553 std::copy( board->Tracks().begin(), board->Tracks().end(),
554 std::back_inserter( items ) );
555 typesInserted.insert( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } );
556 break;
557
558 case PCB_PAD_T:
559 {
560 handledAnything = true;
561
562 for( FOOTPRINT* fp : board->Footprints() )
563 {
564 std::copy( fp->Pads().begin(), fp->Pads().end(),
565 std::back_inserter( items ) );
566 }
567
568 typesInserted.insert( PCB_PAD_T );
569 break;
570 }
571
572 case PCB_FOOTPRINT_T:
573 {
574 handledAnything = true;
575
576 std::copy( board->Footprints().begin(), board->Footprints().end(),
577 std::back_inserter( items ) );
578
579 typesInserted.insert( PCB_FOOTPRINT_T );
580 break;
581 }
582
583 case PCB_SHAPE_T:
584 case PCB_TEXT_T:
585 case PCB_TEXTBOX_T:
586 {
587 handledAnything = true;
588 bool inserted = false;
589
590 for( BOARD_ITEM* item : board->Drawings() )
591 {
592 if( item->Type() == type )
593 {
594 items.emplace_back( item );
595 inserted = true;
596 }
597 }
598
599 if( inserted )
600 typesInserted.insert( PCB_SHAPE_T );
601
602 break;
603 }
604
605 case PCB_ZONE_T:
606 {
607 handledAnything = true;
608
609 std::copy( board->Zones().begin(), board->Zones().end(),
610 std::back_inserter( items ) );
611
612 typesInserted.insert( PCB_ZONE_T );
613 break;
614 }
615
616 default:
617 break;
618 }
619 }
620
621 if( !handledAnything )
622 {
623 ApiResponseStatus e;
624 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
625 e.set_error_message( "none of the requested types are valid for a Board object" );
626 return tl::unexpected( e );
627 }
628
629 for( const BOARD_ITEM* item : items )
630 {
631 if( !typesRequested.count( item->Type() ) )
632 continue;
633
634 google::protobuf::Any itemBuf;
635 item->Serialize( itemBuf );
636 response.mutable_items()->Add( std::move( itemBuf ) );
637 }
638
639 response.set_status( ItemRequestStatus::IRS_OK );
640 return response;
641}
642
643
644void API_HANDLER_PCB::deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
645 const std::string& aClientName )
646{
647 BOARD* board = frame()->GetBoard();
648 std::vector<BOARD_ITEM*> validatedItems;
649
650 for( std::pair<const KIID, ItemDeletionStatus> pair : aItemsToDelete )
651 {
652 if( BOARD_ITEM* item = board->GetItem( pair.first ) )
653 {
654 validatedItems.push_back( item );
655 aItemsToDelete[pair.first] = ItemDeletionStatus::IDS_OK;
656 }
657
658 // Note: we don't currently support locking items from API modification, but here is where
659 // to add it in the future (and return IDS_IMMUTABLE)
660 }
661
662 COMMIT* commit = getCurrentCommit( aClientName );
663
664 for( BOARD_ITEM* item : validatedItems )
665 commit->Remove( item );
666
667 if( !m_activeClients.count( aClientName ) )
668 pushCurrentCommit( aClientName, _( "Deleted items via API" ) );
669}
670
671
672std::optional<EDA_ITEM*> API_HANDLER_PCB::getItemFromDocument( const DocumentSpecifier& aDocument,
673 const KIID& aId )
674{
675 if( !validateDocument( aDocument ) )
676 return std::nullopt;
677
678 return getItemById( aId );
679}
680
681
684{
685 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
686 {
687 ApiResponseStatus e;
688 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
689 e.set_status( ApiStatusCode::AS_UNHANDLED );
690 return tl::unexpected( e );
691 }
692
693 std::set<KICAD_T> filter;
694
695 for( int typeRaw : aCtx.Request.types() )
696 {
697 auto typeMessage = static_cast<types::KiCadObjectType>( typeRaw );
698 KICAD_T type = FromProtoEnum<KICAD_T>( typeMessage );
699
700 if( type == TYPE_NOT_INIT )
701 continue;
702
703 filter.insert( type );
704 }
705
707 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
708
709 SelectionResponse response;
710
711 for( EDA_ITEM* item : selectionTool->GetSelection() )
712 {
713 if( filter.empty() || filter.contains( item->Type() ) )
714 item->Serialize( *response.add_items() );
715 }
716
717 return response;
718}
719
720
723{
724 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
725 return tl::unexpected( *busy );
726
727 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
728 {
729 ApiResponseStatus e;
730 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
731 e.set_status( ApiStatusCode::AS_UNHANDLED );
732 return tl::unexpected( e );
733 }
734
737 frame()->Refresh();
738
739 return Empty();
740}
741
742
745{
746 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
747 return tl::unexpected( *busy );
748
749 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
750 {
751 ApiResponseStatus e;
752 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
753 e.set_status( ApiStatusCode::AS_UNHANDLED );
754 return tl::unexpected( e );
755 }
756
758 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
759
760 std::vector<EDA_ITEM*> toAdd;
761
762 for( const types::KIID& id : aCtx.Request.items() )
763 {
764 if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
765 toAdd.emplace_back( *item );
766 }
767
768 selectionTool->AddItemsToSel( &toAdd );
769 frame()->Refresh();
770
771 SelectionResponse response;
772
773 for( EDA_ITEM* item : selectionTool->GetSelection() )
774 item->Serialize( *response.add_items() );
775
776 return response;
777}
778
779
782{
783 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
784 return tl::unexpected( *busy );
785
786 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
787 {
788 ApiResponseStatus e;
789 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
790 e.set_status( ApiStatusCode::AS_UNHANDLED );
791 return tl::unexpected( e );
792 }
793
795 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
796
797 std::vector<EDA_ITEM*> toRemove;
798
799 for( const types::KIID& id : aCtx.Request.items() )
800 {
801 if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
802 toRemove.emplace_back( *item );
803 }
804
805 selectionTool->RemoveItemsFromSel( &toRemove );
806 frame()->Refresh();
807
808 SelectionResponse response;
809
810 for( EDA_ITEM* item : selectionTool->GetSelection() )
811 item->Serialize( *response.add_items() );
812
813 return response;
814}
815
816
819{
820 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
821
822 if( !documentValidation )
823 return tl::unexpected( documentValidation.error() );
824
825 BoardStackupResponse response;
826 google::protobuf::Any any;
827
829
830 any.UnpackTo( response.mutable_stackup() );
831
832 // User-settable layer names are not stored in BOARD_STACKUP at the moment
833 for( board::BoardStackupLayer& layer : *response.mutable_stackup()->mutable_layers() )
834 {
835 if( layer.type() == board::BoardStackupLayerType::BSLT_DIELECTRIC )
836 continue;
837
838 PCB_LAYER_ID id = FromProtoEnum<PCB_LAYER_ID>( layer.layer() );
839 wxCHECK2( id != UNDEFINED_LAYER, continue );
840
841 layer.set_user_name( frame()->GetBoard()->GetLayerName( id ) );
842 }
843
844 return response;
845}
846
847
850{
851 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
852
853 if( !documentValidation )
854 return tl::unexpected( documentValidation.error() );
855
857 GraphicsDefaultsResponse response;
858
859 // TODO: This should change to be an enum class
860 constexpr std::array<kiapi::board::BoardLayerClass, LAYER_CLASS_COUNT> classOrder = {
861 kiapi::board::BLC_SILKSCREEN,
862 kiapi::board::BLC_COPPER,
863 kiapi::board::BLC_EDGES,
864 kiapi::board::BLC_COURTYARD,
865 kiapi::board::BLC_FABRICATION,
866 kiapi::board::BLC_OTHER
867 };
868
869 for( int i = 0; i < LAYER_CLASS_COUNT; ++i )
870 {
871 kiapi::board::BoardLayerGraphicsDefaults* l = response.mutable_defaults()->add_layers();
872
873 l->set_layer( classOrder[i] );
874 l->mutable_line_thickness()->set_value_nm( bds.m_LineThickness[i] );
875
876 kiapi::common::types::TextAttributes* text = l->mutable_text();
877 text->mutable_size()->set_x_nm( bds.m_TextSize[i].x );
878 text->mutable_size()->set_y_nm( bds.m_TextSize[i].y );
879 text->mutable_stroke_width()->set_value_nm( bds.m_TextThickness[i] );
880 text->set_italic( bds.m_TextItalic[i] );
881 text->set_keep_upright( bds.m_TextUpright[i] );
882 }
883
884 return response;
885}
886
887
890{
891 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
892 !documentValidation )
893 {
894 return tl::unexpected( documentValidation.error() );
895 }
896
897 VECTOR2I origin;
898 const BOARD_DESIGN_SETTINGS& settings = frame()->GetBoard()->GetDesignSettings();
899
900 switch( aCtx.Request.type() )
901 {
902 case BOT_GRID:
903 origin = settings.GetGridOrigin();
904 break;
905
906 case BOT_DRILL:
907 origin = settings.GetAuxOrigin();
908 break;
909
910 default:
911 case BOT_UNKNOWN:
912 {
913 ApiResponseStatus e;
914 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
915 e.set_error_message( "Unexpected origin type" );
916 return tl::unexpected( e );
917 }
918 }
919
920 types::Vector2 reply;
921 PackVector2( reply, origin );
922 return reply;
923}
924
927{
928 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
929 return tl::unexpected( *busy );
930
931 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
932 !documentValidation )
933 {
934 return tl::unexpected( documentValidation.error() );
935 }
936
938 VECTOR2I origin = UnpackVector2( aCtx.Request.origin() );
939
940 switch( aCtx.Request.type() )
941 {
942 case BOT_GRID:
943 settings.SetGridOrigin( origin );
944 frame()->Refresh();
945 break;
946
947 case BOT_DRILL:
948 {
949 PCB_EDIT_FRAME* f = frame();
950
951 frame()->CallAfter( [f, origin]()
952 {
953 TOOL_MANAGER* mgr = f->GetToolManager();
955 f->Refresh();
956 } );
957 break;
958 }
959
960 default:
961 case BOT_UNKNOWN:
962 {
963 ApiResponseStatus e;
964 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
965 e.set_error_message( "Unexpected origin type" );
966 return tl::unexpected( e );
967 }
968 }
969
970 return Empty();
971}
972
973
976{
977 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
978 return tl::unexpected( *busy );
979
980 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
981 {
982 ApiResponseStatus e;
983 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
984 e.set_status( ApiStatusCode::AS_UNHANDLED );
985 return tl::unexpected( e );
986 }
987
988 GetBoundingBoxResponse response;
989 bool includeText = aCtx.Request.mode() == BoundingBoxMode::BBM_ITEM_AND_CHILD_TEXT;
990
991 for( const types::KIID& idMsg : aCtx.Request.items() )
992 {
993 KIID id( idMsg.value() );
994 std::optional<BOARD_ITEM*> optItem = getItemById( id );
995
996 if( !optItem )
997 continue;
998
999 BOARD_ITEM* item = *optItem;
1000 BOX2I bbox;
1001
1002 if( item->Type() == PCB_FOOTPRINT_T )
1003 bbox = static_cast<FOOTPRINT*>( item )->GetBoundingBox( includeText );
1004 else
1005 bbox = item->GetBoundingBox();
1006
1007 response.add_items()->set_value( idMsg.value() );
1008 PackBox2( *response.add_boxes(), bbox );
1009 }
1010
1011 return response;
1012}
1013
1014
1017{
1018 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1019 !documentValidation )
1020 {
1021 return tl::unexpected( documentValidation.error() );
1022 }
1023
1024 PadShapeAsPolygonResponse response;
1025 PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID, board::types::BoardLayer>( aCtx.Request.layer() );
1026
1027 for( const types::KIID& padRequest : aCtx.Request.pads() )
1028 {
1029 KIID id( padRequest.value() );
1030 std::optional<BOARD_ITEM*> optPad = getItemById( id );
1031
1032 if( !optPad || ( *optPad )->Type() != PCB_PAD_T )
1033 continue;
1034
1035 response.add_pads()->set_value( padRequest.value() );
1036
1037 PAD* pad = static_cast<PAD*>( *optPad );
1038 SHAPE_POLY_SET poly;
1039 pad->TransformShapeToPolygon( poly, pad->Padstack().EffectiveLayerFor( layer ), 0,
1041
1042 types::PolygonWithHoles* polyMsg = response.mutable_polygons()->Add();
1043 PackPolyLine( *polyMsg->mutable_outline(), poly.COutline( 0 ) );
1044 }
1045
1046 return response;
1047}
1048
1049
1052{
1053 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1054
1055 if( !documentValidation )
1056 return tl::unexpected( documentValidation.error() );
1057
1058 BOARD* board = frame()->GetBoard();
1059 const TITLE_BLOCK& block = board->GetTitleBlock();
1060
1061 types::TitleBlockInfo response;
1062
1063 response.set_title( block.GetTitle().ToUTF8() );
1064 response.set_date( block.GetDate().ToUTF8() );
1065 response.set_revision( block.GetRevision().ToUTF8() );
1066 response.set_company( block.GetCompany().ToUTF8() );
1067 response.set_comment1( block.GetComment( 0 ).ToUTF8() );
1068 response.set_comment2( block.GetComment( 1 ).ToUTF8() );
1069 response.set_comment3( block.GetComment( 2 ).ToUTF8() );
1070 response.set_comment4( block.GetComment( 3 ).ToUTF8() );
1071 response.set_comment5( block.GetComment( 4 ).ToUTF8() );
1072 response.set_comment6( block.GetComment( 5 ).ToUTF8() );
1073 response.set_comment7( block.GetComment( 6 ).ToUTF8() );
1074 response.set_comment8( block.GetComment( 7 ).ToUTF8() );
1075 response.set_comment9( block.GetComment( 8 ).ToUTF8() );
1076
1077 return response;
1078}
1079
1080
1083{
1084 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1085
1086 if( !documentValidation )
1087 return tl::unexpected( documentValidation.error() );
1088
1089 ExpandTextVariablesResponse reply;
1090 BOARD* board = frame()->GetBoard();
1091
1092 std::function<bool( wxString* )> textResolver =
1093 [&]( wxString* token ) -> bool
1094 {
1095 // Handles m_board->GetTitleBlock() *and* m_board->GetProject()
1096 return board->ResolveTextVar( token, 0 );
1097 };
1098
1099 for( const std::string& textMsg : aCtx.Request.text() )
1100 {
1101 wxString text = ExpandTextVars( wxString::FromUTF8( textMsg ), &textResolver );
1102 reply.add_text( text.ToUTF8() );
1103 }
1104
1105 return reply;
1106}
1107
1108
1111{
1112 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1113 return tl::unexpected( *busy );
1114
1115 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1116
1117 if( !documentValidation )
1118 return tl::unexpected( documentValidation.error() );
1119
1120 TOOL_MANAGER* mgr = frame()->GetToolManager();
1121 std::vector<EDA_ITEM*> toSelect;
1122
1123 for( const kiapi::common::types::KIID& id : aCtx.Request.items() )
1124 {
1125 if( std::optional<BOARD_ITEM*> item = getItemById( KIID( id.value() ) ) )
1126 toSelect.emplace_back( static_cast<EDA_ITEM*>( *item ) );
1127 }
1128
1129 if( toSelect.empty() )
1130 {
1131 ApiResponseStatus e;
1132 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1133 e.set_error_message( fmt::format( "None of the given items exist on the board",
1134 aCtx.Request.board().board_filename() ) );
1135 return tl::unexpected( e );
1136 }
1137
1138 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
1139 selectionTool->GetSelection().SetReferencePoint( toSelect[0]->GetPosition() );
1140
1142 mgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSelect );
1143
1144 COMMIT* commit = getCurrentCommit( aCtx.ClientName );
1145 mgr->PostAPIAction( PCB_ACTIONS::move, commit );
1146
1147 return Empty();
1148}
1149
1150
1152{
1153 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1154
1155 if( !documentValidation )
1156 return tl::unexpected( documentValidation.error() );
1157
1158 NetsResponse response;
1159 BOARD* board = frame()->GetBoard();
1160
1161 std::set<wxString> netclassFilter;
1162
1163 for( const std::string& nc : aCtx.Request.netclass_filter() )
1164 netclassFilter.insert( wxString( nc.c_str(), wxConvUTF8 ) );
1165
1166 for( NETINFO_ITEM* net : board->GetNetInfo() )
1167 {
1168 NETCLASS* nc = net->GetNetClass();
1169
1170 if( !netclassFilter.empty() && nc && !netclassFilter.count( nc->GetName() ) )
1171 continue;
1172
1173 board::types::Net* netProto = response.add_nets();
1174 netProto->set_name( net->GetNetname() );
1175 netProto->mutable_code()->set_value( net->GetNetCode() );
1176 }
1177
1178 return response;
1179}
1180
1181
1184{
1185 NetClassForNetsResponse response;
1186
1187 BOARD* board = frame()->GetBoard();
1188 NETINFO_LIST nets = board->GetNetInfo();
1189 google::protobuf::Any any;
1190
1191 for( const board::types::Net& net : aCtx.Request.net() )
1192 {
1193 NETINFO_ITEM* netInfo = nets.GetNetItem( wxString::FromUTF8( net.name() ) );
1194
1195 if( !netInfo )
1196 continue;
1197
1198 netInfo->GetNetClass()->Serialize( any );
1199 auto [pair, rc] = response.mutable_classes()->insert( { net.name(), {} } );
1200 any.UnpackTo( &pair->second );
1201 }
1202
1203 return response;
1204}
1205
1206
1208{
1209 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1210 return tl::unexpected( *busy );
1211
1212 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1213
1214 if( !documentValidation )
1215 return tl::unexpected( documentValidation.error() );
1216
1217 if( aCtx.Request.zones().empty() )
1218 {
1219 TOOL_MANAGER* mgr = frame()->GetToolManager();
1220 frame()->CallAfter( [mgr]()
1221 {
1223 } );
1224 }
1225 else
1226 {
1227 // TODO
1228 ApiResponseStatus e;
1229 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
1230 return tl::unexpected( e );
1231 }
1232
1233 return Empty();
1234}
1235
1236
1239{
1240 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1241
1242 if( !documentValidation )
1243 return tl::unexpected( documentValidation.error() );
1244
1245 SavedDocumentResponse response;
1246 response.mutable_document()->CopyFrom( aCtx.Request.document() );
1247
1248 CLIPBOARD_IO io;
1249 io.SetWriter(
1250 [&]( const wxString& aData )
1251 {
1252 response.set_contents( aData.ToUTF8() );
1253 } );
1254
1255 io.SaveBoard( wxEmptyString, frame()->GetBoard(), nullptr );
1256
1257 return response;
1258}
1259
1260
1263{
1264 SavedSelectionResponse response;
1265
1266 TOOL_MANAGER* mgr = frame()->GetToolManager();
1267 PCB_SELECTION_TOOL* selectionTool = mgr->GetTool<PCB_SELECTION_TOOL>();
1268 PCB_SELECTION& selection = selectionTool->GetSelection();
1269
1270 CLIPBOARD_IO io;
1271 io.SetWriter(
1272 [&]( const wxString& aData )
1273 {
1274 response.set_contents( aData.ToUTF8() );
1275 } );
1276
1277 io.SetBoard( frame()->GetBoard() );
1278 io.SaveSelection( selection, false );
1279
1280 return response;
1281}
1282
1283
1286{
1287 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1288 return tl::unexpected( *busy );
1289
1290 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1291
1292 if( !documentValidation )
1293 return tl::unexpected( documentValidation.error() );
1294
1295 CreateItemsResponse response;
1296 return response;
1297}
1298
1299
1302{
1303 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1304
1305 if( !documentValidation )
1306 return tl::unexpected( documentValidation.error() );
1307
1308 BoardLayers response;
1309
1310 for( PCB_LAYER_ID layer : frame()->GetBoard()->GetVisibleLayers() )
1311 response.add_layers( ToProtoEnum<PCB_LAYER_ID, board::types::BoardLayer>( layer ) );
1312
1313 return response;
1314}
1315
1316
1319{
1320 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1321 return tl::unexpected( *busy );
1322
1323 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1324
1325 if( !documentValidation )
1326 return tl::unexpected( documentValidation.error() );
1327
1328 LSET visible;
1329 LSET enabled = frame()->GetBoard()->GetEnabledLayers();
1330
1331 for( int layerIdx : aCtx.Request.layers() )
1332 {
1333 PCB_LAYER_ID layer =
1334 FromProtoEnum<PCB_LAYER_ID>( static_cast<board::types::BoardLayer>( layerIdx ) );
1335
1336 if( enabled.Contains( layer ) )
1337 visible.set( layer );
1338 }
1339
1340 frame()->GetBoard()->SetVisibleLayers( visible );
1343 frame()->Refresh();
1344 return Empty();
1345}
1346
1347
1350{
1351 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1352
1353 if( !documentValidation )
1354 return tl::unexpected( documentValidation.error() );
1355
1356 BoardLayerResponse response;
1357 response.set_layer(
1358 ToProtoEnum<PCB_LAYER_ID, board::types::BoardLayer>( frame()->GetActiveLayer() ) );
1359
1360 return response;
1361}
1362
1363
1366{
1367 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1368 return tl::unexpected( *busy );
1369
1370 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
1371
1372 if( !documentValidation )
1373 return tl::unexpected( documentValidation.error() );
1374
1375 PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( aCtx.Request.layer() );
1376
1377 if( !frame()->GetBoard()->GetEnabledLayers().Contains( layer ) )
1378 {
1379 ApiResponseStatus err;
1380 err.set_status( ApiStatusCode::AS_BAD_REQUEST );
1381 err.set_error_message( fmt::format( "Layer {} is not a valid layer for the given board",
1382 magic_enum::enum_name( layer ) ) );
1383 return tl::unexpected( err );
1384 }
1385
1386 frame()->SetActiveLayer( layer );
1387 return Empty();
1388}
1389
1390
1393{
1394 BoardEditorAppearanceSettings reply;
1395
1396 // TODO: might be nice to put all these things in one place and have it derive SERIALIZABLE
1397
1398 const PCB_DISPLAY_OPTIONS& displayOptions = frame()->GetDisplayOptions();
1399
1400 reply.set_inactive_layer_display( ToProtoEnum<HIGH_CONTRAST_MODE, InactiveLayerDisplayMode>(
1401 displayOptions.m_ContrastModeDisplay ) );
1402 reply.set_net_color_display(
1403 ToProtoEnum<NET_COLOR_MODE, NetColorDisplayMode>( displayOptions.m_NetColorMode ) );
1404
1405 reply.set_board_flip( frame()->GetCanvas()->GetView()->IsMirroredX()
1406 ? BoardFlipMode::BFM_FLIPPED_X
1407 : BoardFlipMode::BFM_NORMAL );
1408
1409 PCBNEW_SETTINGS* editorSettings = frame()->GetPcbNewSettings();
1410
1411 reply.set_ratsnest_display( ToProtoEnum<RATSNEST_MODE, RatsnestDisplayMode>(
1412 editorSettings->m_Display.m_RatsnestMode ) );
1413
1414 return reply;
1415}
1416
1417
1420{
1421 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1422 return tl::unexpected( *busy );
1423
1425 KIGFX::PCB_VIEW* view = frame()->GetCanvas()->GetView();
1426 PCBNEW_SETTINGS* editorSettings = frame()->GetPcbNewSettings();
1427 const BoardEditorAppearanceSettings& newSettings = aCtx.Request.settings();
1428
1429 options.m_ContrastModeDisplay =
1430 FromProtoEnum<HIGH_CONTRAST_MODE>( newSettings.inactive_layer_display() );
1431 options.m_NetColorMode =
1432 FromProtoEnum<NET_COLOR_MODE>( newSettings.net_color_display() );
1433
1434 bool flip = newSettings.board_flip() == BoardFlipMode::BFM_FLIPPED_X;
1435
1436 if( flip != view->IsMirroredX() )
1437 {
1438 view->SetMirror( !view->IsMirroredX(), view->IsMirroredY() );
1439 view->RecacheAllItems();
1440 }
1441
1442 editorSettings->m_Display.m_RatsnestMode =
1443 FromProtoEnum<RATSNEST_MODE>( newSettings.ratsnest_display() );
1444
1445 frame()->SetDisplayOptions( options );
1447 frame()->GetCanvas()->Refresh();
1448
1449 return Empty();
1450}
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
Definition: approximation.h:34
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
@ LAYER_CLASS_COUNT
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:220
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: actions.h:228
Base class for API handlers related to editor frames.
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.
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< 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< 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< commands::GetItemsResponse > handleGetItems(const HANDLER_CONTEXT< commands::GetItems > &aCtx)
HANDLER_RESULT< PadShapeAsPolygonResponse > handleGetPadShapeAsPolygon(const HANDLER_CONTEXT< GetPadShapeAsPolygon > &aCtx)
PCB_EDIT_FRAME * frame() const
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 SetContentModified(bool aModified=true)
Definition: base_screen.h:59
BASE_SET & set(size_t pos)
Definition: base_set.h:116
Container for design settings for a BOARD object.
void SetGridOrigin(const VECTOR2I &aOrigin)
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:78
virtual void CopyFrom(const BOARD_ITEM *aOther)
Definition: board_item.cpp:41
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:297
BOARD_STACKUP GetStackupOrDefault() const
Definition: board.cpp:2369
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:897
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:861
BOARD_ITEM * GetItem(const KIID &aID) const
Definition: board.cpp:1501
const ZONES & Zones() const
Definition: board.h:342
bool ResolveTextVar(wxString *token, int aDepth) const
Definition: board.cpp:434
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:721
const FOOTPRINTS & Footprints() const
Definition: board.h:338
const TRACKS & Tracks() const
Definition: board.h:336
const wxString & GetFileName() const
Definition: board.h:334
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:946
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:829
const DRAWINGS & Drawings() const
Definition: board.h:340
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:74
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:92
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Definition: commit.h:108
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:80
static DELETED_BOARD_ITEM * GetInstance()
Definition: board_item.h:482
void ReleaseFile()
Release the current file marked in use.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:96
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:84
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:108
virtual wxString GetFriendlyName() const
Definition: eda_item.cpp:374
void SetMirror(bool aMirrorX, bool aMirrorY)
Control the mirroring of the VIEW.
Definition: view.cpp:547
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:765
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:246
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1439
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition: view.h:254
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.
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
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:314
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: netclass.cpp:134
Handle the data for a net.
Definition: netinfo.h:56
NETCLASS * GetNetClass()
Definition: netinfo.h:101
Container for NETINFO_ITEM elements, which are the nets.
Definition: netinfo.h:346
NETINFO_ITEM * GetNetItem(int aNetCode) const
Definition: pad.h:54
DISPLAY_OPTIONS m_Display
static TOOL_ACTION zoneFillAll
Definition: pcb_actions.h:390
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:103
static TOOL_ACTION drillSetOrigin
Definition: pcb_actions.h:535
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.
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Load a KiCad board (.kicad_pcb) from aFileName.
bool SavePcbCopy(const wxString &aFileName, bool aCreateProject=false, bool aHeadless=false)
Write the board data structures to aFileName.
bool Files_io_from_id(int aId)
Read and write board files according to aId.
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:370
int AddItemsToSel(const TOOL_EVENT &aEvent)
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.cpp:178
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
Definition: title_block.h:107
const wxString & GetTitle() const
Definition: title_block.h:63
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
Master controller class:
Definition: tool_manager.h:62
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
bool PostAPIAction(const TOOL_ACTION &aAction, COMMIT *aCommit)
Definition: tool_manager.h:282
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition: common.cpp:59
#define _(s)
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:548
static const std::string KiCadPcbFileExtension
@ ID_SAVE_BOARD
Definition: id.h:74
PROJECT & Prj()
Definition: kicad.cpp:597
#define KICTL_REVERT
reverting to a previously-saved (KiCad) file.
Definition: kiway_player.h:78
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
KICOMMON_API void PackBox2(types::Box2 &aOutput, const BOX2I &aInput)
Definition: api_utils.cpp:104
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
Definition: api_utils.cpp:32
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition: api_utils.cpp:84
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput)
Definition: api_utils.cpp:77
KICOMMON_API void PackPolyLine(types::PolyLine &aOutput, const SHAPE_LINE_CHAIN &aSlc)
Definition: api_utils.cpp:117
Class to handle a set of BOARD_ITEMs.
BOARD * GetBoard()
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:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ 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:103
@ 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:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ 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:101
@ 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:104