diff --git a/CMake b/CMake index c144d4d..f96d16e 160000 --- a/CMake +++ b/CMake @@ -1 +1 @@ -Subproject commit c144d4d957bf63dafe9c2798b4660168cbd848e4 +Subproject commit f96d16ec9be058fc35f3966e0a8dfe7d62ad3fb1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b2f811..d2fa71f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2018-2021 QuasarApp. +# Copyright (C) 2018-2025 QuasarApp. # Distributed under the lgplv3 software license, see the accompanying # Everyone is permitted to copy and distribute verbatim copies # of this license document, but changing it is not allowed. @@ -14,20 +14,13 @@ if(TARGET ${PROJECT_NAME}) endif() -if ( NOT DEFINED VIEWSOLUTIONS_EXAMPLES ) - set(VIEWSOLUTIONS_EXAMPLES ON) - - if (DEFINED TARGET_PLATFORM_TOOLCHAIN) - if (${TARGET_PLATFORM_TOOLCHAIN} STREQUAL "wasm32") - set(VIEWSOLUTIONS_EXAMPLES OFF) - endif() - endif() - - if (ANDROID) - set(VIEWSOLUTIONS_EXAMPLES OFF) - endif() +if (ANDROID OR IOS) + option(VIEWSOLUTIONS_EXAMPLES "Build examples" OFF) +else() + option(VIEWSOLUTIONS_EXAMPLES "Build examples" ON) endif() + include(CMake/QuasarApp.cmake) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick QuickControls2 REQUIRED) @@ -36,7 +29,6 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick QuickControls2 REQUIRED add_subdirectory(ViewSolutions) if (VIEWSOLUTIONS_EXAMPLES ) - message("DISABLE_EXAMPLES = ${DISABLE_EXAMPLES}") add_subdirectory(Examples) endif() diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index 804a889..432e37b 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2018-2021 QuasarApp. +# Copyright (C) 2018-2025 QuasarApp. # Distributed under the lgplv3 software license, see the accompanying # Everyone is permitted to copy and distribute verbatim copies # of this license document, but changing it is not allowed. diff --git a/Examples/src/main.cpp b/Examples/src/main.cpp index 8c77fd4..83b35f1 100644 --- a/Examples/src/main.cpp +++ b/Examples/src/main.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** # -# Copyright (C) 2018-2021 QuasarApp. +# Copyright (C) 2018-2025 QuasarApp. # Distributed under the lgplv3 software license, see the accompanying # Everyone is permitted to copy and distribute verbatim copies # of this license document, but changing it is not allowed. diff --git a/Examples/src/main.qml b/Examples/src/main.qml index ab8022f..e7383ef 100644 --- a/Examples/src/main.qml +++ b/Examples/src/main.qml @@ -1,7 +1,7 @@ /**************************************************************************** ** # -# Copyright (C) 2018-2021 QuasarApp. +# Copyright (C) 2018-2025 QuasarApp. # Distributed under the lgplv3 software license, see the accompanying # Everyone is permitted to copy and distribute verbatim copies # of this license document, but changing it is not allowed. diff --git a/ViewSolutions/CMakeLists.txt b/ViewSolutions/CMakeLists.txt index ae3ebb1..d995886 100644 --- a/ViewSolutions/CMakeLists.txt +++ b/ViewSolutions/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2018-2021 QuasarApp. +# Copyright (C) 2018-2025 QuasarApp. # Distributed under the lgplv3 software license, see the accompanying # Everyone is permitted to copy and distribute verbatim copies # of this license document, but changing it is not allowed. @@ -18,6 +18,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) file(GLOB SOURCE_CPP "src/*.cpp" + "src/*.h" "src/*.qrc" ) diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml new file mode 100644 index 0000000..b6f1c42 --- /dev/null +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml @@ -0,0 +1,38 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + + +import QtQuick +import QtQuick.Controls + +Control { + property string title: "" + + // shows the back button with text + property bool buttonBack: true + + // shows close button on the ActivityProcessor header + property bool closeButton: true + // attach to this property link to ActivityProcessor (if is it not to abble atomaticaly) + property var activityProcessorLink: null + + // emit this signal when you finish work on this page. The ActivityProcessor will inoke pop method. + signal finish(); + + // invoked by ActivityProcessor when the will be invoked resetState of ActivityProcessor + property var resetState: () => {} + + // this is lambda function with required action of this page. + // If is it not null then MainActivityProcessor will execute this action and forbide distroy this UI. + property var requireAction: null + + // This is call back function, If this function exists its will be called before pop object from main activity, but if requireAction is null. + // Note: this field will fill if you add callback function on newActivityWithProp, newActivity or newActivityFromComponent functions! + property var activityCallBack: () => {} + property bool saveChangesInUnsaved: false + +} diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml new file mode 100644 index 0000000..00364c7 --- /dev/null +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml @@ -0,0 +1,298 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + + +import QtQuick +import QtQuick.Controls + +Page { + id: root + + // use Comonent delegates only + property alias initialItem: stackView.initialItem + property alias currentItem: stackView.currentItem + property int titlesAligh: Text.AlignLeft + + property alias depth: stackView.depth + property bool cache: true + property bool enableHeader: true + + padding: 0 + clip: true + + background: Item{} + + header: ActivityProcessorHeader { + id: headerView + visible: root.enableHeader + title: { + if (root.enableHeader && stackView.currentItem && stackView.currentItem.title) { + return stackView.currentItem.title + } + + return "" + } + + backButton: root.enableHeader && stackView.depth > 1 && (stackView.currentItem && stackView.currentItem.buttonBack) + + closeButton: root.enableHeader && (stackView.currentItem && stackView.currentItem.closeButton) + titlesAligh: root.titlesAligh + onBackClicked: { + root.popItem() + } + + } + + contentItem: StackView { + id: stackView + + Connections { + target: (stackView.currentItem && stackView.currentItem.finish)? stackView.currentItem : null + + function onFinish() { + root.popItem() + } + } + + padding: 0 + + implicitWidth: (stackView.currentItem)? stackView.currentItem.implicitWidth: 0 + implicitHeight: (stackView.currentItem)? stackView.currentItem.implicitHeight: 0 + + property int durationAnimation: 400 + popEnter: Transition { + ParallelAnimation { + NumberAnimation { + properties: "opacity" + from: 0 + to: 1 + duration: stackView.durationAnimation + } + NumberAnimation { + properties: "x" + from: (stackView.mirrored ? -1 : 1) * -stackView.width + to: 0 + duration: stackView.durationAnimation + easing.type: Easing.OutCubic + } + } + } + + popExit: Transition { + ParallelAnimation { + NumberAnimation { + properties: "opacity" + from: 1 + to: 0 + duration: stackView.durationAnimation / 2 + } + NumberAnimation { + properties: "x" + from: 0 + to: (stackView.mirrored ? -1 : 1) * stackView.width + duration: stackView.durationAnimation + easing.type: Easing.OutCubic + } + } + } + + pushEnter: Transition { + ParallelAnimation { + NumberAnimation { + properties: "opacity" + from: 0 + to: 1 + duration: stackView.durationAnimation + } + NumberAnimation { + properties: "x" + from: (stackView.mirrored ? -1 : 1) * stackView.width + to: 0 + duration: stackView.durationAnimation + easing.type: Easing.OutCubic + } + } + } + + pushExit: Transition { + ParallelAnimation { + NumberAnimation { + properties: "opacity" + from: 1 + to: 0 + duration: stackView.durationAnimation / 2 + } + NumberAnimation { + properties: "x" + from: 0 + to: (stackView.mirrored ? -1 : 1) * -stackView.width + duration: stackView.durationAnimation + easing.type: Easing.OutCubic + } + } + } + } + + + // create new activity from component with model activityModel, after drop this activity will be called callback function + // Note The callback function works only with ActivityPage childs. + function newActivityFromComponent(component, activityModel, callback) { + var activity = component.createObject(stackView); + if (activity === null) { + // Error Handling + console.error("Error creating Activity object. " + component.errorString()); + return; + } + + if (activityModel && typeof(activity.model) != "undefined") { + activity.model = activityModel; + } + + + if (typeof(activity.activityCallBack) === "function" + && typeof(callback) === "function") { + activity.activityCallBack = callback; + } + stackView.push(activity); + + return activity; + } + + // create new activity from file with model activityModel, after drop this activity will be called callback function + // Note The callback function works only with ActivityPage childs. + function newActivity(viewFile, activityModel, callback) { + + if (!viewFile || !viewFile.length) { + console.error("Failed to create activity. view object is invalid"); + return; + } + + var component = Qt.createComponent(viewFile); + + if (component.status === Component.Ready) { + + + var activity = component.createObject(stackView); + if (activity === null) { + // Error Handling + console.error("Error creating Activity object"); + return; + } + + if (activityModel && typeof(activity.model) != "undefined") { + activity.model = activityModel; + } + + + stackView.push(activity); + + if (typeof(activity.activityCallBack) === "function" + && typeof(callback) === "function") { + activity.activityCallBack = callback; + } + return activity; + + } else if (component.status === Component.Error) { + // Error Handling + console.log("Error loading component:", component.errorString()); + } + } + + // create new activity from file with custom propery list "properties", after drop this activity will be called callback function + // Note The callback function works only with ActivityPage childs. + function newActivityWithProp(viewFile, properties, callback) { + + if (!viewFile || !viewFile.length) { + console.error("Failed to create activity. view object is invalid"); + return; + } + + var component = Qt.createComponent(viewFile); + + if (component.status === Component.Ready) { + + var activity = component.createObject(stackView, properties); + if (activity === null) { + // Error Handling + console.error("Error creating Activity object"); + return; + } + + stackView.push(activity); + + if (typeof(activity.activityCallBack) === "function" + && typeof(callback) === "function") { + activity.activityCallBack = callback; + } + return activity; + + } else if (component.status === Component.Error) { + // Error Handling + console.log("Error loading component:", component.errorString()); + } + } + + // create new activity from component with custom propery list "properties", after drop this activity will be called callback function + // Note The callback function works only with ActivityPage childs. + function newActivityFromComponentWithProp(component, properties, callback) { + + var activity = component.createObject(stackView, properties); + if (activity === null) { + // Error Handling + console.error("Error creating Activity object. " + component.errorString()); + return; + } + + stackView.push(activity); + + if (typeof(activity.activityCallBack) === "function" + && typeof(callback) === "function") { + activity.activityCallBack = callback; + } + + return activity; + } + + function popItem() { + let actionRequire = stackView.currentItem && stackView.currentItem.requireAction && stackView.currentItem.requireAction(); + + if (actionRequire) { + return false; + } + + var item = stackView.pop(); + if (item) { + if (item.activityCallBack) { + item.activityCallBack() + } + item.destroy(1000); + } + + return true; + } + + function resetState() { + if (cache && stackView.depth < 3) { + + // About limitation: the stackView.pop can't change focus to first element if the elements depth bigger then 2. + + while(stackView.depth > 1) { + if (!popItem()) { + break; + } + } + if (stackView.currentItem && typeof(stackView.currentItem.resetState) === "function") { + stackView.currentItem.resetState(); + } + + } else { + stackView.clear() + stackView.push(stackView.initialItem) + } + } + +} diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml new file mode 100644 index 0000000..c7b3aca --- /dev/null +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml @@ -0,0 +1,58 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + + +ToolBar { + + id: root + property int titlesAligh: Text.AlignHCenter + + property string title: "" + property bool titleUppercase: true + property bool backButton: false + property bool closeButton: false + + signal backClicked() + signal closeClicked() + + contentItem: RowLayout { + + + ToolButton { + + visible: root.backButton + text: "<<" + + onClicked: { + root.backClicked() + } + } + + Text { + id: centralTitle + text: (root.titleUppercase)? root.title.toUpperCase(): root.title + horizontalAlignment: root.titlesAligh + Layout.fillWidth: true; + + } + + ToolButton { + Layout.alignment: Qt.AlignRight + text: "x" + onClicked: root.closeClicked() + visible: root.closeButton + + } + + } +} + + diff --git a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml b/ViewSolutions/src/ViewSolutionsModule/ImageView.qml index b5a4b81..5613063 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ImageView.qml @@ -1,47 +1,56 @@ -import QtQuick 2.15 -import QtQuick.Layouts 1.14 -import QtQuick.Controls 2.15 -import QtQuick.Controls.Material 2.15 -import QtQuick.Controls.Universal 2.15 +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# -Item { +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick.Controls.Material +import QtQuick.Controls.Universal +import QtQuick.Effects + +AbstractButton { id: root property string source: "" property alias imagesource: sourceImg - property string text: "" - property bool hover: false - property bool presed: false - property bool selected: false - property real power: 1.0 property string toolTip: "" - property color textColor: Material.color(Material.Grey) + property color textColor: Material.foreground - property color background: colorPicker.pick(source) - property color selectedColor: "#5de2ff" - property color borderColor: "#00000000" - property color hoverColor: "#00000000" - - signal clicked(var mouse); + property color backgroundColor: Material.background + property color selectedColor: Material.accent + property color hoverColor: Material.accent Connections { target: sourceImg function onStatusChanged(status) { if (status === Image.Ready) { - root.background = colorPicker.pick(source); + root.backgroundColor = colorPicker.pick(source); } } } - Item { + hoverEnabled: true + + opacity: { + if (enabled) { + return 1 + } + + return 0.5 + } + + contentItem: Control { id: privateData property int rootMinSize: Math.min(root.height, root.width) - anchors.margins: (root.hover && !presed)? rootMinSize * 0.01: rootMinSize * 0.1 - + bottomPadding : 8 property real rx : 0 property real ry : 0 property real rz : 0 @@ -53,20 +62,41 @@ Item { } } - anchors.fill: parent - Rectangle { - id: background - color: root.background - border.color: (root.hover)? root.hoverColor: root.selected? root.selectedColor: "#00000000" - border.width: 4 - anchors.fill: parent - radius: border.width * 2 - - Behavior on border.color { - ColorAnimation { - duration: 250 - } + Behavior on rx { + NumberAnimation { + easing.type: Easing.OutExpo + duration: 550 } + } + + Behavior on ry { + NumberAnimation { + easing.type: Easing.OutExpo + duration: 550 + } + } + + Behavior on rz { + NumberAnimation { + easing.type: Easing.OutExpo + duration: 550 + } + } + + background: Rectangle { + color: { + + if (root.hovered) { + return root.hoverColor + } + + if (root.checked) { + return root.selectedColor + } + + return root.backgroundColor + } + radius: 16 Behavior on color { ColorAnimation { @@ -75,34 +105,56 @@ Item { } } - ColumnLayout { - Image { - id: sourceImg - source: root.source + contentItem: ColumnLayout { + spacing: 8 - clip: true - fillMode: Image.PreserveAspectCrop - Layout.fillHeight: true + + MultiEffect { + id: imgEffect Layout.fillWidth: true - Layout.margins: 5 + Layout.fillHeight: true + source: Image { + id: sourceImg + source: root.source + clip: true + fillMode: Image.PreserveAspectCrop + width: imgEffect.width + height: imgEffect.height + } + + maskEnabled: true + maskSource: ShaderEffectSource { + sourceItem: Rectangle { + radius: 16 + width: imgEffect.width + height: imgEffect.height + color: "Black" + + Rectangle { + color: "Black" + + anchors.bottom: parent.bottom + height: 20 + width: parent.width + } + } + } } + Label { text: root.text visible: text.length - Layout.preferredHeight: root.height * 0.1 Layout.fillWidth: true - color: textColor - font.pixelSize: root.height * 0.09 - font.bold: true + color: root.textColor + font: root.font horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } - anchors.fill: parent } transform: [ @@ -126,7 +178,7 @@ Item { ToolTip { parent: root - visible: root.hover && text.length + visible: root.hovered && text.length text: root.toolTip delay: 500 @@ -134,38 +186,23 @@ Item { MouseArea { - + acceptedButtons: Qt.NoButton hoverEnabled: true; - onEntered: { - hover = true - } - onExited: { - hover = false; privateData.ry = 0 privateData.rx = 0 } onPositionChanged: (mouse) => { - let fromCenter = root.width / 2 - privateData.ry = -((mouse.x - fromCenter) / (fromCenter * 0.05)) * power + let fromCenter = root.width / 2 + privateData.ry = -((mouse.x - fromCenter) / (fromCenter * 0.05)) * root.power - fromCenter = root.height / 2 - privateData.rx = ((mouse.y - fromCenter) / (fromCenter * 0.05)) * power + fromCenter = root.height / 2 + privateData.rx = ((mouse.y - fromCenter) / (fromCenter * 0.05)) * root.power - } - - onPressed: { - presed = true; - } - - onReleased: (mouse) => { - presed = false; - - root.clicked(mouse) - } + } anchors.fill: parent diff --git a/ViewSolutions/src/ViewSolutionsModule/ViewPortDelegatBase.qml b/ViewSolutions/src/ViewSolutionsModule/ViewPortDelegatBase.qml index d0b87ac..6570b8d 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ViewPortDelegatBase.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ViewPortDelegatBase.qml @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + import QtQuick 2.15 import QtQuick.Layouts 1.14 import QtQuick.Controls 2.15 diff --git a/ViewSolutions/src/ViewSolutionsModule/ViewPortGradientPage.qml b/ViewSolutions/src/ViewSolutionsModule/ViewPortGradientPage.qml index c488635..990455d 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ViewPortGradientPage.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ViewPortGradientPage.qml @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + import QtQuick 2.15 import QtQuick.Layouts 1.14 import QtQuick.Controls 2.15 diff --git a/ViewSolutions/src/ViewSolutionsModule/ViewPortPage.qml b/ViewSolutions/src/ViewSolutionsModule/ViewPortPage.qml index fbb2fcf..aa8922a 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ViewPortPage.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ViewPortPage.qml @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + import QtQuick 2.15 import QtQuick.Layouts 1.14 import QtQuick.Controls 2.15 diff --git a/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticGradientPage.qml b/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticGradientPage.qml index 126f91d..1715153 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticGradientPage.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticGradientPage.qml @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 diff --git a/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticPage.qml b/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticPage.qml index 4473d87..ce1dc8a 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticPage.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ViewPortStaticPage.qml @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 diff --git a/ViewSolutions/src/ViewSolutionsModule/ViewSolutionsControl.qml b/ViewSolutions/src/ViewSolutionsModule/ViewSolutionsControl.qml index 37f5c59..6851012 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ViewSolutionsControl.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ViewSolutionsControl.qml @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 diff --git a/ViewSolutions/src/ViewSolutionsModule/qmldir b/ViewSolutions/src/ViewSolutionsModule/qmldir index 07e46e3..80985fd 100644 --- a/ViewSolutions/src/ViewSolutionsModule/qmldir +++ b/ViewSolutions/src/ViewSolutionsModule/qmldir @@ -1,4 +1,7 @@ module ViewSolutionsModule +ActivityPage 1.0 ActivityPage.qml +ActivityProcessor 1.0 ActivityProcessor.qml +ActivityProcessorHeader 1.0 ActivityProcessorHeader.qml ImageView 1.0 ImageView.qml ViewPortDelegatBase 1.0 ViewPortDelegatBase.qml ViewPortPage 1.0 ViewPortPage.qml diff --git a/ViewSolutions/src/ViewSolutionsResources.qrc b/ViewSolutions/src/ViewSolutionsResources.qrc index 2431968..2b80125 100644 --- a/ViewSolutions/src/ViewSolutionsResources.qrc +++ b/ViewSolutions/src/ViewSolutionsResources.qrc @@ -8,6 +8,9 @@ ViewSolutionsModule/ViewPortStaticPage.qml ViewSolutionsModule/ViewPortStaticGradientPage.qml ViewSolutionsModule/ViewSolutionsControl.qml + ViewSolutionsModule/ActivityProcessorHeader.qml + ViewSolutionsModule/ActivityProcessor.qml + ViewSolutionsModule/ActivityPage.qml diff --git a/ViewSolutions/src/basehashmodel.cpp b/ViewSolutions/src/basehashmodel.cpp new file mode 100644 index 0000000..812112a --- /dev/null +++ b/ViewSolutions/src/basehashmodel.cpp @@ -0,0 +1,2 @@ +#include "basehashmodel.h" + diff --git a/ViewSolutions/src/basehashmodel.h b/ViewSolutions/src/basehashmodel.h new file mode 100644 index 0000000..9f7cdd8 --- /dev/null +++ b/ViewSolutions/src/basehashmodel.h @@ -0,0 +1,188 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef BASEHASHMODEL_H +#define BASEHASHMODEL_H +#include +#include + +namespace ViewSolutions { + +/** + * @tparam KEY - is type of hash table key, + * @tparam DATA - is main stored delegate model of all list items. + + * @brief The BaseHashModel class is base class of all GUI list models + * + * Conceptions and using rooles + * * All models should provides delegate models base of qobject + * * If model require fast solution just implement BaseListModel model + * + * + * @note to access to delegate model use Qt::EditRole role: available in qml by delegateModel keyword + * **example:** : + * ``` + * class VariantListModel: public BaseHashModel +{ + Q_OBJECT + +public: + VariantListModel(QObject* ptr = nullptr): BaseListModel(ptr){}; +}; +} + * ``` + * + * @note The BaseHashModel is not support Qml space, to short access in qml use the @a BaseListModel + */ +template +class BaseHashModel: public QAbstractListModel +{ + +public: + BaseHashModel(QObject* parent = nullptr): QAbstractListModel(parent) { + + } + + int rowCount(const QModelIndex &parent) const override { + return m_data.size(); + } + + QHash roleNames() const override { + QHash roles; + roles[Qt::EditRole] = "delegateModel"; + return roles; + } + + QVariant data(const QModelIndex &index, int role) const override { + if (index.isValid() && role == Qt::EditRole) { + + auto iter = std::next(m_data.begin(), index.row()); + if (iter == m_data.end()) { + return {}; + } + + if constexpr (std::is_same_v) { + return *iter; + } else if constexpr(std::is_base_of_v) { + QQmlEngine::setObjectOwnership(*iter, QQmlEngine::CppOwnership); + + return QVariant::fromValue(*iter); + + } else if constexpr (std::is_same_v> || + std::is_base_of_v) { + QObject* ptr = iter->get(); + + QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership); + return QVariant::fromValue(ptr); + } else { + return QVariant::fromValue(*iter); + + } + } + + return {}; + } + + /** + * @brief getByKey returns value by key + * @param key + * @return + */ + virtual QVariant getByKey(const KEY& key) { + auto&& val = m_data.value(key); + if constexpr (std::is_same_v) { + return val; + } else if constexpr(std::is_base_of_v) { + QQmlEngine::setObjectOwnership(val, QQmlEngine::CppOwnership); + + return QVariant::fromValue(val); + + } else if constexpr (std::is_base_of_v, DATA>) { + QObject* ptr = val.get(); + + QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership); + return QVariant::fromValue(ptr); + } else { + return QVariant::fromValue(val); + + } + + return {}; + } + + const QHash& dateList() const { + return m_data; + } + + /** + * @brief setByKey update delegate by key + * @param key + * @param data + */ + virtual void setByKey(const KEY& key, const DATA& data) { + auto&& iter = m_data.find(key); + if (iter != m_data.end() || *iter != data) { + + int insertIdx = std::distance(m_data.begin(), m_data.insert(key, data)); + emit dataChanged(index(insertIdx, 0), + index(insertIdx, 0)); + } + } + + virtual void removeByKey(const KEY& key) { + auto&& iter = m_data.find(key); + if (iter != m_data.end()) { + + int removeIdx = std::distance(m_data.begin(), iter); + beginRemoveRows(QModelIndex{}, removeIdx, removeIdx); + m_data.erase(iter); + endRemoveRows(); + } + } + + /** + * @brief setDataList sets new date of model, and reset all model; + * @param newData + */ + void setDataList(const QHash &newData) { + + const int diff = newData.size() - m_data.size(); + + if (diff > 0) { + beginInsertRows(QModelIndex{}, m_data.size(), m_data.size() + diff - 1); + m_data = newData; + endInsertRows(); + + emit dataChanged(index(0, 0), + index(m_data.size() - diff - 1, 0)); + } else if (diff == 0) { + m_data = newData; + + emit dataChanged(index(0, 0), + index(m_data.size() - diff - 1, 0)); + } else { + beginRemoveRows(QModelIndex{}, m_data.size() + diff, m_data.size() - 1); + m_data = newData; + + endRemoveRows(); + + emit dataChanged(index(0, 0), + index(m_data.size() - 1, 0)); + } + } + +private: + QHash m_data; + +}; + + + +} + + +#endif // BASEHASHMODEL_H diff --git a/ViewSolutions/src/baselistmodel.h b/ViewSolutions/src/baselistmodel.h new file mode 100644 index 0000000..1d69ea7 --- /dev/null +++ b/ViewSolutions/src/baselistmodel.h @@ -0,0 +1,145 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef BASELISTMODEL_H +#define BASELISTMODEL_H + +#include +#include + +namespace ViewSolutions { + +class __PrvateBaseListModel : public QAbstractListModel{ + Q_OBJECT +protected: + __PrvateBaseListModel(QObject* parent = nullptr): QAbstractListModel(parent){} +signals: + void listDateChanged(); +}; + + +#define BASE_LIST_MODEL_DATA_PROPERTY(Type) \ +Q_PROPERTY(QList listDate READ dateList WRITE setDataList NOTIFY listDateChanged FINAL) + + +/** + * @tparam TYPE - is main stored delegate model of all list items. + * @brief The BaseListModel class is base class of all GUI list models + * + * Conceptions and using rooles + * * All models should provides delegate models base of qobject + * * If model require fast solution just implement BaseListModel model + * + * + * @note to access to delegate model use Qt::EditRole role: available in qml by delegateModel keyword + * **example:** : + * ``` + * class VariantListModel: public BaseListModel +{ + Q_OBJECT + BASE_LIST_MODEL_DATA_PROPERTY(QVariant) + +public: + VariantListModel(QObject* ptr = nullptr): BaseListModel(ptr){}; +}; +} + * ``` + */ +template +class BaseListModel: public __PrvateBaseListModel +{ + +public: + BaseListModel(QObject* parent = nullptr): __PrvateBaseListModel(parent) { + + } + + int rowCount(const QModelIndex &parent) const override { + return m_data.size(); + } + + QHash roleNames() const override { + QHash roles; + roles[Qt::EditRole] = "delegateModel"; + return roles; + } + + QVariant data(const QModelIndex &index, int role) const override { + if (index.isValid() && + index.row() < m_data.size() && + m_data.size() && + role == Qt::EditRole) { + + if constexpr (std::is_same_v) { + return m_data[index.row()]; + } else if constexpr(std::is_base_of_v) { + QQmlEngine::setObjectOwnership(m_data[index.row()], QQmlEngine::CppOwnership); + + return QVariant::fromValue(m_data[index.row()]); + + } else if constexpr (std::is_same_v> || + std::is_base_of_v) { + QObject* ptr = m_data[index.row()].get(); + + QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership); + return QVariant::fromValue(ptr); + } else { + return QVariant::fromValue(m_data[index.row()]); + + } + } + + return {}; + } + + /** + * @brief setDataList sets new date of model, and reset all model; + * @param newData + */ + Q_INVOKABLE void setDataList(const QList &newData) { + + const int diff = newData.size() - m_data.size(); + + if (diff > 0) { + beginInsertRows(QModelIndex{}, m_data.size(), m_data.size() + diff - 1); + m_data = newData; + endInsertRows(); + + emit dataChanged(index(0, 0), + index(m_data.size() - diff - 1, 0)); + } else if (diff == 0) { + m_data = newData; + + emit dataChanged(index(0, 0), + index(m_data.size() - diff - 1, 0)); + } else { + beginRemoveRows(QModelIndex{}, m_data.size() + diff, m_data.size() - 1); + m_data = newData; + + endRemoveRows(); + + emit dataChanged(index(0, 0), + index(m_data.size() - 1, 0)); + } + + emit listDateChanged(); + + } + + Q_INVOKABLE const QList& dateList() const { + return m_data; + } + +private: + QList m_data; + +}; + + + +} +#endif // BASELISTMODEL_H diff --git a/ViewSolutions/src/colorpicker.cpp b/ViewSolutions/src/colorpicker.cpp index c792c17..0bbefd0 100644 --- a/ViewSolutions/src/colorpicker.cpp +++ b/ViewSolutions/src/colorpicker.cpp @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #include "colorpicker.h" #include diff --git a/ViewSolutions/src/colorpicker.h b/ViewSolutions/src/colorpicker.h index a512f00..cc05f2e 100644 --- a/ViewSolutions/src/colorpicker.h +++ b/ViewSolutions/src/colorpicker.h @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #ifndef COLORPICKER_H #define COLORPICKER_H #include "viewsolutions_global.h" diff --git a/ViewSolutions/src/iguitokensmodel.cpp b/ViewSolutions/src/iguitokensmodel.cpp new file mode 100644 index 0000000..2f8cbd6 --- /dev/null +++ b/ViewSolutions/src/iguitokensmodel.cpp @@ -0,0 +1,27 @@ +//# +//# Copyright (C) 2024-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "iguitokensmodel.h" + +namespace ViewSolutions { + +iGUITokensModel::iGUITokensModel() {} + +QString iGUITokensModel::modelId() const { + return "GUITokens"; +} + +QColor iGUITokensModel::addTransporent(QColor input, float alpha) const { + return addTransporentImpl(input, alpha); +} + +QColor &iGUITokensModel::addTransporentImpl(QColor &input, float alpha) const { + input.setAlphaF(alpha); + return input; +} + +} diff --git a/ViewSolutions/src/iguitokensmodel.h b/ViewSolutions/src/iguitokensmodel.h new file mode 100644 index 0000000..98f67e5 --- /dev/null +++ b/ViewSolutions/src/iguitokensmodel.h @@ -0,0 +1,145 @@ +//# +//# Copyright (C) 2024-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef IGUITOKENSMODEL_H +#define IGUITOKENSMODEL_H + +#include "imodel.h" +#include +#include +#include + +namespace ViewSolutions { + +/** + * @brief The Tokens class is general global instanke of all QML constans used in the App. + */ +class VIEWSOLUTION_EXPORT iGUITokensModel: public QObject, public iModel +{ + Q_OBJECT + + // colors contants + Q_PROPERTY(QColor color_accent_primary READ color_surface_accent_primary CONSTANT FINAL) + + Q_PROPERTY(QColor color_accent_secondary READ color_surface_accent_secondary CONSTANT FINAL) + Q_PROPERTY(QColor color_accent_error READ color_surface_accent_error CONSTANT FINAL) + Q_PROPERTY(QColor color_accent_success READ color_surface_accent_success CONSTANT FINAL) + + Q_PROPERTY(QColor color_text_primary READ color_text_primary CONSTANT FINAL) + Q_PROPERTY(QColor color_text_secondary READ color_text_secondary CONSTANT FINAL) + Q_PROPERTY(QColor color_text_tertiary READ color_text_tertiary CONSTANT FINAL) + + Q_PROPERTY(QColor color_text_disabled READ color_text_disabled CONSTANT FINAL) + + Q_PROPERTY(QColor color_border_primary READ color_border_primary CONSTANT FINAL) + Q_PROPERTY(QColor color_border_secondary READ color_border_secondary CONSTANT FINAL) + Q_PROPERTY(QColor color_border_disabled READ color_border_disabled CONSTANT FINAL) + + Q_PROPERTY(QColor color_devider READ color_devider CONSTANT FINAL) + Q_PROPERTY(QColor color_background READ color_background CONSTANT FINAL) + + //states_colors_constants: + Q_PROPERTY(QColor pressed_focused READ pressed_focused CONSTANT FINAL) + Q_PROPERTY(QColor hover READ hover CONSTANT FINAL) + + // fonts + Q_PROPERTY(QFont font_caption_1 READ font_caption_1 CONSTANT FINAL) + Q_PROPERTY(QFont font_caption_2 READ font_caption_2 CONSTANT FINAL) + Q_PROPERTY(QFont font_caption_3 READ font_caption_3 CONSTANT FINAL) + + Q_PROPERTY(QFont font_body_1 READ font_body_1 CONSTANT FINAL) + Q_PROPERTY(QFont font_body_2 READ font_body_2 CONSTANT FINAL) + Q_PROPERTY(QFont font_body_large READ font_body_large CONSTANT FINAL) + Q_PROPERTY(QFont font_subtitle_1 READ font_subtitle_1 CONSTANT FINAL) + Q_PROPERTY(QFont font_subtitle_2 READ font_subtitle_2 CONSTANT FINAL) + Q_PROPERTY(QFont font_subtitle_large READ font_subtitle_large CONSTANT FINAL) + Q_PROPERTY(QFont font_subtitle_x_large READ font_subtitle_x_large CONSTANT FINAL) + Q_PROPERTY(QFont font_subtitle_uppercase READ font_subtitle_uppercase CONSTANT FINAL) + + Q_PROPERTY(QFont font_title_1 READ font_title_1 CONSTANT FINAL) + Q_PROPERTY(QFont font_title_1_secondary READ font_title_1_secondary CONSTANT FINAL) + + Q_PROPERTY(QFont font_title_2 READ font_title_2 CONSTANT FINAL) + Q_PROPERTY(QFont font_title_3 READ font_title_3 CONSTANT FINAL) + Q_PROPERTY(QFont font_title_3_secondary READ font_title_3_secondary CONSTANT FINAL) + + Q_PROPERTY(QFont font_title_strong READ font_title_strong CONSTANT FINAL) + Q_PROPERTY(QFont font_title_large READ font_title_large CONSTANT FINAL) + Q_PROPERTY(QFont font_title_x_large READ font_title_x_large CONSTANT FINAL) + Q_PROPERTY(QFont font_title_uppercase READ font_title_uppercase CONSTANT FINAL) + Q_PROPERTY(QFont font_botton_1 READ font_botton_1 CONSTANT FINAL) + Q_PROPERTY(QFont font_botton_2 READ font_botton_2 CONSTANT FINAL) + Q_PROPERTY(QFont font_bubble READ font_bubble CONSTANT FINAL) + + +public: + explicit iGUITokensModel(); + virtual QColor color_surface_accent_primary() const = 0; + virtual QColor color_surface_accent_secondary() const = 0; + virtual QColor color_surface_accent_error() const = 0; + virtual QColor color_surface_accent_success() const = 0; + + virtual QColor color_text_primary() const = 0; + virtual QColor color_text_secondary() const = 0; + virtual QColor color_text_tertiary() const = 0; + + virtual QColor color_text_disabled() const = 0; + virtual QColor color_border_primary() const = 0; + virtual QColor color_border_secondary() const = 0; + virtual QColor color_border_disabled() const = 0; + virtual QColor color_devider() const = 0; + virtual QColor color_background() const = 0; + + virtual QColor pressed_focused() const = 0; + virtual QColor hover() const = 0; + + virtual QFont font_caption_1() const = 0; + virtual QFont font_caption_2() const = 0; + virtual QFont font_caption_3() const = 0; + + virtual QFont font_body_1() const = 0; + virtual QFont font_body_2() const = 0; + virtual QFont font_body_large() const = 0; + virtual QFont font_subtitle_1() const = 0; + virtual QFont font_subtitle_2() const = 0; + virtual QFont font_subtitle_large() const = 0; + virtual QFont font_subtitle_x_large() const = 0; + virtual QFont font_subtitle_uppercase() const = 0; + virtual QFont font_title_1() const = 0; + virtual QFont font_title_1_secondary() const = 0; + + virtual QFont font_title_2() const = 0; + + virtual QFont font_title_3() const = 0; + virtual QFont font_title_3_secondary() const = 0; + + virtual QFont font_title_strong() const = 0; + virtual QFont font_title_large() const = 0; + virtual QFont font_title_x_large() const = 0; + virtual QFont font_title_uppercase() const = 0; + virtual QFont font_botton_1() const = 0; + virtual QFont font_botton_2() const = 0; + virtual QFont font_bubble() const = 0; + + // iModel interface +public: + QString modelId() const; + + Q_INVOKABLE QColor addTransporent(QColor input, float alpha) const; + + +protected: + /** + * @brief addTransporent This method add alpha chennel to the color. + * @param input input link to color + * @param alpha alphachennol factor from 0 to 1. + * @return color with new alpha chennel. + */ + QColor& addTransporentImpl(QColor& input, float alpha) const; +}; +} +#endif // IGUITOKENSMODEL_H diff --git a/ViewSolutions/src/imodel.cpp b/ViewSolutions/src/imodel.cpp new file mode 100644 index 0000000..e0ac335 --- /dev/null +++ b/ViewSolutions/src/imodel.cpp @@ -0,0 +1,30 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "imodel.h" + +#include + +namespace ViewSolutions { + + +const QWeakPointer &iModel::storage() const { + return m_storage; +} + +QQmlApplicationEngine *iModel::engine() const { + if (auto&& storage = m_storage.lock()) { + return storage->engine(); + } + + return nullptr; +} + +void iModel::initStorage(const QWeakPointer &newStorage) { + m_storage = newStorage; +} +} diff --git a/ViewSolutions/src/imodel.h b/ViewSolutions/src/imodel.h new file mode 100644 index 0000000..828141f --- /dev/null +++ b/ViewSolutions/src/imodel.h @@ -0,0 +1,69 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef IMODEL_H +#define IMODEL_H + +#include +#include +#include +#include "viewsolutions_global.h" + + +namespace ViewSolutions { + +class ModelStorage; + +/** + * @brief The iModel class is base model for GUI models. Works with @a ModelStorage. + * All models after adding can get access to any othe models that located on same storage object. + */ +class VIEWSOLUTION_EXPORT iModel +{ +public: + iModel() = default; + virtual ~iModel() = default; + + /** + * @brief modelId returns text model id. override this method to provide access to model in qml or other models. + * @return model id. + */ + virtual QString modelId() const = 0; + + /** + * @brief storage returns storage object. this method return context of the model's storage. + * @return storage object. + */ + const QWeakPointer& storage() const; + + /** + * @brief engine returns qml engine. + * @return qml engine. + * @note can be return nullptr if the models system initialized without qml engine. + * @note this method convert weak pointer to shared pointer, + * so you can use it without any restrictions, + * but it may be slowly then dirrect access. + */ + QQmlApplicationEngine * engine() const; + +protected: + + /** + * @brief initStorage This method is called by storage object after adding model to storage. + * @param newStorage is storage object. + */ + virtual void initStorage(const QWeakPointer& newStorage); + +private: + + QWeakPointer m_storage; + + friend class ModelStorage; +}; + +} +#endif // IMODEL_H diff --git a/ViewSolutions/src/listviewmodel.cpp b/ViewSolutions/src/listviewmodel.cpp index 21bcd7a..e4cfbf5 100644 --- a/ViewSolutions/src/listviewmodel.cpp +++ b/ViewSolutions/src/listviewmodel.cpp @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #include "listviewmodel.h" namespace ViewSolutions { @@ -77,7 +84,7 @@ void ListViewModel::addSource(QObject* data) { } void ListViewModel::clear(bool fast) { - for (auto i : qAsConst(_data)) { + for (auto i : std::as_const(_data)) { if (fast) { i->deleteLater(); } else { diff --git a/ViewSolutions/src/listviewmodel.h b/ViewSolutions/src/listviewmodel.h index eb7a5ed..e5653b6 100644 --- a/ViewSolutions/src/listviewmodel.h +++ b/ViewSolutions/src/listviewmodel.h @@ -1,3 +1,10 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #ifndef LISTVIEWMODEL_H #define LISTVIEWMODEL_H #include diff --git a/ViewSolutions/src/modelstorage.cpp b/ViewSolutions/src/modelstorage.cpp new file mode 100644 index 0000000..f946223 --- /dev/null +++ b/ViewSolutions/src/modelstorage.cpp @@ -0,0 +1,41 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "modelstorage.h" + +#include + +namespace ViewSolutions { + +ModelStorage::ModelStorage(QQmlApplicationEngine *engine) { + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); + _engine = engine; +} + +bool ModelStorage::addModel(const QSharedPointer &model) { + if (_storage.contains(model->modelId())) { + return false; + } + + if (QObject* qobject = dynamic_cast(model.get())) { + QQmlEngine::setObjectOwnership(qobject, QQmlEngine::CppOwnership); + } + + _storage[model->modelId()] = model; + model->initStorage(sharedFromThis().toWeakRef()); + + return true; +} + +QObject* ModelStorage::getModel(const QString &modeId) const { + return dynamic_cast(_storage.value(modeId).get()); +} + +QQmlApplicationEngine *ModelStorage::engine() const { + return _engine; +} +} diff --git a/ViewSolutions/src/modelstorage.h b/ViewSolutions/src/modelstorage.h new file mode 100644 index 0000000..5a72d6f --- /dev/null +++ b/ViewSolutions/src/modelstorage.h @@ -0,0 +1,61 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef MODELSTORAGE_H +#define MODELSTORAGE_H + +#include "imodel.h" + +#include +#include +#include + +namespace ViewSolutions { + +/** + * @brief The ModelStorage class main model storage object. Provide access to all models in the application. + */ +class VIEWSOLUTION_EXPORT ModelStorage: public QObject, public QEnableSharedFromThis +{ + Q_OBJECT +public: + ModelStorage(QQmlApplicationEngine* engine = nullptr); + + /** + * @brief addModel adds new model into storage. + * @param model is model object. + * @return true if model added succesfful, if model alredy exists or model is invalid return false. + * @note All valid models should be inherited from QObject, and inited using a QSharedPointer::create() method. + */ + bool addModel(const QSharedPointer& model); + + /** + * @brief getModel This method isible on The QML and using for gettings required GUI models. + * @param modeId This is id of required model. + * @return model raw pointer. + */ + Q_INVOKABLE QObject* getModel(const QString& modeId) const; + + template + QSharedPointer get(const QString& modeId) const { + return _storage.value(modeId).staticCast(); + } + + /** + * @brief engine returns context qml engine. + * @return qml engine. + */ + QQmlApplicationEngine *engine() const; + +private: + QHash> _storage; + QQmlApplicationEngine * _engine = nullptr; +}; + +} + +#endif // MODELSTORAGE_H diff --git a/ViewSolutions/src/qmlcolorpicker.cpp b/ViewSolutions/src/qmlcolorpicker.cpp index 928ceae..09b53a4 100644 --- a/ViewSolutions/src/qmlcolorpicker.cpp +++ b/ViewSolutions/src/qmlcolorpicker.cpp @@ -1,3 +1,11 @@ + +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #include "qmlcolorpicker.h" #include @@ -9,62 +17,58 @@ QMLColorPicker::QMLColorPicker(QObject *parent) : } -QMLColorPicker *ViewSolutions::QMLColorPicker::instance() { - static auto ints = new QMLColorPicker(); - return ints; -} - QColor QMLColorPicker::pick(const QString &img) const { if (img.left(6) == "image:") { int urlBegin = img.indexOf('/', 8); QString id = img.mid(8, urlBegin - 8); - if (!_engine) - return {}; + if (auto eng = engine()) { + QQuickImageProvider* provider = dynamic_cast(eng->imageProvider(id)); - QQuickImageProvider* provider = dynamic_cast(_engine->imageProvider(id)); - - if (!provider) { - return {}; - } - - QString url = img.mid(urlBegin + 1); - - if (provider->imageType() & QQmlImageProviderBase::ImageResponse) { - auto async = static_cast(provider); - auto textureFacrory = async->requestImageResponse(url, {})->textureFactory(); - - if (!textureFacrory) { + if (!provider) { return {}; } - QColor responce = ColorPicker::pick(textureFacrory->image()); + QString url = img.mid(urlBegin + 1); - delete textureFacrory; + if (provider->imageType() & QQmlImageProviderBase::ImageResponse) { + auto async = static_cast(provider); + auto textureFacrory = async->requestImageResponse(url, {})->textureFactory(); - return responce; + if (!textureFacrory) { + return {}; + } + + QColor responce = ColorPicker::pick(textureFacrory->image()); + + delete textureFacrory; + + return responce; + } + + if (provider->imageType() & QQmlImageProviderBase::Texture) { + return ColorPicker::pick(provider->requestTexture(url, nullptr, {})->image()); + } + + if (provider->imageType() & QQmlImageProviderBase::Pixmap) { + return ColorPicker::pick(provider->requestPixmap(url, nullptr, {}).toImage()); + } + + if (provider->imageType() & QQmlImageProviderBase::Image) { + return ColorPicker::pick(provider->requestImage(url, nullptr, {})); + } + + return {}; } - if (provider->imageType() & QQmlImageProviderBase::Texture) { - return ColorPicker::pick(provider->requestTexture(url, nullptr, {})->image()); - } - - if (provider->imageType() & QQmlImageProviderBase::Pixmap) { - return ColorPicker::pick(provider->requestPixmap(url, nullptr, {}).toImage()); - } - - if (provider->imageType() & QQmlImageProviderBase::Image) { - return ColorPicker::pick(provider->requestImage(url, nullptr, {})); - } - - return {}; } return ColorPicker::pick(img); } -void QMLColorPicker::setEngine(QQmlApplicationEngine *engine) { - _engine = engine; +QString QMLColorPicker::modelId() const { + return "ColorPicker"; } + } diff --git a/ViewSolutions/src/qmlcolorpicker.h b/ViewSolutions/src/qmlcolorpicker.h index 8eba381..3cf8c4d 100644 --- a/ViewSolutions/src/qmlcolorpicker.h +++ b/ViewSolutions/src/qmlcolorpicker.h @@ -1,42 +1,43 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #ifndef QMLCOLORPICKER_H #define QMLCOLORPICKER_H #include "colorpicker.h" #include +#include -class QQmlApplicationEngine; namespace ViewSolutions { /** * @brief The QMLColorPicker class - Qml wrapper for ColorPicker class. */ -class VIEWSOLUTION_EXPORT QMLColorPicker : public QObject, private ColorPicker +class VIEWSOLUTION_EXPORT QMLColorPicker : public QObject, public iModel, private ColorPicker { Q_OBJECT public: explicit QMLColorPicker(QObject *parent = nullptr); - /** - * @brief instance This method return instance object of the QMLColorPicker setvice. - * @return Static instance of this ColorPicker. - */ - static QMLColorPicker* instance(); + /** * @brief pick This is override function for qml. * @param img This is path to image. * @return General color of image. */ - Q_INVOKABLE QColor pick(const QString &img) const; + Q_INVOKABLE QColor pick(const QString &img) const; /** - * @brief setEngine This method set qml engine for working with image providers. - * @param engine This is new engine. + * @brief instance This is singleton instance of QMLColorPicker. + * @return */ - void setEngine(QQmlApplicationEngine *engine); + QString modelId() const override; -private: - - QQmlApplicationEngine *_engine = nullptr; }; + } #endif // QMLCOLORPICKER_H diff --git a/ViewSolutions/src/variantlistmodel.h b/ViewSolutions/src/variantlistmodel.h new file mode 100644 index 0000000..5b81ffa --- /dev/null +++ b/ViewSolutions/src/variantlistmodel.h @@ -0,0 +1,23 @@ +#ifndef VARIANTLISTMODEL_H +#define VARIANTLISTMODEL_H + +#include "baselistmodel.h" + + +namespace ViewSolutions { + +/** + * @brief The VariantListModel class is universal implementation for all atomic types. + */ +class VariantListModel: public BaseListModel +{ + Q_OBJECT + BASE_LIST_MODEL_DATA_PROPERTY(QVariant) + +public: + VariantListModel(QObject* ptr = nullptr): BaseListModel(ptr){}; +}; + +} + +#endif // VARIANTLISTMODEL_H diff --git a/ViewSolutions/src/viewsolutions.cpp b/ViewSolutions/src/viewsolutions.cpp index ef74ce5..7c848dc 100644 --- a/ViewSolutions/src/viewsolutions.cpp +++ b/ViewSolutions/src/viewsolutions.cpp @@ -1,29 +1,50 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "variantlistmodel.h" #include "viewsolutions.h" #include #include #include #include #include +#include namespace ViewSolutions { -bool init(QQmlApplicationEngine *engine) { +QSharedPointer init(QQmlApplicationEngine *engine) { if (!engine) - return false; + return nullptr; auto root = engine->rootContext(); if (!root) - return false; + return nullptr; initResources(); engine->addImportPath(":/"); - auto picker = QMLColorPicker::instance(); - picker->setEngine(engine); - root->setContextProperty("colorPicker", picker); - return true; + auto&& storage = QSharedPointer::create(engine); + QQmlEngine::setObjectOwnership(storage.get(), QQmlEngine::CppOwnership); + + root->setContextProperty("modelsStorage", storage.get()); + + auto&& picker = QSharedPointer::create(); + storage->addModel(picker); + + // to-do - remove + root->setContextProperty("colorPicker", picker.get()); + + qRegisterMetaType("VariantListModel"); + + + + return storage; } } diff --git a/ViewSolutions/src/viewsolutions.h b/ViewSolutions/src/viewsolutions.h index 80777df..dd28f23 100644 --- a/ViewSolutions/src/viewsolutions.h +++ b/ViewSolutions/src/viewsolutions.h @@ -1,6 +1,14 @@ +//# +//# Copyright (C) 2020-2025 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #ifndef VIEWSOLUTIONS_H #define VIEWSOLUTIONS_H +#include "modelstorage.h" #include "viewsolutions_global.h" class QQmlApplicationEngine; @@ -15,10 +23,13 @@ inline void initResources() { Q_INIT_RESOURCE(ViewSolutionsResources); } * @brief the ViewSolutions namespace */ namespace ViewSolutions { + /** - * @brief init this method import all qml resources to your project. - */ - bool VIEWSOLUTION_EXPORT init(QQmlApplicationEngine *engine); + * @brief init this method import all qml resources to your project. + * @param engine is QQmlApplicationEngine object. + * @return gui model storage object. + */ +QSharedPointer VIEWSOLUTION_EXPORT init(QQmlApplicationEngine *engine); } #endif // VIEWSOLUTIONS_H