1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4
5 #include "uiattributes.h"
6 #include "cstream.h"
7 #include "../lib/cpoint.h"
8 #include "../lib/crect.h"
9 #include "../lib/cstring.h"
10 #include <sstream>
11 #include <algorithm>
12
13 namespace VSTGUI {
14 namespace {
15
16 //------------------------------------------------------------------------
17 template<bool OnlyInteger>
trimmedNumericalString(const std::string & str,size_t from,size_t numChars)18 Optional<std::string> trimmedNumericalString (const std::string& str, size_t from, size_t numChars)
19 {
20 std::string result;
21 auto strSize = str.size ();
22 if (from >= strSize)
23 return {};
24 auto points = 0u;
25 auto to = numChars == std::string::npos ? strSize : from + numChars;
26 for (auto i = from; i < to && i < strSize; ++i)
27 {
28 auto c = str[i];
29 if (!std::isspace (c))
30 {
31 if (!std::isdigit (c) && c != '-' && c != '+')
32 {
33 if (!OnlyInteger && c == '.' && points == 0u)
34 ++points;
35 else if (points == 1u && c == 'e')
36 {
37 }
38 else
39 return {};
40 }
41 result.push_back (c);
42 }
43 }
44 return Optional<std::string> {std::move (result)};
45 }
46
47 } // anonymous
48
49 //-----------------------------------------------------------------------------
pointToString(CPoint p)50 std::string UIAttributes::pointToString (CPoint p)
51 {
52 return doubleToString (p.x) + ", " + doubleToString (p.y);
53 }
54
55 //-----------------------------------------------------------------------------
stringToPoint(const std::string & str,CPoint & p)56 bool UIAttributes::stringToPoint (const std::string& str, CPoint& p)
57 {
58 size_t start = 0;
59 size_t pos = str.find (",", start, 1);
60 if (pos != std::string::npos)
61 {
62 std::vector<std::string> subStrings;
63 while (pos != std::string::npos)
64 {
65 if (!subStrings.empty ())
66 return false;
67 if (auto subStr = trimmedNumericalString<false> (str, start, pos - start))
68 subStrings.emplace_back (std::move (*subStr));
69 else
70 return false;
71 start = pos + 1;
72 pos = str.find (",", start, 1);
73 }
74 if (auto subStr = trimmedNumericalString<false> (str, start, std::string::npos))
75 subStrings.emplace_back (std::move (*subStr));
76 else
77 return false;
78 if (subStrings.size () == 2)
79 {
80 p.x = UTF8StringView (subStrings[0].data ()).toDouble ();
81 p.y = UTF8StringView (subStrings[1].data ()).toDouble ();
82 return true;
83 }
84 }
85 return false;
86 }
87
88 //------------------------------------------------------------------------
doubleToString(double value,uint32_t precision)89 std::string UIAttributes::doubleToString (double value, uint32_t precision)
90 {
91 std::stringstream str;
92 str.imbue (std::locale::classic ());
93 str.precision (precision);
94 str << value;
95 return str.str ();
96 }
97
98 //-----------------------------------------------------------------------------
stringToDouble(const std::string & str,double & value)99 bool UIAttributes::stringToDouble (const std::string& str, double& value)
100 {
101 if (auto string = trimmedNumericalString<false> (str, 0, str.size ()))
102 {
103 std::istringstream sstream (*string);
104 sstream.imbue (std::locale::classic ());
105 sstream >> value;
106 return sstream.fail () == false;
107 }
108 return false;
109 }
110
111 //-----------------------------------------------------------------------------
boolToString(bool value)112 std::string UIAttributes::boolToString (bool value)
113 {
114 return value ? "true" : "false";
115 }
116
117 //-----------------------------------------------------------------------------
stringToBool(const std::string & str,bool & value)118 bool UIAttributes::stringToBool (const std::string& str, bool& value)
119 {
120 if (str == "true")
121 {
122 value = true;
123 return true;
124 }
125 if (str == "false")
126 {
127 value = false;
128 return true;
129 }
130 return false;
131 }
132
133 //-----------------------------------------------------------------------------
integerToString(int32_t value)134 std::string UIAttributes::integerToString (int32_t value)
135 {
136 std::stringstream str;
137 str << value;
138 return str.str ();
139 }
140
141 //-----------------------------------------------------------------------------
stringToInteger(const std::string & str,int32_t & value)142 bool UIAttributes::stringToInteger (const std::string& str, int32_t& value)
143 {
144 if (auto string = trimmedNumericalString<true> (str, 0, str.size ()))
145 {
146 std::istringstream sstream (*string);
147 sstream.imbue (std::locale::classic ());
148 sstream >> value;
149 return sstream.fail () == false;
150 }
151 return false;
152 }
153
154 //-----------------------------------------------------------------------------
rectToString(CRect r,uint32_t precision)155 std::string UIAttributes::rectToString (CRect r, uint32_t precision)
156 {
157 return doubleToString (r.left) + ", " + doubleToString (r.top) + ", " +
158 doubleToString (r.right) + ", " + doubleToString (r.bottom);
159 }
160
161 //-----------------------------------------------------------------------------
stringToRect(const std::string & str,CRect & r)162 bool UIAttributes::stringToRect (const std::string& str, CRect& r)
163 {
164 size_t start = 0;
165 size_t pos = str.find (",", start, 1);
166 if (pos != std::string::npos)
167 {
168 std::vector<std::string> subStrings;
169 while (pos != std::string::npos)
170 {
171 if (subStrings.size () >= 3)
172 return false;
173 if (auto subStr = trimmedNumericalString<false> (str, start, pos - start))
174 subStrings.emplace_back (std::move (*subStr));
175 else
176 return false;
177 start = pos + 1;
178 pos = str.find (",", start, 1);
179 }
180 if (auto subStr = trimmedNumericalString<false> (str, start, std::string::npos))
181 subStrings.emplace_back (std::move (*subStr));
182 else
183 return false;
184 if (subStrings.size () == 4)
185 {
186 r.left = UTF8StringView (subStrings[0].data ()).toDouble ();
187 r.top = UTF8StringView (subStrings[1].data ()).toDouble ();
188 r.right = UTF8StringView (subStrings[2].data ()).toDouble ();
189 r.bottom = UTF8StringView (subStrings[3].data ()).toDouble ();
190 return true;
191 }
192 }
193 return false;
194 }
195
196 //-----------------------------------------------------------------------------
stringArrayToString(const StringArray & values)197 std::string UIAttributes::stringArrayToString (const StringArray& values)
198 {
199 std::string value;
200 size_t numValues = values.size ();
201 for (size_t i = 0; i < numValues - 1; i++)
202 {
203 value += values[i];
204 value += ',';
205 }
206 value += values[numValues-1];
207 return value;
208 }
209
210 //-----------------------------------------------------------------------------
stringToStringArray(const std::string & str,std::vector<std::string> & values)211 bool UIAttributes::stringToStringArray (const std::string& str, std::vector<std::string>& values)
212 {
213 std::stringstream ss (str);
214 std::string item;
215 while (std::getline (ss, item, ','))
216 {
217 values.emplace_back (std::move (item));
218 }
219 return true;
220 }
221
222 //-----------------------------------------------------------------------------
223 //-----------------------------------------------------------------------------
224 //-----------------------------------------------------------------------------
UIAttributes(UTF8StringPtr * attributes)225 UIAttributes::UIAttributes (UTF8StringPtr* attributes)
226 {
227 if (attributes)
228 {
229 int32_t i = 0;
230 while (attributes[i] != nullptr && attributes[i+1] != nullptr)
231 {
232 emplace (attributes[i], attributes[i+1]);
233 i += 2;
234 }
235 }
236 }
237
238 //-----------------------------------------------------------------------------
hasAttribute(const std::string & name) const239 bool UIAttributes::hasAttribute (const std::string& name) const
240 {
241 if (getAttributeValue (name) != nullptr)
242 return true;
243 return false;
244 }
245
246 //-----------------------------------------------------------------------------
getAttributeValue(const std::string & name) const247 const std::string* UIAttributes::getAttributeValue (const std::string& name) const
248 {
249 const_iterator iter = find (name);
250 if (iter != end ())
251 return &iter->second;
252 return nullptr;
253 }
254
255 //-----------------------------------------------------------------------------
setAttribute(const std::string & name,const std::string & value)256 void UIAttributes::setAttribute (const std::string& name, const std::string& value)
257 {
258 iterator iter = find (name);
259 if (iter != end ())
260 iter->second = value;
261 else
262 emplace (name, value);
263 }
264
265 //-----------------------------------------------------------------------------
setAttribute(const std::string & name,std::string && value)266 void UIAttributes::setAttribute (const std::string& name, std::string&& value)
267 {
268 iterator iter = find (name);
269 if (iter != end ())
270 iter->second = std::move (value);
271 else
272 emplace (name, std::move (value));
273 }
274
275 //-----------------------------------------------------------------------------
setAttribute(std::string && name,std::string && value)276 void UIAttributes::setAttribute (std::string&& name, std::string&& value)
277 {
278 iterator iter = find (name);
279 if (iter != end ())
280 iter->second = std::move (value);
281 else
282 emplace (std::move (name), std::move (value));
283 }
284
285 //-----------------------------------------------------------------------------
removeAttribute(const std::string & name)286 void UIAttributes::removeAttribute (const std::string& name)
287 {
288 iterator iter = find (name);
289 if (iter != end ())
290 erase (iter);
291 }
292
293 //-----------------------------------------------------------------------------
setDoubleAttribute(const std::string & name,double value)294 void UIAttributes::setDoubleAttribute (const std::string& name, double value)
295 {
296 setAttribute (name, doubleToString (value, 40));
297 }
298
299 //-----------------------------------------------------------------------------
getDoubleAttribute(const std::string & name,double & value) const300 bool UIAttributes::getDoubleAttribute (const std::string& name, double& value) const
301 {
302 if (auto str = getAttributeValue (name))
303 return stringToDouble (*str, value);
304 return false;
305 }
306
307 //-----------------------------------------------------------------------------
setBooleanAttribute(const std::string & name,bool value)308 void UIAttributes::setBooleanAttribute (const std::string& name, bool value)
309 {
310 setAttribute (name, boolToString (value));
311 }
312
313 //-----------------------------------------------------------------------------
getBooleanAttribute(const std::string & name,bool & value) const314 bool UIAttributes::getBooleanAttribute (const std::string& name, bool& value) const
315 {
316 if (auto str = getAttributeValue (name))
317 return stringToBool (*str, value);
318 return false;
319 }
320
321 //-----------------------------------------------------------------------------
setIntegerAttribute(const std::string & name,int32_t value)322 void UIAttributes::setIntegerAttribute (const std::string& name, int32_t value)
323 {
324 setAttribute (name, integerToString (value));
325 }
326
327 //-----------------------------------------------------------------------------
getIntegerAttribute(const std::string & name,int32_t & value) const328 bool UIAttributes::getIntegerAttribute (const std::string& name, int32_t& value) const
329 {
330 if (auto str = getAttributeValue (name))
331 return stringToInteger(*str, value);
332 return false;
333 }
334
335 //-----------------------------------------------------------------------------
setPointAttribute(const std::string & name,const CPoint & p)336 void UIAttributes::setPointAttribute (const std::string& name, const CPoint& p)
337 {
338 setAttribute (name, pointToString (p));
339 }
340
341 //-----------------------------------------------------------------------------
getPointAttribute(const std::string & name,CPoint & p) const342 bool UIAttributes::getPointAttribute (const std::string& name, CPoint& p) const
343 {
344 if (auto str = getAttributeValue (name))
345 return stringToPoint (*str, p);
346 return false;
347 }
348
349 //-----------------------------------------------------------------------------
setRectAttribute(const std::string & name,const CRect & r)350 void UIAttributes::setRectAttribute (const std::string& name, const CRect& r)
351 {
352 setAttribute (name, rectToString (r));
353 }
354
355 //-----------------------------------------------------------------------------
getRectAttribute(const std::string & name,CRect & r) const356 bool UIAttributes::getRectAttribute (const std::string& name, CRect& r) const
357 {
358 if (auto str = getAttributeValue (name))
359 return stringToRect (*str, r);
360 return false;
361 }
362
363 //-----------------------------------------------------------------------------
setStringArrayAttribute(const std::string & name,const StringArray & values)364 void UIAttributes::setStringArrayAttribute (const std::string& name, const StringArray& values)
365 {
366 setAttribute (name, stringArrayToString (values));
367 }
368
369 //-----------------------------------------------------------------------------
getStringArrayAttribute(const std::string & name,StringArray & values) const370 bool UIAttributes::getStringArrayAttribute (const std::string& name, StringArray& values) const
371 {
372 if (auto str = getAttributeValue (name))
373 return stringToStringArray(*str, values);
374 return false;
375 }
376
377 //-----------------------------------------------------------------------------
store(OutputStream & stream) const378 bool UIAttributes::store (OutputStream& stream) const
379 {
380 if (!(stream << (int32_t)'UIAT')) return false;
381 if (!(stream << (uint32_t)size ())) return false;
382 const_iterator it = begin ();
383 while (it != end ())
384 {
385 if (!(stream << (*it).first)) return false;
386 if (!(stream << (*it).second)) return false;
387 ++it;
388 }
389 return true;
390 }
391
392 //-----------------------------------------------------------------------------
restore(InputStream & stream)393 bool UIAttributes::restore (InputStream& stream)
394 {
395 int32_t identifier;
396 if (!(stream >> identifier)) return false;
397 if (identifier == 'UIAT')
398 {
399 uint32_t numAttr;
400 if (!(stream >> numAttr)) return false;
401 for (uint32_t i = 0; i < numAttr; i++)
402 {
403 std::string key, value;
404 if (!(stream >> key)) return false;
405 if (!(stream >> value)) return false;
406 setAttribute (std::move (key), std::move (value));
407 }
408 return true;
409 }
410 return false;
411 }
412
413 }
414