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 "uidescription.h"
6 #include "uidescriptionlistener.h"
7 #include "uiattributes.h"
8 #include "uiviewfactory.h"
9 #include "uiviewcreator.h"
10 #include "cstream.h"
11 #include "base64codec.h"
12 #include "icontroller.h"
13 #include "../lib/cfont.h"
14 #include "../lib/cstring.h"
15 #include "../lib/cframe.h"
16 #include "../lib/cdrawcontext.h"
17 #include "../lib/cgradient.h"
18 #include "../lib/cgraphicspath.h"
19 #include "../lib/cbitmap.h"
20 #include "../lib/cbitmapfilter.h"
21 #include "../lib/dispatchlist.h"
22 #include "../lib/platform/std_unorderedmap.h"
23 #include "../lib/platform/iplatformbitmap.h"
24 #include "../lib/platform/iplatformfont.h"
25 #include "detail/uiviewcreatorattributes.h"
26 #include <sstream>
27 #include <fstream>
28 #include <algorithm>
29 #include <cassert>
30 #include <deque>
31
32 namespace VSTGUI {
33
34 //-----------------------------------------------------------------------------
35 /// @cond ignore
36 //-----------------------------------------------------------------------------
37 template <class T> class ScopePointer
38 {
39 public:
ScopePointer(T ** pointer,T * obj)40 ScopePointer (T** pointer, T* obj) : pointer (pointer), oldObject (nullptr)
41 {
42 if (pointer)
43 {
44 oldObject = *pointer;
45 *pointer = obj;
46 }
47 }
~ScopePointer()48 ~ScopePointer () noexcept
49 {
50 if (pointer)
51 *pointer = oldObject;
52 }
53 protected:
54 T** pointer;
55 T* oldObject;
56 };
57
58 namespace MainNodeNames {
59 static const IdStringPtr kBitmap = "bitmaps";
60 static const IdStringPtr kFont = "fonts";
61 static const IdStringPtr kColor = "colors";
62 static const IdStringPtr kControlTag = "control-tags";
63 static const IdStringPtr kVariable = "variables";
64 static const IdStringPtr kTemplate = "template";
65 static const IdStringPtr kCustom = "custom";
66 static const IdStringPtr kGradient = "gradients";
67 }
68
69 class UINode;
70
71 using UIDescListContainerType = std::vector<UINode*>;
72 //-----------------------------------------------------------------------------
73 class UIDescList : public NonAtomicReferenceCounted, private UIDescListContainerType
74 {
75 public:
76 using UIDescListContainerType::begin;
77 using UIDescListContainerType::end;
78 using UIDescListContainerType::rbegin;
79 using UIDescListContainerType::rend;
80 using UIDescListContainerType::iterator;
81 using UIDescListContainerType::const_iterator;
82 using UIDescListContainerType::const_reverse_iterator;
83 using UIDescListContainerType::empty;
84 using UIDescListContainerType::size;
85
86 explicit UIDescList (bool ownsObjects = true);
87 UIDescList (const UIDescList& uiDesc);
88 ~UIDescList () noexcept override;
89
90 virtual void add (UINode* obj);
91 virtual void remove (UINode* obj);
92 virtual void removeAll ();
93 virtual UINode* findChildNode (UTF8StringView nodeName) const;
94 virtual UINode* findChildNodeWithAttributeValue (const std::string& attributeName, const std::string& attributeValue) const;
95
nodeAttributeChanged(UINode * child,const std::string & attributeName,const std::string & oldAttributeValue)96 virtual void nodeAttributeChanged (UINode* child, const std::string& attributeName, const std::string& oldAttributeValue) {}
97
98 void sort ();
99
100 protected:
101 bool ownsObjects;
102 };
103
104 //-----------------------------------------------------------------------------
105 class UINode : public NonAtomicReferenceCounted
106 {
107 public:
108 using DataStorage = std::string;
109
110 UINode (const std::string& name, const SharedPointer<UIAttributes>& attributes = {}, bool needsFastChildNameAttributeLookup = false);
111 UINode (const std::string& name, const SharedPointer<UIDescList>& children, const SharedPointer<UIAttributes>& attributes = {});
112 UINode (const UINode& n);
113 ~UINode () noexcept override;
114
getName() const115 const std::string& getName () const { return name; }
getData()116 DataStorage& getData () { return data; }
getData() const117 const DataStorage& getData () const { return data; }
118
getAttributes() const119 const SharedPointer<UIAttributes>& getAttributes () const { return attributes; }
getChildren() const120 UIDescList& getChildren () const { return *children; }
121 bool hasChildren () const;
122 void childAttributeChanged (UINode* child, const char* attributeName, const char* oldAttributeValue);
123
124 enum {
125 kNoExport = 1 << 0
126 };
127
noExport() const128 bool noExport () const { return hasBit (flags, kNoExport); }
noExport(bool state)129 void noExport (bool state) { setBit (flags, kNoExport, state); }
130
operator ==(const UINode & n) const131 bool operator== (const UINode& n) const { return name == n.name; }
132
133 void sortChildren ();
freePlatformResources()134 virtual void freePlatformResources () {}
135
136 protected:
137 std::string name;
138 DataStorage data;
139 SharedPointer<UIAttributes> attributes;
140 SharedPointer<UIDescList> children;
141 int32_t flags;
142 };
143
144 //-----------------------------------------------------------------------------
145 class UICommentNode : public UINode
146 {
147 public:
148 explicit UICommentNode (const std::string& comment);
149 };
150
151 //-----------------------------------------------------------------------------
152 class UIVariableNode : public UINode
153 {
154 public:
155 UIVariableNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
156
157 enum Type {
158 kNumber,
159 kString,
160 kUnknown
161 };
162
163 Type getType () const;
164 double getNumber () const;
165 const std::string& getString () const;
166
167 protected:
168 Type type;
169 double number;
170 };
171
172 //-----------------------------------------------------------------------------
173 class UIControlTagNode : public UINode
174 {
175 public:
176 UIControlTagNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
177 int32_t getTag ();
178 void setTag (int32_t newTag);
179
180 const std::string* getTagString () const;
181 void setTagString (const std::string& str);
182
183 protected:
184 int32_t tag;
185 };
186
187 //-----------------------------------------------------------------------------
188 class UIBitmapNode : public UINode
189 {
190 public:
191 UIBitmapNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
192 CBitmap* getBitmap (const std::string& pathHint);
193 void setBitmap (UTF8StringPtr bitmapName);
194 void setNinePartTiledOffset (const CRect* offsets);
195 void invalidBitmap ();
getFilterProcessed() const196 bool getFilterProcessed () const { return filterProcessed; }
setFilterProcessed()197 void setFilterProcessed () { filterProcessed = true; }
getScaledBitmapsAdded() const198 bool getScaledBitmapsAdded () const { return scaledBitmapsAdded; }
setScaledBitmapsAdded()199 void setScaledBitmapsAdded () { scaledBitmapsAdded = true; }
200
201 void createXMLData (const std::string& pathHint);
202 void removeXMLData ();
203
204 void freePlatformResources () override;
205 protected:
206 ~UIBitmapNode () noexcept override;
207 CBitmap* createBitmap (const std::string& str, CNinePartTiledDescription* partDesc) const;
208 SharedPointer<IPlatformBitmap> createBitmapFromDataNode () const;
209 static bool imagesEqual (IPlatformBitmap* b1, IPlatformBitmap* b2);
210 UINode* dataNode () const;
211 CBitmap* bitmap;
212 bool filterProcessed;
213 bool scaledBitmapsAdded;
214 };
215
216 //-----------------------------------------------------------------------------
217 class UIFontNode : public UINode
218 {
219 public:
220 UIFontNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
221 CFontRef getFont ();
222 void setFont (CFontRef newFont);
223 void setAlternativeFontNames (UTF8StringPtr fontNames);
224 bool getAlternativeFontNames (std::string& fontNames);
225
226 void freePlatformResources () override;
227 protected:
228 ~UIFontNode () noexcept override;
229 CFontRef font;
230 };
231
232 //-----------------------------------------------------------------------------
233 class UIColorNode : public UINode
234 {
235 public:
236 UIColorNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
getColor() const237 const CColor& getColor () const { return color; }
238 void setColor (const CColor& newColor);
239 protected:
240 CColor color;
241 };
242
243 //-----------------------------------------------------------------------------
244 class UIGradientNode : public UINode
245 {
246 public:
247 UIGradientNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
248 CGradient* getGradient ();
249 void setGradient (CGradient* g);
250
251 void freePlatformResources () override;
252 protected:
253 SharedPointer<CGradient> gradient;
254
255 };
256
257 //-----------------------------------------------------------------------------
258 class UIDescListWithFastFindAttributeNameChild : public UIDescList
259 {
260 private:
261 using ChildMap = std::unordered_map<std::string, UINode*>;
262 public:
UIDescListWithFastFindAttributeNameChild()263 UIDescListWithFastFindAttributeNameChild () {}
264
add(UINode * obj)265 void add (UINode* obj) override
266 {
267 UIDescList::add (obj);
268 const std::string* nameAttributeValue = obj->getAttributes ()->getAttributeValue ("name");
269 if (nameAttributeValue)
270 childMap.emplace (*nameAttributeValue, obj);
271 }
272
remove(UINode * obj)273 void remove (UINode* obj) override
274 {
275 const std::string* nameAttributeValue = obj->getAttributes ()->getAttributeValue ("name");
276 if (nameAttributeValue)
277 {
278 ChildMap::iterator it = childMap.find (*nameAttributeValue);
279 if (it != childMap.end ())
280 childMap.erase (it);
281 }
282 UIDescList::remove (obj);
283 }
284
removeAll()285 void removeAll () override
286 {
287 childMap.clear ();
288 UIDescList::removeAll ();
289 }
290
findChildNodeWithAttributeValue(const std::string & attributeName,const std::string & attributeValue) const291 UINode* findChildNodeWithAttributeValue (const std::string& attributeName, const std::string& attributeValue) const override
292 {
293 if (attributeName != "name")
294 return UIDescList::findChildNodeWithAttributeValue (attributeName, attributeValue);
295 ChildMap::const_iterator it = childMap.find (attributeValue);
296 if (it != childMap.end ())
297 return it->second;
298 return nullptr;
299 }
300
nodeAttributeChanged(UINode * node,const std::string & attributeName,const std::string & oldAttributeValue)301 void nodeAttributeChanged (UINode* node, const std::string& attributeName, const std::string& oldAttributeValue) override
302 {
303 if (attributeName != "name")
304 return;
305 ChildMap::iterator it = childMap.find (oldAttributeValue);
306 if (it != childMap.end ())
307 childMap.erase (it);
308 const std::string* nameAttributeValue = node->getAttributes ()->getAttributeValue ("name");
309 if (nameAttributeValue)
310 childMap.emplace (*nameAttributeValue, node);
311 }
312 private:
313 ChildMap childMap;
314 };
315
316
317 //-----------------------------------------------------------------------------
UIDescList(bool ownsObjects)318 UIDescList::UIDescList (bool ownsObjects)
319 : ownsObjects (ownsObjects)
320 {
321 }
322
323 //------------------------------------------------------------------------
UIDescList(const UIDescList & uiDesc)324 UIDescList::UIDescList (const UIDescList& uiDesc)
325 : ownsObjects (false)
326 {
327 for (auto& child : uiDesc)
328 add (child);
329 }
330
331 //-----------------------------------------------------------------------------
~UIDescList()332 UIDescList::~UIDescList () noexcept
333 {
334 removeAll ();
335 }
336
337 //-----------------------------------------------------------------------------
add(UINode * obj)338 void UIDescList::add (UINode* obj)
339 {
340 if (!ownsObjects)
341 obj->remember ();
342 UIDescListContainerType::emplace_back (obj);
343 }
344
345 //-----------------------------------------------------------------------------
remove(UINode * obj)346 void UIDescList::remove (UINode* obj)
347 {
348 UIDescListContainerType::iterator pos = std::find (UIDescListContainerType::begin (), UIDescListContainerType::end (), obj);
349 if (pos != UIDescListContainerType::end ())
350 {
351 UIDescListContainerType::erase (pos);
352 obj->forget ();
353 }
354 }
355
356 //-----------------------------------------------------------------------------
removeAll()357 void UIDescList::removeAll ()
358 {
359 for (const_reverse_iterator it = rbegin (), end = rend (); it != end; ++it)
360 (*it)->forget ();
361 clear ();
362 }
363
364 //-----------------------------------------------------------------------------
findChildNode(UTF8StringView nodeName) const365 UINode* UIDescList::findChildNode (UTF8StringView nodeName) const
366 {
367 for (const auto& node : *this)
368 {
369 auto& name = node->getName ();
370 if (nodeName == UTF8StringView (name))
371 return node;
372 }
373 return nullptr;
374 }
375
376 //-----------------------------------------------------------------------------
findChildNodeWithAttributeValue(const std::string & attributeName,const std::string & attributeValue) const377 UINode* UIDescList::findChildNodeWithAttributeValue (const std::string& attributeName, const std::string& attributeValue) const
378 {
379 for (const auto& node : *this)
380 {
381 const std::string* attributeValuePtr = node->getAttributes ()->getAttributeValue (attributeName);
382 if (attributeValuePtr && *attributeValuePtr == attributeValue)
383 return node;
384 }
385 return nullptr;
386 }
387
388 //-----------------------------------------------------------------------------
sort()389 void UIDescList::sort ()
390 {
391 std::sort (begin (), end (), [] (const UINode* n1, const UINode* n2) {
392 const std::string* str1 = n1->getAttributes ()->getAttributeValue ("name");
393 const std::string* str2 = n2->getAttributes ()->getAttributeValue ("name");
394 if (str1 && str2)
395 return *str1 < *str2;
396 else if (str1)
397 return true;
398 return false;
399 });
400 }
401
402 //-----------------------------------------------------------------------------
403 class UIDescWriter
404 {
405 public:
406 bool write (OutputStream& stream, UINode* rootNode);
407 protected:
408 static void encodeAttributeString (std::string& str);
409
410 bool writeNode (UINode* node, OutputStream& stream);
411 bool writeComment (UICommentNode* node, OutputStream& stream);
412 bool writeNodeData (UINode::DataStorage& str, OutputStream& stream);
413 bool writeAttributes (UIAttributes* attr, OutputStream& stream);
414 int32_t intendLevel;
415 };
416
417 //-----------------------------------------------------------------------------
write(OutputStream & stream,UINode * rootNode)418 bool UIDescWriter::write (OutputStream& stream, UINode* rootNode)
419 {
420 intendLevel = 0;
421 stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
422 return writeNode (rootNode, stream);
423 }
424
425 //-----------------------------------------------------------------------------
encodeAttributeString(std::string & str)426 void UIDescWriter::encodeAttributeString (std::string& str)
427 {
428 const int8_t entities[] = {'&', '<','>', '\'', '\"', 0};
429 const char* replacements[] = {"&", "<", ">", "'", """};
430 int32_t i = 0;
431 while (entities[i] != 0)
432 {
433 size_t pos = 0;
434 while ((pos = str.find (entities[i], pos)) != std::string::npos)
435 {
436 str.replace (pos, 1, replacements[i]);
437 pos++;
438 }
439 i++;
440 }
441 }
442
443 //-----------------------------------------------------------------------------
writeAttributes(UIAttributes * attr,OutputStream & stream)444 bool UIDescWriter::writeAttributes (UIAttributes* attr, OutputStream& stream)
445 {
446 bool result = true;
447 using SortedAttributes = std::map<std::string,std::string>;
448 SortedAttributes sortedAttributes (attr->begin (), attr->end ());
449 for (auto& sa : sortedAttributes)
450 {
451 if (sa.second.length () > 0)
452 {
453 stream << " ";
454 stream << sa.first;
455 stream << "=\"";
456 std::string value (sa.second);
457 encodeAttributeString (value);
458 stream << value;
459 stream << "\"";
460 }
461 }
462 return result;
463 }
464
465 //-----------------------------------------------------------------------------
writeNodeData(UINode::DataStorage & str,OutputStream & stream)466 bool UIDescWriter::writeNodeData (UINode::DataStorage& str, OutputStream& stream)
467 {
468 for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
469 uint32_t i = 0;
470 for (auto c : str)
471 {
472 stream << static_cast<int8_t> (c);
473 if (i++ > 80)
474 {
475 stream << "\n";
476 i = 0;
477 for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
478 }
479 }
480 stream << "\n";
481 return true;
482 }
483
484 //-----------------------------------------------------------------------------
writeComment(UICommentNode * node,OutputStream & stream)485 bool UIDescWriter::writeComment (UICommentNode* node, OutputStream& stream)
486 {
487 stream << "<!--";
488 stream << node->getData ();
489 stream << "-->\n";
490 return true;
491 }
492
493 //-----------------------------------------------------------------------------
writeNode(UINode * node,OutputStream & stream)494 bool UIDescWriter::writeNode (UINode* node, OutputStream& stream)
495 {
496 bool result = true;
497 if (node->noExport ())
498 return result;
499 for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
500 if (UICommentNode* commentNode = dynamic_cast<UICommentNode*> (node))
501 {
502 return writeComment (commentNode, stream);
503 }
504 stream << "<";
505 stream << node->getName ();
506 result = writeAttributes (node->getAttributes (), stream);
507 if (result)
508 {
509 UIDescList& children = node->getChildren ();
510 if (!children.empty ())
511 {
512 stream << ">\n";
513 intendLevel++;
514 if (!node->getData ().empty ())
515 result = writeNodeData (node->getData (), stream);
516 for (auto& childNode : children)
517 {
518 if (!writeNode (childNode, stream))
519 return false;
520 }
521 intendLevel--;
522 for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
523 stream << "</";
524 stream << node->getName ();
525 stream << ">\n";
526 }
527 else if (!node->getData ().empty ())
528 {
529 stream << ">\n";
530 intendLevel++;
531 result = writeNodeData (node->getData (), stream);
532 intendLevel--;
533 for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
534 stream << "</";
535 stream << node->getName ();
536 stream << ">\n";
537 }
538 else
539 stream << "/>\n";
540 }
541 return result;
542 }
543 /// @endcond
544
545 //-----------------------------------------------------------------------------
546 //-----------------------------------------------------------------------------
547 //-----------------------------------------------------------------------------
parseColor(const std::string & colorString,CColor & color)548 bool UIDescription::parseColor (const std::string& colorString, CColor& color)
549 {
550 if (colorString.length () == 7)
551 {
552 if (colorString[0] == '#')
553 {
554 std::string rv (colorString.substr (1, 2));
555 std::string gv (colorString.substr (3, 2));
556 std::string bv (colorString.substr (5, 2));
557 color.red = (uint8_t)strtol (rv.c_str (), nullptr, 16);
558 color.green = (uint8_t)strtol (gv.c_str (), nullptr, 16);
559 color.blue = (uint8_t)strtol (bv.c_str (), nullptr, 16);
560 color.alpha = 255;
561 return true;
562 }
563 }
564 if (colorString.length () == 9)
565 {
566 if (colorString[0] == '#')
567 {
568 std::string rv (colorString.substr (1, 2));
569 std::string gv (colorString.substr (3, 2));
570 std::string bv (colorString.substr (5, 2));
571 std::string av (colorString.substr (7, 2));
572 color.red = (uint8_t)strtol (rv.c_str (), nullptr, 16);
573 color.green = (uint8_t)strtol (gv.c_str (), nullptr, 16);
574 color.blue = (uint8_t)strtol (bv.c_str (), nullptr, 16);
575 color.alpha = (uint8_t)strtol (av.c_str (), nullptr, 16);
576 return true;
577 }
578 }
579 return false;
580 }
581
582 //-----------------------------------------------------------------------------
getGenericViewFactory()583 static UIViewFactory* getGenericViewFactory ()
584 {
585 static UIViewFactory genericViewFactory;
586 return &genericViewFactory;
587 }
588
589 namespace UIDescriptionPrivate {
590
591 //-----------------------------------------------------------------------------
592 template <bool nameHasExtension, size_t numIndicators>
rangeOfScaleFactor(const std::string & name,const char (& identicator)[numIndicators])593 std::pair<size_t, size_t> rangeOfScaleFactor (const std::string& name,
594 const char (&identicator)[numIndicators])
595 {
596 auto result = std::make_pair (std::string::npos, std::string::npos);
597 size_t xIndex;
598 if (nameHasExtension)
599 {
600 xIndex = name.rfind ("x.");
601 }
602 else
603 {
604 if (name[name.size () - 1] != 'x')
605 return result;
606 xIndex = name.size () - 1;
607 }
608 if (xIndex == std::string::npos)
609 return result;
610
611 for (auto i = 0u; i < numIndicators; ++i)
612 {
613 size_t indicatorIndex = name.find_last_of (identicator[i]);
614 if (indicatorIndex == std::string::npos)
615 continue;
616 if (xIndex < indicatorIndex)
617 continue;
618 result.first = xIndex;
619 result.second = indicatorIndex;
620 break;
621 }
622 return result;
623 }
624
625 //-----------------------------------------------------------------------------
626 template <size_t numIndicators>
decodeScaleFactorFromName(const std::string & name,const char (& identicator)[numIndicators],double & scaleFactor)627 bool decodeScaleFactorFromName (const std::string& name, const char (&identicator)[numIndicators],
628 double& scaleFactor)
629 {
630 auto range = rangeOfScaleFactor<true> (name, identicator);
631 if (range.first == std::string::npos)
632 return false;
633 std::string tmp (name);
634 tmp.erase (0, ++range.second);
635 tmp.erase (range.first - range.second);
636 scaleFactor = UTF8StringView (tmp.c_str ()).toDouble ();
637 return scaleFactor != 0;
638 }
639
640 //-----------------------------------------------------------------------------
641 static constexpr const char scaleFactorIndicatorChars[] = "#_";
642
643 //-----------------------------------------------------------------------------
decodeScaleFactorFromName(const std::string & name,double & scaleFactor)644 static bool decodeScaleFactorFromName (const std::string& name, double& scaleFactor)
645 {
646 if (!decodeScaleFactorFromName (name, scaleFactorIndicatorChars, scaleFactor))
647 return false;
648 return true;
649 }
650
651 //-----------------------------------------------------------------------------
removeScaleFactorFromName(const std::string & name)652 static std::string removeScaleFactorFromName (const std::string& name)
653 {
654 auto range = rangeOfScaleFactor<false> (name, scaleFactorIndicatorChars);
655 if (range.first == std::string::npos)
656 return "";
657 auto result = name.substr (0, range.second);
658 return result;
659 }
660
661 } // UIDescriptionPrivate
662
663 IdStringPtr IUIDescription::kCustomViewName = "custom-view-name";
664
665 //-----------------------------------------------------------------------------
666 struct UIDescription::Impl
667 {
668 CResourceDescription xmlFile;
669 std::string filePath;
670
671 mutable IController* controller {nullptr};
672 IViewFactory* viewFactory {nullptr};
673 Xml::IContentProvider* xmlContentProvider {nullptr};
674 IBitmapCreator* bitmapCreator { nullptr};
675
676 SharedPointer<UINode> nodes;
677 SharedPointer<UIDescription> sharedResources;
678
679 mutable std::deque<IController*> subControllerStack;
680 std::deque<UINode*> nodeStack;
681
682 bool restoreViewsMode {false};
683
684 Optional<UINode*> variableBaseNode;
685
getVariableBaseNodeVSTGUI::UIDescription::Impl686 UINode* getVariableBaseNode ()
687 {
688 if (!variableBaseNode)
689 {
690 if (nodes)
691 variableBaseNode = nodes->getChildren ().findChildNode (MainNodeNames::kVariable);
692 }
693 return *variableBaseNode;
694 }
695
696 DispatchList<UIDescriptionListener*> listeners;
697 };
698
699 //-----------------------------------------------------------------------------
UIDescription(const CResourceDescription & xmlFile,IViewFactory * _viewFactory)700 UIDescription::UIDescription (const CResourceDescription& xmlFile, IViewFactory* _viewFactory)
701 {
702 impl = std::unique_ptr<Impl> (new Impl);
703 impl->xmlFile = xmlFile;
704 impl->viewFactory = _viewFactory;
705 if (xmlFile.type == CResourceDescription::kStringType && xmlFile.u.name != nullptr)
706 setFilePath (xmlFile.u.name);
707 if (impl->viewFactory == nullptr)
708 impl->viewFactory = getGenericViewFactory ();
709 }
710
711 //-----------------------------------------------------------------------------
UIDescription(Xml::IContentProvider * xmlContentProvider,IViewFactory * _viewFactory)712 UIDescription::UIDescription (Xml::IContentProvider* xmlContentProvider, IViewFactory* _viewFactory)
713 {
714 impl = std::unique_ptr<Impl> (new Impl);
715 impl->viewFactory = _viewFactory;
716 impl->xmlContentProvider = xmlContentProvider;
717 if (impl->viewFactory == nullptr)
718 impl->viewFactory = getGenericViewFactory ();
719 }
720
721 //-----------------------------------------------------------------------------
~UIDescription()722 UIDescription::~UIDescription () noexcept
723 {
724 }
725
726 //------------------------------------------------------------------------
setFilePath(UTF8StringPtr path)727 void UIDescription::setFilePath (UTF8StringPtr path)
728 {
729 impl->filePath = path;
730 impl->xmlFile.u.name = impl->filePath.data (); // make sure that xmlFile.u.name points to valid memory
731 }
732
733 //-----------------------------------------------------------------------------
getFilePath() const734 UTF8StringPtr UIDescription::getFilePath () const
735 {
736 return impl->filePath.data ();
737 }
738
739 //-----------------------------------------------------------------------------
getXmlFile() const740 const CResourceDescription& UIDescription::getXmlFile () const
741 {
742 return impl->xmlFile;
743 }
744
745 //-----------------------------------------------------------------------------
addDefaultNodes()746 void UIDescription::addDefaultNodes ()
747 {
748 if (impl->sharedResources)
749 return;
750 UINode* fontsNode = getBaseNode (MainNodeNames::kFont);
751 if (fontsNode)
752 {
753 struct DefaultFont {
754 UTF8StringPtr name;
755 CFontRef font;
756 };
757
758 const DefaultFont defaultFonts [] = {
759 { "~ SystemFont", kSystemFont },
760 { "~ NormalFontVeryBig", kNormalFontVeryBig },
761 { "~ NormalFontBig", kNormalFontBig },
762 { "~ NormalFont", kNormalFont },
763 { "~ NormalFontSmall", kNormalFontSmall },
764 { "~ NormalFontSmaller", kNormalFontSmaller },
765 { "~ NormalFontVerySmall", kNormalFontVerySmall },
766 { "~ SymbolFont", kSymbolFont },
767 { nullptr, nullptr },
768 };
769 int32_t i = 0;
770 while (defaultFonts[i].name != nullptr)
771 {
772 auto attr = makeOwned<UIAttributes> ();
773 attr->setAttribute ("name", defaultFonts[i].name);
774 UIFontNode* node = new UIFontNode ("font", attr);
775 node->setFont (defaultFonts[i].font);
776 node->noExport (true);
777 fontsNode->getChildren ().add (node);
778 i++;
779 }
780 }
781 UINode* colorsNode = getBaseNode (MainNodeNames::kColor);
782 if (colorsNode)
783 {
784 struct DefaultColor {
785 UTF8StringPtr name;
786 CColor color;
787 };
788
789 const DefaultColor defaultColors [] = {
790 { "~ BlackCColor", kBlackCColor },
791 { "~ WhiteCColor", kWhiteCColor },
792 { "~ GreyCColor", kGreyCColor },
793 { "~ RedCColor", kRedCColor },
794 { "~ GreenCColor", kGreenCColor },
795 { "~ BlueCColor", kBlueCColor },
796 { "~ YellowCColor", kYellowCColor },
797 { "~ CyanCColor", kCyanCColor },
798 { "~ MagentaCColor", kMagentaCColor },
799 { "~ TransparentCColor", kTransparentCColor },
800 { nullptr, kBlackCColor }
801 };
802
803 int32_t i = 0;
804 while (defaultColors[i].name != nullptr)
805 {
806 auto attr = makeOwned<UIAttributes> ();
807 attr->setAttribute ("name", defaultColors[i].name);
808 std::string colorStr;
809 UIViewCreator::colorToString (defaultColors[i].color, colorStr, nullptr);
810 attr->setAttribute ("rgba", colorStr);
811 UIColorNode* node = new UIColorNode ("color", attr);
812 node->noExport (true);
813 colorsNode->getChildren ().add (node);
814 i++;
815 }
816 }
817 }
818
819 //-----------------------------------------------------------------------------
parsed() const820 bool UIDescription::parsed () const
821 {
822 return impl->nodes != nullptr;
823 }
824
825 //-----------------------------------------------------------------------------
setXmlContentProvider(Xml::IContentProvider * provider)826 void UIDescription::setXmlContentProvider (Xml::IContentProvider* provider)
827 {
828 impl->xmlContentProvider = provider;
829 }
830
831 //-----------------------------------------------------------------------------
parse()832 bool UIDescription::parse ()
833 {
834 if (parsed ())
835 return true;
836 Xml::Parser parser;
837 if (impl->xmlContentProvider)
838 {
839 if (parser.parse (impl->xmlContentProvider, this))
840 {
841 addDefaultNodes ();
842 return true;
843 }
844 }
845 else
846 {
847 CResourceInputStream resInputStream;
848 if (resInputStream.open (impl->xmlFile))
849 {
850 Xml::InputStreamContentProvider contentProvider (resInputStream);
851 if (parser.parse (&contentProvider, this))
852 {
853 addDefaultNodes ();
854 return true;
855 }
856 }
857 else if (impl->xmlFile.type == CResourceDescription::kStringType)
858 {
859 CFileStream fileStream;
860 if (fileStream.open (impl->xmlFile.u.name, CFileStream::kReadMode))
861 {
862 Xml::InputStreamContentProvider contentProvider (fileStream);
863 if (parser.parse (&contentProvider, this))
864 {
865 addDefaultNodes ();
866 return true;
867 }
868 }
869 }
870 }
871 if (!impl->nodes)
872 {
873 impl->nodes = makeOwned<UINode> ("vstgui-ui-description");
874 addDefaultNodes ();
875 }
876 return false;
877 }
878
879 //-----------------------------------------------------------------------------
setController(IController * inController) const880 void UIDescription::setController (IController* inController) const
881 {
882 impl->controller = inController;
883 }
884
885 //-----------------------------------------------------------------------------
getController() const886 IController* UIDescription::getController () const
887 {
888 return impl->controller;
889 }
890
891 //-----------------------------------------------------------------------------
getViewFactory() const892 const IViewFactory* UIDescription::getViewFactory () const
893 {
894 return impl->viewFactory;
895 }
896
897 //-----------------------------------------------------------------------------
registerListener(UIDescriptionListener * listener)898 void UIDescription::registerListener (UIDescriptionListener* listener)
899 {
900 impl->listeners.add (listener);
901 }
902
903 //-----------------------------------------------------------------------------
unregisterListener(UIDescriptionListener * listener)904 void UIDescription::unregisterListener (UIDescriptionListener* listener)
905 {
906 impl->listeners.remove (listener);
907 }
908
909 //-----------------------------------------------------------------------------
setBitmapCreator(IBitmapCreator * creator)910 void UIDescription::setBitmapCreator (IBitmapCreator* creator)
911 {
912 impl->bitmapCreator = creator;
913 }
914
915 //-----------------------------------------------------------------------------
FreeNodePlatformResources(UINode * node)916 static void FreeNodePlatformResources (UINode* node)
917 {
918 for (auto& child : node->getChildren ())
919 {
920 child->freePlatformResources ();
921 FreeNodePlatformResources (child);
922 }
923 }
924
925 //-----------------------------------------------------------------------------
freePlatformResources()926 void UIDescription::freePlatformResources ()
927 {
928 if (impl->nodes)
929 FreeNodePlatformResources (impl->nodes);
930 }
931
932 //-----------------------------------------------------------------------------
saveWindowsRCFile(UTF8StringPtr filename)933 bool UIDescription::saveWindowsRCFile (UTF8StringPtr filename)
934 {
935 if (impl->sharedResources)
936 return true;
937 bool result = false;
938 UINode* bitmapNodes = getBaseNode (MainNodeNames::kBitmap);
939 if (bitmapNodes && !bitmapNodes->getChildren().empty ())
940 {
941 CFileStream stream;
942 if (stream.open (filename, CFileStream::kWriteMode|CFileStream::kTruncateMode))
943 {
944 for (auto& childNode : bitmapNodes->getChildren ())
945 {
946 UIAttributes* attr = childNode->getAttributes ();
947 if (attr)
948 {
949 const std::string* path = attr->getAttributeValue ("path");
950 if (path && !path->empty ())
951 {
952 stream << *path;
953 stream << "\t PNG \"";
954 stream << *path;
955 stream << "\"\r";
956 }
957 }
958 }
959 result = true;
960 }
961 }
962 return result;
963 }
964
965 //-----------------------------------------------------------------------------
moveOldFile(UTF8StringPtr filename)966 static std::string moveOldFile (UTF8StringPtr filename)
967 {
968 FILE* file = fopen (filename, "r");
969 if (file)
970 {
971 fclose (file);
972 std::string newName = filename;
973 newName += ".old";
974 if (std::rename (filename, newName.c_str ()) == 0)
975 return newName;
976 }
977 return "";
978 }
979
980 //-----------------------------------------------------------------------------
save(UTF8StringPtr filename,int32_t flags)981 bool UIDescription::save (UTF8StringPtr filename, int32_t flags)
982 {
983 std::string oldName = moveOldFile (filename);
984 bool result = false;
985 CFileStream stream;
986 if (stream.open (filename, CFileStream::kWriteMode|CFileStream::kTruncateMode))
987 {
988 result = saveToStream (stream, flags);
989 }
990 if (result && flags & kWriteWindowsResourceFile)
991 {
992 std::string rcFileName (filename);
993 size_t extPos = rcFileName.find_last_of ('.');
994 if (extPos != std::string::npos)
995 {
996 rcFileName.erase (extPos+1);
997 rcFileName += "rc";
998 saveWindowsRCFile (rcFileName.c_str ());
999 }
1000 }
1001 if (result && oldName.empty () == false)
1002 std::remove (oldName.c_str ());
1003
1004 return result;
1005 }
1006
1007 //-----------------------------------------------------------------------------
saveToStream(OutputStream & stream,int32_t flags)1008 bool UIDescription::saveToStream (OutputStream& stream, int32_t flags)
1009 {
1010 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1011 l->beforeUIDescSave (this);
1012 });
1013 if (!impl->sharedResources)
1014 {
1015 UINode* bitmapNodes = getBaseNode (MainNodeNames::kBitmap);
1016 if (bitmapNodes)
1017 {
1018 for (auto& childNode : bitmapNodes->getChildren ())
1019 {
1020 UIBitmapNode* bitmapNode = dynamic_cast<UIBitmapNode*> (childNode);
1021 if (bitmapNode)
1022 {
1023 if (flags & kWriteImagesIntoXMLFile)
1024 bitmapNode->createXMLData (impl->filePath);
1025 else
1026 bitmapNode->removeXMLData ();
1027 }
1028 }
1029 }
1030 }
1031 impl->nodes->getAttributes ()->setAttribute ("version", "1");
1032
1033 BufferedOutputStream bufferedStream (stream);
1034 UIDescWriter writer;
1035 return writer.write (bufferedStream, impl->nodes);
1036 }
1037
1038 //-----------------------------------------------------------------------------
setSharedResources(const SharedPointer<UIDescription> & resources)1039 void UIDescription::setSharedResources (const SharedPointer<UIDescription>& resources)
1040 {
1041 impl->sharedResources = resources;
1042 }
1043
1044 //-----------------------------------------------------------------------------
getSharedResources() const1045 const SharedPointer<UIDescription>& UIDescription::getSharedResources () const
1046 {
1047 return impl->sharedResources;
1048 }
1049
1050 //-----------------------------------------------------------------------------
findNodeForView(CView * view) const1051 UINode* UIDescription::findNodeForView (CView* view) const
1052 {
1053 CView* parentView = view;
1054 std::string templateName;
1055 while (parentView && getTemplateNameFromView (parentView, templateName) == false)
1056 parentView = parentView->getParentView ();
1057 if (parentView)
1058 {
1059 UINode* node = nullptr;
1060 for (const auto& itNode : impl->nodes->getChildren ())
1061 {
1062 if (itNode->getName () == MainNodeNames::kTemplate)
1063 {
1064 const std::string* nodeName = itNode->getAttributes ()->getAttributeValue ("name");
1065 if (nodeName && *nodeName == templateName)
1066 {
1067 node = itNode;
1068 break;
1069 }
1070 }
1071 }
1072 if (node)
1073 {
1074 while (view != parentView)
1075 {
1076 if (view == parentView)
1077 return node;
1078 CViewContainer* container = parentView->asViewContainer ();
1079 vstgui_assert (container != nullptr);
1080 UIDescList::iterator nodeIterator = node->getChildren ().begin ();
1081 CViewContainer* childContainer = nullptr;
1082 ViewIterator it (container);
1083 while (*it && nodeIterator != node->getChildren ().end ())
1084 {
1085 if (*it == view)
1086 {
1087 node = *nodeIterator;
1088 parentView = view;
1089 break;
1090 }
1091 childContainer = (*it)->asViewContainer ();
1092 if (childContainer && childContainer->isChild (view, true))
1093 {
1094 break;
1095 }
1096 childContainer = nullptr;
1097 ++nodeIterator;
1098 ++it;
1099 }
1100 if (childContainer)
1101 {
1102 node = *nodeIterator;
1103 parentView = childContainer;
1104 }
1105 else
1106 {
1107 break;
1108 }
1109 }
1110 if (view == parentView)
1111 return node;
1112 }
1113 }
1114 return nullptr;
1115 }
1116
1117 //-----------------------------------------------------------------------------
storeViews(const std::list<CView * > & views,OutputStream & stream,UIAttributes * customData) const1118 bool UIDescription::storeViews (const std::list<CView*>& views, OutputStream& stream, UIAttributes* customData) const
1119 {
1120 auto nodeList = makeOwned<UIDescList> (false);
1121 for (auto& view : views)
1122 {
1123 UINode* node = findNodeForView (view);
1124 if (node)
1125 {
1126 nodeList->add (node);
1127 }
1128 else
1129 {
1130 #if VSTGUI_LIVE_EDITING
1131 auto attr = makeOwned<UIAttributes> ();
1132 UIViewFactory* factory = dynamic_cast<UIViewFactory*> (impl->viewFactory);
1133 if (factory)
1134 {
1135 if (factory->getAttributesForView (view, const_cast<UIDescription*> (this), *attr) == false)
1136 return false;
1137 UINode* node = new UINode ("view", attr);
1138 nodeList->add (node);
1139 node->forget ();
1140 }
1141 #endif
1142 }
1143 }
1144 if (!nodeList->empty ())
1145 {
1146 if (customData)
1147 {
1148 UINode* customNode = new UINode (MainNodeNames::kCustom, customData);
1149 nodeList->add (customNode);
1150 customNode->forget ();
1151 customData->remember ();
1152 }
1153 UINode baseNode ("vstgui-ui-description-view-list", nodeList);
1154 UIDescWriter writer;
1155 return writer.write (stream, &baseNode);
1156 }
1157 return false;
1158 }
1159
1160 //-----------------------------------------------------------------------------
restoreViews(InputStream & stream,std::list<SharedPointer<CView>> & views,UIAttributes ** customData)1161 bool UIDescription::restoreViews (InputStream& stream, std::list<SharedPointer<CView> >& views, UIAttributes** customData)
1162 {
1163 SharedPointer<UINode> baseNode;
1164 if (impl->nodes)
1165 {
1166 auto origNodes = std::move (impl->nodes);
1167 impl->nodes = baseNode;
1168
1169 Xml::InputStreamContentProvider contentProvider (stream);
1170 Xml::Parser parser;
1171 if (parser.parse (&contentProvider, this))
1172 {
1173 baseNode = impl->nodes;
1174 }
1175 impl->nodes = std::move (origNodes);
1176 }
1177 if (baseNode)
1178 {
1179 UIDescList& children = baseNode->getChildren ();
1180 for (auto& childNode : children)
1181 {
1182 if (childNode->getName() == MainNodeNames::kCustom)
1183 {
1184 if (customData)
1185 {
1186 *customData = childNode->getAttributes ();
1187 (*customData)->remember ();
1188 }
1189 }
1190 else
1191 {
1192 CView* view = createViewFromNode (childNode);
1193 if (view)
1194 {
1195 views.emplace_back (view);
1196 view->forget ();
1197 }
1198 }
1199 }
1200 }
1201 return views.empty () == false;
1202 }
1203
1204 //-----------------------------------------------------------------------------
createViewFromNode(UINode * node) const1205 CView* UIDescription::createViewFromNode (UINode* node) const
1206 {
1207 const std::string* templateName = node->getAttributes ()->getAttributeValue (MainNodeNames::kTemplate);
1208 if (templateName)
1209 {
1210 CView* view = createView (templateName->c_str (), impl->controller);
1211 if (view)
1212 impl->viewFactory->applyAttributeValues (view, *node->getAttributes (), this);
1213 return view;
1214 }
1215
1216 IController* subController = nullptr;
1217 CView* result = nullptr;
1218 if (impl->controller)
1219 {
1220 const std::string* subControllerName = node->getAttributes ()->getAttributeValue ("sub-controller");
1221 if (subControllerName)
1222 {
1223 subController = impl->controller->createSubController (subControllerName->c_str (), this);
1224 if (subController)
1225 {
1226 impl->subControllerStack.emplace_back (impl->controller);
1227 setController (subController);
1228 }
1229 }
1230 result = impl->controller->createView (*node->getAttributes (), this);
1231 if (result && impl->viewFactory)
1232 {
1233 const std::string* viewClass = node->getAttributes ()->getAttributeValue (UIViewCreator::kAttrClass);
1234 if (viewClass)
1235 impl->viewFactory->applyCustomViewAttributeValues (result, viewClass->c_str (), *node->getAttributes (), this);
1236 }
1237 }
1238 if (result == nullptr && impl->viewFactory)
1239 {
1240 result = impl->viewFactory->createView (*node->getAttributes (), this);
1241 if (result == nullptr)
1242 {
1243 result = new CViewContainer (CRect (0, 0, 0, 0));
1244 impl->viewFactory->applyCustomViewAttributeValues (result, "CViewContainer", *node->getAttributes (), this);
1245 }
1246 }
1247 if (result && node->hasChildren ())
1248 {
1249 CViewContainer* viewContainer = result->asViewContainer ();
1250 for (const auto& itNode : node->getChildren ())
1251 {
1252 if (viewContainer)
1253 {
1254 if (itNode->getName () == "view")
1255 {
1256 CView* childView = createViewFromNode (itNode);
1257 if (childView)
1258 {
1259 if (!viewContainer->addView (childView))
1260 childView->forget ();
1261 }
1262 }
1263 }
1264 if (itNode->getName () == "attribute")
1265 {
1266 const std::string* attrName = itNode->getAttributes ()->getAttributeValue ("id");
1267 const std::string* attrValue = itNode->getAttributes ()->getAttributeValue ("value");
1268 if (attrName && attrValue)
1269 {
1270 CViewAttributeID attrId = 0;
1271 if (attrName->size () == 4)
1272 {
1273 char c1 = (*attrName)[0];
1274 char c2 = (*attrName)[1];
1275 char c3 = (*attrName)[2];
1276 char c4 = (*attrName)[3];
1277 attrId = ((((size_t)c1) << 24) | (((size_t)c2) << 16) | (((size_t)c3) << 8) | (((size_t)c4) << 0));
1278 }
1279 else
1280 attrId = (CViewAttributeID)strtol (attrName->c_str (), nullptr, 10);
1281 if (attrId)
1282 result->setAttribute (attrId, static_cast<uint32_t> (attrValue->size () + 1), attrValue->c_str ());
1283 }
1284 }
1285 }
1286 }
1287 if (result && impl->controller)
1288 result = impl->controller->verifyView (result, *node->getAttributes (), this);
1289 if (subController)
1290 {
1291 if (result)
1292 result->setAttribute (kCViewControllerAttribute, subController);
1293 setController (impl->subControllerStack.back ());
1294 impl->subControllerStack.pop_back ();
1295 if (result == nullptr)
1296 {
1297 auto obj = dynamic_cast<IReference*> (subController);
1298 if (obj)
1299 obj->forget ();
1300 else
1301 delete subController;
1302 }
1303 }
1304 return result;
1305 }
1306
1307 //-----------------------------------------------------------------------------
1308 CViewAttributeID UIDescription::kTemplateNameAttributeID = 'uitl';
1309
1310 //-----------------------------------------------------------------------------
createView(UTF8StringPtr name,IController * _controller) const1311 CView* UIDescription::createView (UTF8StringPtr name, IController* _controller) const
1312 {
1313 ScopePointer<IController> sp (&impl->controller, _controller);
1314 if (impl->nodes)
1315 {
1316 for (const auto& itNode : impl->nodes->getChildren ())
1317 {
1318 if (itNode->getName () == MainNodeNames::kTemplate)
1319 {
1320 const std::string* nodeName = itNode->getAttributes ()->getAttributeValue ("name");
1321 if (nodeName && *nodeName == name)
1322 {
1323 CView* view = createViewFromNode (itNode);
1324 if (view)
1325 view->setAttribute (kTemplateNameAttributeID, static_cast<uint32_t> (strlen (name) + 1), name);
1326 return view;
1327 }
1328 }
1329 }
1330 }
1331 return nullptr;
1332 }
1333
1334 //-----------------------------------------------------------------------------
getTemplateNameFromView(CView * view,std::string & templateName) const1335 bool UIDescription::getTemplateNameFromView (CView* view, std::string& templateName) const
1336 {
1337 bool result = false;
1338 uint32_t attrSize = 0;
1339 if (view->getAttributeSize (kTemplateNameAttributeID, attrSize))
1340 {
1341 char* str = new char[attrSize];
1342 if (view->getAttribute (kTemplateNameAttributeID, attrSize, str, attrSize))
1343 {
1344 templateName = str;
1345 result = true;
1346 }
1347 delete [] str;
1348 }
1349 return result;
1350 }
1351
1352 //-----------------------------------------------------------------------------
getViewAttributes(UTF8StringPtr name) const1353 const UIAttributes* UIDescription::getViewAttributes (UTF8StringPtr name) const
1354 {
1355 if (impl->nodes)
1356 {
1357 for (const auto& itNode : impl->nodes->getChildren ())
1358 {
1359 if (itNode->getName () == MainNodeNames::kTemplate)
1360 {
1361 const std::string* nodeName = itNode->getAttributes ()->getAttributeValue ("name");
1362 if (nodeName && *nodeName == name)
1363 return itNode->getAttributes ();
1364 }
1365 }
1366 }
1367 return nullptr;
1368 }
1369
1370 //-----------------------------------------------------------------------------
getBaseNode(UTF8StringPtr name) const1371 UINode* UIDescription::getBaseNode (UTF8StringPtr name) const
1372 {
1373 UTF8StringView nameView (name);
1374 nameView.calculateByteCount ();
1375 if (impl->sharedResources)
1376 {
1377 if (nameView == MainNodeNames::kBitmap || nameView == MainNodeNames::kFont || nameView == MainNodeNames::kColor || nameView == MainNodeNames::kGradient)
1378 {
1379 return impl->sharedResources->getBaseNode (name);
1380 }
1381 }
1382 if (impl->nodes)
1383 {
1384 UINode* node = impl->nodes->getChildren ().findChildNode (nameView);
1385 if (node)
1386 return node;
1387
1388 node = new UINode (name);
1389 impl->nodes->getChildren ().add (node);
1390 return node;
1391 }
1392 return nullptr;
1393 }
1394
1395 //-----------------------------------------------------------------------------
findChildNodeByNameAttribute(UINode * node,UTF8StringPtr nameAttribute) const1396 UINode* UIDescription::findChildNodeByNameAttribute (UINode* node, UTF8StringPtr nameAttribute) const
1397 {
1398 if (node)
1399 return node->getChildren ().findChildNodeWithAttributeValue ("name", nameAttribute);
1400 return nullptr;
1401 }
1402
1403 //-----------------------------------------------------------------------------
getTagForName(UTF8StringPtr name) const1404 int32_t UIDescription::getTagForName (UTF8StringPtr name) const
1405 {
1406 int32_t tag = -1;
1407 UIControlTagNode* controlTagNode = dynamic_cast<UIControlTagNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kControlTag), name));
1408 if (controlTagNode)
1409 {
1410 tag = controlTagNode->getTag ();
1411 if (tag == -1)
1412 {
1413 const std::string* tagStr = controlTagNode->getTagString ();
1414 if (tagStr)
1415 {
1416 double value;
1417 if (calculateStringValue (tagStr->c_str (), value))
1418 {
1419 tag = (int32_t)value;
1420 controlTagNode->setTag (tag);
1421 }
1422 }
1423 }
1424 }
1425 if (impl->controller)
1426 tag = impl->controller->getTagForName (name, tag);
1427 return tag;
1428 }
1429
1430 //-----------------------------------------------------------------------------
hasColorName(UTF8StringPtr name) const1431 bool UIDescription::hasColorName (UTF8StringPtr name) const
1432 {
1433 UIColorNode* node = dynamic_cast<UIColorNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kColor), name));
1434 return node ? true : false;
1435 }
1436
1437 //-----------------------------------------------------------------------------
hasTagName(UTF8StringPtr name) const1438 bool UIDescription::hasTagName (UTF8StringPtr name) const
1439 {
1440 UIControlTagNode* node = dynamic_cast<UIControlTagNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kControlTag), name));
1441 return node ? true : false;
1442 }
1443
1444 //-----------------------------------------------------------------------------
hasFontName(UTF8StringPtr name) const1445 bool UIDescription::hasFontName (UTF8StringPtr name) const
1446 {
1447 UIFontNode* node = dynamic_cast<UIFontNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kFont), name));
1448 return node ? true : false;
1449 }
1450
1451 //-----------------------------------------------------------------------------
hasBitmapName(UTF8StringPtr name) const1452 bool UIDescription::hasBitmapName (UTF8StringPtr name) const
1453 {
1454 UIBitmapNode* node = dynamic_cast<UIBitmapNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kBitmap), name));
1455 return node ? true : false;
1456 }
1457
1458 //-----------------------------------------------------------------------------
hasGradientName(UTF8StringPtr name) const1459 bool UIDescription::hasGradientName (UTF8StringPtr name) const
1460 {
1461 UIGradientNode* node = dynamic_cast<UIGradientNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kGradient), name));
1462 return node ? true : false;
1463 }
1464
1465 //-----------------------------------------------------------------------------
getControlListener(UTF8StringPtr name) const1466 IControlListener* UIDescription::getControlListener (UTF8StringPtr name) const
1467 {
1468 if (impl->controller)
1469 return impl->controller->getControlListener (name);
1470 return nullptr;
1471 }
1472
1473 //-----------------------------------------------------------------------------
getBitmap(UTF8StringPtr name) const1474 CBitmap* UIDescription::getBitmap (UTF8StringPtr name) const
1475 {
1476 UIBitmapNode* bitmapNode = dynamic_cast<UIBitmapNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kBitmap), name));
1477 if (bitmapNode)
1478 {
1479 CBitmap* bitmap = bitmapNode->getBitmap (impl->filePath);
1480 if (impl->bitmapCreator && bitmap && bitmap->getPlatformBitmap () == nullptr)
1481 {
1482 auto platformBitmap = impl->bitmapCreator->createBitmap (*bitmapNode->getAttributes ());
1483 if (platformBitmap)
1484 {
1485 double scaleFactor;
1486 if (UIDescriptionPrivate::decodeScaleFactorFromName (name, scaleFactor))
1487 platformBitmap->setScaleFactor (scaleFactor);
1488 bitmap->setPlatformBitmap (platformBitmap);
1489 }
1490 }
1491 if (bitmap && bitmapNode->getFilterProcessed () == false)
1492 {
1493 std::list<SharedPointer<BitmapFilter::IFilter> > filters;
1494 for (auto& childNode : bitmapNode->getChildren ())
1495 {
1496 const std::string* filterName = nullptr;
1497 if (childNode->getName () == "filter" && (filterName = childNode->getAttributes ()->getAttributeValue ("name")))
1498 {
1499 auto filter = owned (BitmapFilter::Factory::getInstance().createFilter (filterName->c_str ()));
1500 if (filter == nullptr)
1501 continue;
1502 filters.emplace_back (filter);
1503 for (auto& propertyNode : childNode->getChildren ())
1504 {
1505 if (propertyNode->getName () != "property")
1506 continue;
1507 const std::string* name = propertyNode->getAttributes ()->getAttributeValue ("name");
1508 if (name == nullptr)
1509 continue;
1510 switch (filter->getProperty (name->c_str ()).getType ())
1511 {
1512 case BitmapFilter::Property::kInteger:
1513 {
1514 int32_t intValue;
1515 if (propertyNode->getAttributes ()->getIntegerAttribute ("value", intValue))
1516 filter->setProperty (name->c_str (), intValue);
1517 break;
1518 }
1519 case BitmapFilter::Property::kFloat:
1520 {
1521 double floatValue;
1522 if (propertyNode->getAttributes ()->getDoubleAttribute ("value", floatValue))
1523 filter->setProperty (name->c_str (), floatValue);
1524 break;
1525 }
1526 case BitmapFilter::Property::kPoint:
1527 {
1528 CPoint pointValue;
1529 if (propertyNode->getAttributes ()->getPointAttribute ("value", pointValue))
1530 filter->setProperty (name->c_str (), pointValue);
1531 break;
1532 }
1533 case BitmapFilter::Property::kRect:
1534 {
1535 CRect rectValue;
1536 if (propertyNode->getAttributes ()->getRectAttribute ("value", rectValue))
1537 filter->setProperty (name->c_str (), rectValue);
1538 break;
1539 }
1540 case BitmapFilter::Property::kColor:
1541 {
1542 const std::string* colorString = propertyNode->getAttributes()->getAttributeValue ("value");
1543 if (colorString)
1544 {
1545 CColor color;
1546 if (getColor (colorString->c_str (), color))
1547 filter->setProperty(name->c_str (), color);
1548 }
1549 break;
1550 }
1551 case BitmapFilter::Property::kTransformMatrix:
1552 {
1553 // TODO
1554 break;
1555 }
1556 case BitmapFilter::Property::kObject: // objects can not be stored/restored
1557 case BitmapFilter::Property::kUnknown:
1558 break;
1559 }
1560 }
1561 }
1562 }
1563 for (auto& filter : filters)
1564 {
1565 filter->setProperty (BitmapFilter::Standard::Property::kInputBitmap, bitmap);
1566 if (filter->run ())
1567 {
1568 auto obj = filter->getProperty (BitmapFilter::Standard::Property::kOutputBitmap).getObject ();
1569 CBitmap* outputBitmap = dynamic_cast<CBitmap*>(obj);
1570 if (outputBitmap)
1571 {
1572 bitmap->setPlatformBitmap (outputBitmap->getPlatformBitmap ());
1573 }
1574 }
1575 }
1576 bitmapNode->setFilterProcessed ();
1577 }
1578 if (bitmap && bitmapNode->getScaledBitmapsAdded () == false)
1579 {
1580 double scaleFactor;
1581 if (!UIDescriptionPrivate::decodeScaleFactorFromName (bitmap->getResourceDescription ().u.name, scaleFactor))
1582 {
1583 // find scaled versions for this bitmap
1584 UINode* bitmapsNode = getBaseNode (MainNodeNames::kBitmap);
1585 for (auto& it : bitmapsNode->getChildren ())
1586 {
1587 UIBitmapNode* childNode = dynamic_cast<UIBitmapNode*>(it);
1588 if (childNode == nullptr || childNode == bitmapNode)
1589 continue;
1590 const std::string* childNodeBitmapName = childNode->getAttributes()->getAttributeValue ("name");
1591 if (childNodeBitmapName == nullptr)
1592 continue;
1593 std::string nameWithoutScaleFactor = UIDescriptionPrivate::removeScaleFactorFromName (*childNodeBitmapName);
1594 if (nameWithoutScaleFactor == name)
1595 {
1596 childNode->setScaledBitmapsAdded ();
1597 CBitmap* childBitmap = getBitmap (childNodeBitmapName->c_str ());
1598 if (childBitmap && childBitmap->getPlatformBitmap ())
1599 bitmap->addBitmap (childBitmap->getPlatformBitmap ());
1600 }
1601 }
1602 }
1603 bitmapNode->setScaledBitmapsAdded ();
1604 }
1605 return bitmap;
1606 }
1607 return nullptr;
1608 }
1609
1610 //-----------------------------------------------------------------------------
getFont(UTF8StringPtr name) const1611 CFontRef UIDescription::getFont (UTF8StringPtr name) const
1612 {
1613 UIFontNode* fontNode = dynamic_cast<UIFontNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kFont), name));
1614 if (fontNode)
1615 return fontNode->getFont ();
1616 return nullptr;
1617 }
1618
1619 //-----------------------------------------------------------------------------
getColor(UTF8StringPtr name,CColor & color) const1620 bool UIDescription::getColor (UTF8StringPtr name, CColor& color) const
1621 {
1622 UIColorNode* colorNode = dynamic_cast<UIColorNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kColor), name));
1623 if (colorNode)
1624 {
1625 color = colorNode->getColor ();
1626 return true;
1627 }
1628 if (parseColor (name, color))
1629 return true;
1630 return false;
1631 }
1632
1633 //-----------------------------------------------------------------------------
getGradient(UTF8StringPtr name) const1634 CGradient* UIDescription::getGradient (UTF8StringPtr name) const
1635 {
1636 UIGradientNode* gradientNode = dynamic_cast<UIGradientNode*> (findChildNodeByNameAttribute (getBaseNode(MainNodeNames::kGradient), name));
1637 if (gradientNode)
1638 return gradientNode->getGradient ();
1639 return nullptr;
1640 }
1641
1642 //-----------------------------------------------------------------------------
lookupName(const ObjType & obj,IdStringPtr mainNodeName,CompareFunction compare) const1643 template<typename NodeType, typename ObjType, typename CompareFunction> UTF8StringPtr UIDescription::lookupName (const ObjType& obj, IdStringPtr mainNodeName, CompareFunction compare) const
1644 {
1645 UINode* baseNode = getBaseNode (mainNodeName);
1646 if (baseNode)
1647 {
1648 UIDescList& children = baseNode->getChildren ();
1649 for (const auto& itNode : children)
1650 {
1651 NodeType* node = dynamic_cast<NodeType*>(itNode);
1652 if (node && compare (this, node, obj))
1653 {
1654 const std::string* name = node->getAttributes ()->getAttributeValue ("name");
1655 return name ? name->c_str () : nullptr;
1656 }
1657 }
1658 }
1659 return nullptr;
1660 }
1661
1662 //-----------------------------------------------------------------------------
lookupColorName(const CColor & color) const1663 UTF8StringPtr UIDescription::lookupColorName (const CColor& color) const
1664 {
1665 return lookupName<UIColorNode> (color, MainNodeNames::kColor, [] (const UIDescription* desc, UIColorNode* node, const CColor& color) {
1666 return node->getColor() == color;
1667 });
1668 }
1669
1670 //-----------------------------------------------------------------------------
lookupFontName(const CFontRef font) const1671 UTF8StringPtr UIDescription::lookupFontName (const CFontRef font) const
1672 {
1673 return font ? lookupName<UIFontNode> (font, MainNodeNames::kFont, [] (const UIDescription* desc, UIFontNode* node, const CFontRef& font) {
1674 return node->getFont () && node->getFont () == font;
1675 }) : nullptr;
1676 }
1677
1678 //-----------------------------------------------------------------------------
lookupBitmapName(const CBitmap * bitmap) const1679 UTF8StringPtr UIDescription::lookupBitmapName (const CBitmap* bitmap) const
1680 {
1681 return bitmap ? lookupName<UIBitmapNode> (bitmap, MainNodeNames::kBitmap, [] (const UIDescription* desc, UIBitmapNode* node, const CBitmap* bitmap) {
1682 return node->getBitmap (desc->impl->filePath) == bitmap;
1683 }) : nullptr;
1684 }
1685
1686 //-----------------------------------------------------------------------------
lookupGradientName(const CGradient * gradient) const1687 UTF8StringPtr UIDescription::lookupGradientName (const CGradient* gradient) const
1688 {
1689 return gradient ? lookupName<UIGradientNode> (gradient, MainNodeNames::kGradient, [] (const UIDescription* desc, UIGradientNode* node, const CGradient* gradient) {
1690 return node->getGradient() == gradient || (node->getGradient () && gradient->getColorStops () == node->getGradient ()->getColorStops ());
1691 }) : nullptr;
1692 }
1693
1694 //-----------------------------------------------------------------------------
lookupControlTagName(const int32_t tag) const1695 UTF8StringPtr UIDescription::lookupControlTagName (const int32_t tag) const
1696 {
1697 return lookupName<UIControlTagNode> (tag, MainNodeNames::kControlTag, [] (const UIDescription* desc, UIControlTagNode* node, const int32_t tag) {
1698 int32_t nodeTag = node->getTag ();
1699 if (nodeTag == -1 && node->getTagString ())
1700 {
1701 double v;
1702 if (desc->calculateStringValue (node->getTagString ()->c_str (), v))
1703 nodeTag = (int32_t)v;
1704 }
1705 return nodeTag == tag;
1706 });
1707 }
1708
1709 //-----------------------------------------------------------------------------
1710 template<typename NodeType>
changeNodeName(UTF8StringPtr oldName,UTF8StringPtr newName,IdStringPtr mainNodeName)1711 void UIDescription::changeNodeName (UTF8StringPtr oldName, UTF8StringPtr newName, IdStringPtr mainNodeName)
1712 {
1713 UINode* mainNode = getBaseNode (mainNodeName);
1714 NodeType* node = dynamic_cast<NodeType*> (findChildNodeByNameAttribute(mainNode, oldName));
1715 if (node)
1716 {
1717 node->getAttributes ()->setAttribute ("name", newName);
1718 mainNode->childAttributeChanged (node, "name", oldName);
1719 mainNode->sortChildren ();
1720 }
1721 }
1722
1723 //-----------------------------------------------------------------------------
changeColorName(UTF8StringPtr oldName,UTF8StringPtr newName)1724 void UIDescription::changeColorName (UTF8StringPtr oldName, UTF8StringPtr newName)
1725 {
1726 changeNodeName<UIColorNode> (oldName, newName, MainNodeNames::kColor);
1727 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1728 l->onUIDescColorChanged (this);
1729 });
1730 }
1731
1732 //-----------------------------------------------------------------------------
changeTagName(UTF8StringPtr oldName,UTF8StringPtr newName)1733 void UIDescription::changeTagName (UTF8StringPtr oldName, UTF8StringPtr newName)
1734 {
1735 changeNodeName<UIControlTagNode> (oldName, newName, MainNodeNames::kControlTag);
1736 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1737 l->onUIDescTagChanged (this);
1738 });
1739 }
1740
1741 //-----------------------------------------------------------------------------
changeFontName(UTF8StringPtr oldName,UTF8StringPtr newName)1742 void UIDescription::changeFontName (UTF8StringPtr oldName, UTF8StringPtr newName)
1743 {
1744 changeNodeName<UIFontNode> (oldName, newName, MainNodeNames::kFont);
1745 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1746 l->onUIDescFontChanged (this);
1747 });
1748 }
1749
1750 //-----------------------------------------------------------------------------
changeBitmapName(UTF8StringPtr oldName,UTF8StringPtr newName)1751 void UIDescription::changeBitmapName (UTF8StringPtr oldName, UTF8StringPtr newName)
1752 {
1753 changeNodeName<UIBitmapNode> (oldName, newName, MainNodeNames::kBitmap);
1754 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1755 l->onUIDescBitmapChanged (this);
1756 });
1757 }
1758
1759 //-----------------------------------------------------------------------------
changeGradientName(UTF8StringPtr oldName,UTF8StringPtr newName)1760 void UIDescription::changeGradientName (UTF8StringPtr oldName, UTF8StringPtr newName)
1761 {
1762 changeNodeName<UIGradientNode> (oldName, newName, MainNodeNames::kGradient);
1763 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1764 l->onUIDescGradientChanged (this);
1765 });
1766 }
1767
1768 //-----------------------------------------------------------------------------
changeColor(UTF8StringPtr name,const CColor & newColor)1769 void UIDescription::changeColor (UTF8StringPtr name, const CColor& newColor)
1770 {
1771 UINode* colorsNode = getBaseNode (MainNodeNames::kColor);
1772 UIColorNode* node = dynamic_cast<UIColorNode*> (findChildNodeByNameAttribute (colorsNode, name));
1773 if (node)
1774 {
1775 if (!node->noExport ())
1776 {
1777 node->setColor (newColor);
1778 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1779 l->onUIDescColorChanged (this);
1780 });
1781 }
1782 }
1783 else
1784 {
1785 if (colorsNode)
1786 {
1787 auto attr = makeOwned<UIAttributes> ();
1788 attr->setAttribute ("name", name);
1789 std::string colorStr;
1790 UIViewCreator::colorToString (newColor, colorStr, nullptr);
1791 attr->setAttribute ("rgba", colorStr);
1792 UIColorNode* node = new UIColorNode ("color", attr);
1793 colorsNode->getChildren ().add (node);
1794 colorsNode->sortChildren ();
1795 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1796 l->onUIDescColorChanged (this);
1797 });
1798 }
1799 }
1800 }
1801
1802 //-----------------------------------------------------------------------------
changeFont(UTF8StringPtr name,CFontRef newFont)1803 void UIDescription::changeFont (UTF8StringPtr name, CFontRef newFont)
1804 {
1805 UINode* fontsNode = getBaseNode (MainNodeNames::kFont);
1806 UIFontNode* node = dynamic_cast<UIFontNode*> (findChildNodeByNameAttribute (fontsNode, name));
1807 if (node)
1808 {
1809 if (!node->noExport ())
1810 {
1811 node->setFont (newFont);
1812 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1813 l->onUIDescFontChanged (this);
1814 });
1815 }
1816 }
1817 else
1818 {
1819 if (fontsNode)
1820 {
1821 auto attr = makeOwned<UIAttributes> ();
1822 attr->setAttribute ("name", name);
1823 UIFontNode* node = new UIFontNode ("font", attr);
1824 node->setFont (newFont);
1825 fontsNode->getChildren ().add (node);
1826 fontsNode->sortChildren ();
1827 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1828 l->onUIDescFontChanged (this);
1829 });
1830 }
1831 }
1832 }
1833
1834 //-----------------------------------------------------------------------------
changeGradient(UTF8StringPtr name,CGradient * newGradient)1835 void UIDescription::changeGradient (UTF8StringPtr name, CGradient* newGradient)
1836 {
1837 UINode* gradientsNode = getBaseNode (MainNodeNames::kGradient);
1838 UIGradientNode* node = dynamic_cast<UIGradientNode*> (findChildNodeByNameAttribute (gradientsNode, name));
1839 if (node)
1840 {
1841 if (!node->noExport ())
1842 {
1843 node->setGradient (newGradient);
1844 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1845 l->onUIDescGradientChanged (this);
1846 });
1847 }
1848 }
1849 else
1850 {
1851 if (gradientsNode)
1852 {
1853 auto attr = makeOwned<UIAttributes> ();
1854 attr->setAttribute ("name", name);
1855 UIGradientNode* node = new UIGradientNode ("gradient", attr);
1856 node->setGradient (newGradient);
1857 gradientsNode->getChildren ().add (node);
1858 gradientsNode->sortChildren ();
1859 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1860 l->onUIDescGradientChanged (this);
1861 });
1862 }
1863 }
1864 }
1865
1866 //-----------------------------------------------------------------------------
changeBitmap(UTF8StringPtr name,UTF8StringPtr newName,const CRect * nineparttiledOffset)1867 void UIDescription::changeBitmap (UTF8StringPtr name, UTF8StringPtr newName, const CRect* nineparttiledOffset)
1868 {
1869 UINode* bitmapsNode = getBaseNode (MainNodeNames::kBitmap);
1870 UIBitmapNode* node = dynamic_cast<UIBitmapNode*> (findChildNodeByNameAttribute (bitmapsNode, name));
1871 if (node)
1872 {
1873 if (!node->noExport ())
1874 {
1875 node->setBitmap (newName);
1876 node->setNinePartTiledOffset (nineparttiledOffset);
1877 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1878 l->onUIDescBitmapChanged (this);
1879 });
1880 }
1881 }
1882 else
1883 {
1884 if (bitmapsNode)
1885 {
1886 auto attr = makeOwned<UIAttributes> ();
1887 attr->setAttribute ("name", name);
1888 UIBitmapNode* node = new UIBitmapNode ("bitmap", attr);
1889 if (nineparttiledOffset)
1890 node->setNinePartTiledOffset (nineparttiledOffset);
1891 node->setBitmap (newName);
1892 bitmapsNode->getChildren ().add (node);
1893 bitmapsNode->sortChildren ();
1894 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1895 l->onUIDescBitmapChanged (this);
1896 });
1897 }
1898 }
1899 }
1900
1901 //-----------------------------------------------------------------------------
changeBitmapFilters(UTF8StringPtr bitmapName,const std::list<SharedPointer<UIAttributes>> & filters)1902 void UIDescription::changeBitmapFilters (UTF8StringPtr bitmapName, const std::list<SharedPointer<UIAttributes> >& filters)
1903 {
1904 UIBitmapNode* bitmapNode = dynamic_cast<UIBitmapNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kBitmap), bitmapName));
1905 if (bitmapNode)
1906 {
1907 bitmapNode->getChildren().removeAll ();
1908 for (const auto& filter : filters)
1909 {
1910 const std::string* filterName = filter->getAttributeValue ("name");
1911 if (filterName == nullptr)
1912 continue;
1913 UINode* filterNode = new UINode ("filter");
1914 filterNode->getAttributes ()->setAttribute ("name", *filterName);
1915 for (auto& it2 : *filter)
1916 {
1917 if (it2.first == "name")
1918 continue;
1919 UINode* propertyNode = new UINode ("property");
1920 propertyNode->getAttributes ()->setAttribute("name", it2.first);
1921 propertyNode->getAttributes ()->setAttribute("value", it2.second);
1922 filterNode->getChildren ().add (propertyNode);
1923 }
1924 bitmapNode->getChildren ().add (filterNode);
1925 }
1926 bitmapNode->invalidBitmap ();
1927 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1928 l->onUIDescBitmapChanged (this);
1929 });
1930 }
1931 }
1932
1933 //-----------------------------------------------------------------------------
collectBitmapFilters(UTF8StringPtr bitmapName,std::list<SharedPointer<UIAttributes>> & filters) const1934 void UIDescription::collectBitmapFilters (UTF8StringPtr bitmapName, std::list<SharedPointer<UIAttributes> >& filters) const
1935 {
1936 UIBitmapNode* bitmapNode = dynamic_cast<UIBitmapNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kBitmap), bitmapName));
1937 if (bitmapNode)
1938 {
1939 for (auto& childNode : bitmapNode->getChildren ())
1940 {
1941 if (childNode->getName () == "filter")
1942 {
1943 const std::string* filterName = childNode->getAttributes ()->getAttributeValue ("name");
1944 if (filterName == nullptr)
1945 continue;
1946 auto attributes = makeOwned<UIAttributes> ();
1947 attributes->setAttribute ("name", *filterName);
1948 for (auto& it2 : childNode->getChildren ())
1949 {
1950 if (it2->getName () == "property")
1951 {
1952 const std::string* name = it2->getAttributes ()->getAttributeValue ("name");
1953 const std::string* value = it2->getAttributes ()->getAttributeValue ("value");
1954 if (name && value)
1955 {
1956 attributes->setAttribute (*name, *value);
1957 }
1958 }
1959 }
1960 filters.emplace_back (attributes);
1961 }
1962 }
1963 }
1964 }
1965
1966 //-----------------------------------------------------------------------------
removeChildNode(UINode * baseNode,UTF8StringPtr nodeName)1967 static void removeChildNode (UINode* baseNode, UTF8StringPtr nodeName)
1968 {
1969 UIDescList& children = baseNode->getChildren ();
1970 for (const auto& itNode : children)
1971 {
1972 const std::string* name = itNode->getAttributes ()->getAttributeValue ("name");
1973 if (name && *name == nodeName)
1974 {
1975 if (!itNode->noExport ())
1976 children.remove (itNode);
1977 return;
1978 }
1979 }
1980 }
1981
1982 //-----------------------------------------------------------------------------
removeNode(UTF8StringPtr name,IdStringPtr mainNodeName)1983 void UIDescription::removeNode (UTF8StringPtr name, IdStringPtr mainNodeName)
1984 {
1985 UINode* node = getBaseNode (mainNodeName);
1986 if (node)
1987 {
1988 removeChildNode (node, name);
1989 }
1990 }
1991
1992 //-----------------------------------------------------------------------------
removeColor(UTF8StringPtr name)1993 void UIDescription::removeColor (UTF8StringPtr name)
1994 {
1995 removeNode (name, MainNodeNames::kColor);
1996 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
1997 l->onUIDescColorChanged (this);
1998 });
1999 }
2000
2001 //-----------------------------------------------------------------------------
removeTag(UTF8StringPtr name)2002 void UIDescription::removeTag (UTF8StringPtr name)
2003 {
2004 removeNode (name, MainNodeNames::kControlTag);
2005 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2006 l->onUIDescTagChanged (this);
2007 });
2008 }
2009
2010 //-----------------------------------------------------------------------------
removeFont(UTF8StringPtr name)2011 void UIDescription::removeFont (UTF8StringPtr name)
2012 {
2013 removeNode (name, MainNodeNames::kFont);
2014 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2015 l->onUIDescFontChanged (this);
2016 });
2017 }
2018
2019 //-----------------------------------------------------------------------------
removeBitmap(UTF8StringPtr name)2020 void UIDescription::removeBitmap (UTF8StringPtr name)
2021 {
2022 removeNode (name, MainNodeNames::kBitmap);
2023 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2024 l->onUIDescBitmapChanged (this);
2025 });
2026 }
2027
2028 //-----------------------------------------------------------------------------
removeGradient(UTF8StringPtr name)2029 void UIDescription::removeGradient (UTF8StringPtr name)
2030 {
2031 removeNode (name, MainNodeNames::kGradient);
2032 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2033 l->onUIDescGradientChanged (this);
2034 });
2035 }
2036
2037 //-----------------------------------------------------------------------------
changeAlternativeFontNames(UTF8StringPtr name,UTF8StringPtr alternativeFonts)2038 void UIDescription::changeAlternativeFontNames (UTF8StringPtr name, UTF8StringPtr alternativeFonts)
2039 {
2040 UIFontNode* node = dynamic_cast<UIFontNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kFont), name));
2041 if (node)
2042 {
2043 node->setAlternativeFontNames (alternativeFonts);
2044 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2045 l->onUIDescFontChanged (this);
2046 });
2047 }
2048 }
2049
2050 //-----------------------------------------------------------------------------
getAlternativeFontNames(UTF8StringPtr name,std::string & alternativeFonts) const2051 bool UIDescription::getAlternativeFontNames (UTF8StringPtr name, std::string& alternativeFonts) const
2052 {
2053 UIFontNode* node = dynamic_cast<UIFontNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kFont), name));
2054 if (node)
2055 {
2056 if (node->getAlternativeFontNames (alternativeFonts))
2057 return true;
2058 }
2059 return false;
2060 }
2061
2062 //-----------------------------------------------------------------------------
collectTemplateViewNames(std::list<const std::string * > & names) const2063 void UIDescription::collectTemplateViewNames (std::list<const std::string*>& names) const
2064 {
2065 if (!impl->nodes)
2066 return;
2067 for (const auto& itNode : impl->nodes->getChildren ())
2068 {
2069 if (itNode->getName () == MainNodeNames::kTemplate)
2070 {
2071 const std::string* nodeName = itNode->getAttributes ()->getAttributeValue ("name");
2072 if (nodeName)
2073 names.emplace_back (nodeName);
2074 }
2075 }
2076 }
2077
2078 //-----------------------------------------------------------------------------
collectNamesFromNode(IdStringPtr mainNodeName,std::list<const std::string * > & names) const2079 template<typename NodeType> void UIDescription::collectNamesFromNode (IdStringPtr mainNodeName, std::list<const std::string*>& names) const
2080 {
2081 UINode* node = getBaseNode (mainNodeName);
2082 if (node)
2083 {
2084 UIDescList& children = node->getChildren ();
2085 for (const auto& itNode : children)
2086 {
2087 NodeType* node = dynamic_cast<NodeType*>(itNode);
2088 if (node)
2089 {
2090 const std::string* name = node->getAttributes ()->getAttributeValue ("name");
2091 if (name)
2092 names.emplace_back (name);
2093 }
2094 }
2095 }
2096 }
2097
2098 //-----------------------------------------------------------------------------
collectColorNames(std::list<const std::string * > & names) const2099 void UIDescription::collectColorNames (std::list<const std::string*>& names) const
2100 {
2101 collectNamesFromNode<UIColorNode> (MainNodeNames::kColor, names);
2102 }
2103
2104 //-----------------------------------------------------------------------------
collectFontNames(std::list<const std::string * > & names) const2105 void UIDescription::collectFontNames (std::list<const std::string*>& names) const
2106 {
2107 collectNamesFromNode<UIFontNode> (MainNodeNames::kFont, names);
2108 }
2109
2110 //-----------------------------------------------------------------------------
collectBitmapNames(std::list<const std::string * > & names) const2111 void UIDescription::collectBitmapNames (std::list<const std::string*>& names) const
2112 {
2113 collectNamesFromNode<UIBitmapNode> (MainNodeNames::kBitmap, names);
2114 }
2115
2116 //-----------------------------------------------------------------------------
collectGradientNames(std::list<const std::string * > & names) const2117 void UIDescription::collectGradientNames (std::list<const std::string*>& names) const
2118 {
2119 collectNamesFromNode<UIGradientNode> (MainNodeNames::kGradient, names);
2120 }
2121
2122 //-----------------------------------------------------------------------------
collectControlTagNames(std::list<const std::string * > & names) const2123 void UIDescription::collectControlTagNames (std::list<const std::string*>& names) const
2124 {
2125 collectNamesFromNode<UIControlTagNode> (MainNodeNames::kControlTag, names);
2126 }
2127
2128 //-----------------------------------------------------------------------------
updateAttributesForView(UINode * node,CView * view,bool deep)2129 bool UIDescription::updateAttributesForView (UINode* node, CView* view, bool deep)
2130 {
2131 bool result = false;
2132 #if VSTGUI_LIVE_EDITING
2133 UIViewFactory* factory = dynamic_cast<UIViewFactory*> (impl->viewFactory);
2134 std::list<std::string> attributeNames;
2135 CViewContainer* container = view->asViewContainer ();
2136 if (factory->getAttributeNamesForView (view, attributeNames))
2137 {
2138 for (auto& name : attributeNames)
2139 {
2140 std::string value;
2141 if (factory->getAttributeValue (view, name, value, this))
2142 node->getAttributes ()->setAttribute (name, std::move (value));
2143 }
2144 node->getAttributes ()->setAttribute (UIViewCreator::kAttrClass, factory->getViewName (view));
2145 result = true;
2146 }
2147 if (deep && container)
2148 {
2149 ViewIterator it (container);
2150 while (*it)
2151 {
2152 CView* subView = *it;
2153 std::string subTemplateName;
2154 if (getTemplateNameFromView (subView, subTemplateName))
2155 {
2156 auto attr = makeOwned<UIAttributes> ();
2157 attr->setAttribute (MainNodeNames::kTemplate, subTemplateName);
2158 UINode* subNode = new UINode ("view", attr);
2159 node->getChildren ().add (subNode);
2160 updateAttributesForView (subNode, subView, false);
2161 CRect r = subView->getViewSize ();
2162 CRect r2 (r);
2163 r.offset (-r.left, -r.top);
2164 subView->setViewSize (r);
2165 subView->setMouseableArea (r);
2166 updateViewDescription (subTemplateName.c_str (), subView);
2167 subView->setViewSize (r2);
2168 subView->setMouseableArea (r2);
2169 }
2170 else
2171 {
2172 // check if subview is created via UIDescription
2173 // if it is, it's just added to this node
2174 UINode* subNode = new UINode ("view");
2175 if (updateAttributesForView (subNode, subView))
2176 {
2177 node->getChildren ().add (subNode);
2178 }
2179 else
2180 {
2181 // if it is not, we check if it has children. This can happen per example for a CScrollView for its container view.
2182 if (!subNode->getChildren ().empty ())
2183 {
2184 for (auto& childNode : subNode->getChildren ())
2185 {
2186 childNode->remember ();
2187 node->getChildren ().add (childNode);
2188 }
2189 }
2190 subNode->forget ();
2191 }
2192 }
2193 ++it;
2194 }
2195 }
2196 #endif
2197 return result;
2198 }
2199
2200 //-----------------------------------------------------------------------------
updateViewDescription(UTF8StringPtr name,CView * view)2201 void UIDescription::updateViewDescription (UTF8StringPtr name, CView* view)
2202 {
2203 #if VSTGUI_LIVE_EDITING
2204 bool doIt = true;
2205 impl->listeners.forEach ([&] (UIDescriptionListener* l) {
2206 if (!l->doUIDescTemplateUpdate (this, name))
2207 doIt = false;
2208 });
2209 if (!doIt)
2210 return;
2211
2212 UIViewFactory* factory = dynamic_cast<UIViewFactory*> (impl->viewFactory);
2213 if (factory && impl->nodes)
2214 {
2215 UINode* node = nullptr;
2216 for (auto& childNode : impl->nodes->getChildren ())
2217 {
2218 if (childNode->getName () == MainNodeNames::kTemplate)
2219 {
2220 const std::string* nodeName = childNode->getAttributes ()->getAttributeValue ("name");
2221 if (*nodeName == name)
2222 {
2223 node = childNode;
2224 break;
2225 }
2226 }
2227 }
2228 if (node == nullptr)
2229 {
2230 node = new UINode (MainNodeNames::kTemplate);
2231 }
2232 node->getChildren ().removeAll ();
2233 updateAttributesForView (node, view);
2234 }
2235 #endif
2236 }
2237
2238 //-----------------------------------------------------------------------------
addNewTemplate(UTF8StringPtr name,const SharedPointer<UIAttributes> & attr)2239 bool UIDescription::addNewTemplate (UTF8StringPtr name, const SharedPointer<UIAttributes>& attr)
2240 {
2241 #if VSTGUI_LIVE_EDITING
2242 vstgui_assert (impl->nodes);
2243 UINode* templateNode = findChildNodeByNameAttribute (impl->nodes, name);
2244 if (templateNode == nullptr)
2245 {
2246 UINode* newNode = new UINode (MainNodeNames::kTemplate, attr);
2247 attr->setAttribute ("name", name);
2248 impl->nodes->getChildren ().add (newNode);
2249 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2250 l->onUIDescTemplateChanged (this);
2251 });
2252 return true;
2253 }
2254 #endif
2255 return false;
2256 }
2257
2258 //-----------------------------------------------------------------------------
removeTemplate(UTF8StringPtr name)2259 bool UIDescription::removeTemplate (UTF8StringPtr name)
2260 {
2261 #if VSTGUI_LIVE_EDITING
2262 UINode* templateNode = findChildNodeByNameAttribute (impl->nodes, name);
2263 if (templateNode)
2264 {
2265 impl->nodes->getChildren ().remove (templateNode);
2266 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2267 l->onUIDescTemplateChanged (this);
2268 });
2269 return true;
2270 }
2271 #endif
2272 return false;
2273 }
2274
2275 //-----------------------------------------------------------------------------
changeTemplateName(UTF8StringPtr name,UTF8StringPtr newName)2276 bool UIDescription::changeTemplateName (UTF8StringPtr name, UTF8StringPtr newName)
2277 {
2278 #if VSTGUI_LIVE_EDITING
2279 UINode* templateNode = findChildNodeByNameAttribute (impl->nodes, name);
2280 if (templateNode)
2281 {
2282 templateNode->getAttributes()->setAttribute ("name", newName);
2283 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2284 l->onUIDescTemplateChanged (this);
2285 });
2286 return true;
2287 }
2288 #endif
2289 return false;
2290 }
2291
2292 //-----------------------------------------------------------------------------
duplicateTemplate(UTF8StringPtr name,UTF8StringPtr duplicateName)2293 bool UIDescription::duplicateTemplate (UTF8StringPtr name, UTF8StringPtr duplicateName)
2294 {
2295 #if VSTGUI_LIVE_EDITING
2296 UINode* templateNode = findChildNodeByNameAttribute (impl->nodes, name);
2297 if (templateNode)
2298 {
2299 UINode* duplicate = new UINode (*templateNode);
2300 vstgui_assert (duplicate);
2301 if (duplicate)
2302 {
2303 duplicate->getAttributes()->setAttribute ("name", duplicateName);
2304 impl->nodes->getChildren ().add (duplicate);
2305 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2306 l->onUIDescTemplateChanged (this);
2307 });
2308 return true;
2309 }
2310 }
2311 #endif
2312 return false;
2313 }
2314
2315 //-----------------------------------------------------------------------------
setCustomAttributes(UTF8StringPtr name,const SharedPointer<UIAttributes> & attr)2316 bool UIDescription::setCustomAttributes (UTF8StringPtr name, const SharedPointer<UIAttributes>& attr)
2317 {
2318 UINode* customNode = findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kCustom), name);
2319 if (customNode)
2320 return false;
2321 UINode* parent = getBaseNode (MainNodeNames::kCustom);
2322 vstgui_assert (parent != nullptr);
2323 attr->setAttribute ("name", name);
2324 customNode = new UINode ("attributes", attr);
2325 parent->getChildren ().add (customNode);
2326 return true;
2327 }
2328
2329 //-----------------------------------------------------------------------------
getCustomAttributes(UTF8StringPtr name) const2330 SharedPointer<UIAttributes> UIDescription::getCustomAttributes (UTF8StringPtr name) const
2331 {
2332 auto node = findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kCustom), name);
2333 return node ? node->getAttributes () : nullptr;
2334 }
2335
2336 //-----------------------------------------------------------------------------
getCustomAttributes(UTF8StringPtr name,bool create)2337 SharedPointer<UIAttributes> UIDescription::getCustomAttributes (UTF8StringPtr name, bool create)
2338 {
2339 auto attributes = getCustomAttributes (name);
2340 if (attributes)
2341 return attributes;
2342 if (create)
2343 {
2344 auto attributes = makeOwned<UIAttributes> ();
2345 if (setCustomAttributes (name, attributes))
2346 return attributes;
2347 }
2348 return nullptr;
2349 }
2350
2351 //-----------------------------------------------------------------------------
getFocusDrawingSettings() const2352 UIDescription::FocusDrawing UIDescription::getFocusDrawingSettings () const
2353 {
2354 FocusDrawing fd;
2355 auto attributes = getCustomAttributes ("FocusDrawing");
2356 if (attributes)
2357 {
2358 attributes->getBooleanAttribute ("enabled", fd.enabled);
2359 attributes->getDoubleAttribute ("width", fd.width);
2360 if (auto colorAttr = attributes->getAttributeValue ("color"))
2361 fd.colorName = *colorAttr;
2362 }
2363 return fd;
2364 }
2365
2366 //-----------------------------------------------------------------------------
setFocusDrawingSettings(const FocusDrawing & fd)2367 void UIDescription::setFocusDrawingSettings (const FocusDrawing& fd)
2368 {
2369 auto attributes = getCustomAttributes ("FocusDrawing", true);
2370 if (!attributes)
2371 return;
2372 attributes->setBooleanAttribute ("enabled", fd.enabled);
2373 attributes->setDoubleAttribute ("width", fd.width);
2374 attributes->setAttribute ("color", fd.colorName.getString ());
2375 }
2376
2377 //-----------------------------------------------------------------------------
getControlTagString(UTF8StringPtr tagName,std::string & tagString) const2378 bool UIDescription::getControlTagString (UTF8StringPtr tagName, std::string& tagString) const
2379 {
2380 UIControlTagNode* controlTagNode = dynamic_cast<UIControlTagNode*> (findChildNodeByNameAttribute (getBaseNode (MainNodeNames::kControlTag), tagName));
2381 if (controlTagNode)
2382 {
2383 const std::string* tagStr = controlTagNode->getTagString ();
2384 if (tagStr)
2385 {
2386 tagString = *tagStr;
2387 return true;
2388 }
2389 }
2390 return false;
2391 }
2392
2393 //-----------------------------------------------------------------------------
changeControlTagString(UTF8StringPtr tagName,const std::string & newTagString,bool create)2394 bool UIDescription::changeControlTagString (UTF8StringPtr tagName, const std::string& newTagString, bool create)
2395 {
2396 UINode* tagsNode = getBaseNode (MainNodeNames::kControlTag);
2397 UIControlTagNode* controlTagNode = dynamic_cast<UIControlTagNode*> (findChildNodeByNameAttribute (tagsNode, tagName));
2398 if (controlTagNode)
2399 {
2400 if (create)
2401 return false;
2402 controlTagNode->setTagString (newTagString);
2403 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2404 l->onUIDescTagChanged (this);
2405 });
2406 return true;
2407 }
2408 if (create)
2409 {
2410 if (tagsNode)
2411 {
2412 auto attr = makeOwned<UIAttributes> ();
2413 attr->setAttribute ("name", tagName);
2414 UIControlTagNode* node = new UIControlTagNode ("control-tag", attr);
2415 node->setTagString (newTagString);
2416 tagsNode->getChildren ().add (node);
2417 tagsNode->sortChildren ();
2418 impl->listeners.forEach ([this] (UIDescriptionListener* l) {
2419 l->onUIDescTagChanged (this);
2420 });
2421 return true;
2422 }
2423 }
2424 return false;
2425 }
2426
2427 //-----------------------------------------------------------------------------
getVariable(UTF8StringPtr name,double & value) const2428 bool UIDescription::getVariable (UTF8StringPtr name, double& value) const
2429 {
2430 UIVariableNode* node = dynamic_cast<UIVariableNode*> (findChildNodeByNameAttribute (impl->getVariableBaseNode (), name));
2431 if (node)
2432 {
2433 if (node->getType () == UIVariableNode::kNumber)
2434 {
2435 value = node->getNumber ();
2436 return true;
2437 }
2438 if (node->getType () == UIVariableNode::kString)
2439 {
2440 double v;
2441 if (calculateStringValue (node->getString ().c_str (), v))
2442 {
2443 value = v;
2444 return true;
2445 }
2446 }
2447 }
2448 return false;
2449 }
2450
2451 //-----------------------------------------------------------------------------
getVariable(UTF8StringPtr name,std::string & value) const2452 bool UIDescription::getVariable (UTF8StringPtr name, std::string& value) const
2453 {
2454 UIVariableNode* node = dynamic_cast<UIVariableNode*> (findChildNodeByNameAttribute (impl->getVariableBaseNode (), name));
2455 if (node)
2456 {
2457 value = node->getString ();
2458 return true;
2459 }
2460 return false;
2461 }
2462
2463 namespace UIDescriptionPrivate {
2464
2465 //-----------------------------------------------------------------------------
2466 struct Locale
2467 {
LocaleVSTGUI::UIDescriptionPrivate::Locale2468 Locale ()
2469 {
2470 origLocal = std::locale ();
2471 std::locale::global (std::locale::classic ());
2472 }
2473
~LocaleVSTGUI::UIDescriptionPrivate::Locale2474 ~Locale () noexcept
2475 {
2476 std::locale::global (origLocal);
2477 }
2478
2479 std::locale origLocal;
2480 };
2481
2482 //-----------------------------------------------------------------------------
2483 class StringToken : public std::string
2484 {
2485 public:
2486 enum Type {
2487 kString,
2488 kAdd,
2489 kSubtract,
2490 kMulitply,
2491 kDivide,
2492 kOpenParenthesis,
2493 kCloseParenthesis,
2494 kResult
2495 };
2496
StringToken(const std::string & str)2497 explicit StringToken (const std::string& str) : std::string (str), type (kString), result (0) {}
2498 StringToken (const StringToken& token) = default;
StringToken(Type type,double value=0)2499 StringToken (Type type, double value = 0) : type (type), result (value) {}
2500
2501 Type type;
2502 double result;
2503 };
2504
2505 using StringTokenList = std::list<StringToken>;
2506
2507 //-----------------------------------------------------------------------------
tokenizeString(std::string & str,StringTokenList & tokens)2508 static bool tokenizeString (std::string& str, StringTokenList& tokens)
2509 {
2510 UTF8CodePointIterator<std::string::const_iterator> start (str.begin ());
2511 UTF8CodePointIterator<std::string::const_iterator> end (str.end ());
2512 auto iterator = start;
2513 while (iterator != end)
2514 {
2515 auto codePoint = *iterator;
2516 if (isspace (codePoint))
2517 {
2518 if (start != iterator)
2519 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2520 start = iterator;
2521 ++start;
2522 }
2523 else
2524 {
2525 switch (codePoint)
2526 {
2527 case '+':
2528 {
2529 if (start != iterator)
2530 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2531 tokens.emplace_back (StringToken::kAdd);
2532 start = iterator;
2533 ++start;
2534 break;
2535 }
2536 case '-':
2537 {
2538 if (start != iterator)
2539 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2540 tokens.emplace_back (StringToken::kSubtract);
2541 start = iterator;
2542 ++start;
2543 break;
2544 }
2545 case '*':
2546 {
2547 if (start != iterator)
2548 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2549 tokens.emplace_back (StringToken::kMulitply);
2550 start = iterator;
2551 ++start;
2552 break;
2553 }
2554 case '/':
2555 {
2556 if (start != iterator)
2557 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2558 tokens.emplace_back (StringToken::kDivide);
2559 start = iterator;
2560 ++start;
2561 break;
2562 }
2563 case '(':
2564 {
2565 if (start != iterator)
2566 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2567 tokens.emplace_back (StringToken::kOpenParenthesis);
2568 start = iterator;
2569 ++start;
2570 break;
2571 }
2572 case ')':
2573 {
2574 if (start != iterator)
2575 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2576 tokens.emplace_back (StringToken::kCloseParenthesis);
2577 start = iterator;
2578 ++start;
2579 break;
2580 }
2581 }
2582 }
2583 ++iterator;
2584 }
2585 if (start != iterator)
2586 tokens.emplace_back (std::string {start.base (), iterator.base ()});
2587 return true;
2588 }
2589
2590 //-----------------------------------------------------------------------------
computeTokens(StringTokenList & tokens,double & result)2591 static bool computeTokens (StringTokenList& tokens, double& result)
2592 {
2593 int32_t openCount = 0;
2594 StringTokenList::iterator openPosition = tokens.end ();
2595 // first check parentheses
2596 for (StringTokenList::iterator it = tokens.begin (); it != tokens.end (); ++it)
2597 {
2598 if ((*it).type == StringToken::kOpenParenthesis)
2599 {
2600 openCount++;
2601 if (openCount == 1)
2602 openPosition = it;
2603 }
2604 else if ((*it).type == StringToken::kCloseParenthesis)
2605 {
2606 openCount--;
2607 if (openCount == 0)
2608 {
2609 StringTokenList tmp (++openPosition, it);
2610 double value = 0;
2611 if (computeTokens (tmp, value))
2612 {
2613 --openPosition;
2614 ++it;
2615 tokens.erase (openPosition, it);
2616 tokens.insert (it, StringToken (StringToken::kResult, value));
2617 if (it == tokens.end ())
2618 {
2619 break;
2620 }
2621
2622 }
2623 else
2624 return false;
2625 }
2626 }
2627 }
2628 // now multiply and divide
2629 StringTokenList::iterator prevToken = tokens.begin ();
2630 for (StringTokenList::iterator it = tokens.begin (); it != tokens.end (); ++it)
2631 {
2632 if (prevToken != it)
2633 {
2634 if ((*it).type == StringToken::kMulitply)
2635 {
2636 if ((*prevToken).type == StringToken::kResult)
2637 {
2638 ++it;
2639 if ((*it).type == StringToken::kResult)
2640 {
2641 double value = (*prevToken).result * (*it).result;
2642 ++it;
2643 tokens.erase (prevToken, it);
2644 tokens.insert (it, StringToken (StringToken::kResult, value));
2645 --it;
2646 prevToken = it;
2647 }
2648 else
2649 {
2650 return false;
2651 }
2652 }
2653 else
2654 {
2655 return false;
2656 }
2657 }
2658 else if ((*it).type == StringToken::kDivide)
2659 {
2660 if ((*prevToken).type == StringToken::kResult)
2661 {
2662 ++it;
2663 if ((*it).type == StringToken::kResult)
2664 {
2665 double value = (*prevToken).result / (*it).result;
2666 ++it;
2667 tokens.erase (prevToken, it);
2668 tokens.insert (it, StringToken (StringToken::kResult, value));
2669 --it;
2670 prevToken = it;
2671 }
2672 else
2673 {
2674 return false;
2675 }
2676 }
2677 else
2678 {
2679 return false;
2680 }
2681 }
2682 else
2683 {
2684 prevToken = it;
2685 }
2686 }
2687 }
2688 // now add and subtract
2689 int32_t lastType = -1;
2690 for (StringTokenList::const_iterator it = tokens.begin (); it != tokens.end (); ++it)
2691 {
2692 if ((*it).type == UIDescriptionPrivate::StringToken::kResult)
2693 {
2694 double value = (*it).result;
2695 if (lastType == -1)
2696 result = value;
2697 else if (lastType == StringToken::kAdd)
2698 result += value;
2699 else if (lastType == StringToken::kSubtract)
2700 result -= value;
2701 else
2702 {
2703 #if DEBUG
2704 DebugPrint ("Wrong Expression: %d\n", (*it).type);
2705 #endif
2706 return false;
2707 }
2708 }
2709 else if (!(lastType == -1 || lastType == UIDescriptionPrivate::StringToken::kResult))
2710 {
2711 #if DEBUG
2712 DebugPrint ("Wrong Expression: %d\n", (*it).type);
2713 #endif
2714 return false;
2715 }
2716 lastType = (*it).type;
2717
2718 }
2719 return true;
2720 }
2721
2722 } // namespace UIDescriptionPrivate
2723
2724 //-----------------------------------------------------------------------------
calculateStringValue(UTF8StringPtr _str,double & result) const2725 bool UIDescription::calculateStringValue (UTF8StringPtr _str, double& result) const
2726 {
2727 UIDescriptionPrivate::Locale localeResetter;
2728
2729 char* endPtr = nullptr;
2730 result = strtod (_str, &endPtr);
2731 if (endPtr == _str + strlen (_str))
2732 return true;
2733 std::string str (_str);
2734 UIDescriptionPrivate::StringTokenList tokens;
2735 if (!UIDescriptionPrivate::tokenizeString (str, tokens))
2736 {
2737 #if DEBUG
2738 DebugPrint("TokenizeString failed :%s\n", _str);
2739 #endif
2740 return false;
2741 }
2742 // first make substituation
2743 for (auto& token : tokens)
2744 {
2745 if (token.type == UIDescriptionPrivate::StringToken::kString)
2746 {
2747 const char* tokenStr = token.c_str ();
2748 double value = strtod (tokenStr, &endPtr);
2749 if (endPtr != tokenStr + token.length ())
2750 {
2751 // if it is not pure numeric try to substitute the string with a control tag or variable
2752 if (token.find ("tag.") == 0)
2753 {
2754 value = getTagForName (token.c_str () + 4);
2755 if (value == -1)
2756 {
2757 #if DEBUG
2758 DebugPrint("Tag not found :%s\n", tokenStr);
2759 #endif
2760 return false;
2761 }
2762 }
2763 else if (token.find ("var.") == 0)
2764 {
2765 double v;
2766 if (getVariable (token.c_str () + 4, v))
2767 {
2768 value = v;
2769 }
2770 else
2771 {
2772 #if DEBUG
2773 DebugPrint("Variable not found :%s\n", tokenStr);
2774 #endif
2775 return false;
2776 }
2777 }
2778 else
2779 {
2780 #if DEBUG
2781 DebugPrint("Substitution failed :%s\n", tokenStr);
2782 #endif
2783 return false;
2784 }
2785 }
2786 token.result = value;
2787 token.type = UIDescriptionPrivate::StringToken::kResult;
2788 }
2789 }
2790 result = 0;
2791 return UIDescriptionPrivate::computeTokens (tokens, result);
2792 }
2793
2794 //-----------------------------------------------------------------------------
startXmlElement(Xml::Parser * parser,IdStringPtr elementName,UTF8StringPtr * elementAttributes)2795 void UIDescription::startXmlElement (Xml::Parser* parser, IdStringPtr elementName, UTF8StringPtr* elementAttributes)
2796 {
2797 std::string name (elementName);
2798 if (impl->nodes)
2799 {
2800 UINode* parent = impl->nodeStack.back ();
2801 UINode* newNode = nullptr;
2802 if (impl->restoreViewsMode)
2803 {
2804 if (name != "view" && name != MainNodeNames::kCustom)
2805 {
2806 parser->stop ();
2807 }
2808 newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes));
2809 }
2810 else
2811 {
2812 if (parent == impl->nodes)
2813 {
2814 // only allowed second level elements
2815 if (name == MainNodeNames::kControlTag || name == MainNodeNames::kColor || name == MainNodeNames::kBitmap)
2816 newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes), true);
2817 else if (name == MainNodeNames::kFont || name == MainNodeNames::kTemplate
2818 || name == MainNodeNames::kControlTag || name == MainNodeNames::kCustom
2819 || name == MainNodeNames::kVariable || name == MainNodeNames::kGradient)
2820 newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes));
2821 else
2822 parser->stop ();
2823 }
2824 else if (parent->getName () == MainNodeNames::kBitmap)
2825 {
2826 if (name == "bitmap")
2827 newNode = new UIBitmapNode (name, makeOwned<UIAttributes> (elementAttributes));
2828 else
2829 parser->stop ();
2830 }
2831 else if (parent->getName () == MainNodeNames::kFont)
2832 {
2833 if (name == "font")
2834 newNode = new UIFontNode (name, makeOwned<UIAttributes> (elementAttributes));
2835 else
2836 parser->stop ();
2837 }
2838 else if (parent->getName () == MainNodeNames::kColor)
2839 {
2840 if (name == "color")
2841 newNode = new UIColorNode (name, makeOwned<UIAttributes> (elementAttributes));
2842 else
2843 parser->stop ();
2844 }
2845 else if (parent->getName () == MainNodeNames::kControlTag)
2846 {
2847 if (name == "control-tag")
2848 newNode = new UIControlTagNode (name, makeOwned<UIAttributes> (elementAttributes));
2849 else
2850 parser->stop ();
2851 }
2852 else if (parent->getName () == MainNodeNames::kVariable)
2853 {
2854 if (name == "var")
2855 newNode = new UIVariableNode (name, makeOwned<UIAttributes> (elementAttributes));
2856 else
2857 parser->stop ();
2858 }
2859 else if (parent->getName () == MainNodeNames::kGradient)
2860 {
2861 if (name == "gradient")
2862 newNode = new UIGradientNode (name, makeOwned<UIAttributes> (elementAttributes));
2863 else
2864 parser->stop ();
2865 }
2866 else
2867 newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes));
2868 }
2869 if (newNode)
2870 {
2871 parent->getChildren ().add (newNode);
2872 impl->nodeStack.emplace_back (newNode);
2873 }
2874 }
2875 else if (name == "vstgui-ui-description")
2876 {
2877 impl->nodes = makeOwned<UINode> (name, makeOwned<UIAttributes> (elementAttributes));
2878 impl->nodeStack.emplace_back (impl->nodes);
2879 }
2880 else if (name == "vstgui-ui-description-view-list")
2881 {
2882 vstgui_assert (impl->nodes == nullptr);
2883 impl->nodes = makeOwned<UINode> (name, makeOwned<UIAttributes> (elementAttributes));
2884 impl->nodeStack.emplace_back (impl->nodes);
2885 impl->restoreViewsMode = true;
2886 }
2887 }
2888
2889 //-----------------------------------------------------------------------------
endXmlElement(Xml::Parser * parser,IdStringPtr name)2890 void UIDescription::endXmlElement (Xml::Parser* parser, IdStringPtr name)
2891 {
2892 if (impl->nodeStack.back () == impl->nodes)
2893 impl->restoreViewsMode = false;
2894 impl->nodeStack.pop_back ();
2895 }
2896
2897 //-----------------------------------------------------------------------------
xmlCharData(Xml::Parser * parser,const int8_t * data,int32_t length)2898 void UIDescription::xmlCharData (Xml::Parser* parser, const int8_t* data, int32_t length)
2899 {
2900 if (impl->nodeStack.size () == 0)
2901 return;
2902 auto& nodeData = impl->nodeStack.back ()->getData ();
2903 const int8_t* dataStart = nullptr;
2904 uint32_t validChars = 0;
2905 for (int32_t i = 0; i < length; i++, ++data)
2906 {
2907 if (*data < 0x21)
2908 {
2909 if (dataStart)
2910 {
2911 nodeData.append (reinterpret_cast<const char*> (dataStart), validChars);
2912 dataStart = nullptr;
2913 validChars = 0;
2914 }
2915 continue;
2916 }
2917 if (dataStart == nullptr)
2918 dataStart = data;
2919 ++validChars;
2920 }
2921 if (dataStart && validChars > 0)
2922 nodeData.append (reinterpret_cast<const char*> (dataStart), validChars);
2923 }
2924
2925 //-----------------------------------------------------------------------------
xmlComment(Xml::Parser * parser,IdStringPtr comment)2926 void UIDescription::xmlComment (Xml::Parser* parser, IdStringPtr comment)
2927 {
2928 #if VSTGUI_LIVE_EDITING
2929 if (impl->nodeStack.size () == 0)
2930 {
2931 #if DEBUG
2932 DebugPrint ("*** WARNING : Comment outside of root tag will be removed on save !\nComment: %s\n", comment);
2933 #endif
2934 return;
2935 }
2936 UINode* parent = impl->nodeStack.back ();
2937 if (parent && comment)
2938 {
2939 std::string commentStr (comment);
2940 if (!commentStr.empty ())
2941 {
2942 UICommentNode* commentNode = new UICommentNode (comment);
2943 parent->getChildren ().add (commentNode);
2944 }
2945 }
2946 #endif
2947 }
2948
2949 //-----------------------------------------------------------------------------
2950 //-----------------------------------------------------------------------------
2951 //-----------------------------------------------------------------------------
UINode(const std::string & _name,const SharedPointer<UIAttributes> & _attributes,bool needsFastChildNameAttributeLookup)2952 UINode::UINode (const std::string& _name, const SharedPointer<UIAttributes>& _attributes, bool needsFastChildNameAttributeLookup)
2953 : name (_name)
2954 , attributes (_attributes)
2955 , flags (0)
2956 {
2957 if (needsFastChildNameAttributeLookup)
2958 children = makeOwned<UIDescListWithFastFindAttributeNameChild> ();
2959 else
2960 children = makeOwned<UIDescList> ();
2961 if (attributes == nullptr)
2962 attributes = makeOwned<UIAttributes> ();
2963 }
2964
2965 //-----------------------------------------------------------------------------
UINode(const std::string & _name,const SharedPointer<UIDescList> & _children,const SharedPointer<UIAttributes> & _attributes)2966 UINode::UINode (const std::string& _name, const SharedPointer<UIDescList>& _children, const SharedPointer<UIAttributes>& _attributes)
2967 : name (_name)
2968 , attributes (_attributes)
2969 , children (_children)
2970 , flags (0)
2971 {
2972 vstgui_assert (children != nullptr);
2973 if (attributes == nullptr)
2974 attributes = makeOwned<UIAttributes> ();
2975 }
2976
2977 //-----------------------------------------------------------------------------
UINode(const UINode & n)2978 UINode::UINode (const UINode& n)
2979 : name (n.name)
2980 , data (n.data)
2981 , attributes (makeOwned<UIAttributes> (*n.attributes))
2982 , children (makeOwned<UIDescList> (*n.children))
2983 , flags (n.flags)
2984 {
2985 }
2986
2987 //-----------------------------------------------------------------------------
~UINode()2988 UINode::~UINode () noexcept
2989 {
2990 }
2991
2992 //-----------------------------------------------------------------------------
hasChildren() const2993 bool UINode::hasChildren () const
2994 {
2995 return !children->empty ();
2996 }
2997
2998 //-----------------------------------------------------------------------------
childAttributeChanged(UINode * child,const char * attributeName,const char * oldAttributeValue)2999 void UINode::childAttributeChanged (UINode* child, const char* attributeName, const char* oldAttributeValue)
3000 {
3001 children->nodeAttributeChanged (child, attributeName, oldAttributeValue);
3002 }
3003
3004 //-----------------------------------------------------------------------------
sortChildren()3005 void UINode::sortChildren ()
3006 {
3007 children->sort ();
3008 }
3009
3010 //-----------------------------------------------------------------------------
3011 //-----------------------------------------------------------------------------
3012 //-----------------------------------------------------------------------------
UICommentNode(const std::string & comment)3013 UICommentNode::UICommentNode (const std::string& comment)
3014 : UINode ("comment")
3015 {
3016 data = comment;
3017 }
3018
3019 //-----------------------------------------------------------------------------
3020 //-----------------------------------------------------------------------------
3021 //-----------------------------------------------------------------------------
UIVariableNode(const std::string & name,const SharedPointer<UIAttributes> & attributes)3022 UIVariableNode::UIVariableNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
3023 : UINode (name, attributes)
3024 , type (kUnknown)
3025 , number (0)
3026 {
3027 const std::string* typeStr = attributes->getAttributeValue ("type");
3028 const std::string* valueStr = attributes->getAttributeValue ("value");
3029 if (typeStr)
3030 {
3031 if (*typeStr == "number")
3032 type = kNumber;
3033 else if (*typeStr == "string")
3034 type = kString;
3035 }
3036 if (valueStr)
3037 {
3038 UIDescriptionPrivate::Locale localeResetter;
3039
3040 const char* strPtr = valueStr->c_str ();
3041 if (type == kUnknown)
3042 {
3043 char* endPtr = nullptr;
3044 double numberCheck = strtod (strPtr, &endPtr);
3045 if (endPtr == strPtr + strlen (strPtr))
3046 {
3047 number = numberCheck;
3048 type = kNumber;
3049 }
3050 else
3051 type = kString;
3052 }
3053 else if (type == kNumber)
3054 {
3055 number = strtod (strPtr, nullptr);
3056 }
3057 }
3058 }
3059
3060 //-----------------------------------------------------------------------------
getType() const3061 UIVariableNode::Type UIVariableNode::getType () const
3062 {
3063 return type;
3064 }
3065
3066 //-----------------------------------------------------------------------------
getNumber() const3067 double UIVariableNode::getNumber () const
3068 {
3069 return number;
3070 }
3071
3072 //-----------------------------------------------------------------------------
getString() const3073 const std::string& UIVariableNode::getString () const
3074 {
3075 const std::string* value = attributes->getAttributeValue ("value");
3076 if (value)
3077 return *value;
3078 static std::string kEmpty;
3079 return kEmpty;
3080 }
3081
3082 //-----------------------------------------------------------------------------
3083 //-----------------------------------------------------------------------------
3084 //-----------------------------------------------------------------------------
UIControlTagNode(const std::string & name,const SharedPointer<UIAttributes> & attributes)3085 UIControlTagNode::UIControlTagNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
3086 : UINode (name, attributes)
3087 , tag (-1)
3088 {
3089 }
3090
3091 //-----------------------------------------------------------------------------
getTag()3092 int32_t UIControlTagNode::getTag ()
3093 {
3094 if (tag == -1)
3095 {
3096 const std::string* tagStr = attributes->getAttributeValue ("tag");
3097 if (tagStr)
3098 {
3099 if (tagStr->size () == 6 && (*tagStr)[0] == '\'' && (*tagStr)[5] == '\'')
3100 {
3101 char c1 = (*tagStr)[1];
3102 char c2 = (*tagStr)[2];
3103 char c3 = (*tagStr)[3];
3104 char c4 = (*tagStr)[4];
3105 tag = ((((int32_t)c1) << 24) | (((int32_t)c2) << 16) | (((int32_t)c3) << 8) | (((int32_t)c4) << 0));
3106 }
3107 else
3108 {
3109 char* endPtr = nullptr;
3110 tag = (int32_t)strtol (tagStr->c_str (), &endPtr, 10);
3111 if (endPtr != tagStr->c_str () + tagStr->length ())
3112 tag = -1;
3113 }
3114 }
3115 }
3116 return tag;
3117 }
3118
3119 //-----------------------------------------------------------------------------
setTag(int32_t newTag)3120 void UIControlTagNode::setTag (int32_t newTag)
3121 {
3122 tag = newTag;
3123 }
3124
3125 //-----------------------------------------------------------------------------
getTagString() const3126 const std::string* UIControlTagNode::getTagString () const
3127 {
3128 return attributes->getAttributeValue ("tag");
3129 }
3130
3131 //-----------------------------------------------------------------------------
setTagString(const std::string & str)3132 void UIControlTagNode::setTagString (const std::string& str)
3133 {
3134 attributes->setAttribute ("tag", str);
3135 tag = -1;
3136 }
3137
3138 //-----------------------------------------------------------------------------
3139 //-----------------------------------------------------------------------------
3140 //-----------------------------------------------------------------------------
UIBitmapNode(const std::string & name,const SharedPointer<UIAttributes> & attributes)3141 UIBitmapNode::UIBitmapNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
3142 : UINode (name, attributes)
3143 , bitmap (nullptr)
3144 , filterProcessed (false)
3145 , scaledBitmapsAdded (false)
3146 {
3147 }
3148
3149 //-----------------------------------------------------------------------------
~UIBitmapNode()3150 UIBitmapNode::~UIBitmapNode () noexcept
3151 {
3152 if (bitmap)
3153 bitmap->forget ();
3154 }
3155
3156 //-----------------------------------------------------------------------------
freePlatformResources()3157 void UIBitmapNode::freePlatformResources ()
3158 {
3159 if (bitmap)
3160 bitmap->forget ();
3161 bitmap = nullptr;
3162 }
3163
3164 //-----------------------------------------------------------------------------
imagesEqual(IPlatformBitmap * b1,IPlatformBitmap * b2)3165 bool UIBitmapNode::imagesEqual (IPlatformBitmap* b1, IPlatformBitmap* b2)
3166 {
3167 if (b1 == b2)
3168 return true;
3169 if (b1->getSize () != b2->getSize () || b1->getScaleFactor () != b2->getScaleFactor ())
3170 return false;
3171 auto ac1 = b1->lockPixels (true);
3172 if (!ac1)
3173 return false;
3174 auto ac2 = b2->lockPixels (true);
3175 if (!ac2)
3176 return false;
3177 auto rowBytes = ac1->getBytesPerRow ();
3178 if (rowBytes != ac2->getBytesPerRow ())
3179 return false;
3180 if (ac1->getPixelFormat () != ac2->getPixelFormat ())
3181 return false;
3182 auto adr1 = ac1->getAddress ();
3183 if (!adr1)
3184 return false;
3185 auto adr2 = ac2->getAddress ();
3186 if (!adr2)
3187 return false;
3188 uint32_t rows = static_cast<uint32_t> (b1->getSize ().y);
3189 for (uint32_t y = 0; y < rows; ++y, adr1 += rowBytes, adr2 += rowBytes)
3190 {
3191 if (memcmp (adr1, adr2, rowBytes) != 0)
3192 return false;
3193 }
3194 return true;
3195 }
3196
3197 //-----------------------------------------------------------------------------
createXMLData(const std::string & pathHint)3198 void UIBitmapNode::createXMLData (const std::string& pathHint)
3199 {
3200 UINode* node = getChildren ().findChildNode ("data");
3201 if (node)
3202 {
3203 if (node->getData ().empty ())
3204 {
3205 getChildren ().remove (node);
3206 node = nullptr;
3207 }
3208 else if (auto bitmap = getBitmap (pathHint))
3209 {
3210 if (auto platformBitmap = bitmap->getPlatformBitmap ())
3211 {
3212 if (auto dataBitmap = createBitmapFromDataNode ())
3213 {
3214 if (!imagesEqual (platformBitmap, dataBitmap))
3215 {
3216 removeXMLData ();
3217 node = nullptr;
3218 }
3219 }
3220 }
3221 }
3222 }
3223 if (node == nullptr)
3224 {
3225 if (CBitmap* bitmap = getBitmap (pathHint))
3226 {
3227 if (auto platformBitmap = bitmap->getPlatformBitmap ())
3228 {
3229 auto buffer = IPlatformBitmap::createMemoryPNGRepresentation (platformBitmap);
3230 if (!buffer.empty ())
3231 {
3232 auto result = Base64Codec::encode (buffer.data(), static_cast<uint32_t> (buffer.size ()));
3233 UINode* dataNode = new UINode ("data");
3234 dataNode->getAttributes ()->setAttribute ("encoding", "base64");
3235 dataNode->getData ().append (reinterpret_cast<const char*> (result.data.get ()), static_cast<std::streamsize> (result.dataSize));
3236 getChildren ().add (dataNode);
3237 }
3238 }
3239 }
3240 }
3241 }
3242
3243 //-----------------------------------------------------------------------------
removeXMLData()3244 void UIBitmapNode::removeXMLData ()
3245 {
3246 UINode* node = getChildren ().findChildNode ("data");
3247 if (node)
3248 getChildren ().remove (node);
3249 }
3250
3251 //-----------------------------------------------------------------------------
createBitmap(const std::string & str,CNinePartTiledDescription * partDesc) const3252 CBitmap* UIBitmapNode::createBitmap (const std::string& str, CNinePartTiledDescription* partDesc) const
3253 {
3254 if (partDesc)
3255 return new CNinePartTiledBitmap (CResourceDescription (str.c_str()), *partDesc);
3256 return new CBitmap (CResourceDescription (str.c_str()));
3257 }
3258
3259 //------------------------------------------------------------------------
dataNode() const3260 UINode* UIBitmapNode::dataNode () const
3261 {
3262 UINode* node = getChildren ().findChildNode ("data");
3263 return (node && !node->getData ().empty ()) ? node : nullptr;
3264 }
3265
3266 //------------------------------------------------------------------------
createBitmapFromDataNode() const3267 SharedPointer<IPlatformBitmap> UIBitmapNode::createBitmapFromDataNode () const
3268 {
3269 if (auto node = dataNode ())
3270 {
3271 auto codecStr = node->getAttributes ()->getAttributeValue ("encoding");
3272 if (codecStr && *codecStr == "base64")
3273 {
3274 auto result = Base64Codec::decode (node->getData ());
3275 if (auto platformBitmap = IPlatformBitmap::createFromMemory (result.data.get (), result.dataSize))
3276 {
3277 double scaleFactor = 1.;
3278 if (attributes->getDoubleAttribute ("scale-factor", scaleFactor))
3279 platformBitmap->setScaleFactor (scaleFactor);
3280 return platformBitmap;
3281 }
3282 }
3283 }
3284 return nullptr;
3285 }
3286
3287 //-----------------------------------------------------------------------------
getBitmap(const std::string & pathHint)3288 CBitmap* UIBitmapNode::getBitmap (const std::string& pathHint)
3289 {
3290 if (bitmap == nullptr)
3291 {
3292 const std::string* path = attributes->getAttributeValue ("path");
3293 if (path)
3294 {
3295 CNinePartTiledDescription partDesc;
3296 CNinePartTiledDescription* partDescPtr = nullptr;
3297 CRect offsets;
3298 if (attributes->getRectAttribute ("nineparttiled-offsets", offsets))
3299 {
3300 partDesc = CNinePartTiledDescription (offsets.left, offsets.top, offsets.right, offsets.bottom);
3301 partDescPtr = &partDesc;
3302 }
3303 bitmap = createBitmap (*path, partDescPtr);
3304 if (bitmap->getPlatformBitmap () == nullptr && pathIsAbsolute (pathHint))
3305 {
3306 std::string absPath = pathHint;
3307 if (removeLastPathComponent (absPath))
3308 {
3309 absPath += "/" + *path;
3310 if (auto platformBitmap = IPlatformBitmap::createFromPath (absPath.c_str ()))
3311 bitmap->setPlatformBitmap (platformBitmap);
3312 }
3313 }
3314 }
3315 if (bitmap && bitmap->getPlatformBitmap () == nullptr)
3316 {
3317 if (auto platformBitmap = createBitmapFromDataNode ())
3318 bitmap->setPlatformBitmap (platformBitmap);
3319 }
3320 if (bitmap && path && bitmap->getPlatformBitmap () && bitmap->getPlatformBitmap ()->getScaleFactor () == 1.)
3321 {
3322 double scaleFactor = 1.;
3323 if (UIDescriptionPrivate::decodeScaleFactorFromName (*path, scaleFactor))
3324 {
3325 bitmap->getPlatformBitmap ()->setScaleFactor (scaleFactor);
3326 attributes->setDoubleAttribute ("scale-factor", scaleFactor);
3327 }
3328 }
3329 }
3330 return bitmap;
3331 }
3332
3333 //-----------------------------------------------------------------------------
setBitmap(UTF8StringPtr bitmapName)3334 void UIBitmapNode::setBitmap (UTF8StringPtr bitmapName)
3335 {
3336 attributes->setAttribute ("path", std::string (bitmapName));
3337 if (bitmap)
3338 bitmap->forget ();
3339 bitmap = nullptr;
3340 double scaleFactor = 1.;
3341 if (UIDescriptionPrivate::decodeScaleFactorFromName (bitmapName, scaleFactor))
3342 attributes->setDoubleAttribute ("scale-factor", scaleFactor);
3343 removeXMLData ();
3344 }
3345
3346 //-----------------------------------------------------------------------------
setNinePartTiledOffset(const CRect * offsets)3347 void UIBitmapNode::setNinePartTiledOffset (const CRect* offsets)
3348 {
3349 if (bitmap)
3350 {
3351 CNinePartTiledBitmap* tiledBitmap = dynamic_cast<CNinePartTiledBitmap*> (bitmap);
3352 if (offsets && tiledBitmap)
3353 {
3354 tiledBitmap->setPartOffsets (CNinePartTiledDescription (offsets->left, offsets->top, offsets->right, offsets->bottom));
3355 }
3356 else
3357 {
3358 bitmap->forget ();
3359 bitmap = nullptr;
3360 }
3361 }
3362 if (offsets)
3363 attributes->setRectAttribute ("nineparttiled-offsets", *offsets);
3364 else
3365 attributes->removeAttribute ("nineparttiled-offsets");
3366 }
3367
3368 //-----------------------------------------------------------------------------
invalidBitmap()3369 void UIBitmapNode::invalidBitmap ()
3370 {
3371 if (bitmap)
3372 bitmap->forget ();
3373 bitmap = nullptr;
3374 filterProcessed = false;
3375 }
3376
3377 //-----------------------------------------------------------------------------
3378 //-----------------------------------------------------------------------------
3379 //-----------------------------------------------------------------------------
UIFontNode(const std::string & name,const SharedPointer<UIAttributes> & attributes)3380 UIFontNode::UIFontNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
3381 : UINode (name, attributes)
3382 , font (nullptr)
3383 {
3384 }
3385
3386 //-----------------------------------------------------------------------------
~UIFontNode()3387 UIFontNode::~UIFontNode () noexcept
3388 {
3389 if (font)
3390 font->forget ();
3391 }
3392
3393 //-----------------------------------------------------------------------------
freePlatformResources()3394 void UIFontNode::freePlatformResources ()
3395 {
3396 if (font)
3397 font->forget ();
3398 font = nullptr;
3399 }
3400
3401 //-----------------------------------------------------------------------------
getFont()3402 CFontRef UIFontNode::getFont ()
3403 {
3404 if (font == nullptr)
3405 {
3406 const std::string* nameAttr = attributes->getAttributeValue ("font-name");
3407 const std::string* sizeAttr = attributes->getAttributeValue ("size");
3408 const std::string* boldAttr = attributes->getAttributeValue ("bold");
3409 const std::string* italicAttr = attributes->getAttributeValue ("italic");
3410 const std::string* underlineAttr = attributes->getAttributeValue ("underline");
3411 const std::string* strikethroughAttr = attributes->getAttributeValue ("strike-through");
3412 if (nameAttr)
3413 {
3414 int32_t size = 12;
3415 if (sizeAttr)
3416 size = (int32_t)strtol (sizeAttr->c_str (), nullptr, 10);
3417 int32_t fontStyle = 0;
3418 if (boldAttr && *boldAttr == "true")
3419 fontStyle |= kBoldFace;
3420 if (italicAttr && *italicAttr == "true")
3421 fontStyle |= kItalicFace;
3422 if (underlineAttr && *underlineAttr == "true")
3423 fontStyle |= kUnderlineFace;
3424 if (strikethroughAttr && *strikethroughAttr == "true")
3425 fontStyle |= kStrikethroughFace;
3426 if (attributes->hasAttribute ("alternative-font-names"))
3427 {
3428 std::list<std::string> fontNames;
3429 if (IPlatformFont::getAllPlatformFontFamilies (fontNames))
3430 {
3431 if (std::find (fontNames.begin (), fontNames.end (), *nameAttr) == fontNames.end ())
3432 {
3433 std::vector<std::string> alternativeFontNames;
3434 attributes->getStringArrayAttribute ("alternative-font-names", alternativeFontNames);
3435 for (auto& alternateFontName : alternativeFontNames)
3436 {
3437 auto trimmedString = trim (UTF8String (alternateFontName));
3438 if (std::find (fontNames.begin (), fontNames.end (), trimmedString.getString ()) != fontNames.end ())
3439 {
3440 font = new CFontDesc (trimmedString.data (), size, fontStyle);
3441 break;
3442 }
3443 }
3444 }
3445 }
3446 }
3447 if (font == nullptr)
3448 font = new CFontDesc (nameAttr->c_str (), size, fontStyle);
3449 }
3450 }
3451 return font;
3452 }
3453
3454 //-----------------------------------------------------------------------------
setFont(CFontRef newFont)3455 void UIFontNode::setFont (CFontRef newFont)
3456 {
3457 if (font)
3458 font->forget ();
3459 font = newFont;
3460 font->remember ();
3461
3462 std::string name (*attributes->getAttributeValue ("name"));
3463 std::string alternativeNames;
3464 getAlternativeFontNames (alternativeNames);
3465
3466 attributes->removeAll ();
3467 attributes->setAttribute ("name", name);
3468 attributes->setAttribute ("font-name", newFont->getName ().getString ());
3469 std::stringstream str;
3470 str << newFont->getSize ();
3471 attributes->setAttribute ("size", str.str ());
3472 if (newFont->getStyle () & kBoldFace)
3473 attributes->setAttribute ("bold", "true");
3474 if (newFont->getStyle () & kItalicFace)
3475 attributes->setAttribute ("italic", "true");
3476 if (newFont->getStyle () & kUnderlineFace)
3477 attributes->setAttribute ("underline", "true");
3478 if (newFont->getStyle () & kStrikethroughFace)
3479 attributes->setAttribute ("strike-through", "true");
3480
3481 setAlternativeFontNames (alternativeNames.c_str ());
3482 }
3483
3484 //-----------------------------------------------------------------------------
setAlternativeFontNames(UTF8StringPtr fontNames)3485 void UIFontNode::setAlternativeFontNames (UTF8StringPtr fontNames)
3486 {
3487 if (fontNames && fontNames[0] != 0)
3488 {
3489 attributes->setAttribute("alternative-font-names", fontNames);
3490 }
3491 else
3492 {
3493 attributes->removeAttribute ("alternative-font-names");
3494 }
3495 }
3496
3497 //-----------------------------------------------------------------------------
getAlternativeFontNames(std::string & fontNames)3498 bool UIFontNode::getAlternativeFontNames (std::string& fontNames)
3499 {
3500 const std::string* value = attributes->getAttributeValue ("alternative-font-names");
3501 if (value)
3502 {
3503 fontNames = *value;
3504 return true;
3505 }
3506 return false;
3507 }
3508
3509 //-----------------------------------------------------------------------------
UIColorNode(const std::string & name,const SharedPointer<UIAttributes> & attributes)3510 UIColorNode::UIColorNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
3511 : UINode (name, attributes)
3512 {
3513 color.alpha = 255;
3514 const std::string* red = attributes->getAttributeValue ("red");
3515 const std::string* green = attributes->getAttributeValue ("green");
3516 const std::string* blue = attributes->getAttributeValue ("blue");
3517 const std::string* alpha = attributes->getAttributeValue ("alpha");
3518 const std::string* rgb = attributes->getAttributeValue ("rgb");
3519 const std::string* rgba = attributes->getAttributeValue ("rgba");
3520 if (red)
3521 color.red = (uint8_t)strtol (red->c_str (), nullptr, 10);
3522 if (green)
3523 color.green = (uint8_t)strtol (green->c_str (), nullptr, 10);
3524 if (blue)
3525 color.blue = (uint8_t)strtol (blue->c_str (), nullptr, 10);
3526 if (alpha)
3527 color.alpha = (uint8_t)strtol (alpha->c_str (), nullptr, 10);
3528 if (rgb)
3529 UIDescription::parseColor (*rgb, color);
3530 if (rgba)
3531 UIDescription::parseColor (*rgba, color);
3532 }
3533
3534 //-----------------------------------------------------------------------------
setColor(const CColor & newColor)3535 void UIColorNode::setColor (const CColor& newColor)
3536 {
3537 std::string name (*attributes->getAttributeValue ("name"));
3538 attributes->removeAll ();
3539 attributes->setAttribute ("name", name);
3540
3541 std::string colorString;
3542 UIViewCreator::colorToString (newColor, colorString, nullptr);
3543 attributes->setAttribute ("rgba", colorString);
3544 color = newColor;
3545 }
3546
3547 //-----------------------------------------------------------------------------
UIGradientNode(const std::string & name,const SharedPointer<UIAttributes> & attributes)3548 UIGradientNode::UIGradientNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
3549 : UINode (name, attributes)
3550 {
3551 }
3552
3553 //-----------------------------------------------------------------------------
freePlatformResources()3554 void UIGradientNode::freePlatformResources ()
3555 {
3556 gradient = nullptr;
3557 }
3558
3559 //-----------------------------------------------------------------------------
getGradient()3560 CGradient* UIGradientNode::getGradient ()
3561 {
3562 if (gradient == nullptr)
3563 {
3564 CGradient::ColorStopMap colorStops;
3565 double start;
3566 CColor color;
3567 for (auto& colorNode : getChildren ())
3568 {
3569 if (colorNode->getName () == "color-stop")
3570 {
3571 const std::string* rgba = colorNode->getAttributes ()->getAttributeValue ("rgba");
3572 if (rgba == nullptr || colorNode->getAttributes()->getDoubleAttribute ("start", start) == false)
3573 continue;
3574 if (UIDescription::parseColor (*rgba, color) == false)
3575 continue;
3576 colorStops.emplace (start, color);
3577 }
3578 }
3579 if (colorStops.size () > 1)
3580 gradient = owned (CGradient::create (colorStops));
3581 }
3582 return gradient;
3583 }
3584
3585 //-----------------------------------------------------------------------------
setGradient(CGradient * g)3586 void UIGradientNode::setGradient (CGradient* g)
3587 {
3588 gradient = g;
3589 getChildren ().removeAll ();
3590 if (gradient == nullptr)
3591 return;
3592
3593 const CGradient::ColorStopMap colorStops = gradient->getColorStops ();
3594 for (const auto& colorStop : colorStops)
3595 {
3596 UINode* node = new UINode ("color-stop");
3597 node->getAttributes ()->setDoubleAttribute ("start", colorStop.first);
3598 std::string colorString;
3599 UIViewCreator::colorToString (colorStop.second, colorString, nullptr);
3600 node->getAttributes ()->setAttribute ("rgba", colorString);
3601 getChildren ().add (node);
3602 }
3603 }
3604
3605 } // namespace
3606