diff options
-rwxr-xr-x[-rw-r--r--] | opentrack-compat/options.hpp | 161 |
1 files changed, 115 insertions, 46 deletions
diff --git a/opentrack-compat/options.hpp b/opentrack-compat/options.hpp index d41c5cd1..0cdacb28 100644..100755 --- a/opentrack-compat/options.hpp +++ b/opentrack-compat/options.hpp @@ -10,6 +10,9 @@ #include <memory> #include <tuple> #include <map> +#include <cinttypes> +#include <vector> +#include <memory> #include <QObject> #include <QSettings> @@ -30,13 +33,10 @@ #include <QFileInfo> #include <QDir> #include <QStandardPaths> - -#include <cinttypes> +#include <QApplication> #include <QDebug> -#include <memory> - #ifdef BUILD_compat # include "compat-export.hpp" #else @@ -57,35 +57,19 @@ namespace options { // conversion results in nonsensical runtime behavior -sh inline t qcruft_to_t (const QVariant& datum); - template<> - inline int qcruft_to_t<int>(const QVariant& t) - { - return t.toInt(); - } + template<> inline unsigned qcruft_to_t<unsigned>(const QVariant &t) { return t.toUInt(); } - template<> - inline QString qcruft_to_t<QString>(const QVariant& t) - { - return t.toString(); - } + template<> inline int qcruft_to_t<int>(const QVariant& t) { return t.toInt(); } - template<> - inline bool qcruft_to_t<bool>(const QVariant& t) - { - return t.toBool(); - } + template<> inline QString qcruft_to_t<QString>(const QVariant& t) { return t.toString(); } - template<> - inline double qcruft_to_t<double>(const QVariant& t) - { - return t.toDouble(); - } + template<> inline bool qcruft_to_t<bool>(const QVariant& t) { return t.toBool(); } - template<> - inline QVariant qcruft_to_t<QVariant>(const QVariant& t) - { - return t; - } + template<> inline double qcruft_to_t<double>(const QVariant& t) { return t.toDouble(); } + + template<> inline QVariant qcruft_to_t<QVariant>(const QVariant& t) { return t; } + + template<> inline float qcruft_to_t<float>(const QVariant& t) { return t.toFloat(); } // snapshot of qsettings group at given time class OPENTRACK_COMPAT_EXPORT group { @@ -208,17 +192,31 @@ namespace options { virtual void reload() = 0; }; - template<typename t> - class value : public base_value { + template<typename t_> + class value : public base_value + { + 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(datum); + store(static_cast<underlying_t>(datum)); return datum; } - static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; - static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::UniqueConnection; - value(pbundle b, const QString& name, t def) : base_value(b, name), def(def) + static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::UniqueConnection; + static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; + value(pbundle b, const QString& name, t def) : base_value(b, name), def(static_cast<underlying_t>(def)) { QObject::connect(b.get(), SIGNAL(reloading()), this, SLOT(reload()), @@ -230,13 +228,13 @@ namespace options { operator t() const { - return b->contains(self_name) ? b->get<t>(self_name) : def; + return static_cast<t>(b->contains(self_name) ? b->get<underlying_t>(self_name) : def); } void reload() override { *this = static_cast<t>(*this); } private: - t def; + underlying_t def; }; struct OPENTRACK_COMPAT_EXPORT opts @@ -249,13 +247,84 @@ namespace options { 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(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; + + fn1(value<t>& v, QComboBox* cb, const std::vector<int>& enum_cases) : v(v), cb(cb), enum_cases(enum_cases) + {} + + void operator()(int idx) + { + if (idx < 0u || idx >= (int)enum_cases.size()) + v = static_cast<t>(-1); + else + v = static_cast<t>(enum_cases[idx]); + } + }; + + struct fn2 + { + 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) + { + for (unsigned i = 0; i < enum_cases.size(); i++) + { + if (val == enum_cases[i]) + { + 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.SAFE_CONNTYPE); + base_value::connect(&v, + static_cast<void (base_value::*)(int)>(&base_value::valueChanged), + cb, + fn2(v, cb, enum_cases), + 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); + base_value::connect(&v, SIGNAL(valueChanged(int)), cb, SLOT(setCurrentIndex(int)), v.DIRECT_CONNTYPE); } template<> @@ -264,7 +333,7 @@ namespace options { 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); + base_value::connect(&v, SIGNAL(valueChanged(QString)), cb, SLOT(setCurrentText(QString)), v.DIRECT_CONNTYPE); } template<> @@ -272,7 +341,7 @@ namespace options { { 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); + base_value::connect(&v, SIGNAL(valueChanged(bool)), cb, SLOT(setChecked(bool)), v.DIRECT_CONNTYPE); } template<> @@ -280,7 +349,7 @@ namespace options { { 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); + base_value::connect(&v, SIGNAL(valueChanged(double)), dsb, SLOT(setValue(double)), v.DIRECT_CONNTYPE); } template<> @@ -288,7 +357,7 @@ namespace options { { 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); + base_value::connect(&v, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)), v.DIRECT_CONNTYPE); } template<> @@ -297,7 +366,7 @@ namespace options { 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); + base_value::connect(&v, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int)), v.DIRECT_CONNTYPE); } template<> @@ -305,14 +374,14 @@ namespace options { { 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); + base_value::connect(&v, SIGNAL(valueChanged(QString)),le, SLOT(setText(QString)), v.DIRECT_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.SAFE_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.DIRECT_CONNTYPE); } template<> @@ -320,6 +389,6 @@ namespace options { { 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); + base_value::connect(&v, SIGNAL(valueChanged(int)), t, SLOT(setCurrentIndex(int)), v.DIRECT_CONNTYPE); } } |