summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2016-05-09 16:25:46 +0200
committerStanislaw Halik <sthalik@misaki.pl>2016-05-09 16:25:46 +0200
commitfa14f46d09a3739b33dd74b577804fdec22b7325 (patch)
tree5f390cdd3b9bce7a000733a7fa28d93002c496f3
parentacec691b5d6d6373e8f8f41f288d5fb6e2f84215 (diff)
compat/options: add enum support
-rwxr-xr-x[-rw-r--r--]opentrack-compat/options.hpp161
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);
}
}