KiCad PCB EDA Suite
Loading...
Searching...
No Matches
property_value_converter.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
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <properties/property.h>
27#include <geometry/eda_angle.h>
28#include <gal/color4d.h>
29#include <math/vector2d.h>
30#include <math/box2.h>
31#include <kiid.h>
32#include <layer_ids.h>
33
34#include <wx/string.h>
35
36#include <optional>
37
38
39namespace KICAD_DIFF
40{
41
42namespace
43{
44
49template <typename T, typename F>
50std::optional<DIFF_VALUE> tryAs( const wxAny& aValue, F&& aMaker )
51{
52 if( aValue.CheckType<T>() )
53 return aMaker( aValue.As<T>() );
54
55 return std::nullopt;
56}
57
58
65DISPLAY_HINT displayHintFor( const PROPERTY_BASE* aProperty )
66{
67 if( !aProperty )
68 return DISPLAY_HINT::NONE;
69
70 switch( aProperty->Display() )
71 {
73 case PT_COORD: return DISPLAY_HINT::COORD;
74 case PT_DEGREE: return DISPLAY_HINT::ANGLE;
75 default: return DISPLAY_HINT::NONE;
76 }
77}
78
79
82DIFF_VALUE withHint( DIFF_VALUE aValue, DISPLAY_HINT aHint )
83{
84 if( aHint == DISPLAY_HINT::NONE )
85 return aValue;
86
87 return aValue.WithDisplayHint( aHint );
88}
89
90} // namespace
91
92
93DIFF_VALUE WxAnyToDiffValue( const wxAny& aValue, PROPERTY_BASE* aProperty )
94{
95 // The order matters: more specific types first (so that std::optional<int>
96 // is not mis-matched against int).
97
98 // Distance / coordinate / angle hint, derived once from the property so the
99 // numeric branches below render in user units instead of raw IU.
100 const DISPLAY_HINT hint = displayHintFor( aProperty );
101
102 if( auto v = tryAs<bool>( aValue, []( bool x ) { return DIFF_VALUE::FromBool( x ); } ) )
103 return *v;
104
105 // std::optional<int> and std::optional<double> are used heavily for soldermask
106 // margins, drill diameters with fallback, etc.
107 if( aValue.CheckType<std::optional<int>>() )
108 {
109 std::optional<int> opt = aValue.As<std::optional<int>>();
110
111 if( !opt.has_value() )
112 return DIFF_VALUE(); // T::NONE — distinguishes "unset" from "0"
113
114 return withHint( DIFF_VALUE::FromInt( *opt ), hint );
115 }
116
117 if( aValue.CheckType<std::optional<double>>() )
118 {
119 std::optional<double> opt = aValue.As<std::optional<double>>();
120
121 if( !opt.has_value() )
122 return DIFF_VALUE();
123
124 return withHint( DIFF_VALUE::FromDouble( *opt ), hint );
125 }
126
127 if( auto v = tryAs<int>( aValue, [&]( int x )
128 { return withHint( DIFF_VALUE::FromInt( x ), hint ); } ) )
129 return *v;
130
131 if( auto v = tryAs<long>( aValue, [&]( long x )
132 { return withHint( DIFF_VALUE::FromInt64( x ), hint ); } ) )
133 return *v;
134
135 if( auto v = tryAs<long long>( aValue, [&]( long long x )
136 { return withHint( DIFF_VALUE::FromInt64( x ), hint ); } ) )
137 return *v;
138
139 if( auto v = tryAs<unsigned>( aValue, [&]( unsigned x )
140 { return withHint( DIFF_VALUE::FromInt64( x ), hint ); } ) )
141 return *v;
142
143 if( auto v = tryAs<double>( aValue, [&]( double x )
144 { return withHint( DIFF_VALUE::FromDouble( x ), hint ); } ) )
145 return *v;
146
147 if( aValue.CheckType<float>() )
148 return withHint( DIFF_VALUE::FromDouble( aValue.As<float>() ), hint );
149
150 if( auto v = tryAs<wxString>( aValue, []( const wxString& x )
151 { return DIFF_VALUE::FromString( x ); } ) )
152 return *v;
153
154 if( auto v = tryAs<std::string>( aValue, []( const std::string& x )
155 { return DIFF_VALUE::FromString( x ); } ) )
156 return *v;
157
158 if( auto v = tryAs<KIID>( aValue, []( const KIID& x )
159 { return DIFF_VALUE::FromKiid( x ); } ) )
160 return *v;
161
162 if( auto v = tryAs<EDA_ANGLE>( aValue, []( const EDA_ANGLE& x )
163 { return DIFF_VALUE::FromDouble( x.AsDegrees() )
165 return *v;
166
167 if( auto v = tryAs<VECTOR2I>( aValue, [&]( const VECTOR2I& x )
168 { return withHint( DIFF_VALUE::FromVector2I( x ), hint ); } ) )
169 return *v;
170
171 if( auto v = tryAs<BOX2I>( aValue, []( const BOX2I& x )
172 { return DIFF_VALUE::FromBox2I( x ); } ) )
173 return *v;
174
175 if( auto v = tryAs<KIGFX::COLOR4D>( aValue, []( const KIGFX::COLOR4D& x )
176 { return DIFF_VALUE::FromColor( x ); } ) )
177 return *v;
178
179 if( auto v = tryAs<PCB_LAYER_ID>( aValue, []( PCB_LAYER_ID x )
180 { return DIFF_VALUE::FromLayer( x ); } ) )
181 return *v;
182
183 // Enum-backed properties: PROPERTY_ENUM<Owner, T> stores the enum type T
184 // in the wxAny, so CheckType<int>() is false. wxAny::GetAs<int>() asks
185 // the wxAnyValueType for a conversion; for enums whose value type
186 // registers int compatibility this succeeds. When it does, we pair the
187 // integer with the choice label so JSON output is readable.
188 if( aProperty && aProperty->HasChoices() )
189 {
190 int enumInt = 0;
191
192 if( aValue.GetAs<int>( &enumInt ) )
193 {
194 const wxPGChoices& choices = aProperty->Choices();
195 std::string label;
196
197 for( unsigned ii = 0; ii < choices.GetCount(); ++ii )
198 {
199 if( choices.GetValue( ii ) == enumInt )
200 {
201 label = std::string( choices.GetLabel( ii ).ToUTF8() );
202 break;
203 }
204 }
205
206 return DIFF_VALUE::FromEnum( enumInt, label );
207 }
208
209 // Fallback: print the value as a label string. Most wxAnyValueType
210 // implementations register a wxString conversion for display.
211 wxString s;
212
213 if( aValue.GetAs<wxString>( &s ) )
214 return DIFF_VALUE::FromEnum( 0, std::string( s.ToUTF8() ) );
215 }
216
217 // Unknown type: produce NONE rather than throwing. The caller decides how
218 // to handle an unsupported property (typically by skipping it).
219 return DIFF_VALUE();
220}
221
222
223bool DiffValueToWxAny( const DIFF_VALUE& aValue, wxAny& aOut )
224{
225 switch( aValue.GetType() )
226 {
227 case DIFF_VALUE::T::NONE: return false;
228 case DIFF_VALUE::T::BOOL: aOut = aValue.AsBool(); break;
229 case DIFF_VALUE::T::INT: aOut = aValue.AsInt(); break;
230 case DIFF_VALUE::T::INT64: aOut = aValue.AsInt64(); break;
231 case DIFF_VALUE::T::DOUBLE: aOut = aValue.AsDouble(); break;
232 case DIFF_VALUE::T::STRING: aOut = aValue.AsString(); break;
233 case DIFF_VALUE::T::KIID: aOut = aValue.AsKiid(); break;
234 case DIFF_VALUE::T::VECTOR2I: aOut = aValue.AsVector2I(); break;
235 case DIFF_VALUE::T::BOX2I: aOut = aValue.AsBox2I(); break;
236 case DIFF_VALUE::T::COLOR: aOut = aValue.AsColor(); break;
237 case DIFF_VALUE::T::LAYER: aOut = aValue.AsLayer(); break;
238 case DIFF_VALUE::T::ENUM: aOut = aValue.AsEnum().first; break;
239 case DIFF_VALUE::T::POLYGON_SET: return false;
240 }
241
242 return true;
243}
244
245} // namespace KICAD_DIFF
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
A typed sum value used to carry the before/after of any single property.
static DIFF_VALUE FromLayer(PCB_LAYER_ID aLayer)
static DIFF_VALUE FromDouble(double aValue)
static DIFF_VALUE FromEnum(int aValue, const std::string &aLabel)
KIGFX::COLOR4D AsColor() const
DIFF_VALUE WithDisplayHint(DISPLAY_HINT aHint) const
Tag this value with a display hint and return a copy, so call sites can chain DIFF_VALUE::FromInt( w ...
static DIFF_VALUE FromInt64(int64_t aValue)
static DIFF_VALUE FromInt(int aValue)
static DIFF_VALUE FromBox2I(const BOX2I &aValue)
static DIFF_VALUE FromKiid(const KIID &aValue)
static DIFF_VALUE FromColor(const KIGFX::COLOR4D &aValue)
static DIFF_VALUE FromBool(bool aValue)
static DIFF_VALUE FromString(const wxString &aValue)
PCB_LAYER_ID AsLayer() const
static DIFF_VALUE FromVector2I(const VECTOR2I &aValue)
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
Definition kiid.h:44
PROPERTY_DISPLAY Display() const
Definition property.h:308
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
Definition property.h:246
virtual const wxPGChoices & Choices() const
Return a limited set of possible values (e.g.
Definition property.h:226
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
#define F(x, y, z)
Definition md5_hash.cpp:15
bool DiffValueToWxAny(const DIFF_VALUE &aValue, wxAny &aOut)
Convert a DIFF_VALUE back into a wxAny a PROPERTY_BASE setter can consume.
DISPLAY_HINT
How a numeric DIFF_VALUE should be interpreted when rendered for humans.
@ COORD
Coordinate in internal units (PT_COORD)
@ DISTANCE
Length in internal units (PT_SIZE)
@ ANGLE
Angle in degrees (PT_DEGREE)
DIFF_VALUE WxAnyToDiffValue(const wxAny &aValue, PROPERTY_BASE *aProperty)
Convert a wxAny value read from a PROPERTY_BASE getter into a DIFF_VALUE that the engine can store,...
@ PT_DEGREE
Angle expressed in degrees.
Definition property.h:66
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683