mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-04-26 20:31:46 +00:00
refactor(cleanup): synchronize configuration state with ui
This commit is contained in:
parent
2f4b0cc5db
commit
effd469b5e
10 changed files with 358 additions and 49 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Quick)
|
find_package(Qt6 REQUIRED COMPONENTS Quick)
|
||||||
|
|
||||||
set(UI_SOURCES
|
set(UI_SOURCES
|
||||||
"src/ui.cpp"
|
"src/backend.cpp"
|
||||||
"src/main.cpp")
|
"src/main.cpp")
|
||||||
|
|
||||||
set(UI_RESOURCES
|
set(UI_RESOURCES
|
||||||
|
|
@ -28,5 +28,6 @@ target_compile_options(lsfg-vk-ui PRIVATE
|
||||||
-Wno-unsafe-buffer-usage-in-libc-call
|
-Wno-unsafe-buffer-usage-in-libc-call
|
||||||
-Wno-global-constructors)
|
-Wno-global-constructors)
|
||||||
|
|
||||||
target_link_libraries(lsfg-vk-ui PRIVATE
|
target_link_libraries(lsfg-vk-ui
|
||||||
Qt6::Quick)
|
PUBLIC lsfg-vk-common
|
||||||
|
PRIVATE Qt6::Quick)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,51 @@ ApplicationWindow {
|
||||||
minimumHeight: 400
|
minimumHeight: 400
|
||||||
visible: true
|
visible: true
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog_name
|
||||||
|
title: "(...)"
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
|
||||||
|
modal: true
|
||||||
|
dim: true
|
||||||
|
x: (parent.width - width) / 2
|
||||||
|
y: (parent.height - height) / 2
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: nameField
|
||||||
|
placeholderText: "Choose a profile name"
|
||||||
|
selectByMouse: true
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog_confirm
|
||||||
|
title: "Confirm Deletion"
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
|
||||||
|
modal: true
|
||||||
|
dim: true
|
||||||
|
x: (parent.width - width) / 2
|
||||||
|
y: (parent.height - height) / 2
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Are you sure you want to delete the selected profile?"
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SplitView {
|
SplitView {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
orientation: Qt.Horizontal
|
orientation: Qt.Horizontal
|
||||||
|
|
@ -30,20 +75,37 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileList {
|
ProfileList {
|
||||||
|
model: backend.profiles
|
||||||
|
selected: backend.profile_index
|
||||||
|
onSelect: (index) => backend.profile_index = index
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
text: "Create New Profile"
|
text: "Create New Profile"
|
||||||
Layout.fillWidth: true
|
onClicked: {
|
||||||
|
dialog_name.title = "Create New Profile"
|
||||||
|
nameField.text = ""
|
||||||
|
|
||||||
|
dialog_name.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
text: "Rename Profile"
|
text: "Rename Profile"
|
||||||
Layout.fillWidth: true
|
onClicked: {
|
||||||
|
dialog_name.title = "Rename Profile"
|
||||||
|
nameField.text = "(...)"
|
||||||
|
|
||||||
|
dialog_name.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
text: "Delete Profile"
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
text: "Delete Profile"
|
||||||
|
onClicked: {
|
||||||
|
dialog_confirm.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,56 +116,91 @@ ApplicationWindow {
|
||||||
name: "Global Settings"
|
name: "Global Settings"
|
||||||
|
|
||||||
GroupEntry {
|
GroupEntry {
|
||||||
title: "Browse for Lossless.dll"
|
title: "Path to Lossless Scaling"
|
||||||
description: "Change the location of Lossless.dll"
|
description: "Change the location of Lossless.dll"
|
||||||
|
|
||||||
FileEdit {}
|
FileEdit {
|
||||||
|
title: "Select Lossless.dll"
|
||||||
|
filter: "Dynamic Link Library Files (*.dll)"
|
||||||
|
|
||||||
|
text: backend.dll
|
||||||
|
onUpdate: (text) => backend.dll = text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupEntry {
|
GroupEntry {
|
||||||
title: "Allow half-precision"
|
title: "Allow half-precision"
|
||||||
description: "Allow acceleration through half-precision"
|
description: "Allow acceleration through half-precision"
|
||||||
|
|
||||||
CheckBox {}
|
CheckBox {
|
||||||
|
checked: backend.allow_fp16
|
||||||
|
onToggled: backend.allow_fp16 = checked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
name: "Profile Settings"
|
name: "Profile Settings"
|
||||||
|
enabled: backend.available
|
||||||
|
|
||||||
GroupEntry {
|
GroupEntry {
|
||||||
title: "Multiplier"
|
title: "Multiplier"
|
||||||
description: "Control the amount of generated frames"
|
description: "Control the amount of generated frames"
|
||||||
|
|
||||||
SpinBox { from: 2; to: 100 }
|
SpinBox {
|
||||||
|
from: 2
|
||||||
|
to: 100
|
||||||
|
|
||||||
|
value: backend.multiplier
|
||||||
|
onValueModified: backend.multiplier = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupEntry {
|
GroupEntry {
|
||||||
title: "Flow Scale"
|
title: "Flow Scale"
|
||||||
description: "Lower the internal motion estimation resolution"
|
description: "Lower the internal motion estimation resolution"
|
||||||
|
|
||||||
FlowSlider { from: 0.25; to: 1.00 }
|
FlowSlider {
|
||||||
|
from: 0.25
|
||||||
|
to: 1.00
|
||||||
|
|
||||||
|
value: backend.flow_scale
|
||||||
|
onUpdate: (value) => backend.flow_scale = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupEntry {
|
GroupEntry {
|
||||||
title: "Performance Mode"
|
title: "Performance Mode"
|
||||||
description: "Use a significantly lighter frame generation modeln"
|
description: "Use a significantly lighter frame generation modeln"
|
||||||
|
|
||||||
CheckBox {}
|
CheckBox {
|
||||||
|
checked: backend.performance_mode
|
||||||
|
onToggled: backend.performance_mode = checked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupEntry {
|
GroupEntry {
|
||||||
title: "Pacing Mode"
|
title: "Pacing Mode"
|
||||||
description: "Change how frames are presented to the display"
|
description: "Change how frames are presented to the display"
|
||||||
|
|
||||||
ComboBox { model: ["None"] }
|
ComboBox {
|
||||||
|
model: ["None"]
|
||||||
|
|
||||||
|
currentValue: backend.pacing_mode
|
||||||
|
onActivated: (index) => backend.pacing_mode = model[index]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupEntry {
|
GroupEntry {
|
||||||
title: "GPU"
|
title: "GPU"
|
||||||
description: "Select which GPU to use for frame generation"
|
description: "Select which GPU to use for frame generation"
|
||||||
|
|
||||||
ComboBox { model: ["Auto"] }
|
ComboBox {
|
||||||
|
model: ["Default"]
|
||||||
|
|
||||||
|
currentValue: backend.gpu
|
||||||
|
onActivated: (index) => backend.gpu = model[index]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@ import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
property var model
|
||||||
|
property int selected
|
||||||
|
signal select(int index)
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
id: root
|
id: root
|
||||||
|
|
@ -12,5 +16,31 @@ Rectangle {
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
id: view
|
||||||
|
|
||||||
|
model: root.model
|
||||||
|
currentIndex: root.selected
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: view.width
|
||||||
|
height: 32
|
||||||
|
color: ListView.isCurrentItem ? palette.highlight : "transparent"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
|
||||||
|
text: display
|
||||||
|
color: ListView.isCurrentItem ? palette.highlightedText : palette.text
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.select(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,34 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
property string title
|
||||||
|
property string filter
|
||||||
|
property string text
|
||||||
|
signal update(string text)
|
||||||
|
|
||||||
id: root
|
id: root
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
Layout.fillWidth: true;
|
Layout.fillWidth: true;
|
||||||
Layout.maximumWidth: 450;
|
Layout.maximumWidth: 450;
|
||||||
|
|
||||||
|
text: root.text
|
||||||
|
onEditingFinished: root.update(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
icon.name: "folder-open"
|
icon.name: "folder-open"
|
||||||
|
onClicked: picker.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDialog {
|
||||||
|
id: picker
|
||||||
|
title: root.title
|
||||||
|
nameFilters: [root.filter, "All Files (*)"]
|
||||||
|
onAccepted: root.update(selectedFile.toString().replace("file://", ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,30 @@ import QtQuick.Layouts
|
||||||
RowLayout {
|
RowLayout {
|
||||||
property real from
|
property real from
|
||||||
property real to
|
property real to
|
||||||
|
property real value
|
||||||
|
signal update(real value)
|
||||||
|
|
||||||
id: root
|
id: root
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
Slider {
|
Slider {
|
||||||
Layout.fillWidth: true;
|
Layout.fillWidth: true;
|
||||||
Layout.maximumWidth: 450;
|
Layout.maximumWidth: 450;
|
||||||
|
|
||||||
|
value: root.value
|
||||||
|
from: root.from
|
||||||
|
to: root.to
|
||||||
|
|
||||||
|
onMoved: root.update(value.toFixed(2))
|
||||||
|
onValueChanged: label.text = (value * 100).toFixed(0) + "%"
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.preferredWidth: 40;
|
Layout.preferredWidth: 40;
|
||||||
|
|
||||||
|
id: label
|
||||||
text: "0%"
|
text: "0%"
|
||||||
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,43 @@
|
||||||
#include "backend.hpp"
|
#include "backend.hpp"
|
||||||
|
#include "lsfg-vk-common/configuration/config.hpp"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QStringListModel>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QString>
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
using namespace lsfgvk::ui;
|
using namespace lsfgvk::ui;
|
||||||
|
|
||||||
Backend::Backend(QObject* parent) : QObject(parent) {
|
Backend::Backend() {
|
||||||
|
// load configuration
|
||||||
|
ls::Configuration config{false};
|
||||||
|
config.reload();
|
||||||
|
|
||||||
|
this->m_global = config.getGlobalConf();
|
||||||
|
this->m_profiles = config.getProfiles();
|
||||||
|
|
||||||
|
// create profile list model
|
||||||
|
QStringList profiles; // NOLINT (IWYU)
|
||||||
|
for (const auto& profile : this->m_profiles)
|
||||||
|
profiles.append(QString::fromStdString(profile.name));
|
||||||
|
|
||||||
|
this->m_profile_list_model = new QStringListModel(profiles, this);
|
||||||
|
|
||||||
|
// try to select first profile
|
||||||
|
if (!this->m_profiles.empty())
|
||||||
|
this->m_profile_index = 0;
|
||||||
|
|
||||||
|
// spawn saving thread
|
||||||
|
std::thread([this]() {
|
||||||
|
while (true) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
|
|
||||||
|
if (!this->m_dirty.exchange(false))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::cerr << "configuration updated >:3" << '\n';
|
||||||
|
}
|
||||||
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,158 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "lsfg-vk-common/configuration/config.hpp"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QStringListModel>
|
||||||
|
#include <QString>
|
||||||
|
#include <atomic>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#define getters public
|
||||||
|
#define setters public
|
||||||
|
|
||||||
namespace lsfgvk::ui {
|
namespace lsfgvk::ui {
|
||||||
|
|
||||||
|
/// Class tying ui and configuration together
|
||||||
class Backend : public QObject {
|
class Backend : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
Q_PROPERTY(QStringListModel* profiles READ calculateProfileListModel NOTIFY refreshUI)
|
||||||
explicit Backend(QObject* parent = nullptr);
|
Q_PROPERTY(int profile_index READ getProfileIndex WRITE profileSelected NOTIFY refreshUI)
|
||||||
private:
|
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(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(QString gpu READ getGPU WRITE gpuUpdated NOTIFY refreshUI)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Backend();
|
||||||
|
|
||||||
|
getters:
|
||||||
|
[[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;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QString getDll() const {
|
||||||
|
return QString::fromStdString(this->m_global.dll.value_or(""));
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool getAllowFP16() const {
|
||||||
|
return this->m_global.allow_fp16;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VALIDATE_AND_GET_PROFILE(default) \
|
||||||
|
if (!isValidProfileIndex()) return default; \
|
||||||
|
auto& conf = this->m_profiles[static_cast<size_t>(this->m_profile_index)];
|
||||||
|
|
||||||
|
[[nodiscard]] size_t getMultiplier() const {
|
||||||
|
VALIDATE_AND_GET_PROFILE(2)
|
||||||
|
return conf.multiplier;
|
||||||
|
}
|
||||||
|
[[nodiscard]] float getFlowScale() const {
|
||||||
|
VALIDATE_AND_GET_PROFILE(1.0F)
|
||||||
|
return conf.flow_scale;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool getPerformanceMode() const {
|
||||||
|
VALIDATE_AND_GET_PROFILE(false)
|
||||||
|
return conf.performance_mode;
|
||||||
|
}
|
||||||
|
[[nodiscard]] QString getPacingMode() const {
|
||||||
|
VALIDATE_AND_GET_PROFILE("None")
|
||||||
|
switch (conf.pacing) {
|
||||||
|
case ls::Pacing::None: return "None";
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Unknown pacing type in backend");
|
||||||
|
}
|
||||||
|
[[nodiscard]] QString getGPU() const {
|
||||||
|
VALIDATE_AND_GET_PROFILE("Default")
|
||||||
|
return QString::fromStdString(conf.gpu.value_or("Default"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef VALIDATE_AND_GET_PROFILE
|
||||||
|
|
||||||
|
setters:
|
||||||
|
void profileSelected(int idx) {
|
||||||
|
this->m_profile_index = idx;
|
||||||
|
emit refreshUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MARK_DIRTY() \
|
||||||
|
this->m_dirty.store(true, std::memory_order_relaxed); \
|
||||||
|
emit refreshUI();
|
||||||
|
|
||||||
|
void dllUpdated(const QString& dll) {
|
||||||
|
auto& conf = this->m_global;
|
||||||
|
if (dll.trimmed().isEmpty())
|
||||||
|
conf.dll = std::nullopt;
|
||||||
|
else
|
||||||
|
conf.dll = dll.toStdString();
|
||||||
|
MARK_DIRTY()
|
||||||
|
}
|
||||||
|
void allowFP16Updated(bool allow_fp16) {
|
||||||
|
auto& conf = this->m_global;
|
||||||
|
conf.allow_fp16 = allow_fp16;
|
||||||
|
MARK_DIRTY()
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VALIDATE_AND_GET_PROFILE() \
|
||||||
|
if (!isValidProfileIndex()) return; \
|
||||||
|
auto& conf = this->m_profiles[static_cast<size_t>(this->m_profile_index)];
|
||||||
|
|
||||||
|
void multiplierUpdated(size_t multiplier) {
|
||||||
|
VALIDATE_AND_GET_PROFILE()
|
||||||
|
conf.multiplier = multiplier;
|
||||||
|
MARK_DIRTY()
|
||||||
|
}
|
||||||
|
void flowScaleUpdated(float flow_scale) {
|
||||||
|
VALIDATE_AND_GET_PROFILE()
|
||||||
|
conf.flow_scale = flow_scale;
|
||||||
|
MARK_DIRTY()
|
||||||
|
}
|
||||||
|
void performanceModeUpdated(bool performance_mode) {
|
||||||
|
VALIDATE_AND_GET_PROFILE()
|
||||||
|
conf.performance_mode = performance_mode;
|
||||||
|
MARK_DIRTY()
|
||||||
|
}
|
||||||
|
void pacingModeUpdated(const QString& pacing_mode) {
|
||||||
|
VALIDATE_AND_GET_PROFILE()
|
||||||
|
if (pacing_mode == "None")
|
||||||
|
conf.pacing = ls::Pacing::None;
|
||||||
|
MARK_DIRTY()
|
||||||
|
}
|
||||||
|
void gpuUpdated(const QString& gpu) {
|
||||||
|
VALIDATE_AND_GET_PROFILE()
|
||||||
|
if (gpu.trimmed().isEmpty())
|
||||||
|
conf.gpu = std::nullopt;
|
||||||
|
else
|
||||||
|
conf.gpu.emplace(gpu.toStdString());
|
||||||
|
MARK_DIRTY()
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef VALIDATE_AND_GET_PROFILE
|
||||||
|
#undef MARK_DIRTY
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void refreshUI();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ls::GlobalConf m_global;
|
||||||
|
std::vector<ls::GameConf> m_profiles;
|
||||||
|
|
||||||
|
QStringListModel* m_profile_list_model;
|
||||||
|
int m_profile_index{-1};
|
||||||
|
|
||||||
|
std::atomic_bool m_dirty{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "ui.hpp"
|
#include "backend.hpp"
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
|
|
@ -12,9 +13,9 @@ int main(int argc, char* argv[]) {
|
||||||
QGuiApplication::setApplicationDisplayName("lsfg-vk-ui");
|
QGuiApplication::setApplicationDisplayName("lsfg-vk-ui");
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
UI ui;
|
Backend backend;
|
||||||
|
|
||||||
engine.rootContext()->setContextProperty("ui", &ui);
|
engine.rootContext()->setContextProperty("backend", &backend);
|
||||||
engine.load("qrc:/rsc/UI.qml");
|
engine.load("qrc:/rsc/UI.qml");
|
||||||
|
|
||||||
return QGuiApplication::exec();
|
return QGuiApplication::exec();
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
#include "ui.hpp"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace lsfgvk::ui;
|
|
||||||
|
|
||||||
UI::UI(QObject* parent) : QObject(parent) {
|
|
||||||
std::cerr << "Hello, world!" << '\n';
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
namespace lsfgvk::ui {
|
|
||||||
|
|
||||||
class UI : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit UI(QObject* parent = nullptr);
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue