/* Copyright (c) 2015-2016, Stanislaw Halik <sthalik@misaki.pl> * 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 "export.hpp" #include "bundle.hpp" #include "slider.hpp" #include "base-value.hpp" #include "value-traits.hpp" #include "compat/macros.hpp" #include <type_traits> #include <typeinfo> #include <QMetaType> namespace options::detail { template<typename t> class dereference_wrapper final { t x; public: constexpr t const* operator->() const { return &x; } constexpr t* operator->() { return &x; } constexpr explicit dereference_wrapper(t&& x) : x(x) {} }; } // ns options::detail namespace options { template<typename u> class value final : public value_ { using t = std::conditional_t<std::is_enum_v<remove_cvref_t<u>>, std::decay_t<u>, remove_cvref_t<u>>; const t def; using traits = detail::value_traits<t>; cc_noinline t get() const { if (self_name.isEmpty() || !b->contains(self_name)) return traits::pass_value(def); QVariant variant = b->get_variant(self_name); if (variant.isNull() || !variant.isValid()) return traits::pass_value(def); return traits::pass_value(traits::value_with_default(traits::value_from_qvariant(variant), def)); } friend class detail::connector; void bundle_value_changed() const override { if (!self_name.isEmpty()) emit valueChanged(traits::storage_from_value(get())); } void store_variant(const QVariant& value) override { if (self_name.isEmpty()) return; if (traits::is_equal(get(), traits::value_from_qvariant(value))) return; if (value.isValid() && !value.isNull()) b->store_kv(self_name, value); else b->store_kv(self_name, traits::qvariant_from_value(def)); } public: cc_noinline value<u>& operator=(const t& datum) { store_variant(traits::qvariant_from_value(traits::pass_value(datum))); return *this; } static constexpr inline Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; static constexpr inline Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; cc_noinline value(bundle b, const QString& name, t def) : value_(b, name), def(def) { } cc_noinline t default_value() const { return def; } cc_noinline void set_to_default() override { *this = def; } operator t() const { return get(); } template<typename w, typename = decltype(static_cast<w>(std::declval<t>()))> explicit cc_forceinline operator w() const { return to<w>(); } auto operator->() const { return detail::dereference_wrapper<t>{get()}; } cc_forceinline t operator()() const { return get(); } cc_forceinline t operator*() const { return get(); } template<typename w> w to() const { return static_cast<w>(get()); } }; // some linker problems #if !defined OTR_INST_VALUE # define OTR_INST_VALUE OTR_TEMPLATE_IMPORT #endif OTR_INST_VALUE(value<double>); OTR_INST_VALUE(value<float>); OTR_INST_VALUE(value<int>); OTR_INST_VALUE(value<bool>); OTR_INST_VALUE(value<QString>); OTR_INST_VALUE(value<slider_value>); OTR_INST_VALUE(value<QPointF>); OTR_INST_VALUE(value<QVariant>); OTR_INST_VALUE(value<QList<double>>); OTR_INST_VALUE(value<QList<float>>); OTR_INST_VALUE(value<QList<int>>); OTR_INST_VALUE(value<QList<bool>>); OTR_INST_VALUE(value<QList<QString>>); OTR_INST_VALUE(value<QList<slider_value>>); OTR_INST_VALUE(value<QList<QPointF>>); OTR_INST_VALUE(value<QList<QVariant>>); } // ns options