From 083fff57be0ce6bbf649f0463216b280c42a1dbc Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sat, 17 Feb 2024 04:24:03 -0800 Subject: [PATCH] feat: add PersistentProperties --- CMakeLists.txt | 1 + src/cpp/module.md | 1 + src/cpp/persistentprops.cpp | 24 ++++++++++++++++ src/cpp/persistentprops.hpp | 57 +++++++++++++++++++++++++++++++++++++ src/cpp/reload.hpp | 4 ++- 5 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/cpp/persistentprops.cpp create mode 100644 src/cpp/persistentprops.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 590b4c5e..a999fb29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ qt_add_executable(quickshell src/cpp/qmlscreen.cpp src/cpp/watcher.cpp src/cpp/region.cpp + src/cpp/persistentprops.cpp ) qt_add_qml_module(quickshell URI QuickShell) diff --git a/src/cpp/module.md b/src/cpp/module.md index 86faae2a..e55da91d 100644 --- a/src/cpp/module.md +++ b/src/cpp/module.md @@ -9,6 +9,7 @@ headers = [ "proxywindow.hpp", "layershell.hpp", "region.hpp", + "persistentprops.hpp", ] ----- The core types provided by QuickShell diff --git a/src/cpp/persistentprops.cpp b/src/cpp/persistentprops.cpp new file mode 100644 index 00000000..f2c7dbd8 --- /dev/null +++ b/src/cpp/persistentprops.cpp @@ -0,0 +1,24 @@ +#include "persistentprops.hpp" + +#include +#include + +void PersistentProperties::onReload(QObject* oldInstance) { + if (qobject_cast(oldInstance) == nullptr) { + emit this->loaded(); + return; + } + + const auto* metaObject = this->metaObject(); + for (auto i = metaObject->propertyOffset(); i < metaObject->propertyCount(); i++) { + const auto prop = metaObject->property(i); + auto oldProp = oldInstance->property(prop.name()); + + if (oldProp.isValid()) { + this->setProperty(prop.name(), oldProp); + } + } + + emit this->loaded(); + emit this->reloaded(); +} diff --git a/src/cpp/persistentprops.hpp b/src/cpp/persistentprops.hpp new file mode 100644 index 00000000..ef4e2bf6 --- /dev/null +++ b/src/cpp/persistentprops.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +#include "reload.hpp" + +///! Object that holds properties that can persist across a config reload. +/// PersistentProperties holds properties declated in it across a reload, which is +/// often useful for things like keeping expandable popups open and styling them. +/// +/// Below is an example of using `PersistentProperties` to keep track of the state +/// of an expandable panel. When the configuration is reloaded, the `expanderOpen` property +/// will be saved and the expandable panel will stay in the open/closed state. +/// +/// ```qml +/// PersistentProperties { +/// id: persist +/// reloadableId: "persistedStates" +/// +/// property bool expanderOpen: false +/// } +/// +/// Button { +/// id: expanderButton +/// anchors.centerIn: parent +/// text: "toggle expander" +/// onClicked: persist.expanderOpen = !persist.expanderOpen +/// } +/// +/// Rectangle { +/// anchors.top: expanderButton.bottom +/// anchors.left: expanderButton.left +/// anchors.right: expanderButton.right +/// height: 100 +/// +/// color: "lightblue" +/// visible: persist.expanderOpen +/// } +/// ``` +class PersistentProperties: public Reloadable { + Q_OBJECT; + QML_ELEMENT; + +public: + PersistentProperties(QObject* parent = nullptr): Reloadable(parent) {} + + void onReload(QObject* oldInstance) override; + +signals: + /// Called every time the reload stage completes. + /// Will be called every time, including when nothing was loaded from an old instance. + void loaded(); + /// Called every time the properties are reloaded. + /// Will not be called if no old instance was loaded. + void reloaded(); +}; diff --git a/src/cpp/reload.hpp b/src/cpp/reload.hpp index fc701849..1261afc6 100644 --- a/src/cpp/reload.hpp +++ b/src/cpp/reload.hpp @@ -52,7 +52,9 @@ class Reloadable: public QObject, public QQmlParserStatus { public: explicit Reloadable(QObject* parent = nullptr): QObject(parent) {} - /// called unconditionally in the reload phase, with nullptr if no source could be determined + // Called unconditionally in the reload phase, with nullptr if no source could be determined. + // If non null the old instance may or may not be of the same type, and should be checked + // by `onReload`. virtual void onReload(QObject* oldInstance) = 0; // TODO: onReload runs after initialization for reloadable objects created late