From 00a440754c7982121ea3602e6c981b1c02f2afa6 Mon Sep 17 00:00:00 2001 From: EndrII Date: Mon, 17 Feb 2025 13:48:52 +0100 Subject: [PATCH 01/10] added new models storages --- CMake | 2 +- CMakeLists.txt | 20 +- Examples/CMakeLists.txt | 2 +- Examples/src/main.cpp | 2 +- Examples/src/main.qml | 2 +- ViewSolutions/CMakeLists.txt | 3 +- .../src/ViewSolutionsModule/ActivityPage.qml | 42 +++ .../ViewSolutionsModule/ActivityProcessor.qml | 313 ++++++++++++++++++ .../ActivityProcessorHeader.qml | 106 ++++++ .../src/ViewSolutionsModule/ImageView.qml | 7 + .../ViewPortDelegatBase.qml | 7 + .../ViewPortGradientPage.qml | 7 + .../src/ViewSolutionsModule/ViewPortPage.qml | 7 + .../ViewPortStaticGradientPage.qml | 7 + .../ViewPortStaticPage.qml | 7 + .../ViewSolutionsControl.qml | 7 + ViewSolutions/src/ViewSolutionsModule/qmldir | 3 + ViewSolutions/src/ViewSolutionsResources.qrc | 3 + ViewSolutions/src/basehashmodel.cpp | 2 + ViewSolutions/src/basehashmodel.h | 188 +++++++++++ ViewSolutions/src/baselistmodel.h | 145 ++++++++ ViewSolutions/src/colorpicker.cpp | 7 + ViewSolutions/src/colorpicker.h | 7 + ViewSolutions/src/iguitokensmodel.cpp | 23 ++ ViewSolutions/src/iguitokensmodel.h | 140 ++++++++ ViewSolutions/src/imodel.cpp | 30 ++ ViewSolutions/src/imodel.h | 69 ++++ ViewSolutions/src/listviewmodel.cpp | 9 +- ViewSolutions/src/listviewmodel.h | 7 + ViewSolutions/src/modelstorage.cpp | 41 +++ ViewSolutions/src/modelstorage.h | 61 ++++ ViewSolutions/src/qmlcolorpicker.cpp | 80 ++--- ViewSolutions/src/qmlcolorpicker.h | 29 +- ViewSolutions/src/variantlistmodel.h | 23 ++ ViewSolutions/src/viewsolutions.cpp | 35 +- ViewSolutions/src/viewsolutions.h | 17 +- 36 files changed, 1378 insertions(+), 82 deletions(-) create mode 100644 ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml create mode 100644 ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml create mode 100644 ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml create mode 100644 ViewSolutions/src/basehashmodel.cpp create mode 100644 ViewSolutions/src/basehashmodel.h create mode 100644 ViewSolutions/src/baselistmodel.h create mode 100644 ViewSolutions/src/iguitokensmodel.cpp create mode 100644 ViewSolutions/src/iguitokensmodel.h create mode 100644 ViewSolutions/src/imodel.cpp create mode 100644 ViewSolutions/src/imodel.h create mode 100644 ViewSolutions/src/modelstorage.cpp create mode 100644 ViewSolutions/src/modelstorage.h create mode 100644 ViewSolutions/src/variantlistmodel.h 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..1a6eba6 --- /dev/null +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml @@ -0,0 +1,42 @@ +//# +//# 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: "" + property string subTitle: "" + + // shows the back button with text + property bool isFullBackButton: false + property bool buttonBack: true + + // shows close button on the ActivityProcessor header + property bool closeButton: true + property bool closeButtonBorder: false + // 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 + + topPadding: 24 +} diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml new file mode 100644 index 0000000..04409be --- /dev/null +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml @@ -0,0 +1,313 @@ +//# +//# 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 + +Pane { + id: root + + // use Comonent delegates only + property alias initialItem: stackView.initialItem + property alias currentItem: stackView.currentItem + property alias titlesAligh: headerView.titlesAligh + property bool cache: true + property bool enableHeader: true + + padding: 0 + clip: true + + background: Item{} + + contentItem: Page { + id: contentPage + + padding: 0 + background: Item{} + + header: ActivityProcessorHeader { + id: headerView + visible: root.enableHeader + title: { + if (root.enableHeader && stackView.currentItem && stackView.currentItem.title) { + return stackView.currentItem.title + } + + return "" + } + + subTitle: { + if (root.enableHeader && stackView.currentItem && stackView.currentItem.subTitle) { + return stackView.currentItem.subTitle + } + return "" + + } + backButton: root.enableHeader && stackView.depth > 1 && (stackView.currentItem && stackView.currentItem.buttonBack) + fullBackButton: root.enableHeader && (stackView.currentItem && stackView.currentItem.isFullBackButton) + + closeButton: root.enableHeader && (stackView.currentItem && stackView.currentItem.closeButton) + closeButtonBorder: root.enableHeader && (stackView.currentItem && stackView.currentItem.closeButtonBorder) + titlesAligh: Text.AlignLeft + onBackClicked: { + popItem() + } + + onCloseClicked: { + popupProcessor.close() + } + } + + contentItem: StackView { + Connections { + target: (stackView.currentItem && stackView.currentItem.finish)? stackView.currentItem : null + + function onFinish() { + popItem(); + } + } + + padding: 0 + id: stackView + + implicitWidth: stackView.currentItem.implicitWidth + implicitHeight: stackView.currentItem.implicitHeight + + 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..c8d5f81 --- /dev/null +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml @@ -0,0 +1,106 @@ +//# +//# 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 + +GridLayout { + + id: root + property int titlesAligh: Text.AlignHCenter + + property font titlesFont: tokensModel.font_title_uppercase + property alias rightSubtitleWidget: rightSubtitleControl.contentItem + + property bool closeButtonBorder: true + property string title: "" + property bool titleUppercase: true + property string subTitle: "" + property bool backButton: false + property bool fullBackButton: false + property bool closeButton: false + property int headerRowHeight: 40 + + signal backClicked() + signal closeClicked() + + columns: 3 + + Item { + implicitWidth: headerRowHeight + visible: !backButton && titlesAligh === Text.AlignHCenter + } + + Button { + + // Layout.alignment: Qt.AlignLeft + visible: backButton + icon: (root.fullBackButton)? "qrc:/assets/icons/arrowleft_tac.svg" + :"qrc:/assets/icons/arrowleft.svg" + fontColor: tokensModel.color_text_secondary + backgroundBorderColor: tokensModel.color_border_secondary + isFlat: !root.fullBackButton + text: root.fullBackButton? qsTr("Go Back"): "" + Layout.preferredHeight: 24 + Layout.preferredWidth: (root.fullBackButton)? implicitWidth: 24 + leftPadding: (root.fullBackButton)? 16 : padding + rightPadding: (root.fullBackButton)? 16 :padding + baseHeaght: 16 + padding: 4 + customFocusPolicy: Qt.NoFocus + + onClicked: { + backClicked() + } + } + + Text { + id: centralTitle + text: (titleUppercase)? root.title.toUpperCase(): root.title + horizontalAlignment: root.titlesAligh + font: titlesFont + Layout.fillWidth: true; + Layout.preferredHeight: 40 + } + + ToolButton { + Layout.alignment: Qt.AlignRight + icon: "qrc:/assets/icons/dismiss.svg" + onClicked: closeClicked() + visible: root.closeButton + isFlat: !closeButtonBorder + + padding: 10 + baseHeaght: 20 + bordersSize: 2 + customFocusPolicy: Qt.NoFocus + implicitHeight: headerRowHeight + } + + Text { + Layout.row: 1 + Layout.column: (backButton || titlesAligh === Text.AlignHCenter)? 1 : 0 + + Layout.minimumHeight: 16 + visible: root.subTitle.length + wrapMode: Text.WordWrap + elide: Text.ElideNone + Layout.fillWidth: true; + text: root.subTitle + color: tokensModel.color_text_tertiary + font: tokensModel.font_subtitle_2 + horizontalAlignment: centralTitle.horizontalAlignment + } + + Control { + id: rightSubtitleControl + Layout.row: 1 + Layout.column: 2 + + } +} diff --git a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml b/ViewSolutions/src/ViewSolutionsModule/ImageView.qml index b5a4b81..af92719 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ImageView.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/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..6b0fdab --- /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..f2d580f --- /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..a8697fb --- /dev/null +++ b/ViewSolutions/src/iguitokensmodel.cpp @@ -0,0 +1,23 @@ +//# +//# 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 { + input.setAlphaF(alpha); + return input; +} + +} diff --git a/ViewSolutions/src/iguitokensmodel.h b/ViewSolutions/src/iguitokensmodel.h new file mode 100644 index 0000000..21e0ded --- /dev/null +++ b/ViewSolutions/src/iguitokensmodel.h @@ -0,0 +1,140 @@ +//# +//# 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_dark READ color_devider_dark CONSTANT FINAL) + Q_PROPERTY(QColor color_devider_white READ color_devider_white 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_dark() const = 0; + virtual QColor color_devider_white() 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; + +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& addTransporent(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..d2ec9ba 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 init(QQmlApplicationEngine *engine); } #endif // VIEWSOLUTIONS_H From 7e9c085052d25b0f441fb39c26c4fb1ea76572cb Mon Sep 17 00:00:00 2001 From: EndrII Date: Mon, 17 Feb 2025 14:08:12 +0100 Subject: [PATCH 02/10] clear deprecated functions --- .../src/ViewSolutionsModule/ActivityPage.qml | 3 - .../ViewSolutionsModule/ActivityProcessor.qml | 16 +--- .../ActivityProcessorHeader.qml | 75 +++---------------- 3 files changed, 12 insertions(+), 82 deletions(-) diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml index 1a6eba6..642cb55 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml @@ -11,10 +11,8 @@ import QtQuick.Controls Control { property string title: "" - property string subTitle: "" // shows the back button with text - property bool isFullBackButton: false property bool buttonBack: true // shows close button on the ActivityProcessor header @@ -38,5 +36,4 @@ Control { property var activityCallBack: () => {} property bool saveChangesInUnsaved: false - topPadding: 24 } diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml index 04409be..b50b2e2 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml @@ -41,26 +41,14 @@ Pane { return "" } - subTitle: { - if (root.enableHeader && stackView.currentItem && stackView.currentItem.subTitle) { - return stackView.currentItem.subTitle - } - return "" - - } backButton: root.enableHeader && stackView.depth > 1 && (stackView.currentItem && stackView.currentItem.buttonBack) - fullBackButton: root.enableHeader && (stackView.currentItem && stackView.currentItem.isFullBackButton) closeButton: root.enableHeader && (stackView.currentItem && stackView.currentItem.closeButton) - closeButtonBorder: root.enableHeader && (stackView.currentItem && stackView.currentItem.closeButtonBorder) titlesAligh: Text.AlignLeft onBackClicked: { - popItem() + root.popItem() } - onCloseClicked: { - popupProcessor.close() - } } contentItem: StackView { @@ -68,7 +56,7 @@ Pane { target: (stackView.currentItem && stackView.currentItem.finish)? stackView.currentItem : null function onFinish() { - popItem(); + root.popItem() } } diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml index c8d5f81..08a15cd 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml @@ -9,98 +9,43 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -GridLayout { +RowLayout { id: root property int titlesAligh: Text.AlignHCenter - property font titlesFont: tokensModel.font_title_uppercase - property alias rightSubtitleWidget: rightSubtitleControl.contentItem - - property bool closeButtonBorder: true property string title: "" property bool titleUppercase: true - property string subTitle: "" property bool backButton: false - property bool fullBackButton: false property bool closeButton: false - property int headerRowHeight: 40 signal backClicked() signal closeClicked() - columns: 3 + ToolButton { - Item { - implicitWidth: headerRowHeight - visible: !backButton && titlesAligh === Text.AlignHCenter - } - - Button { - - // Layout.alignment: Qt.AlignLeft - visible: backButton - icon: (root.fullBackButton)? "qrc:/assets/icons/arrowleft_tac.svg" - :"qrc:/assets/icons/arrowleft.svg" - fontColor: tokensModel.color_text_secondary - backgroundBorderColor: tokensModel.color_border_secondary - isFlat: !root.fullBackButton - text: root.fullBackButton? qsTr("Go Back"): "" - Layout.preferredHeight: 24 - Layout.preferredWidth: (root.fullBackButton)? implicitWidth: 24 - leftPadding: (root.fullBackButton)? 16 : padding - rightPadding: (root.fullBackButton)? 16 :padding - baseHeaght: 16 - padding: 4 - customFocusPolicy: Qt.NoFocus + visible: root.backButton + text: "<<" onClicked: { - backClicked() + root.backClicked() } } Text { id: centralTitle - text: (titleUppercase)? root.title.toUpperCase(): root.title + text: (root.titleUppercase)? root.title.toUpperCase(): root.title horizontalAlignment: root.titlesAligh - font: titlesFont Layout.fillWidth: true; - Layout.preferredHeight: 40 + } ToolButton { Layout.alignment: Qt.AlignRight - icon: "qrc:/assets/icons/dismiss.svg" - onClicked: closeClicked() + text: "x" + onClicked: root.closeClicked() visible: root.closeButton - isFlat: !closeButtonBorder - - padding: 10 - baseHeaght: 20 - bordersSize: 2 - customFocusPolicy: Qt.NoFocus - implicitHeight: headerRowHeight - } - - Text { - Layout.row: 1 - Layout.column: (backButton || titlesAligh === Text.AlignHCenter)? 1 : 0 - - Layout.minimumHeight: 16 - visible: root.subTitle.length - wrapMode: Text.WordWrap - elide: Text.ElideNone - Layout.fillWidth: true; - text: root.subTitle - color: tokensModel.color_text_tertiary - font: tokensModel.font_subtitle_2 - horizontalAlignment: centralTitle.horizontalAlignment - } - - Control { - id: rightSubtitleControl - Layout.row: 1 - Layout.column: 2 } + } From 9ebd46b46d89885d6f7431b2b8c4926dd639d925 Mon Sep 17 00:00:00 2001 From: EndrII Date: Mon, 17 Feb 2025 14:12:51 +0100 Subject: [PATCH 03/10] fix documentation --- ViewSolutions/src/basehashmodel.h | 2 +- ViewSolutions/src/baselistmodel.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ViewSolutions/src/basehashmodel.h b/ViewSolutions/src/basehashmodel.h index 6b0fdab..9f7cdd8 100644 --- a/ViewSolutions/src/basehashmodel.h +++ b/ViewSolutions/src/basehashmodel.h @@ -24,7 +24,7 @@ namespace ViewSolutions { * * * @note to access to delegate model use Qt::EditRole role: available in qml by delegateModel keyword - * @example : + * **example:** : * ``` * class VariantListModel: public BaseHashModel { diff --git a/ViewSolutions/src/baselistmodel.h b/ViewSolutions/src/baselistmodel.h index f2d580f..1d69ea7 100644 --- a/ViewSolutions/src/baselistmodel.h +++ b/ViewSolutions/src/baselistmodel.h @@ -36,7 +36,7 @@ Q_PROPERTY(QList listDate READ dateList WRITE setDataList NOTIFY listDateC * * * @note to access to delegate model use Qt::EditRole role: available in qml by delegateModel keyword - * @example : + * **example:** : * ``` * class VariantListModel: public BaseListModel { From 61dc2c0970dca6059a91fb955344220f88ce1a37 Mon Sep 17 00:00:00 2001 From: EndrII Date: Mon, 17 Feb 2025 16:07:34 +0100 Subject: [PATCH 04/10] update activity page --- ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml | 1 - ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml index 642cb55..b6f1c42 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityPage.qml @@ -17,7 +17,6 @@ Control { // shows close button on the ActivityProcessor header property bool closeButton: true - property bool closeButtonBorder: false // attach to this property link to ActivityProcessor (if is it not to abble atomaticaly) property var activityProcessorLink: null diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml index b50b2e2..845472e 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml @@ -63,8 +63,8 @@ Pane { padding: 0 id: stackView - implicitWidth: stackView.currentItem.implicitWidth - implicitHeight: stackView.currentItem.implicitHeight + implicitWidth: (stackView.currentItem)? stackView.currentItem.implicitWidth: 0 + implicitHeight: (stackView.currentItem)? stackView.currentItem.implicitHeight: 0 property int durationAnimation: 400 popEnter: Transition { From 5044b1b5bb99a422342fe7e6af51c60ecf79d168 Mon Sep 17 00:00:00 2001 From: EndrII Date: Tue, 18 Feb 2025 14:14:50 +0100 Subject: [PATCH 05/10] fix view image button --- .../src/ViewSolutionsModule/ImageView.qml | 71 ++++++++++++------- ViewSolutions/src/iguitokensmodel.h | 6 +- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml b/ViewSolutions/src/ViewSolutionsModule/ImageView.qml index af92719..2c4c3c3 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ImageView.qml @@ -5,13 +5,13 @@ //# of this license document, but changing it is not allowed. //# -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 +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick.Controls.Material +import QtQuick.Controls.Universal -Item { +Control { id: root property string source: "" property alias imagesource: sourceImg @@ -27,7 +27,7 @@ Item { property color textColor: Material.color(Material.Grey) - property color background: colorPicker.pick(source) + property color backgroundColor: colorPicker.pick(source) property color selectedColor: "#5de2ff" property color borderColor: "#00000000" property color hoverColor: "#00000000" @@ -39,12 +39,12 @@ Item { function onStatusChanged(status) { if (status === Image.Ready) { - root.background = colorPicker.pick(source); + root.backgroundColor = colorPicker.pick(source); } } } - Item { + contentItem: Control { id: privateData property int rootMinSize: Math.min(root.height, root.width) anchors.margins: (root.hover && !presed)? rootMinSize * 0.01: rootMinSize * 0.1 @@ -60,13 +60,31 @@ Item { } } - anchors.fill: parent - Rectangle { - id: background - color: root.background + 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: root.backgroundColor 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 { @@ -82,16 +100,18 @@ Item { } } - ColumnLayout { + contentItem: ColumnLayout { Image { id: sourceImg source: root.source clip: true fillMode: Image.PreserveAspectCrop + mipmap: true + smooth: true Layout.fillHeight: true Layout.fillWidth: true - Layout.margins: 5 + Layout.margins: 4 @@ -100,16 +120,13 @@ Item { 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: [ @@ -145,11 +162,11 @@ Item { hoverEnabled: true; onEntered: { - hover = true + root.hover = true } onExited: { - hover = false; + root.hover = false; privateData.ry = 0 privateData.rx = 0 @@ -157,19 +174,19 @@ Item { onPositionChanged: (mouse) => { let fromCenter = root.width / 2 - privateData.ry = -((mouse.x - fromCenter) / (fromCenter * 0.05)) * power + privateData.ry = -((mouse.x - fromCenter) / (fromCenter * 0.05)) * root.power fromCenter = root.height / 2 - privateData.rx = ((mouse.y - fromCenter) / (fromCenter * 0.05)) * power + privateData.rx = ((mouse.y - fromCenter) / (fromCenter * 0.05)) * root.power } onPressed: { - presed = true; + root.presed = true; } onReleased: (mouse) => { - presed = false; + root.presed = false; root.clicked(mouse) } diff --git a/ViewSolutions/src/iguitokensmodel.h b/ViewSolutions/src/iguitokensmodel.h index 21e0ded..d417362 100644 --- a/ViewSolutions/src/iguitokensmodel.h +++ b/ViewSolutions/src/iguitokensmodel.h @@ -37,8 +37,7 @@ class VIEWSOLUTION_EXPORT iGUITokensModel: public QObject, public iModel 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_dark READ color_devider_dark CONSTANT FINAL) - Q_PROPERTY(QColor color_devider_white READ color_devider_white CONSTANT FINAL) + Q_PROPERTY(QColor color_devider READ color_devider CONSTANT FINAL) //states_colors_constants: Q_PROPERTY(QColor pressed_focused READ pressed_focused CONSTANT FINAL) @@ -89,8 +88,7 @@ public: 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_dark() const = 0; - virtual QColor color_devider_white() const = 0; + virtual QColor color_devider() const = 0; virtual QColor pressed_focused() const = 0; virtual QColor hover() const = 0; From 7dc8e899468a10847d9afc0ca29a8a6f92ae6ab5 Mon Sep 17 00:00:00 2001 From: EndrII Date: Wed, 19 Feb 2025 16:04:15 +0100 Subject: [PATCH 06/10] fix activity processor --- .../ViewSolutionsModule/ActivityProcessor.qml | 158 +++++++++--------- 1 file changed, 80 insertions(+), 78 deletions(-) diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml index 845472e..27823bb 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml @@ -16,6 +16,7 @@ Pane { property alias initialItem: stackView.initialItem property alias currentItem: stackView.currentItem property alias titlesAligh: headerView.titlesAligh + property alias depth: stackView.depth property bool cache: true property bool enableHeader: true @@ -52,93 +53,94 @@ Pane { } contentItem: StackView { - Connections { - target: (stackView.currentItem && stackView.currentItem.finish)? stackView.currentItem : null + id: stackView - function onFinish() { - root.popItem() - } + Connections { + target: (stackView.currentItem && stackView.currentItem.finish)? stackView.currentItem : null + + function onFinish() { + root.popItem() } + } - padding: 0 - id: stackView + padding: 0 - implicitWidth: (stackView.currentItem)? stackView.currentItem.implicitWidth: 0 - implicitHeight: (stackView.currentItem)? stackView.currentItem.implicitHeight: 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 - } + property int durationAnimation: 400 + popEnter: Transition { + ParallelAnimation { + NumberAnimation { + properties: "opacity" + from: 0 + to: 1 + duration: stackView.durationAnimation } - } - - 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 - } + 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 From 2f6fecae9a287430b9b1faa4a7db2d6765e5c830 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 20 Feb 2025 11:30:30 +0100 Subject: [PATCH 07/10] fix export symbols --- ViewSolutions/src/viewsolutions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ViewSolutions/src/viewsolutions.h b/ViewSolutions/src/viewsolutions.h index d2ec9ba..dd28f23 100644 --- a/ViewSolutions/src/viewsolutions.h +++ b/ViewSolutions/src/viewsolutions.h @@ -29,7 +29,7 @@ namespace ViewSolutions { * @param engine is QQmlApplicationEngine object. * @return gui model storage object. */ -QSharedPointer init(QQmlApplicationEngine *engine); +QSharedPointer VIEWSOLUTION_EXPORT init(QQmlApplicationEngine *engine); } #endif // VIEWSOLUTIONS_H From 09344df833e6a6e91f97dc091795f593cd723c2d Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 20 Feb 2025 15:14:18 +0100 Subject: [PATCH 08/10] fix ImaGeView button --- .../src/ViewSolutionsModule/ImageView.qml | 119 ++++++++++-------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml b/ViewSolutions/src/ViewSolutionsModule/ImageView.qml index 2c4c3c3..5613063 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ImageView.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ImageView.qml @@ -10,29 +10,22 @@ import QtQuick.Layouts import QtQuick.Controls import QtQuick.Controls.Material import QtQuick.Controls.Universal +import QtQuick.Effects -Control { +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 backgroundColor: 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 @@ -44,11 +37,20 @@ Control { } } + 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 @@ -82,16 +84,19 @@ Control { } background: Rectangle { - color: root.backgroundColor - border.color: (root.hover)? root.hoverColor: root.selected? root.selectedColor: "#00000000" - border.width: 4 - radius: border.width * 2 + color: { - Behavior on border.color { - ColorAnimation { - duration: 250 + if (root.hovered) { + return root.hoverColor } + + if (root.checked) { + return root.selectedColor + } + + return root.backgroundColor } + radius: 16 Behavior on color { ColorAnimation { @@ -101,22 +106,45 @@ Control { } contentItem: ColumnLayout { - Image { - id: sourceImg - source: root.source + spacing: 8 - clip: true - fillMode: Image.PreserveAspectCrop - mipmap: true - smooth: true - Layout.fillHeight: true + + MultiEffect { + id: imgEffect Layout.fillWidth: true - Layout.margins: 4 + 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 @@ -150,7 +178,7 @@ Control { ToolTip { parent: root - visible: root.hover && text.length + visible: root.hovered && text.length text: root.toolTip delay: 500 @@ -158,38 +186,23 @@ Control { MouseArea { - + acceptedButtons: Qt.NoButton hoverEnabled: true; - onEntered: { - root.hover = true - } - onExited: { - root.hover = false; privateData.ry = 0 privateData.rx = 0 } onPositionChanged: (mouse) => { - let fromCenter = root.width / 2 - privateData.ry = -((mouse.x - fromCenter) / (fromCenter * 0.05)) * root.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)) * root.power + fromCenter = root.height / 2 + privateData.rx = ((mouse.y - fromCenter) / (fromCenter * 0.05)) * root.power - } - - onPressed: { - root.presed = true; - } - - onReleased: (mouse) => { - root.presed = false; - - root.clicked(mouse) - } + } anchors.fill: parent From ee0a47e6d6e4873cc027b223f2dd16f6e74e9144 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 20 Feb 2025 19:02:16 +0100 Subject: [PATCH 09/10] update fix --- .../ActivityProcessorHeader.qml | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml index 08a15cd..c7b3aca 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessorHeader.qml @@ -9,7 +9,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -RowLayout { + +ToolBar { id: root property int titlesAligh: Text.AlignHCenter @@ -22,30 +23,36 @@ RowLayout { signal backClicked() signal closeClicked() - ToolButton { + contentItem: RowLayout { - visible: root.backButton - text: "<<" - onClicked: { - root.backClicked() + 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; + 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 + + } } - - ToolButton { - Layout.alignment: Qt.AlignRight - text: "x" - onClicked: root.closeClicked() - visible: root.closeButton - - } - } + + From ed1fd106e63972aa7bfcb51d1262ee8b1bf0388b Mon Sep 17 00:00:00 2001 From: EndrII Date: Fri, 21 Feb 2025 11:55:57 +0100 Subject: [PATCH 10/10] update guiTokens --- .../ViewSolutionsModule/ActivityProcessor.qml | 193 +++++++++--------- ViewSolutions/src/iguitokensmodel.cpp | 6 +- ViewSolutions/src/iguitokensmodel.h | 9 +- 3 files changed, 107 insertions(+), 101 deletions(-) diff --git a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml index 27823bb..00364c7 100644 --- a/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml +++ b/ViewSolutions/src/ViewSolutionsModule/ActivityProcessor.qml @@ -9,13 +9,14 @@ import QtQuick import QtQuick.Controls -Pane { +Page { id: root // use Comonent delegates only property alias initialItem: stackView.initialItem property alias currentItem: stackView.currentItem - property alias titlesAligh: headerView.titlesAligh + property int titlesAligh: Text.AlignLeft + property alias depth: stackView.depth property bool cache: true property bool enableHeader: true @@ -25,124 +26,118 @@ Pane { background: Item{} - contentItem: Page { - id: contentPage - - padding: 0 - 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: Text.AlignLeft - onBackClicked: { - root.popItem() + header: ActivityProcessorHeader { + id: headerView + visible: root.enableHeader + title: { + if (root.enableHeader && stackView.currentItem && stackView.currentItem.title) { + return stackView.currentItem.title } + return "" } - contentItem: StackView { - id: stackView + backButton: root.enableHeader && stackView.depth > 1 && (stackView.currentItem && stackView.currentItem.buttonBack) - Connections { - target: (stackView.currentItem && stackView.currentItem.finish)? stackView.currentItem : null + closeButton: root.enableHeader && (stackView.currentItem && stackView.currentItem.closeButton) + titlesAligh: root.titlesAligh + onBackClicked: { + root.popItem() + } - function onFinish() { - 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 } } + } - 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 } } + } - 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 } } + } - 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 } - } - - 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 - } + 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) { diff --git a/ViewSolutions/src/iguitokensmodel.cpp b/ViewSolutions/src/iguitokensmodel.cpp index a8697fb..2f8cbd6 100644 --- a/ViewSolutions/src/iguitokensmodel.cpp +++ b/ViewSolutions/src/iguitokensmodel.cpp @@ -15,7 +15,11 @@ QString iGUITokensModel::modelId() const { return "GUITokens"; } -QColor &iGUITokensModel::addTransporent(QColor &input, float alpha) const { +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 index d417362..98f67e5 100644 --- a/ViewSolutions/src/iguitokensmodel.h +++ b/ViewSolutions/src/iguitokensmodel.h @@ -34,10 +34,13 @@ class VIEWSOLUTION_EXPORT iGUITokensModel: public QObject, public iModel 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) @@ -89,6 +92,7 @@ public: 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; @@ -125,6 +129,9 @@ public: public: QString modelId() const; + Q_INVOKABLE QColor addTransporent(QColor input, float alpha) const; + + protected: /** * @brief addTransporent This method add alpha chennel to the color. @@ -132,7 +139,7 @@ protected: * @param alpha alphachennol factor from 0 to 1. * @return color with new alpha chennel. */ - QColor& addTransporent(QColor& input, float alpha) const; + QColor& addTransporentImpl(QColor& input, float alpha) const; }; } #endif // IGUITOKENSMODEL_H