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,646 @@
// 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 "../../include/helpers/value.h"
#include "../../../lib/algorithm.h"
#include "../../../lib/dispatchlist.h"
#include "../../include/ivaluelistener.h"
#include <algorithm>
#include <sstream>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace Standalone {
namespace Detail {
namespace /* anonymous */ {
//------------------------------------------------------------------------
IValue::Type convertStepToValue (IStepValue::StepType step, IStepValue::StepType steps)
{
return static_cast<IValue::Type> (step) / static_cast<IValue::Type> (steps);
}
//------------------------------------------------------------------------
IStepValue::StepType convertValueToStep (IValue::Type value, IStepValue::StepType steps)
{
return std::min (
steps, static_cast<IStepValue::StepType> (value * static_cast<IValue::Type> (steps + 1)));
}
//------------------------------------------------------------------------
class PercentValueConverter : public IValueConverter
{
public:
UTF8String valueAsString (IValue::Type value) const override
{
auto v = static_cast<uint32_t> (value * 100.);
return toString (v) + " %";
}
IValue::Type stringAsValue (const UTF8String& string) const override
{
auto v = UTF8StringView (string).toDouble ();
return v / 100.;
}
IValue::Type plainToNormalized (IValue::Type plain) const override { return plain / 100.; }
IValue::Type normalizedToPlain (IValue::Type normalized) const override
{
return normalized * 100.;
}
};
//------------------------------------------------------------------------
class DefaultValueConverter : public IValueConverter
{
public:
DefaultValueConverter (uint32_t stringPrecision = 40) : stringPrecision (stringPrecision) {}
UTF8String valueAsString (IValue::Type value) const override
{
UTF8String result;
if (value < 0. || value > 1.)
return result;
value = normalizedToPlain (value);
std::stringstream sstream;
sstream.imbue (std::locale::classic ());
sstream.precision (stringPrecision);
if (stringPrecision)
sstream << std::showpoint;
sstream << std::fixed;
sstream << value;
result = sstream.str ();
return result;
}
IValue::Type stringAsValue (const UTF8String& string) const override
{
IValue::Type value;
std::istringstream sstream (string.getString ());
sstream.imbue (std::locale::classic ());
sstream.precision (stringPrecision);
sstream >> value;
value = plainToNormalized (value);
if (sstream.fail () || value < 0. || value > 1.)
return IValue::InvalidValue;
return value;
}
IValue::Type plainToNormalized (IValue::Type plain) const override { return plain; }
IValue::Type normalizedToPlain (IValue::Type normalized) const override { return normalized; }
private:
uint32_t stringPrecision {40};
};
//------------------------------------------------------------------------
class RangeValueConverter : public DefaultValueConverter,
public IRangeValueConverter
{
public:
RangeValueConverter (IValue::Type minValue, IValue::Type maxValue, uint32_t stringPrecision)
: DefaultValueConverter (stringPrecision), minValue (minValue), maxValue (maxValue)
{
}
IValue::Type plainToNormalized (IValue::Type plain) const override
{
return (plain - minValue) / (maxValue - minValue);
}
IValue::Type normalizedToPlain (IValue::Type normalized) const override
{
return normalized * (maxValue - minValue) + minValue;
}
void setRange (IValue::Type _min, IValue::Type _max) override
{
minValue = _min;
maxValue = _max;
}
private:
IValue::Type minValue;
IValue::Type maxValue;
};
//------------------------------------------------------------------------
class StringListValueConverter : public IValueConverter
{
public:
explicit StringListValueConverter (const std::initializer_list<UTF8String>& list)
: strings (list)
{
}
explicit StringListValueConverter (const IStringListValue::StringList& list) : strings (list) {}
UTF8String valueAsString (IValue::Type value) const override
{
if (strings.empty ())
return "";
auto index =
convertValueToStep (value, static_cast<IStepValue::StepType> (strings.size () - 1));
return strings[index];
}
IValue::Type stringAsValue (const UTF8String& string) const override
{
if (auto index = indexOf (strings.begin (), strings.end (), string))
{
return convertStepToValue (static_cast<IStepValue::StepType> (*index),
static_cast<IStepValue::StepType> (strings.size () - 1));
}
return IValue::InvalidValue;
}
IValue::Type plainToNormalized (IValue::Type plain) const override
{
return convertStepToValue (static_cast<IStepValue::StepType> (plain),
static_cast<IStepValue::StepType> (strings.size () - 1));
}
IValue::Type normalizedToPlain (IValue::Type normalized) const override
{
return convertValueToStep (normalized,
static_cast<IStepValue::StepType> (strings.size () - 1));
}
bool updateString (size_t index, const UTF8String& str)
{
if (index < strings.size ())
{
strings[index] = str;
return true;
}
return false;
}
private:
IStringListValue::StringList strings;
};
//------------------------------------------------------------------------
struct ValueBase : public IValue
{
ValueBase (const UTF8String& id) : idString (id) {}
const UTF8String& getID () const override { return idString; }
using Listeners = DispatchList<IValueListener*>;
void registerListener (IValueListener* listener) override { listeners.add (listener); }
void unregisterListener (IValueListener* listener) override { listeners.remove (listener); }
Listeners& getListeners () { return listeners; }
private:
UTF8String idString;
Listeners listeners;
};
//------------------------------------------------------------------------
class StaticStringValue : public ValueBase,
public IValueConverter
{
public:
StaticStringValue (const UTF8String& id, const UTF8String& value)
: ValueBase (id), value (value)
{
}
StaticStringValue (const UTF8String& id, UTF8String&& value)
: ValueBase (id), value (std::move (value))
{
}
void beginEdit () override {}
bool performEdit (Type newValue) override { return false; }
void endEdit () override {}
void setActive (bool state) override {}
bool isActive () const override { return false; }
Type getValue () const override { return 0.; }
bool isEditing () const override { return false; }
const IValueConverter& getConverter () const override { return *this; }
UTF8String valueAsString (IValue::Type) const override { return value; }
IValue::Type stringAsValue (const UTF8String&) const override { return 0.; }
IValue::Type plainToNormalized (IValue::Type) const override { return 0.; }
IValue::Type normalizedToPlain (IValue::Type) const override { return 0.; }
private:
UTF8String value;
};
//------------------------------------------------------------------------
class Value : public ValueBase
{
public:
Value (const UTF8String& id, Type initialValue, const ValueConverterPtr& valueConverter);
void beginEdit () override;
bool performEdit (Type newValue) override;
void endEdit () override;
void setActive (bool state) override;
bool isActive () const override;
Type getValue () const override;
bool isEditing () const override;
const IValueConverter& getConverter () const override;
bool hasValueConverter () const { return valueConverter != nullptr; }
void setValueConverter (const ValueConverterPtr& stringConverter);
const ValueConverterPtr& getValueConverter () const { return valueConverter; }
void dispatchStateChange ();
private:
Type value;
bool active {true};
uint32_t editCount {0};
ValueConverterPtr valueConverter;
};
//------------------------------------------------------------------------
class StringValue : public Value,
public IValueConverter,
public IStringValue
{
public:
StringValue (const UTF8String& id, const UTF8String& value)
: Value (id, 0, nullptr), str (value)
{
}
StringValue (const UTF8String& id, UTF8String&& value)
: Value (id, 0, nullptr), str (std::move (value))
{
}
const IValueConverter& getConverter () const override { return *this; }
UTF8String valueAsString (IValue::Type) const override { return str; }
IValue::Type stringAsValue (const UTF8String& s) const override
{
if (isEditing ())
str = s;
return 0.;
}
IValue::Type plainToNormalized (IValue::Type) const override { return 0.; }
IValue::Type normalizedToPlain (IValue::Type) const override { return 0.; }
void setString (const UTF8String& s) override
{
str = s;
if (isEditing ())
performEdit (0.);
}
const UTF8String& getString () const override { return str; }
private:
mutable UTF8String str;
};
//------------------------------------------------------------------------
class StepValue : public Value,
public IStepValue,
public IValueConverter,
public IMutableStepValue
{
public:
StepValue (const UTF8String& id, StepType initialSteps, Type initialValue,
const ValueConverterPtr& stringConverter);
bool performEdit (Type newValue) override;
StepType getSteps () const override;
IValue::Type stepToValue (StepType step) const override;
StepType valueToStep (IValue::Type) const override;
UTF8String valueAsString (IValue::Type value) const override;
IValue::Type stringAsValue (const UTF8String& string) const override;
IValue::Type plainToNormalized (IValue::Type plain) const override;
IValue::Type normalizedToPlain (IValue::Type normalized) const override;
const IValueConverter& getConverter () const override;
bool setNumSteps (StepType numSteps) override;
private:
StepType steps;
};
//------------------------------------------------------------------------
class StringListValue : public StepValue,
public IStringListValue
{
public:
StringListValue (const UTF8String& id, StepType initialSteps, Type initialValue,
const ValueConverterPtr& stringConverter);
bool setNumSteps (StepType numSteps) override;
bool updateStringList (const StringList& newStrings) override;
bool updateString (size_t index, const StringType& string) override;
};
//------------------------------------------------------------------------
Value::Value (const UTF8String& id, Type initialValue, const ValueConverterPtr& valueConverter)
: ValueBase (id), value (initialValue), valueConverter (valueConverter)
{
}
//------------------------------------------------------------------------
void Value::beginEdit ()
{
++editCount;
if (editCount == 1)
{
getListeners ().forEach ([this] (IValueListener* l) { l->onBeginEdit (*this); });
}
}
//------------------------------------------------------------------------
bool Value::performEdit (Type newValue)
{
if (newValue < 0. || newValue > 1.)
return false;
// if (newValue == value)
// return true;
value = newValue;
getListeners ().forEach ([this] (IValueListener* l) { l->onPerformEdit (*this, value); });
return true;
}
//------------------------------------------------------------------------
void Value::endEdit ()
{
vstgui_assert (editCount > 0);
--editCount;
if (editCount == 0)
{
getListeners ().forEach ([this] (IValueListener* l) { l->onEndEdit (*this); });
}
}
//------------------------------------------------------------------------
void Value::setActive (bool state)
{
if (state == active)
return;
active = state;
dispatchStateChange ();
}
//------------------------------------------------------------------------
bool Value::isActive () const { return active; }
//------------------------------------------------------------------------
Value::Type Value::getValue () const { return value; }
//------------------------------------------------------------------------
bool Value::isEditing () const { return editCount != 0; }
//------------------------------------------------------------------------
const IValueConverter& Value::getConverter () const { return *valueConverter.get (); }
//------------------------------------------------------------------------
void Value::dispatchStateChange ()
{
getListeners ().forEach ([this] (IValueListener* l) { l->onStateChange (*this); });
}
//------------------------------------------------------------------------
void Value::setValueConverter (const ValueConverterPtr& converter) { valueConverter = converter; }
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
StepValue::StepValue (const UTF8String& id, StepType initialSteps, Type initialValue,
const ValueConverterPtr& stringConverter)
: Value (id, initialValue, stringConverter), steps (initialSteps - 1)
{
vstgui_assert (initialSteps > 0);
}
//------------------------------------------------------------------------
bool StepValue::performEdit (Type newValue)
{
return Value::performEdit (stepToValue (valueToStep (newValue)));
}
//------------------------------------------------------------------------
StepValue::StepType StepValue::getSteps () const { return steps + 1; }
//------------------------------------------------------------------------
IValue::Type StepValue::stepToValue (StepType step) const
{
if (steps == 0)
return 0.;
return convertStepToValue (step, steps);
}
//------------------------------------------------------------------------
StepValue::StepType StepValue::valueToStep (IValue::Type value) const
{
return convertValueToStep (value, steps);
}
//------------------------------------------------------------------------
UTF8String StepValue::valueAsString (IValue::Type value) const
{
auto v = valueToStep (value);
return UTF8String (std::to_string (v));
}
//------------------------------------------------------------------------
IValue::Type StepValue::stringAsValue (const UTF8String& string) const
{
StepType v;
std::istringstream sstream (string.getString ());
sstream.imbue (std::locale::classic ());
sstream >> v;
if (sstream.fail () || v > steps)
return IValue::InvalidValue;
return stepToValue (v);
}
//------------------------------------------------------------------------
IValue::Type StepValue::plainToNormalized (IValue::Type plain) const
{
return stepToValue (static_cast<IStepValue::StepType> (plain));
}
//------------------------------------------------------------------------
IValue::Type StepValue::normalizedToPlain (IValue::Type normalized) const
{
return valueToStep (normalized);
}
//------------------------------------------------------------------------
const IValueConverter& StepValue::getConverter () const
{
if (!hasValueConverter ())
return *this;
return Value::getConverter ();
}
//------------------------------------------------------------------------
bool StepValue::setNumSteps (StepType numSteps)
{
if (numSteps == 0)
{
vstgui_assert (numSteps > 0, "numSteps must be greater than zero");
return false;
}
steps = numSteps - 1;
dispatchStateChange ();
return true;
}
//------------------------------------------------------------------------
StringListValue::StringListValue (const UTF8String& id, StepType initialSteps, Type initialValue,
const ValueConverterPtr& stringConverter)
: StepValue (id, initialSteps, initialValue, stringConverter)
{
}
//------------------------------------------------------------------------
bool StringListValue::setNumSteps (StepType numSteps)
{
if (getSteps () == numSteps)
return true;
if (numSteps == 0)
numSteps = 1;
StepValue::setNumSteps (numSteps);
return true;
}
//------------------------------------------------------------------------
bool StringListValue::updateStringList (const StringList& newStrings)
{
setValueConverter (std::make_shared<Detail::StringListValueConverter> (newStrings));
setNumSteps (static_cast<IStepValue::StepType> (newStrings.size ()));
return true;
}
//------------------------------------------------------------------------
bool StringListValue::updateString (size_t index, const StringType& string)
{
if (auto converter = dynamicPtrCast<Detail::StringListValueConverter> (getValueConverter ()))
if (converter->updateString (index, string))
{
dispatchStateChange ();
return true;
}
return false;
}
//------------------------------------------------------------------------
ValueConverterPtr getDefaultConverter ()
{
static ValueConverterPtr gInstance = std::make_shared<Detail::DefaultValueConverter> ();
return gInstance;
}
//------------------------------------------------------------------------
} // anonymous
} // Detail
//------------------------------------------------------------------------
namespace Value {
//------------------------------------------------------------------------
ValuePtr make (const UTF8String& id, IValue::Type initialValue,
const ValueConverterPtr& stringConverter)
{
vstgui_assert (id.empty () == false);
return std::make_shared<Detail::Value> (
id, initialValue,
stringConverter.get () ? stringConverter : Detail::getDefaultConverter ());
}
//------------------------------------------------------------------------
ValuePtr makeStepValue (const UTF8String& id, IStepValue::StepType numSteps,
IValue::Type initialValue, const ValueConverterPtr& stringConverter)
{
vstgui_assert (id.empty () == false);
vstgui_assert (numSteps > 0, "numSteps must be greater than 0");
if (numSteps == 0)
return {};
return std::make_shared<Detail::StepValue> (id, numSteps, initialValue, stringConverter);
}
//------------------------------------------------------------------------
ValuePtr makeStringListValue (const UTF8String& id,
const std::initializer_list<IStringListValue::StringType>& strings,
IValue::Type initialValue)
{
vstgui_assert (id.empty () == false);
return std::make_shared<Detail::StringListValue> (
id, static_cast<IStepValue::StepType> (strings.size ()), initialValue,
std::make_shared<Detail::StringListValueConverter> (strings));
}
//------------------------------------------------------------------------
ValuePtr makeStringListValue (const UTF8String& id, const IStringListValue::StringList& strings)
{
vstgui_assert (id.empty () == false);
return std::make_shared<Detail::StringListValue> (
id, static_cast<IStepValue::StepType> (strings.size ()), 0,
std::make_shared<Detail::StringListValueConverter> (strings));
}
//------------------------------------------------------------------------
ValuePtr makeStaticStringValue (const UTF8String& id, const UTF8String& value)
{
return std::make_shared<Detail::StaticStringValue> (id, value);
}
//------------------------------------------------------------------------
ValuePtr makeStaticStringValue (const UTF8String& id, UTF8String&& value)
{
return std::make_shared<Detail::StaticStringValue> (id, std::move (value));
}
//------------------------------------------------------------------------
ValuePtr makeStringValue (const UTF8String& id, const UTF8String& initialString)
{
return std::make_shared<Detail::StringValue> (id, initialString);
}
//------------------------------------------------------------------------
ValuePtr makeStringValue (const UTF8String& id, UTF8String&& initialString)
{
return std::make_shared<Detail::StringValue> (id, std::move (initialString));
}
//------------------------------------------------------------------------
ValueConverterPtr makePercentConverter ()
{
return std::make_shared<Detail::PercentValueConverter> ();
}
//------------------------------------------------------------------------
ValueConverterPtr makeRangeConverter (IValue::Type minValue, IValue::Type maxValue,
uint32_t stringPrecision)
{
return std::make_shared<Detail::RangeValueConverter> (minValue, maxValue, stringPrecision);
}
//------------------------------------------------------------------------
} // Value
} // Standalone
} // VSTGUI