/* 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 "export.hpp" #include "bundle.hpp" #include "slider.hpp" #include "base-value.hpp" #include "value-traits.hpp" #include "compat/macros.hpp" #include #include #include namespace options::detail { template 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 class value final : public value_ { static_assert(std::is_same_v>); mutable QMutex mtx; const t def; mutable t cached_value = def; using traits = detail::value_traits; never_inline auto get() const noexcept { if (!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)); } never_inline void store_variant(QVariant&& value) noexcept override { if (traits::is_equal(get(), traits::value_from_qvariant(value))) return; if (is_null()) return; if (value.isValid() && !value.isNull()) b->store_kv(self_name, value); else b->store_kv(self_name, traits::qvariant_from_value(def)); } never_inline void store_variant(const QVariant& value) noexcept override { QVariant copy{value}; store_variant(std::move(copy)); } bool is_null() const { return self_name.isEmpty() || b->name().isEmpty(); } public: QVariant get_variant() const noexcept override { if (QVariant ret{b->get_variant(self_name)}; ret.isValid() && !ret.isNull()) return ret; return traits::qvariant_from_value(def); } never_inline void notify() const override { if (is_null()) return; auto x = get(); bool b = progn( QMutexLocker l(&mtx); if (!traits::is_equal(x, cached_value)) { cached_value = x; return true; } return false; ); if (b) { maybe_trace(true); emit valueChanged(traits::storage_from_value(x)); maybe_trace(false); } } auto& operator=(t&& datum) noexcept { if (is_null()) return *this; store_variant(traits::qvariant_from_value(traits::pass_value(datum))); return *this; } auto& operator=(const t& datum) noexcept { if (is_null()) return *this; t copy{datum}; *this = std::move(copy); return *this; } auto& operator=(const value& datum) noexcept { *this = *datum; return *this; } static constexpr Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; static constexpr Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; value(bundle b, const QString& name, t def) noexcept : value_(b, name), def(std::move(def)) { } //value(const value& other) noexcept : value{other.b, other.self_name, other.def} {} value(const value&) = delete; t default_value() const { return def; } void set_to_default() noexcept override { *this = def; } operator t() const { return get(); } template explicit force_inline operator u() const { return to(); } auto operator->() const noexcept { return detail::dereference_wrapper{get()}; } force_inline auto operator()() const noexcept { return get(); } force_inline auto operator*() const noexcept { return get(); } template u to() const noexcept { return static_cast(get()); } }; #if !defined OTR_OPTIONS_INST_VALUE # define OTR_OPTIONS_INST_VALUE OTR_TEMPLATE_IMPORT #endif OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value) OTR_OPTIONS_INST_VALUE(value>) OTR_OPTIONS_INST_VALUE(value>) OTR_OPTIONS_INST_VALUE(value>) OTR_OPTIONS_INST_VALUE(value>) OTR_OPTIONS_INST_VALUE(value>) OTR_OPTIONS_INST_VALUE(value>) OTR_OPTIONS_INST_VALUE(value>) OTR_OPTIONS_INST_VALUE(value>) } // ns options