Merge branch 'main' into feat/reposition-bar
C++ / fmt (pull_request) Successful in 4s
JS/TS / lint (pull_request) Successful in 16s
JS/TS / fmt (pull_request) Successful in 23s
Python / fmt (pull_request) Successful in 33s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 1m0s
Python / typecheck (pull_request) Failing after 1m8s
Rust / fmt (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 1m46s
C++ / build (pull_request) Successful in 2m33s
Rust / clippy (pull_request) Successful in 1m30s
Python / buildcheck (pull_request) Successful in 2m41s
C++ / clang-tidy (pull_request) Successful in 7m9s
C++ / fmt (pull_request) Successful in 4s
JS/TS / lint (pull_request) Successful in 16s
JS/TS / fmt (pull_request) Successful in 23s
Python / fmt (pull_request) Successful in 33s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 1m0s
Python / typecheck (pull_request) Failing after 1m8s
Rust / fmt (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 1m46s
C++ / build (pull_request) Successful in 2m33s
Rust / clippy (pull_request) Successful in 1m30s
Python / buildcheck (pull_request) Successful in 2m41s
C++ / clang-tidy (pull_request) Successful in 7m9s
This commit is contained in:
@@ -78,3 +78,4 @@ add_subdirectory(Internal)
|
||||
add_subdirectory(Services)
|
||||
add_subdirectory(Components)
|
||||
add_subdirectory(Blobs)
|
||||
add_subdirectory(Config)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
qml_module(ZShell-config
|
||||
URI ZShell.Config
|
||||
SOURCES
|
||||
confignode.hpp confignode.cpp
|
||||
configobject.hpp configobject.cpp
|
||||
configlist.hpp configlist.cpp
|
||||
config.hpp config.cpp
|
||||
tokens.hpp
|
||||
appearance.hpp
|
||||
background.hpp
|
||||
bar.hpp
|
||||
clipboard.hpp
|
||||
colors.hpp
|
||||
dashboard.hpp
|
||||
dock.hpp
|
||||
general.hpp
|
||||
launcher.hpp
|
||||
lock.hpp
|
||||
notifs.hpp
|
||||
osd.hpp
|
||||
screenshot.hpp
|
||||
services.hpp
|
||||
sidebar.hpp
|
||||
utilities.hpp
|
||||
)
|
||||
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlregistration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class Anim : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, mediaGifSpeedAdjustment, 300)
|
||||
CFG_PROPERTY(qreal, sessionGifSpeed, 0.7)
|
||||
|
||||
public:
|
||||
explicit Anim(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Deform : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(qreal, scale, 1)
|
||||
|
||||
public:
|
||||
explicit Deform(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class FontFamily : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QString, clock, QStringLiteral("Rubik"))
|
||||
CFG_PROPERTY(QString, material, QStringLiteral("Material Symbols Rounded"))
|
||||
CFG_PROPERTY(QString, mono, QStringLiteral("CaskaydiaCove NF"))
|
||||
CFG_PROPERTY(QString, sans, QStringLiteral("Segoe UI Variable Text"))
|
||||
|
||||
public:
|
||||
explicit FontFamily(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Font : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CONFIG_SUBOBJECT(FontFamily, family)
|
||||
|
||||
public:
|
||||
explicit Font(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_family(new FontFamily(this)) {}
|
||||
};
|
||||
|
||||
class Transparency : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(qreal, base, 0.85)
|
||||
CFG_PROPERTY(bool, enabled, false)
|
||||
CFG_PROPERTY(qreal, layers, 0.4)
|
||||
|
||||
public:
|
||||
explicit Transparency(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Appearance : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CONFIG_SUBOBJECT(Anim, anim)
|
||||
CONFIG_SUBOBJECT(Deform, deform)
|
||||
CONFIG_SUBOBJECT(Font, font)
|
||||
CONFIG_SUBOBJECT(Transparency, transparency)
|
||||
|
||||
public:
|
||||
explicit Appearance(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_anim(new Anim(this))
|
||||
, m_deform(new Deform(this))
|
||||
, m_font(new Font(this))
|
||||
, m_transparency(new Transparency(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class Background : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(int, wallFadeDuration, 300)
|
||||
|
||||
public:
|
||||
explicit Background(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include "configlist.hpp"
|
||||
#include "configobject.hpp"
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qqmlregistration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class BarEntry : public ListEntry {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
public:
|
||||
explicit BarEntry(QObject* parent = nullptr) : ListEntry(parent) {}
|
||||
};
|
||||
|
||||
class Popouts : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, statusIcons, true)
|
||||
CFG_PROPERTY(bool, tray, true)
|
||||
|
||||
public:
|
||||
explicit Popouts(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Tray : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, recolorIcons, false)
|
||||
CFG_PROPERTY(bool, showOnHover, true)
|
||||
CFG_PROPERTY(int, trayIconSize, 24)
|
||||
CONFIG_LIST(
|
||||
EntryList,
|
||||
statusIcons,
|
||||
{
|
||||
LIST_ENTRY(audio, true),
|
||||
LIST_ENTRY(microphone, true),
|
||||
LIST_ENTRY(bluetooth, false),
|
||||
LIST_ENTRY(network, false),
|
||||
LIST_ENTRY(wifi, false),
|
||||
LIST_ENTRY(power, true),
|
||||
})
|
||||
|
||||
public:
|
||||
explicit Tray(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Bar : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, autoHide, false)
|
||||
CFG_PROPERTY(int, border, 4)
|
||||
CFG_PROPERTY(bool, fullscreenReveal, true)
|
||||
CFG_PROPERTY(int, height, 24)
|
||||
CFG_PROPERTY(bool, hideWhenNotif, true)
|
||||
CONFIG_SUBOBJECT(Popouts, popouts)
|
||||
CFG_PROPERTY(int, revealDelay, 100)
|
||||
CFG_PROPERTY(int, rounding, 14)
|
||||
CFG_PROPERTY(int, smoothing, 32)
|
||||
CFG_PROPERTY(QString, position, "top")
|
||||
CONFIG_SUBOBJECT(Tray, tray)
|
||||
CONFIG_LIST(
|
||||
EntryList,
|
||||
entries,
|
||||
{
|
||||
LIST_ENTRY(workspaces, true),
|
||||
LIST_ENTRY(audio, true),
|
||||
LIST_ENTRY(media, true),
|
||||
LIST_ENTRY(resources, true),
|
||||
LIST_ENTRY(updates, true),
|
||||
LIST_ENTRY(dash, false),
|
||||
LIST_ENTRY(spacer, true),
|
||||
LIST_ENTRY(activeWindow, true),
|
||||
LIST_ENTRY(spacer, true),
|
||||
LIST_ENTRY(hyprsunset, true),
|
||||
LIST_ENTRY(tray, true),
|
||||
LIST_ENTRY(statusIcons, true),
|
||||
LIST_ENTRY(network, false),
|
||||
LIST_ENTRY(upower, true),
|
||||
LIST_ENTRY(clock, true),
|
||||
LIST_ENTRY(notifBell, true),
|
||||
})
|
||||
|
||||
public:
|
||||
explicit Bar(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_popouts(new Popouts(this))
|
||||
, m_tray(new Tray(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class ClipboardSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, itemHeight, 60)
|
||||
CFG_PROPERTY(int, minPreviewWidth, 200)
|
||||
CFG_PROPERTY(int, previewWidth, 800)
|
||||
CFG_PROPERTY(int, width, 500)
|
||||
|
||||
public:
|
||||
explicit ClipboardSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Clipboard : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(int, maxEntriesShown, 10)
|
||||
CONFIG_SUBOBJECT(ClipboardSizes, sizes)
|
||||
|
||||
public:
|
||||
explicit Clipboard(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_sizes(new ClipboardSizes(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class Presets : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QString, accent, QString())
|
||||
CFG_PROPERTY(QString, name, QStringLiteral("Catppuccin"))
|
||||
CFG_PROPERTY(QString, variant, QStringLiteral("latte"))
|
||||
|
||||
public:
|
||||
explicit Presets(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Colors : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CONFIG_SUBOBJECT(Presets, presets)
|
||||
CFG_PROPERTY(QString, schemeType, QStringLiteral("fidelity"))
|
||||
|
||||
public:
|
||||
explicit Colors(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_presets(new Presets(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,257 @@
|
||||
#include "config.hpp"
|
||||
|
||||
#include "appearance.hpp"
|
||||
#include "background.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "clipboard.hpp"
|
||||
#include "colors.hpp"
|
||||
#include "dashboard.hpp"
|
||||
#include "dock.hpp"
|
||||
#include "general.hpp"
|
||||
#include "launcher.hpp"
|
||||
#include "lock.hpp"
|
||||
#include "notifs.hpp"
|
||||
#include "osd.hpp"
|
||||
#include "screenshot.hpp"
|
||||
#include "services.hpp"
|
||||
#include "sidebar.hpp"
|
||||
#include "utilities.hpp"
|
||||
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QJsonDocument>
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QFutureWatcher>
|
||||
#include <QFileInfo>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qfileinfo.h>
|
||||
#include <qfilesystemwatcher.h>
|
||||
#include <qthreadpool.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
Config::Config(QObject* parent)
|
||||
: ConfigObject(parent)
|
||||
, m_appearance(new Appearance(this))
|
||||
, m_background(new Background(this))
|
||||
, m_bar(new Bar(this))
|
||||
, m_clipboard(new Clipboard(this))
|
||||
, m_colors(new Colors(this))
|
||||
, m_dashboard(new Dashboard(this))
|
||||
, m_dock(new Dock(this))
|
||||
, m_general(new General(this))
|
||||
, m_launcher(new Launcher(this))
|
||||
, m_lock(new Lock(this))
|
||||
, m_notifs(new Notifs(this))
|
||||
, m_osd(new Osd(this))
|
||||
, m_screenshot(new Screenshot(this))
|
||||
, m_services(new Services(this))
|
||||
, m_sidebar(new Sidebar(this))
|
||||
, m_utilities(new Utilities(this)) {
|
||||
connect(this, &ConfigObject::propertiesChanged, this, &Config::scheduleSave);
|
||||
|
||||
m_saveTimer.setSingleShot(true);
|
||||
m_saveTimer.setInterval(300);
|
||||
connect(&m_saveTimer, &QTimer::timeout, this, &Config::flushAsync);
|
||||
|
||||
m_reloadTimer.setSingleShot(true);
|
||||
m_reloadTimer.setInterval(50);
|
||||
connect(&m_reloadTimer, &QTimer::timeout, this, &Config::reloadAsync);
|
||||
|
||||
connect(
|
||||
&m_watcher,
|
||||
&QFileSystemWatcher::directoryChanged,
|
||||
this,
|
||||
&Config::onWatcherEvent);
|
||||
|
||||
connect(
|
||||
&m_watcher,
|
||||
&QFileSystemWatcher::fileChanged,
|
||||
this,
|
||||
&Config::onWatcherEvent);
|
||||
|
||||
loadSync();
|
||||
updateWatch();
|
||||
|
||||
m_firstLoadDone = true;
|
||||
}
|
||||
|
||||
Config* Config::create(QQmlEngine*, QJSEngine*) {
|
||||
return new Config();
|
||||
}
|
||||
|
||||
QString Config::filePath() const {
|
||||
const QString dir =
|
||||
QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
|
||||
QStringLiteral("/zshell");
|
||||
QDir().mkpath(dir);
|
||||
return dir + QStringLiteral("/config.json");
|
||||
}
|
||||
|
||||
void Config::loadSync() {
|
||||
m_loading = true;
|
||||
QFile f(filePath());
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
const auto doc = QJsonDocument::fromJson(f.readAll());
|
||||
if (doc.isObject()) loadFromJson(QJsonValue(doc.object()));
|
||||
} else {
|
||||
qInfo() << "Config: no existing config at" << filePath()
|
||||
<< "- using defaults";
|
||||
}
|
||||
m_loading = false;
|
||||
}
|
||||
|
||||
void Config::updateWatch() {
|
||||
const QFileInfo info(filePath());
|
||||
|
||||
const QString dir = info.absolutePath();
|
||||
const QString file = info.absoluteFilePath();
|
||||
|
||||
if (!m_watcher.directories().contains(dir)) m_watcher.addPath(dir);
|
||||
if (info.exists() && !m_watcher.files().contains(file))
|
||||
m_watcher.addPath(file);
|
||||
}
|
||||
|
||||
void Config::onWatcherEvent(const QString&) {
|
||||
updateWatch();
|
||||
|
||||
const QFileInfo info(filePath());
|
||||
if (!info.exists()) return;
|
||||
|
||||
QFile file(info.absoluteFilePath());
|
||||
if (!file.open(QIODevice::ReadOnly)) return;
|
||||
|
||||
const QByteArray hash =
|
||||
QCryptographicHash::hash(file.readAll(), QCryptographicHash::Sha256);
|
||||
|
||||
{
|
||||
QMutexLocker lock(&m_writeMutex);
|
||||
|
||||
if (hash == m_lastWriteHash) return;
|
||||
}
|
||||
|
||||
m_reloadPending = true;
|
||||
|
||||
if (!m_loading) m_reloadTimer.start();
|
||||
}
|
||||
|
||||
void Config::loadAsync() {
|
||||
m_loading = true;
|
||||
|
||||
auto future = QtConcurrent::run([this]() {
|
||||
QFile f(filePath());
|
||||
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
const auto doc = QJsonDocument::fromJson(f.readAll());
|
||||
|
||||
if (doc.isObject()) {
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this, doc]() {
|
||||
loadFromJson(QJsonValue(doc.object()));
|
||||
m_loading = false;
|
||||
|
||||
if (m_reloadPending) m_reloadTimer.start();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this]() {
|
||||
m_loading = false;
|
||||
|
||||
if (m_reloadPending) m_reloadTimer.start();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
} else {
|
||||
qInfo() << "Config: failed to reload from" << filePath()
|
||||
<< "- using in-memory values";
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this]() {
|
||||
m_loading = false;
|
||||
|
||||
if (m_reloadPending) m_reloadTimer.start();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
});
|
||||
|
||||
m_loadFuture = future;
|
||||
}
|
||||
|
||||
void Config::load() {
|
||||
if (!m_firstLoadDone) {
|
||||
loadSync();
|
||||
} else {
|
||||
loadAsync();
|
||||
}
|
||||
}
|
||||
|
||||
void Config::reloadAsync() {
|
||||
if (m_loading) return;
|
||||
|
||||
m_reloadPending = false;
|
||||
loadAsync();
|
||||
}
|
||||
|
||||
void Config::scheduleSave() {
|
||||
if (m_loading) return;
|
||||
m_saveTimer.start();
|
||||
}
|
||||
|
||||
void Config::flushAsync() {
|
||||
const QByteArray data =
|
||||
QJsonDocument(toJson().toObject()).toJson(QJsonDocument::Indented);
|
||||
|
||||
const QByteArray hash =
|
||||
QCryptographicHash::hash(data, QCryptographicHash::Sha256);
|
||||
|
||||
QThreadPool::globalInstance()->start([this, data, hash]() {
|
||||
const bool success = writeAtomically(data);
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this, success, hash]() {
|
||||
if (!success) return;
|
||||
|
||||
QMutexLocker lock(&m_writeMutex);
|
||||
m_lastWriteHash = hash;
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
|
||||
void Config::saveNow() {
|
||||
m_saveTimer.stop();
|
||||
flushAsync();
|
||||
}
|
||||
|
||||
bool Config::writeAtomically(const QByteArray& data) {
|
||||
QSaveFile f(filePath());
|
||||
|
||||
if (!f.open(QIODevice::WriteOnly)) {
|
||||
qWarning() << "Config: failed to open for atomic write:"
|
||||
<< f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.write(data) != data.size()) {
|
||||
qWarning() << "Config: failed to write:" << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!f.commit()) {
|
||||
qWarning() << "Config: commit failed:" << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace ZShell::config
|
||||
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "configobject.hpp"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QFuture>
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
#include <qqmlregistration.h>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
class QQmlEngine;
|
||||
class QJSEngine;
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class Appearance;
|
||||
class Background;
|
||||
class Bar;
|
||||
class Clipboard;
|
||||
class Colors;
|
||||
class Dashboard;
|
||||
class Dock;
|
||||
class General;
|
||||
class Launcher;
|
||||
class Lock;
|
||||
class Notifs;
|
||||
class Osd;
|
||||
class Screenshot;
|
||||
class Services;
|
||||
class Sidebar;
|
||||
class Utilities;
|
||||
|
||||
class Config : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
Q_MOC_INCLUDE("appearance.hpp")
|
||||
Q_MOC_INCLUDE("background.hpp")
|
||||
Q_MOC_INCLUDE("bar.hpp")
|
||||
Q_MOC_INCLUDE("clipboard.hpp")
|
||||
Q_MOC_INCLUDE("colors.hpp")
|
||||
Q_MOC_INCLUDE("dashboard.hpp")
|
||||
Q_MOC_INCLUDE("dock.hpp")
|
||||
Q_MOC_INCLUDE("general.hpp")
|
||||
Q_MOC_INCLUDE("launcher.hpp")
|
||||
Q_MOC_INCLUDE("lock.hpp")
|
||||
Q_MOC_INCLUDE("notifs.hpp")
|
||||
Q_MOC_INCLUDE("osd.hpp")
|
||||
Q_MOC_INCLUDE("screenshot.hpp")
|
||||
Q_MOC_INCLUDE("services.hpp")
|
||||
Q_MOC_INCLUDE("sidebar.hpp")
|
||||
Q_MOC_INCLUDE("utilities.hpp")
|
||||
|
||||
CONFIG_SUBOBJECT(Appearance, appearance)
|
||||
CONFIG_SUBOBJECT(Background, background)
|
||||
CONFIG_SUBOBJECT(Bar, bar)
|
||||
CONFIG_SUBOBJECT(Clipboard, clipboard)
|
||||
CONFIG_SUBOBJECT(Colors, colors)
|
||||
CONFIG_SUBOBJECT(Dashboard, dashboard)
|
||||
CONFIG_SUBOBJECT(Dock, dock)
|
||||
CONFIG_SUBOBJECT(General, general)
|
||||
CONFIG_SUBOBJECT(Launcher, launcher)
|
||||
CONFIG_SUBOBJECT(Lock, lock)
|
||||
CONFIG_SUBOBJECT(Notifs, notifs)
|
||||
CONFIG_SUBOBJECT(Osd, osd)
|
||||
CONFIG_SUBOBJECT(Screenshot, screenshot)
|
||||
CONFIG_SUBOBJECT(Services, services)
|
||||
CONFIG_SUBOBJECT(Sidebar, sidebar)
|
||||
CONFIG_SUBOBJECT(Utilities, utilities)
|
||||
|
||||
public:
|
||||
explicit Config(QObject* parent = nullptr);
|
||||
static Config* create(QQmlEngine*, QJSEngine*);
|
||||
|
||||
Q_INVOKABLE void load();
|
||||
Q_INVOKABLE void saveNow();
|
||||
Q_INVOKABLE void reloadAsync();
|
||||
|
||||
private Q_SLOTS:
|
||||
void scheduleSave();
|
||||
void flushAsync();
|
||||
void onWatcherEvent(const QString& path);
|
||||
|
||||
private:
|
||||
QString filePath() const;
|
||||
bool writeAtomically(const QByteArray& data);
|
||||
void updateWatch();
|
||||
void loadSync();
|
||||
void loadAsync();
|
||||
|
||||
QTimer m_saveTimer;
|
||||
QTimer m_reloadTimer;
|
||||
QFileSystemWatcher m_watcher;
|
||||
|
||||
QMutex m_writeMutex;
|
||||
QByteArray m_lastWriteHash;
|
||||
|
||||
bool m_reloadPending = false;
|
||||
bool m_loading = false;
|
||||
bool m_firstLoadDone = false;
|
||||
QFuture<void> m_loadFuture;
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,305 @@
|
||||
#include "configlist.hpp"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QMetaObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QString>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
ConfigList::ConfigList(QObject* parent, const QVariantList& defaults)
|
||||
: ConfigNode(parent), m_defaults(QJsonArray::fromVariantList(defaults)) {}
|
||||
|
||||
int ConfigList::count() const {
|
||||
return static_cast<int>(m_items.size());
|
||||
}
|
||||
|
||||
QVariantList ConfigList::values() const {
|
||||
QVariantList vals;
|
||||
vals.reserve(m_items.size());
|
||||
for (auto* const item : m_items)
|
||||
vals.append(QVariant::fromValue(item));
|
||||
return vals;
|
||||
}
|
||||
|
||||
ConfigObject* ConfigList::itemAt(int index) const {
|
||||
if (index < 0 || index >= m_items.size()) return nullptr;
|
||||
|
||||
return m_items.at(index);
|
||||
}
|
||||
|
||||
const QList<ConfigObject*>& ConfigList::items() const {
|
||||
return m_items;
|
||||
}
|
||||
|
||||
void ConfigList::remove(int index) {
|
||||
if (index < 0 || index >= m_items.size()) {
|
||||
qCWarning(lcConfig)
|
||||
<< metaObject()->className() << "cannot remove index" << index
|
||||
<< "of" << count();
|
||||
return;
|
||||
}
|
||||
|
||||
destroyItem(m_items.takeAt(index));
|
||||
|
||||
m_loaded = true;
|
||||
emit countChanged();
|
||||
emit valuesChanged();
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
void ConfigList::move(int from, int to) {
|
||||
if (from < 0 || from >= m_items.size() || to < 0 || to >= m_items.size()) {
|
||||
qCWarning(lcConfig) << metaObject()->className() << "cannot move"
|
||||
<< from << "to" << to << "of" << count();
|
||||
return;
|
||||
}
|
||||
|
||||
if (from == to) return;
|
||||
|
||||
m_items.move(from, to);
|
||||
|
||||
m_loaded = true;
|
||||
emit valuesChanged();
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
void ConfigList::clear() {
|
||||
if (m_items.isEmpty()) return;
|
||||
|
||||
destroyItems();
|
||||
|
||||
m_loaded = true;
|
||||
emit countChanged();
|
||||
emit valuesChanged();
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
void ConfigList::loadFromJson(const QJsonValue& json) {
|
||||
if (!json.isArray()) {
|
||||
qCWarning(
|
||||
lcConfig,
|
||||
"Option '%s' must be a list, ignoring",
|
||||
qUtf8Printable(propertyPath()));
|
||||
m_rejectedJson = json;
|
||||
return;
|
||||
}
|
||||
|
||||
m_rejectedJson = QJsonValue::Undefined;
|
||||
populate(json.toArray());
|
||||
m_loaded = true;
|
||||
}
|
||||
|
||||
QJsonValue ConfigList::toJson() const {
|
||||
if (m_loaded) return elementsToJson();
|
||||
|
||||
return m_rejectedJson;
|
||||
}
|
||||
|
||||
void ConfigList::clearLoadedKeys() {
|
||||
m_loaded = false;
|
||||
m_rejectedJson = QJsonValue::Undefined;
|
||||
}
|
||||
|
||||
QStringList ConfigList::unknownKeys() const {
|
||||
QStringList keys;
|
||||
|
||||
for (int i = 0; i < m_items.size(); ++i) {
|
||||
const auto childKeys = m_items.at(i)->unknownKeys();
|
||||
for (const auto& childKey : childKeys)
|
||||
keys.append(joinPath(QString("[%1]").arg(i), childKey));
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
void ConfigList::resyncFromGlobal() {
|
||||
syncValuesFromGlobal();
|
||||
}
|
||||
|
||||
ConfigObject* ConfigList::insertItem(const QVariantMap& props, int index) {
|
||||
const auto pos = index < 0 || index > m_items.size() ? m_items.size()
|
||||
: index;
|
||||
|
||||
appendItem(QJsonObject::fromVariantMap(props));
|
||||
m_items.move(m_items.size() - 1, pos);
|
||||
|
||||
auto* const item = m_items.at(pos);
|
||||
const auto unknown = item->unknownKeys();
|
||||
for (const auto& key : unknown)
|
||||
qCWarning(lcConfig) << "Unknown option" << key << "for"
|
||||
<< item->metaObject()->className();
|
||||
|
||||
m_loaded = true;
|
||||
emit countChanged();
|
||||
emit valuesChanged();
|
||||
notifyChanged();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
QJsonArray ConfigList::elementsToJson() const {
|
||||
QJsonArray arr;
|
||||
|
||||
for (auto* const item : m_items)
|
||||
arr.append(item->toJson().toObject());
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
void ConfigList::resetToDefaults() {
|
||||
loadFromJsonQuietly(m_defaults);
|
||||
m_loaded = false;
|
||||
}
|
||||
|
||||
void ConfigList::syncValuesFromGlobal() {
|
||||
if (m_loaded) return;
|
||||
|
||||
if (auto* const global = qobject_cast<ConfigList*>(m_global))
|
||||
populate(global->elementsToJson());
|
||||
}
|
||||
|
||||
void ConfigList::onGlobalPropertiesChanged(const QMap<QString, QVariant>&) {
|
||||
syncValuesFromGlobal();
|
||||
}
|
||||
|
||||
QString ConfigList::childPath(const ConfigNode* child) const {
|
||||
for (int i = 0; i < m_items.size(); ++i)
|
||||
if (m_items.at(i) == child) return QString("[%1]").arg(i);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ConfigList::populate(const QJsonArray& arr) {
|
||||
const auto current = elementsToJson();
|
||||
if (current == arr) return;
|
||||
|
||||
const auto old = m_items;
|
||||
QList<bool> reused(old.size(), false);
|
||||
|
||||
m_items.clear();
|
||||
m_items.reserve(arr.size());
|
||||
|
||||
for (int i = 0; i < arr.size(); ++i) {
|
||||
auto match =
|
||||
i < old.size() && !reused.at(i) && current.at(i) == arr.at(i) ? i
|
||||
: -1;
|
||||
|
||||
for (int j = 0; match < 0 && j < old.size(); ++j)
|
||||
if (!reused.at(j) && current.at(j) == arr.at(i)) match = j;
|
||||
|
||||
auto update = false;
|
||||
for (int j = 0; match < 0 && j < old.size(); ++j) {
|
||||
if (!reused.at(j) &&
|
||||
sameElement(old.at(j), current.at(j), arr.at(i))) {
|
||||
match = j;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (match < 0) {
|
||||
appendItem(arr.at(i));
|
||||
continue;
|
||||
}
|
||||
|
||||
reused[match] = true;
|
||||
|
||||
if (update) old.at(match)->loadFromJsonQuietly(arr.at(i));
|
||||
|
||||
m_items.append(old.at(match));
|
||||
}
|
||||
|
||||
for (int i = 0; i < old.size(); ++i)
|
||||
if (!reused.at(i)) destroyItem(old.at(i));
|
||||
|
||||
if (m_items.size() != old.size()) emit countChanged();
|
||||
|
||||
emit valuesChanged();
|
||||
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
bool ConfigList::sameElement(
|
||||
const ConfigObject* item,
|
||||
const QJsonValue& current,
|
||||
const QJsonValue& json) {
|
||||
const auto keys = item->identityKeys();
|
||||
if (keys.isEmpty()) return false;
|
||||
|
||||
const auto currentObj = current.toObject();
|
||||
const auto newObj = json.toObject();
|
||||
|
||||
if (currentObj.keys() != newObj.keys()) return false;
|
||||
|
||||
for (const auto& key : keys)
|
||||
if (!newObj.contains(key) || currentObj.value(key) != newObj.value(key))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConfigList::appendItem(const QJsonValue& json) {
|
||||
auto* const item = createItem();
|
||||
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
|
||||
|
||||
if (m_items.isEmpty()) rejectGlobalOnlyElement(item);
|
||||
|
||||
item->loadFromJsonQuietly(json);
|
||||
|
||||
connectItem(item);
|
||||
|
||||
m_items.append(item);
|
||||
}
|
||||
|
||||
void ConfigList::rejectGlobalOnlyElement(const ConfigObject* item) const {
|
||||
const auto keys = item->globalOnlyKeys();
|
||||
if (keys.isEmpty()) return;
|
||||
|
||||
qCCritical(
|
||||
lcConfig,
|
||||
"%s declares global-only options (%s) which do not work inside a list, "
|
||||
"use CONFIG_GLOBAL_LIST on %s instead",
|
||||
item->metaObject()->className(),
|
||||
qUtf8Printable(keys.join(", ")),
|
||||
metaObject()->className());
|
||||
}
|
||||
|
||||
void ConfigList::connectItem(ConfigNode* node) {
|
||||
connect(
|
||||
node, &ConfigNode::propertiesChanged, this, &ConfigList::onItemChanged);
|
||||
|
||||
const auto children = node->childNodes();
|
||||
for (auto* const child : children)
|
||||
connectItem(child);
|
||||
}
|
||||
|
||||
void ConfigList::disconnectItem(ConfigNode* node) {
|
||||
node->disconnect(this);
|
||||
|
||||
const auto children = node->childNodes();
|
||||
for (auto* const child : children)
|
||||
disconnectItem(child);
|
||||
}
|
||||
|
||||
void ConfigList::destroyItems() {
|
||||
for (auto* const item : std::as_const(m_items))
|
||||
destroyItem(item);
|
||||
|
||||
m_items.clear();
|
||||
}
|
||||
|
||||
void ConfigList::destroyItem(ConfigObject* item) {
|
||||
disconnectItem(item);
|
||||
item->deleteLater();
|
||||
}
|
||||
|
||||
void ConfigList::onItemChanged() {
|
||||
m_loaded = true;
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
void ConfigList::notifyChanged() {
|
||||
notifyPropertyChanged("values", count());
|
||||
}
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include "configobject.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QVariantList>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class ConfigList : public ConfigNode {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(QVariantList values READ values NOTIFY valuesChanged)
|
||||
|
||||
public:
|
||||
explicit ConfigList(
|
||||
QObject* parent = nullptr, const QVariantList& defaults = {});
|
||||
|
||||
[[nodiscard]] int count() const;
|
||||
[[nodiscard]] QVariantList values() const;
|
||||
[[nodiscard]] ConfigObject* itemAt(int index) const;
|
||||
[[nodiscard]] const QList<ConfigObject*>& items() const;
|
||||
|
||||
Q_INVOKABLE void remove(int index);
|
||||
Q_INVOKABLE void move(int from, int to);
|
||||
Q_INVOKABLE void clear();
|
||||
|
||||
void loadFromJson(const QJsonValue& json) override;
|
||||
[[nodiscard]] QJsonValue toJson() const override;
|
||||
void clearLoadedKeys() override;
|
||||
[[nodiscard]] QStringList unknownKeys() const override;
|
||||
void resyncFromGlobal() override;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
void valuesChanged();
|
||||
|
||||
protected:
|
||||
virtual ConfigObject* createItem() = 0;
|
||||
|
||||
void resetToDefaults();
|
||||
|
||||
ConfigObject* insertItem(const QVariantMap& props, int index = -1);
|
||||
|
||||
[[nodiscard]] QJsonArray elementsToJson() const;
|
||||
|
||||
void syncValuesFromGlobal() override;
|
||||
void onGlobalPropertiesChanged(
|
||||
const QMap<QString, QVariant>& changed) override;
|
||||
[[nodiscard]] QString childPath(const ConfigNode* child) const override;
|
||||
|
||||
private:
|
||||
void populate(const QJsonArray& arr);
|
||||
static bool sameElement(
|
||||
const ConfigObject* item,
|
||||
const QJsonValue& current,
|
||||
const QJsonValue& json);
|
||||
void appendItem(const QJsonValue& json);
|
||||
void destroyItems();
|
||||
void destroyItem(ConfigObject* item);
|
||||
void rejectGlobalOnlyElement(const ConfigObject* item) const;
|
||||
void connectItem(ConfigNode* node);
|
||||
void disconnectItem(ConfigNode* node);
|
||||
void onItemChanged();
|
||||
void notifyChanged();
|
||||
|
||||
QJsonArray m_defaults;
|
||||
QList<ConfigObject*> m_items;
|
||||
bool m_loaded = false;
|
||||
QJsonValue m_rejectedJson = QJsonValue::Undefined;
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
|
||||
#define CONFIG_LIST_TYPE(Element, Name) \
|
||||
class Name : public ZShell::config::ConfigList { \
|
||||
Q_OBJECT \
|
||||
QML_ANONYMOUS \
|
||||
\
|
||||
public: \
|
||||
explicit Name( \
|
||||
QObject* parent = nullptr, const QVariantList& defaults = {}) \
|
||||
: ZShell::config::ConfigList(parent, defaults) { \
|
||||
resetToDefaults(); \
|
||||
} \
|
||||
\
|
||||
Q_INVOKABLE ZShell::config::Element* at(int index) const { \
|
||||
return static_cast<ZShell::config::Element*>(itemAt(index)); \
|
||||
} \
|
||||
Q_INVOKABLE ZShell::config::Element* insert( \
|
||||
const QVariantMap& props, int index = -1) { \
|
||||
return static_cast<ZShell::config::Element*>( \
|
||||
insertItem(props, index)); \
|
||||
} \
|
||||
\
|
||||
protected: \
|
||||
[[nodiscard]] ZShell::config::ConfigObject* createItem() override { \
|
||||
return new ZShell::config::Element(this); \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
#define CONFIG_LIST(Type, name, ...) \
|
||||
Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \
|
||||
\
|
||||
public: \
|
||||
[[nodiscard]] Type* name() const { \
|
||||
return m_##name; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__));
|
||||
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class ListEntry : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QString, id)
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
|
||||
public:
|
||||
explicit ListEntry(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
|
||||
[[nodiscard]] QStringList identityKeys() const override {
|
||||
return {QStringLiteral("id")};
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_LIST_TYPE(ListEntry, EntryList)
|
||||
|
||||
} // namespace ZShell::config
|
||||
|
||||
#define LIST_ENTRY(id, enabled) \
|
||||
vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}})
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "confignode.hpp"
|
||||
|
||||
#include <qjsonvalue.h>
|
||||
#include <qloggingcategory.h>
|
||||
#include <qmetaobject.h>
|
||||
#include <qstring.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcConfig, "zshell.config")
|
||||
|
||||
ConfigNode::ConfigNode(QObject* parent) : QObject(parent) {
|
||||
m_batchTimer = new QTimer(this);
|
||||
m_batchTimer->setSingleShot(true);
|
||||
m_batchTimer->setInterval(0);
|
||||
connect(
|
||||
m_batchTimer, &QTimer::timeout, this, &ConfigNode::emitBatchedChanges);
|
||||
}
|
||||
|
||||
void ConfigNode::loadFromJsonQuietly(const QJsonValue& json) {
|
||||
setNotifySuppressed(true);
|
||||
loadFromJson(json);
|
||||
setNotifySuppressed(false);
|
||||
}
|
||||
|
||||
void ConfigNode::setNotifySuppressed(bool suppressed) {
|
||||
m_suppressNotify = suppressed;
|
||||
|
||||
const auto children = childNodes();
|
||||
for (auto* const child : children)
|
||||
child->setNotifySuppressed(suppressed);
|
||||
}
|
||||
|
||||
QList<ConfigNode*> ConfigNode::childNodes() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void ConfigNode::syncFromGlobal(ConfigNode* global) {
|
||||
m_global = global;
|
||||
resyncFromGlobal();
|
||||
}
|
||||
|
||||
bool ConfigNode::isOverlay() const {
|
||||
return m_global != nullptr && this != m_global;
|
||||
}
|
||||
|
||||
QString ConfigNode::propertyPath(const QString& name) const {
|
||||
if (name.isEmpty()) return objectName();
|
||||
|
||||
QObject* const parentObj = parent();
|
||||
if (parentObj) {
|
||||
if (auto* parentNode = qobject_cast<ConfigNode*>(parentObj)) {
|
||||
const auto childName = parentNode->childPath(this);
|
||||
if (!childName.isEmpty()) {
|
||||
return joinPath(parentNode->propertyPath(childName), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int ConfigNode::basePropertyOffset() {
|
||||
return QObject::staticMetaObject.propertyCount();
|
||||
}
|
||||
|
||||
void ConfigNode::notifyPropertyChanged(
|
||||
const QString& name, const QVariant& value) {
|
||||
if (m_suppressNotify) return;
|
||||
|
||||
m_pendingChanges[name] = value;
|
||||
if (m_batchTimer && !m_batchTimer->isActive()) m_batchTimer->start();
|
||||
}
|
||||
|
||||
QString ConfigNode::joinPath(const QString& parent, const QString& child) {
|
||||
// List elements are addressed as parent[i], everything else as parent.child
|
||||
if (child.startsWith(QLatin1Char('['))) return parent + child;
|
||||
|
||||
return parent + QLatin1Char('.') + child;
|
||||
}
|
||||
|
||||
void ConfigNode::emitBatchedChanges() {
|
||||
if (m_pendingChanges.isEmpty()) return;
|
||||
|
||||
QMap<QString, QVariant> changes = m_pendingChanges;
|
||||
m_pendingChanges.clear();
|
||||
emit propertiesChanged(changes);
|
||||
}
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <QJsonValue>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcConfig)
|
||||
|
||||
class ConfigNode : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigNode(QObject* parent = nullptr);
|
||||
|
||||
virtual void loadFromJson(const QJsonValue& json) = 0;
|
||||
void loadFromJsonQuietly(const QJsonValue& json);
|
||||
[[nodiscard]] virtual QJsonValue toJson() const = 0;
|
||||
|
||||
virtual void clearLoadedKeys() = 0;
|
||||
[[nodiscard]] virtual QStringList unknownKeys() const = 0;
|
||||
[[nodiscard]] virtual QList<ConfigNode*> childNodes() const;
|
||||
|
||||
void syncFromGlobal(ConfigNode* global);
|
||||
virtual void resyncFromGlobal() = 0;
|
||||
|
||||
[[nodiscard]] bool isOverlay() const;
|
||||
[[nodiscard]] QString propertyPath(const QString& name = {}) const;
|
||||
|
||||
[[nodiscard]] static int basePropertyOffset();
|
||||
|
||||
signals:
|
||||
void propertiesChanged(const QMap<QString, QVariant>& changed);
|
||||
|
||||
protected:
|
||||
virtual void syncValuesFromGlobal() = 0;
|
||||
virtual void onGlobalPropertiesChanged(
|
||||
const QMap<QString, QVariant>& changed) = 0;
|
||||
|
||||
[[nodiscard]] virtual QString childPath(const ConfigNode* child) const = 0;
|
||||
|
||||
void notifyPropertyChanged(const QString& name, const QVariant& value);
|
||||
|
||||
[[nodiscard]] static QString joinPath(
|
||||
const QString& parent, const QString& child);
|
||||
|
||||
ConfigNode* m_global = nullptr;
|
||||
|
||||
private:
|
||||
void setNotifySuppressed(bool suppressed);
|
||||
void emitBatchedChanges();
|
||||
|
||||
QMap<QString, QVariant> m_pendingChanges;
|
||||
QTimer* m_batchTimer = nullptr;
|
||||
bool m_suppressNotify = false;
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,270 @@
|
||||
#include "configobject.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QMetaObject>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {}
|
||||
|
||||
void ConfigObject::loadFromJson(const QJsonValue& json) {
|
||||
const auto obj = json.toObject();
|
||||
const auto* meta = metaObject();
|
||||
|
||||
QSet<QString> known;
|
||||
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
auto prop = meta->property(i);
|
||||
const auto key = QString::fromUtf8(prop.name());
|
||||
|
||||
known.insert(key);
|
||||
|
||||
if (!obj.contains(key)) continue;
|
||||
|
||||
const auto jsonVal = obj.value(key);
|
||||
|
||||
if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
|
||||
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
|
||||
node->loadFromJson(jsonVal);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prop.isWritable()) continue;
|
||||
|
||||
if (prop.metaType().id() == QMetaType::QStringList) {
|
||||
QStringList list;
|
||||
const auto jsonArr = jsonVal.toArray();
|
||||
for (const auto& v : jsonArr)
|
||||
list.append(v.toString());
|
||||
prop.write(this, QVariant::fromValue(list));
|
||||
m_loadedKeys.insert(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prop.metaType().id() == QMetaType::QVariantList) {
|
||||
prop.write(this, jsonVal.toVariant());
|
||||
m_loadedKeys.insert(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
prop.write(this, jsonVal.toVariant());
|
||||
m_loadedKeys.insert(key);
|
||||
}
|
||||
|
||||
m_extras = {};
|
||||
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
||||
if (!known.contains(it.key())) {
|
||||
m_extras.insert(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonValue ConfigObject::toJson() const {
|
||||
QJsonObject obj;
|
||||
const auto* meta = metaObject();
|
||||
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
const auto prop = meta->property(i);
|
||||
|
||||
if (!prop.isReadable()) continue;
|
||||
|
||||
const auto key = QString::fromUtf8(prop.name());
|
||||
|
||||
const auto value = prop.read(this);
|
||||
|
||||
if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
|
||||
if (auto* const node = value.value<ConfigNode*>()) {
|
||||
const auto childJson = node->toJson();
|
||||
if (!childJson.isUndefined()) obj.insert(key, childJson);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_loadedKeys.contains(key)) continue;
|
||||
|
||||
if (!prop.isWritable()) continue;
|
||||
|
||||
if (prop.metaType().id() == QMetaType::QStringList) {
|
||||
QJsonArray arr;
|
||||
const auto strList = value.toStringList();
|
||||
for (const auto& s : strList)
|
||||
arr.append(s);
|
||||
obj.insert(key, arr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prop.metaType().id() == QMetaType::QVariantList) {
|
||||
obj.insert(key, QJsonArray::fromVariantList(value.toList()));
|
||||
continue;
|
||||
}
|
||||
|
||||
obj.insert(key, QJsonValue::fromVariant(value));
|
||||
}
|
||||
|
||||
for (auto it = m_extras.begin(); it != m_extras.end(); ++it)
|
||||
obj.insert(it.key(), it.value());
|
||||
|
||||
if (obj.isEmpty()) return QJsonValue::Undefined;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ConfigObject::clearLoadedKeys() {
|
||||
m_loadedKeys.clear();
|
||||
m_extras = {};
|
||||
|
||||
const auto* meta = metaObject();
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
auto prop = meta->property(i);
|
||||
if (auto* const node = prop.read(this).value<ConfigNode*>())
|
||||
node->clearLoadedKeys();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList ConfigObject::identityKeys() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList ConfigObject::unknownKeys() const {
|
||||
auto keys = m_extras.keys();
|
||||
|
||||
const auto* meta = metaObject();
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
const auto prop = meta->property(i);
|
||||
auto* const node = prop.read(this).value<ConfigNode*>();
|
||||
if (!node) continue;
|
||||
|
||||
const auto childKeys = node->unknownKeys();
|
||||
for (const auto& childKey : childKeys)
|
||||
keys.append(joinPath(QString::fromUtf8(prop.name()), childKey));
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
QList<ConfigNode*> ConfigObject::childNodes() const {
|
||||
QList<ConfigNode*> nodes;
|
||||
|
||||
const auto* meta = metaObject();
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
const auto prop = meta->property(i);
|
||||
|
||||
if (auto* const node = prop.read(this).value<ConfigNode*>())
|
||||
nodes.append(node);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
void ConfigObject::syncValuesFromGlobal() {
|
||||
const auto* meta = metaObject();
|
||||
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
auto prop = meta->property(i);
|
||||
const auto key = QString::fromUtf8(prop.name());
|
||||
|
||||
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
|
||||
if (auto* const globalNode =
|
||||
prop.read(m_global).value<ConfigNode*>())
|
||||
node->syncFromGlobal(globalNode);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prop.isWritable()) continue;
|
||||
|
||||
if (!m_loadedKeys.contains(key)) {
|
||||
auto val = prop.read(m_global);
|
||||
prop.write(this, val);
|
||||
m_loadedKeys.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigObject::resyncFromGlobal() {
|
||||
if (!m_global) return;
|
||||
|
||||
const auto* meta = metaObject();
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
auto prop = meta->property(i);
|
||||
const auto key = QString::fromUtf8(prop.name());
|
||||
|
||||
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
|
||||
node->resyncFromGlobal();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prop.isWritable()) continue;
|
||||
|
||||
if (!m_loadedKeys.contains(key)) {
|
||||
prop.write(this, prop.read(m_global));
|
||||
m_loadedKeys.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ConfigObject::isPropertyLoaded(const QString& name) const {
|
||||
return m_loadedKeys.contains(name);
|
||||
}
|
||||
|
||||
bool ConfigObject::isGlobalOnly(const QString& name) const {
|
||||
return m_globalOnlyKeys.contains(name);
|
||||
}
|
||||
|
||||
QStringList ConfigObject::globalOnlyKeys() const {
|
||||
return {m_globalOnlyKeys.begin(), m_globalOnlyKeys.end()};
|
||||
}
|
||||
|
||||
void ConfigObject::resetOption(const QString& name) {
|
||||
m_loadedKeys.remove(name);
|
||||
|
||||
const int idx = metaObject()->indexOfProperty(name.toUtf8().constData());
|
||||
if (idx < 0) return;
|
||||
|
||||
const auto prop = metaObject()->property(idx);
|
||||
|
||||
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
|
||||
node->clearLoadedKeys();
|
||||
node->resyncFromGlobal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_global && prop.isWritable()) prop.write(this, prop.read(m_global));
|
||||
}
|
||||
|
||||
void ConfigObject::onGlobalPropertiesChanged(
|
||||
const QMap<QString, QVariant>& changed) {
|
||||
for (auto it = changed.begin(); it != changed.end(); ++it) {
|
||||
if (m_loadedKeys.contains(it.key()) || isGlobalOnly(it.key())) continue;
|
||||
|
||||
int idx = metaObject()->indexOfProperty(it.key().toUtf8().constData());
|
||||
if (idx >= 0) {
|
||||
metaObject()->property(idx).write(this, it.value());
|
||||
m_loadedKeys.remove(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString ConfigObject::childPath(const ConfigNode* child) const {
|
||||
const auto* meta = metaObject();
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
const auto prop = meta->property(i);
|
||||
|
||||
if (prop.read(this).value<ConfigNode*>() == child)
|
||||
return QString::fromUtf8(prop.name());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ConfigObject::markPropertyLoaded(const QString& name) {
|
||||
m_loadedKeys.insert(name);
|
||||
}
|
||||
|
||||
void ConfigObject::markGlobalOnly(const QString& name) {
|
||||
m_globalOnlyKeys.insert(name);
|
||||
}
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "confignode.hpp"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QMetaProperty>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <QVariantList>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
inline QVariantMap vmap(
|
||||
std::initializer_list<std::pair<QString, QVariant>> entries) {
|
||||
QVariantMap map;
|
||||
for (const auto& [key, value] : entries)
|
||||
map.insert(key, value);
|
||||
return map;
|
||||
}
|
||||
|
||||
#define CFG_PROPERTY(Type, name, ...) \
|
||||
Q_PROPERTY(Type name READ name WRITE set_##name NOTIFY name##Changed) \
|
||||
public: \
|
||||
[[nodiscard]] Type name() const { \
|
||||
return m_##name; \
|
||||
} \
|
||||
void set_##name(const Type& value) { \
|
||||
if (ConfigObject::updateMember(m_##name, value)) { \
|
||||
markPropertyLoaded(QStringLiteral(#name)); \
|
||||
Q_EMIT name##Changed(); \
|
||||
notifyPropertyChanged( \
|
||||
QStringLiteral(#name), QVariant::fromValue(m_##name)); \
|
||||
} \
|
||||
} \
|
||||
Q_SIGNAL void name##Changed(); \
|
||||
\
|
||||
private: \
|
||||
Type m_##name __VA_OPT__(= __VA_ARGS__);
|
||||
|
||||
#define CONFIG_SUBOBJECT(Type, name) \
|
||||
Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \
|
||||
\
|
||||
public: \
|
||||
[[nodiscard]] Type* name() const { \
|
||||
return m_##name; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
Type* m_##name = nullptr;
|
||||
|
||||
class ConfigObject : public ConfigNode {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigObject(QObject* parent = nullptr);
|
||||
|
||||
void loadFromJson(const QJsonValue& json) override;
|
||||
[[nodiscard]] QJsonValue toJson() const override;
|
||||
void clearLoadedKeys() override;
|
||||
[[nodiscard]] QStringList unknownKeys() const override;
|
||||
[[nodiscard]] QList<ConfigNode*> childNodes() const override;
|
||||
void resyncFromGlobal() override;
|
||||
|
||||
[[nodiscard]] virtual QStringList identityKeys() const;
|
||||
|
||||
[[nodiscard]] bool isPropertyLoaded(const QString& name) const;
|
||||
[[nodiscard]] bool isGlobalOnly(const QString& name) const;
|
||||
[[nodiscard]] QStringList globalOnlyKeys() const;
|
||||
|
||||
Q_INVOKABLE void resetOption(const QString& name);
|
||||
|
||||
template <typename T> static bool updateMember(T& member, const T& value) {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
if (qFuzzyCompare(member + 1.0, value + 1.0)) return false;
|
||||
} else {
|
||||
if (member == value) return false;
|
||||
}
|
||||
member = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void syncValuesFromGlobal() override;
|
||||
void onGlobalPropertiesChanged(
|
||||
const QMap<QString, QVariant>& changed) override;
|
||||
[[nodiscard]] QString childPath(const ConfigNode* child) const override;
|
||||
|
||||
void markPropertyLoaded(const QString& name);
|
||||
void markGlobalOnly(const QString& name);
|
||||
|
||||
private:
|
||||
QSet<QString> m_loadedKeys;
|
||||
QSet<QString> m_globalOnlyKeys;
|
||||
QJsonObject m_extras;
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class Performance : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(bool, showBattery, false)
|
||||
CFG_PROPERTY(bool, showCpu, true)
|
||||
CFG_PROPERTY(bool, showGpu, true)
|
||||
CFG_PROPERTY(bool, showMemory, true)
|
||||
CFG_PROPERTY(bool, showNetwork, true)
|
||||
CFG_PROPERTY(bool, showStorage, true)
|
||||
CFG_PROPERTY(bool, showVram, true)
|
||||
|
||||
public:
|
||||
explicit Performance(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class DashboardSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, dateTimeWidth, 110)
|
||||
CFG_PROPERTY(int, infoIconSize, 25)
|
||||
CFG_PROPERTY(int, infoWidth, 200)
|
||||
CFG_PROPERTY(int, mediaCoverArtSize, 150)
|
||||
CFG_PROPERTY(int, mediaProgressSweep, 180)
|
||||
CFG_PROPERTY(int, mediaProgressThickness, 8)
|
||||
CFG_PROPERTY(int, mediaVisualizerSize, 200)
|
||||
CFG_PROPERTY(int, mediaWidth, 200)
|
||||
CFG_PROPERTY(int, resourceProgessThickness, 10)
|
||||
CFG_PROPERTY(int, resourceSize, 200)
|
||||
CFG_PROPERTY(int, tabIndicatorHeight, 3)
|
||||
CFG_PROPERTY(int, tabIndicatorSpacing, 5)
|
||||
CFG_PROPERTY(int, weatherWidth, 250)
|
||||
|
||||
public:
|
||||
explicit DashboardSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Dashboard : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(int, mediaUpdateInterval, 2000)
|
||||
CONFIG_SUBOBJECT(Performance, performance)
|
||||
CFG_PROPERTY(int, resourceUpdateInterval, 1000)
|
||||
CONFIG_SUBOBJECT(DashboardSizes, sizes)
|
||||
|
||||
public:
|
||||
explicit Dashboard(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_performance(new Performance(this))
|
||||
, m_sizes(new DashboardSizes(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <QStringList>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class Dock : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enable, false)
|
||||
CFG_PROPERTY(int, height, 80)
|
||||
CFG_PROPERTY(bool, hoverToReveal, false)
|
||||
CFG_PROPERTY(QStringList, ignoredAppRegexes, {})
|
||||
CFG_PROPERTY(
|
||||
QStringList,
|
||||
pinnedApps,
|
||||
(QStringList{
|
||||
QStringLiteral("com.ayugram.desktop"),
|
||||
QStringLiteral("com.obsproject.studio"),
|
||||
QStringLiteral("librewolf")}))
|
||||
CFG_PROPERTY(bool, pinnedOnStartup, false)
|
||||
|
||||
public:
|
||||
explicit Dock(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,158 @@
|
||||
#pragma once
|
||||
#include "configlist.hpp"
|
||||
#include "configobject.hpp"
|
||||
#include <QStringList>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class BatteryThresholdEntry : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QString, icon)
|
||||
CFG_PROPERTY(QString, message)
|
||||
CFG_PROPERTY(QString, name)
|
||||
CFG_PROPERTY(int, perc)
|
||||
|
||||
public:
|
||||
explicit BatteryThresholdEntry(QObject* parent = nullptr)
|
||||
: ConfigObject(parent) {}
|
||||
|
||||
[[nodiscard]] QStringList identityKeys() const override {
|
||||
return {QStringLiteral("perc")};
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_LIST_TYPE(BatteryThresholdEntry, BatteryThresholdList)
|
||||
|
||||
class IdleTimeoutEntry : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QString, idleAction)
|
||||
CFG_PROPERTY(QString, name)
|
||||
CFG_PROPERTY(int, timeout)
|
||||
|
||||
public:
|
||||
explicit IdleTimeoutEntry(QObject* parent = nullptr)
|
||||
: ConfigObject(parent) {}
|
||||
|
||||
[[nodiscard]] QStringList identityKeys() const override {
|
||||
return {QStringLiteral("name")};
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_LIST_TYPE(IdleTimeoutEntry, IdleTimeoutList)
|
||||
|
||||
class Apps : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QStringList, archiver, {QStringLiteral("ark")})
|
||||
CFG_PROPERTY(QStringList, audio, {QStringLiteral("pavucontrol")})
|
||||
CFG_PROPERTY(QStringList, document, {QStringLiteral("libreoffice")})
|
||||
CFG_PROPERTY(QStringList, editor, {QStringLiteral("kate")})
|
||||
CFG_PROPERTY(QStringList, explorer, {QStringLiteral("dolphin")})
|
||||
CFG_PROPERTY(QStringList, image, {QStringLiteral("imv")})
|
||||
CFG_PROPERTY(QStringList, playback, {QStringLiteral("vlc")})
|
||||
CFG_PROPERTY(QStringList, terminal, {QStringLiteral("wezterm")})
|
||||
|
||||
public:
|
||||
explicit Apps(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Battery : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, critPerc, 5)
|
||||
CONFIG_LIST(
|
||||
BatteryThresholdList,
|
||||
popupThresholds,
|
||||
{
|
||||
vmap(
|
||||
{{"icon", "battery_android_frame_2"},
|
||||
{"message", "Battery low"},
|
||||
{"name", "Low battery"},
|
||||
{"perc", 20}}),
|
||||
vmap(
|
||||
{{"icon", "battery_android_frame_2"},
|
||||
{"message", "Battery lower"},
|
||||
{"name", "Low battery"},
|
||||
{"perc", 15}}),
|
||||
vmap(
|
||||
{{"icon", "battery_android_frame_2"},
|
||||
{"message", "Battery lowest"},
|
||||
{"name", "Low battery"},
|
||||
{"perc", 10}}),
|
||||
})
|
||||
|
||||
public:
|
||||
explicit Battery(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class ColorSettings : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, hyprsunsetTemp, 2600)
|
||||
CFG_PROPERTY(QString, mode, QStringLiteral("dark"))
|
||||
CFG_PROPERTY(bool, neovimColors, false)
|
||||
CFG_PROPERTY(bool, scheduleDark, false)
|
||||
CFG_PROPERTY(int, scheduleDarkEnd, 600)
|
||||
CFG_PROPERTY(int, scheduleDarkStart, 1140)
|
||||
CFG_PROPERTY(bool, scheduleHyprsunset, true)
|
||||
CFG_PROPERTY(int, scheduleHyprsunsetEnd, 570)
|
||||
CFG_PROPERTY(int, scheduleHyprsunsetStart, 1200)
|
||||
CFG_PROPERTY(bool, schemeGeneration, true)
|
||||
CFG_PROPERTY(bool, smart, false)
|
||||
|
||||
public:
|
||||
explicit ColorSettings(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Idle : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CONFIG_LIST(
|
||||
IdleTimeoutList,
|
||||
timeouts,
|
||||
{
|
||||
vmap(
|
||||
{{"idleAction", QStringLiteral("lock")},
|
||||
{"name", QStringLiteral("Lock")},
|
||||
{"timeout", 180}}),
|
||||
})
|
||||
|
||||
public:
|
||||
explicit Idle(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class General : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CONFIG_SUBOBJECT(Apps, apps)
|
||||
CONFIG_SUBOBJECT(Battery, battery)
|
||||
CONFIG_SUBOBJECT(ColorSettings, color)
|
||||
CFG_PROPERTY(QString, dateFormat, QStringLiteral("ddd d MMM - hh:mm:ss"))
|
||||
CFG_PROPERTY(bool, desktopIcons, true)
|
||||
CONFIG_SUBOBJECT(Idle, idle)
|
||||
CFG_PROPERTY(QString, logo, QString())
|
||||
CFG_PROPERTY(bool, showOverFullscreen, true)
|
||||
CFG_PROPERTY(
|
||||
QString,
|
||||
wallpaperPath,
|
||||
QStringLiteral("/mnt/IronWolf/SDImages/SWWW_Wals/"))
|
||||
|
||||
public:
|
||||
explicit General(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_apps(new Apps(this))
|
||||
, m_battery(new Battery(this))
|
||||
, m_color(new ColorSettings(this))
|
||||
, m_idle(new Idle(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,177 @@
|
||||
#pragma once
|
||||
#include "configlist.hpp"
|
||||
#include "configobject.hpp"
|
||||
#include <QStringList>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class LauncherActionEntry : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QVariantList, command)
|
||||
CFG_PROPERTY(bool, dangerous, false)
|
||||
CFG_PROPERTY(QString, description)
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(QString, icon)
|
||||
CFG_PROPERTY(QString, name)
|
||||
|
||||
public:
|
||||
explicit LauncherActionEntry(QObject* parent = nullptr)
|
||||
: ConfigObject(parent) {}
|
||||
|
||||
[[nodiscard]] QStringList identityKeys() const override {
|
||||
return {QStringLiteral("name")};
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_LIST_TYPE(LauncherActionEntry, LauncherActionList)
|
||||
|
||||
class LauncherSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, itemHeight, 50)
|
||||
CFG_PROPERTY(int, itemWidth, 600)
|
||||
CFG_PROPERTY(int, wallpaperHeight, 200)
|
||||
CFG_PROPERTY(int, wallpaperWidth, 280)
|
||||
|
||||
public:
|
||||
explicit LauncherSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class UseFuzzy : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, actions, true)
|
||||
CFG_PROPERTY(bool, apps, true)
|
||||
CFG_PROPERTY(bool, schemes, true)
|
||||
CFG_PROPERTY(bool, variants, true)
|
||||
CFG_PROPERTY(bool, wallpapers, true)
|
||||
|
||||
public:
|
||||
explicit UseFuzzy(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Launcher : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QString, actionPrefix, QStringLiteral("<"))
|
||||
CONFIG_LIST(
|
||||
LauncherActionList,
|
||||
actions,
|
||||
{
|
||||
vmap(
|
||||
{{"command", QVariantList{"autocomplete", "calc"}},
|
||||
{"dangerous", false},
|
||||
{"description", "Do simple math equations"},
|
||||
{"enabled", true},
|
||||
{"icon", "calculate"},
|
||||
{"name", "Calculator"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"setMode", "light"}},
|
||||
{"dangerous", false},
|
||||
{"description", "Change to light mode"},
|
||||
{"enabled", true},
|
||||
{"icon", "light_mode"},
|
||||
{"name", "Light"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"setMode", "dark"}},
|
||||
{"dangerous", false},
|
||||
{"description", "Change to dark mode"},
|
||||
{"enabled", true},
|
||||
{"icon", "dark_mode"},
|
||||
{"name", "Dark"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"autocomplete", "wallpaper"}},
|
||||
{"dangerous", false},
|
||||
{"description", "Change the current wallpaper"},
|
||||
{"enabled", true},
|
||||
{"icon", "image"},
|
||||
{"name", "Wallpaper"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"autocomplete", "variant"}},
|
||||
{"dangerous", false},
|
||||
{"description", "Change the current scheme variant"},
|
||||
{"enabled", true},
|
||||
{"icon", "colors"},
|
||||
{"name", "Variant"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"systemctl", "poweroff"}},
|
||||
{"dangerous", true},
|
||||
{"description", "Shutdown the system"},
|
||||
{"enabled", true},
|
||||
{"icon", "power_settings_new"},
|
||||
{"name", "Shutdown"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"systemctl", "reboot"}},
|
||||
{"dangerous", true},
|
||||
{"description", "Reboot the system"},
|
||||
{"enabled", true},
|
||||
{"icon", "cached"},
|
||||
{"name", "Reboot"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"loginctl", "terminate-user", ""}},
|
||||
{"dangerous", true},
|
||||
{"description", "Log out of the current session"},
|
||||
{"enabled", true},
|
||||
{"icon", "logout"},
|
||||
{"name", "Logout"}}),
|
||||
vmap(
|
||||
{{"command", QVariantList{"loginctl", "lock-session"}},
|
||||
{"dangerous", false},
|
||||
{"description", "Lock the current session"},
|
||||
{"enabled", true},
|
||||
{"icon", "lock"},
|
||||
{"name", "Lock"}}),
|
||||
vmap(
|
||||
{{"command",
|
||||
QVariantList{"systemctl", "suspend-then-hibernate"}},
|
||||
{"dangerous", false},
|
||||
{"description", "Suspend then hibernate"},
|
||||
{"enabled", true},
|
||||
{"icon", "bedtime"},
|
||||
{"name", "Sleep"}}),
|
||||
})
|
||||
CFG_PROPERTY(int, dragThreshold, 150)
|
||||
CFG_PROPERTY(bool, enableDangerousActions, true)
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(
|
||||
QStringList,
|
||||
favoriteApps,
|
||||
{QStringLiteral("Balatro"),
|
||||
QStringLiteral("Slay the Spire 2"),
|
||||
QStringLiteral("com.obsproject.Studio")})
|
||||
CFG_PROPERTY(
|
||||
QStringList,
|
||||
hiddenApps,
|
||||
{QStringLiteral("zellij"),
|
||||
QStringLiteral("vim"),
|
||||
QStringLiteral("jshell-java-openjdk"),
|
||||
QStringLiteral("jconsole-java-openjdk"),
|
||||
QStringLiteral("jshell-java21-openjdk"),
|
||||
QStringLiteral("jconsole-java21-openjdk"),
|
||||
QStringLiteral("jshell-java17-openjdk"),
|
||||
QStringLiteral("jconsole-java17-openjdk"),
|
||||
QStringLiteral("org.neovim.nvim"),
|
||||
QStringLiteral("avahi-discover"),
|
||||
QStringLiteral("bvnc"),
|
||||
QStringLiteral("bssh"),
|
||||
QStringLiteral("nm-connection-editor")})
|
||||
CFG_PROPERTY(int, maxAppsShown, 18)
|
||||
CFG_PROPERTY(int, maxWallpapers, 7)
|
||||
CONFIG_SUBOBJECT(LauncherSizes, sizes)
|
||||
CFG_PROPERTY(QString, specialPrefix, QStringLiteral("@"))
|
||||
CONFIG_SUBOBJECT(UseFuzzy, useFuzzy)
|
||||
CFG_PROPERTY(bool, uwsm, true)
|
||||
|
||||
public:
|
||||
explicit Launcher(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_sizes(new LauncherSizes(this))
|
||||
, m_useFuzzy(new UseFuzzy(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class LockSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, centerWidth, 600)
|
||||
CFG_PROPERTY(qreal, heightMult, 0.7)
|
||||
CFG_PROPERTY(qreal, ratio, 1.78)
|
||||
|
||||
public:
|
||||
explicit LockSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Lock : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, blurAmount, 10)
|
||||
CFG_PROPERTY(bool, enableFprint, true)
|
||||
CFG_PROPERTY(int, maxFprintTries, 3)
|
||||
CFG_PROPERTY(bool, recolorLogo, false)
|
||||
CFG_PROPERTY(bool, showNotifContent, true)
|
||||
CFG_PROPERTY(bool, showNotifIcon, true)
|
||||
CONFIG_SUBOBJECT(LockSizes, sizes)
|
||||
|
||||
public:
|
||||
explicit Lock(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_sizes(new LockSizes(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class NotifsSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, badge, 20)
|
||||
CFG_PROPERTY(int, image, 41)
|
||||
CFG_PROPERTY(int, width, 400)
|
||||
|
||||
public:
|
||||
explicit NotifsSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Notifs : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, actionOnClick, false)
|
||||
CFG_PROPERTY(int, appNotifCooldown, 0)
|
||||
CFG_PROPERTY(qreal, clearThreshold, 0.3)
|
||||
CFG_PROPERTY(int, defaultExpireTimeout, 5000)
|
||||
CFG_PROPERTY(int, expandThreshold, 20)
|
||||
CFG_PROPERTY(bool, expire, true)
|
||||
CFG_PROPERTY(int, groupPreviewNum, 5)
|
||||
CFG_PROPERTY(bool, openExpanded, false)
|
||||
CFG_PROPERTY(bool, showInFullscreen, false)
|
||||
CONFIG_SUBOBJECT(NotifsSizes, sizes)
|
||||
|
||||
public:
|
||||
explicit Notifs(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_sizes(new NotifsSizes(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class OsdSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, sliderHeight, 150)
|
||||
CFG_PROPERTY(int, sliderWidth, 30)
|
||||
|
||||
public:
|
||||
explicit OsdSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Osd : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, allMonBrightness, true)
|
||||
CFG_PROPERTY(bool, enableBrightness, true)
|
||||
CFG_PROPERTY(bool, enableMicrophone, true)
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(int, hideDelay, 3000)
|
||||
CONFIG_SUBOBJECT(OsdSizes, sizes)
|
||||
|
||||
public:
|
||||
explicit Osd(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_sizes(new OsdSizes(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <QVariantList>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class Screenshot : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enable_pp, false)
|
||||
CFG_PROPERTY(QString, mode, QStringLiteral("manual"))
|
||||
CFG_PROPERTY(int, radius, 49)
|
||||
CFG_PROPERTY(bool, rounding, false)
|
||||
CFG_PROPERTY(bool, saveOnCopy, false)
|
||||
CFG_PROPERTY(bool, shadow, true)
|
||||
CFG_PROPERTY(int, shadow_blur, 0)
|
||||
CFG_PROPERTY(QVariantList, shadow_color, (QVariantList{0, 0, 0, 160}))
|
||||
CFG_PROPERTY(int, shadow_offset_x, 30)
|
||||
CFG_PROPERTY(int, shadow_offset_y, 50)
|
||||
|
||||
public:
|
||||
explicit Screenshot(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "configlist.hpp"
|
||||
#include "configobject.hpp"
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class PlayerAliasEntry : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(QString, from)
|
||||
CFG_PROPERTY(QString, to)
|
||||
|
||||
public:
|
||||
explicit PlayerAliasEntry(QObject* parent = nullptr)
|
||||
: ConfigObject(parent) {}
|
||||
|
||||
[[nodiscard]] QStringList identityKeys() const override {
|
||||
return {QStringLiteral("from")};
|
||||
}
|
||||
};
|
||||
|
||||
CONFIG_LIST_TYPE(PlayerAliasEntry, PlayerAliasList)
|
||||
|
||||
class Services : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(qreal, audioIncrement, 0.1)
|
||||
CFG_PROPERTY(qreal, brightnessIncrement, 0.1)
|
||||
CFG_PROPERTY(bool, ddcutilService, true)
|
||||
CFG_PROPERTY(QString, defaultPlayer, QStringLiteral("Spotify"))
|
||||
CFG_PROPERTY(QString, gpuType, QStringLiteral("NVIDIA"))
|
||||
CFG_PROPERTY(qreal, maxVolume, 1)
|
||||
CFG_PROPERTY(qreal, minBrightness, 0.01)
|
||||
CONFIG_LIST(
|
||||
PlayerAliasList,
|
||||
playerAliases,
|
||||
{
|
||||
vmap(
|
||||
{{"from", QStringLiteral("com.github.th_ch.youtube_music")},
|
||||
{"to", QStringLiteral("YT Music")}}),
|
||||
})
|
||||
CFG_PROPERTY(bool, updates, true)
|
||||
CFG_PROPERTY(bool, useFahrenheit, false)
|
||||
CFG_PROPERTY(bool, useTwelveHourClock, false)
|
||||
CFG_PROPERTY(int, visualizerBars, 50)
|
||||
CFG_PROPERTY(QString, weatherLocation, QString())
|
||||
|
||||
public:
|
||||
explicit Services(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class SidebarSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, width, 520)
|
||||
|
||||
public:
|
||||
explicit SidebarSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Sidebar : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, dragThreshold, 30)
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CONFIG_SUBOBJECT(SidebarSizes, sizes)
|
||||
|
||||
public:
|
||||
explicit Sidebar(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_sizes(new SidebarSizes(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,221 @@
|
||||
#pragma once
|
||||
|
||||
#include "configobject.hpp"
|
||||
|
||||
#include <QVariantList>
|
||||
#include <qqmlengine.h>
|
||||
#include <qqmlregistration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class AppearanceRounding : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(qreal, extraSmall, 4)
|
||||
CFG_PROPERTY(qreal, full, 1000)
|
||||
CFG_PROPERTY(qreal, large, 24)
|
||||
CFG_PROPERTY(qreal, medium, 16)
|
||||
CFG_PROPERTY(qreal, normal, 18)
|
||||
CFG_PROPERTY(qreal, scale, 1)
|
||||
CFG_PROPERTY(qreal, small, 12)
|
||||
CFG_PROPERTY(qreal, smallest, 8)
|
||||
|
||||
public:
|
||||
explicit AppearanceRounding(QObject* parent = nullptr)
|
||||
: ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class AppearancePadding : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(qreal, extraLarge, 28)
|
||||
CFG_PROPERTY(qreal, extraLargeIncreased, 32)
|
||||
CFG_PROPERTY(qreal, extraSmall, 4)
|
||||
CFG_PROPERTY(qreal, large, 16)
|
||||
CFG_PROPERTY(qreal, largeIncreased, 20)
|
||||
CFG_PROPERTY(qreal, larger, 12)
|
||||
CFG_PROPERTY(qreal, normal, 8)
|
||||
CFG_PROPERTY(qreal, scale, 1)
|
||||
CFG_PROPERTY(qreal, small, 5)
|
||||
CFG_PROPERTY(qreal, smaller, 7)
|
||||
CFG_PROPERTY(qreal, smallest, 2)
|
||||
|
||||
public:
|
||||
explicit AppearancePadding(QObject* parent = nullptr)
|
||||
: ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class AppearanceSpacing : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(qreal, extraSmall, 4)
|
||||
CFG_PROPERTY(qreal, large, 20)
|
||||
CFG_PROPERTY(qreal, larger, 16)
|
||||
CFG_PROPERTY(qreal, normal, 12)
|
||||
CFG_PROPERTY(qreal, scale, 1)
|
||||
CFG_PROPERTY(qreal, small, 8)
|
||||
CFG_PROPERTY(qreal, smaller, 10)
|
||||
|
||||
public:
|
||||
explicit AppearanceSpacing(QObject* parent = nullptr)
|
||||
: ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class FontSizeTokens : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(qreal, extraLarge, 28)
|
||||
CFG_PROPERTY(qreal, large, 18)
|
||||
CFG_PROPERTY(qreal, larger, 16)
|
||||
CFG_PROPERTY(qreal, medium, 14)
|
||||
CFG_PROPERTY(qreal, normal, 13)
|
||||
CFG_PROPERTY(qreal, scale, 1)
|
||||
CFG_PROPERTY(qreal, small, 11)
|
||||
CFG_PROPERTY(qreal, smaller, 12)
|
||||
|
||||
public:
|
||||
explicit FontSizeTokens(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class FontTokens : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CONFIG_SUBOBJECT(FontSizeTokens, size)
|
||||
|
||||
public:
|
||||
explicit FontTokens(QObject* parent = nullptr)
|
||||
: ConfigObject(parent), m_size(new FontSizeTokens(this)) {}
|
||||
};
|
||||
|
||||
class AnimCurves : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList,
|
||||
emphasized,
|
||||
QVariantList{
|
||||
0.05,
|
||||
0,
|
||||
2.0 / 15.0,
|
||||
0.06,
|
||||
1.0 / 6.0,
|
||||
0.4,
|
||||
5.0 / 24.0,
|
||||
0.82,
|
||||
0.25,
|
||||
1,
|
||||
1,
|
||||
1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList, emphasizedAccel, QVariantList{0.3, 0, 0.8, 0.15, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList, emphasizedDecel, QVariantList{0.05, 0.7, 0.1, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList,
|
||||
expressiveDefaultEffects,
|
||||
QVariantList{0.34, 0.8, 0.34, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList,
|
||||
expressiveDefaultSpatial,
|
||||
QVariantList{0.38, 1.21, 0.22, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList, expressiveEffects, QVariantList{0.34, 0.8, 0.34, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList,
|
||||
expressiveFastEffects,
|
||||
QVariantList{0.31, 0.94, 0.34, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList,
|
||||
expressiveFastSpatial,
|
||||
QVariantList{0.42, 1.67, 0.21, 0.9, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList,
|
||||
expressiveSlowEffects,
|
||||
QVariantList{0.34, 0.88, 0.34, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(
|
||||
QVariantList,
|
||||
expressiveSlowSpatial,
|
||||
QVariantList{0.39, 1.29, 0.35, 0.98, 1, 1})
|
||||
|
||||
CFG_PROPERTY(QVariantList, standard, QVariantList{0.2, 0, 0, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(QVariantList, standardAccel, QVariantList{0.3, 0, 1, 1, 1, 1})
|
||||
|
||||
CFG_PROPERTY(QVariantList, standardDecel, QVariantList{0, 0, 0, 1, 1, 1})
|
||||
|
||||
public:
|
||||
explicit AnimCurves(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class AnimDurations : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, expressiveDefaultSpatial, 500)
|
||||
CFG_PROPERTY(int, expressiveEffects, 200)
|
||||
CFG_PROPERTY(int, expressiveFastEffects, 150)
|
||||
CFG_PROPERTY(int, expressiveFastSpatial, 350)
|
||||
CFG_PROPERTY(int, expressiveSlowEffects, 300)
|
||||
CFG_PROPERTY(int, extraLarge, 1000)
|
||||
CFG_PROPERTY(int, large, 600)
|
||||
CFG_PROPERTY(int, normal, 400)
|
||||
CFG_PROPERTY(qreal, scale, 1)
|
||||
CFG_PROPERTY(int, small, 200)
|
||||
|
||||
public:
|
||||
explicit AnimDurations(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class AnimTokens : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CONFIG_SUBOBJECT(AnimCurves, curves)
|
||||
CONFIG_SUBOBJECT(AnimDurations, durations)
|
||||
|
||||
public:
|
||||
explicit AnimTokens(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_curves(new AnimCurves(this))
|
||||
, m_durations(new AnimDurations(this)) {}
|
||||
};
|
||||
|
||||
class Tokens : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
CONFIG_SUBOBJECT(AppearanceRounding, rounding)
|
||||
CONFIG_SUBOBJECT(AppearancePadding, padding)
|
||||
CONFIG_SUBOBJECT(AppearanceSpacing, spacing)
|
||||
CONFIG_SUBOBJECT(FontTokens, font)
|
||||
CONFIG_SUBOBJECT(AnimTokens, anim)
|
||||
|
||||
public:
|
||||
explicit Tokens(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_rounding(new AppearanceRounding(this))
|
||||
, m_padding(new AppearancePadding(this))
|
||||
, m_spacing(new AppearanceSpacing(this))
|
||||
, m_font(new FontTokens(this))
|
||||
, m_anim(new AnimTokens(this)) {}
|
||||
|
||||
static Tokens* create(QQmlEngine*, QJSEngine*) { return new Tokens(); }
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include "configobject.hpp"
|
||||
#include <QVariantList>
|
||||
#include <QStringList>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
class UtilitiesSizes : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(int, toastWidth, 430)
|
||||
CFG_PROPERTY(int, width, 430)
|
||||
|
||||
public:
|
||||
explicit UtilitiesSizes(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Toasts : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, audioInputChanged, true)
|
||||
CFG_PROPERTY(bool, audioOutputChanged, true)
|
||||
CFG_PROPERTY(bool, capsLockChanged, true)
|
||||
CFG_PROPERTY(bool, chargingChanged, true)
|
||||
CFG_PROPERTY(bool, configLoaded, true)
|
||||
CFG_PROPERTY(bool, dndChanged, true)
|
||||
CFG_PROPERTY(bool, gameModeChanged, true)
|
||||
CFG_PROPERTY(bool, kbLayoutChanged, true)
|
||||
CFG_PROPERTY(bool, kbLimit, true)
|
||||
CFG_PROPERTY(bool, nowPlaying, false)
|
||||
CFG_PROPERTY(bool, numLockChanged, true)
|
||||
CFG_PROPERTY(bool, vpnChanged, true)
|
||||
|
||||
public:
|
||||
explicit Toasts(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Vpn : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enabled, false)
|
||||
CFG_PROPERTY(QStringList, provider, (QStringList{QStringLiteral("netbird")}))
|
||||
|
||||
public:
|
||||
explicit Vpn(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||
};
|
||||
|
||||
class Utilities : public ConfigObject {
|
||||
Q_OBJECT
|
||||
QML_ANONYMOUS
|
||||
|
||||
CFG_PROPERTY(bool, enabled, true)
|
||||
CFG_PROPERTY(int, maxToasts, 4)
|
||||
CONFIG_SUBOBJECT(UtilitiesSizes, sizes)
|
||||
CONFIG_SUBOBJECT(Toasts, toasts)
|
||||
CONFIG_SUBOBJECT(Vpn, vpn)
|
||||
|
||||
public:
|
||||
explicit Utilities(QObject* parent = nullptr)
|
||||
: ConfigObject(parent)
|
||||
, m_sizes(new UtilitiesSizes(this))
|
||||
, m_toasts(new Toasts(this))
|
||||
, m_vpn(new Vpn(this)) {}
|
||||
};
|
||||
|
||||
} // namespace ZShell::config
|
||||
Reference in New Issue
Block a user