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