KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_wizard_properties_panel.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
21#include <ranges>
22
24
25#include <footprint_wizard.h>
26#include <geometry/eda_angle.h>
30#include <widgets/ui_common.h>
31
32#include <wx/regex.h>
33#include <wx/stattext.h>
34
35
37 FOOTPRINT_WIZARD_FRAME* aFrame ) :
38 PROPERTIES_PANEL( aParent, aFrame ),
39 m_frame( aFrame ),
40 m_unitEditorInstance( nullptr ),
41 m_checkboxEditorInstance( nullptr ),
42 m_ratioEditorInstance( nullptr )
43{
44 // AUI panel caption is enough
45 m_caption->Hide();
46
47 wxASSERT( wxPGGlobalVars );
48
49 wxString editorKey = PG_UNIT_EDITOR::BuildEditorName( m_frame );
50 auto it = wxPGGlobalVars->m_mapEditorClasses.find( editorKey );
51
52 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
53 {
54 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( it->second );
55 m_unitEditorInstance->UpdateFrame( m_frame );
56 }
57 else
58 {
59 PG_UNIT_EDITOR* new_editor = new PG_UNIT_EDITOR( m_frame );
60 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( wxPropertyGrid::RegisterEditorClass( new_editor ) );
61 }
62
63 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_CHECKBOX_EDITOR::EDITOR_NAME );
64
65 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
66 {
67 PG_CHECKBOX_EDITOR* cbEditor = new PG_CHECKBOX_EDITOR();
68 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( wxPropertyGrid::RegisterEditorClass( cbEditor ) );
69 }
70 else
71 {
72 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( it->second );
73 }
74
75 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_RATIO_EDITOR::EDITOR_NAME );
76
77 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
78 {
79 PG_RATIO_EDITOR* ratioEditor = new PG_RATIO_EDITOR();
80 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( wxPropertyGrid::RegisterEditorClass( ratioEditor ) );
81 }
82 else
83 {
84 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( it->second );
85 }
86}
87
88
94
95
99
100
102{
103 SUPPRESS_GRID_CHANGED_EVENTS raii( this );
104
105 if( m_grid->IsEditorFocused() )
106 m_grid->CommitChangesFromEditor();
107
108 m_grid->Clear();
109
110 if( !aWizard )
111 return;
112
113 std::map<kiapi::common::types::WizardParameterCategory, std::vector<WIZARD_PARAMETER*>> params;
114
115 for( const std::unique_ptr<WIZARD_PARAMETER>& param : aWizard->Info().parameters )
116 params[param->category].emplace_back( param.get() );
117
118 for( kiapi::common::types::WizardParameterCategory category : params | std::views::keys )
119 {
120 auto groupItem = new wxPropertyCategory( WIZARD_PARAMETER::ParameterCategoryName( category ) );
121 m_grid->Append( groupItem );
122
123 for( WIZARD_PARAMETER* param : params[category] )
124 {
125 if( wxPGProperty* prop = createPGProperty( param ) )
126 m_grid->Append( prop );
127 }
128 }
129
131}
132
133
135{
136 wxPGProperty* ret = nullptr;
137
138 switch( aParam->type )
139 {
140 case kiapi::common::types::WPDT_DISTANCE:
141 ret = new PGPROPERTY_SIZE( m_frame );
142 ret->SetEditor( PG_UNIT_EDITOR::BuildEditorName( m_frame ) );
143 break;
144
145 case kiapi::common::types::WPDT_AREA:
146 ret = new PGPROPERTY_AREA( m_frame );
147 ret->SetEditor( PG_UNIT_EDITOR::BuildEditorName( m_frame ) );
148 break;
149
150 case kiapi::common::types::WPDT_VOLUME:
151 wxASSERT_MSG( false, "Volume properties are not currently implemented" );
152 break;
153
154 case kiapi::common::types::WPDT_TIME:
155 ret = new wxFloatProperty();
156 break;
157
158 case kiapi::common::types::WPDT_ANGLE:
159 ret = new PGPROPERTY_ANGLE();;
160 ret->SetEditor( PG_UNIT_EDITOR::BuildEditorName( m_frame ) );
161 break;
162
163 case kiapi::common::types::WPDT_STRING:
164 ret = new PGPROPERTY_STRING();
165 break;
166
167 case kiapi::common::types::WPDT_INTEGER:
168 ret = new wxIntProperty();
169 break;
170
171 case kiapi::common::types::WPDT_REAL:
172 ret = new wxFloatProperty();
173 break;
174
175 case kiapi::common::types::WPDT_BOOL:
176 ret = new PGPROPERTY_BOOL();
177 break;
178
179 case kiapi::common::types::WPDT_ENUM:
180 {
181 if( auto param = dynamic_cast<const WIZARD_ENUM_PARAMETER*>( aParam ) )
182 {
183 wxPGChoices pgChoices;
184
185 for( size_t i = 0; i < param->choices.size(); ++i )
186 pgChoices.Add( wxGetTranslation( param->choices[i].second ), static_cast<int>( i ) );
187
188 ret = new wxEnumProperty( wxPG_LABEL, wxPG_LABEL, pgChoices );
189 }
190
191 break;
192 }
193
194 case kiapi::common::types::WPDT_UNKNOWN:
195 default:
196 break;
197 }
198
199 if( ret )
200 {
201 ret->SetLabel( wxGetTranslation( aParam->name ) );
202 ret->SetName( aParam->identifier );
203 ret->SetHelpString( wxGetTranslation( aParam->description ) );
204 ret->SetClientData( aParam );
205
206 if( auto ip = dynamic_cast<const WIZARD_INT_PARAMETER*>( aParam ) )
207 ret->SetValue( ip->value );
208 else if( auto rp = dynamic_cast<const WIZARD_REAL_PARAMETER*>( aParam ) )
209 ret->SetValue( rp->value );
210 else if( auto bp = dynamic_cast<const WIZARD_BOOL_PARAMETER*>( aParam ) )
211 ret->SetValue( bp->value );
212 else if( auto sp = dynamic_cast<const WIZARD_STRING_PARAMETER*>( aParam ) )
213 ret->SetValue( sp->value );
214 else if( auto ep = dynamic_cast<const WIZARD_ENUM_PARAMETER*>( aParam ) )
215 ret->SetValue( ep->value );
216 }
217
218 return ret;
219}
220
221
223{
224 return static_cast<WIZARD_PARAMETER*>( aEvent.GetProperty()->GetClientData() );
225}
226
227
229{
230 switch( aParam->type )
231 {
232 case kiapi::common::types::WPDT_DISTANCE:
233 return m_frame->MessageTextFromValue( aValue, true, EDA_DATA_TYPE::DISTANCE );
234
235 case kiapi::common::types::WPDT_AREA:
236 return m_frame->MessageTextFromValue( aValue, true, EDA_DATA_TYPE::AREA );
237
238 case kiapi::common::types::WPDT_TIME:
239 return m_frame->MessageTextFromValue( aValue, true, EDA_DATA_TYPE::TIME );
240
241 default:
242 return wxString::Format( wxS( "%d" ), aValue );
243 }
244}
245
246
248{
249 switch( aParam->type )
250 {
251 case kiapi::common::types::WPDT_ANGLE:
252 return m_frame->MessageTextFromValue( EDA_ANGLE( aValue, DEGREES_T ) );
253
254 default:
255 return wxString::Format( wxS( "%.3f" ), aValue );
256 }
257}
258
259
260void FOOTPRINT_WIZARD_PROPERTIES_PANEL::valueChanging( wxPropertyGridEvent& aEvent )
261{
263 return;
264
265 WIZARD_PARAMETER* param = getParamFromEvent( aEvent );
266 wxCHECK( param, /* void */ );
267
268 wxAny newValue = aEvent.GetPropertyValue();
269
270 if( WIZARD_INT_PARAMETER* ip = dynamic_cast<WIZARD_INT_PARAMETER*>( param ) )
271 {
272 int value = newValue.As<int>();
273
274 if( ip->min && value < *ip->min )
275 {
276 m_frame->SetBuildMessage( wxString::Format( _( "%s must be at least %s." ),
277 wxGetTranslation( ip->name ),
278 formatConstraintValue( ip, *ip->min ) ) );
279 aEvent.Veto();
280 return;
281 }
282
283 if( ip->max && value > *ip->max )
284 {
285 m_frame->SetBuildMessage( wxString::Format( _( "%s must be at most %s." ),
286 wxGetTranslation( ip->name ),
287 formatConstraintValue( ip, *ip->max ) ) );
288 aEvent.Veto();
289 return;
290 }
291
292 if( ip->multiple && ( value % *ip->multiple ) != 0 )
293 {
294 m_frame->SetBuildMessage( wxString::Format( _( "%s must be a multiple of %s." ),
295 wxGetTranslation( ip->name ),
296 formatConstraintValue( ip, *ip->multiple ) ) );
297 aEvent.Veto();
298 return;
299 }
300 }
301 else if( WIZARD_REAL_PARAMETER* rp = dynamic_cast<WIZARD_REAL_PARAMETER*>( param ) )
302 {
303 double value = newValue.As<double>();
304
305 if( rp->min && value < *rp->min )
306 {
307 m_frame->SetBuildMessage( wxString::Format( _( "%s must be at least %s." ),
308 wxGetTranslation( rp->name ),
309 formatConstraintValue( rp, *rp->min ) ) );
310 aEvent.Veto();
311 return;
312 }
313
314 if( rp->max && value > *rp->max )
315 {
316 m_frame->SetBuildMessage( wxString::Format( _( "%s must be at most %s." ),
317 wxGetTranslation( rp->name ),
318 formatConstraintValue( rp, *rp->max ) ) );
319 aEvent.Veto();
320 return;
321 }
322 }
323 else if( WIZARD_STRING_PARAMETER* sp = dynamic_cast<WIZARD_STRING_PARAMETER*>( param ) )
324 {
325 if( sp->validation_regex )
326 {
327 if( wxRegEx re( *sp->validation_regex, wxRE_ADVANCED ); re.IsValid() )
328 {
329 if( wxString value = newValue.As<wxString>(); !re.Matches( value ) )
330 {
331 m_frame->SetBuildMessage( wxString::Format( _( "%s does not match the required format '%s'." ),
332 wxGetTranslation( sp->name ), *sp->validation_regex ) );
333 aEvent.Veto();
334 return;
335 }
336 }
337 }
338 }
339
340 aEvent.Skip();
341}
342
343
344void FOOTPRINT_WIZARD_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
345{
346 WIZARD_PARAMETER* param = getParamFromEvent( aEvent );
347 wxCHECK( param, /* void */ );
348
349 wxAny newValue = aEvent.GetPropertyValue();
350
351 if( WIZARD_INT_PARAMETER* ip = dynamic_cast<WIZARD_INT_PARAMETER*>( param ) )
352 {
353 ip->value = newValue.As<int>();
354 }
355 else if( WIZARD_REAL_PARAMETER* rp = dynamic_cast<WIZARD_REAL_PARAMETER*>( param ) )
356 {
357 rp->value = newValue.As<double>();
358 }
359 else if( WIZARD_BOOL_PARAMETER* bp = dynamic_cast<WIZARD_BOOL_PARAMETER*>( param ) )
360 {
361 bp->value = newValue.As<bool>();
362 }
363 else if( WIZARD_STRING_PARAMETER* sp = dynamic_cast<WIZARD_STRING_PARAMETER*>( param ) )
364 {
365 sp->value = newValue.As<wxString>();
366 }
367 else if( WIZARD_ENUM_PARAMETER* ep = dynamic_cast<WIZARD_ENUM_PARAMETER*>( param ) )
368 {
369 ep->value = newValue.As<int>();
370 }
371
372 m_frame->OnWizardParametersChanged();
373}
FOOTPRINT_WIZARD_PROPERTIES_PANEL(wxWindow *aParent, FOOTPRINT_WIZARD_FRAME *aFrame)
wxString formatConstraintValue(const WIZARD_PARAMETER *aParam, int aValue) const
void valueChanged(wxPropertyGridEvent &aEvent) override
wxPGProperty * createPGProperty(const PROPERTY_BASE *aProperty) const override
static WIZARD_PARAMETER * getParamFromEvent(const wxPropertyGridEvent &aEvent)
void valueChanging(wxPropertyGridEvent &aEvent) override
WIZARD_INFO & Info()
A wxEnumProperty that displays a color next to the enum value.
static const wxString EDITOR_NAME
Definition pg_editors.h:75
static const wxString EDITOR_NAME
Definition pg_editors.h:117
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
PROPERTIES_PANEL(wxWindow *aParent, EDA_BASE_FRAME *aFrame)
wxPropertyGrid * m_grid
wxStaticText * m_caption
kiapi::common::types::WizardParameterDataType type
static wxString ParameterCategoryName(kiapi::common::types::WizardParameterCategory aCategory)
#define _(s)
@ DEGREES_T
Definition eda_angle.h:31
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
std::vector< std::unique_ptr< WIZARD_PARAMETER > > parameters
Functions to provide common constants and other functions to assist in making a consistent UI.