145 lines
3.9 KiB
QML
145 lines
3.9 KiB
QML
/*
|
|
* Split-flap display mode — airport departure board style.
|
|
* White characters on black cells with a flap split line;
|
|
* changed characters flip with a cascading animation.
|
|
* Pure QtQuick so it can be tested outside the plasmoid shell.
|
|
*/
|
|
|
|
import QtQuick 2.15
|
|
|
|
Row {
|
|
id: root
|
|
|
|
// wired by the parent loader
|
|
property string display: "--"
|
|
property color trendColor: "#9e9e9e"
|
|
|
|
spacing: height * 0.06
|
|
|
|
property var chars: []
|
|
property bool ready: false
|
|
readonly property real cellFont: height * 0.72
|
|
readonly property real cellWidth: cellFont * 0.80
|
|
|
|
Component.onCompleted: {
|
|
chars = display.split("");
|
|
ready = true;
|
|
}
|
|
|
|
onDisplayChanged: {
|
|
if (!ready) {
|
|
return;
|
|
}
|
|
var nc = display.split("");
|
|
var n = Math.max(chars.length, nc.length);
|
|
for (var i = 0; i < n; i++) {
|
|
var from = i < chars.length ? chars[i] : "";
|
|
var to = i < nc.length ? nc[i] : "";
|
|
if (from !== to) {
|
|
var cell = rep.itemAt(i);
|
|
if (cell) {
|
|
cell.flipTo(to, i * 45);
|
|
}
|
|
}
|
|
}
|
|
chars = nc;
|
|
}
|
|
|
|
Repeater {
|
|
id: rep
|
|
model: root.chars.length
|
|
|
|
delegate: Rectangle {
|
|
id: cell
|
|
|
|
width: root.cellWidth
|
|
height: root.height
|
|
radius: 2
|
|
color: "#0b0b0d"
|
|
border.color: "#26262b"
|
|
border.width: 1
|
|
|
|
// plain property (not a binding) so the flip animation
|
|
// controls when the character actually changes
|
|
property string ch: ""
|
|
property string pendingCh: ""
|
|
|
|
Component.onCompleted: {
|
|
ch = root.chars[index] !== undefined ? root.chars[index] : "";
|
|
}
|
|
|
|
function flipTo(newCh, delay) {
|
|
if (newCh === ch) {
|
|
return;
|
|
}
|
|
pendingCh = newCh;
|
|
delayTimer.interval = Math.max(0, delay);
|
|
delayTimer.restart();
|
|
}
|
|
|
|
Timer {
|
|
id: delayTimer
|
|
interval: 0
|
|
onTriggered: flipAnim.start()
|
|
}
|
|
|
|
transform: Scale {
|
|
id: scaleTransform
|
|
origin.y: cell.height / 2
|
|
yScale: 1
|
|
}
|
|
|
|
SequentialAnimation {
|
|
id: flipAnim
|
|
NumberAnimation {
|
|
target: scaleTransform
|
|
property: "yScale"
|
|
to: 0.06
|
|
duration: 130
|
|
easing.type: Easing.InQuad
|
|
}
|
|
ScriptAction {
|
|
script: cell.ch = cell.pendingCh
|
|
}
|
|
NumberAnimation {
|
|
target: scaleTransform
|
|
property: "yScale"
|
|
to: 1
|
|
duration: 130
|
|
easing.type: Easing.OutQuad
|
|
}
|
|
}
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: cell.ch
|
|
color: "#f2f2f2"
|
|
font.family: "DejaVu Sans Mono"
|
|
font.pixelSize: root.cellFont
|
|
}
|
|
|
|
// the flap split line across the middle
|
|
Rectangle {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
y: parent.height / 2 - 1
|
|
width: parent.width
|
|
height: 2
|
|
color: "#000000"
|
|
opacity: 0.55
|
|
}
|
|
}
|
|
}
|
|
|
|
// trend LED (green/red/grey) — boards are monochrome, so the
|
|
// trend shows here instead of in the letter color
|
|
Rectangle {
|
|
width: root.height * 0.14
|
|
height: width
|
|
radius: width / 2
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: root.trendColor
|
|
border.color: "#26262b"
|
|
border.width: 1
|
|
}
|
|
}
|