From 6f688ae1aab0a79d56fa75cefd607ab22b2b4811 Mon Sep 17 00:00:00 2001 From: miruka Date: Thu, 21 May 2020 19:54:35 -0400 Subject: [PATCH] Implement circle progress bars in QML --- mirage.pro | 2 - src/gui/Base/HBusyIndicator.qml | 16 ++++- src/gui/Base/HCircleProgressBar.qml | 92 ++++++++++++++++++----------- src/gui/Base/HImage.qml | 5 +- src/gui/LoadingScreen.qml | 14 +++-- src/main.cpp | 8 --- 6 files changed, 83 insertions(+), 54 deletions(-) diff --git a/mirage.pro b/mirage.pro index 75d111f7..a9ea86f5 100644 --- a/mirage.pro +++ b/mirage.pro @@ -13,10 +13,8 @@ QRC_FILE = $$BUILD_DIR/resources.qrc RESOURCES += $$QRC_FILE HEADERS += src/utils.h src/clipboard.h \ - submodules/RadialBarDemo/radialbar.h \ submodules/hsluv-c/src/hsluv.h SOURCES += src/main.cpp src/utils.cpp src/clipboard.cpp \ - submodules/RadialBarDemo/radialbar.cpp \ submodules/hsluv-c/src/hsluv.c TARGET = mirage diff --git a/src/gui/Base/HBusyIndicator.qml b/src/gui/Base/HBusyIndicator.qml index 1b75ad02..3fe4f063 100644 --- a/src/gui/Base/HBusyIndicator.qml +++ b/src/gui/Base/HBusyIndicator.qml @@ -1,9 +1,19 @@ // SPDX-License-Identifier: LGPL-3.0-or-later import QtQuick 2.12 -import QtQuick.Controls 2.12 HCircleProgressBar { - indeterminate: true - dialWidth: 2 + progress: 0.5 + + label.visible: false + baseCircle.strokeWidth: 2 + progressCircle.strokeWidth: 2 + + + HNumberAnimation on rotation { + from: 0 + to: 360 + loops: Animation.Infinite + duration: theme ? (theme.animationDuration * 6) : 600 + } } diff --git a/src/gui/Base/HCircleProgressBar.qml b/src/gui/Base/HCircleProgressBar.qml index ab85d43b..290be8e3 100644 --- a/src/gui/Base/HCircleProgressBar.qml +++ b/src/gui/Base/HCircleProgressBar.qml @@ -1,50 +1,76 @@ // SPDX-License-Identifier: LGPL-3.0-or-later import QtQuick 2.12 -import RadialBar 1.0 +import QtQuick.Shapes 1.12 -RadialBar { - id: bar + +Item { implicitWidth: 96 * (theme ? theme.uiScale : 1) implicitHeight: implicitWidth - foregroundColor: theme.controls.circleProgressBar.background - progressColor: theme.controls.circleProgressBar.foreground - dialWidth: theme.controls.circleProgressBar.thickness - startAngle: 0 - spanAngle: 360 - from: 0 - to: 1 - value: 0 - - showText: true - textFont.pixelSize: theme ? theme.fontSize.big : 22 - textColor: theme ? theme.controls.circleProgressBar.text : "white" + layer.enabled: true + layer.samples: 4 + layer.smooth: true - property alias from: bar.minValue - property alias to: bar.maxValue - property bool indeterminate: false + property real progress: 0 // 0-1 - property real indeterminateSpan: - theme.controls.circleProgressBar.indeterminateSpan + readonly property alias baseCircle: baseCircle + readonly property alias progressCircle: progressCircle + readonly property alias label: label - Binding on value { - value: bar.to * bar.indeterminateSpan - when: bar.indeterminate + HLabel { + id: label + anchors.centerIn: parent + text: progressNumber + "%" + font.pixelSize: theme ? theme.fontSize.big : 22 + + property int progressNumber: Math.floor(progress * 100) + + Behavior on progressNumber { HNumberAnimation { factor: 2 } } } - Binding on showText { - value: false - when: bar.indeterminate - } + Shape { + id: shape + anchors.fill: parent + asynchronous: true - HNumberAnimation on rotation { - running: bar.indeterminate - from: 0 - to: 360 - loops: Animation.Infinite - duration: theme ? (theme.animationDuration * 6) : 600 + ShapePath { + id: baseCircle + fillColor: "transparent" + strokeColor: theme.controls.circleProgressBar.background + strokeWidth: theme.controls.circleProgressBar.thickness + capStyle: ShapePath.RoundCap + startX: shape.width / 2 + startY: strokeWidth + + PathAngleArc { + centerX: shape.width / 2 + centerY: shape.height / 2 + radiusX: shape.width / 2 - baseCircle.strokeWidth + radiusY: shape.height / 2 - baseCircle.strokeWidth + sweepAngle: 360 + } + } + + ShapePath { + id: progressCircle + fillColor: baseCircle.fillColor + strokeColor: theme.controls.circleProgressBar.foreground + strokeWidth: baseCircle.strokeWidth + + PathAngleArc { + centerX: shape.width / 2 + centerY: shape.height / 2 + radiusX: shape.width / 2 - progressCircle.strokeWidth + radiusY: shape.height / 2 - progressCircle.strokeWidth + startAngle: 270 + sweepAngle: progress * 360 + + Behavior on startAngle { HNumberAnimation {} } + Behavior on sweepAngle { HNumberAnimation {} } + } + } } } diff --git a/src/gui/Base/HImage.qml b/src/gui/Base/HImage.qml index 6895d4bf..8f262baa 100644 --- a/src/gui/Base/HImage.qml +++ b/src/gui/Base/HImage.qml @@ -110,10 +110,7 @@ Image { sourceComponent: HCircleProgressBar { id: progressBar - value: image.progress - text: Math.round(value * 100) + "%" - - Behavior on value { HNumberAnimation { factor: 2 } } + progress: image.progress } } diff --git a/src/gui/LoadingScreen.qml b/src/gui/LoadingScreen.qml index c619173e..b47d985f 100644 --- a/src/gui/LoadingScreen.qml +++ b/src/gui/LoadingScreen.qml @@ -4,15 +4,21 @@ import QtQuick 2.12 import "Base" Rectangle { - color: utils.hsluv(0, 0, 0, 0.5) + color: utils.hsluv(0, 0, 0, 0.7) HBusyIndicator { anchors.centerIn: parent width: Math.min(160, parent.width - 16, parent.height - 16) height: width - indeterminateSpan: 0.5 - foregroundColor: utils.hsluv(240, 60 / 1.5 * 2, 0, 0.7) - progressColor: utils.hsluv(240, 60 * 1.5, 72) + // Because the theme is not loaded at this point, we must set these + // properties manually: + baseCircle.strokeColor: utils.hsluv(240, 60 / 1.5 * 2, 0, 0.7) + progressCircle.strokeColor: utils.hsluv(240, 60 * 1.5, 72) + label.font.family: "Roboto" + label.font.pixelSize: 0 + label.color: "black" + label.linkColor: "black" + } } diff --git a/src/main.cpp b/src/main.cpp index 0a78b090..6bd5933c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,8 +16,6 @@ #include #endif -#include "../submodules/RadialBarDemo/radialbar.h" - #include "utils.h" #include "clipboard.h" @@ -149,12 +147,6 @@ int main(int argc, char *argv[]) { } ); - // Register our custom visual items that will be importable from QML, e.g. - // import RadialBar 1.0 - // ... - // RadialBar { ... } - qmlRegisterType("RadialBar", 1, 0, "RadialBar"); - // Create the QML root component by loading its file from the Qt Resource // System or local file system if not possible. QQmlComponent component(