#pragma once #include "bundle.hpp" #include "slider.hpp" #include #include #include #include #define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); } #define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) namespace options { namespace detail { template struct value_type_traits { using type = t;}; template<> struct value_type_traits { using type = const QString&; }; template<> struct value_type_traits { using type = const slider_value&; }; template struct value_type_traits> { using type = const QList::type>::type>&; }; template using value_type_t = typename value_type_traits::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&); OPENTRACK_DEFINE_SIGNAL(const QList&); OPENTRACK_DEFINE_SIGNAL(const QList&); OPENTRACK_DEFINE_SIGNAL(const QList&); OPENTRACK_DEFINE_SIGNAL(const QList&); OPENTRACK_DEFINE_SIGNAL(const QList&); OPENTRACK_DEFINE_SIGNAL(const QList&); protected: bundle b; QString self_name; template void store(const t& datum) { b->store_kv(self_name, QVariant::fromValue(datum)); emit valueChanged(static_cast>(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&) OPENTRACK_DEFINE_SLOT(const QList&) OPENTRACK_DEFINE_SLOT(const QList&) OPENTRACK_DEFINE_SLOT(const QList&) OPENTRACK_DEFINE_SLOT(const QList&) OPENTRACK_DEFINE_SLOT(const QList&) OPENTRACK_DEFINE_SLOT(const QList&) public slots: virtual void reload() = 0; }; namespace detail { template struct value_get_traits { static inline t get(const t& val, const t&) { return val; } }; template<> struct value_get_traits { using t = slider_value; static inline t get(const t& val, const t& def) { return t(val.cur(), def.min(), def.max()); } }; template struct value_element_type { using type = typename std::remove_reference::type>::type; }; // Qt uses int a lot in slots so use it for all enums template struct value_element_type::value>::type> { using type = int; }; template using value_element_type_t = typename value_element_type::type; } template class value final : public base_value { public: using element_type = detail::value_element_type_t; t operator=(const t& datum) { store(static_cast(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(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(b->get(self_name)) : def; return detail::value_get_traits::get(val, def); } operator t() const { return get(); } void reload() override { *this = static_cast(*this); } private: t def; }; }