diff options
Diffstat (limited to 'facetracknoir/options.h')
-rw-r--r-- | facetracknoir/options.h | 306 |
1 files changed, 185 insertions, 121 deletions
diff --git a/facetracknoir/options.h b/facetracknoir/options.h index 3fd0e767..7833ea41 100644 --- a/facetracknoir/options.h +++ b/facetracknoir/options.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013 Stanislaw Halik +/* Copyright (c) 2013-2014 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 @@ -7,15 +7,17 @@ #pragma once +#include <memory> +#include <tuple> +#include <map> +#include <string> + #include <QObject> #include <QSettings> -#include <QMap> #include <QString> #include <QVariant> #include <QMutex> #include <QMutexLocker> -#include <memory> -#include <cassert> #include <QWidget> #include <QComboBox> #include <QCheckBox> @@ -26,17 +28,19 @@ #include <QLabel> #include <QCoreApplication> -#ifdef __GNUC__ -# define ov override -#else -# define ov -#endif +#include <cinttypes> #include <QDebug> namespace options { - template<typename T> - inline T qcruft_to_t (const QVariant& t); + template<typename k, typename v> + using map = std::map<k, v>; + using std::string; + + 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& datum); template<> inline int qcruft_to_t<int>(const QVariant& t) @@ -71,60 +75,72 @@ namespace options { // snapshot of qsettings group at given time class group { private: - QMap<QString, QVariant> map; - QString name; - public: - group(const QString& name) : name(name) + map<string, QVariant> map; + string name; + static const QString ini_pathname() { QSettings settings(group::org); - QString currentFile = - settings.value("SettingsFile", - QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); - QSettings iniFile(currentFile, QSettings::IniFormat); - iniFile.beginGroup(name); - for (auto& k : iniFile.childKeys()) - map[k] = iniFile.value(k); - iniFile.endGroup(); + return settings.value("SettingsFile", + QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); + } + public: + group(const string& name) : name(name) + { + QSettings conf(ini_pathname(), QSettings::IniFormat); + auto q_name = QString::fromStdString(name); + conf.beginGroup(q_name); + for (auto& k_ : conf.childKeys()) + { + auto tmp = k_.toUtf8(); + string k(tmp); + map[k] = conf.value(k_); + } + conf.endGroup(); } static constexpr const char* org = "opentrack"; - void save() { - QSettings settings(group::org); - QString currentFile = - settings.value("SettingsFile", - QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); - QSettings s(currentFile, QSettings::IniFormat); - s.beginGroup(name); - for (auto& k : map.keys()) - s.setValue(k, map[k]); + + void save() + { + QSettings s(ini_pathname(), QSettings::IniFormat); + auto q_name = QString::fromStdString(name); + s.beginGroup(q_name); + for (auto& i : map) + { + auto k = QString::fromStdString(i.first); + s.setValue(k, i.second); + } s.endGroup(); } - template<typename T> - T get(const QString& k) { - return qcruft_to_t<T>(map.value(k)); + + template<typename t> + t get(const string& k) + { + return qcruft_to_t<t>(map[k]); } - - void put(const QString& s, const QVariant& d) + + void put(const string& s, const QVariant& d) { map[s] = d; } - bool contains(const QString& s) + + bool contains(const string& s) { - return map.contains(s); + return map.count(s) != 0; } }; class impl_bundle : public QObject { Q_OBJECT - private: + protected: QMutex mtx; - const QString group_name; + const string group_name; group saved; group transient; + bool modified; impl_bundle(const impl_bundle&) = delete; impl_bundle& operator=(const impl_bundle&) = delete; - bool modified; public: - impl_bundle(const QString& group_name) : + impl_bundle(const string& group_name) : mtx(QMutex::Recursive), group_name(group_name), saved(group_name), @@ -132,37 +148,39 @@ namespace options { modified(false) { } + + string name() { return group_name; } + void reload() { QMutexLocker l(&mtx); saved = group(group_name); transient = saved; - emit reloaded(); - } - - std::shared_ptr<impl_bundle> make(const QString& name) { - return std::make_shared<impl_bundle>(name); + modified = false; } - void store(const QString& name, const QVariant& datum) + + bool store_kv(const string& 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() << name << transient.get<QVariant>(name) << datum; modified = true; transient.put(name, datum); - emit bundleChanged(); + return true; } + return false; } - bool contains(const QString& name) + bool contains(const string& name) { QMutexLocker l(&mtx); return transient.contains(name); } - template<typename T> - T get(const QString& name) { + template<typename t> + t get(const string& name) + { QMutexLocker l(&mtx); - return transient.get<T>(name); + return transient.get<t>(name); } void save() { @@ -171,90 +189,139 @@ namespace options { saved = transient; transient.save(); } - void revert() - { - QMutexLocker l(&mtx); - modified = false; - transient = saved; - emit bundleChanged(); - } bool modifiedp() { QMutexLocker l(&mtx); return modified; } - signals: - void bundleChanged(); - void reloaded(); }; - - typedef std::shared_ptr<impl_bundle> pbundle; + + class opt_bundle; + + namespace + { + template<typename k, typename v, typename cnt = int> + struct opt_singleton + { + public: + using pbundle = std::shared_ptr<v>; + using tt = std::tuple<cnt, pbundle>; + private: + QMutex implsgl_mtx; + map<k, tt> implsgl_data; + public: + opt_singleton() : implsgl_mtx(QMutex::Recursive) {} + + pbundle bundle(const k& key) + { + QMutexLocker l(&implsgl_mtx); + + if (implsgl_data.count(key) != 0) + return std::get<1>(implsgl_data[key]); + + auto shr = std::make_shared<v>(key); + implsgl_data[key] = tt(cnt(1), shr); + return shr; + } + + void bundle_decf(const k& key) + { + QMutexLocker l(&implsgl_mtx); + + if (--std::get<0>(implsgl_data[key]) == 0) + implsgl_data.erase(key); + } + + ~opt_singleton() { implsgl_data.clear(); } + }; + + using pbundle = std::shared_ptr<opt_bundle>; + using t_fact = opt_singleton<string, opt_bundle>; + static t_fact* opt_factory = new t_fact; + } + + static inline t_fact::pbundle bundle(const string name) { return opt_factory->bundle(name); } + + class opt_bundle : public impl_bundle + { + public: + opt_bundle() : impl_bundle("i-have-no-name") {} + opt_bundle(const string& group_name) : impl_bundle(group_name) {} + + ~opt_bundle() + { + opt_factory->bundle_decf(this->group_name); + } + }; class base_value : public QObject { Q_OBJECT +#define DEFINE_SLOT(t) void setValue(t datum) { store(datum); } +#define DEFINE_SIGNAL(t) void valueChanged(const t&) public: - base_value(pbundle b, const QString& name) : b(b), self_name(name) { - connect(b.get(), SIGNAL(reloaded()), this, SLOT(reread_value())); - } + base_value(pbundle b, const string& name) : b(b), self_name(name) {} protected: - virtual QVariant operator=(const QVariant& datum) = 0; pbundle b; - QString self_name; - public slots: - void reread_value() + string self_name; + + template<typename t> + void store(const t& datum) { - this->operator=(b->get<QVariant>(self_name)); + if (b->store_kv(self_name, datum)) + emit valueChanged(datum); } 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); }; + + static inline string string_from_qstring(const QString& datum) + { + auto tmp = datum.toUtf8(); + return string(tmp.constData()); + } - template<typename T> + template<typename t> class value : public base_value { - protected: - QVariant operator=(const QVariant& datum) { - auto foo = qcruft_to_t<T>(datum); - b->store(self_name, qVariantFromValue<T>(foo)); - emit valueChanged(foo); + public: + t operator=(const t datum) + { + store(datum); return datum; } - public: - 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::UniqueConnection; + value(pbundle b, const string& 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() { return b->get<T>(self_name); } - QVariant operator=(const T& datum) + value(pbundle b, const QString& name, t def) : value(b, string_from_qstring(name), def) {} + value(pbundle b, const char* name, t def) : value(b, string(name), def) {} + + operator t() { - return this->operator =(qVariantFromValue<T>(datum)); + 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<> @@ -262,58 +329,55 @@ 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); - } - - inline pbundle bundle(const QString& group) { - return std::make_shared<impl_bundle>(group); + base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.SAFE_CONNTYPE); } } |