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[] = {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"};
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