81 lines
2.6 KiB
QML
81 lines
2.6 KiB
QML
// The fifteen seconds a display change has left, drawn as a ring.
|
|
//
|
|
// Repainted once per second, when `secondsLeft` changes, and never otherwise:
|
|
// this shell has no idle animation, and a countdown that redraws every frame
|
|
// would be one -- on a 240 Hz panel it is 240 repaints to move a number that
|
|
// changes once.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property int secondsLeft: 0
|
|
property int totalSeconds: 15
|
|
|
|
implicitWidth: 40
|
|
implicitHeight: 40
|
|
|
|
// A Canvas reads Theme inside onPaint, where nothing records a dependency
|
|
// on it, so a palette change would leave the ring drawn in the old warn
|
|
// tone until the next tick -- or for good, on a countdown sitting still.
|
|
// Naming the color as a property gives the repaint something to watch.
|
|
readonly property color ringColor: Theme.warn
|
|
|
|
onSecondsLeftChanged: ring.requestPaint()
|
|
onTotalSecondsChanged: ring.requestPaint()
|
|
onRingColorChanged: ring.requestPaint()
|
|
onVisibleChanged: if (root.visible) ring.requestPaint()
|
|
|
|
Canvas {
|
|
id: ring
|
|
|
|
anchors.fill: parent
|
|
|
|
onPaint: {
|
|
const context = ring.getContext("2d");
|
|
context.reset();
|
|
|
|
const stroke = 3.5;
|
|
const radius = Math.min(ring.width, ring.height) / 2 - stroke / 2 - 1;
|
|
const centreX = ring.width / 2;
|
|
const centreY = ring.height / 2;
|
|
if (radius <= 0)
|
|
return;
|
|
|
|
context.lineWidth = stroke;
|
|
context.lineCap = "round";
|
|
|
|
context.strokeStyle = Theme.alpha(Theme.warn, 0.18);
|
|
context.beginPath();
|
|
context.arc(centreX, centreY, radius, 0, Math.PI * 2);
|
|
context.stroke();
|
|
|
|
const remaining = root.totalSeconds > 0
|
|
? Math.max(0, Math.min(1, root.secondsLeft / root.totalSeconds))
|
|
: 0;
|
|
if (remaining <= 0)
|
|
return;
|
|
|
|
// Twelve o'clock, clockwise, so the arc empties the way a clock
|
|
// face does rather than unwinding backwards.
|
|
context.strokeStyle = Theme.warn;
|
|
context.beginPath();
|
|
context.arc(centreX, centreY, radius,
|
|
-Math.PI / 2, -Math.PI / 2 + remaining * Math.PI * 2);
|
|
context.stroke();
|
|
}
|
|
}
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: String(Math.max(0, root.secondsLeft))
|
|
color: Theme.warn
|
|
font.family: Theme.fontFamily
|
|
font.features: Theme.tabularFigures
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Font.DemiBold
|
|
}
|
|
}
|