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