From 98c1e8587d0af66c68fc447114cada7396caaab4 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Tue, 23 Dec 2025 21:13:40 +0100 Subject: [PATCH] refactor(cleanup): add active_in dialog --- lsfg-vk-ui/CMakeLists.txt | 5 +- lsfg-vk-ui/rsc/UI.qml | 60 +++++++++++++++- .../rsc/{panes => dialogs}/CenteredDialog.qml | 2 +- lsfg-vk-ui/rsc/dialogs/LargeDialog.qml | 28 ++++++++ .../ProfileList.qml => widgets/List.qml} | 2 + lsfg-vk-ui/src/backend.cpp | 10 +++ lsfg-vk-ui/src/backend.hpp | 69 ++++++++++++++++--- 7 files changed, 161 insertions(+), 15 deletions(-) rename lsfg-vk-ui/rsc/{panes => dialogs}/CenteredDialog.qml (89%) create mode 100644 lsfg-vk-ui/rsc/dialogs/LargeDialog.qml rename lsfg-vk-ui/rsc/{panes/ProfileList.qml => widgets/List.qml} (96%) diff --git a/lsfg-vk-ui/CMakeLists.txt b/lsfg-vk-ui/CMakeLists.txt index 893dbb2..7f6e731 100644 --- a/lsfg-vk-ui/CMakeLists.txt +++ b/lsfg-vk-ui/CMakeLists.txt @@ -6,13 +6,14 @@ set(UI_SOURCES "src/utils.cpp") set(UI_RESOURCES - "rsc/panes/CenteredDialog.qml" + "rsc/dialogs/CenteredDialog.qml" + "rsc/dialogs/LargeDialog.qml" "rsc/panes/Group.qml" "rsc/panes/GroupEntry.qml" "rsc/panes/Pane.qml" - "rsc/panes/ProfileList.qml" "rsc/widgets/FileEdit.qml" "rsc/widgets/FlowSlider.qml" + "rsc/widgets/List.qml" "rsc/UI.qml") qt_add_executable(lsfg-vk-ui ${UI_SOURCES}) diff --git a/lsfg-vk-ui/rsc/UI.qml b/lsfg-vk-ui/rsc/UI.qml index fb92ae2..68129d4 100644 --- a/lsfg-vk-ui/rsc/UI.qml +++ b/lsfg-vk-ui/rsc/UI.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Window +import "dialogs" import "panes" import "widgets" @@ -51,6 +52,49 @@ ApplicationWindow { } } + LargeDialog { + id: active_in_dialog + onConfirm: backend.createProfile(create_name.text) + + List { + Layout.fillWidth: true + Layout.fillHeight: true + + model: backend.active_in + selected: backend.active_in_index + onSelect: (index) => { + backend.active_in_index = index + var idx = backend.active_in.index(index, 0); + active_in_name.text = backend.active_in.data(idx); + } + } + + RowLayout { + spacing: 8 + + TextField { + Layout.fillWidth: true + id: active_in_name + placeholderText: "Specify linux binary / exe file / process name" + focus: true + } + Button { + icon.name: "find-location" + onClicked: { + // TODO :3 + } + } + Button { + icon.name: "list-add" + onClicked: backend.addActiveIn(active_in_name.text) + } + Button { + icon.name: "list-remove" + onClicked: backend.removeActiveIn() + } + } + } + SplitView { anchors.fill: parent orientation: Qt.Horizontal @@ -67,7 +111,7 @@ ApplicationWindow { horizontalAlignment: Text.AlignHCenter } - ProfileList { + List { model: backend.profiles selected: backend.profile_index onSelect: (index) => backend.profile_index = index @@ -137,6 +181,18 @@ ApplicationWindow { name: "Profile Settings" enabled: backend.available + GroupEntry { + title: "Active In" + description: "Specify which applications this profile is active in" + + Button { + Layout.alignment: Qt.AlignRight + + text: "Edit..." + onClicked: active_in_dialog.open() + } + } + GroupEntry { title: "Multiplier" description: "Control the amount of generated frames" @@ -169,7 +225,7 @@ ApplicationWindow { GroupEntry { title: "Performance Mode" - description: "Use a significantly lighter frame generation modeln" + description: "Use a significantly lighter frame generation model" CheckBox { Layout.alignment: Qt.AlignRight diff --git a/lsfg-vk-ui/rsc/panes/CenteredDialog.qml b/lsfg-vk-ui/rsc/dialogs/CenteredDialog.qml similarity index 89% rename from lsfg-vk-ui/rsc/panes/CenteredDialog.qml rename to lsfg-vk-ui/rsc/dialogs/CenteredDialog.qml index 6ee06e6..c096d10 100644 --- a/lsfg-vk-ui/rsc/panes/CenteredDialog.qml +++ b/lsfg-vk-ui/rsc/dialogs/CenteredDialog.qml @@ -9,7 +9,7 @@ Dialog { id: root title: name - standardButtons: Dialog.Ok | Dialog.Cancel + standardButtons: Dialog.Ok onAccepted: root.confirm() modal: true diff --git a/lsfg-vk-ui/rsc/dialogs/LargeDialog.qml b/lsfg-vk-ui/rsc/dialogs/LargeDialog.qml new file mode 100644 index 0000000..59004c0 --- /dev/null +++ b/lsfg-vk-ui/rsc/dialogs/LargeDialog.qml @@ -0,0 +1,28 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +Dialog { + property string name + default property alias content: inner.children + signal confirm() + + id: root + title: name + onAccepted: root.confirm() + + modal: true + dim: true + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: parent.width * 0.75 + height: parent.height * 0.75 + + contentItem: ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + id: inner + spacing: 8 + } +} diff --git a/lsfg-vk-ui/rsc/panes/ProfileList.qml b/lsfg-vk-ui/rsc/widgets/List.qml similarity index 96% rename from lsfg-vk-ui/rsc/panes/ProfileList.qml rename to lsfg-vk-ui/rsc/widgets/List.qml index a7802c9..83b5e95 100644 --- a/lsfg-vk-ui/rsc/panes/ProfileList.qml +++ b/lsfg-vk-ui/rsc/widgets/List.qml @@ -13,6 +13,7 @@ Rectangle { border.color: palette.light border.width: 1 radius: 4 + clip: true ListView { anchors.fill: parent @@ -24,6 +25,7 @@ Rectangle { delegate: Rectangle { width: view.width height: 32 + radius: 4 color: ListView.isCurrentItem ? palette.highlight : "transparent" Text { diff --git a/lsfg-vk-ui/src/backend.cpp b/lsfg-vk-ui/src/backend.cpp index 01dbe25..89ba98a 100644 --- a/lsfg-vk-ui/src/backend.cpp +++ b/lsfg-vk-ui/src/backend.cpp @@ -41,6 +41,16 @@ Backend::Backend() { this->m_profile_list_model = new QStringListModel(profiles, this); + // create active_in list models + this->m_active_in_list_models.reserve(this->m_profiles.size()); + for (const auto& profile : this->m_profiles) { + QStringList active_in; // NOLINT (IWYU) + for (const auto& path : profile.active_in) + active_in.append(QString::fromStdString(path)); + + this->m_active_in_list_models.push_back(new QStringListModel(active_in, this)); + } + // try to select first profile if (!this->m_profiles.empty()) this->m_profile_index = 0; diff --git a/lsfg-vk-ui/src/backend.hpp b/lsfg-vk-ui/src/backend.hpp index 8baaba9..c009bb8 100644 --- a/lsfg-vk-ui/src/backend.hpp +++ b/lsfg-vk-ui/src/backend.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #define getters public @@ -18,34 +19,30 @@ namespace lsfgvk::ui { class Backend : public QObject { Q_OBJECT - Q_PROPERTY(QStringList gpus READ calculateGPUList NOTIFY refreshUI) + Q_PROPERTY(QStringListModel* profiles READ calculateProfileListModel NOTIFY refreshUI) Q_PROPERTY(int profile_index READ getProfileIndex WRITE profileSelected NOTIFY refreshUI) - Q_PROPERTY(bool available READ isValidProfileIndex NOTIFY refreshUI) Q_PROPERTY(QString dll READ getDll WRITE dllUpdated NOTIFY refreshUI) Q_PROPERTY(bool allow_fp16 READ getAllowFP16 WRITE allowFP16Updated NOTIFY refreshUI) + Q_PROPERTY(bool available READ isValidProfileIndex NOTIFY refreshUI) + Q_PROPERTY(QStringListModel* active_in READ calculateActiveInModel NOTIFY refreshUI) + Q_PROPERTY(int active_in_index READ getActiveInIndex WRITE activeInSelected NOTIFY refreshUI) Q_PROPERTY(size_t multiplier READ getMultiplier WRITE multiplierUpdated NOTIFY refreshUI) Q_PROPERTY(float flow_scale READ getFlowScale WRITE flowScaleUpdated NOTIFY refreshUI) Q_PROPERTY(bool performance_mode READ getPerformanceMode WRITE performanceModeUpdated NOTIFY refreshUI) Q_PROPERTY(QString pacing_mode READ getPacingMode WRITE pacingModeUpdated NOTIFY refreshUI) + Q_PROPERTY(QStringList gpus READ calculateGPUList NOTIFY refreshUI) Q_PROPERTY(QString gpu READ getGPU WRITE gpuUpdated NOTIFY refreshUI) public: explicit Backend(); getters: - [[nodiscard]] QStringList calculateGPUList() const { - return this->m_gpu_list; - } - [[nodiscard]] QStringListModel* calculateProfileListModel() const { return this->m_profile_list_model; } - [[nodiscard]] bool isValidProfileIndex() const { - return this->m_profile_index >= 0 && std::cmp_less(this->m_profile_index, this->m_profiles.size()); - } [[nodiscard]] int getProfileIndex() const { return this->m_profile_index; } @@ -61,6 +58,18 @@ namespace lsfgvk::ui { if (!isValidProfileIndex()) return default; \ auto& conf = this->m_profiles[static_cast(this->m_profile_index)]; + [[nodiscard]] bool isValidProfileIndex() const { + return this->m_profile_index >= 0 && std::cmp_less(this->m_profile_index, this->m_profiles.size()); + } + [[nodiscard]] QStringListModel* calculateActiveInModel() const { + if (!isValidProfileIndex()) return nullptr; + return this->m_active_in_list_models.at(static_cast(this->m_profile_index)); + } + [[nodiscard]] int getActiveInIndex() const { + if (!isValidProfileIndex()) return -1; + return static_cast(this->m_active_in_index); + } + [[nodiscard]] size_t getMultiplier() const { VALIDATE_AND_GET_PROFILE(2) return conf.multiplier; @@ -80,6 +89,9 @@ namespace lsfgvk::ui { } throw std::runtime_error("Unknown pacing type in backend"); } + [[nodiscard]] QStringList calculateGPUList() const { + return this->m_gpu_list; + } [[nodiscard]] QString getGPU() const { VALIDATE_AND_GET_PROFILE("Default") return QString::fromStdString(conf.gpu.value_or("Default")); @@ -93,6 +105,11 @@ namespace lsfgvk::ui { emit refreshUI(); } + void activeInSelected(int idx) { + this->m_active_in_index = idx; + emit refreshUI(); + } + #define MARK_DIRTY() \ this->m_dirty.store(true, std::memory_order_relaxed); \ emit refreshUI(); @@ -145,6 +162,34 @@ namespace lsfgvk::ui { MARK_DIRTY() } + Q_INVOKABLE void addActiveIn(const QString& name) { + VALIDATE_AND_GET_PROFILE() + auto& active_in = conf.active_in; + active_in.push_back(name.toStdString()); + + auto& model = this->m_active_in_list_models + .at(static_cast(this->m_profile_index)); + model->insertRow(model->rowCount()); + model->setData(model->index(model->rowCount() - 1), name); + MARK_DIRTY() + } + Q_INVOKABLE void removeActiveIn() { + VALIDATE_AND_GET_PROFILE() + if (this->m_active_in_index < 0 || std::cmp_greater_equal(static_cast(this->m_active_in_index), conf.active_in.size())) + return; + + auto& active_in = conf.active_in; + active_in.erase(active_in.begin() + this->m_active_in_index); + auto& model = this->m_active_in_list_models + .at(static_cast(this->m_profile_index)); + model->removeRow(this->m_active_in_index); + if (!active_in.empty()) + this->m_active_in_index = 0; + else + this->m_active_in_index = -1; + MARK_DIRTY() + } + Q_INVOKABLE void createProfile(const QString& name) { ls::GameConf conf; conf.name = name.toStdString(); @@ -189,10 +234,14 @@ namespace lsfgvk::ui { ls::GlobalConf m_global; std::vector m_profiles; - QStringList m_gpu_list; QStringListModel* m_profile_list_model; int m_profile_index{-1}; + std::vector m_active_in_list_models; + int m_active_in_index{-1}; + + QStringList m_gpu_list; + std::atomic_bool m_dirty{false}; };