diff options
-rw-r--r-- | facetracknoir/options.hpp | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/facetracknoir/options.hpp b/facetracknoir/options.hpp new file mode 100644 index 00000000..7db75941 --- /dev/null +++ b/facetracknoir/options.hpp @@ -0,0 +1,200 @@ +/* Copyright (c) 2013 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 <QSettings> +#include <QSettings> +#include <QMap> +#include <QString> +#include <QVariant> +#include <memory> +#include <cassert> +#include <QWidget> +#include <QComboBox> +#include <QCheckBox> +#include <QDoubleSpinBox> +#include <QSpinBox> +#include <QSlider> + +namespace options { + template<typename T> + inline T qcruft_to_t(const QVariant& t); + + 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 double qcruft_to_t<double>(const QVariant& t) + { + return t.toDouble(); + } + + template<> + inline float qcruft_to_t<float>(const QVariant& t) + { + return t.toFloat(); + } + + // snapshot of qsettings group at given time + class group { + private: + QMap<QString, QVariant> map; + QString name; + public: + group(const QString& name, QSettings& s) : name(name) + { + s.beginGroup(name); + for (auto& k : s.childKeys()) + map[k] = s.value(k); + s.endGroup(); + } + static constexpr const char* org = "opentrack"; + void save() { + QSettings s(org); + s.beginGroup(name); + for (auto& k : map.keys()) + s.setValue(k, map[k]); + s.endGroup(); + } + template<typename T> + T get(const QString& k) { + return qcruft_to_t<T>(map.value(k)); + } + + void put(const QString& s, const QVariant& d) + { + map[s] = d; + } + }; + + class bundle { + private: + const QString group_name; + group saved; + group transient; + bundle(const bundle&) = delete; + bundle& operator=(const bundle&) = delete; + bool modified; + public: + bundle(const QString& group_name, QSettings& s) : + group_name(group_name), + saved(group_name, s), + transient(saved), + modified(false) + { + } + std::shared_ptr<bundle> make(const QString& name, QSettings& s) { + assert(s.format() == QSettings::IniFormat); + return std::make_shared<bundle>(name, s); + } + void store(QString& name, QVariant& datum) + { + modified = true; + transient.put(name, datum); + } + template<typename T> + T get(QString& name) { + transient.get<T>(name); + } + void save() + { + modified = false; + saved = transient; + transient.save(); + } + void revert() + { + modified = false; + transient = saved; + } + }; + + typedef std::shared_ptr<bundle> pbundle; + + class QCruft : public QObject { + }; + + template<typename T> + class value : public QCruft { + private: + const QString self_name; + pbundle b; + public: + value(const pbundle& b, const QString& name) : + self_name(name), + b(b) + { + } + operator T() { return b->get<T>(self_name); } + T& operator=(const T& datum) { + b->store(self_name, datum); + emit valueChanged(datum); + return datum; + } + public slots: + void setValue(const T datum) { + this->operator =(datum); + } + signals: + void valueChanged(T datum); + }; + + template<typename T, typename Q> + inline void tie(value<T>&, Q*); + + template<> + inline void tie<int, QComboBox>(value<int>& v, QComboBox* cb) + { + QObject::connect(cb, SIGNAL(currentIndexChanged(int)), &v, SLOT(setValue(int))); + QObject::connect(&v, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int))); + } + + template<> + inline void tie<QString, QComboBox>(value<QString>& v, QComboBox* cb) + { + QObject::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(QString))); + QObject::connect(&v, SIGNAL(valueChanged(QString)), &v, SLOT(setValue(QString))); + } + + template<> + inline void tie<bool, QCheckBox>(value<bool>& v, QCheckBox* cb) + { + QObject::connect(cb, SIGNAL(toggled(bool)), &v, SLOT(setValue(bool))); + QObject::connect(&v, SIGNAL(valueChanged(bool)), cb, SLOT(setChecked(bool))); + } + + template<> + inline void tie<double, QDoubleSpinBox>(value<double>& v, QDoubleSpinBox* dsb) + { + QObject::connect(dsb, SIGNAL(valueChanged(double)), &v, SLOT(setValue(double))); + QObject::connect(&v, SIGNAL(valueChanged(double)), dsb, SLOT(setValue(double))); + } + + template<> + inline void tie<int, QSpinBox>(value<int>& v, QSpinBox* sb) + { + QObject::connect(sb, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int))); + QObject::connect(&v, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int))); + } + + template<> + inline void tie<int, QSlider>(value<int>& v, QSlider* sl) + { + QObject::connect(sl, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int))); + QObject::connect(&v, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int))); + } +} |