nosignal-shell/components/controls/CircularProgress.qml
2026-04-23 22:42:41 +10:00

102 lines
2.9 KiB
QML

import QtQuick
import QtQuick.Shapes
import Caelestia.Components
import Caelestia.Config
import qs.components
import qs.services
Item {
id: root
property real value
property int startAngle: -90
property int sweepAngle: 360
property int strokeWidth: Tokens.padding.small
property int padding: 0
property int spacing: Tokens.spacing.small
property color fgColour: Colours.palette.m3primary
property color bgColour: Colours.palette.m3secondaryContainer
property bool wavy: false
property alias waveFrequency: wave.frequency
property alias waveAmplitude: wave.amplitudeMultiplier
property alias wavePaused: waveProgAnim.paused
property alias waveDuration: waveProgAnim.duration
readonly property real size: Math.min(width, height)
readonly property real arcRadius: (size - padding - strokeWidth * (1 + waveAmplitude * 2)) / 2
readonly property real clampedVal: Math.max(1 / 360, Math.min(1, value))
readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI)
readonly property real thickness: strokeWidth * (1 + waveAmplitude) * 2 // For consumers
property real implicitSize
implicitWidth: implicitSize
implicitHeight: implicitSize
Shape {
preferredRendererType: Shape.CurveRenderer
asynchronous: true
opacity: Math.min(1, remainingArc.sweepAngle)
ShapePath {
fillColor: "transparent"
strokeColor: root.bgColour
strokeWidth: Math.min(1, remainingArc.sweepAngle) * root.strokeWidth
capStyle: ShapePath.RoundCap
PathAngleArc {
id: remainingArc
radiusX: root.arcRadius
radiusY: root.arcRadius
centerX: root.size / 2
centerY: root.size / 2
startAngle: root.startAngle + root.clampedVal * root.sweepAngle + root.gapAngle
sweepAngle: Math.max(1 / 360, root.sweepAngle * (1 - root.clampedVal) - root.gapAngle * 2)
}
Behavior on strokeColor {
CAnim {}
}
}
}
WavyLine {
id: wave
anchors.fill: parent
anchors.margins: -lineWidth * amplitudeMultiplier
lineWidth: root.strokeWidth
color: root.fgColour
pathType: WavyLine.Arc
radius: root.arcRadius
startAngle: root.startAngle
fullAngle: root.sweepAngle
value: root.clampedVal
frequency: 8
amplitudeMultiplier: root.wavy ? 0.5 : 0
Anim on waveProgress {
id: waveProgAnim
running: true
from: 0
to: 1
duration: 2000
easing.type: Easing.Linear
loops: Animation.Infinite
}
Behavior on color {
CAnim {}
}
Behavior on amplitudeMultiplier {
Anim {
type: Anim.DefaultEffects
}
}
}
}