added new models storages

This commit is contained in:
Andrei Yankovich 2025-02-17 13:48:52 +01:00
parent 40e620ea32
commit 00a440754c
36 changed files with 1378 additions and 82 deletions

2
CMake

@ -1 +1 @@
Subproject commit c144d4d957bf63dafe9c2798b4660168cbd848e4
Subproject commit f96d16ec9be058fc35f3966e0a8dfe7d62ad3fb1

View File

@ -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()

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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"
)

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -8,6 +8,9 @@
<file>ViewSolutionsModule/ViewPortStaticPage.qml</file>
<file>ViewSolutionsModule/ViewPortStaticGradientPage.qml</file>
<file>ViewSolutionsModule/ViewSolutionsControl.qml</file>
<file>ViewSolutionsModule/ActivityProcessorHeader.qml</file>
<file>ViewSolutionsModule/ActivityProcessor.qml</file>
<file>ViewSolutionsModule/ActivityPage.qml</file>
</qresource>
<qresource prefix="/img"/>
</RCC>

View File

@ -0,0 +1,2 @@
#include "basehashmodel.h"

View File

@ -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 <QAbstractItemModel>
#include <QQmlEngine>
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<int> model
*
*
* @note to access to delegate model use Qt::EditRole role: available in qml by delegateModel keyword
* @example :
* ```
* class VariantListModel: public BaseHashModel<QVariant>
{
Q_OBJECT
public:
VariantListModel(QObject* ptr = nullptr): BaseListModel<QString, QVariant>(ptr){};
};
}
* ```
*
* @note The BaseHashModel is not support Qml space, to short access in qml use the @a BaseListModel
*/
template<class KEY, class DATA>
class BaseHashModel: public QAbstractListModel
{
public:
BaseHashModel(QObject* parent = nullptr): QAbstractListModel(parent) {
}
int rowCount(const QModelIndex &parent) const override {
return m_data.size();
}
QHash<int, QByteArray> roleNames() const override {
QHash<int, QByteArray> 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<DATA, QVariant>) {
return *iter;
} else if constexpr(std::is_base_of_v<QObject, DATA>) {
QQmlEngine::setObjectOwnership(*iter, QQmlEngine::CppOwnership);
return QVariant::fromValue(*iter);
} else if constexpr (std::is_same_v<DATA, QSharedPointer<QObject>> ||
std::is_base_of_v<QObject, typename DATA::element_type>) {
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<DATA, QVariant>) {
return val;
} else if constexpr(std::is_base_of_v<QObject, DATA>) {
QQmlEngine::setObjectOwnership(val, QQmlEngine::CppOwnership);
return QVariant::fromValue(val);
} else if constexpr (std::is_base_of_v<QSharedPointer<QObject>, DATA>) {
QObject* ptr = val.get();
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
return QVariant::fromValue(ptr);
} else {
return QVariant::fromValue(val);
}
return {};
}
const QHash<KEY, DATA>& 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<KEY, DATA> &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<KEY, DATA> m_data;
};
}
#endif // BASEHASHMODEL_H

View File

@ -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 <QAbstractItemModel>
#include <QQmlEngine>
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<Type> 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<int> model
*
*
* @note to access to delegate model use Qt::EditRole role: available in qml by delegateModel keyword
* @example :
* ```
* class VariantListModel: public BaseListModel<QVariant>
{
Q_OBJECT
BASE_LIST_MODEL_DATA_PROPERTY(QVariant)
public:
VariantListModel(QObject* ptr = nullptr): BaseListModel<QVariant>(ptr){};
};
}
* ```
*/
template<class TYPE>
class BaseListModel: public __PrvateBaseListModel
{
public:
BaseListModel(QObject* parent = nullptr): __PrvateBaseListModel(parent) {
}
int rowCount(const QModelIndex &parent) const override {
return m_data.size();
}
QHash<int, QByteArray> roleNames() const override {
QHash<int, QByteArray> 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<TYPE, QVariant>) {
return m_data[index.row()];
} else if constexpr(std::is_base_of_v<QObject, TYPE>) {
QQmlEngine::setObjectOwnership(m_data[index.row()], QQmlEngine::CppOwnership);
return QVariant::fromValue(m_data[index.row()]);
} else if constexpr (std::is_same_v<TYPE, QSharedPointer<QObject>> ||
std::is_base_of_v<QObject, typename TYPE::element_type>) {
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<TYPE> &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<TYPE>& dateList() const {
return m_data;
}
private:
QList<TYPE> m_data;
};
}
#endif // BASELISTMODEL_H

