KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pg_editors.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <eda_draw_frame.h>
26#include <widgets/unit_binder.h>
27
28#include <wx/log.h>
29
30const wxString PG_UNIT_EDITOR::EDITOR_NAME = wxS( "KiCadUnitEditor" );
31const wxString PG_CHECKBOX_EDITOR::EDITOR_NAME = wxS( "KiCadCheckboxEditor" );
32const wxString PG_COLOR_EDITOR::EDITOR_NAME = wxS( "KiCadColorEditor" );
33const wxString PG_RATIO_EDITOR::EDITOR_NAME = wxS( "KiCadRatioEditor" );
34
35
37 wxPGTextCtrlEditor(),
38 m_frame( aFrame )
39{
40 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
41 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
42
44}
45
46
48{
49}
50
51
53{
54 return EDITOR_NAME + aFrame->GetName();
55}
56
57
59{
60 m_frame = aFrame;
61
62 if( aFrame )
63 {
64 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
65 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
66 }
67 else
68 {
69 m_unitBinder = nullptr;
70 }
71}
72
73
74wxPGWindowList PG_UNIT_EDITOR::CreateControls( wxPropertyGrid* aPropGrid, wxPGProperty* aProperty,
75 const wxPoint& aPos, const wxSize& aSize ) const
76{
77 wxASSERT( m_unitBinder );
78
79#if wxCHECK_VERSION( 3, 3, 0 )
80 wxString text = aProperty->GetValueAsString( wxPGPropValFormatFlags::EditableValue );
81#else
82 wxString text = aProperty->GetValueAsString( wxPG_EDITABLE_VALUE );
83#endif
84 wxWindow* win = aPropGrid->GenerateEditorTextCtrl( aPos, aSize, text, nullptr, 0,
85 aProperty->GetMaxLength() );
86 wxPGWindowList ret( win, nullptr );
87
88 m_unitBinder->SetControl( win );
89 m_unitBinder->RequireEval();
90 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
91
92 if( PGPROPERTY_DISTANCE* prop = dynamic_cast<PGPROPERTY_DISTANCE*>( aProperty ) )
93 {
94 m_unitBinder->SetCoordType( prop->CoordType() );
95 }
96 else if( dynamic_cast<PGPROPERTY_AREA*>( aProperty) != nullptr )
97 {
98 m_unitBinder->SetDataType( EDA_DATA_TYPE::AREA );
99 }
100 else if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) != nullptr )
101 {
103 m_unitBinder->SetUnits( EDA_UNITS::DEGREES );
104 }
105 else if( dynamic_cast<PGPROPERTY_TIME*>( aProperty ) != nullptr )
106 {
107 m_unitBinder->SetUnits( EDA_UNITS::PS );
108 }
109
110 UpdateControl( aProperty, win );
111
112 return ret;
113}
114
115
116void PG_UNIT_EDITOR::UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const
117{
118 wxVariant var = aProperty->GetValue();
119
120 if( var.GetType() == wxT( "std::optional<int>" ) )
121 {
122 auto* variantData = static_cast<STD_OPTIONAL_INT_VARIANT_DATA*>( var.GetData() );
123
124 if( variantData->Value().has_value() )
125 m_unitBinder->ChangeValue( variantData->Value().value() );
126 else
127 m_unitBinder->ChangeValue( wxEmptyString );
128 }
129 else if( var.GetType() == wxPG_VARIANT_TYPE_LONG )
130 {
131 m_unitBinder->ChangeValue( var.GetLong() );
132 }
133 else if( var.GetType() == wxPG_VARIANT_TYPE_LONGLONG )
134 {
135 m_unitBinder->ChangeDoubleValue( var.GetLongLong().ToDouble() );
136 }
137 else if( var.GetType() == wxPG_VARIANT_TYPE_DOUBLE )
138 {
139 m_unitBinder->ChangeValue( var.GetDouble() );
140 }
141 else if( var.GetType() == wxT( "EDA_ANGLE" ) )
142 {
143 EDA_ANGLE_VARIANT_DATA* angleData = static_cast<EDA_ANGLE_VARIANT_DATA*>( var.GetData() );
144 m_unitBinder->ChangeAngleValue( angleData->Angle() );
145 }
146 else if( !aProperty->IsValueUnspecified() )
147 {
148 wxFAIL_MSG( wxT( "PG_UNIT_EDITOR should only be used with numeric properties!" ) );
149 }
150}
151
152
153bool PG_UNIT_EDITOR::OnEvent( wxPropertyGrid* aPropGrid, wxPGProperty* aProperty,
154 wxWindow* aCtrl, wxEvent& aEvent ) const
155{
156 if( aEvent.GetEventType() == wxEVT_LEFT_UP )
157 {
158 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl ) )
159 {
160 if( !textCtrl->HasFocus() )
161 {
162 textCtrl->SelectAll();
163 return false;
164 }
165 }
166 }
167
168 return wxPGTextCtrlEditor::OnEvent( aPropGrid, aProperty, aCtrl, aEvent );
169}
170
171
172bool PG_UNIT_EDITOR::GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty,
173 wxWindow* aCtrl ) const
174{
175 if( !m_unitBinder )
176 return false;
177
178 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl );
179 wxCHECK_MSG( textCtrl, false, "PG_UNIT_EDITOR requires a text control!" );
180 wxString textVal = textCtrl->GetValue();
181
182 if( textVal == wxT( "<...>" ) )
183 {
184 aVariant.MakeNull();
185 return true;
186 }
187
188 bool changed;
189
190 if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) != nullptr )
191 {
192 EDA_ANGLE angle = m_unitBinder->GetAngleValue();
193
194 if( aVariant.GetType() == wxT( "EDA_ANGLE" ) )
195 {
196 EDA_ANGLE_VARIANT_DATA* ad = static_cast<EDA_ANGLE_VARIANT_DATA*>( aVariant.GetData() );
197 changed = ( aVariant.IsNull() || angle != ad->Angle() );
198
199 if( changed )
200 {
201 ad->SetAngle( angle );
202 m_unitBinder->SetAngleValue( angle );
203 }
204 }
205 else
206 {
207 changed = ( aVariant.IsNull() || angle.AsDegrees() != aVariant.GetDouble() );
208
209 if( changed )
210 {
211 aVariant = angle.AsDegrees();
212 m_unitBinder->SetValue( angle.AsDegrees() );
213 }
214 }
215 }
216 else if( dynamic_cast<PGPROPERTY_AREA*>( aProperty ) != nullptr )
217 {
218 wxLongLongNative result = m_unitBinder->GetValue();
219 changed = ( aVariant.IsNull() || result != aVariant.GetLongLong() );
220
221 if( changed )
222 {
223 aVariant = result;
224 m_unitBinder->SetDoubleValue( result.ToDouble() );
225 }
226 }
227 else if( aVariant.GetType() == wxT( "std::optional<int>" ) )
228 {
229 auto* variantData = static_cast<STD_OPTIONAL_INT_VARIANT_DATA*>( aVariant.GetData() );
230 std::optional<int> result;
231
232 if( m_unitBinder->IsNull() )
233 {
234 changed = ( aVariant.IsNull() || variantData->Value().has_value() );
235
236 if( changed )
237 {
238 aVariant = wxVariant( std::optional<int>() );
239 m_unitBinder->SetValue( wxEmptyString );
240 }
241 }
242 else
243 {
244 result = std::optional<int>( m_unitBinder->GetValue() );
245 changed = ( aVariant.IsNull() || result != variantData->Value() );
246
247 if( changed )
248 {
249 aVariant = wxVariant( result );
250 m_unitBinder->SetValue( result.value() );
251 }
252 }
253 }
254 else
255 {
256 long result = m_unitBinder->GetValue();
257 changed = ( aVariant.IsNull() || result != aVariant.GetLong() );
258
259 if( changed )
260 {
261 aVariant = result;
262 m_unitBinder->SetValue( result );
263 }
264 }
265
266 // Changing unspecified always causes event (returning
267 // true here should be enough to trigger it).
268 if( !changed && aVariant.IsNull() )
269 changed = true;
270
271 return changed;
272}
273
274
276 wxPGCheckBoxEditor()
277{
278}
279
280
281wxPGWindowList PG_CHECKBOX_EDITOR::CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
282 const wxPoint& aPos, const wxSize& aSize ) const
283{
284 // Override wx behavior and toggle unspecified checkboxes to "true"
285 // CreateControls for a checkbox editor is only triggered when the user activates the checkbox
286 // Set the value to false here; the base class will then trigger an event setting it true.
287 if( aProperty->IsValueUnspecified() )
288 aProperty->SetValueFromInt( 0 );
289
290 return wxPGCheckBoxEditor::CreateControls( aGrid, aProperty, aPos, aSize );
291}
292
293
294bool PG_COLOR_EDITOR::OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aWindow,
295 wxEvent& aEvent ) const
296{
297 return false;
298}
299
300
301wxPGWindowList PG_COLOR_EDITOR::CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
302 const wxPoint& aPos, const wxSize& aSize ) const
303{
304 auto colorProp = dynamic_cast<PGPROPERTY_COLOR4D*>( aProperty );
305
306 if( !colorProp )
307 return nullptr;
308
310 KIGFX::COLOR4D defColor = colorFromVariant( colorProp->GetDefaultValue() );
311
312 COLOR_SWATCH* editor = new COLOR_SWATCH( aGrid->GetPanel(), color, wxID_ANY,
313 colorProp->GetBackgroundColor(), defColor,
314 SWATCH_LARGE, true );
315 editor->SetPosition( aPos );
316 editor->SetSize( aSize );
317
318 editor->Bind( COLOR_SWATCH_CHANGED,
319 [=]( wxCommandEvent& aEvt )
320 {
321 wxVariant val;
322 auto data = new COLOR4D_VARIANT_DATA( editor->GetSwatchColor() );
323 val.SetData( data );
324 aGrid->ChangePropertyValue( colorProp, val );
325 } );
326
327#if wxCHECK_VERSION( 3, 3, 0 )
328 if( aGrid->GetInternalFlags() & wxPropertyGrid::wxPG_FL_ACTIVATION_BY_CLICK )
329#else
330 if( aGrid->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK )
331#endif
332 {
333 aGrid->CallAfter(
334 [=]()
335 {
336 editor->GetNewSwatchColor();
337 } );
338 }
339
340 return editor;
341}
342
343
344void PG_COLOR_EDITOR::UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const
345{
346 if( auto swatch = dynamic_cast<COLOR_SWATCH*>( aCtrl ) )
347 swatch->SetSwatchColor( colorFromProperty( aProperty ), false );
348}
349
350
351KIGFX::COLOR4D PG_COLOR_EDITOR::colorFromVariant( const wxVariant& aVariant ) const
352{
354 COLOR4D_VARIANT_DATA* data = nullptr;
355
356 if( aVariant.IsType( wxS( "COLOR4D" ) ) )
357 {
358 data = static_cast<COLOR4D_VARIANT_DATA*>( aVariant.GetData() );
359 color = data->Color();
360 }
361
362 return color;
363}
364
365
367{
368 return colorFromVariant( aProperty->GetValue() );
369}
370
371
372bool PG_RATIO_EDITOR::GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty,
373 wxWindow* aCtrl ) const
374{
375 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl );
376 wxCHECK_MSG( textCtrl, false, "PG_RATIO_EDITOR requires a text control!" );
377 wxString textVal = textCtrl->GetValue();
378
379 if( textVal == wxT( "<...>" ) )
380 {
381 aVariant.MakeNull();
382 return true;
383 }
384
385 bool changed;
386
387 if( aVariant.GetType() == wxT( "std::optional<double>" ) )
388 {
389 auto* variantData = static_cast<STD_OPTIONAL_DOUBLE_VARIANT_DATA*>( aVariant.GetData() );
390
391 if( textVal.empty() )
392 {
393 changed = ( aVariant.IsNull() || variantData->Value().has_value() );
394
395 if( changed )
396 aVariant = wxVariant( std::optional<double>() );
397 }
398 else
399 {
400 double dblValue;
401 textVal.ToDouble( &dblValue );
402 std::optional<double> result( dblValue );
403 changed = ( aVariant.IsNull() || result != variantData->Value() );
404
405 if( changed )
406 {
407 aVariant = wxVariant( result );
408 textCtrl->SetValue( wxString::Format( wxS( "%g" ), dblValue ) );
409 }
410 }
411 }
412 else
413 {
414 double result;
415 textVal.ToDouble( &result );
416 changed = ( aVariant.IsNull() || result != aVariant.GetDouble() );
417
418 if( changed )
419 {
420 aVariant = result;
421 textCtrl->SetValue( wxString::Format( wxS( "%g" ), result ) );
422 }
423 }
424
425 // Changing unspecified always causes event (returning
426 // true here should be enough to trigger it).
427 if( !changed && aVariant.IsNull() )
428 changed = true;
429
430 return changed;
431}
432
433
434void PG_RATIO_EDITOR::UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const
435{
436 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl );
437 wxVariant var = aProperty->GetValue();
438
439 wxCHECK_MSG( textCtrl, /*void*/, wxT( "PG_RATIO_EDITOR must be used with a textCtrl!" ) );
440
441 if( var.GetType() == wxT( "std::optional<double>" ) )
442 {
443 auto* variantData = static_cast<STD_OPTIONAL_DOUBLE_VARIANT_DATA*>( var.GetData() );
444 wxString strValue;
445
446 if( variantData->Value().has_value() )
447 strValue = wxString::Format( wxS( "%g" ), variantData->Value().value() );
448
449 textCtrl->ChangeValue( strValue );
450 }
451 else if( var.GetType() == wxPG_VARIANT_TYPE_DOUBLE )
452 {
453 textCtrl->ChangeValue( wxString::Format( wxS( "%g" ), var.GetDouble() ) );
454 }
455 else if( !aProperty->IsValueUnspecified() )
456 {
457 wxFAIL_MSG( wxT( "PG_RATIO_EDITOR should only be used with scale-free numeric "
458 "properties!" ) );
459 }
460}
int color
Definition: DXF_plotter.cpp:63
const KIGFX::COLOR4D & Color()
A simple color swatch of the kind used to set layer colors.
Definition: color_swatch.h:57
const EDA_ANGLE & Angle()
void SetAngle(const EDA_ANGLE &aAngle)
double AsDegrees() const
Definition: eda_angle.h:116
The base class for create windows for drawing purpose.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:398
A wxEnumProperty that displays a color next to the enum value.
wxPGWindowList CreateControls(wxPropertyGrid *aGrid, wxPGProperty *aProperty, const wxPoint &aPos, const wxSize &aSize) const override
Definition: pg_editors.cpp:281
static const wxString EDITOR_NAME
Definition: pg_editors.h:75
static const wxString EDITOR_NAME
Definition: pg_editors.h:91
wxPGWindowList CreateControls(wxPropertyGrid *aGrid, wxPGProperty *aProperty, const wxPoint &aPos, const wxSize &aSize) const override
Definition: pg_editors.cpp:301
bool OnEvent(wxPropertyGrid *aGrid, wxPGProperty *aProperty, wxWindow *aWindow, wxEvent &aEvent) const override
Definition: pg_editors.cpp:294
KIGFX::COLOR4D colorFromVariant(const wxVariant &aVariant) const
Definition: pg_editors.cpp:351
void UpdateControl(wxPGProperty *aProperty, wxWindow *aCtrl) const override
Definition: pg_editors.cpp:344
KIGFX::COLOR4D colorFromProperty(wxPGProperty *aProperty) const
Definition: pg_editors.cpp:366
bool GetValueFromControl(wxVariant &aVariant, wxPGProperty *aProperty, wxWindow *aCtrl) const override
Definition: pg_editors.cpp:372
static const wxString EDITOR_NAME
Definition: pg_editors.h:117
void UpdateControl(wxPGProperty *aProperty, wxWindow *aCtrl) const override
Definition: pg_editors.cpp:434
std::unique_ptr< PROPERTY_EDITOR_UNIT_BINDER > m_unitBinder
Definition: pg_editors.h:66
wxPGWindowList CreateControls(wxPropertyGrid *aPropGrid, wxPGProperty *aProperty, const wxPoint &aPos, const wxSize &aSize) const override
Definition: pg_editors.cpp:74
static const wxString EDITOR_NAME
Definition: pg_editors.h:34
void UpdateControl(wxPGProperty *aProperty, wxWindow *aCtrl) const override
Definition: pg_editors.cpp:116
void UpdateFrame(EDA_DRAW_FRAME *aFrame)
When restarting an editor, the instance of PG_UNIT_EDITOR may be the same but the referenced frame is...
Definition: pg_editors.cpp:58
EDA_DRAW_FRAME * m_frame
Definition: pg_editors.h:64
PG_UNIT_EDITOR(EDA_DRAW_FRAME *aFrame)
Definition: pg_editors.cpp:36
bool GetValueFromControl(wxVariant &aVariant, wxPGProperty *aProperty, wxWindow *aCtrl) const override
Definition: pg_editors.cpp:172
wxString m_editorName
Definition: pg_editors.h:68
bool OnEvent(wxPropertyGrid *aPropGrid, wxPGProperty *aProperty, wxWindow *aCtrl, wxEvent &aEvent) const override
Definition: pg_editors.cpp:153
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
Definition: pg_editors.cpp:52
virtual ~PG_UNIT_EDITOR()
Definition: pg_editors.cpp:47
EDA_UNITS GetUserUnits() const
@ SWATCH_LARGE
Definition: color_swatch.h:42
static std::string strValue(double aValue)