/* Copyright (c) 2015-2016, Stanislaw Halik * Permission to use, copy, modify, and/or distribute this * software for any purpose with or without fee is hereby granted, * provided that the above copyright notice and this permission * notice appear in all copies. */ #pragma once #include "connector.hpp" #include "bundle.hpp" #include "slider.hpp" #include #include #include #include #include #include #define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); } #define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) const 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&; }; template using value_type_t = typename value_type_traits::type; } class OPENTRACK_OPTIONS_EXPORT base_value : public QObject { Q_OBJECT friend class ::options::detail::connector; using comparator = bool(*)(const QVariant& val1, const QVariant& val2); public: QString name() const { return self_name; } base_value(bundle b, const QString& name, comparator cmp, std::type_index type_idx); ~base_value() override; 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; comparator cmp; std::type_index type_index; template void store(const t& datum) { b->store_kv(self_name, QVariant::fromValue(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&) virtual void reload() = 0; virtual void bundle_value_changed() const = 0; virtual void set_to_default() = 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<> struct value_element_type { using type = double; }; 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; static bool is_equal(const QVariant& val1, const QVariant& val2) { return val1.value() == val2.value(); } t operator=(const t& datum) { const element_type tmp = static_cast(datum); if (tmp != get()) store(tmp); return datum; } static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; value(bundle b, const QString& name, t def) : base_value(b, name, &is_equal, std::type_index(typeid(element_type))), 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 default_value() const { return def; } void set_to_default() override { *this = def; } operator t() const { return get(); } void reload() override { *this = static_cast(*this); } void bundle_value_changed() const override { emit valueChanged(static_cast>(get())); } element_type operator()() const { return get(); } private: t get() const { t val = b->contains(self_name) ? static_cast(b->get(self_name)) : def; return detail::value_get_traits::get(val, def); } const t def; }; }