summaryrefslogtreecommitdiffhomepage
path: root/options/value.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'options/value.hpp')
-rw-r--r--options/value.hpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/options/value.hpp b/options/value.hpp
new file mode 100644
index 00000000..4d8d69f8
--- /dev/null
+++ b/options/value.hpp
@@ -0,0 +1,167 @@
+#pragma once
+
+#include "bundle.hpp"
+#include "slider.hpp"
+#include <type_traits>
+#include <QString>
+#include <QPointF>
+#include <QList>
+
+#define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); }
+#define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t)
+namespace options {
+
+namespace detail {
+template<typename t> struct value_type_traits { using type = t;};
+template<> struct value_type_traits<QString> { using type = const QString&; };
+template<> struct value_type_traits<slider_value> { using type = const slider_value&; };
+template<typename u> struct value_type_traits<QList<u>>
+{
+ using type = const QList<typename std::remove_const<typename std::remove_reference<u>::type>::type>&;
+};
+template<typename t> using value_type_t = typename value_type_traits<t>::type;
+}
+
+class OPENTRACK_OPTIONS_EXPORT base_value : public QObject
+{
+ Q_OBJECT
+public:
+ QString name() const { return self_name; }
+ base_value(bundle b, const QString& name) : b(b), self_name(name) {}
+signals:
+ OPENTRACK_DEFINE_SIGNAL(double);
+ OPENTRACK_DEFINE_SIGNAL(float);
+ OPENTRACK_DEFINE_SIGNAL(int);
+ OPENTRACK_DEFINE_SIGNAL(bool);
+ OPENTRACK_DEFINE_SIGNAL(const QString&);
+ OPENTRACK_DEFINE_SIGNAL(const slider_value&);
+ OPENTRACK_DEFINE_SIGNAL(const QPointF&);
+
+ OPENTRACK_DEFINE_SIGNAL(const QList<double>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<float>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<int>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<bool>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<QString>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<slider_value>&);
+ OPENTRACK_DEFINE_SIGNAL(const QList<QPointF>&);
+protected:
+ bundle b;
+ QString self_name;
+
+ template<typename t>
+ void store(const t& datum)
+ {
+ b->store_kv(self_name, QVariant::fromValue(datum));
+ emit valueChanged(static_cast<detail::value_type_t<t>>(datum));
+ }
+
+ void store(float datum)
+ {
+ store(double(datum));
+ }
+
+public slots:
+ OPENTRACK_DEFINE_SLOT(double)
+ OPENTRACK_DEFINE_SLOT(int)
+ OPENTRACK_DEFINE_SLOT(bool)
+ OPENTRACK_DEFINE_SLOT(const QString&)
+ OPENTRACK_DEFINE_SLOT(const slider_value&)
+ OPENTRACK_DEFINE_SLOT(const QPointF&)
+
+ OPENTRACK_DEFINE_SLOT(const QList<double>&)
+ OPENTRACK_DEFINE_SLOT(const QList<float>&)
+ OPENTRACK_DEFINE_SLOT(const QList<int>&)
+ OPENTRACK_DEFINE_SLOT(const QList<bool>&)
+ OPENTRACK_DEFINE_SLOT(const QList<QString>&)
+ OPENTRACK_DEFINE_SLOT(const QList<slider_value>&)
+ OPENTRACK_DEFINE_SLOT(const QList<QPointF>&)
+ public slots:
+ virtual void reload() = 0;
+};
+
+namespace detail {
+template<typename t>
+struct value_get_traits
+{
+ static inline t get(const t& val, const t&)
+ {
+ return val;
+ }
+};
+
+template<>
+struct value_get_traits<slider_value>
+{
+ using t = slider_value;
+ static inline t get(const t& val, const t& def)
+ {
+ return t(val.cur(), def.min(), def.max());
+ }
+};
+
+template<typename t, typename Enable = void>
+struct value_element_type
+{
+ using type = typename std::remove_reference<typename std::remove_cv<t>::type>::type;
+};
+
+// Qt uses int a lot in slots so use it for all enums
+template<typename t>
+struct value_element_type<t, typename std::enable_if<std::is_enum<t>::value>::type>
+{
+ using type = int;
+};
+
+template<typename t> using value_element_type_t = typename value_element_type<t>::type;
+
+}
+
+template<typename t>
+class value final : public base_value
+{
+public:
+ using element_type = detail::value_element_type_t<t>;
+
+ t operator=(const t& datum)
+ {
+ store(static_cast<element_type>(datum));
+ return datum;
+ }
+
+ static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::AutoConnection;
+ static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection;
+
+ value(bundle b, const QString& name, t def) : base_value(b, name), def(def)
+ {
+ QObject::connect(b.get(), SIGNAL(reloading()),
+ this, SLOT(reload()),
+ DIRECT_CONNTYPE);
+ if (!b->contains(name) || b->get<QVariant>(name).type() == QVariant::Invalid)
+ *this = def;
+ }
+
+ value(bundle b, const char* name, t def) : value(b, QString(name), def)
+ {
+ }
+
+ t get() const
+ {
+ t val = b->contains(self_name)
+ ? static_cast<t>(b->get<element_type>(self_name))
+ : def;
+ return detail::value_get_traits<t>::get(val, def);
+ }
+
+ operator t() const { return get(); }
+
+ void reload() override
+ {
+ *this = static_cast<t>(*this);
+ }
+
+private:
+ t def;
+};
+
+
+}