Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
@@ -0,0 +1,29 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
namespace VSTGUI {
namespace Detail {
//-----------------------------------------------------------------------------
struct Locale
{
Locale ()
{
origLocal = std::locale ();
std::locale::global (std::locale::classic ());
}
~Locale () noexcept
{
std::locale::global (origLocal);
}
std::locale origLocal;
};
//------------------------------------------------------------------------
} // Detail
} // VSTGUI
@@ -0,0 +1,50 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../../lib/ccolor.h"
#include <string>
namespace VSTGUI {
namespace Detail {
//-----------------------------------------------------------------------------
inline bool parseColor (const std::string& colorString, CColor& color)
{
if (colorString.length () == 7)
{
if (colorString[0] == '#')
{
std::string rv (colorString.substr (1, 2));
std::string gv (colorString.substr (3, 2));
std::string bv (colorString.substr (5, 2));
color.red = (uint8_t)strtol (rv.c_str (), nullptr, 16);
color.green = (uint8_t)strtol (gv.c_str (), nullptr, 16);
color.blue = (uint8_t)strtol (bv.c_str (), nullptr, 16);
color.alpha = 255;
return true;
}
}
if (colorString.length () == 9)
{
if (colorString[0] == '#')
{
std::string rv (colorString.substr (1, 2));
std::string gv (colorString.substr (3, 2));
std::string bv (colorString.substr (5, 2));
std::string av (colorString.substr (7, 2));
color.red = (uint8_t)strtol (rv.c_str (), nullptr, 16);
color.green = (uint8_t)strtol (gv.c_str (), nullptr, 16);
color.blue = (uint8_t)strtol (bv.c_str (), nullptr, 16);
color.alpha = (uint8_t)strtol (av.c_str (), nullptr, 16);
return true;
}
}
return false;
}
} // Detail
} // VSTGUI
@@ -0,0 +1,82 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
namespace VSTGUI {
namespace Detail {
//-----------------------------------------------------------------------------
template <bool nameHasExtension, size_t numIndicators>
inline std::pair<size_t, size_t> rangeOfScaleFactor (const std::string& name,
const char (&identicator)[numIndicators])
{
auto result = std::make_pair (std::string::npos, std::string::npos);
size_t xIndex;
if (nameHasExtension)
{
xIndex = name.rfind ("x.");
}
else
{
if (name[name.size () - 1] != 'x')
return result;
xIndex = name.size () - 1;
}
if (xIndex == std::string::npos)
return result;
for (auto i = 0u; i < numIndicators; ++i)
{
size_t indicatorIndex = name.find_last_of (identicator[i]);
if (indicatorIndex == std::string::npos)
continue;
if (xIndex < indicatorIndex)
continue;
result.first = xIndex;
result.second = indicatorIndex;
break;
}
return result;
}
//-----------------------------------------------------------------------------
template <size_t numIndicators>
inline bool decodeScaleFactorFromName (const std::string& name,
const char (&identicator)[numIndicators],
double& scaleFactor)
{
auto range = rangeOfScaleFactor<true> (name, identicator);
if (range.first == std::string::npos)
return false;
std::string tmp (name);
tmp.erase (0, ++range.second);
tmp.erase (range.first - range.second);
scaleFactor = UTF8StringView (tmp.c_str ()).toDouble ();
return scaleFactor != 0;
}
//-----------------------------------------------------------------------------
static constexpr const char scaleFactorIndicatorChars[] = "#_";
//-----------------------------------------------------------------------------
inline bool decodeScaleFactorFromName (const std::string& name, double& scaleFactor)
{
if (!decodeScaleFactorFromName (name, scaleFactorIndicatorChars, scaleFactor))
return false;
return true;
}
//-----------------------------------------------------------------------------
inline std::string removeScaleFactorFromName (const std::string& name)
{
auto range = rangeOfScaleFactor<false> (name, scaleFactorIndicatorChars);
if (range.first == std::string::npos)
return "";
auto result = name.substr (0, range.second);
return result;
}
} // Detail
} // VSTGUI
@@ -0,0 +1,160 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "../uiattributes.h"
#include "uidesclist.h"
#include "uinode.h"
namespace VSTGUI {
namespace Detail {
//-----------------------------------------------------------------------------
UIDescList::UIDescList (bool ownsObjects) : ownsObjects (ownsObjects)
{
}
//------------------------------------------------------------------------
UIDescList::UIDescList (const UIDescList& uiDesc) : ownsObjects (false)
{
for (auto& child : uiDesc)
add (child);
}
//-----------------------------------------------------------------------------
UIDescList::~UIDescList () noexcept
{
removeAll ();
}
//-----------------------------------------------------------------------------
void UIDescList::add (UINode* obj)
{
if (!ownsObjects)
obj->remember ();
UIDescListContainerType::emplace_back (obj);
}
//-----------------------------------------------------------------------------
void UIDescList::remove (UINode* obj)
{
UIDescListContainerType::iterator pos =
std::find (UIDescListContainerType::begin (), UIDescListContainerType::end (), obj);
if (pos != UIDescListContainerType::end ())
{
UIDescListContainerType::erase (pos);
obj->forget ();
}
}
//-----------------------------------------------------------------------------
void UIDescList::removeAll ()
{
for (const_reverse_iterator it = rbegin (), end = rend (); it != end; ++it)
(*it)->forget ();
clear ();
}
//-----------------------------------------------------------------------------
UINode* UIDescList::findChildNode (UTF8StringView nodeName) const
{
for (const auto& node : *this)
{
auto& name = node->getName ();
if (nodeName == UTF8StringView (name))
return node;
}
return nullptr;
}
//-----------------------------------------------------------------------------
UINode* UIDescList::findChildNodeWithAttributeValue (const std::string& attributeName,
const std::string& attributeValue) const
{
for (const auto& node : *this)
{
const std::string* attributeValuePtr =
node->getAttributes ()->getAttributeValue (attributeName);
if (attributeValuePtr && *attributeValuePtr == attributeValue)
return node;
}
return nullptr;
}
//-----------------------------------------------------------------------------
void UIDescList::sort ()
{
std::sort (begin (), end (), [] (const UINode* n1, const UINode* n2) {
const std::string* str1 = n1->getAttributes ()->getAttributeValue ("name");
const std::string* str2 = n2->getAttributes ()->getAttributeValue ("name");
if (str1 && str2)
return *str1 < *str2;
else if (str1)
return true;
return false;
});
}
//------------------------------------------------------------------------
UIDescListWithFastFindAttributeNameChild::UIDescListWithFastFindAttributeNameChild ()
{
}
//------------------------------------------------------------------------
void UIDescListWithFastFindAttributeNameChild::add (UINode* obj)
{
UIDescList::add (obj);
const std::string* nameAttributeValue = obj->getAttributes ()->getAttributeValue ("name");
if (nameAttributeValue)
childMap.emplace (*nameAttributeValue, obj);
}
//------------------------------------------------------------------------
void UIDescListWithFastFindAttributeNameChild::remove (UINode* obj)
{
const std::string* nameAttributeValue = obj->getAttributes ()->getAttributeValue ("name");
if (nameAttributeValue)
{
ChildMap::iterator it = childMap.find (*nameAttributeValue);
if (it != childMap.end ())
childMap.erase (it);
}
UIDescList::remove (obj);
}
//------------------------------------------------------------------------
void UIDescListWithFastFindAttributeNameChild::removeAll ()
{
childMap.clear ();
UIDescList::removeAll ();
}
//------------------------------------------------------------------------
UINode* UIDescListWithFastFindAttributeNameChild::findChildNodeWithAttributeValue (
const std::string& attributeName, const std::string& attributeValue) const
{
if (attributeName != "name")
return UIDescList::findChildNodeWithAttributeValue (attributeName, attributeValue);
ChildMap::const_iterator it = childMap.find (attributeValue);
if (it != childMap.end ())
return it->second;
return nullptr;
}
//------------------------------------------------------------------------
void UIDescListWithFastFindAttributeNameChild::nodeAttributeChanged (
UINode* node, const std::string& attributeName, const std::string& oldAttributeValue)
{
if (attributeName != "name")
return;
ChildMap::iterator it = childMap.find (oldAttributeValue);
if (it != childMap.end ())
childMap.erase (it);
const std::string* nameAttributeValue = node->getAttributes ()->getAttributeValue ("name");
if (nameAttributeValue)
childMap.emplace (*nameAttributeValue, node);
}
//------------------------------------------------------------------------
} // Detail
} // VSTGUI
@@ -0,0 +1,76 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../../lib/cstring.h"
#include "../../lib/vstguibase.h"
#include <unordered_map>
#include <vector>
namespace VSTGUI {
namespace Detail {
class UINode;
using UIDescListContainerType = std::vector<UINode*>;
//-----------------------------------------------------------------------------
class UIDescList : public NonAtomicReferenceCounted, private UIDescListContainerType
{
public:
using UIDescListContainerType::begin;
using UIDescListContainerType::end;
using UIDescListContainerType::rbegin;
using UIDescListContainerType::rend;
using UIDescListContainerType::iterator;
using UIDescListContainerType::const_iterator;
using UIDescListContainerType::const_reverse_iterator;
using UIDescListContainerType::empty;
using UIDescListContainerType::size;
explicit UIDescList (bool ownsObjects = true);
UIDescList (const UIDescList& uiDesc);
~UIDescList () noexcept override;
virtual void add (UINode* obj);
virtual void remove (UINode* obj);
virtual void removeAll ();
virtual UINode* findChildNode (UTF8StringView nodeName) const;
virtual UINode* findChildNodeWithAttributeValue (const std::string& attributeName,
const std::string& attributeValue) const;
virtual void nodeAttributeChanged (UINode* child, const std::string& attributeName,
const std::string& oldAttributeValue)
{
}
void sort ();
protected:
bool ownsObjects;
};
//-----------------------------------------------------------------------------
class UIDescListWithFastFindAttributeNameChild : public UIDescList
{
private:
using ChildMap = std::unordered_map<std::string, UINode*>;
public:
UIDescListWithFastFindAttributeNameChild ();
void add (UINode* obj) override;
void remove (UINode* obj) override;
void removeAll () override;
UINode* findChildNodeWithAttributeValue (const std::string& attributeName,
const std::string& attributeValue) const override;
void nodeAttributeChanged (UINode* node, const std::string& attributeName,
const std::string& oldAttributeValue) override;
private:
ChildMap childMap;
};
} // Detail
} // VSTGUI
@@ -0,0 +1,744 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "../uiattributes.h"
#include "uijsonpersistence.h"
#include <array>
#include <deque>
#include <map>
#if __cplusplus > 201402L
#include <string_view>
#endif
#define RAPIDJSON_HAS_STDSTRING 1
#if DEBUG
#include "../../thirdparty/rapidjson/include/rapidjson/error/en.h"
#endif
#include "../../thirdparty/rapidjson/include/rapidjson/document.h"
#include "../../thirdparty/rapidjson/include/rapidjson/prettywriter.h"
#include "../../thirdparty/rapidjson/include/rapidjson/reader.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace Detail {
static constexpr auto attributeNameStr = "name";
static constexpr auto attributeValueStr = "value";
static constexpr auto attributeClassStr = "class";
static constexpr auto attributeTagStr = "tag";
static constexpr auto attributeRGBAStr = "rgba";
static constexpr auto keyDataStr = "data";
static constexpr auto keyChildrenStr = "children";
static constexpr auto keyTemplatesStr = "templates";
static constexpr auto keyViewsStr = "views";
static constexpr auto attributesStr = "attributes";
static constexpr auto colorStr = "color";
static constexpr auto controlTagStr = "control-tag";
static constexpr auto bitmapStr = "bitmap";
static constexpr auto fontStr = "font";
static constexpr auto templateStr = "template";
static constexpr auto colorStopStr = "color-stop";
static constexpr auto viewStr = "view";
static constexpr auto gradientStr = "gradient";
//------------------------------------------------------------------------
namespace UIJsonDescReader {
//------------------------------------------------------------------------
template <size_t size>
struct ContentProviderWrapper
{
using Ch = uint8_t;
ContentProviderWrapper (IContentProvider& s) : stream (s)
{
bufferLeft = bufferSize = stream.readRawData (reinterpret_cast<int8_t*> (buffer.data ()),
static_cast<int32_t> (buffer.size ()));
if (bufferLeft == kStreamIOError)
bufferSize = bufferLeft = 0;
if (bufferSize == 0)
{
current = 0;
bufferLeft = 1;
}
else
current = buffer[bufferSize - bufferLeft];
}
Ch Peek () const { return current; }
Ch Take ()
{
auto result = Peek ();
++pos;
if (bufferLeft == 1)
{
bufferLeft = bufferSize = stream.readRawData (
reinterpret_cast<int8_t*> (buffer.data ()), static_cast<int32_t> (buffer.size ()));
if (bufferLeft == kStreamIOError)
bufferSize = bufferLeft = 0;
if (bufferSize == 0)
{
current = 0;
return result;
}
}
else
--bufferLeft;
current = buffer[bufferSize - bufferLeft];
return result;
}
size_t Tell () { return pos; }
Ch* PutBegin ()
{
vstgui_assert (false);
return 0;
}
void Put (Ch c) { vstgui_assert (false); }
void Flush () { vstgui_assert (false); };
size_t PutEnd (Ch* begin)
{
vstgui_assert (false);
return 0;
}
Ch current {};
size_t pos {0};
IContentProvider& stream;
std::array<Ch, size> buffer;
size_t bufferLeft {};
size_t bufferSize {};
};
//------------------------------------------------------------------------
struct Handler
{
using Ch = char;
using SizeType = rapidjson::SizeType;
enum class State
{
Uninitialized = 0,
Initialized,
InRootNode,
InBitmapRootNode,
InFontRootNode,
InColorRootNode,
InGradientRootNode,
InControlTagRootNode,
InCustomRootNode,
InVariableRootNode,
InTemplateRootNode,
BitmapNode,
FontNode,
GradientNode,
TemplateNode,
ChildrenNode,
ViewNode,
DataNode,
ViewAttributes,
};
bool Null () { return false; }
bool Bool (bool b) { return false; }
bool Int (int i) { return false; }
bool Uint (unsigned i) { return false; }
bool Int64 (int64_t i) { return false; }
bool Uint64 (uint64_t i) { return false; }
bool Double (double d) { return false; }
bool RawNumber (const Ch* str, SizeType length, bool copy) { return false; }
bool String (const Ch* str, SizeType length, bool copy)
{
if (state == State::InColorRootNode)
{
auto attrs = newAttributesWithNameAttr (keyStr);
attrs->setAttribute (attributeRGBAStr, {str, length});
nodeStack.back ()->getChildren ().add (new UIColorNode (colorStr, attrs));
}
else if (state == State::InControlTagRootNode)
{
auto attrs = newAttributesWithNameAttr (keyStr);
attrs->setAttribute (attributeTagStr, {str, length});
nodeStack.back ()->getChildren ().add (new UIControlTagNode (controlTagStr, attrs));
}
else if (state == State::InVariableRootNode)
{
auto attrs = newAttributesWithNameAttr (keyStr);
attrs->setAttribute (attributeValueStr, {str, length});
nodeStack.back ()->getChildren ().add (new UIVariableNode (controlTagStr, attrs));
}
else if (state == State::DataNode && keyStr == "data")
{
nodeStack.back ()->setData ({str, length});
}
else
{
nodeStack.back ()->getAttributes ()->setAttribute (keyStr, {str, length});
}
keyStr.clear ();
return true;
}
bool Key (const Ch* str, SizeType length, bool copy)
{
keyStr = {str, length};
return true;
}
bool StartObject ()
{
UINode* newNode = nullptr;
State newState {};
switch (state)
{
case State::Uninitialized:
{
newState = State::Initialized;
break;
}
case State::Initialized:
{
vstgui_assert (keyStr == "vstgui-ui-description" ||
keyStr == "vstgui-ui-description-view-list");
rootNode = makeOwned<UINode> (std::move (keyStr));
newNode = rootNode;
newState = State::InRootNode;
break;
}
case State::InRootNode:
{
if (keyStr == keyTemplatesStr || keyStr == keyViewsStr)
{
newState = State::InTemplateRootNode;
break;
}
auto needsFastChildNameAttributeLookup = false;
if (keyStr == MainNodeNames::kBitmap)
{
newState = State::InBitmapRootNode;
needsFastChildNameAttributeLookup = true;
}
else if (keyStr == MainNodeNames::kFont)
newState = State::InFontRootNode;
else if (keyStr == MainNodeNames::kColor)
{
newState = State::InColorRootNode;
needsFastChildNameAttributeLookup = true;
}
else if (keyStr == MainNodeNames::kGradient)
newState = State::InGradientRootNode;
else if (keyStr == MainNodeNames::kControlTag)
{
newState = State::InControlTagRootNode;
needsFastChildNameAttributeLookup = true;
}
else if (keyStr == MainNodeNames::kCustom)
newState = State::InCustomRootNode;
else if (keyStr == MainNodeNames::kVariable)
newState = State::InVariableRootNode;
else
return false;
newNode = new UINode (keyStr, nullptr, needsFastChildNameAttributeLookup);
break;
}
case State::InBitmapRootNode:
{
newNode = new UIBitmapNode (bitmapStr, newAttributesWithNameAttr (keyStr));
newState = State::BitmapNode;
break;
}
case State::InFontRootNode:
{
newNode = new UIFontNode (fontStr, newAttributesWithNameAttr (keyStr));
newState = State::FontNode;
break;
}
case State::InCustomRootNode:
{
newNode = new UINode (attributesStr, newAttributesWithNameAttr (keyStr));
newState = State::DataNode;
break;
}
case State::InTemplateRootNode:
{
newNode = new UINode (templateStr, newAttributesWithNameAttr (keyStr));
newState = State::TemplateNode;
break;
}
case State::BitmapNode:
{
vstgui_assert (keyStr == keyDataStr);
newNode = new UINode (keyStr);
newState = State::DataNode;
break;
}
case State::GradientNode:
{
vstgui_assert (keyStr.empty ());
newNode = new UINode (colorStopStr);
newState = State::DataNode;
break;
}
case State::TemplateNode:
{
if (keyStr == attributesStr)
newState = State::ViewAttributes;
else if (keyStr == keyChildrenStr)
newState = State::ChildrenNode;
break;
}
case State::ChildrenNode:
{
auto attr = makeOwned<UIAttributes> (15);
newNode = new UINode (viewStr, attr);
newState = State::ViewNode;
break;
}
case State::ViewNode:
{
newState = State::ChildrenNode;
break;
}
case State::InColorRootNode:
case State::InControlTagRootNode:
case State::InVariableRootNode:
case State::InGradientRootNode:
case State::FontNode:
case State::DataNode:
case State::ViewAttributes:
{
// not allowed here, invalid JSON data!
return false;
}
}
keyStr.clear ();
pushNode (newNode);
pushState (newState);
return true;
}
bool EndObject (SizeType memberCount)
{
if (state == State::InTemplateRootNode || state == State::ChildrenNode ||
state == State::ViewAttributes)
{
popState ();
return true;
}
popState ();
return popNode ();
}
bool StartArray ()
{
if (state == State::InGradientRootNode)
{
auto newNode = new UIGradientNode (gradientStr, newAttributesWithNameAttr (keyStr));
pushNode (newNode);
pushState (State::GradientNode);
keyStr.clear ();
return true;
}
return false;
}
bool EndArray (SizeType elementCount)
{
if (state != State::GradientNode)
return false;
popState ();
if (!popNode ())
return false;
return true;
}
bool popNode ()
{
if (nodeStack.empty ())
return state == State::Uninitialized;
nodeStack.pop_back ();
return true;
}
void pushNode (UINode* newNode)
{
if (newNode)
{
if (newNode != rootNode)
nodeStack.back ()->getChildren ().add (newNode);
nodeStack.emplace_back (newNode);
}
}
void popState ()
{
stateStack.pop_back ();
state = stateStack.back ();
}
void pushState (State newState)
{
stateStack.emplace_back (newState);
state = newState;
}
static SharedPointer<UIAttributes> newAttributesWithNameAttr (const std::string& name)
{
auto attributes = makeOwned<UIAttributes> ();
attributes->setAttribute (attributeNameStr, name);
return attributes;
}
SharedPointer<UINode> rootNode;
std::deque<UINode*> nodeStack;
std::deque<State> stateStack {State::Uninitialized};
State state {};
std::string keyStr;
};
//------------------------------------------------------------------------
SharedPointer<UINode> read (IContentProvider& stream)
{
ContentProviderWrapper<1024> streamWrapper (stream);
Handler handler;
rapidjson::Reader reader;
auto result = reader.Parse<rapidjson::kParseStopWhenDoneFlag> (streamWrapper, handler);
if (result.IsError ())
{
#if DEBUG
DebugPrint ("JSON Parsing Error:");
if (auto errorString = rapidjson::GetParseError_En (result.Code ()))
DebugPrint (" %s", errorString);
else
DebugPrint (" %d", result.Code ());
DebugPrint ("\n\tAt byte offset: %d\n", result.Offset ());
#endif
return nullptr;
}
return handler.rootNode;
}
//------------------------------------------------------------------------
} // UIJsonDescReader
//------------------------------------------------------------------------
namespace UIJsonDescWriter {
//------------------------------------------------------------------------
template <typename CharT>
struct OutputStreamWrapper
{
using Ch = CharT;
OutputStreamWrapper (OutputStream& stream) : stream (stream) {}
void Put (CharT c) { stream << c; }
void Flush () {}
OutputStream& stream;
};
using DefaultOutputStreamWrapper = OutputStreamWrapper<uint8_t>;
//------------------------------------------------------------------------
static const std::string* getNodeAttributeName (const UINode* node)
{
if (auto attributes = node->getAttributes ())
return attributes->getAttributeValue (attributeNameStr);
return nullptr;
}
//------------------------------------------------------------------------
static const std::string* getNodeAttributeViewClass (const UINode* node)
{
if (auto attributes = node->getAttributes ())
return attributes->getAttributeValue (attributeClassStr);
return nullptr;
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeAttributes (const UIAttributes& attributes, JSONWriter& writer,
bool ignoreNameAttribute = false)
{
#if __cplusplus > 201402L
std::map<std::string_view, std::string_view> ordered (attributes.begin (), attributes.end ());
#else
std::map<std::string, std::string> ordered (attributes.begin (), attributes.end ());
#endif
for (const auto& attr : ordered)
{
if (ignoreNameAttribute && attr.first == attributeNameStr)
continue;
if (attr.second.empty ()) // don't write empty attributes
continue;
writer.Key (attr.first.data (), static_cast<rapidjson::SizeType> (attr.first.size ()));
writer.String (attr.second.data (), static_cast<rapidjson::SizeType> (attr.second.size ()));
}
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeNode (const UINode* node, JSONWriter& writer)
{
auto name = getNodeAttributeName (node);
if (name)
writer.Key (*name);
writer.StartObject ();
writeAttributes (*node->getAttributes (), writer, name != nullptr);
for (const auto& child : node->getChildren ())
{
writer.Key (child->getName ());
writer.StartObject ();
writeAttributes (*child->getAttributes (), writer);
if (child->getData ().empty () == false)
{
writer.Key (keyDataStr);
writer.String (child->getData ());
}
vstgui_assert (child->getChildren ().empty ());
writer.EndObject ();
}
writer.EndObject ();
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeGradientNode (const UINode* node, JSONWriter& writer)
{
auto name = getNodeAttributeName (node);
vstgui_assert (name);
writer.Key (*name);
writer.StartArray ();
for (const auto& child : node->getChildren ())
{
writer.StartObject ();
writeAttributes (*child->getAttributes (), writer);
vstgui_assert (child->getChildren ().empty ());
writer.EndObject ();
}
writer.EndArray ();
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeSingleAttributeNode (const char* attrName, const UINode* node, JSONWriter& writer)
{
auto name = getNodeAttributeName (node);
vstgui_assert (name);
writer.Key (*name);
vstgui_assert (node->getAttributes ());
if (auto tag = node->getAttributes ()->getAttributeValue (attrName))
writer.String (*tag);
else
writer.String ("");
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeColorAttributeNode (const UINode* node, JSONWriter& writer)
{
auto name = getNodeAttributeName (node);
vstgui_assert (name);
writer.Key (*name);
vstgui_assert (node->getAttributes ());
if (auto color = node->getAttributes ()->getAttributeValue (attributeRGBAStr))
{
writer.String (*color);
}
else
{
auto colorNode = dynamic_cast<const UIColorNode*> (node);
vstgui_assert (colorNode);
writer.String (colorNode->getColor ().toString ().getString ());
}
}
//------------------------------------------------------------------------
template <typename JSONWriter, typename Proc>
void writeResourceNode (const char* name, const UINode* resNode, Proc proc, JSONWriter& writer)
{
writer.Key (name);
writer.StartObject ();
if (resNode->getAttributes () && resNode->getAttributes ()->empty () == false)
writeAttributes (*resNode->getAttributes (), writer);
for (auto& child : resNode->getChildren ())
{
if (child->noExport () == false)
proc (child, writer);
}
writer.EndObject ();
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeTemplateNode (const std::string* name, const UINode* node, JSONWriter& writer)
{
if (name)
writer.Key (*name);
writer.StartObject ();
writer.String (attributesStr);
writer.StartObject ();
writeAttributes (*node->getAttributes (), writer, name != nullptr);
writer.EndObject ();
if (node->getChildren ().empty () == false)
{
writer.Key (keyChildrenStr);
writer.StartObject ();
for (const auto& child : node->getChildren ())
{
writeTemplateNode (getNodeAttributeViewClass (child), child, writer);
}
writer.EndObject ();
}
writer.EndObject ();
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeViewNodes (const std::vector<const UINode*>& views, JSONWriter& writer)
{
if (views.empty ())
return;
writer.Key (keyViewsStr);
writer.StartObject ();
for (auto& child : views)
{
writeTemplateNode (getNodeAttributeViewClass (child), child, writer);
}
writer.EndObject ();
}
//------------------------------------------------------------------------
template <typename JSONWriter>
void writeTemplates (const std::vector<const UINode*>& templates, JSONWriter& writer)
{
if (templates.empty ())
return;
writer.Key (keyTemplatesStr);
writer.StartObject ();
for (auto& child : templates)
{
writeTemplateNode (getNodeAttributeName (child), child, writer);
}
writer.EndObject ();
}
//------------------------------------------------------------------------
template <typename JSONWriter>
bool writeRootNode (UINode* rootNode, JSONWriter& writer)
{
writer.StartObject ();
writer.Key (rootNode->getName ());
writer.StartObject ();
writeAttributes (*rootNode->getAttributes (), writer);
bool result = true;
std::vector<const UINode*> templateNodes;
std::vector<const UINode*> viewNodes;
const UINode* bitmapsNode = nullptr;
const UINode* fontsNode = nullptr;
const UINode* colorsNode = nullptr;
const UINode* controlTagsNode = nullptr;
const UINode* variablesNode = nullptr;
const UINode* gradientsNode = nullptr;
const UINode* customNode = nullptr;
for (const auto& child : rootNode->getChildren ())
{
if (child->getName () == MainNodeNames::kTemplate)
templateNodes.emplace_back (child);
else if (child->getName () == MainNodeNames::kBitmap)
bitmapsNode = child;
else if (child->getName () == MainNodeNames::kFont)
fontsNode = child;
else if (child->getName () == MainNodeNames::kColor)
colorsNode = child;
else if (child->getName () == MainNodeNames::kControlTag)
controlTagsNode = child;
else if (child->getName () == MainNodeNames::kVariable)
variablesNode = child;
else if (child->getName () == MainNodeNames::kGradient)
gradientsNode = child;
else if (child->getName () == MainNodeNames::kCustom)
customNode = child;
else if (child->getName () == viewStr)
viewNodes.emplace_back (child);
else if (child->getName () == "comment")
{
// comments are removed
continue;
}
else
return false; // unexpected input
}
if (variablesNode)
{
writeResourceNode (MainNodeNames::kVariable, variablesNode,
[] (UINode* node, JSONWriter& writer) {
writeSingleAttributeNode (attributeValueStr, node, writer);
},
writer);
}
if (bitmapsNode)
{
writeResourceNode (MainNodeNames::kBitmap, bitmapsNode, writeNode<JSONWriter>, writer);
}
if (fontsNode)
{
writeResourceNode (MainNodeNames::kFont, fontsNode, writeNode<JSONWriter>, writer);
}
if (colorsNode)
{
writeResourceNode (MainNodeNames::kColor, colorsNode, writeColorAttributeNode<JSONWriter>,
writer);
}
if (gradientsNode)
{
writeResourceNode (MainNodeNames::kGradient, gradientsNode, writeGradientNode<JSONWriter>,
writer);
}
if (controlTagsNode)
{
writeResourceNode (MainNodeNames::kControlTag, controlTagsNode,
[] (UINode* node, JSONWriter& writer) {
writeSingleAttributeNode (attributeTagStr, node, writer);
},
writer);
}
if (customNode)
{
writeResourceNode (MainNodeNames::kCustom, customNode, writeNode<JSONWriter>, writer);
}
writeViewNodes (viewNodes, writer);
writeTemplates (templateNodes, writer);
writer.EndObject ();
writer.EndObject ();
return result;
}
//------------------------------------------------------------------------
bool write (OutputStream& stream, UINode* rootNode, bool pretty)
{
DefaultOutputStreamWrapper output (stream);
if (pretty)
{
rapidjson::PrettyWriter<DefaultOutputStreamWrapper> writer (output);
writer.SetIndent ('\t', 1);
auto result = writeRootNode (rootNode, writer);
return result;
}
rapidjson::Writer<DefaultOutputStreamWrapper> writer (output);
auto result = writeRootNode (rootNode, writer);
return result;
}
//------------------------------------------------------------------------
} // UIJsonDescWriter
//------------------------------------------------------------------------
} // Detail
} // VSTGUI
@@ -0,0 +1,35 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../cstream.h"
#include "../icontentprovider.h"
#include "uinode.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace Detail {
//------------------------------------------------------------------------
namespace UIJsonDescReader {
//------------------------------------------------------------------------
SharedPointer<UINode> read (IContentProvider& contentProvider);
//------------------------------------------------------------------------
} // UIJsonDescReader
//------------------------------------------------------------------------
namespace UIJsonDescWriter {
//------------------------------------------------------------------------
bool write (OutputStream& stream, UINode* rootNode, bool pretty = true);
//------------------------------------------------------------------------
} // UIJsonDescWriter
//------------------------------------------------------------------------
} // Detail
} // VSTGUI
@@ -0,0 +1,742 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "../../lib/cbitmap.h"
#include "../../lib/cfont.h"
#include "../../lib/cgradient.h"
#include "../../lib/platform/platformfactory.h"
#include "../base64codec.h"
#include "../cstream.h"
#include "../uiattributes.h"
#include "../uiviewcreator.h"
#include "locale.h"
#include "parsecolor.h"
#include "scalefactorutils.h"
#include "uinode.h"
#include <list>
#include <string>
#include <sstream>
namespace VSTGUI {
namespace Detail {
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
UINode::UINode (const std::string& _name, const SharedPointer<UIAttributes>& _attributes,
bool needsFastChildNameAttributeLookup)
: name (_name), attributes (_attributes), flags (0)
{
if (needsFastChildNameAttributeLookup)
children = makeOwned<UIDescListWithFastFindAttributeNameChild> ();
else
children = makeOwned<UIDescList> ();
if (attributes == nullptr)
attributes = makeOwned<UIAttributes> ();
}
//-----------------------------------------------------------------------------
UINode::UINode (const std::string& _name, const SharedPointer<UIDescList>& _children,
const SharedPointer<UIAttributes>& _attributes)
: name (_name), attributes (_attributes), children (_children), flags (0)
{
vstgui_assert (children != nullptr);
if (attributes == nullptr)
attributes = makeOwned<UIAttributes> ();
}
//-----------------------------------------------------------------------------
UINode::UINode (const UINode& n)
: name (n.name)
, data (n.data)
, attributes (makeOwned<UIAttributes> (*n.attributes))
, children (makeOwned<UIDescList> (*n.children))
, flags (n.flags)
{
}
//-----------------------------------------------------------------------------
UINode::~UINode () noexcept
{
}
//-----------------------------------------------------------------------------
bool UINode::hasChildren () const
{
return !children->empty ();
}
//-----------------------------------------------------------------------------
void UINode::childAttributeChanged (UINode* child, const char* attributeName,
const char* oldAttributeValue)
{
children->nodeAttributeChanged (child, attributeName, oldAttributeValue);
}
//-----------------------------------------------------------------------------
void UINode::sortChildren ()
{
children->sort ();
}
//------------------------------------------------------------------------
void UINode::setData (DataStorage&& newData)
{
data = std::move (newData);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
UICommentNode::UICommentNode (const std::string& comment) : UINode ("comment")
{
data = comment;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
UIVariableNode::UIVariableNode (const std::string& name,
const SharedPointer<UIAttributes>& attributes)
: UINode (name, attributes), type (kUnknown), number (0)
{
const std::string* typeStr = attributes->getAttributeValue ("type");
const std::string* valueStr = attributes->getAttributeValue ("value");
if (typeStr)
{
if (*typeStr == "number")
type = kNumber;
else if (*typeStr == "string")
type = kString;
}
if (valueStr)
{
Detail::Locale localeResetter;
const char* strPtr = valueStr->c_str ();
if (type == kUnknown)
{
char* endPtr = nullptr;
double numberCheck = strtod (strPtr, &endPtr);
if (endPtr == strPtr + strlen (strPtr))
{
number = numberCheck;
type = kNumber;
}
else
type = kString;
}
else if (type == kNumber)
{
number = strtod (strPtr, nullptr);
}
}
}
//-----------------------------------------------------------------------------
UIVariableNode::Type UIVariableNode::getType () const
{
return type;
}
//-----------------------------------------------------------------------------
double UIVariableNode::getNumber () const
{
return number;
}
//-----------------------------------------------------------------------------
const std::string& UIVariableNode::getString () const
{
const std::string* value = attributes->getAttributeValue ("value");
if (value)
return *value;
static std::string kEmpty;
return kEmpty;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
UIControlTagNode::UIControlTagNode (const std::string& name,
const SharedPointer<UIAttributes>& attributes)
: UINode (name, attributes), tag (-1)
{
}
//-----------------------------------------------------------------------------
int32_t UIControlTagNode::getTag ()
{
if (tag == -1)
{
const std::string* tagStr = attributes->getAttributeValue ("tag");
if (tagStr)
{
if (tagStr->size () == 6 && (*tagStr)[0] == '\'' && (*tagStr)[5] == '\'')
{
char c1 = (*tagStr)[1];
char c2 = (*tagStr)[2];
char c3 = (*tagStr)[3];
char c4 = (*tagStr)[4];
tag = ((((int32_t)c1) << 24) | (((int32_t)c2) << 16) | (((int32_t)c3) << 8) |
(((int32_t)c4) << 0));
}
else
{
char* endPtr = nullptr;
tag = (int32_t)strtol (tagStr->c_str (), &endPtr, 10);
if (endPtr != tagStr->c_str () + tagStr->length ())
tag = -1;
}
}
}
return tag;
}
//-----------------------------------------------------------------------------
void UIControlTagNode::setTag (int32_t newTag)
{
tag = newTag;
}
//-----------------------------------------------------------------------------
const std::string* UIControlTagNode::getTagString () const
{
return attributes->getAttributeValue ("tag");
}
//-----------------------------------------------------------------------------
void UIControlTagNode::setTagString (const std::string& str)
{
attributes->setAttribute ("tag", str);
tag = -1;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
UIBitmapNode::UIBitmapNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
: UINode (name, attributes), bitmap (nullptr), filterProcessed (false), scaledBitmapsAdded (false)
{
}
//-----------------------------------------------------------------------------
UIBitmapNode::~UIBitmapNode () noexcept
{
if (bitmap)
bitmap->forget ();
}
//-----------------------------------------------------------------------------
void UIBitmapNode::freePlatformResources ()
{
if (bitmap)
bitmap->forget ();
bitmap = nullptr;
}
//-----------------------------------------------------------------------------
bool UIBitmapNode::imagesEqual (IPlatformBitmap* b1, IPlatformBitmap* b2)
{
if (b1 == b2)
return true;
if (b1->getSize () != b2->getSize () || b1->getScaleFactor () != b2->getScaleFactor ())
return false;
auto ac1 = b1->lockPixels (true);
if (!ac1)
return false;
auto ac2 = b2->lockPixels (true);
if (!ac2)
return false;
auto rowBytes = ac1->getBytesPerRow ();
if (rowBytes != ac2->getBytesPerRow ())
return false;
if (ac1->getPixelFormat () != ac2->getPixelFormat ())
return false;
auto adr1 = ac1->getAddress ();
if (!adr1)
return false;
auto adr2 = ac2->getAddress ();
if (!adr2)
return false;
uint32_t rows = static_cast<uint32_t> (b1->getSize ().y);
for (uint32_t y = 0; y < rows; ++y, adr1 += rowBytes, adr2 += rowBytes)
{
if (memcmp (adr1, adr2, rowBytes) != 0)
return false;
}
return true;
}
//-----------------------------------------------------------------------------
bool UIBitmapNode::hasXMLData () const
{
return getChildren ().findChildNode ("data") != nullptr;
}
//-----------------------------------------------------------------------------
void UIBitmapNode::createXMLData (const std::string& pathHint)
{
UINode* node = getChildren ().findChildNode ("data");
if (node)
{
if (node->getData ().empty ())
{
getChildren ().remove (node);
node = nullptr;
}
else if (auto bm = getBitmap (pathHint))
{
if (auto platformBitmap = bm->getPlatformBitmap ())
{
if (auto dataBitmap = createBitmapFromDataNode ())
{
if (!imagesEqual (platformBitmap, dataBitmap))
{
removeXMLData ();
node = nullptr;
}
}
}
}
}
if (node == nullptr)
{
if (auto bm = getBitmap (pathHint))
{
if (auto platformBitmap = bm->getPlatformBitmap ())
{
auto buffer =
getPlatformFactory ().createBitmapMemoryPNGRepresentation (platformBitmap);
if (!buffer.empty ())
{
auto result = Base64Codec::encode (buffer.data (),
static_cast<uint32_t> (buffer.size ()));
UINode* dataNode = new UINode ("data");
dataNode->getAttributes ()->setAttribute ("encoding", "base64");
dataNode->getData ().append (reinterpret_cast<const char*> (result.data.get ()),
static_cast<std::streamsize> (result.dataSize));
getChildren ().add (dataNode);
}
}
}
}
}
//-----------------------------------------------------------------------------
void UIBitmapNode::removeXMLData ()
{
UINode* node = getChildren ().findChildNode ("data");
if (node)
getChildren ().remove (node);
}
//-----------------------------------------------------------------------------
CBitmap* UIBitmapNode::createBitmap (const std::string& str, const BitmapVariant& variant) const
{
if (auto partDesc = std::get_if<CNinePartTiledDescription> (&variant))
return new CNinePartTiledBitmap (CResourceDescription (str.data ()), *partDesc);
else if (auto multiFrameDesc = std::get_if<CMultiFrameBitmapDescription> (&variant))
return new CMultiFrameBitmap (CResourceDescription (str.data ()), *multiFrameDesc);
return new CBitmap (CResourceDescription (str.c_str ()));
}
//------------------------------------------------------------------------
UINode* UIBitmapNode::dataNode () const
{
UINode* node = getChildren ().findChildNode ("data");
return (node && !node->getData ().empty ()) ? node : nullptr;
}
//------------------------------------------------------------------------
PlatformBitmapPtr UIBitmapNode::createBitmapFromDataNode () const
{
if (auto node = dataNode ())
{
auto codecStr = node->getAttributes ()->getAttributeValue ("encoding");
if (codecStr && *codecStr == "base64")
{
auto result = Base64Codec::decode (node->getData ());
if (auto platformBitmap = getPlatformFactory ().createBitmapFromMemory (
result.data.get (), result.dataSize))
{
double scaleFactor = 1.;
if (attributes->getDoubleAttribute ("scale-factor", scaleFactor))
platformBitmap->setScaleFactor (scaleFactor);
return platformBitmap;
}
}
}
return nullptr;
}
//-----------------------------------------------------------------------------
CBitmap* UIBitmapNode::getBitmap (const std::string& pathHint)
{
if (bitmap == nullptr)
{
const std::string* path = attributes->getAttributeValue ("path");
if (path)
{
BitmapVariant bitmapVariant;
int32_t tmpValue {};
CRect offsets;
if (attributes->getRectAttribute ("nineparttiled-offsets", offsets))
{
bitmapVariant = CNinePartTiledDescription (offsets.left, offsets.top, offsets.right,
offsets.bottom);
}
else if (attributes->getIntegerAttribute ("multiframe-num-frames", tmpValue))
{
CMultiFrameBitmapDescription multiFrameDesc {};
multiFrameDesc.numFrames = static_cast<uint16_t> (tmpValue);
if (attributes->getIntegerAttribute ("mulitframe-frames-per-row", tmpValue))
multiFrameDesc.framesPerRow = static_cast<uint16_t> (tmpValue);
attributes->getPointAttribute ("multiframe-size", multiFrameDesc.frameSize);
bitmapVariant = multiFrameDesc;
}
bitmap = createBitmap (*path, bitmapVariant);
if (bitmap->getPlatformBitmap () == nullptr && pathIsAbsolute (pathHint))
{
std::string absPath = pathHint;
if (removeLastPathComponent (absPath))
{
absPath += "/" + *path;
if (auto platformBitmap =
getPlatformFactory ().createBitmapFromPath (absPath.c_str ()))
{
bitmap->setPlatformBitmap (platformBitmap);
}
}
}
}
if (bitmap && bitmap->getPlatformBitmap () == nullptr)
{
if (auto platformBitmap = createBitmapFromDataNode ())
bitmap->setPlatformBitmap (platformBitmap);
}
if (bitmap && path && bitmap->getPlatformBitmap () &&
bitmap->getPlatformBitmap ()->getScaleFactor () == 1.)
{
double scaleFactor = 1.;
if (Detail::decodeScaleFactorFromName (*path, scaleFactor))
{
bitmap->getPlatformBitmap ()->setScaleFactor (scaleFactor);
attributes->setDoubleAttribute ("scale-factor", scaleFactor);
}
}
}
return bitmap;
}
//-----------------------------------------------------------------------------
void UIBitmapNode::setBitmap (UTF8StringPtr bitmapName)
{
std::string name (bitmapName);
attributes->setAttribute ("path", name);
if (bitmap)
bitmap->forget ();
bitmap = nullptr;
double scaleFactor = 1.;
if (Detail::decodeScaleFactorFromName (name, scaleFactor))
attributes->setDoubleAttribute ("scale-factor", scaleFactor);
removeXMLData ();
}
//-----------------------------------------------------------------------------
void UIBitmapNode::setMultiFrameDesc (const CMultiFrameBitmapDescription* desc)
{
if (bitmap)
{
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap); mfb && desc)
{
mfb->setMultiFrameDesc (*desc);
}
else
{
bitmap->forget ();
bitmap = nullptr;
}
}
if (desc)
{
attributes->setPointAttribute ("multiframe-size", desc->frameSize);
attributes->setIntegerAttribute ("multiframe-num-frames", desc->numFrames);
attributes->setIntegerAttribute ("mulitframe-frames-per-row", desc->framesPerRow);
}
else
{
attributes->removeAttribute ("multiframe-size");
attributes->removeAttribute ("multiframe-num-frames");
attributes->removeAttribute ("mulitframe-frames-per-row");
}
}
//-----------------------------------------------------------------------------
void UIBitmapNode::setNinePartTiledOffset (const CRect* offsets)
{
if (bitmap)
{
auto* tiledBitmap = dynamic_cast<CNinePartTiledBitmap*> (bitmap);
if (offsets && tiledBitmap)
{
tiledBitmap->setPartOffsets (CNinePartTiledDescription (
offsets->left, offsets->top, offsets->right, offsets->bottom));
}
else
{
bitmap->forget ();
bitmap = nullptr;
}
}
if (offsets)
attributes->setRectAttribute ("nineparttiled-offsets", *offsets);
else
attributes->removeAttribute ("nineparttiled-offsets");
}
//-----------------------------------------------------------------------------
void UIBitmapNode::invalidBitmap ()
{
if (bitmap)
bitmap->forget ();
bitmap = nullptr;
filterProcessed = false;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
UIFontNode::UIFontNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
: UINode (name, attributes), font (nullptr)
{
}
//-----------------------------------------------------------------------------
UIFontNode::~UIFontNode () noexcept
{
if (font)
font->forget ();
}
//-----------------------------------------------------------------------------
void UIFontNode::freePlatformResources ()
{
if (font)
font->forget ();
font = nullptr;
}
//-----------------------------------------------------------------------------
CFontRef UIFontNode::getFont ()
{
if (font == nullptr)
{
const std::string* nameAttr = attributes->getAttributeValue ("font-name");
const std::string* sizeAttr = attributes->getAttributeValue ("size");
const std::string* boldAttr = attributes->getAttributeValue ("bold");
const std::string* italicAttr = attributes->getAttributeValue ("italic");
const std::string* underlineAttr = attributes->getAttributeValue ("underline");
const std::string* strikethroughAttr = attributes->getAttributeValue ("strike-through");
if (nameAttr)
{
int32_t size = 12;
if (sizeAttr)
size = (int32_t)strtol (sizeAttr->c_str (), nullptr, 10);
int32_t fontStyle = 0;
if (boldAttr && *boldAttr == "true")
fontStyle |= kBoldFace;
if (italicAttr && *italicAttr == "true")
fontStyle |= kItalicFace;
if (underlineAttr && *underlineAttr == "true")
fontStyle |= kUnderlineFace;
if (strikethroughAttr && *strikethroughAttr == "true")
fontStyle |= kStrikethroughFace;
if (attributes->hasAttribute ("alternative-font-names"))
{
std::list<std::string> fontNames;
getPlatformFactory ().getAllFontFamilies ([&fontNames] (const std::string& name) {
fontNames.push_back (name);
return true;
});
if (std::find (fontNames.begin (), fontNames.end (), *nameAttr) == fontNames.end ())
{
std::vector<std::string> alternativeFontNames;
attributes->getStringArrayAttribute ("alternative-font-names",
alternativeFontNames);
for (auto& alternateFontName : alternativeFontNames)
{
auto trimmedString = trim (UTF8String (alternateFontName));
if (std::find (fontNames.begin (), fontNames.end (),
trimmedString.getString ()) != fontNames.end ())
{
font = new CFontDesc (trimmedString.data (), size, fontStyle);
break;
}
}
}
}
if (font == nullptr)
font = new CFontDesc (nameAttr->c_str (), size, fontStyle);
}
}
return font;
}
//-----------------------------------------------------------------------------
void UIFontNode::setFont (CFontRef newFont)
{
if (font)
font->forget ();
font = newFont;
font->remember ();
std::string name (*attributes->getAttributeValue ("name"));
std::string alternativeNames;
getAlternativeFontNames (alternativeNames);
attributes->removeAll ();
attributes->setAttribute ("name", name);
attributes->setAttribute ("font-name", newFont->getName ().getString ());
std::stringstream str;
str << newFont->getSize ();
attributes->setAttribute ("size", str.str ());
if (newFont->getStyle () & kBoldFace)
attributes->setAttribute ("bold", "true");
if (newFont->getStyle () & kItalicFace)
attributes->setAttribute ("italic", "true");
if (newFont->getStyle () & kUnderlineFace)
attributes->setAttribute ("underline", "true");
if (newFont->getStyle () & kStrikethroughFace)
attributes->setAttribute ("strike-through", "true");
setAlternativeFontNames (alternativeNames.c_str ());
}
//-----------------------------------------------------------------------------
void UIFontNode::setAlternativeFontNames (UTF8StringPtr fontNames)
{
if (fontNames && fontNames[0] != 0)
{
attributes->setAttribute ("alternative-font-names", fontNames);
}
else
{
attributes->removeAttribute ("alternative-font-names");
}
}
//-----------------------------------------------------------------------------
bool UIFontNode::getAlternativeFontNames (std::string& fontNames)
{
const std::string* value = attributes->getAttributeValue ("alternative-font-names");
if (value)
{
fontNames = *value;
return true;
}
return false;
}
//-----------------------------------------------------------------------------
UIColorNode::UIColorNode (const std::string& name, const SharedPointer<UIAttributes>& attributes)
: UINode (name, attributes)
{
color.alpha = 255;
const std::string* red = attributes->getAttributeValue ("red");
const std::string* green = attributes->getAttributeValue ("green");
const std::string* blue = attributes->getAttributeValue ("blue");
const std::string* alpha = attributes->getAttributeValue ("alpha");
const std::string* rgb = attributes->getAttributeValue ("rgb");
const std::string* rgba = attributes->getAttributeValue ("rgba");
if (red)
color.red = (uint8_t)strtol (red->c_str (), nullptr, 10);
if (green)
color.green = (uint8_t)strtol (green->c_str (), nullptr, 10);
if (blue)
color.blue = (uint8_t)strtol (blue->c_str (), nullptr, 10);
if (alpha)
color.alpha = (uint8_t)strtol (alpha->c_str (), nullptr, 10);
if (rgb)
parseColor (*rgb, color);
if (rgba)
parseColor (*rgba, color);
}
//-----------------------------------------------------------------------------
void UIColorNode::setColor (const CColor& newColor)
{
std::string name (*attributes->getAttributeValue ("name"));
attributes->removeAll ();
attributes->setAttribute ("name", name);
std::string colorString;
UIViewCreator::colorToString (newColor, colorString, nullptr);
attributes->setAttribute ("rgba", colorString);
color = newColor;
}
//-----------------------------------------------------------------------------
UIGradientNode::UIGradientNode (const std::string& name,
const SharedPointer<UIAttributes>& attributes)
: UINode (name, attributes)
{
}
//-----------------------------------------------------------------------------
void UIGradientNode::freePlatformResources ()
{
gradient = nullptr;
}
//-----------------------------------------------------------------------------
CGradient* UIGradientNode::getGradient ()
{
if (gradient == nullptr)
{
GradientColorStopMap colorStops;
double start;
CColor color;
for (auto& colorNode : getChildren ())
{
if (colorNode->getName () == "color-stop")
{
const std::string* rgba = colorNode->getAttributes ()->getAttributeValue ("rgba");
if (rgba == nullptr ||
colorNode->getAttributes ()->getDoubleAttribute ("start", start) == false)
continue;
if (parseColor (*rgba, color) == false)
continue;
colorStops.emplace (start, color);
}
}
if (colorStops.size () > 1)
gradient = owned (CGradient::create (colorStops));
}
return gradient;
}
//-----------------------------------------------------------------------------
void UIGradientNode::setGradient (CGradient* g)
{
gradient = g;
getChildren ().removeAll ();
if (gradient == nullptr)
return;
const GradientColorStopMap colorStops = gradient->getColorStops ();
for (const auto& colorStop : colorStops)
{
UINode* node = new UINode ("color-stop");
node->getAttributes ()->setDoubleAttribute ("start", colorStop.first);
std::string colorString;
UIViewCreator::colorToString (colorStop.second, colorString, nullptr);
node->getAttributes ()->setAttribute ("rgba", colorString);
getChildren ().add (node);
}
}
} // Detail
} // VSTGUI
@@ -0,0 +1,201 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../../lib/vstguifwd.h"
#include "../uidescriptionfwd.h"
#include "../../lib/ccolor.h"
#include "uidesclist.h"
#include <variant>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace Detail {
//------------------------------------------------------------------------
namespace MainNodeNames {
static constexpr IdStringPtr kBitmap = "bitmaps";
static constexpr IdStringPtr kFont = "fonts";
static constexpr IdStringPtr kColor = "colors";
static constexpr IdStringPtr kControlTag = "control-tags";
static constexpr IdStringPtr kVariable = "variables";
static constexpr IdStringPtr kTemplate = "template";
static constexpr IdStringPtr kCustom = "custom";
static constexpr IdStringPtr kGradient = "gradients";
} // MainNodeNames
//-----------------------------------------------------------------------------
class UINode : public NonAtomicReferenceCounted
{
public:
using DataStorage = std::string;
UINode (const std::string& name, const SharedPointer<UIAttributes>& attributes = {},
bool needsFastChildNameAttributeLookup = false);
UINode (const std::string& name, const SharedPointer<UIDescList>& children,
const SharedPointer<UIAttributes>& attributes = {});
UINode (const UINode& n);
~UINode () noexcept override;
const std::string& getName () const { return name; }
DataStorage& getData () { return data; }
const DataStorage& getData () const { return data; }
void setData (DataStorage&& newData);
const SharedPointer<UIAttributes>& getAttributes () const { return attributes; }
UIDescList& getChildren () const { return *children; }
bool hasChildren () const;
void childAttributeChanged (UINode* child, const char* attributeName,
const char* oldAttributeValue);
enum
{
kNoExport = 1 << 0
};
bool noExport () const { return hasBit (flags, kNoExport); }
void noExport (bool state) { setBit (flags, kNoExport, state); }
bool operator== (const UINode& n) const { return name == n.name; }
void sortChildren ();
virtual void freePlatformResources () {}
protected:
std::string name;
DataStorage data;
SharedPointer<UIAttributes> attributes;
SharedPointer<UIDescList> children;
int32_t flags;
};
//-----------------------------------------------------------------------------
class UICommentNode : public UINode
{
public:
explicit UICommentNode (const std::string& comment);
};
//-----------------------------------------------------------------------------
class UIVariableNode : public UINode
{
public:
UIVariableNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
enum Type
{
kNumber,
kString,
kUnknown
};
Type getType () const;
double getNumber () const;
const std::string& getString () const;
protected:
Type type;
double number;
};
//-----------------------------------------------------------------------------
class UIControlTagNode : public UINode
{
public:
UIControlTagNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
int32_t getTag ();
void setTag (int32_t newTag);
const std::string* getTagString () const;
void setTagString (const std::string& str);
protected:
int32_t tag;
};
//-----------------------------------------------------------------------------
class UIBitmapNode : public UINode
{
public:
UIBitmapNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
CBitmap* getBitmap (const std::string& pathHint);
void setBitmap (UTF8StringPtr bitmapName);
void setMultiFrameDesc (const CMultiFrameBitmapDescription* desc);
void setNinePartTiledOffset (const CRect* offsets);
void invalidBitmap ();
bool getFilterProcessed () const { return filterProcessed; }
void setFilterProcessed () { filterProcessed = true; }
bool getScaledBitmapsAdded () const { return scaledBitmapsAdded; }
void setScaledBitmapsAdded () { scaledBitmapsAdded = true; }
void createXMLData (const std::string& pathHint);
void removeXMLData ();
bool hasXMLData () const;
void freePlatformResources () override;
protected:
~UIBitmapNode () noexcept override;
using BitmapVariant =
std::variant<uint32_t, CNinePartTiledDescription, CMultiFrameBitmapDescription>;
CBitmap* createBitmap (const std::string& str, const BitmapVariant& variant) const;
PlatformBitmapPtr createBitmapFromDataNode () const;
static bool imagesEqual (IPlatformBitmap* b1, IPlatformBitmap* b2);
UINode* dataNode () const;
CBitmap* bitmap;
bool filterProcessed;
bool scaledBitmapsAdded;
};
//-----------------------------------------------------------------------------
class UIFontNode : public UINode
{
public:
UIFontNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
CFontRef getFont ();
void setFont (CFontRef newFont);
void setAlternativeFontNames (UTF8StringPtr fontNames);
bool getAlternativeFontNames (std::string& fontNames);
void freePlatformResources () override;
protected:
~UIFontNode () noexcept override;
CFontRef font;
};
//-----------------------------------------------------------------------------
class UIColorNode : public UINode
{
public:
UIColorNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
const CColor& getColor () const { return color; }
void setColor (const CColor& newColor);
protected:
CColor color;
};
//-----------------------------------------------------------------------------
class UIGradientNode : public UINode
{
public:
UIGradientNode (const std::string& name, const SharedPointer<UIAttributes>& attributes);
CGradient* getGradient ();
void setGradient (CGradient* g);
void freePlatformResources () override;
protected:
SharedPointer<CGradient> gradient;
};
//------------------------------------------------------------------------
} // Detail
} // VSTGUI
@@ -0,0 +1,344 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../iuidescription.h"
#include <cstring>
namespace VSTGUI {
namespace UIViewCreator {
//-----------------------------------------------------------------------------
// view names
//-----------------------------------------------------------------------------
static const IdStringPtr kCView = "CView";
static const IdStringPtr kCViewContainer = "CViewContainer";
static const IdStringPtr kCLayeredViewContainer = "CLayeredViewContainer";
static const IdStringPtr kCRowColumnView = "CRowColumnView";
static const IdStringPtr kCScrollView = "CScrollView";
static const IdStringPtr kUIViewSwitchContainer = "UIViewSwitchContainer";
static const IdStringPtr kCSplitView = "CSplitView";
static const IdStringPtr kCShadowViewContainer = "CShadowViewContainer";
static const IdStringPtr kCControl = "CControl";
static const IdStringPtr kCOnOffButton = "COnOffButton";
static const IdStringPtr kCCheckBox = "CCheckBox";
static const IdStringPtr kCParamDisplay = "CParamDisplay";
static const IdStringPtr kCXYPad = "CXYPad";
static const IdStringPtr kCOptionMenu = "COptionMenu";
static const IdStringPtr kCTextLabel = "CTextLabel";
static const IdStringPtr kCMultiLineTextLabel = "CMultiLineTextLabel";
static const IdStringPtr kCTextEdit = "CTextEdit";
static const IdStringPtr kCSearchTextEdit = "CSearchTextEdit";
static const IdStringPtr kCTextButton = "CTextButton";
static const IdStringPtr kCSegmentButton = "CSegmentButton";
static const IdStringPtr kCKnob = "CKnob";
static const IdStringPtr kCAnimKnob = "CAnimKnob";
static const IdStringPtr kCVerticalSwitch = "CVerticalSwitch";
static const IdStringPtr kCHorizontalSwitch = "CHorizontalSwitch";
static const IdStringPtr kCRockerSwitch = "CRockerSwitch";
static const IdStringPtr kCMovieBitmap = "CMovieBitmap";
static const IdStringPtr kCMovieButton = "CMovieButton";
static const IdStringPtr kCKickButton = "CKickButton";
static const IdStringPtr kCSlider = "CSlider";
static const IdStringPtr kCVuMeter = "CVuMeter";
static const IdStringPtr kCAnimationSplashScreen = "CAnimationSplashScreen";
static const IdStringPtr kCGradientView = "CGradientView";
static const IdStringPtr kCStringListControl = "CStringListControl";
static const IdStringPtr kCAutoAnimation = "CAutoAnimation";
//-----------------------------------------------------------------------------
// attributes used in more than one view creator
//-----------------------------------------------------------------------------
static const std::string kAttrClass = "class";
static const std::string kAttrTitle = "title";
static const std::string kAttrFont = "font";
static const std::string kAttrFontColor = "font-color";
static const std::string kAttrFrameColor = "frame-color";
static const std::string kAttrTextAlignment = "text-alignment";
static const std::string kAttrRoundRectRadius = "round-rect-radius";
static const std::string kAttrFrameWidth = "frame-width";
static const std::string kAttrGradientStartColor = "gradient-start-color";
static const std::string kAttrGradientEndColor = "gradient-end-color";
static const std::string kAttrZoomFactor = "zoom-factor";
static const std::string kAttrHandleBitmap = "handle-bitmap";
static const std::string kAttrOrientation = "orientation";
static const std::string kAttrAnimationTime = "animation-time";
static const std::string kAttrGradient = "gradient";
//-----------------------------------------------------------------------------
// CViewCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrOrigin = "origin";
static const std::string kAttrSize = "size";
static const std::string kAttrTransparent = "transparent";
static const std::string kAttrMouseEnabled = "mouse-enabled";
static const std::string kAttrWantsFocus = "wants-focus";
static const std::string kAttrBitmap = "bitmap";
static const std::string kAttrDisabledBitmap = "disabled-bitmap";
static const std::string kAttrAutosize = "autosize";
static const std::string kAttrTooltip = "tooltip";
static const std::string kAttrCustomViewName = IUIDescription::kCustomViewName;
static const std::string kAttrSubController = "sub-controller";
static const std::string kAttrUIDescLabel = "uidesc-label";
static const std::string kAttrOpacity = "opacity";
//-----------------------------------------------------------------------------
// CViewContainerCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrBackgroundColor = "background-color";
static const std::string kAttrBackgroundColorDrawStyle = "background-color-draw-style";
//-----------------------------------------------------------------------------
// CLayeredViewContainerCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrZIndex = "z-index";
//-----------------------------------------------------------------------------
// CRowColumnViewCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrRowStyle = "row-style";
static const std::string kAttrSpacing = "spacing";
static const std::string kAttrMargin = "margin";
static const std::string kAttrAnimateViewResizing = "animate-view-resizing";
static const std::string kAttrHideClippedSubviews = "hide-clipped-subviews";
static const std::string kAttrEqualSizeLayout = "equal-size-layout";
static const std::string kAttrViewResizeAnimationTime = "view-resize-animation-time";
//-----------------------------------------------------------------------------
// CScrollViewCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrContainerSize = "container-size";
static const std::string kAttrHorizontalScrollbar = "horizontal-scrollbar";
static const std::string kAttrVerticalScrollbar = "vertical-scrollbar";
static const std::string kAttrAutoDragScrolling = "auto-drag-scrolling";
static const std::string kAttrBordered = "bordered";
static const std::string kAttrOverlayScrollbars = "overlay-scrollbars";
static const std::string kAttrFollowFocusView = "follow-focus-view";
static const std::string kAttrAutoHideScrollbars = "auto-hide-scrollbars";
static const std::string kAttrScrollbarBackgroundColor = "scrollbar-background-color";
static const std::string kAttrScrollbarFrameColor = "scrollbar-frame-color";
static const std::string kAttrScrollbarScrollerColor = "scrollbar-scroller-color";
static const std::string kAttrScrollbarWidth = "scrollbar-width";
static const std::string kAttrMinScrollerSize = "scrollbar-min-scroller-size";
//-----------------------------------------------------------------------------
// CControlCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrControlTag = "control-tag";
static const std::string kAttrDefaultValue = "default-value";
static const std::string kAttrMinValue = "min-value";
static const std::string kAttrMaxValue = "max-value";
static const std::string kAttrWheelIncValue = "wheel-inc-value";
static const std::string kAttrBackgroundOffset = "background-offset";
//-----------------------------------------------------------------------------
// CCheckBoxCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrBoxframeColor = "boxframe-color";
static const std::string kAttrBoxfillColor = "boxfill-color";
static const std::string kAttrCheckmarkColor = "checkmark-color";
static const std::string kAttrDrawCrossbox = "draw-crossbox";
static const std::string kAttrAutosizeToFit = "autosize-to-fit";
//-----------------------------------------------------------------------------
// CParamDisplayCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrBackColor = "back-color";
static const std::string kAttrShadowColor = "shadow-color";
static const std::string kAttrFontAntialias = "font-antialias";
static const std::string kAttrStyle3DIn = "style-3D-in";
static const std::string kAttrStyle3DOut = "style-3D-out";
static const std::string kAttrStyleNoFrame = "style-no-frame";
static const std::string kAttrStyleNoText = "style-no-text";
static const std::string kAttrStyleNoDraw = "style-no-draw";
static const std::string kAttrStyleShadowText = "style-shadow-text";
static const std::string kAttrStyleRoundRect = "style-round-rect";
static const std::string kAttrTextInset = "text-inset";
static const std::string kAttrValuePrecision = "value-precision";
static const std::string kAttrTextRotation = "text-rotation";
static const std::string kAttrTextShadowOffset = "text-shadow-offset";
//-----------------------------------------------------------------------------
// COptionMenuCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrMenuPopupStyle = "menu-popup-style";
static const std::string kAttrMenuCheckStyle = "menu-check-style";
//-----------------------------------------------------------------------------
// CTextLabelCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrTruncateMode = "truncate-mode";
//-----------------------------------------------------------------------------
// CMultiLineTextLabelCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrLineLayout = "line-layout";
static const std::string kAttrAutoHeight = "auto-height";
static const std::string kAttrVerticalCentered = "vertical-centered";
//-----------------------------------------------------------------------------
// CTextEditCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrSecureStyle = "secure-style";
static const std::string kAttrImmediateTextChange = "immediate-text-change";
static const std::string kAttrStyleDoubleClick = "style-doubleclick";
static const std::string kAttrPlaceholderTitle = "placeholder-title";
static const std::string kAttrClearMarkInset = "clearmark-inset";
//-----------------------------------------------------------------------------
// CTextButtonCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrTextColor = "text-color";
static const std::string kAttrTextColorHighlighted = "text-color-highlighted";
static const std::string kAttrGradientStartColorHighlighted = "gradient-start-color-highlighted";
static const std::string kAttrGradientEndColorHighlighted = "gradient-end-color-highlighted";
static const std::string kAttrFrameColorHighlighted = "frame-color-highlighted";
static const std::string kAttrRoundRadius = "round-radius";
static const std::string kAttrKickStyle = "kick-style";
static const std::string kAttrIcon = "icon";
static const std::string kAttrIconHighlighted = "icon-highlighted";
static const std::string kAttrIconPosition = "icon-position";
static const std::string kAttrIconTextMargin = "icon-text-margin";
static const std::string kAttrGradientHighlighted = "gradient-highlighted";
//-----------------------------------------------------------------------------
// CSegmentButtonCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrStyle = "style";
static const std::string kAttrSelectionMode = "selection-mode";
static const std::string kAttrSegmentNames = "segment-names";
//-----------------------------------------------------------------------------
// CKnobCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrAngleStart = "angle-start";
static const std::string kAttrAngleRange = "angle-range";
static const std::string kAttrKnobRange = "knob-range";
static const std::string kAttrValueInset = "value-inset";
static const std::string kAttrCoronaInset = "corona-inset";
static const std::string kAttrCoronaColor = "corona-color";
static const std::string kAttrCoronaDrawing = "corona-drawing";
static const std::string kAttrCoronaOutline = "corona-outline";
static const std::string kAttrCoronaInverted = "corona-inverted";
static const std::string kAttrCoronaFromCenter = "corona-from-center";
static const std::string kAttrCoronaDashDot = "corona-dash-dot";
static const std::string kAttrCoronaDashDotLengths = "corona-dash-dot-lengths";
static const std::string kAttrHandleColor = "handle-color";
static const std::string kAttrHandleShadowColor = "handle-shadow-color";
static const std::string kAttrHandleLineWidth = "handle-line-width";
static const std::string kAttrCircleDrawing = "circle-drawing";
static const std::string kAttrCoronaLineCapButt = "corona-line-cap-butt";
static const std::string kAttrSkipHandleDrawing = "skip-handle-drawing";
static const std::string kAttrCoronaOutlineWidthAdd = "corona-outline-width-add";
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//-----------------------------------------------------------------------------
// IMultiBitmapControlCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrHeightOfOneImage = "height-of-one-image";
static const std::string kAttrSubPixmaps = "sub-pixmaps";
#endif
//-----------------------------------------------------------------------------
// CAnimKnobCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrInverseBitmap = "inverse-bitmap";
//-----------------------------------------------------------------------------
// CSliderCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrMode = "mode";
static const std::string kAttrHandleOffset = "handle-offset";
static const std::string kAttrBitmapOffset = "bitmap-offset";
static const std::string kAttrReverseOrientation = "reverse-orientation";
static const std::string kAttrDrawFrame = "draw-frame";
static const std::string kAttrDrawBack = "draw-back";
static const std::string kAttrDrawValue = "draw-value";
static const std::string kAttrDrawValueInverted = "draw-value-inverted";
static const std::string kAttrDrawValueFromCenter = "draw-value-from-center";
static const std::string kAttrDrawFrameColor = "draw-frame-color";
static const std::string kAttrDrawBackColor = "draw-back-color";
static const std::string kAttrDrawValueColor = "draw-value-color";
//-----------------------------------------------------------------------------
// CVuMeterCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrOffBitmap = "off-bitmap";
static const std::string kAttrNumLed = "num-led";
static const std::string kAttrDecreaseStepValue = "decrease-step-value";
//-----------------------------------------------------------------------------
// CAnimationSplashScreenCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrSplashBitmap = "splash-bitmap";
static const std::string kAttrSplashOrigin = "splash-origin";
static const std::string kAttrSplashSize = "splash-size";
static const std::string kAttrAnimationIndex = "animation-index";
//-----------------------------------------------------------------------------
// UIViewSwitchContainerCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrTemplateNames = "template-names";
static const std::string kAttrTemplateSwitchControl = "template-switch-control";
static const std::string kAttrAnimationStyle = "animation-style";
static const std::string kAttrAnimationTimingFunction = "animation-timing-function";
//-----------------------------------------------------------------------------
// CSplitViewCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrSeparatorWidth = "separator-width";
static const std::string kAttrResizeMethod = "resize-method";
//-----------------------------------------------------------------------------
// CShadowViewContainerCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrShadowIntensity = "shadow-intensity";
static const std::string kAttrShadowBlurSize = "shadow-blur-size";
static const std::string kAttrShadowOffset = "shadow-offset";
//-----------------------------------------------------------------------------
// CGradientViewCreator attributes
//-----------------------------------------------------------------------------
static const std::string kAttrGradientAngle = "gradient-angle";
static const std::string kAttrGradientStyle = "gradient-style";
static const std::string kAttrGradientStartColorOffset = "gradient-start-color-offset";
static const std::string kAttrGradientEndColorOffset = "gradient-end-color-offset";
static const std::string kAttrDrawAntialiased = "draw-antialiased";
static const std::string kAttrRadialCenter = "radial-center";
static const std::string kAttrRadialRadius = "radial-radius";
//------------------------------------------------------------------------
// StringListControlCreator attributes
//------------------------------------------------------------------------
static const std::string kAttrSelectedFontColor = "font-color-selected";
static const std::string kAttrSelectedBackColor = "back-color-selected";
static const std::string kAttrLineColor = "line-color";
static const std::string kAttrLineWidth = "line-width";
static const std::string kAttrHoverColor = "hover-color";
static const std::string kAttrRowHeight = "row-height";
static const std::string kAttrStyleHover = "style-hover";
//------------------------------------------------------------------------
// Some globally used strings
//------------------------------------------------------------------------
static constexpr auto strTrue = "true";
static constexpr auto strFalse = "false";
static constexpr auto strHorizontal = "horizontal";
static constexpr auto strVertical = "vertical";
static constexpr auto strHorizontalInverse = "horizontal-inverse";
static constexpr auto strVerticalInverse = "vertical-inverse";
static constexpr auto strNone = "none";
static constexpr auto strHead = "head";
static constexpr auto strTail = "tail";
static constexpr auto strLeft = "left";
static constexpr auto strRight = "right";
static constexpr auto strCenter = "center";
} // UIViewCreator
} // VSTGUI
@@ -0,0 +1,315 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "uixmlpersistence.h"
#if VSTGUI_ENABLE_XML_PARSER
#include "../uiattributes.h"
#include "../cstream.h"
#include <map>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace Detail {
//-----------------------------------------------------------------------------
SharedPointer<UINode> UIXMLParser::parse (IContentProvider* provider)
{
Xml::Parser parser;
if (parser.parse (provider, this))
return std::move (nodes);
return nullptr;
}
//-----------------------------------------------------------------------------
void UIXMLParser::startXmlElement (Xml::Parser* parser, IdStringPtr elementName, UTF8StringPtr* elementAttributes)
{
std::string name (elementName);
if (nodes)
{
UINode* parent = nodeStack.back ();
UINode* newNode = nullptr;
if (restoreViewsMode)
{
if (name != "view" && name != MainNodeNames::kCustom)
{
parser->stop ();
}
newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes));
}
else
{
if (parent == nodes)
{
// only allowed second level elements
if (name == MainNodeNames::kControlTag || name == MainNodeNames::kColor || name == MainNodeNames::kBitmap)
newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes), true);
else if (name == MainNodeNames::kFont || name == MainNodeNames::kTemplate
|| name == MainNodeNames::kControlTag || name == MainNodeNames::kCustom
|| name == MainNodeNames::kVariable || name == MainNodeNames::kGradient)
newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes));
else
parser->stop ();
}
else if (parent->getName () == MainNodeNames::kBitmap)
{
if (name == "bitmap")
newNode = new UIBitmapNode (name, makeOwned<UIAttributes> (elementAttributes));
else
parser->stop ();
}
else if (parent->getName () == MainNodeNames::kFont)
{
if (name == "font")
newNode = new UIFontNode (name, makeOwned<UIAttributes> (elementAttributes));
else
parser->stop ();
}
else if (parent->getName () == MainNodeNames::kColor)
{
if (name == "color")
newNode = new UIColorNode (name, makeOwned<UIAttributes> (elementAttributes));
else
parser->stop ();
}
else if (parent->getName () == MainNodeNames::kControlTag)
{
if (name == "control-tag")
newNode = new UIControlTagNode (name, makeOwned<UIAttributes> (elementAttributes));
else
parser->stop ();
}
else if (parent->getName () == MainNodeNames::kVariable)
{
if (name == "var")
newNode = new UIVariableNode (name, makeOwned<UIAttributes> (elementAttributes));
else
parser->stop ();
}
else if (parent->getName () == MainNodeNames::kGradient)
{
if (name == "gradient")
newNode = new UIGradientNode (name, makeOwned<UIAttributes> (elementAttributes));
else
parser->stop ();
}
else
newNode = new UINode (name, makeOwned<UIAttributes> (elementAttributes));
}
if (newNode)
{
parent->getChildren ().add (newNode);
nodeStack.emplace_back (newNode);
}
}
else if (name == "vstgui-ui-description")
{
nodes = makeOwned<UINode> (name, makeOwned<UIAttributes> (elementAttributes));
nodeStack.emplace_back (nodes);
}
else if (name == "vstgui-ui-description-view-list")
{
vstgui_assert (nodes == nullptr);
nodes = makeOwned<UINode> (name, makeOwned<UIAttributes> (elementAttributes));
nodeStack.emplace_back (nodes);
restoreViewsMode = true;
}
}
//-----------------------------------------------------------------------------
void UIXMLParser::endXmlElement (Xml::Parser* parser, IdStringPtr name)
{
if (nodeStack.back () == nodes)
restoreViewsMode = false;
nodeStack.pop_back ();
}
//-----------------------------------------------------------------------------
void UIXMLParser::xmlCharData (Xml::Parser* parser, const int8_t* data, int32_t length)
{
if (nodeStack.empty ())
return;
auto& nodeData = nodeStack.back ()->getData ();
const int8_t* dataStart = nullptr;
uint32_t validChars = 0;
for (int32_t i = 0; i < length; i++, ++data)
{
if (*data < 0x21)
{
if (dataStart)
{
nodeData.append (reinterpret_cast<const char*> (dataStart), validChars);
dataStart = nullptr;
validChars = 0;
}
continue;
}
if (dataStart == nullptr)
dataStart = data;
++validChars;
}
if (dataStart && validChars > 0)
nodeData.append (reinterpret_cast<const char*> (dataStart), validChars);
}
//-----------------------------------------------------------------------------
void UIXMLParser::xmlComment (Xml::Parser* parser, IdStringPtr comment)
{
#if VSTGUI_LIVE_EDITING
if (nodeStack.empty ())
{
#if DEBUG
DebugPrint ("*** WARNING : Comment outside of root tag will be removed on save !\nComment: %s\n", comment);
#endif
return;
}
UINode* parent = nodeStack.back ();
if (parent && comment)
{
std::string commentStr (comment);
if (!commentStr.empty ())
{
UICommentNode* commentNode = new UICommentNode (comment);
parent->getChildren ().add (commentNode);
}
}
#endif
}
//-----------------------------------------------------------------------------
bool UIXMLDescWriter::write (OutputStream& stream, UINode* rootNode)
{
intendLevel = 0;
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
return writeNode (rootNode, stream);
}
//-----------------------------------------------------------------------------
void UIXMLDescWriter::encodeAttributeString (std::string& str)
{
const int8_t entities[] = {'&', '<','>', '\'', '\"', 0};
const char* replacements[] = {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"};
int32_t i = 0;
while (entities[i] != 0)
{
size_t pos = 0;
while ((pos = str.find (entities[i], pos)) != std::string::npos)
{
str.replace (pos, 1, replacements[i]);
pos++;
}
i++;
}
}
//-----------------------------------------------------------------------------
bool UIXMLDescWriter::writeAttributes (UIAttributes* attr, OutputStream& stream)
{
bool result = true;
using SortedAttributes = std::map<std::string,std::string>;
SortedAttributes sortedAttributes (attr->begin (), attr->end ());
for (auto& sa : sortedAttributes)
{
if (sa.second.length () > 0)
{
stream << " ";
stream << sa.first;
stream << "=\"";
std::string value (sa.second);
encodeAttributeString (value);
stream << value;
stream << "\"";
}
}
return result;
}
//-----------------------------------------------------------------------------
bool UIXMLDescWriter::writeNodeData (UINode::DataStorage& str, OutputStream& stream)
{
for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
uint32_t i = 0;
for (auto c : str)
{
stream << static_cast<int8_t> (c);
if (i++ > 80)
{
stream << "\n";
i = 0;
for (int32_t i2 = 0; i2 < intendLevel; i2++) stream << "\t";
}
}
stream << "\n";
return true;
}
//-----------------------------------------------------------------------------
bool UIXMLDescWriter::writeComment (UICommentNode* node, OutputStream& stream)
{
stream << "<!--";
stream << node->getData ();
stream << "-->\n";
return true;
}
//-----------------------------------------------------------------------------
bool UIXMLDescWriter::writeNode (UINode* node, OutputStream& stream)
{
if (!node)
return false;
bool result = true;
if (node->noExport ())
return result;
for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
if (auto* commentNode = dynamic_cast<UICommentNode*> (node))
{
return writeComment (commentNode, stream);
}
stream << "<";
stream << node->getName ();
result = writeAttributes (node->getAttributes (), stream);
if (result)
{
UIDescList& children = node->getChildren ();
if (!children.empty ())
{
stream << ">\n";
intendLevel++;
if (!node->getData ().empty ())
result = writeNodeData (node->getData (), stream);
for (auto& childNode : children)
{
if (!writeNode (childNode, stream))
return false;
}
intendLevel--;
for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
stream << "</";
stream << node->getName ();
stream << ">\n";
}
else if (!node->getData ().empty ())
{
stream << ">\n";
intendLevel++;
result = writeNodeData (node->getData (), stream);
intendLevel--;
for (int32_t i = 0; i < intendLevel; i++) stream << "\t";
stream << "</";
stream << node->getName ();
stream << ">\n";
}
else
stream << "/>\n";
}
return result;
}
//------------------------------------------------------------------------
} // Detail
} // VSTGUI
#endif // VSTGUI_ENABLE_XML_PARSER
@@ -0,0 +1,60 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../../lib/vstguibase.h"
#if VSTGUI_ENABLE_XML_PARSER
#include "uinode.h"
#include "../xmlparser.h"
#include <deque>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace Detail {
//-----------------------------------------------------------------------------
struct UIXMLParser : public Xml::IHandler
{
SharedPointer<UINode> parse (IContentProvider* provider);
void startXmlElement (Xml::Parser* parser, IdStringPtr elementName, UTF8StringPtr* elementAttributes) override;
void endXmlElement (Xml::Parser* parser, IdStringPtr name) override;
void xmlCharData (Xml::Parser* parser, const int8_t* data, int32_t length) override;
void xmlComment (Xml::Parser* parser, IdStringPtr comment) override;
const SharedPointer<UINode> getNodes () const { return nodes; }
private:
SharedPointer<UINode> nodes;
std::deque<UINode*> nodeStack;
bool restoreViewsMode {false};
};
//-----------------------------------------------------------------------------
class UIXMLDescWriter
{
public:
using UINode = Detail::UINode;
using UICommentNode = Detail::UICommentNode;
bool write (OutputStream& stream, UINode* rootNode);
protected:
static void encodeAttributeString (std::string& str);
bool writeNode (UINode* node, OutputStream& stream);
bool writeComment (UICommentNode* node, OutputStream& stream);
bool writeNodeData (UINode::DataStorage& str, OutputStream& stream);
bool writeAttributes (UIAttributes* attr, OutputStream& stream);
int32_t intendLevel;
};
//------------------------------------------------------------------------
} // Detail
} // VSTGUI
#endif