summaryrefslogtreecommitdiff
path: root/components/CircularProgress.qml
blob: 240e520ce47747554fdf9a3b7cb8ee687eb68670 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// From https://github.com/rafzby/circular-progressbar with modifications
// License: LGPL-3.0 - A copy can be found in `licenses` folder of repo

import QtQuick

/**
 * Material 3 circular progress. See https://m3.material.io/components/progress-indicators/specs
 */
Item {
    id: root

    property int size: 30
    property int lineWidth: 2
    property real value: 0
    // property color primaryColor: Appearance.m3colors.m3onSecondaryContainer
    // property color secondaryColor: Appearance.colors.colSecondaryContainer
    property real gapAngle: Math.PI / 9
    property bool fill: false
    property int fillOverflow: 2
    property int animationDuration: 1000
    property var easingType: Easing.OutCubic

    width: size
    height: size

    signal animationFinished

    onValueChanged: {
        canvas.degree = value * 360;
    }
    // onPrimaryColorChanged: {
    //     canvas.requestPaint();
    // }
    // onSecondaryColorChanged: {
    //     canvas.requestPaint();
    // }

    Canvas {
        id: canvas

        property real degree: 0

        anchors.fill: parent
        antialiasing: true

        onDegreeChanged: {
            requestPaint();
        }

        onPaint: {
            var ctx = getContext("2d");
            var x = root.width / 2;
            var y = root.height / 2;
            var radius = root.size / 2 - root.lineWidth;
            var startAngle = (Math.PI / 180) * 270;
            var fullAngle = (Math.PI / 180) * (270 + 360);
            var progressAngle = (Math.PI / 180) * (270 + degree);
            var epsilon = 0.01; // Small angle in radians

            ctx.reset();
            if (root.fill) {
                // ctx.fillStyle = root.secondaryColor;
                ctx.beginPath();
                ctx.arc(x, y, radius + fillOverflow, startAngle, fullAngle);
                ctx.fill();
            }
            ctx.lineCap = 'round';
            ctx.lineWidth = root.lineWidth;

            // Secondary
            ctx.beginPath();
            ctx.arc(x, y, radius, progressAngle + gapAngle, fullAngle - gapAngle);
            // ctx.strokeStyle = root.secondaryColor;
            ctx.stroke();

            // Primary (value indication)
            var endAngle = progressAngle + (value > 0 ? 0 : epsilon);
            ctx.beginPath();
            ctx.arc(x, y, radius, startAngle, endAngle);
            // ctx.strokeStyle = root.primaryColor;
            ctx.stroke();
        }

        Behavior on degree {
            NumberAnimation {
                duration: root.animationDuration
                easing.type: root.easingType
            }
        }
    }
}