Files
plasma-bitcoin-price/contents/ui/DisplayNixie.qml
T

196 lines
6.2 KiB
QML

/*
* Nixie tube display mode — retro amber glowing digits in glass tubes.
* Glow is faked with layered text copies, so no QtGraphicalEffects
* dependency. Tubes flicker randomly (nixie cathode style); the
* flicker intensity is configurable (0 = off, 100 = nervous).
* The euro sign is plain text (default font, white), followed by a
* trend arrow (green up / red down; unchanged keeps the last arrow).
* Pure QtQuick: testable outside the plasmoid shell.
*/
import QtQuick 2.15
Row {
id: root
// wired by the parent loader
property string display: "--"
// 1 = up, -1 = down, 0 = unchanged -> keep showing the last arrow
property int trendDir: 0
property int lastDir: 0
onTrendDirChanged: {
if (trendDir !== 0) {
lastDir = trendDir;
}
}
// 0 = no flicker, 100 = frequent and deep flicker
property int flickerIntensity: 40
spacing: height * 0.05
function digitsOf(s) {
var out = "";
for (var i = 0; i < s.length; i++) {
var ch = s.charAt(i);
if (ch >= "0" && ch <= "9") {
out += ch;
}
}
return out;
}
readonly property string digits: digitsOf(display)
readonly property real tubeWidth: height * 0.52
readonly property real glowFont: height * 0.80
readonly property bool flickerOn: flickerIntensity > 0 && digits.length > 0
Repeater {
model: root.digits.length
delegate: Rectangle {
id: tube
width: root.tubeWidth
height: root.height
radius: width * 0.30
gradient: Gradient {
GradientStop { position: 0.0; color: "#3a2410" }
GradientStop { position: 0.5; color: "#241505" }
GradientStop { position: 1.0; color: "#160c03" }
}
border.color: "#4a2e12"
border.width: 1
// glass reflection strip
Rectangle {
anchors.top: parent.top
anchors.topMargin: parent.height * 0.06
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width * 0.5
height: parent.height * 0.16
radius: height / 2
color: "#ffffff"
opacity: 0.06
}
// digit + glow layers, flickered as one group
Item {
id: glowGroup
anchors.fill: parent
Text {
id: glowText
anchors.centerIn: parent
text: root.digits[index]
color: "#ffb648"
font.family: "DejaVu Serif"
font.pixelSize: root.glowFont
// layered glow: two scaled copies behind the crisp digit
Text {
anchors.centerIn: parent
text: parent.text
color: "#ff8c00"
opacity: 0.30
font: parent.font
scale: 1.24
}
Text {
anchors.centerIn: parent
text: parent.text
color: "#ff9d1e"
opacity: 0.50
font: parent.font
scale: 1.10
}
}
}
// nixie flicker: random dropout of the cathode glow.
// repeat: true keeps the cycle alive; each trigger reschedules
// the next interval (intensity 40 -> ~4 s between flicks,
// 100 -> ~1.5 s).
Timer {
id: flickTimer
repeat: true
running: root.flickerOn
interval: 1500
onTriggered: {
flick.restart();
scheduleNext();
}
function scheduleNext() {
var base = 6000 - root.flickerIntensity * 45;
interval = Math.max(700, base * (0.6 + Math.random() * 0.8));
}
Component.onCompleted: scheduleNext()
}
SequentialAnimation {
id: flick
ScriptAction {
script: {
var range = root.flickerIntensity / 100 * 0.75;
glowGroup.opacity = 1 - (0.15 + Math.random() * range);
}
}
PauseAnimation { duration: 40 + Math.random() * 140 }
NumberAnimation {
target: glowGroup
property: "opacity"
to: 1.0
duration: 90 + Math.random() * 160
easing.type: Easing.OutQuad
}
}
}
}
// breathing room between the tubes and the currency sign
Item {
width: root.height * 0.22
height: 1
}
// euro sign in the plain-text font, white
Text {
anchors.verticalCenter: parent.verticalCenter
text: "\u20AC"
visible: root.digits.length > 0
color: "#ffffff"
font.family: Qt.application.font.family
font.pixelSize: root.height * 0.85
}
// same breathing room between the euro sign and the arrow
Item {
width: root.height * 0.22
height: 1
}
// trend arrow: green up / red down; unchanged keeps the last arrow.
// The triangle glyph sits low on the baseline; shift it up so its
// visual center matches the euro sign.
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -root.height * 0.095
text: root.lastDir > 0 ? "\u25B2" : "\u25BC"
visible: root.digits.length > 0 && root.lastDir !== 0
color: root.lastDir > 0 ? "#2ecc71" : "#e74c3c"
font.family: Qt.application.font.family
font.pixelSize: root.height * 0.9
}
// error / empty state
Text {
anchors.verticalCenter: parent.verticalCenter
text: "--"
color: "#7a4e1c"
font.family: "DejaVu Serif"
font.pixelSize: root.glowFont * 0.8
visible: root.digits.length === 0
}
}