diff options
-rw-r--r-- | facetracknoir/options.h | 151 |
1 files changed, 71 insertions, 80 deletions
diff --git a/facetracknoir/options.h b/facetracknoir/options.h index 291ac071..37377b55 100644 --- a/facetracknoir/options.h +++ b/facetracknoir/options.h @@ -28,10 +28,10 @@ #include <QDebug> namespace options { - template<typename T> + template<typename t> // don't elide usages of the function, qvariant default implicit // conversion results in nonsensical runtime behavior -sh - inline T qcruft_to_t (const QVariant& t); + inline t qcruft_to_t (const QVariant& datum); template<> inline int qcruft_to_t<int>(const QVariant& t) @@ -84,6 +84,7 @@ namespace options { conf.endGroup(); } static constexpr const char* org = "opentrack"; + void save() { QSettings s(ini_pathname(), QSettings::IniFormat); s.beginGroup(name); @@ -91,9 +92,9 @@ namespace options { s.setValue(k, map[k]); s.endGroup(); } - template<typename T> - T get(const QString& k) { - return qcruft_to_t<T>(map.value(k)); + template<typename t> + t get(const QString& k) { + return qcruft_to_t<t>(map.value(k)); } void put(const QString& s, const QVariant& d) { @@ -105,7 +106,8 @@ namespace options { } }; - class impl_bundle { + class impl_bundle : public QObject { + Q_OBJECT private: QMutex mtx; const QString group_name; @@ -114,7 +116,8 @@ namespace options { impl_bundle(const impl_bundle&) = delete; impl_bundle& operator=(const impl_bundle&) = delete; bool modified; - long priv_cookie; + signals: + void changed(); public: impl_bundle(const QString& group_name) : mtx(QMutex::Recursive), @@ -128,18 +131,20 @@ namespace options { QMutexLocker l(&mtx); saved = group(group_name); transient = saved; - priv_cookie++; } - void store(const QString& name, const QVariant& datum) + void store_kv(const QString& name, const QVariant& datum) { QMutexLocker l(&mtx); - if (!transient.contains(name) || datum != transient.get<QVariant>(name)) + auto old = transient.get<QVariant>(name); + if (!transient.contains(name) || datum != old) { if (!modified) - qDebug() << "bundle" << group_name << "modified due to" << name << transient.get<QVariant>(name) << datum << "->" << datum; + qDebug() << "bundle" << group_name << + "modified due to" << name << + transient.get<QVariant>(name) << + old << "->" << datum; modified = true; transient.put(name, datum); - priv_cookie++; } } bool contains(const QString& name) @@ -147,10 +152,10 @@ namespace options { QMutexLocker l(&mtx); return transient.contains(name); } - template<typename T> - T get(const QString& name) { + template<typename t> + t get(const QString& name) { QMutexLocker l(&mtx); - return transient.get<T>(name); + return transient.get<t>(name); } void save() { @@ -158,100 +163,85 @@ namespace options { modified = false; saved = transient; transient.save(); + emit changed(); } void revert() { QMutexLocker l(&mtx); modified = false; transient = saved; - priv_cookie++; + emit changed(); } bool modifiedp() { QMutexLocker l(&mtx); return modified; } - long cookie() const { - return priv_cookie; - } }; using pbundle = std::shared_ptr<impl_bundle>; class base_value : public QObject { Q_OBJECT +#define DEFINE_SLOT(t) void setValue(t datum) { store(datum); } +#define DEFINE_SIGNAL(t) void valueChanged(t); public: - base_value(pbundle b, const QString& name) : b(b), self_name(name), cookie_snap(0) {} - virtual QVariant operator=(const QVariant& datum) = 0; - template<typename T> - QVariant operator=(const T& datum) - { - return this->operator =(qVariantFromValue<T>(datum)); - } - protected: - pbundle b; - QString self_name; - template<typename T> - QVariant store(const T& datum) - { - b->store(self_name, qVariantFromValue<T>(datum)); - emit valueChanged(datum); - return datum; - } - void maybe_lazy_change() - { - long cookie = b->cookie(); - if (cookie_snap != cookie) - { - cookie_snap = cookie; - this->operator=(b->get<QVariant>(self_name)); - } - } - private: - long cookie_snap; + base_value(pbundle b, const QString& name) : b(b), self_name(name) {} public slots: -#define DEFINE_SLOT(t) void setValue(t datum) { this->operator=(qVariantFromValue(datum)); } DEFINE_SLOT(double) DEFINE_SLOT(int) DEFINE_SLOT(QString) DEFINE_SLOT(bool) signals: -#define DEFINE_SIGNAL(t) void valueChanged(t); - DEFINE_SIGNAL(double) - DEFINE_SIGNAL(int) - DEFINE_SIGNAL(QString) - DEFINE_SIGNAL(bool) + DEFINE_SIGNAL(double); + DEFINE_SIGNAL(int); + DEFINE_SIGNAL(bool); + DEFINE_SIGNAL(QString); + // Qt5 moc really insists on that one -sh 20141012 + DEFINE_SIGNAL(QVariant); + protected: + pbundle b; + QString self_name; + + template<typename t> + void store(const t& datum) + { + b->store_kv(self_name, datum); + emit valueChanged(static_cast<t>(datum)); + } }; - template<typename T> + template<typename t> class value : public base_value { public: - QVariant operator=(const QVariant& datum) { - return store(qcruft_to_t<T>(datum)); + t operator=(const t& datum) + { + store(qVariantFromValue<t>(datum)); + return datum; } - static constexpr const Qt::ConnectionType QT_CONNTYPE = Qt::UniqueConnection; - static constexpr const Qt::ConnectionType OPT_CONNTYPE = Qt::UniqueConnection; - value(pbundle b, const QString& name, T def) : base_value(b, name) + static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; + static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::AutoConnection; + value(pbundle b, const QString& name, t def) : base_value(b, name) { if (!b->contains(name) || b->get<QVariant>(name).type() == QVariant::Invalid) - this->operator=(qVariantFromValue<T>(def)); + *this = def; } - operator T() + operator t() { - maybe_lazy_change(); - return b->get<T>(self_name); + return b->get<t>(self_name); } }; - template<typename T, typename Q> - inline void tie_setting(value<T>&, Q*); + template<typename t, typename q> + inline void tie_setting(value<t>&, q*); template<> inline void tie_setting(value<int>& v, QComboBox* cb) { cb->setCurrentIndex(v); - base_value::connect(cb, SIGNAL(currentIndexChanged(int)), &v, SLOT(setValue(int)), v.QT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(int)), cb, SLOT(setCurrentIndex(int)), v.OPT_CONNTYPE); + 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<> @@ -259,55 +249,56 @@ namespace options { { cb->setCurrentText(v); v = cb->currentText(); - base_value::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(QString)), v.QT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(QString)), cb, SLOT(setCurrentText(QString)), v.OPT_CONNTYPE); + 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<bool>& v, QCheckBox* cb) { cb->setChecked(v); - base_value::connect(cb, SIGNAL(toggled(bool)), &v, SLOT(setValue(bool)), v.QT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(bool)), cb, SLOT(setChecked(bool)), v.OPT_CONNTYPE); + 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<double>& v, QDoubleSpinBox* dsb) { dsb->setValue(v); - base_value::connect(dsb, SIGNAL(valueChanged(double)), &v, SLOT(setValue(double)), v.QT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(double)), dsb, SLOT(setValue(double)), v.OPT_CONNTYPE); + 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, QSpinBox* sb) { sb->setValue(v); - base_value::connect(sb, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.QT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)), v.OPT_CONNTYPE); + 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<int>& v, QSlider* sl) { sl->setValue(v); - base_value::connect(sl, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.QT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int)), v.OPT_CONNTYPE); + 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, QLineEdit* le) { le->setText(v); - base_value::connect(le, SIGNAL(textChanged(QString)), &v, SLOT(setValue(QString)), v.QT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(QString)),le, SLOT(setText(QString)), v.OPT_CONNTYPE); + 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<QString>& v, QLabel* lb) { lb->setText(v); - base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.OPT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.SAFE_CONNTYPE); } inline pbundle bundle(const QString& group) { |