View File

@ -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 <QColor>

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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 <QColor>
#include <QFont>
#include <QObject>
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

View File

@ -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 <modelstorage.h>
namespace ViewSolutions {
const QWeakPointer<ModelStorage> &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<ModelStorage> &newStorage) {
m_storage = newStorage;
}
}

View File

@ -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 <QQmlApplicationEngine>
#include <QString>
#include <QWeakPointer>
#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<ModelStorage>& 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<ModelStorage>& newStorage);
private:
QWeakPointer<ModelStorage> m_storage;
friend class ModelStorage;
};
}
#endif // IMODEL_H

View File

@ -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 {

View File

@ -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 <QAbstractItemModel>

View File

@ -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 <QQmlEngine>
namespace ViewSolutions {
ModelStorage::ModelStorage(QQmlApplicationEngine *engine) {
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
_engine = engine;
}
bool ModelStorage::addModel(const QSharedPointer<iModel> &model) {
if (_storage.contains(model->modelId())) {
return false;
}
if (QObject* qobject = dynamic_cast<QObject*>(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<QObject*>(_storage.value(modeId).get());
}
QQmlApplicationEngine *ModelStorage::engine() const {
return _engine;
}
}

View File

@ -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 <QHash>
#include <QObject>
#include <QSharedPointer>
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<ModelStorage>
{
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<iModel>& 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 <class Type>
QSharedPointer<Type> get(const QString& modeId) const {
return _storage.value(modeId).staticCast<Type>();
}
/**
* @brief engine returns context qml engine.
* @return qml engine.
*/
QQmlApplicationEngine *engine() const;
private:
QHash<QString, QSharedPointer<iModel>> _storage;
QQmlApplicationEngine * _engine = nullptr;
};
}
#endif // MODELSTORAGE_H

View File

@ -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 <QQmlApplicationEngine>
@ -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<QQuickImageProvider*>(eng->imageProvider(id));
QQuickImageProvider* provider = dynamic_cast<QQuickImageProvider*>(_engine->imageProvider(id));
if (!provider) {
return {};
}
QString url = img.mid(urlBegin + 1);
if (provider->imageType() & QQmlImageProviderBase::ImageResponse) {
auto async = static_cast<QQuickAsyncImageProvider*>(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<QQuickAsyncImageProvider*>(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";
}
}

View File

@ -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 <QObject>
#include <imodel.h>
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

View File

@ -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<QVariant>
{
Q_OBJECT
BASE_LIST_MODEL_DATA_PROPERTY(QVariant)
public:
VariantListModel(QObject* ptr = nullptr): BaseListModel<QVariant>(ptr){};
};
}
#endif // VARIANTLISTMODEL_H

View File

@ -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 <QQmlContext>
#include <qmlcolorpicker.h>
#include <QQmlApplicationEngine>
#include <QFile>
#include <QDir>
#include <modelstorage.h>
namespace ViewSolutions {
bool init(QQmlApplicationEngine *engine) {
QSharedPointer<ModelStorage> 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<ModelStorage>::create(engine);
QQmlEngine::setObjectOwnership(storage.get(), QQmlEngine::CppOwnership);
root->setContextProperty("modelsStorage", storage.get());
auto&& picker = QSharedPointer<QMLColorPicker>::create();
storage->addModel(picker);
// to-do - remove
root->setContextProperty("colorPicker", picker.get());
qRegisterMetaType<VariantListModel>("VariantListModel");
return storage;
}
}

View File

@ -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<ModelStorage> init(QQmlApplicationEngine *engine);
}
#endif // VIEWSOLUTIONS_H