Compare commits

...

11 Commits

16 changed files with 630 additions and 0 deletions

56
CMakeLists.txt Normal file
View File

@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 3.16)
set(TARGET_APP "GenericQMLApp")
project(${TARGET_APP} VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Quick)
qt_standard_project_setup(REQUIRES 6.8)
qt_add_executable(${TARGET_APP}
main.cpp
)
qt_add_qml_module(${TARGET_APP}
URI GenericQML
QML_FILES
Main.qml
ListPage.qml
ListItemDelegate.qml
ExpandableItemDelegate.qml
EditableItemDelegate.qml
controls/PressAndHoldButton.qml
RESOURCES
icons/software-application.png
icons/moreUp.png icons/moreDown.png
icons/arrow-down.png icons/arrow-up.png
icons/list-delete.png
icons/minus-sign.png icons/plus-sign.png
)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(${TARGET_APP} PROPERTIES
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.${TARGET_APP}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
target_include_directories(${TARGET_APP} PRIVATE ${CORE_LIB_DIR}/)
target_link_libraries(${TARGET_APP} PRIVATE GenericCore)
target_link_libraries(${TARGET_APP}
PRIVATE Qt6::Quick
)
include(GNUInstallDirs)
install(TARGETS ${TARGET_APP}
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

163
EditableItemDelegate.qml Normal file
View File

@ -0,0 +1,163 @@
import QtQuick
import "controls"
Item {
//! [0]
id: delegateItem
width: listView.width
height: 80
clip: true
required property int index
// required property string edit
// required property QtObject model
required property string name
required property string description
required property string info
required property int amount
required property real factor
Rectangle {
id: background
x: 2
y: 2
width: parent.width - x * 2
height: parent.height - y * 2
color: wccDarkLight
border.color: index === listView.currentIndex ? "blue" : wccDarkDefault
border.width: 3
radius: 5
}
Column {
id: arrows
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
Image {
source: "icons/arrow-up.png"
MouseArea {
anchors.fill: parent
// onClicked: fruitModel.move(delegateItem.index,
// delegateItem.index - 1, 1)
}
}
Image {
source: "icons/arrow-down.png"
MouseArea {
anchors.fill: parent
// onClicked: fruitModel.move(delegateItem.index,
// delegateItem.index + 1, 1)
}
}
}
Column {
anchors {
left: arrows.right
horizontalCenter: parent.horizontalCenter
bottom: parent.verticalCenter
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: delegateItem.name
font.pixelSize: 15
color: "white"
}
Text {
text: delegateItem.description
color: "White"
}
}
Item {
anchors {
left: arrows.right
horizontalCenter: parent.horizontalCenter
top: parent.verticalCenter
bottom: parent.bottom
}
Row {
anchors.centerIn: parent
spacing: 10
PressAndHoldButton {
anchors.verticalCenter: parent.verticalCenter
source: "icons/plus-sign.png"
onClicked: delegateItem.factor = delegateItem.factor + 0.25
}
Text {
id: factorText
anchors.verticalCenter: parent.verticalCenter
text: 'Factor: ' + Number(delegateItem.factor).toFixed(2)
font.pixelSize: 15
color: "white"
font.bold: true
}
PressAndHoldButton {
anchors.verticalCenter: parent.verticalCenter
source: "icons/minus-sign.png"
onClicked: delegateItem.factor = Math.max(
0, delegateItem.factor - 0.25)
}
Image {
source: "icons/list-delete.png"
MouseArea {
anchors.fill: parent
onClicked: fruitModel.remove(delegateItem.index)
}
}
}
}
// Animate adding and removing of items:
//! [1]
SequentialAnimation {
id: addAnimation
PropertyAction {
target: delegateItem
property: "height"
value: 0
}
NumberAnimation {
target: delegateItem
property: "height"
to: 80
duration: 250
easing.type: Easing.InOutQuad
}
}
ListView.onAdd: addAnimation.start()
SequentialAnimation {
id: removeAnimation
PropertyAction {
target: delegateItem
property: "ListView.delayRemove"
value: true
}
NumberAnimation {
target: delegateItem
property: "height"
to: 0
duration: 250
easing.type: Easing.InOutQuad
}
// Make sure delayRemove is set back to false so that the item can be destroyed
PropertyAction {
target: delegateItem
property: "ListView.delayRemove"
value: false
}
}
ListView.onRemove: removeAnimation.start()
}

214
ExpandableItemDelegate.qml Normal file
View File

@ -0,0 +1,214 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Item {
id: item
required property int index
required property string name
required property string description
required property string info
required property int amount
required property real factor
property real detailsOpacity: 0
width: ListView.view.width
height: 70
Rectangle {
id: background
x: 2
y: 2
width: parent.width - x * 2
height: parent.height - y * 2
color: wccDarkLight
border.color: index === listView.currentIndex ? "blue" : wccDarkDefault
border.width: 3
radius: 5
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: mouse => {
parent.ListView.view.currentIndex = parent.index
if (mouse.button === Qt.RightButton) {
item.state = 'Details'
}
}
}
Row {
id: topLayout
x: 10
y: 10
height: icon.height
width: parent.width
spacing: 10
Image {
id: icon
width: 50
height: 50
source: "icons/software-application.png"
}
Column {
width: background.width - icon.width - 20
height: icon.height
spacing: 5
Text {
text: item.name
font.bold: true
font.pointSize: 16
}
Text {
text: qsTr("Details")
font.bold: true
font.pointSize: 9
opacity: item.detailsOpacity
}
Text {
text: item.description
wrapMode: Text.WordWrap
width: parent.width
font.pointSize: 9
opacity: item.detailsOpacity
}
}
}
Item {
id: details
x: 10
width: parent.width - 20
anchors {
top: topLayout.bottom
topMargin: 10
bottom: parent.bottom
bottomMargin: 10
}
opacity: item.detailsOpacity
Text {
id: moreInfoTitle
anchors.top: parent.top
text: qsTr("Further information")
font.pointSize: 9
font.bold: true
}
Flickable {
id: flick
width: parent.width
anchors {
top: moreInfoTitle.bottom
bottom: parent.bottom
}
contentHeight: infoText.height
clip: true
ColumnLayout {
Text {
id: infoText
text: item.info
wrapMode: Text.WordWrap
width: details.width
}
Text {
id: amountText
text: "Amount: " + item.amount
wrapMode: Text.WordWrap
width: details.width
}
Text {
id: factorText
text: "Factor: " + item.factor
wrapMode: Text.WordWrap
width: details.width
}
}
}
Image {
anchors {
right: flick.right
top: flick.top
}
source: "icons/moreUp.png"
opacity: flick.atYBeginning ? 0 : 1
}
Image {
anchors {
right: flick.right
bottom: flick.bottom
}
source: "icons/moreDown.png"
opacity: flick.atYEnd ? 0 : 1
}
}
Button {
y: 10
anchors {
right: background.right
rightMargin: 10
}
opacity: item.detailsOpacity
text: qsTr("Close")
onClicked: item.state = ''
}
states: State {
name: "Details"
PropertyChanges {
background.color: "white"
icon {
// Make picture bigger
width: 130
height: 130
}
item {
// Make details visible
detailsOpacity: 1
x: 0
// Fill the entire list area with the detailed view
height: listView.height
}
}
// Move the list so that this item is at the top.
PropertyChanges {
item.ListView.view.contentY: item.y
explicit: true
}
// Disallow flicking while we're in detailed view
PropertyChanges {
item.ListView.view.interactive: false
}
}
transitions: Transition {
// Make the state changes smooth
ParallelAnimation {
ColorAnimation {
property: "color"
duration: 500
}
NumberAnimation {
duration: 300
properties: "detailsOpacity,x,contentY,height,width"
}
}
}
}

24
ListItemDelegate.qml Normal file
View File

@ -0,0 +1,24 @@
import QtQuick
Item {
id: myItem
required property int index
required property string name
required property string info
property int fontSize: 16
width: parent.width
height: 40
Column {
Text {
text: '<b>Name:</b> ' + myItem.name
}
Text {
text: '<b>Info:</b> ' + myItem.info
}
}
MouseArea {
anchors.fill: parent
onClicked: parent.ListView.view.currentIndex = parent.index
}
}

61
ListPage.qml Normal file
View File

@ -0,0 +1,61 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls.Material
Page {
id: page
ListView {
id: listView
anchors.fill: parent
focus: true
clip: true
model: mainModel
delegateModelAccess: DelegateModel.ReadWrite
// delegate: ListItemDelegate {}
// delegate: ExpandableItemDelegate {}
delegate: EditableItemDelegate {}
header: bannercomponent
footer: Rectangle {
width: parent.width
height: 30
gradient: mainGradient
}
}
Component {
//instantiated when header is processed
id: bannercomponent
Rectangle {
id: banner
width: parent.width
height: 50
gradient: mainGradient
border {
color: wccPurpleDark
width: 2
}
Text {
anchors.centerIn: parent
text: window.title
font.pixelSize: 32
color: wccDarkLight
}
}
}
Gradient {
id: mainGradient
GradientStop {
position: 0.0
color: wccPurpleDefault
}
GradientStop {
position: 0.66
color: wccPurpleDark
}
}
}

32
Main.qml Normal file
View File

@ -0,0 +1,32 @@
import QtQuick
import QtQuick.Layouts
import QtQml.Models
Window {
id: window
width: 480
height: 800
visible: true
title: `${Application.name}`
property int fontSize: 16
property color textColor: "black"
property color wccDarkDark: "#010101"
property color wccDarkDefault: "#3C3B3B"
property color wccDarkLight: "#828282"
property color wccPurpleDark: "#631A61"
property color wccPurpleDefault: "#A834A5"
property color wccPurpleLight: "#E88FE5"
property color wccLavenderDark: "#8C52FF"
property color wccLavenderDefault: "#9D74EE"
property color wccLavenderLight: "#BC9AFF"
ListPage {
id: listPage
anchors.fill: parent
}
}

View File

@ -0,0 +1,45 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
Image {
id: container
property int repeatDelay: 300
property int repeatDuration: 75
property bool pressed
signal clicked
scale: pressed ? 0.9 : 1
function release() {
autoRepeatClicks.stop()
container.pressed = false
}
SequentialAnimation on pressed {
id: autoRepeatClicks
running: false
PropertyAction { target: container; property: "pressed"; value: true }
ScriptAction { script: container.clicked() }
PauseAnimation { duration: container.repeatDelay }
SequentialAnimation {
loops: Animation.Infinite
ScriptAction { script: container.clicked() }
PauseAnimation { duration: container.repeatDuration }
}
}
MouseArea {
anchors.fill: parent
onPressed: autoRepeatClicks.start()
onReleased: container.release()
onCanceled: container.release()
}
}

BIN
icons/arrow-down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

BIN
icons/arrow-up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

BIN
icons/list-delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

BIN
icons/minus-sign.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

BIN
icons/moreDown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

BIN
icons/moreUp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

BIN
icons/plus-sign.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

35
main.cpp Normal file
View File

@ -0,0 +1,35 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <model/generalsortfiltermodel.h>
#include "genericcore.h"
#ifdef QT_DEBUG
#include "utils/messagehandler.h"
#endif
int main(int argc, char* argv[]) {
#ifdef QT_DEBUG
qInstallMessageHandler(consoleHandlerColoredVerboseInDarkTheme);
#endif
QGuiApplication app(argc, argv);
std::unique_ptr<GenericCore> core = std::make_unique<GenericCore>();
std::shared_ptr<GeneralSortFilterModel> mainModel = core->getSortFilterModel();
// qInfo() << "QMLApp Version:" << QMLAPP_VERSION;
qInfo() << "core->getString():" << core->toString();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty(QStringLiteral("core"), core.get());
engine.rootContext()->setContextProperty(QStringLiteral("mainModel"), mainModel.get());
QObject::connect(
&engine, &QQmlApplicationEngine::objectCreationFailed, &app,
[]() { QCoreApplication::exit(-1); }, Qt::QueuedConnection);
engine.loadFromModule("GenericQML", "Main");
return app.exec();
}