KiCad PCB EDA Suite
Loading...
Searching...
No Matches
api_handler_editor.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) 2024 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
22
23#include <api/api_enums.h>
24#include <api/api_utils.h>
25#include <eda_base_frame.h>
26#include <eda_item.h>
27#include <title_block.h>
28#include <wx/wx.h>
29
30using namespace kiapi::common::commands;
31
32
46
47
50{
51 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
52 return tl::unexpected( *busy );
53
54 // Before 11.0, commit requests had no header so we assume they are for the PCB editor
55 if( aCtx.Request.has_header() && !validateItemHeaderDocument( aCtx.Request.header() ) )
56 {
57 ApiResponseStatus e;
58 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
59 e.set_status( ApiStatusCode::AS_UNHANDLED );
60 return tl::unexpected( e );
61 }
62
63 if( m_commits.count( aCtx.ClientName ) )
64 {
65 ApiResponseStatus e;
66 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
67 e.set_error_message( fmt::format( "the client {} already has a commit in progress",
68 aCtx.ClientName ) );
69 return tl::unexpected( e );
70 }
71
72 wxASSERT( !m_activeClients.count( aCtx.ClientName ) );
73
74 BeginCommitResponse response;
75
76 KIID id;
77 m_commits[aCtx.ClientName] = std::make_pair( id, createCommit() );
78 response.mutable_id()->set_value( id.AsStdString() );
79
80 m_activeClients.insert( aCtx.ClientName );
81
82 return response;
83}
84
85
87 const HANDLER_CONTEXT<EndCommit>& aCtx )
88{
89 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
90 return tl::unexpected( *busy );
91
92 // Before 11.0, commit requests had no header so we assume they are for the PCB editor
93 if( aCtx.Request.has_header() && !validateItemHeaderDocument( aCtx.Request.header() ) )
94 {
95 ApiResponseStatus e;
96 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
97 e.set_status( ApiStatusCode::AS_UNHANDLED );
98 return tl::unexpected( e );
99 }
100
101 if( !m_commits.count( aCtx.ClientName ) )
102 {
103 ApiResponseStatus e;
104 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
105 e.set_error_message( fmt::format( "the client {} does not has a commit in progress",
106 aCtx.ClientName ) );
107 return tl::unexpected( e );
108 }
109
110 wxASSERT( m_activeClients.count( aCtx.ClientName ) );
111
112 const std::pair<KIID, std::unique_ptr<COMMIT>>& pair = m_commits.at( aCtx.ClientName );
113 const KIID& id = pair.first;
114 const std::unique_ptr<COMMIT>& commit = pair.second;
115
116 EndCommitResponse response;
117
118 // Do not check IDs with drop; it is a safety net in case the id was lost on the client side
119 switch( aCtx.Request.action() )
120 {
121 case kiapi::common::commands::CMA_DROP:
122 {
123 commit->Revert();
124 m_commits.erase( aCtx.ClientName );
125 m_activeClients.erase( aCtx.ClientName );
126 break;
127 }
128
129 case kiapi::common::commands::CMA_COMMIT:
130 {
131 if( aCtx.Request.id().value().compare( id.AsStdString() ) != 0 )
132 {
133 ApiResponseStatus e;
134 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
135 e.set_error_message( fmt::format( "the id {} does not match the commit in progress",
136 aCtx.Request.id().value() ) );
137 return tl::unexpected( e );
138 }
139
140 pushCurrentCommit( aCtx.ClientName, wxString( aCtx.Request.message().c_str(), wxConvUTF8 ) );
141 break;
142 }
143
144 default:
145 break;
146 }
147
148 return response;
149}
150
151
152COMMIT* API_HANDLER_EDITOR::getCurrentCommit( const std::string& aClientName )
153{
154 if( !m_commits.count( aClientName ) )
155 {
156 KIID id;
157 m_commits[aClientName] = std::make_pair( id, createCommit() );
158 }
159
160 return m_commits.at( aClientName ).second.get();
161}
162
163
164void API_HANDLER_EDITOR::pushCurrentCommit( const std::string& aClientName,
165 const wxString& aMessage )
166{
167 auto it = m_commits.find( aClientName );
168
169 if( it == m_commits.end() )
170 return;
171
172 it->second.second->Push( aMessage.IsEmpty() ? m_defaultCommitMessage : aMessage );
173 m_commits.erase( it );
174 m_activeClients.erase( aClientName );
175}
176
177
179{
180 if( !validateDocumentInternal( aDocument ) )
181 {
182 ApiResponseStatus e;
183 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
184 e.set_error_message( fmt::format( "the requested document {} is not open",
185 aDocument.board_filename() ) );
186 return tl::unexpected( e );
187 }
188
189 return true;
190}
191
192
194 const types::ItemHeader& aHeader )
195{
196 if( !aHeader.has_document() || aHeader.document().type() != thisDocumentType() )
197 {
198 ApiResponseStatus e;
199 e.set_status( ApiStatusCode::AS_UNHANDLED );
200 // No error message, this is a flag that the server should try a different handler
201 return tl::unexpected( e );
202 }
203
204 HANDLER_RESULT<bool> documentValidation = validateDocument( aHeader.document() );
205
206 if( !documentValidation )
207 return tl::unexpected( documentValidation.error() );
208
209 if( tl::expected<bool, ApiResponseStatus> result = validateDocumentInternal( aHeader.document() ); !result )
210 return tl::unexpected( result.error() );
211
212 if( aHeader.has_container() )
213 {
214 return KIID( aHeader.container().value() );
215 }
216
217 // Valid header, but no container provided
218 return std::nullopt;
219}
220
221
222std::optional<ApiResponseStatus> API_HANDLER_EDITOR::checkForBusy()
223{
224 if( !m_frame )
225 return std::nullopt;
226
227 if( !m_frame->CanAcceptApiCommands() )
228 {
229 ApiResponseStatus e;
230 e.set_status( ApiStatusCode::AS_BUSY );
231 e.set_error_message( "KiCad is busy and cannot respond to API requests right now" );
232 return e;
233 }
234
235 return std::nullopt;
236}
237
238
240 const HANDLER_CONTEXT<CreateItems>& aCtx )
241{
242 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
243 return tl::unexpected( *busy );
244
245 CreateItemsResponse response;
246
248 aCtx.ClientName,
249 aCtx.Request.header(), aCtx.Request.items(),
250 [&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
251 {
252 ItemCreationResult itemResult;
253 itemResult.mutable_status()->CopyFrom( aStatus );
254 itemResult.mutable_item()->CopyFrom( aItem );
255 response.mutable_created_items()->Add( std::move( itemResult ) );
256 } );
257
258 if( !result.has_value() )
259 return tl::unexpected( result.error() );
260
261 response.set_status( *result );
262 return response;
263}
264
265
267 const HANDLER_CONTEXT<UpdateItems>& aCtx )
268{
269 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
270 return tl::unexpected( *busy );
271
272 UpdateItemsResponse response;
273
275 aCtx.ClientName,
276 aCtx.Request.header(), aCtx.Request.items(),
277 [&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
278 {
279 ItemUpdateResult itemResult;
280 itemResult.mutable_status()->CopyFrom( aStatus );
281 itemResult.mutable_item()->CopyFrom( aItem );
282 response.mutable_updated_items()->Add( std::move( itemResult ) );
283 } );
284
285 if( !result.has_value() )
286 return tl::unexpected( result.error() );
287
288 response.set_status( *result );
289 return response;
290}
291
292
294 const HANDLER_CONTEXT<DeleteItems>& aCtx )
295{
296 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
297 return tl::unexpected( *busy );
298
299 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
300 {
301 ApiResponseStatus e;
302 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
303 e.set_status( ApiStatusCode::AS_UNHANDLED );
304 return tl::unexpected( e );
305 }
306
307 std::map<KIID, ItemDeletionStatus> itemsToDelete;
308
309 for( const kiapi::common::types::KIID& kiidBuf : aCtx.Request.item_ids() )
310 {
311 if( !kiidBuf.value().empty() )
312 {
313 KIID kiid( kiidBuf.value() );
314 itemsToDelete[kiid] = ItemDeletionStatus::IDS_NONEXISTENT;
315 }
316 }
317
318 if( itemsToDelete.empty() )
319 {
320 ApiResponseStatus e;
321 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
322 e.set_error_message( "no valid items to delete were given" );
323 return tl::unexpected( e );
324 }
325
326 deleteItemsInternal( itemsToDelete, aCtx.ClientName );
327
328 DeleteItemsResponse response;
329
330 for( const auto& [id, status] : itemsToDelete )
331 {
332 ItemDeletionResult result;
333 result.mutable_id()->set_value( id.AsStdString() );
334 result.set_status( status );
335 }
336
337 response.set_status( kiapi::common::types::ItemRequestStatus::IRS_OK );
338 return response;
339}
340
341
343 const HANDLER_CONTEXT<HitTest>& aCtx )
344{
345 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
346 return tl::unexpected( *busy );
347
348 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
349 {
350 ApiResponseStatus e;
351 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
352 e.set_status( ApiStatusCode::AS_UNHANDLED );
353 return tl::unexpected( e );
354 }
355
356 HitTestResponse response;
357
358 std::optional<EDA_ITEM*> item = getItemFromDocument( aCtx.Request.header().document(),
359 KIID( aCtx.Request.id().value() ) );
360
361 if( !item )
362 {
363 ApiResponseStatus e;
364 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
365 e.set_error_message( "the requested item ID is not present in the given document" );
366 return tl::unexpected( e );
367 }
368
369 const EDA_IU_SCALE& scale = getIuScale();
370 VECTOR2I posIu = UnpackVector2( aCtx.Request.position(), scale );
371 int toleranceIu = scale.NmToIU( aCtx.Request.tolerance() );
372
373 if( ( *item )->HitTest( posIu, toleranceIu ) )
374 response.set_result( HitTestResult::HTR_HIT );
375 else
376 response.set_result( HitTestResult::HTR_NO_HIT );
377
378 return response;
379}
380
381
382std::vector<KICAD_T> API_HANDLER_EDITOR::parseRequestedItemTypes( const google::protobuf::RepeatedField<int>& aTypes )
383{
384 std::vector<KICAD_T> types;
385
386 for( int typeRaw : aTypes )
387 {
388 auto typeMessage = static_cast<types::KiCadObjectType>( typeRaw );
389
390 if( KICAD_T type = FromProtoEnum<KICAD_T>( typeMessage ); type != TYPE_NOT_INIT )
391 types.emplace_back( type );
392 }
393
394 return types;
395}
396
397
400{
401 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
402
403 if( !documentValidation )
404 return tl::unexpected( documentValidation.error() );
405
406 std::optional<TITLE_BLOCK*> optBlock = getTitleBlock();
407
408 if( !optBlock )
409 {
410 ApiResponseStatus e;
411 e.set_status( AS_BAD_REQUEST );
412 e.set_error_message( "this editor does not support a title block" );
413 return tl::unexpected( e );
414 }
415
416 TITLE_BLOCK& block = **optBlock;
417
418 types::TitleBlockInfo response;
419
420 response.set_title( block.GetTitle().ToUTF8() );
421 response.set_date( block.GetDate().ToUTF8() );
422 response.set_revision( block.GetRevision().ToUTF8() );
423 response.set_company( block.GetCompany().ToUTF8() );
424 response.set_comment1( block.GetComment( 0 ).ToUTF8() );
425 response.set_comment2( block.GetComment( 1 ).ToUTF8() );
426 response.set_comment3( block.GetComment( 2 ).ToUTF8() );
427 response.set_comment4( block.GetComment( 3 ).ToUTF8() );
428 response.set_comment5( block.GetComment( 4 ).ToUTF8() );
429 response.set_comment6( block.GetComment( 5 ).ToUTF8() );
430 response.set_comment7( block.GetComment( 6 ).ToUTF8() );
431 response.set_comment8( block.GetComment( 7 ).ToUTF8() );
432 response.set_comment9( block.GetComment( 8 ).ToUTF8() );
433
434 return response;
435}
436
437
440{
441 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
442
443 if( !documentValidation )
444 return tl::unexpected( documentValidation.error() );
445
446 if( !aCtx.Request.has_title_block() )
447 {
448 ApiResponseStatus e;
449 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
450 e.set_error_message( "SetTitleBlockInfo requires title_block" );
451 return tl::unexpected( e );
452 }
453
454 std::optional<TITLE_BLOCK*> optBlock = getTitleBlock();
455
456 if( !optBlock )
457 {
458 ApiResponseStatus e;
459 e.set_status( AS_BAD_REQUEST );
460 e.set_error_message( "this editor does not support a title block" );
461 return tl::unexpected( e );
462 }
463
464 TITLE_BLOCK& block = **optBlock;
465
466 const types::TitleBlockInfo& request = aCtx.Request.title_block();
467
468 block.SetTitle( wxString::FromUTF8( request.title() ) );
469 block.SetDate( wxString::FromUTF8( request.date() ) );
470 block.SetRevision( wxString::FromUTF8( request.revision() ) );
471 block.SetCompany( wxString::FromUTF8( request.company() ) );
472 block.SetComment( 0, wxString::FromUTF8( request.comment1() ) );
473 block.SetComment( 1, wxString::FromUTF8( request.comment2() ) );
474 block.SetComment( 2, wxString::FromUTF8( request.comment3() ) );
475 block.SetComment( 3, wxString::FromUTF8( request.comment4() ) );
476 block.SetComment( 4, wxString::FromUTF8( request.comment5() ) );
477 block.SetComment( 5, wxString::FromUTF8( request.comment6() ) );
478 block.SetComment( 6, wxString::FromUTF8( request.comment7() ) );
479 block.SetComment( 7, wxString::FromUTF8( request.comment8() ) );
480 block.SetComment( 8, wxString::FromUTF8( request.comment9() ) );
481
482 onModified();
483
484 return google::protobuf::Empty();
485}
486
487
490{
491 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
492
493 if( !documentValidation )
494 return tl::unexpected( documentValidation.error() );
495
496 std::optional<PAGE_INFO> optPageInfo = getPageSettings();
497
498 if( !optPageInfo )
499 {
500 ApiResponseStatus e;
501 e.set_status( AS_BAD_REQUEST );
502 e.set_error_message( "this editor does not support page settings" );
503 return tl::unexpected( e );
504 }
505
506 PAGE_INFO& pageInfo = *optPageInfo;
507
508 types::PageSettings response;
509 response.set_page_size( ToProtoEnum<PAGE_SIZE_TYPE, types::PageSize>( pageInfo.GetType() ) );
510
511 if( pageInfo.IsCustom() )
512 PackVector2( *response.mutable_user_page_size(), pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
513
514 response.set_orientation( pageInfo.IsPortrait() ? types::PageOrientation::PO_PORTRAIT
515 : types::PageOrientation::PO_LANDSCAPE );
516 response.set_drawing_sheet( getDrawingSheetFileName().ToUTF8() );
517
518 return response;
519}
520
521
524{
525 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
526
527 if( !documentValidation )
528 return tl::unexpected( documentValidation.error() );
529
530 if( !aCtx.Request.has_page_settings() )
531 {
532 ApiResponseStatus e;
533 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
534 e.set_error_message( "SetPageSettings requires page_settings" );
535 return tl::unexpected( e );
536 }
537
538 std::optional<PAGE_INFO> optPageInfo = getPageSettings();
539
540 if( !optPageInfo )
541 {
542 ApiResponseStatus e;
543 e.set_status( AS_BAD_REQUEST );
544 e.set_error_message( "this editor does not support page settings" );
545 return tl::unexpected( e );
546 }
547
548 const types::PageSettings& request = aCtx.Request.page_settings();
549
550 PAGE_INFO pageInfo = *optPageInfo;
551 PAGE_SIZE_TYPE pageSizeType = FromProtoEnum<PAGE_SIZE_TYPE>( request.page_size() );
552
553 if( pageSizeType == PAGE_SIZE_TYPE::User )
554 {
555 if( !request.has_user_page_size() )
556 {
557 ApiResponseStatus e;
558 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
559 e.set_error_message( "custom page size requires user_page_size" );
560 return tl::unexpected( e );
561 }
562
563 VECTOR2D sizeIu = UnpackVector2( request.user_page_size() );
564 PAGE_INFO::SetCustomWidthMils( pcbIUScale.IUToMils( sizeIu.x ) );
565 PAGE_INFO::SetCustomHeightMils( pcbIUScale.IUToMils( sizeIu.y ) );
566
567 pageInfo.SetType( PAGE_SIZE_TYPE::User );
568 }
569 else
570 {
571 bool portrait = ( request.orientation() == types::PageOrientation::PO_PORTRAIT );
572 pageInfo.SetType( pageSizeType, portrait );
573 }
574
575 if( !setPageSettings( pageInfo ) )
576 {
577 ApiResponseStatus e;
578 e.set_status( AS_BAD_REQUEST );
579 e.set_error_message( "this editor does not support page settings" );
580 return tl::unexpected( e );
581 }
582
583 wxString drawingSheet( wxString::FromUTF8( request.drawing_sheet() ) );
584 setDrawingSheetFileName( drawingSheet );
585
586 onModified();
587
588 types::PageSettings response;
589 response.set_page_size( ToProtoEnum<PAGE_SIZE_TYPE, types::PageSize>( pageInfo.GetType() ) );
590
591 if( pageInfo.IsCustom() )
592 PackVector2( *response.mutable_user_page_size(), pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
593
594 response.set_orientation( pageInfo.IsPortrait() ? types::PageOrientation::PO_PORTRAIT
595 : types::PageOrientation::PO_LANDSCAPE );
596 response.set_drawing_sheet( getDrawingSheetFileName().ToUTF8() );
597
598 return response;
599}
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:44
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
Definition api_handler.h:45
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
virtual std::optional< PAGE_INFO > getPageSettings()
virtual std::unique_ptr< COMMIT > createCommit()=0
Override this to create an appropriate COMMIT subclass for the frame in question.
HANDLER_RESULT< bool > validateDocument(const DocumentSpecifier &aDocument)
HANDLER_RESULT< commands::DeleteItemsResponse > handleDeleteItems(const HANDLER_CONTEXT< commands::DeleteItems > &aCtx)
HANDLER_RESULT< types::PageSettings > handleSetPageSettings(const HANDLER_CONTEXT< commands::SetPageSettings > &aCtx)
virtual const EDA_IU_SCALE & getIuScale() const
Returns the internal-unit scale that the concrete editor uses.
virtual std::optional< EDA_ITEM * > getItemFromDocument(const DocumentSpecifier &aDocument, const KIID &aId)=0
HANDLER_RESULT< std::optional< KIID > > validateItemHeaderDocument(const kiapi::common::types::ItemHeader &aHeader)
If the header is valid, returns the item container.
virtual void setDrawingSheetFileName(const wxString &aFileName)
HANDLER_RESULT< types::PageSettings > handleGetPageSettings(const HANDLER_CONTEXT< commands::GetPageSettings > &aCtx)
virtual std::optional< TITLE_BLOCK * > getTitleBlock()
HANDLER_RESULT< commands::EndCommitResponse > handleEndCommit(const HANDLER_CONTEXT< commands::EndCommit > &aCtx)
virtual tl::expected< bool, ApiResponseStatus > validateDocumentInternal(const DocumentSpecifier &aDocument) const =0
API_HANDLER_EDITOR(EDA_BASE_FRAME *aFrame=nullptr)
static std::vector< KICAD_T > parseRequestedItemTypes(const google::protobuf::RepeatedField< int > &aTypes)
HANDLER_RESULT< commands::CreateItemsResponse > handleCreateItems(const HANDLER_CONTEXT< commands::CreateItems > &aCtx)
COMMIT * getCurrentCommit(const std::string &aClientName)
virtual void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage)
virtual HANDLER_RESULT< 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)=0
std::set< std::string > m_activeClients
std::map< std::string, std::pair< KIID, std::unique_ptr< COMMIT > > > m_commits
virtual bool setPageSettings(const PAGE_INFO &aPageInfo)
HANDLER_RESULT< commands::UpdateItemsResponse > handleUpdateItems(const HANDLER_CONTEXT< commands::UpdateItems > &aCtx)
virtual void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName)=0
virtual wxString getDrawingSheetFileName()
virtual std::optional< ApiResponseStatus > checkForBusy()
Checks if the editor can accept commands.
HANDLER_RESULT< types::TitleBlockInfo > handleGetTitleBlockInfo(const HANDLER_CONTEXT< commands::GetTitleBlockInfo > &aCtx)
virtual types::DocumentType thisDocumentType() const =0
Override this to specify which document type this editor handles.
HANDLER_RESULT< google::protobuf::Empty > handleSetTitleBlockInfo(const HANDLER_CONTEXT< commands::SetTitleBlockInfo > &aCtx)
HANDLER_RESULT< commands::BeginCommitResponse > handleBeginCommit(const HANDLER_CONTEXT< commands::BeginCommit > &aCtx)
virtual void onModified()
HANDLER_RESULT< commands::HitTestResponse > handleHitTest(const HANDLER_CONTEXT< commands::HitTest > &aCtx)
EDA_BASE_FRAME * m_frame
static const wxString m_defaultCommitMessage
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
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:72
The base frame for deriving all KiCad main window classes.
Definition kiid.h:48
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
bool SetType(PAGE_SIZE_TYPE aPageSize, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
static void SetCustomWidthMils(double aWidthInMils)
Set the width of Custom page in mils for any custom page constructed or made via SetType() after maki...
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition page_info.h:177
bool IsCustom() const
bool IsPortrait() const
Definition page_info.h:128
static void SetCustomHeightMils(double aHeightInMils)
Set the height of Custom page in mils for any custom page constructed or made via SetType() after mak...
const PAGE_SIZE_TYPE & GetType() const
Definition page_info.h:102
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
void SetRevision(const wxString &aRevision)
Definition title_block.h:81
void SetComment(int aIdx, const wxString &aComment)
const wxString & GetRevision() const
Definition title_block.h:86
void SetTitle(const wxString &aTitle)
Definition title_block.h:58
const wxString & GetDate() const
Definition title_block.h:76
const wxString & GetComment(int aIdx) const
void SetCompany(const wxString &aCompany)
Definition title_block.h:91
const wxString & GetTitle() const
Definition title_block.h:63
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition title_block.h:71
Base window classes and related definitions.
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
PAGE_SIZE_TYPE
Definition page_info.h:50
const int scale
std::string ClientName
Definition api_handler.h:51
RequestMessageType Request
Definition api_handler.h:52
wxString result
Test unit parsing edge cases and error handling.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:75
@ TYPE_NOT_INIT
Definition typeinfo.h:78
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686