435 lines
12 KiB
C++
435 lines
12 KiB
C++
// 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 "cstream.h"
|
|
#include "../lib/cpoint.h"
|
|
#include "../lib/crect.h"
|
|
#include "../lib/cstring.h"
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
|
|
namespace VSTGUI {
|
|
namespace {
|
|
|
|
//------------------------------------------------------------------------
|
|
template<bool OnlyInteger>
|
|
Optional<std::string> trimmedNumericalString (const std::string& str, size_t from, size_t numChars)
|
|
{
|
|
std::string result;
|
|
auto strSize = str.size ();
|
|
if (from >= strSize)
|
|
return {};
|
|
auto points = 0u;
|
|
auto to = numChars == std::string::npos ? strSize : from + numChars;
|
|
for (auto i = from; i < to && i < strSize; ++i)
|
|
{
|
|
auto c = str[i];
|
|
if (!std::isspace (c))
|
|
{
|
|
if (!std::isdigit (c) && c != '-' && c != '+')
|
|
{
|
|
if (!OnlyInteger && c == '.' && points == 0u)
|
|
++points;
|
|
else if (points == 1u && c == 'e')
|
|
{
|
|
}
|
|
else
|
|
return {};
|
|
}
|
|
result.push_back (c);
|
|
}
|
|
}
|
|
return Optional<std::string> {std::move (result)};
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
//-----------------------------------------------------------------------------
|
|
std::string UIAttributes::pointToString (CPoint p)
|
|
{
|
|
return doubleToString (p.x) + ", " + doubleToString (p.y);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::stringToPoint (const std::string& str, CPoint& p)
|
|
{
|
|
size_t start = 0;
|
|
size_t pos = str.find (",", start, 1);
|
|
if (pos != std::string::npos)
|
|
{
|
|
std::vector<std::string> subStrings;
|
|
while (pos != std::string::npos)
|
|
{
|
|
if (!subStrings.empty ())
|
|
return false;
|
|
if (auto subStr = trimmedNumericalString<false> (str, start, pos - start))
|
|
subStrings.emplace_back (std::move (*subStr));
|
|
else
|
|
return false;
|
|
start = pos + 1;
|
|
pos = str.find (",", start, 1);
|
|
}
|
|
if (auto subStr = trimmedNumericalString<false> (str, start, std::string::npos))
|
|
subStrings.emplace_back (std::move (*subStr));
|
|
else
|
|
return false;
|
|
if (subStrings.size () == 2)
|
|
{
|
|
p.x = UTF8StringView (subStrings[0].data ()).toDouble ();
|
|
p.y = UTF8StringView (subStrings[1].data ()).toDouble ();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
std::string UIAttributes::doubleToString (double value, uint32_t precision)
|
|
{
|
|
std::stringstream str;
|
|
str.imbue (std::locale::classic ());
|
|
str.precision (precision);
|
|
str << value;
|
|
return str.str ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::stringToDouble (const std::string& str, double& value)
|
|
{
|
|
if (auto string = trimmedNumericalString<false> (str, 0, str.size ()))
|
|
{
|
|
std::istringstream sstream (*string);
|
|
sstream.imbue (std::locale::classic ());
|
|
sstream >> value;
|
|
return sstream.fail () == false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
std::string UIAttributes::boolToString (bool value)
|
|
{
|
|
return value ? "true" : "false";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::stringToBool (const std::string& str, bool& value)
|
|
{
|
|
if (str == "true")
|
|
{
|
|
value = true;
|
|
return true;
|
|
}
|
|
if (str == "false")
|
|
{
|
|
value = false;
|
|
return true;
|
|
}
|
|
int32_t intValue;
|
|
if (stringToInteger (str, intValue))
|
|
{
|
|
value = intValue != 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
std::string UIAttributes::integerToString (int32_t value)
|
|
{
|
|
std::stringstream str;
|
|
str << value;
|
|
return str.str ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::stringToInteger (const std::string& str, int32_t& value)
|
|
{
|
|
if (auto string = trimmedNumericalString<true> (str, 0, str.size ()))
|
|
{
|
|
std::istringstream sstream (*string);
|
|
sstream.imbue (std::locale::classic ());
|
|
sstream >> value;
|
|
return sstream.fail () == false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
std::string UIAttributes::rectToString (CRect r, uint32_t precision)
|
|
{
|
|
return doubleToString (r.left) + ", " + doubleToString (r.top) + ", " +
|
|
doubleToString (r.right) + ", " + doubleToString (r.bottom);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::stringToRect (const std::string& str, CRect& r)
|
|
{
|
|
size_t start = 0;
|
|
size_t pos = str.find (",", start, 1);
|
|
if (pos != std::string::npos)
|
|
{
|
|
std::vector<std::string> subStrings;
|
|
while (pos != std::string::npos)
|
|
{
|
|
if (subStrings.size () >= 3)
|
|
return false;
|
|
if (auto subStr = trimmedNumericalString<false> (str, start, pos - start))
|
|
subStrings.emplace_back (std::move (*subStr));
|
|
else
|
|
return false;
|
|
start = pos + 1;
|
|
pos = str.find (",", start, 1);
|
|
}
|
|
if (auto subStr = trimmedNumericalString<false> (str, start, std::string::npos))
|
|
subStrings.emplace_back (std::move (*subStr));
|
|
else
|
|
return false;
|
|
if (subStrings.size () == 4)
|
|
{
|
|
r.left = UTF8StringView (subStrings[0].data ()).toDouble ();
|
|
r.top = UTF8StringView (subStrings[1].data ()).toDouble ();
|
|
r.right = UTF8StringView (subStrings[2].data ()).toDouble ();
|
|
r.bottom = UTF8StringView (subStrings[3].data ()).toDouble ();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
std::string UIAttributes::stringArrayToString (const StringArray& values)
|
|
{
|
|
if (values.empty())
|
|
return {};
|
|
|
|
std::string value;
|
|
size_t numValues = values.size ();
|
|
for (size_t i = 0; i < numValues - 1; i++)
|
|
{
|
|
value += values[i];
|
|
value += ',';
|
|
}
|
|
value += values[numValues-1];
|
|
return value;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::stringToStringArray (const std::string& str, std::vector<std::string>& values)
|
|
{
|
|
std::stringstream ss (str);
|
|
std::string item;
|
|
while (std::getline (ss, item, ','))
|
|
{
|
|
values.emplace_back (std::move (item));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
UIAttributes::UIAttributes (UTF8StringPtr* attributes)
|
|
{
|
|
if (attributes)
|
|
{
|
|
size_t count = 0;
|
|
while (attributes[count] != nullptr && attributes[count+1] != nullptr)
|
|
count += 2;
|
|
if (count)
|
|
UIAttributesMap::reserve (count / 2);
|
|
|
|
int32_t i = 0;
|
|
while (attributes[i] != nullptr && attributes[i+1] != nullptr)
|
|
{
|
|
emplace (attributes[i], attributes[i+1]);
|
|
i += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
UIAttributes::UIAttributes (size_t reserve)
|
|
{
|
|
UIAttributesMap::reserve (reserve);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::hasAttribute (const std::string& name) const
|
|
{
|
|
if (getAttributeValue (name) != nullptr)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
const std::string* UIAttributes::getAttributeValue (const std::string& name) const
|
|
{
|
|
const_iterator iter = find (name);
|
|
if (iter != end ())
|
|
return &iter->second;
|
|
return nullptr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setAttribute (const std::string& name, const std::string& value)
|
|
{
|
|
iterator iter = find (name);
|
|
if (iter != end ())
|
|
iter->second = value;
|
|
else
|
|
emplace (name, value);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setAttribute (const std::string& name, std::string&& value)
|
|
{
|
|
iterator iter = find (name);
|
|
if (iter != end ())
|
|
iter->second = std::move (value);
|
|
else
|
|
emplace (name, std::move (value));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setAttribute (std::string&& name, std::string&& value)
|
|
{
|
|
iterator iter = find (name);
|
|
if (iter != end ())
|
|
iter->second = std::move (value);
|
|
else
|
|
emplace (std::move (name), std::move (value));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::removeAttribute (const std::string& name)
|
|
{
|
|
iterator iter = find (name);
|
|
if (iter != end ())
|
|
erase (iter);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setDoubleAttribute (const std::string& name, double value)
|
|
{
|
|
setAttribute (name, doubleToString (value, 40));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::getDoubleAttribute (const std::string& name, double& value) const
|
|
{
|
|
if (auto str = getAttributeValue (name))
|
|
return stringToDouble (*str, value);
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setBooleanAttribute (const std::string& name, bool value)
|
|
{
|
|
setAttribute (name, boolToString (value));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::getBooleanAttribute (const std::string& name, bool& value) const
|
|
{
|
|
if (auto str = getAttributeValue (name))
|
|
return stringToBool (*str, value);
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setIntegerAttribute (const std::string& name, int32_t value)
|
|
{
|
|
setAttribute (name, integerToString (value));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::getIntegerAttribute (const std::string& name, int32_t& value) const
|
|
{
|
|
if (auto str = getAttributeValue (name))
|
|
return stringToInteger(*str, value);
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setPointAttribute (const std::string& name, const CPoint& p)
|
|
{
|
|
setAttribute (name, pointToString (p));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::getPointAttribute (const std::string& name, CPoint& p) const
|
|
{
|
|
if (auto str = getAttributeValue (name))
|
|
return stringToPoint (*str, p);
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setRectAttribute (const std::string& name, const CRect& r)
|
|
{
|
|
setAttribute (name, rectToString (r));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::getRectAttribute (const std::string& name, CRect& r) const
|
|
{
|
|
if (auto str = getAttributeValue (name))
|
|
return stringToRect (*str, r);
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIAttributes::setStringArrayAttribute (const std::string& name, const StringArray& values)
|
|
{
|
|
setAttribute (name, stringArrayToString (values));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::getStringArrayAttribute (const std::string& name, StringArray& values) const
|
|
{
|
|
if (auto str = getAttributeValue (name))
|
|
return stringToStringArray(*str, values);
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::store (OutputStream& stream) const
|
|
{
|
|
if (!(stream << (int32_t)'UIAT')) return false;
|
|
if (!(stream << (uint32_t)size ())) return false;
|
|
const_iterator it = begin ();
|
|
while (it != end ())
|
|
{
|
|
if (!(stream << (*it).first)) return false;
|
|
if (!(stream << (*it).second)) return false;
|
|
++it;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIAttributes::restore (InputStream& stream)
|
|
{
|
|
int32_t identifier;
|
|
if (!(stream >> identifier)) return false;
|
|
if (identifier == 'UIAT')
|
|
{
|
|
uint32_t numAttr;
|
|
if (!(stream >> numAttr)) return false;
|
|
for (uint32_t i = 0; i < numAttr; i++)
|
|
{
|
|
std::string key, value;
|
|
if (!(stream >> key)) return false;
|
|
if (!(stream >> value)) return false;
|
|
setAttribute (std::move (key), std::move (value));
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|