KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_wizard.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) 2026 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#include <api/api_utils.h>
23#include <footprint.h>
24#include <pgm_base.h>
25#include <wx/log.h>
26
27#include <google/protobuf/util/json_util.h>
28
29#include "footprint_wizard.h"
30
31
33{
34 for( const std::unique_ptr<WIZARD_PARAMETER>& param : m_info.parameters )
35 param->Reset();
36}
37
38
40{
41 m_wizards.clear();
42
44 std::vector<const PLUGIN_ACTION*> actions = manager.GetActionsForScope( PLUGIN_ACTION_SCOPE::FOOTPRINT_WIZARD );
45
46 for( const PLUGIN_ACTION* action : actions )
47 {
48 std::unique_ptr<FOOTPRINT_WIZARD> wizard = std::make_unique<FOOTPRINT_WIZARD>();
49 wizard->SetIdentifier( action->identifier );
50
51 if( RefreshInfo( wizard.get() ) )
52 m_wizards[wizard->Identifier()] = std::move( wizard );
53 }
54}
55
56
57std::vector<FOOTPRINT_WIZARD*> FOOTPRINT_WIZARD_MANAGER::Wizards() const
58{
59 std::vector<FOOTPRINT_WIZARD*> wizards;
60
61 for( const std::unique_ptr<FOOTPRINT_WIZARD>& wizard : m_wizards | std::views::values )
62 wizards.emplace_back( wizard.get() );
63
64 std::ranges::sort( wizards,
65 []( FOOTPRINT_WIZARD* const& lhs,
66 FOOTPRINT_WIZARD* const& rhs ) -> bool
67 {
68 if( !lhs || !rhs )
69 return false;
70
71 return lhs->Info().meta.name < rhs->Info().meta.name;
72 } );
73
74 return wizards;
75}
76
77
78std::optional<FOOTPRINT_WIZARD*> FOOTPRINT_WIZARD_MANAGER::GetWizard( const wxString& aIdentifier )
79{
80 if( m_wizards.contains( aIdentifier ) )
81 return m_wizards[aIdentifier].get();
82
83 return std::nullopt;
84}
85
86
88{
89 wxCHECK( aWizard, false );
90
92
93 const wxLanguageInfo* lang = wxLocale::GetLanguageInfo( Pgm().GetSelectedLanguageIdentifier() );
94
95 std::vector<wxString> args = {
96 wxS( "--get-info" ),
97 wxS( "--lang" ),
98 lang->CanonicalName
99 };
100
101 wxString out, err;
102 int ret = manager.InvokeActionSync( aWizard->Identifier(), args, &out, &err );
103
104 if( ret != 0 )
105 return false;
106
107 kiapi::common::types::WizardInfo info;
108
109 google::protobuf::util::JsonParseOptions options;
110 options.ignore_unknown_fields = true;
111
112 if( !google::protobuf::util::JsonStringToMessage( out.ToStdString(), &info, options ).ok() )
113 return false;
114
115 aWizard->Info().FromProto( info );
116 return true;
117}
118
119
120tl::expected<FOOTPRINT*, wxString> FOOTPRINT_WIZARD_MANAGER::Generate( FOOTPRINT_WIZARD* aWizard )
121{
122 wxCHECK( aWizard, tl::unexpected( _( "Unexpected error with footprint wizard" ) ) );
124
125 const wxLanguageInfo* lang = wxLocale::GetLanguageInfo( Pgm().GetSelectedLanguageIdentifier() );
126
127 std::vector<wxString> args = {
128 wxS( "--generate" ),
129 wxS( "--lang" ),
130 lang->CanonicalName,
131 wxS( "--params" )
132 };
133
134 kiapi::common::types::WizardParameterList params;
135
136 for( const std::unique_ptr<WIZARD_PARAMETER>& param : aWizard->Info().parameters )
137 params.mutable_parameters()->Add( param->Pack() );
138
139 std::string paramsJson;
140
141 if( !google::protobuf::util::MessageToJsonString( params, &paramsJson ).ok() )
142 return tl::unexpected( _( "Unexpected error with footprint wizard" ) );
143
144 args.emplace_back( wxString::Format( wxS( "'%s'" ), paramsJson ) );
145
146 wxString out, err;
147 int ret = manager.InvokeActionSync( aWizard->Identifier(), args, &out, &err );
148
149 if( ret != 0 )
150 return tl::unexpected( wxString::Format( _( "Could not launch footprint wizard '%s'" ), aWizard->Info().meta.name ) );
151
152 kiapi::common::types::WizardGeneratedContent response;
153
154 google::protobuf::util::JsonParseOptions options;
155 options.ignore_unknown_fields = true;
156
157 if( !google::protobuf::util::JsonStringToMessage( out.ToStdString(), &response, options ).ok() )
158 {
159 wxLogTrace( traceApi, wxString::Format( "Could not decode response:\n%s", out ) );
160 return tl::unexpected( _( "Unexpected response from footprint wizard" ) );
161 }
162
163 if( response.status() != kiapi::common::types::WGS_OK )
164 return tl::unexpected( wxString::Format( _( "Footprint wizard error: %s" ), response.error_message() ) );
165
166 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>( nullptr );
167
168 if( !fp->Deserialize( response.content() ) )
169 return tl::unexpected( _( "Unexpected response from footprint wizard" ) );
170
171 return fp.release();
172}
173
174
175void WIZARD_META_INFO::FromProto( const kiapi::common::types::WizardMetaInfo& aProto )
176{
177 identifier = wxString::FromUTF8( aProto.identifier() );
178 name = wxString::FromUTF8( aProto.name() );
179 description = wxString::FromUTF8( aProto.description() );
180
181 types_generated.clear();
182
183 for( int type : aProto.types_generated() )
184 types_generated.insert( static_cast<kiapi::common::types::WizardContentType>( type ) );
185}
186
187
188wxString WIZARD_PARAMETER::ParameterCategoryName( kiapi::common::types::WizardParameterCategory aCategory )
189{
190 using namespace kiapi::common::types;
191
192 switch( aCategory )
193 {
194 case WPC_PACKAGE: return _( "Package" );
195 case WPC_PADS: return _( "Pads" );
196 case WPC_3DMODEL: return _( "3D Model" );
197 case WPC_METADATA: return _( "General" );
198 case WPC_RULES: return _( "Design Rules" );
199 case WPC_UNKNOWN:
200 default:
201 wxCHECK_MSG( false, wxEmptyString, "Unhandled parameter category type!" );
202 }
203}
204
205
206std::unique_ptr<WIZARD_PARAMETER> WIZARD_PARAMETER::Create( const kiapi::common::types::WizardParameter& aProto )
207{
208 std::unique_ptr<WIZARD_PARAMETER> p;
209
210 if( aProto.has_int_() )
211 {
212 p = std::make_unique<WIZARD_INT_PARAMETER>();
213 static_cast<WIZARD_INT_PARAMETER*>( p.get() )->FromProto( aProto.int_() );
214 }
215 else if( aProto.has_real() )
216 {
217 p = std::make_unique<WIZARD_REAL_PARAMETER>();
218 static_cast<WIZARD_REAL_PARAMETER*>( p.get() )->FromProto( aProto.real() );
219 }
220 else if( aProto.has_string() )
221 {
222 p = std::make_unique<WIZARD_STRING_PARAMETER>();
223 static_cast<WIZARD_STRING_PARAMETER*>( p.get() )->FromProto( aProto.string() );
224 }
225 else if( aProto.has_bool_() )
226 {
227 p = std::make_unique<WIZARD_BOOL_PARAMETER>();
228 static_cast<WIZARD_BOOL_PARAMETER*>( p.get() )->FromProto( aProto.bool_() );
229 }
230
231 p->identifier = wxString::FromUTF8( aProto.identifier() );
232 p->name = wxString::FromUTF8( aProto.name() );
233 p->description = wxString::FromUTF8( aProto.description() );
234 p->category = aProto.category();
235 p->type = aProto.type();
236
237 return p;
238}
239
240
241kiapi::common::types::WizardParameter WIZARD_PARAMETER::Pack( bool aCompact )
242{
243 kiapi::common::types::WizardParameter packed;
244
245 packed.set_identifier( identifier.ToUTF8() );
246
247 if( !aCompact )
248 {
249 packed.set_name( name.ToUTF8() );
250 packed.set_description( description.ToUTF8() );
251 packed.set_category( category );
252 packed.set_type( type );
253 }
254
255 return packed;
256}
257
258
259kiapi::common::types::WizardParameter WIZARD_INT_PARAMETER::Pack( bool aCompact )
260{
261 kiapi::common::types::WizardParameter packed = WIZARD_PARAMETER::Pack();
262
263 packed.mutable_int_()->set_value( value );
264
265 if( !aCompact )
266 {
267 packed.mutable_int_()->set_default_( default_value );
268
269 if( min )
270 packed.mutable_int_()->set_min( *min );
271
272 if( max )
273 packed.mutable_int_()->set_max( *max );
274
275 if( multiple )
276 packed.mutable_int_()->set_multiple( *multiple );
277 }
278
279 return packed;
280}
281
282
283kiapi::common::types::WizardParameter WIZARD_REAL_PARAMETER::Pack( bool aCompact )
284{
285 kiapi::common::types::WizardParameter packed = WIZARD_PARAMETER::Pack();
286
287 packed.mutable_real()->set_value( value );
288
289 if( !aCompact )
290 {
291 packed.mutable_real()->set_default_( default_value );
292
293 if( min )
294 packed.mutable_real()->set_min( *min );
295
296 if( max )
297 packed.mutable_real()->set_max( *max );
298 }
299
300 return packed;
301}
302
303
304kiapi::common::types::WizardParameter WIZARD_BOOL_PARAMETER::Pack( bool aCompact )
305{
306 kiapi::common::types::WizardParameter packed = WIZARD_PARAMETER::Pack();
307
308 packed.mutable_bool_()->set_value( value );
309
310 if( !aCompact )
311 packed.mutable_bool_()->set_default_( default_value );
312
313 return packed;
314}
315
316
317kiapi::common::types::WizardParameter WIZARD_STRING_PARAMETER::Pack( bool aCompact )
318{
319 kiapi::common::types::WizardParameter packed = WIZARD_PARAMETER::Pack();
320
321 packed.mutable_string()->set_value( value );
322
323 if( !aCompact )
324 packed.mutable_string()->set_default_( default_value );
325
326 return packed;
327}
328
329
330void WIZARD_INT_PARAMETER::FromProto( const kiapi::common::types::WizardIntParameter& aProto )
331{
332 value = aProto.value();
333 default_value = aProto.default_();
334
335 if( aProto.has_min() )
336 min = aProto.min();
337 else
338 min.reset();
339
340 if( aProto.has_max() )
341 max = aProto.max();
342 else
343 max.reset();
344
345 if( aProto.has_multiple() )
346 multiple = aProto.multiple();
347 else
348 multiple.reset();
349}
350
351
352void WIZARD_REAL_PARAMETER::FromProto( const kiapi::common::types::WizardRealParameter& aProto )
353{
354 value = aProto.value();
355 default_value = aProto.default_();
356
357 if( aProto.has_min() )
358 min = aProto.min();
359 else
360 min.reset();
361
362 if( aProto.has_max() )
363 max = aProto.max();
364 else
365 max.reset();
366}
367
368
369void WIZARD_BOOL_PARAMETER::FromProto( const kiapi::common::types::WizardBoolParameter& aProto )
370{
371 value = aProto.value();
372 default_value = aProto.default_();
373}
374
375
376void WIZARD_STRING_PARAMETER::FromProto( const kiapi::common::types::WizardStringParameter& aProto )
377{
378 value = wxString::FromUTF8( aProto.value() );
379 default_value = wxString::FromUTF8( aProto.default_() );
380
381 if( aProto.has_validation_regex() )
382 validation_regex = wxString::FromUTF8( aProto.validation_regex() );
383 else
384 validation_regex.reset();
385}
386
387
388void WIZARD_INFO::FromProto( const kiapi::common::types::WizardInfo& aProto )
389{
390 meta.FromProto( aProto.meta() );
391
392 parameters.clear();
393 parameters.reserve( aProto.parameters_size() );
394
395 for( const kiapi::common::types::WizardParameter& parameter : aProto.parameters() )
396 parameters.emplace_back( WIZARD_PARAMETER::Create( parameter ) );
397}
Responsible for loading plugin definitions for API-based plugins (ones that do not run inside KiCad i...
int InvokeActionSync(const wxString &aIdentifier, std::vector< wxString > aExtraArgs, wxString *aStdout=nullptr, wxString *aStderr=nullptr, std::shared_ptr< REPORTER > aReporter=nullptr)
Invokes an action synchronously, capturing its output.
std::vector< const PLUGIN_ACTION * > GetActionsForScope(PLUGIN_ACTION_SCOPE aScope)
std::map< wxString, std::unique_ptr< FOOTPRINT_WIZARD > > m_wizards
void ReloadWizards()
Goes through the list of IPC API plugins that provide wizard actions and attempts to refresh the info...
std::vector< FOOTPRINT_WIZARD * > Wizards() const
static bool RefreshInfo(FOOTPRINT_WIZARD *aWizard)
Runs a wizard plugin with the –get-info argument, which should result in the plugin dumping a WizardI...
std::optional< FOOTPRINT_WIZARD * > GetWizard(const wxString &aIdentifier)
tl::expected< FOOTPRINT *, wxString > Generate(FOOTPRINT_WIZARD *aWizard)
Generates a footprint using a given wizard.
const wxString & Identifier() const
WIZARD_INFO & Info()
virtual API_PLUGIN_MANAGER & GetPluginManager() const
Definition pgm_base.h:140
void FromProto(const kiapi::common::types::WizardBoolParameter &aProto)
kiapi::common::types::WizardParameter Pack(bool aCompact=true) override
Packs the current state of this parameter back into a protobuf message.
void FromProto(const kiapi::common::types::WizardIntParameter &aProto)
std::optional< int > min
std::optional< int > multiple
kiapi::common::types::WizardParameter Pack(bool aCompact=true) override
Packs the current state of this parameter back into a protobuf message.
std::optional< int > max
virtual kiapi::common::types::WizardParameter Pack(bool aCompact=true)
Packs the current state of this parameter back into a protobuf message.
kiapi::common::types::WizardParameterDataType type
static wxString ParameterCategoryName(kiapi::common::types::WizardParameterCategory aCategory)
static std::unique_ptr< WIZARD_PARAMETER > Create(const kiapi::common::types::WizardParameter &aProto)
kiapi::common::types::WizardParameterCategory category
kiapi::common::types::WizardParameter Pack(bool aCompact=true) override
Packs the current state of this parameter back into a protobuf message.
void FromProto(const kiapi::common::types::WizardRealParameter &aProto)
std::optional< double > min
std::optional< double > max
std::optional< wxString > validation_regex
kiapi::common::types::WizardParameter Pack(bool aCompact=true) override
Packs the current state of this parameter back into a protobuf message.
void FromProto(const kiapi::common::types::WizardStringParameter &aProto)
#define _(s)
const wxChar *const traceApi
Flag to enable debug output related to the IPC API and its plugin system.
Definition api_utils.cpp:29
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
An action performed by a plugin via the IPC API.
Definition api_plugin.h:72
std::vector< std::unique_ptr< WIZARD_PARAMETER > > parameters
WIZARD_META_INFO meta
void FromProto(const kiapi::common::types::WizardInfo &aProto)
void FromProto(const kiapi::common::types::WizardMetaInfo &aProto)
std::set< kiapi::common::types::WizardContentType > types_generated