From d14258df8ecf5193d60d83fc2c227cb05d060e76 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 30 Jan 2024 03:32:21 -0800 Subject: [PATCH] feat: add Variants type for creating instances --- CMakeLists.txt | 1 + src/cpp/variants.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++ src/cpp/variants.hpp | 40 +++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 src/cpp/variants.cpp create mode 100644 src/cpp/variants.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b33eb8f..760a618 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ qt_standard_project_setup(REQUIRES 6.6) qt_add_executable(qtshell src/cpp/main.cpp src/cpp/shell.cpp + src/cpp/variants.cpp ) qt_add_qml_module(qtshell URI QtShell) diff --git a/src/cpp/variants.cpp b/src/cpp/variants.cpp new file mode 100644 index 0000000..2b333c5 --- /dev/null +++ b/src/cpp/variants.cpp @@ -0,0 +1,94 @@ +#include "variants.hpp" +#include +#include + +#include +#include + +void Variants::setVariants(QVariantList variants) { + this->mVariants = std::move(variants); + qDebug() << "configurations updated:" << this->mVariants; + + this->updateVariants(); +} + +void Variants::componentComplete() { + qDebug() << "configure ready"; + + this->updateVariants(); +} + +void Variants::updateVariants() { + if (this->mComponent == nullptr) { + qWarning() << "Variants instance does not have a component specified"; + return; + } + + // clean up removed entries + for (auto iter = this->instances.values.begin(); iter < this->instances.values.end();) { + if (this->mVariants.contains(iter->first)) { + iter++; + } else { + iter->second->deleteLater(); + iter = this->instances.values.erase(iter); + } + } + + for (auto iter = this->mVariants.begin(); iter < this->mVariants.end(); iter++) { + auto& variantObj = *iter; + if (!variantObj.canConvert()) { + qWarning() << "value passed to Variants is not an object and will be ignored:" << variantObj; + } else { + auto variant = variantObj.value(); + + for (auto iter2 = this->mVariants.begin(); iter2 < iter; iter2++) { + if (*iter2 == variantObj) { + qWarning() << "same value specified twice in Variants, duplicates will be ignored:" + << variantObj; + goto outer; + } + } + + if (this->instances.contains(variant)) { + continue; // we dont need to recreate this one + } + + auto* instance = this->mComponent->createWithInitialProperties(variant, nullptr); + + if (instance == nullptr) { + qWarning() << "failed to create variant with object" << variant; + continue; + } + + instance->setParent(this); + this->instances.insert(variant, instance); + } + + outer:; + } +} + +template +bool AwfulMap::contains(const K& key) const { + return std::ranges::any_of(this->values, [&](const QPair& pair) { + return pair.first == key; + }); +} + +template +void AwfulMap::insert(K key, V value) { + this->values.push_back(QPair(key, value)); +} + +template +bool AwfulMap::remove(const K& key) { + for (auto iter = this->values.begin(); iter < this->values.end(); iter++) { + if (iter->first == key) { + this->values.erase(iter); + + return true; + } + } + + return false; +} diff --git a/src/cpp/variants.hpp b/src/cpp/variants.hpp new file mode 100644 index 0000000..a906c7f --- /dev/null +++ b/src/cpp/variants.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +// extremely inefficient map +template +class AwfulMap { +public: + [[nodiscard]] bool contains(const K& key) const; + void insert(K key, V value); // assumes no duplicates + bool remove(const K& key); // returns true if anything was removed + QList> values; +}; + +class Variants: public QObject, public QQmlParserStatus { + Q_OBJECT; + Q_PROPERTY(QQmlComponent* component MEMBER mComponent); + Q_PROPERTY(QVariantList variants MEMBER mVariants WRITE setVariants); + Q_CLASSINFO("DefaultProperty", "component"); + QML_ELEMENT; + +public: + explicit Variants(QObject* parent = nullptr): QObject(parent) {} + + void classBegin() override {}; + void componentComplete() override; + +private: + void setVariants(QVariantList variants); + void updateVariants(); + + QQmlComponent* mComponent = nullptr; + QVariantList mVariants; + AwfulMap instances; +};