diff options
| -rw-r--r-- | compat/options.hpp | 754 | 
1 files changed, 377 insertions, 377 deletions
| diff --git a/compat/options.hpp b/compat/options.hpp index 07696b3c..815b4e2a 100644 --- a/compat/options.hpp +++ b/compat/options.hpp @@ -50,442 +50,442 @@  #define OPENTRACK_ORG "opentrack-2.3"  namespace options { -    namespace { -        class custom_type_initializer -        { -            custom_type_initializer(); -            static custom_type_initializer singleton; -        }; -    } - -    template<typename k, typename v> using map = std::map<k, v>; +namespace { +class custom_type_initializer +{ +    custom_type_initializer(); +    static custom_type_initializer singleton; +}; +} -    // snapshot of qsettings group at given time -    class OPENTRACK_COMPAT_EXPORT group -    { -    private: -        map<QString, QVariant> kvs; -        QString name; -    public: -        group(const QString& name); -        void save() const; -        void put(const QString& s, const QVariant& d); -        bool contains(const QString& s) const; -        static QString ini_directory(); -        static QString ini_filename(); -        static QString ini_pathname(); -        static const QStringList ini_list(); -        static const mem<QSettings> ini_file(); -        bool operator==(const group& other) const; -        bool operator!=(const group& other) const { return !(*this == other); } - -        template<typename t> -        t get(const QString& k) const -        { -            auto value = kvs.find(k); -            if (value != kvs.cend()) -                return value->second.value<t>(); -            return t(); -        } -    }; +template<typename k, typename v> using map = std::map<k, v>; + +// snapshot of qsettings group at given time +class OPENTRACK_COMPAT_EXPORT group +{ +private: +    map<QString, QVariant> kvs; +    QString name; +public: +    group(const QString& name); +    void save() const; +    void put(const QString& s, const QVariant& d); +    bool contains(const QString& s) const; +    static QString ini_directory(); +    static QString ini_filename(); +    static QString ini_pathname(); +    static const QStringList ini_list(); +    static const mem<QSettings> ini_file(); +    bool operator==(const group& other) const; +    bool operator!=(const group& other) const { return !(*this == other); } -    class OPENTRACK_COMPAT_EXPORT impl_bundle : public QObject +    template<typename t> +    t get(const QString& k) const      { -        Q_OBJECT -    protected: -        QMutex mtx; -        const QString group_name; -        group saved; -        group transient; -        impl_bundle(const impl_bundle&) = delete; -        impl_bundle& operator=(const impl_bundle&) = delete; -    signals: -        void reloading(); -        void saving() const; -    public: -        impl_bundle(const QString& group_name); -        QString name() { return group_name; } -        void reload(); -        void store_kv(const QString& name, const QVariant& datum); -        bool contains(const QString& name) const; -        void save(); -        bool modifiedp() const; - -        template<typename t> -        t get(const QString& name) const -        { -            QMutexLocker l(const_cast<QMutex*>(&mtx)); -            return transient.get<t>(name); -        } -    }; +        auto value = kvs.find(k); +        if (value != kvs.cend()) +            return value->second.value<t>(); +        return t(); +    } +}; + +class OPENTRACK_COMPAT_EXPORT impl_bundle : public QObject +{ +    Q_OBJECT +protected: +    QMutex mtx; +    const QString group_name; +    group saved; +    group transient; +    impl_bundle(const impl_bundle&) = delete; +    impl_bundle& operator=(const impl_bundle&) = delete; +signals: +    void reloading(); +    void saving() const; +public: +    impl_bundle(const QString& group_name); +    QString name() { return group_name; } +    void reload(); +    void store_kv(const QString& name, const QVariant& datum); +    bool contains(const QString& name) const; +    void save(); +    bool modifiedp() const; -    namespace detail +    template<typename t> +    t get(const QString& name) const      { -        class OPENTRACK_COMPAT_EXPORT opt_bundle final : public impl_bundle -        { -        public: -            opt_bundle(const QString& group_name); -            ~opt_bundle(); -        }; - -        struct OPENTRACK_COMPAT_EXPORT opt_singleton -        { -        public: -            using k = QString; -            using v = opt_bundle; -            using cnt = int; -            using pbundle = std::shared_ptr<v>; -            using tt = std::tuple<cnt, std::weak_ptr<v>>; -        private: -            QMutex implsgl_mtx; -            map<k, tt> implsgl_data; -            void after_profile_changed_(); -        public: -            opt_singleton(); -            ~opt_singleton(); -            pbundle bundle(const k& key); -            void bundle_decf(const k& key); -            static void refresh_all_bundles(); -        }; - -        OPENTRACK_COMPAT_EXPORT opt_singleton& singleton(); +        QMutexLocker l(const_cast<QMutex*>(&mtx)); +        return transient.get<t>(name);      } +}; + +namespace detail +{ +class OPENTRACK_COMPAT_EXPORT opt_bundle final : public impl_bundle +{ +public: +    opt_bundle(const QString& group_name); +    ~opt_bundle(); +}; + +struct OPENTRACK_COMPAT_EXPORT opt_singleton +{ +public: +    using k = QString; +    using v = opt_bundle; +    using cnt = int; +    using pbundle = std::shared_ptr<v>; +    using tt = std::tuple<cnt, std::weak_ptr<v>>; +private: +    QMutex implsgl_mtx; +    map<k, tt> implsgl_data; +    void after_profile_changed_(); +public: +    opt_singleton(); +    ~opt_singleton(); +    pbundle bundle(const k& key); +    void bundle_decf(const k& key); +    static void refresh_all_bundles(); +}; + +OPENTRACK_COMPAT_EXPORT opt_singleton& singleton(); +} -    using pbundle = std::shared_ptr<detail::opt_bundle>; +using pbundle = std::shared_ptr<detail::opt_bundle>; -    inline pbundle bundle(const QString& name) -    { -         return detail::singleton().bundle(name); -    } +inline pbundle bundle(const QString& name) +{ +    return detail::singleton().bundle(name); +}  #define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); }  #define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) -    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 t> using value_type_t = typename value_type_traits<t>::type; -    } +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 t> using value_type_t = typename value_type_traits<t>::type; +} + +class OPENTRACK_COMPAT_EXPORT base_value : public QObject +{ +    Q_OBJECT +public: +    QString name() const { return self_name; } +    base_value(pbundle b, const QString& 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&); +protected: +    pbundle b; +    QString self_name; -    class OPENTRACK_COMPAT_EXPORT base_value : public QObject +    template<typename t> +    void store(const t& datum)      { -        Q_OBJECT -    public: -        QString name() const { return self_name; } -        base_value(pbundle b, const QString& 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&); -    protected: -        pbundle 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)); -        } +        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&) +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&)      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()); -            } -        }; +namespace detail { +template<typename t> +struct value_get_traits +{ +    static inline t get(const t& val, const t&) +    { +        return val;      } +}; -    template<typename t_> -    class value : public base_value +template<> +struct value_get_traits<slider_value> +{ +    using t = slider_value; +    static inline t get(const t& val, const t& def)      { -        template<typename t__, typename Enable = void> -        struct get_t -        { using t = t__; }; - -        // Qt uses int a lot in slots so use it for all enums -        template<typename t__> -        struct get_t<t__, typename std::enable_if<std::is_enum<t__>::value>::type> -        //{ using t = typename std::underlying_type<t__>::type; }; -        { using t = int; }; - -        using t = t_; -    public: -        using underlying_t = typename get_t<t_>::t; - -        t operator=(const t& datum) -        { -            store(static_cast<underlying_t>(datum)); -            return datum; -        } +        return t(val.cur(), def.min(), def.max()); +    } +}; +} -        static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::AutoConnection; -        static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; +template<typename t_> +class value : public base_value +{ +    template<typename t__, typename Enable = void> +    struct get_t +    { using t = t__; }; -        value(pbundle 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; -        } +    // Qt uses int a lot in slots so use it for all enums +    template<typename t__> +    struct get_t<t__, typename std::enable_if<std::is_enum<t__>::value>::type> +            //{ using t = typename std::underlying_type<t__>::type; }; +    { using t = int; }; -        value(pbundle b, const char* name, t def) : value(b, QString(name), def) -        { -        } +    using t = t_; +public: +    using underlying_t = typename get_t<t_>::t; -        t get() const -        { -            t val = b->contains(self_name) -                    ? static_cast<t>(b->get<underlying_t>(self_name)) -                    : def; -            return detail::value_get_traits<t>::get(val, def); -        } +    t operator=(const t& datum) +    { +        store(static_cast<underlying_t>(datum)); +        return datum; +    } -        operator t() const { return get(); } +    static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::AutoConnection; +    static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; -        void reload() override -        { -            *this = static_cast<t>(*this); -        } +    value(pbundle 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; +    } -    private: -        t def; -    }; +    value(pbundle b, const char* name, t def) : value(b, QString(name), def) +    { +    } -    struct OPENTRACK_COMPAT_EXPORT opts +    t get() const      { -        pbundle b; -        opts(const QString& name); -        opts& operator=(const opts&) = delete; -        opts(const opts&) = delete; -        ~opts(); -    }; +        t val = b->contains(self_name) +                ? static_cast<t>(b->get<underlying_t>(self_name)) +                : def; +        return detail::value_get_traits<t>::get(val, def); +    } -    template<typename t, typename q> -    inline void tie_setting(value<t>&, q*); +    operator t() const { return get(); } -    template<typename t> -    inline -    typename std::enable_if<std::is_enum<t>::value>::type -    tie_setting(value<t>& v, QComboBox* cb) +    void reload() override      { -        cb->setCurrentIndex(cb->findData((unsigned)static_cast<t>(v))); -        v = static_cast<t>(cb->currentData().toInt()); - -        // QObject::connect plays badly with std::bind of std::shared_ptr. Data seems to get freed. -        // Direct accesses of cb->currentData within arbitrary thread context cause crashes as well. -        // Hence we go for a verbose implementation. +        *this = static_cast<t>(*this); +    } +private: +    t def; +}; + +struct OPENTRACK_COMPAT_EXPORT opts +{ +    pbundle b; +    opts(const QString& name); +    opts& operator=(const opts&) = delete; +    opts(const opts&) = delete; +    ~opts(); +}; + +template<typename t, typename q> +inline void tie_setting(value<t>&, q*); + +template<typename t> +inline +typename std::enable_if<std::is_enum<t>::value>::type +tie_setting(value<t>& v, QComboBox* cb) +{ +    cb->setCurrentIndex(cb->findData((unsigned)static_cast<t>(v))); +    v = static_cast<t>(cb->currentData().toInt()); + +    // QObject::connect plays badly with std::bind of std::shared_ptr. Data seems to get freed. +    // Direct accesses of cb->currentData within arbitrary thread context cause crashes as well. +    // Hence we go for a verbose implementation. + +    std::vector<int> enum_cases; +    enum_cases.reserve(unsigned(cb->count())); + +    for (int i = 0; i < cb->count(); i++) +        enum_cases.push_back(cb->itemData(i).toInt()); + +    struct fn1 +    { +        value<t>& v; +        QComboBox* cb;          std::vector<int> enum_cases; -        enum_cases.reserve(unsigned(cb->count())); -        for (int i = 0; i < cb->count(); i++) -            enum_cases.push_back(cb->itemData(i).toInt()); +        fn1(value<t>& v, QComboBox* cb, const std::vector<int>& enum_cases) : +            v(v), +            cb(cb), +            enum_cases(enum_cases) +        { +        } -        struct fn1 +        void operator()(int idx)          { -            value<t>& v; -            QComboBox* cb; -            std::vector<int> enum_cases; - -            fn1(value<t>& v, QComboBox* cb, const std::vector<int>& enum_cases) : -                v(v), -                cb(cb), -                enum_cases(enum_cases) -            { -            } +            if (idx < 0 || idx >= (int)enum_cases.size()) +                v = static_cast<t>(-1); +            else +                v = static_cast<t>(t(std::intptr_t(enum_cases[idx]))); +        } +    }; -            void operator()(int idx) -            { -                if (idx < 0 || idx >= (int)enum_cases.size()) -                    v = static_cast<t>(-1); -                else -                    v = static_cast<t>(t(std::intptr_t(enum_cases[idx]))); -            } -        }; +    struct fn2 +    { +        value<t>& v; +        QComboBox* cb; +        std::vector<int> enum_cases; -        struct fn2 +        fn2(value<t>& v, QComboBox* cb, const std::vector<int>& enum_cases) : +            v(v), +            cb(cb), +            enum_cases(enum_cases)          { -            value<t>& v; -            QComboBox* cb; -            std::vector<int> enum_cases; - -            fn2(value<t>& v, QComboBox* cb, const std::vector<int>& enum_cases) : -                v(v), -                cb(cb), -                enum_cases(enum_cases) -            { -            } +        } -            void operator()(int val) +        void operator()(int val) +        { +            for (unsigned i = 0; i < enum_cases.size(); i++)              { -                for (unsigned i = 0; i < enum_cases.size(); i++) +                if (val == enum_cases[i])                  { -                    if (val == enum_cases[i]) -                    { -                        cb->setCurrentIndex(i); -                        return; -                    } +                    cb->setCurrentIndex(i); +                    return;                  } -                cb->setCurrentIndex(-1);              } -        }; - -        base_value::connect(cb, -                            static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), -                            &v, -                            fn1(v, cb, enum_cases), -                            v.DIRECT_CONNTYPE); -        base_value::connect(&v, -                            static_cast<void (base_value::*)(int)>(&base_value::valueChanged), -                            cb, -                            fn2(v, cb, enum_cases), -                            v.DIRECT_CONNTYPE); -    } +            cb->setCurrentIndex(-1); +        } +    }; -    template<> -    inline void tie_setting(value<int>& v, QComboBox* cb) -    { -        cb->setCurrentIndex(v); -        v = cb->currentIndex(); -        base_value::connect(cb, SIGNAL(currentIndexChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(int)), cb, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); -    } +    base_value::connect(cb, +                        static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), +                        &v, +                        fn1(v, cb, enum_cases), +                        v.DIRECT_CONNTYPE); +    base_value::connect(&v, +                        static_cast<void (base_value::*)(int)>(&base_value::valueChanged), +                        cb, +                        fn2(v, cb, enum_cases), +                        v.DIRECT_CONNTYPE); +} -    template<> -    inline void tie_setting(value<QString>& v, QComboBox* cb) -    { -        cb->setCurrentText(v); -        v = cb->currentText(); -        base_value::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(QString)), cb, SLOT(setCurrentText(QString)), v.SAFE_CONNTYPE); -    } +template<> +inline void tie_setting(value<int>& v, QComboBox* cb) +{ +    cb->setCurrentIndex(v); +    v = cb->currentIndex(); +    base_value::connect(cb, SIGNAL(currentIndexChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(int)), cb, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); +} -    template<> -    inline void tie_setting(value<bool>& v, QCheckBox* cb) -    { -        cb->setChecked(v); -        base_value::connect(cb, SIGNAL(toggled(bool)), &v, SLOT(setValue(bool)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(bool)), cb, SLOT(setChecked(bool)), v.SAFE_CONNTYPE); -    } +template<> +inline void tie_setting(value<QString>& v, QComboBox* cb) +{ +    cb->setCurrentText(v); +    v = cb->currentText(); +    base_value::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(QString)), cb, SLOT(setCurrentText(QString)), v.SAFE_CONNTYPE); +} -    template<> -    inline void tie_setting(value<double>& v, QDoubleSpinBox* dsb) -    { -        dsb->setValue(v); -        base_value::connect(dsb, SIGNAL(valueChanged(double)), &v, SLOT(setValue(double)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(double)), dsb, SLOT(setValue(double)), v.SAFE_CONNTYPE); -    } +template<> +inline void tie_setting(value<bool>& v, QCheckBox* cb) +{ +    cb->setChecked(v); +    base_value::connect(cb, SIGNAL(toggled(bool)), &v, SLOT(setValue(bool)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(bool)), cb, SLOT(setChecked(bool)), v.SAFE_CONNTYPE); +} -    template<> -    inline void tie_setting(value<int>& v, QSpinBox* sb) -    { -        sb->setValue(v); -        base_value::connect(sb, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)), v.SAFE_CONNTYPE); -    } +template<> +inline void tie_setting(value<double>& v, QDoubleSpinBox* dsb) +{ +    dsb->setValue(v); +    base_value::connect(dsb, SIGNAL(valueChanged(double)), &v, SLOT(setValue(double)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(double)), dsb, SLOT(setValue(double)), v.SAFE_CONNTYPE); +} -    template<> -    inline void tie_setting(value<int>& v, QSlider* sl) -    { -        sl->setValue(v); -        v = sl->value(); -        base_value::connect(sl, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int)), v.SAFE_CONNTYPE); -    } +template<> +inline void tie_setting(value<int>& v, QSpinBox* sb) +{ +    sb->setValue(v); +    base_value::connect(sb, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)), v.SAFE_CONNTYPE); +} -    template<> -    inline void tie_setting(value<QString>& v, QLineEdit* le) -    { -        le->setText(v); -        base_value::connect(le, SIGNAL(textChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(QString)),le, SLOT(setText(QString)), v.SAFE_CONNTYPE); -    } +template<> +inline void tie_setting(value<int>& v, QSlider* sl) +{ +    sl->setValue(v); +    v = sl->value(); +    base_value::connect(sl, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int)), v.SAFE_CONNTYPE); +} -    template<> -    inline void tie_setting(value<QString>& v, QLabel* lb) -    { -        lb->setText(v); -        base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.DIRECT_CONNTYPE); -    } +template<> +inline void tie_setting(value<QString>& v, QLineEdit* le) +{ +    le->setText(v); +    base_value::connect(le, SIGNAL(textChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(QString)),le, SLOT(setText(QString)), v.SAFE_CONNTYPE); +} -    template<> -    inline void tie_setting(value<int>& v, QTabWidget* t) -    { -        t->setCurrentIndex(v); -        base_value::connect(t, SIGNAL(currentChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); -        base_value::connect(&v, SIGNAL(valueChanged(int)), t, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); -    } +template<> +inline void tie_setting(value<QString>& v, QLabel* lb) +{ +    lb->setText(v); +    base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.DIRECT_CONNTYPE); +} -    template<> -    inline void tie_setting(value<slider_value>& v, QSlider* w) -    { -        // we can't get these at runtime since signals cross threads -        const int q_min = w->minimum(); -        const int q_max = w->maximum(); -        const int q_diff = q_max - q_min; +template<> +inline void tie_setting(value<int>& v, QTabWidget* t) +{ +    t->setCurrentIndex(v); +    base_value::connect(t, SIGNAL(currentChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); +    base_value::connect(&v, SIGNAL(valueChanged(int)), t, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); +} -        slider_value sv(v); +template<> +inline void tie_setting(value<slider_value>& v, QSlider* w) +{ +    // we can't get these at runtime since signals cross threads +    const int q_min = w->minimum(); +    const int q_max = w->maximum(); +    const int q_diff = q_max - q_min; -        const double sv_max = sv.max(); -        const double sv_min = sv.min(); -        const double sv_c = sv_max - sv_min; +    slider_value sv(v); -        w->setValue(int((sv.cur() - sv_min) / sv_c * q_diff + q_min)); -        v = slider_value(q_diff <= 0 ? 0 : (w->value() - q_min) * sv_c / (double)q_diff + sv_min, sv_min, sv_max); +    const double sv_max = sv.max(); +    const double sv_min = sv.min(); +    const double sv_c = sv_max - sv_min; -        base_value::connect(w, -                            &QSlider::valueChanged, -                            &v, -                            [=, &v](int pos) -> void -        { -            if (q_diff <= 0 || pos <= 0) -                v = slider_value(sv_min, sv_min, sv_max); -            else -                v = slider_value((pos - q_min) * sv_c / (double)q_diff + sv_min, sv_min, sv_max); -        }, -        v.DIRECT_CONNTYPE); -        base_value::connect(&v, -                            static_cast<void(base_value::*)(double)>(&base_value::valueChanged), -                            w, -                            [=](double value) -> void -        { -            w->setValue(int(value * q_diff) + q_min); -        }, -        v.SAFE_CONNTYPE); -    } +    w->setValue(int((sv.cur() - sv_min) / sv_c * q_diff + q_min)); +    v = slider_value(q_diff <= 0 ? 0 : (w->value() - q_min) * sv_c / (double)q_diff + sv_min, sv_min, sv_max); + +    base_value::connect(w, +                        &QSlider::valueChanged, +                        &v, +                        [=, &v](int pos) -> void +    { +        if (q_diff <= 0 || pos <= 0) +            v = slider_value(sv_min, sv_min, sv_max); +        else +            v = slider_value((pos - q_min) * sv_c / (double)q_diff + sv_min, sv_min, sv_max); +    }, +    v.DIRECT_CONNTYPE); +    base_value::connect(&v, +                        static_cast<void(base_value::*)(double)>(&base_value::valueChanged), +                        w, +                        [=](double value) -> void +    { +        w->setValue(int(value * q_diff) + q_min); +    }, +    v.SAFE_CONNTYPE); +}  } | 
