diff options
| -rw-r--r-- | migration/20160906_01-axis-signs.cpp | 2 | ||||
| -rw-r--r-- | migration/20160906_02-modules.cpp | 2 | ||||
| -rw-r--r-- | migration/20180118_00-reltrans.cpp | 2 | ||||
| -rw-r--r-- | migration/20180428_00-module-names.cpp | 2 | ||||
| -rw-r--r-- | options/base-value.cpp | 13 | ||||
| -rw-r--r-- | options/base-value.hpp | 12 | ||||
| -rw-r--r-- | options/bundle.cpp | 128 | ||||
| -rw-r--r-- | options/bundle.hpp | 60 | ||||
| -rw-r--r-- | options/connector.cpp | 88 | ||||
| -rw-r--r-- | options/connector.hpp | 27 | ||||
| -rw-r--r-- | options/globals.cpp | 45 | ||||
| -rw-r--r-- | options/globals.hpp | 21 | ||||
| -rw-r--r-- | options/group.cpp | 20 | ||||
| -rw-r--r-- | options/group.hpp | 15 | ||||
| -rw-r--r-- | options/metatype.cpp | 2 | ||||
| -rw-r--r-- | options/tie.cpp | 9 | ||||
| -rw-r--r-- | options/tie.hpp | 27 | ||||
| -rw-r--r-- | options/value-traits.hpp | 125 | ||||
| -rw-r--r-- | options/value.hpp | 75 | ||||
| -rw-r--r-- | spline/spline.cpp | 11 | ||||
| -rw-r--r-- | spline/spline.hpp | 2 | 
21 files changed, 329 insertions, 359 deletions
| diff --git a/migration/20160906_01-axis-signs.cpp b/migration/20160906_01-axis-signs.cpp index 7b0be70a..064cd5fb 100644 --- a/migration/20160906_01-axis-signs.cpp +++ b/migration/20160906_01-axis-signs.cpp @@ -73,7 +73,7 @@ void axis_signs_split_rc11::run()      for (const char* name : axis_names)          new_bundle->store_kv(alt_sign_fmt.arg(name), -                             QVariant(old_bundle->get<bool>(alt_sign_fmt.arg(name)))); +                             old_bundle->get_variant(alt_sign_fmt.arg(name)));      new_bundle->save();  } diff --git a/migration/20160906_02-modules.cpp b/migration/20160906_02-modules.cpp index 9ce2b9dc..8ba61248 100644 --- a/migration/20160906_02-modules.cpp +++ b/migration/20160906_02-modules.cpp @@ -58,7 +58,7 @@ struct split_modules_rc11 : migration          bundle old_bundle = make_bundle("opentrack-ui");          for (const char* name : module_names) -            new_bundle->store_kv(name, QVariant(old_bundle->get<QString>(name))); +            new_bundle->store_kv(name, old_bundle->get_variant(name));          new_bundle->save();      } diff --git a/migration/20180118_00-reltrans.cpp b/migration/20180118_00-reltrans.cpp index ba35e7f0..7a2ddec6 100644 --- a/migration/20180118_00-reltrans.cpp +++ b/migration/20180118_00-reltrans.cpp @@ -35,7 +35,7 @@ struct reltrans_enum : migration      void run() override      {          auto b = make_bundle("opentrack-ui"); -        bool value = b->get<bool>(old_name); +        bool value = b->get_variant(old_name).value<bool>();          b->store_kv(new_name, int(value ? reltrans_enabled : reltrans_disabled));          b->save();      } diff --git a/migration/20180428_00-module-names.cpp b/migration/20180428_00-module-names.cpp index fbb7a161..174ca7ee 100644 --- a/migration/20180428_00-module-names.cpp +++ b/migration/20180428_00-module-names.cpp @@ -55,7 +55,7 @@ struct module_names : migration                  continue;              } -            QString value = b->get<QString>(type.name); +            QString value = b->get_variant(type.name).value<QString>();              bool found = false; diff --git a/options/base-value.cpp b/options/base-value.cpp index bcbbd1dc..ec96fe6c 100644 --- a/options/base-value.cpp +++ b/options/base-value.cpp @@ -2,18 +2,15 @@  using namespace options; -value_::value_(bundle const& b, const QString& name, value_::comparator cmp, std::type_index type_idx) : -    b(b), -    self_name(name), -    cmp(cmp), -    type_index(type_idx) +value_::value_(bundle const& b, const QString& name) : +    b(b), self_name(name)  { -    b->on_value_created(name, this); +    b->on_value_created(this);  }  value_::~value_()  { -    b->on_value_destructed(self_name, this); +    b->on_value_destructed(this);  }  void value_::notify() const @@ -23,7 +20,7 @@ void value_::notify() const  namespace options::detail { -void set_base_value_to_default(value_* val) +void set_value_to_default(value_* val)  {      val->set_to_default();  } diff --git a/options/base-value.hpp b/options/base-value.hpp index 750f93f1..6a4709ee 100644 --- a/options/base-value.hpp +++ b/options/base-value.hpp @@ -15,7 +15,6 @@  #include <QPointF>  #include <QVariant> -#include <typeindex>  #include <utility>  #define OTR_OPTIONS_SLOT(t) void setValue(t datum) { store_(datum); } @@ -29,13 +28,12 @@ class OTR_OPTIONS_EXPORT value_ : public QObject      friend class detail::connector; -    using comparator = bool(*)(const QVariant& val1, const QVariant& val2);      template<typename t>      using signal_sig = void(value_::*)(cv_qualified<t>) const;  public:      QString name() const { return self_name; } -    value_(bundle const& b, const QString& name, comparator cmp, std::type_index type_idx); +    value_(bundle const& b, const QString& name);      ~value_() override;      // no C++17 "constexpr inline" for data declarations in MSVC @@ -68,8 +66,6 @@ signals:  protected:      bundle b;      QString self_name; -    comparator cmp; -    std::type_index type_index;      virtual void store_variant(const QVariant& x) = 0; @@ -77,8 +73,7 @@ protected:      void store_(const t& datum)      {          using traits = detail::value_traits<t>; -        using stored_type = typename traits::stored_type; -        store_variant(QVariant::fromValue<stored_type>(datum)); +        store_variant(traits::qvariant_from_value(datum));      }  public slots: @@ -98,11 +93,10 @@ public slots:      OTR_OPTIONS_SLOT(const QList<slider_value>&)      OTR_OPTIONS_SLOT(const QList<QPointF>&) -    virtual void reload() = 0;      virtual void bundle_value_changed() const = 0;      virtual void set_to_default() = 0; -    friend void ::options::detail::set_base_value_to_default(value_* val); +    friend void ::options::detail::set_value_to_default(value_* val);  };  } //ns options diff --git a/options/bundle.cpp b/options/bundle.cpp index c426dd2e..0ab50037 100644 --- a/options/bundle.cpp +++ b/options/bundle.cpp @@ -10,6 +10,8 @@  #include "value.hpp"  #include "globals.hpp" +#include <cstdlib> +  #include <QThread>  #include <QApplication> @@ -18,8 +20,15 @@ using namespace options::globals;  namespace options::detail { -bundle::bundle(const QString& group_name) -    : mtx(QMutex::Recursive), +mutex::mutex(QMutex::RecursionMode mode) : QMutex(mode) {} + +mutex::operator QMutex*() const +{ +    return const_cast<QMutex*>(static_cast<const QMutex*>(this)); +} + +bundle::bundle(const QString& group_name) : +      mtx(QMutex::Recursive),        group_name(group_name),        saved(group_name),        transient(saved) @@ -30,19 +39,25 @@ bundle::~bundle() = default;  void bundle::reload()  { -    if (group_name.size()) +    if (!is_ini_modified()) +        return; + +    if (!group_name.isEmpty())      {          QMutexLocker l(&mtx); + +        // XXX what do we do when values are and aren't equal? +        // see QPointF -sh 20180830 + +        // XXX we could probably skip assigning to `saved' -sh 20180830          saved = group(group_name); -        const bool has_changes = is_modified();          transient = saved; -        if (has_changes) -        { -            connector::notify_all_values(); -            emit reloading(); -            emit changed(); -        } +        mark_ini_modified(false); + +        connector::notify_all_values(); +        emit reloading(); +        emit changed();      }  } @@ -50,10 +65,9 @@ void bundle::set_all_to_default()  {      QMutexLocker l(&mtx); -    forall([](const QString&, value_* val) { set_base_value_to_default(val); }); - -    if (is_modified()) -        mark_ini_modified(); +    forall([](value_* val) { +        set_value_to_default(val); +    });  }  void bundle::store_kv(const QString& name, const QVariant& new_value) @@ -62,16 +76,21 @@ void bundle::store_kv(const QString& name, const QVariant& new_value)      if (!group_name.isEmpty())      { -        const QVariant old_value = transient.get_variant(name); -        if (!connector::is_equal(name, old_value, new_value)) -        { -            transient.put(name, new_value); -            connector::notify_values(name); -            emit changed(); -        } +        transient.put(name, new_value); + +        mark_ini_modified(); + +        connector::notify_values(name); +        emit changed();      }  } +QVariant bundle::get_variant(const QString& name) const +{ +    QMutexLocker l(mtx); +    return transient.get_variant(name); +} +  bool bundle::contains(const QString &name) const  {      QMutexLocker l(mtx); @@ -83,56 +102,18 @@ void bundle::save()      if (QThread::currentThread() != qApp->thread())          qDebug() << "group::save - current thread not ui thread"; -    if (group_name.size() == 0) +    if (group_name.isEmpty())          return; -    bool modified_ = false; -      {          QMutexLocker l(&mtx); -        if (is_modified()) -        { -            //qDebug() << "bundle" << group_name << "changed, saving"; -            modified_ = true; -            saved = transient; -            saved.save(); -        } -    } - -    if (modified_) -    { -        qDebug() << "saving" << name(); -        emit saving(); -    } -} - -bool bundle::is_modified() const -{ -    QMutexLocker l(mtx); - -    for (const auto& kv : transient.kvs) -    { -        const QVariant other = saved.get<QVariant>(kv.first); -        if (!saved.contains(kv.first) || !is_equal(kv.first, kv.second, other)) -        { -            //if (logspam) -            //    qDebug() << "bundle" << group_name << "modified" << "key" << kv.first << "-" << other << "<>" << kv.second; -            return true; -        } -    } - -    for (const auto& kv : saved.kvs) -    { -        if (!transient.contains(kv.first)) -        { -            //if (logspam) -            //    qDebug() << "bundle" << group_name << "modified" << "key" << kv.first << "-" << other << "<>" << kv.second; -            return true; -        } +        saved = transient; +        saved.save();      } -    return false; +    qDebug() << "saving" << name(); +    emit saving();  }  void bundler::after_profile_changed_() @@ -159,11 +140,13 @@ void bundler::refresh_all_bundles()  bundler::bundler() = default;  bundler::~bundler() = default; -std::shared_ptr<bundler::v> bundler::make_bundle_(const bundler::k& key) +std::shared_ptr<bundler::v> bundler::make_bundle_(const k& key)  {      QMutexLocker l(&implsgl_mtx); -    auto it = implsgl_data.find(key); +    using iter = decltype(implsgl_data.cbegin()); + +    const iter it = implsgl_data.find(key);      if (it != implsgl_data.end())      { @@ -177,11 +160,14 @@ std::shared_ptr<bundler::v> bundler::make_bundle_(const bundler::k& key)      auto shr = shared(new v(key), [this, key](v* ptr) {          QMutexLocker l(&implsgl_mtx); -        auto it = implsgl_data.find(key); +        const iter it = implsgl_data.find(key);          if (it != implsgl_data.end()) -            implsgl_data.erase(it); +            (void)implsgl_data.erase(it);          else -            qDebug() << "ERROR: can't find self-bundle!"; +        { +            qCritical() << "ERROR: can't find self-bundle!"; +            std::abort(); +        }          delete ptr;      });      implsgl_data[key] = weak(shr); @@ -194,13 +180,11 @@ bundler& bundler::bundler_singleton()      return ret;  } -QMutex* bundle::get_mtx() const { return mtx; } -  } // ns options::detail  namespace options { -OTR_OPTIONS_EXPORT std::shared_ptr<bundle_> make_bundle(const QString& name) +std::shared_ptr<bundle_> make_bundle(const QString& name)  {      if (name.size())          return detail::bundler::bundler_singleton().make_bundle_(name); diff --git a/options/bundle.hpp b/options/bundle.hpp index 98291fc5..9ab7f74c 100644 --- a/options/bundle.hpp +++ b/options/bundle.hpp @@ -13,7 +13,7 @@  #include <memory>  #include <tuple> -#include <map> +#include <unordered_map>  #include <memory>  #include <vector> @@ -21,13 +21,21 @@  #include <QString>  #include <QVariant>  #include <QMutex> -#include <QMutexLocker>  #include <QDebug> +#include "compat/qhash.hpp" +  #include "export.hpp"  namespace options::detail { +    class OTR_OPTIONS_EXPORT mutex final : public QMutex +    { +    public: +        explicit mutex(QMutex::RecursionMode mode); +        cc_noinline operator QMutex*() const; // NOLINT +    }; +      class bundle;  } // ns options::detail @@ -39,20 +47,10 @@ namespace options {  namespace options::detail { -struct bundler; -  class OTR_OPTIONS_EXPORT bundle final : public QObject, public connector  {      Q_OBJECT -    class OTR_OPTIONS_EXPORT mutex final : public QMutex -    { -    public: -        explicit mutex(QMutex::RecursionMode mode) : QMutex(mode) {} -        operator QMutex*() const { return const_cast<QMutex*>(static_cast<const QMutex*>(this)); } -    }; - -private:      mutex mtx;      const QString group_name;      group saved; @@ -65,24 +63,18 @@ signals:  public:      bundle(const bundle&) = delete; -    bundle(bundle&&) = delete; -    bundle& operator=(bundle&&) = delete;      bundle& operator=(const bundle&) = delete; -    QMutex* get_mtx() const override; -    cc_noinline explicit bundle(const QString& group_name); -    cc_noinline ~bundle() override; +    QMutex* get_mtx() const override { return mtx; }      QString name() const { return group_name; } -    cc_noinline void store_kv(const QString& name, const QVariant& datum); -    cc_noinline bool contains(const QString& name) const; -    cc_noinline bool is_modified() const; -    template<typename t> -    t get(const QString& name) const -    { -        QMutexLocker l(mtx); -        return transient.get<t>(name); -    } +    explicit bundle(const QString& group_name); +    ~bundle() override; + +    void store_kv(const QString& name, const QVariant& datum); +    bool contains(const QString& name) const; + +    QVariant get_variant(const QString& name) const;  public slots:      void save(); @@ -97,27 +89,25 @@ struct OTR_OPTIONS_EXPORT bundler final      using weak = std::weak_ptr<v>;      using shared = std::shared_ptr<v>; +    static void refresh_all_bundles(); +  private:      QMutex implsgl_mtx { QMutex::Recursive }; -    std::map<k, weak> implsgl_data; -    void after_profile_changed_(); +    std::unordered_map<k, weak> implsgl_data {}; -public: -    static void refresh_all_bundles(); +    void after_profile_changed_(); -private:      friend OTR_OPTIONS_EXPORT      std::shared_ptr<v> options::make_bundle(const QString& name); -    std::shared_ptr<v> make_bundle_(const k& key); - -    static bundler& bundler_singleton(); +    [[nodiscard]] std::shared_ptr<v> make_bundle_(const k& key); +    [[nodiscard]] static bundler& bundler_singleton();      bundler();      ~bundler();  }; -void set_base_value_to_default(value_* val); +void set_value_to_default(value_* val);  } // ns options::detail diff --git a/options/connector.cpp b/options/connector.cpp index 73aefed8..838a2e0e 100644 --- a/options/connector.cpp +++ b/options/connector.cpp @@ -9,99 +9,57 @@  #include "connector.hpp"  #include "value.hpp" -#include <utility> -  namespace options::detail { -static bool generic_is_equal(const QVariant& val1, const QVariant& val2) -{ -    return val1 == val2; -} - +connector::connector() = default;  connector::~connector() = default; -bool connector::is_equal(const QString& name, const QVariant& val1, const QVariant& val2) const +void connector::on_value_destructed(value_type val)  { -    QMutexLocker l(get_mtx()); +    const QString& name = val->name(); -    auto it = connected_values.find(name); - -    if (it != connected_values.cend() && !std::get<0>((*it).second).empty()) -        return std::get<1>((*it).second)(val1, val2); -    else -        return generic_is_equal(val1, val2); -} - -bool connector::on_value_destructed_impl(const QString& name, value_type val) -{      QMutexLocker l(get_mtx()); -    auto it = connected_values.find(name); +    const auto it = connected_values.find(name);      if (it != connected_values.end())      { -        std::vector<value_type>& values = std::get<0>((*it).second); -        for (auto it = values.begin(); it != values.end(); it++) +        value_vec& values = it->second; +        for (auto it = values.begin(); it != values.end(); )          {              if (*it == val) -            { -                values.erase(it); -                return true; -            } +                it = values.erase(it); +            else +                it++;          }      } -    return false; -} - -void connector::on_value_destructed(const QString& name, value_type val) -{ -    if (!name.size()) -        return; - -    const bool ok = on_value_destructed_impl(name, val); -    if (!ok) -        qWarning() << "options/connector: value destructed without creating;" -                   << "bundle" -                   << val->b->name() -                   << "value-name" << name -                   << "value-ptr" << quintptr(val); +    if (it != connected_values.end() && it->second.empty()) +        connected_values.erase(it);  } -void connector::on_value_created(const QString& name, value_type val) +void connector::on_value_created(value_type val)  { -    if (!name.size()) +    const QString& name = val->name(); + +    if (name.isEmpty())          return;      QMutexLocker l(get_mtx()); -    int i = 1; -    while (on_value_destructed_impl(name, val)) -    { -        qWarning() << "options/connector: value created twice;" -                   << "cnt" << i++ -                   << "bundle" << val->b->name() -                   << "value-name" << name -                   << "value-ptr" << quintptr(val); -    } -      auto it = connected_values.find(name);      if (it != connected_values.end())      { -        tt& tmp = (*it).second; -        std::type_index& typeidx = std::get<2>(tmp); -        std::vector<value_type>& values = std::get<0>(tmp); - -        if (typeidx != val->type_index) -            std::get<1>((*it).second) = generic_is_equal; +        value_vec& values = it->second;          values.push_back(val);      }      else      { -        std::vector<value_type> vec; +        value_vec vec; +        vec.reserve(4);          vec.push_back(val); -        connected_values.emplace(name, tt(vec, val->cmp, val->type_index)); +        connected_values.emplace(name, vec);      }  } @@ -109,17 +67,15 @@ void connector::notify_values(const QString& name) const  {      auto it = connected_values.find(name);      if (it != connected_values.cend()) -        for (value_type val : std::get<0>((*it).second)) +        for (value_type val : it->second)              val->bundle_value_changed();  }  void connector::notify_all_values() const  { -    for (auto& [k, v] : connected_values) -        for (value_type val : std::get<0>(v)) +    for (const auto& [k, v] : connected_values) +        for (value_type val : v)              val->bundle_value_changed();  } -connector::connector() = default; -  } // ns options::detail diff --git a/options/connector.hpp b/options/connector.hpp index 26812e7f..11aa94da 100644 --- a/options/connector.hpp +++ b/options/connector.hpp @@ -8,15 +8,13 @@  #pragma once -#include <map> +#include <unordered_map>  #include <vector> -#include <tuple> -#include <typeinfo> -#include <typeindex> -#include <QVariant> +  #include <QString>  #include <QMutex> -#include <QMutexLocker> + +#include "compat/qhash.hpp"  #include "export.hpp" @@ -32,13 +30,10 @@ class OTR_OPTIONS_EXPORT connector      using value_type = value_*;      using value_vec = std::vector<value_type>; -    using comparator = bool(*)(const QVariant&, const QVariant&); -    using tt = std::tuple<value_vec, comparator, std::type_index>; -    std::map<QString, tt> connected_values; +    std::unordered_map<QString, value_vec> connected_values; -    void on_value_destructed(const QString& name, value_type val); -    void on_value_created(const QString& name, value_type val); -    bool on_value_destructed_impl(const QString& name, value_type val); +    void on_value_destructed(value_type val); +    void on_value_created(value_type val);  protected:      void notify_values(const QString& name) const; @@ -51,20 +46,16 @@ protected:          QMutexLocker l(get_mtx());          for (auto& pair : connected_values) -            for (auto& val : std::get<0>(pair.second)) -                fun(pair.first, val); +            for (auto& val : pair.second) +                fun(val);      }  public:      connector();      virtual ~connector(); -    bool is_equal(const QString& name, const QVariant& val1, const QVariant& val2) const; -      connector(const connector&) = default;      connector& operator=(const connector&) = default; -    connector(connector&&) = default; -    connector& operator=(connector&&) = default;  };  } // ns options::detail diff --git a/options/globals.cpp b/options/globals.cpp index 85a6bdf2..33327090 100644 --- a/options/globals.cpp +++ b/options/globals.cpp @@ -9,6 +9,8 @@  namespace options::globals::detail { +ini_ctx::ini_ctx() = default; +  bool is_portable_installation()  {  #if defined _WIN32 @@ -23,11 +25,11 @@ saver_::~saver_()  {      if (--ctx.refcount == 0 && ctx.modifiedp)      { -        ctx.modifiedp = false;          auto& settings = *ctx.qsettings;          settings.sync();          if (settings.status() != QSettings::NoError)              qDebug() << "error with .ini file" << settings.fileName() << settings.status(); +        ctx.modifiedp = false;      }      ctx.mtx.unlock();  } @@ -41,7 +43,6 @@ ini_ctx& cur_settings()  {      static ini_ctx ini;      const QString pathname = ini_pathname(); -    static QString ini_pathname;      ini.mtx.lock(); @@ -51,7 +52,7 @@ ini_ctx& cur_settings()          ini.pathname = pathname;      } -    if (pathname != ini_pathname) +    if (ini.pathname != pathname)      {          ini.qsettings.emplace(pathname, QSettings::IniFormat);          ini.pathname = pathname; @@ -66,15 +67,20 @@ ini_ctx& global_settings()      ini.mtx.lock(); -    if (!is_portable_installation()) -        // Windows registry or xdg on Linux -        ini.qsettings.emplace(OPENTRACK_ORG); -    else +    if (ini.pathname.isEmpty())      { -        static const QString pathname = OPENTRACK_BASE_PATH + QStringLiteral("/globals.ini"); -        // file in executable's directory -        ini.qsettings.emplace(pathname, QSettings::IniFormat); -        ini.pathname = pathname; +        if (!is_portable_installation()) +            // Windows registry or xdg on Linux +            ini.qsettings.emplace(OPENTRACK_ORG); +        else +        { +            static const QString pathname = OPENTRACK_BASE_PATH + QStringLiteral("/globals.ini"); +            // file in executable's directory +            ini.qsettings.emplace(pathname, QSettings::IniFormat); +            ini.pathname = pathname; +        } + +        ini.pathname = "placeholder";      }      return ini; @@ -85,6 +91,16 @@ ini_ctx& global_settings()  namespace options::globals  { +using namespace detail; + +bool is_ini_modified() +{ +    ini_ctx& ini = cur_settings(); +    bool ret = ini.modifiedp; +    ini.mtx.unlock(); +    return ret; +} +  QString ini_filename()  {      return with_global_settings_object([&](QSettings& settings) { @@ -119,11 +135,10 @@ QStringList ini_list()      return list;  } -void mark_ini_modified() +void mark_ini_modified(bool value)  { -    using namespace detail;      auto& ini = cur_settings(); -    ini.modifiedp = true; +    ini.modifiedp = value;      ini.mtx.unlock();  } @@ -138,7 +153,7 @@ QString ini_directory()          static const QString subdir = "ini";          if (!QDir(dir).mkpath(subdir)) -            return QString(); +            return {};          return dir + '/' + subdir;      } diff --git a/options/globals.hpp b/options/globals.hpp index 4d74cbf0..8032e5d8 100644 --- a/options/globals.hpp +++ b/options/globals.hpp @@ -11,20 +11,18 @@  namespace options::globals::detail { -struct ini_ctx;  struct saver_; -OTR_OPTIONS_EXPORT ini_ctx& cur_settings(); -OTR_OPTIONS_EXPORT ini_ctx& global_settings(); -OTR_OPTIONS_EXPORT bool is_portable_installation(); - -struct ini_ctx +struct OTR_OPTIONS_EXPORT ini_ctx  {      std::optional<QSettings> qsettings { std::in_place }; +    QString pathname; +    QMutex mtx { QMutex::Recursive }; +      int refcount = 0;      bool modifiedp = false; -    QMutex mtx { QMutex::Recursive }; -    QString pathname; + +    ini_ctx();  };  struct OTR_OPTIONS_EXPORT saver_ final @@ -44,11 +42,16 @@ auto with_settings_object_(ini_ctx& ini, F&& fun)      return fun(*ini.qsettings);  } +OTR_OPTIONS_EXPORT ini_ctx& cur_settings(); +OTR_OPTIONS_EXPORT ini_ctx& global_settings(); +OTR_OPTIONS_EXPORT bool is_portable_installation(); +  } // ns options::globals::detail  namespace options::globals  { -    OTR_OPTIONS_EXPORT void mark_ini_modified(); +    OTR_OPTIONS_EXPORT void mark_ini_modified(bool value = true); +    OTR_OPTIONS_EXPORT bool is_ini_modified();      OTR_OPTIONS_EXPORT QString ini_directory();      OTR_OPTIONS_EXPORT QString ini_filename();      OTR_OPTIONS_EXPORT QString ini_pathname(); diff --git a/options/group.cpp b/options/group.cpp index 5f6c3232..af66aaf2 100644 --- a/options/group.cpp +++ b/options/group.cpp @@ -14,9 +14,7 @@  #include <algorithm>  #include <QFile> -  #include <QDir> -#include <QDebug>  namespace options::detail { @@ -29,14 +27,8 @@ group::group(const QString& name) : name(name)      with_settings_object([&](QSettings& conf) {          conf.beginGroup(name); -        for (auto& k_ : conf.childKeys()) -        { -            auto tmp = k_.toUtf8(); -            QString k(tmp); -            QVariant val = conf.value(k_); -            if (val.type() != QVariant::Invalid) -                kvs[k] = std::move(val); -        } +        for (auto const& k : conf.childKeys()) +            kvs[k] = conf.value(k);          conf.endGroup();      });  } @@ -48,11 +40,9 @@ void group::save() const      with_settings_object([&](QSettings& s) {          s.beginGroup(name); -        for (auto& i : kvs) +        for (auto const& i : kvs)              s.setValue(i.first, i.second);          s.endGroup(); - -        mark_ini_modified();      });  } @@ -64,7 +54,7 @@ void group::put(const QString &s, const QVariant &d)  bool group::contains(const QString &s) const  {      const auto it = kvs.find(s); -    return it != kvs.cend() && it->second != QVariant::Invalid; +    return it != kvs.cend();  }  QVariant group::get_variant(const QString& name) const @@ -73,7 +63,7 @@ QVariant group::get_variant(const QString& name) const      if (it != kvs.cend())          return it->second; -    return {}; +    return QVariant();  }  } // ns options::detail diff --git a/options/group.hpp b/options/group.hpp index ef9f1121..76bb939b 100644 --- a/options/group.hpp +++ b/options/group.hpp @@ -4,21 +4,16 @@  #include "compat/base-path.hpp"  #include "compat/library-path.hpp" -#include "compat/qhash.hpp"  #include "compat/macros.hpp" +#include "compat/qhash.hpp"  #include "export.hpp"  #include <optional>  #include <unordered_map> -#include <QHash>  #include <QString> -#include <QMutex> -#include <QFile> -#include <QDir> -#include <QStandardPaths>  #include <QVariant> -#include <QSettings> +  #include <QDebug>  // XXX TODO remove qsettings usage -sh 20180624 @@ -36,12 +31,6 @@ namespace options::detail {          void put(const QString& s, const QVariant& d);          bool contains(const QString& s) const; -        template<typename t> -        cc_noinline t get(const QString& k) const -        { -            return get_variant(k).value<t>(); -        } -          cc_noinline QVariant get_variant(const QString& name) const;      };  } // ns options::detail diff --git a/options/metatype.cpp b/options/metatype.cpp index b6df94ca..44f30187 100644 --- a/options/metatype.cpp +++ b/options/metatype.cpp @@ -22,7 +22,7 @@ int declare_metatype_for_type(const char* str)  #define OPENTRACK_DEFINE_METATYPE4(t, sym)                                                          \      class sym {                                                                                     \          static const int dribble;                                                                   \ -    } sym ## _singleton;                                                                            \ +    } sym;                                                                                          \      const int sym :: dribble = ::options::detail::declare_metatype_for_type<t>(#t);  #define OPENTRACK_DEFINE_METATYPE(t) OPENTRACK_DEFINE_METATYPE2(t, __COUNTER__) diff --git a/options/tie.cpp b/options/tie.cpp index 1f2d7dae..671a72c2 100644 --- a/options/tie.cpp +++ b/options/tie.cpp @@ -8,6 +8,11 @@  #include "tie.hpp"  #include "compat/run-in-thread.hpp" +#include "compat/macros.hpp" + +#include "value-traits.hpp" + +#include <cmath>  namespace options { @@ -141,9 +146,9 @@ void tie_setting(value<slider_value>& v, QSlider* w)          {              const int q_min = w->minimum();              const int q_max = w->maximum(); -            const int pos = v().to_slider_pos(q_min, q_max); +            const int pos = v->to_slider_pos(q_min, q_max); +            v = v->update_from_slider(pos, q_min, q_max);              w->setValue(pos); -            v = v().update_from_slider(w->value(), q_min, q_max);          });      },      v.DIRECT_CONNTYPE); diff --git a/options/tie.hpp b/options/tie.hpp index f2ec751d..c2607a6c 100644 --- a/options/tie.hpp +++ b/options/tie.hpp @@ -36,20 +36,17 @@ std::enable_if_t<std::is_enum_v<t>> tie_setting(value<t>& v, QComboBox* cb)      cb->setCurrentIndex(cb->findData(int(static_cast<t>(v))));      v = static_cast<t>(cb->currentData().toInt()); -    value_::connect(cb, -                        static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), -                        &v, [&v, cb](int idx) { -        run_in_thread_sync(cb, [&] { -            v = static_cast<t>(cb->itemData(idx).toInt()); -        }); -    }, -    v.DIRECT_CONNTYPE); +    value_::connect(cb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), +                    &v, [&v, cb](int idx) { +                        run_in_thread_sync(cb, [&] { +                            v = static_cast<t>(cb->itemData(idx).toInt()); +                        }); +                    }, v.DIRECT_CONNTYPE);      value_::connect(&v, value_::value_changed<int>(), -                        cb, [cb](int x) { +                    cb, [cb](int x) {                              run_in_thread_sync(cb, [=] { cb->setCurrentIndex(cb->findData(x)); }); -                        }, -                        v.DIRECT_CONNTYPE); +                    }, v.DIRECT_CONNTYPE);  }  template<typename t, typename From, typename To> @@ -79,8 +76,8 @@ void tie_setting(value<t>& v, QLabel* lb, F&& fun)      closure(v());      value_::connect(&v, value_::value_changed<t>(), -                        lb, closure, -                        v.SAFE_CONNTYPE); +                    lb, closure, +                    v.SAFE_CONNTYPE);  }  template<typename t, typename F> @@ -92,8 +89,8 @@ void tie_setting(value<t>& v, QObject* obj, F&& fun)      fun(v());      value_::connect(&v, value_::value_changed<t>(), -                        obj, fun, -                        v.DIRECT_CONNTYPE); +                    obj, fun, +                    v.DIRECT_CONNTYPE);  }  OTR_OPTIONS_EXPORT void tie_setting(value<int>& v, QComboBox* cb); diff --git a/options/value-traits.hpp b/options/value-traits.hpp index 1c98f3e9..3ab623da 100644 --- a/options/value-traits.hpp +++ b/options/value-traits.hpp @@ -1,62 +1,145 @@  #pragma once -#include "export.hpp" -  #include "slider.hpp" +#include "export.hpp"  #include <QString> +#include <cinttypes>  #include <type_traits>  namespace options::detail { +template<typename t, typename Enable = void> +struct value_traits; +  template<typename t, typename u = t, typename Enable = void>  struct default_value_traits  { -    virtual ~default_value_traits() = default; +    using stored_type = std::decay_t<u>; +    using value_type = std::decay_t<t>; -    using stored_type = std::decay_t<t>; -    using value_type = std::decay_t<u>; +    using self = value_traits<t>; -    static value_type from_value(const value_type& val, const value_type&) { return val; } -    static value_type from_storage(const stored_type& x) { return static_cast<value_type>(x); } -    static stored_type to_storage(const value_type& val) { return static_cast<stored_type>(val); } +    static value_type value_with_default(const value_type& val, const value_type&) +    { +        return val; +    } -    static value_type value_from_variant(const QVariant& x) +    static value_type value_from_storage(const stored_type& x)      { -        return from_storage(storage_from_variant(x)); +        return static_cast<value_type>(x);      } -    static stored_type storage_from_variant(const QVariant& x) +    static stored_type storage_from_value(const value_type& val)      { +        return static_cast<stored_type>(val); +    } + +    static value_type value_from_qvariant(const QVariant& x) +    { +        return self::value_from_storage(self::storage_from_qvariant(x)); +    } + +    static QVariant qvariant_from_value(const value_type& val) +    { +        return self::qvariant_from_storage(self::storage_from_value(val)); +    } + +    static constexpr inline +    value_type pass_value(const value_type& x) +    { +        if constexpr(std::is_same_v<value_type, stored_type>) +            return x; +        else +            return self::value_from_storage(self::storage_from_value(x)); +    } + +    static stored_type storage_from_qvariant(const QVariant& x) +    { +        // XXX TODO          return x.value<stored_type>();      } + +    static QVariant qvariant_from_storage(const stored_type& val) +    { +        // XXX TODO +        return QVariant::fromValue<stored_type>(val); +    } + +    static bool is_equal(const value_type& x, const value_type& y) +    { +        return x == y; +    }  }; -template<typename t, typename u = t, typename Enable = void> -struct value_traits : default_value_traits<t, u, Enable> +template<typename t, typename Enable> +struct value_traits : default_value_traits<t> {}; + +template<> +struct value_traits<double> : default_value_traits<double>  { +    static bool is_equal(value_type x, value_type y) +    { +        if (x == y) +            return true; +        else +        { +            using I = std::int64_t; +            constexpr int K = 1000; + +            value_type x_, y_; + +            return I(std::round(std::modf(x, &x_) * K)) == I(std::round(std::modf(y, &y_) * K)) && +                   I(std::round(x_)) == I(std::round(y_)); +        } +    }  }; -template<> -struct value_traits<slider_value> : default_value_traits<slider_value> +template<> struct value_traits<bool> : default_value_traits<bool, int>  { -    static inline slider_value from_value(const slider_value& val, const slider_value& def) +    static stored_type storage_from_qvariant(const QVariant& x)      { -        return { val.cur(), def.min(), def.max() }; +        if (x.type() == QVariant::String) +            return x.toBool(); +        else +            return !!x.toInt(); +    } + +    static QVariant qvariant_from_storage(const stored_type& val) +    { +        return QVariant::fromValue<int>(!!val); +    } + +    static value_type value_from_storage(const stored_type& x) +    { +        return !!x;      }  }; -// Qt uses int a lot in slots so use it for all enums -template<typename t> -struct value_traits<t, t, std::enable_if_t<std::is_enum_v<t>>> : public default_value_traits<int, t> +template<> struct value_traits<float> : value_traits<float, double>  { +    static constexpr inline value_type pass_value(const value_type& x) { return x; }  };  template<> -struct value_traits<float> : public default_value_traits<float, double, void> +struct value_traits<slider_value> : default_value_traits<slider_value>  { +    static slider_value value_with_default(const slider_value& val, const slider_value& def) +    { +        return { val.cur(), def.min(), def.max() }; +    } + +    static bool is_equal(const slider_value& x, const slider_value& y) +    { +        using tr = value_traits<double>; +        return tr::is_equal(x.cur(), y.cur()); +    }  }; +// Qt uses int a lot in slots so use it for all enums +template<typename t> +struct value_traits<t, std::enable_if_t<std::is_enum_v<t>>> : default_value_traits<t, int> {}; +  } // ns options::detail diff --git a/options/value.hpp b/options/value.hpp index bfa8b352..887f0d39 100644 --- a/options/value.hpp +++ b/options/value.hpp @@ -23,51 +23,47 @@  namespace options::detail {      template<typename t> -    struct dereference_wrapper final +    class dereference_wrapper final      { -        cc_forceinline constexpr t const* operator->() const { return &x; } -        cc_forceinline constexpr t* operator->() { return &x; }          t x; -        constexpr explicit cc_forceinline dereference_wrapper(t&& x) : x(x) {} +    public: +        constexpr t const* operator->() const { return &x; } +        constexpr t* operator->() { return &x; } +        constexpr explicit dereference_wrapper(t&& x) : x(x) {}      };  } // ns options::detail  namespace options { -template<typename t> +template<typename u>  class value final : public value_  { +    using t = std::conditional_t<std::is_enum_v<remove_cvref_t<u>>, +                                 std::decay_t<u>, +                                 remove_cvref_t<u>>;      const t def;      using traits = detail::value_traits<t>; -    using stored_type = typename traits::stored_type; - -    static bool is_equal(const QVariant& val1, const QVariant& val2) -    { -        return val1.value<stored_type>() == val2.value<stored_type>(); -    }      cc_noinline      t get() const      { -        if (self_name.isEmpty()) -            return def; +        if (self_name.isEmpty() || !b->contains(self_name)) +            return traits::pass_value(def); -        QVariant variant = b->get<QVariant>(self_name); +        QVariant variant = b->get_variant(self_name); -        if (!b->contains(self_name) || variant.type() == QVariant::Invalid) -            return def; +        if (variant.isNull() || !variant.isValid()) +            return traits::pass_value(def); -        const stored_type x { variant.value<stored_type>() }; - -        return traits::from_value(traits::from_storage(x), def); +        return traits::pass_value(traits::value_with_default(traits::value_from_qvariant(variant), def));      }      friend class detail::connector;      void bundle_value_changed() const override      {          if (!self_name.isEmpty()) -            emit valueChanged(traits::to_storage(get())); +            emit valueChanged(traits::storage_from_value(get()));      }      void store_variant(const QVariant& value) override @@ -75,21 +71,20 @@ class value final : public value_          if (self_name.isEmpty())              return; -        if (value.type() == qMetaTypeId<stored_type>()) +        if (traits::is_equal(get(), traits::value_from_qvariant(value))) +            return; + +        if (value.isValid() && !value.isNull())              b->store_kv(self_name, value);          else -            operator=(traits::value_from_variant(value)); +            b->store_kv(self_name, traits::qvariant_from_value(def));      }  public:      cc_noinline -    value<t>& operator=(const t& datum) +    value<u>& operator=(const t& datum)      { -        if (self_name.isEmpty()) -            return *this; - -        if (datum != get()) -            b->store_kv(self_name, QVariant::fromValue<stored_type>(traits::to_storage(datum))); +        store_variant(traits::qvariant_from_value(traits::pass_value(datum)));          return *this;      } @@ -99,13 +94,8 @@ public:      cc_noinline      value(bundle b, const QString& name, t def) : -        value_(b, name, &is_equal, std::type_index(typeid(stored_type))), -        def(def) +        value_(b, name), def(def)      { -        if (!self_name.isEmpty()) -            QObject::connect(b.get(), &detail::bundle::reloading, -                             this, &value_::reload, -                             DIRECT_CONNTYPE);      }      cc_noinline @@ -120,7 +110,7 @@ public:          *this = def;      } -    operator t() const { return get(); } // NOLINT +    operator t() const { return get(); }      template<typename u, typename = decltype(static_cast<u>(std::declval<t>()))>      explicit cc_forceinline operator u() const { return to<u>(); } @@ -130,22 +120,13 @@ public:          return detail::dereference_wrapper<t>{get()};      } -    cc_noinline -    void reload() override -    { -#if 0 -        if (!self_name.isEmpty()) -            store(traits::to_storage(get())); -#endif -    } -      cc_forceinline t operator()() const { return get(); }      cc_forceinline t operator*() const { return get(); } -    template<typename u> -    u to() const +    template<typename w> +    w to() const      { -        return static_cast<u>(get()); +        return static_cast<w>(get());      }  }; diff --git a/spline/spline.cpp b/spline/spline.cpp index 2fb811d6..ae32b896 100644 --- a/spline/spline.cpp +++ b/spline/spline.cpp @@ -41,11 +41,9 @@ spline::~spline()          QObject::disconnect(conn_changed);          QObject::disconnect(conn_maxx);          QObject::disconnect(conn_maxy); -        QObject::disconnect(conn_reload); -        conn_changed = QMetaObject::Connection(); -        conn_maxx = QMetaObject::Connection(); -        conn_maxy = QMetaObject::Connection(); -        conn_reload = QMetaObject::Connection(); +        conn_changed = {}; +        conn_maxx = {}; +        conn_maxy = {};      }  } @@ -351,9 +349,6 @@ void spline::set_bundle(bundle b, const QString& axis_name, Axis axis)              conn_changed = QObject::connect(b.get(), &bundle_::changed,                                              s.get(), [&] { invalidate_settings(); }); -            conn_reload = QObject::connect(b.get(), &bundle_::reloading, -                                           s.get(), [&] { invalidate_settings(); }); -              // this isn't strictly necessary for the spline but helps the widget              conn_maxx = QObject::connect(&s->opts.clamp_x_, value_::value_changed<int>(),                                           ctx.get(), [&](double) { invalidate_settings(); }); diff --git a/spline/spline.hpp b/spline/spline.hpp index fe2852f2..faecbb2c 100644 --- a/spline/spline.hpp +++ b/spline/spline.hpp @@ -105,7 +105,7 @@ class OTR_SPLINE_EXPORT spline : public base_spline      static int element_count(const QList<QPointF>& points, double max_input);      std::shared_ptr<spline_detail::settings> s; -    QMetaObject::Connection conn_changed, conn_maxx, conn_maxy, conn_reload; +    QMetaObject::Connection conn_changed, conn_maxx, conn_maxy;      static constexpr inline std::size_t value_count = 4096; | 
