The dense bar's panel chrome gets a squarer outline (top-right and bottom-left
chamfers only, square on the other two corners) and a second accent line in
the lower right to balance the existing upper-left one.
The chrome then moves out of DenseBarContent's inline `component
TelemetryPanel` into its own file. The call sites are unchanged apart from the
name -- children still come from the default property -- and the widgets they
pass in (RadarGauge, NetworkTrace, MetricBlock) stay declared in
DenseBarContent, so their scope is unaffected by moving only the definition.
Two things could not come along and had to be reproduced locally, because a
component in its own file has no access to the enclosing scope:
- the palette and the two font families, previously read off `root`. They
are properties with defaults matching DenseBarContent's, which is this
repo's per-component convention. Duplicated on purpose for now; a shared
theme singleton is the place to collapse it.
- MicroText, which is an *inline* component of DenseBarContent and so
invisible from another file. Expanded to the Text it desugars to.
Also qualified the bare offsetY/chamfer/accentLineThickness references as
panel.*; they resolved through the component scope before, but being explicit
avoids ComponentBehavior: Bound warnings in the new file.
Verified the move was verbatim by normalising the old inline block and the new
file body and diffing them -- the only differences are the relocated property
block, the panel.* qualification and the MicroText expansion. Loads clean both
headlessly and in the real layer-shell shell.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx
697 lines
25 KiB
QML
697 lines
25 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import QtQuick.Shapes
|
|
|
|
// Renderable visual core for the desktop telemetry rail. Runtime services stay
|
|
// in DenseBar.qml so this Item can be exercised without Wayland or Hyprland.
|
|
Item {
|
|
id: root
|
|
|
|
implicitWidth: 1920
|
|
implicitHeight: 164
|
|
|
|
readonly property color voidColor: "#0a0a0a"
|
|
readonly property color inkColor: "#dedede"
|
|
readonly property color mutedColor: "#858585"
|
|
readonly property color accentColor: "#e8722a"
|
|
readonly property color hairColor: Qt.rgba(0.87, 0.87, 0.87, 0.28)
|
|
readonly property bool compact: width <= 1400
|
|
readonly property string displayFont: "DepartureMono Nerd Font"
|
|
readonly property string microFont: "DejaVu Sans Mono"
|
|
|
|
property bool autoClock: true
|
|
property date now: new Date()
|
|
property string hostName: "LOCAL"
|
|
property bool telemetryReady: false
|
|
property bool ratesReady: false
|
|
property real cpuFraction: 0
|
|
property int cpuThreads: 0
|
|
property real memoryFraction: 0
|
|
property string memoryUsedText: "--"
|
|
property real temperatureCelsius: NaN
|
|
property string networkInterface: "NET"
|
|
property string networkRxText: "--"
|
|
property string networkTxText: "--"
|
|
property real storageFraction: 0
|
|
property string storageFreeText: "-- FREE"
|
|
property var workspaceIds: [1, 2, 3, 4]
|
|
property int activeWorkspaceId: 1
|
|
property int trayCount: 0
|
|
property real audioFraction: 0
|
|
property bool audioMuted: false
|
|
|
|
signal workspaceActivated(int workspaceId)
|
|
|
|
function pct(value, ready) {
|
|
return ready ? Math.round(Math.max(0, Math.min(1, value)) * 100) : 0;
|
|
}
|
|
|
|
function two(value) {
|
|
return value < 10 ? "0" + value : String(value);
|
|
}
|
|
|
|
function timeText(value) {
|
|
return root.two(value.getHours()) + ":" + root.two(value.getMinutes());
|
|
}
|
|
|
|
function dateText(value) {
|
|
const days = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
|
const months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
|
|
return days[value.getDay()] + " // " + root.two(value.getDate()) + " " + months[value.getMonth()];
|
|
}
|
|
|
|
Timer {
|
|
interval: 30000
|
|
running: root.autoClock
|
|
repeat: true
|
|
triggeredOnStart: true
|
|
onTriggered: root.now = new Date()
|
|
}
|
|
|
|
// Faint drafting grid; no gradient and deliberately subordinate to data.
|
|
Repeater {
|
|
model: Math.ceil(root.width / 40)
|
|
Rectangle {
|
|
required property int index
|
|
x: index * 40
|
|
width: 1
|
|
height: root.height
|
|
color: root.inkColor
|
|
opacity: 0.018
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
model: Math.ceil(root.height / 40)
|
|
Rectangle {
|
|
required property int index
|
|
y: index * 40
|
|
width: root.width
|
|
height: 1
|
|
color: root.inkColor
|
|
opacity: 0.018
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: array
|
|
x: 12
|
|
y: 8
|
|
width: root.width - 24
|
|
height: 92
|
|
|
|
readonly property real identityWidth: root.compact ? 250 : 320
|
|
readonly property real radarWidth: root.compact ? 130 : 164
|
|
readonly property real stateWidth: root.compact ? 210 : 250
|
|
readonly property real flexWidth: Math.max(250, (width - identityWidth - radarWidth - stateWidth - 32) / 2)
|
|
|
|
Row {
|
|
anchors.fill: parent
|
|
spacing: 8
|
|
|
|
StatusBarPanel {
|
|
width: array.identityWidth
|
|
height: array.height
|
|
panelId: "001"
|
|
title: "COMMAND LAYER"
|
|
|
|
Text {
|
|
x: 12
|
|
y: 34
|
|
text: root.hostName.toUpperCase()
|
|
color: root.inkColor
|
|
font.family: root.displayFont
|
|
font.pixelSize: root.compact ? 20 : 25
|
|
font.bold: true
|
|
font.letterSpacing: 2
|
|
elide: Text.ElideRight
|
|
width: parent.width - 92
|
|
}
|
|
|
|
Text {
|
|
x: 13
|
|
y: 63
|
|
text: "STATUS ARRAY // " + (root.telemetryReady ? "LIVE" : "STANDBY")
|
|
color: root.accentColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 7
|
|
font.letterSpacing: 1.4
|
|
}
|
|
|
|
Rectangle {
|
|
x: parent.width - 75
|
|
y: 36
|
|
width: 1
|
|
height: 43
|
|
color: root.hairColor
|
|
}
|
|
|
|
Rectangle {
|
|
x: parent.width - 62
|
|
y: 42
|
|
width: 5
|
|
height: 5
|
|
color: root.accentColor
|
|
opacity: root.telemetryReady ? 1 : 0.35
|
|
}
|
|
|
|
Text {
|
|
x: parent.width - 50
|
|
y: 38
|
|
text: root.telemetryReady ? "ONLINE" : "LOCAL"
|
|
color: root.accentColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 7
|
|
}
|
|
|
|
Text {
|
|
x: parent.width - 63
|
|
y: 57
|
|
text: "NODE // " + (root.hostName || "--").toUpperCase().slice(0, 7)
|
|
color: root.mutedColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 6
|
|
}
|
|
|
|
Shape {
|
|
x: parent.width - 63
|
|
y: 71
|
|
width: 48
|
|
height: 10
|
|
ShapePath {
|
|
fillColor: "transparent"
|
|
strokeColor: root.accentColor
|
|
strokeWidth: 1
|
|
startX: 0; startY: 6
|
|
PathLine { x: 11; y: 6 }
|
|
PathLine { x: 16; y: 1 }
|
|
PathLine { x: 22; y: 9 }
|
|
PathLine { x: 27; y: 6 }
|
|
PathLine { x: 48; y: 6 }
|
|
}
|
|
}
|
|
}
|
|
|
|
StatusBarPanel {
|
|
width: array.flexWidth
|
|
height: array.height
|
|
panelId: "02"
|
|
title: "RESOURCE LATTICE"
|
|
meta: root.telemetryReady ? "REALTIME" : "FALLBACK"
|
|
|
|
Row {
|
|
x: 11
|
|
y: 32
|
|
width: parent.width - 22
|
|
height: 51
|
|
spacing: root.compact ? 7 : 12
|
|
|
|
MetricBlock {
|
|
width: (parent.width - parent.spacing * (root.compact ? 1 : 2)) / (root.compact ? 2 : 3)
|
|
label: "CPU"
|
|
value: root.cpuFraction
|
|
ready: root.ratesReady
|
|
readout: root.ratesReady ? root.pct(root.cpuFraction, true) + "%" : "--"
|
|
detailLeft: "CORE:" + (root.cpuThreads || "--")
|
|
detailRight: root.ratesReady ? "BUSY" : "PRIME"
|
|
}
|
|
|
|
MetricBlock {
|
|
width: (parent.width - parent.spacing * (root.compact ? 1 : 2)) / (root.compact ? 2 : 3)
|
|
label: "MEM"
|
|
value: root.memoryFraction
|
|
ready: root.telemetryReady
|
|
readout: root.telemetryReady ? root.pct(root.memoryFraction, true) + "%" : "--"
|
|
detailLeft: "ALLOC"
|
|
detailRight: root.memoryUsedText
|
|
}
|
|
|
|
MetricBlock {
|
|
visible: !root.compact
|
|
width: (parent.width - parent.spacing * 2) / 3
|
|
label: "THERM"
|
|
value: isFinite(root.temperatureCelsius) ? root.temperatureCelsius / 100 : 0
|
|
ready: isFinite(root.temperatureCelsius)
|
|
readout: isFinite(root.temperatureCelsius) ? Math.round(root.temperatureCelsius) + "°C" : "--"
|
|
detailLeft: "ZONE:01"
|
|
detailRight: isFinite(root.temperatureCelsius) && root.temperatureCelsius >= 85 ? "HOT" : "NOMINAL"
|
|
}
|
|
}
|
|
}
|
|
|
|
StatusBarPanel {
|
|
width: array.radarWidth
|
|
height: array.height
|
|
panelId: "03"
|
|
title: "SCAN"
|
|
|
|
RadarGauge {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
y: 28
|
|
size: 57
|
|
level: root.cpuFraction
|
|
}
|
|
}
|
|
|
|
StatusBarPanel {
|
|
width: array.flexWidth
|
|
height: array.height
|
|
panelId: "04"
|
|
title: "CARRIER UPLINK"
|
|
meta: root.networkInterface.toUpperCase()
|
|
|
|
NetworkTrace {
|
|
x: 12
|
|
y: 43
|
|
width: parent.width - (root.compact ? 117 : 145)
|
|
height: 33
|
|
level: root.ratesReady ? root.cpuFraction : 0.25
|
|
}
|
|
|
|
Column {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 14
|
|
y: 34
|
|
width: root.compact ? 92 : 116
|
|
spacing: 1
|
|
|
|
Text {
|
|
width: parent.width
|
|
text: root.networkRxText
|
|
horizontalAlignment: Text.AlignRight
|
|
color: root.accentColor
|
|
font.family: root.displayFont
|
|
font.pixelSize: root.compact ? 11 : 13
|
|
font.bold: true
|
|
elide: Text.ElideLeft
|
|
}
|
|
MicroText { width: parent.width; text: "RX // DOWN"; horizontalAlignment: Text.AlignRight }
|
|
Text {
|
|
width: parent.width
|
|
text: root.networkTxText
|
|
horizontalAlignment: Text.AlignRight
|
|
color: root.inkColor
|
|
font.family: root.displayFont
|
|
font.pixelSize: root.compact ? 11 : 13
|
|
font.bold: true
|
|
elide: Text.ElideLeft
|
|
}
|
|
MicroText { width: parent.width; text: "TX // UP"; horizontalAlignment: Text.AlignRight }
|
|
}
|
|
}
|
|
|
|
StatusBarPanel {
|
|
width: array.stateWidth
|
|
height: array.height
|
|
panelId: "05"
|
|
title: "SYSTEM STATE"
|
|
|
|
Row {
|
|
x: 10
|
|
y: 35
|
|
spacing: 6
|
|
|
|
StateCell { code: "N"; active: root.ratesReady; label: "NET" }
|
|
StateCell { code: root.audioMuted ? "M" : "A"; active: !root.audioMuted; label: "AUD" }
|
|
StateCell { visible: !root.compact; code: String(root.trayCount); active: root.trayCount > 0; label: "TRAY" }
|
|
}
|
|
|
|
Rectangle {
|
|
x: root.compact ? 101 : 151
|
|
y: 33
|
|
width: 1
|
|
height: 46
|
|
color: root.hairColor
|
|
}
|
|
|
|
Column {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 12
|
|
y: 34
|
|
width: root.compact ? 91 : 82
|
|
spacing: 2
|
|
|
|
Text {
|
|
width: parent.width
|
|
text: root.timeText(root.now)
|
|
horizontalAlignment: Text.AlignRight
|
|
color: root.inkColor
|
|
font.family: root.displayFont
|
|
font.pixelSize: root.compact ? 20 : 22
|
|
font.bold: true
|
|
font.letterSpacing: 1
|
|
}
|
|
Text {
|
|
width: parent.width
|
|
text: root.dateText(root.now)
|
|
horizontalAlignment: Text.AlignRight
|
|
color: root.accentColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 6
|
|
elide: Text.ElideLeft
|
|
}
|
|
MicroText { width: parent.width; text: "LOCAL TIME"; horizontalAlignment: Text.AlignRight }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
StatusBarPanel {
|
|
id: rail
|
|
x: 12
|
|
y: 108
|
|
width: root.width - 24
|
|
height: 34
|
|
showHeader: false
|
|
chamfer: 10
|
|
|
|
Row {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 10
|
|
anchors.rightMargin: 10
|
|
|
|
RailSection {
|
|
width: root.compact ? 252 : 310
|
|
Text {
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: "06 // DESKTOP"
|
|
color: root.accentColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 7
|
|
font.letterSpacing: 1
|
|
}
|
|
Row {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 8
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: 3
|
|
Repeater {
|
|
model: root.workspaceIds.slice(0, root.compact ? 4 : 6)
|
|
Rectangle {
|
|
required property var modelData
|
|
width: 24
|
|
height: 17
|
|
color: Number(modelData) === root.activeWorkspaceId ? Qt.rgba(0.91, 0.45, 0.16, 0.18) : "transparent"
|
|
border.width: 1
|
|
border.color: Number(modelData) === root.activeWorkspaceId ? root.accentColor : root.hairColor
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: root.two(Number(parent.modelData))
|
|
color: Number(parent.modelData) === root.activeWorkspaceId ? root.accentColor : root.mutedColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 7
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: root.workspaceActivated(Number(parent.modelData))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RailSection {
|
|
width: root.compact ? 260 : 410
|
|
MicroText { x: 9; anchors.verticalCenter: parent.verticalCenter; text: "PROCESS" }
|
|
Text {
|
|
x: 76
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: "COMPOSITOR // NODE_EXPORTER // SHELL"
|
|
color: root.telemetryReady ? root.inkColor : root.mutedColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 7
|
|
elide: Text.ElideRight
|
|
width: parent.width - 84
|
|
}
|
|
}
|
|
|
|
RailSection {
|
|
width: root.compact ? 300 : 385
|
|
MicroText { x: 9; anchors.verticalCenter: parent.verticalCenter; text: "VOL // ROOT" }
|
|
Text {
|
|
x: 93
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: root.storageFreeText
|
|
color: root.inkColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 8
|
|
}
|
|
SegmentMeter {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 10
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: root.compact ? 95 : 170
|
|
height: 7
|
|
segments: root.compact ? 10 : 16
|
|
value: root.storageFraction
|
|
ready: root.telemetryReady
|
|
}
|
|
}
|
|
|
|
RailSection {
|
|
visible: !root.compact
|
|
width: 350
|
|
MicroText { x: 9; anchors.verticalCenter: parent.verticalCenter; text: "AUDIO BUS" }
|
|
Text {
|
|
x: 89
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: root.audioMuted ? "MUTED" : Math.round(root.audioFraction * 100) + "%"
|
|
color: root.audioMuted ? root.mutedColor : root.accentColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 8
|
|
}
|
|
SegmentMeter {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 10
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: 155
|
|
height: 7
|
|
segments: 16
|
|
value: root.audioFraction
|
|
ready: true
|
|
}
|
|
}
|
|
|
|
RailSection {
|
|
width: Math.max(150, rail.width - (root.compact ? 812 : 1455) - 20)
|
|
borderVisible: false
|
|
MicroText { x: 9; anchors.verticalCenter: parent.verticalCenter; text: root.compact ? "SYS // " + root.timeText(root.now) : "EVENTS" }
|
|
Text {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 8
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: root.telemetryReady ? "WARN:00 // ERR:00" : "TELEMETRY WAIT"
|
|
color: root.telemetryReady ? root.mutedColor : root.accentColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 7
|
|
elide: Text.ElideLeft
|
|
width: parent.width - 64
|
|
horizontalAlignment: Text.AlignRight
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bottom routing trace and caution hatch.
|
|
Shape {
|
|
x: 12
|
|
y: 150
|
|
width: root.width - 24
|
|
height: 12
|
|
ShapePath {
|
|
fillColor: "transparent"
|
|
strokeColor: Qt.rgba(0.91, 0.45, 0.16, 0.55)
|
|
strokeWidth: 1
|
|
startX: 0; startY: 1
|
|
PathLine { x: 220; y: 1 }
|
|
PathLine { x: 232; y: 11 }
|
|
PathLine { x: 330; y: 11 }
|
|
}
|
|
}
|
|
|
|
Row {
|
|
x: 360
|
|
y: 151
|
|
width: root.width - 372
|
|
height: 3
|
|
spacing: 5
|
|
clip: true
|
|
Repeater {
|
|
model: Math.ceil(parent.width / 10)
|
|
Rectangle {
|
|
required property int index
|
|
width: 5
|
|
height: 3
|
|
color: index % 2 === 0 ? root.accentColor : "transparent"
|
|
opacity: 0.58
|
|
}
|
|
}
|
|
}
|
|
|
|
component MicroText: Text {
|
|
color: root.mutedColor
|
|
font.family: root.microFont
|
|
font.pixelSize: 6
|
|
font.letterSpacing: 0.7
|
|
}
|
|
|
|
component RailSection: Item {
|
|
property bool borderVisible: true
|
|
height: rail.height
|
|
Rectangle {
|
|
visible: parent.borderVisible
|
|
anchors.right: parent.right
|
|
width: 1
|
|
height: parent.height
|
|
color: root.hairColor
|
|
opacity: 0.65
|
|
}
|
|
}
|
|
|
|
component MetricBlock: Item {
|
|
id: metric
|
|
property string label: ""
|
|
property real value: 0
|
|
property bool ready: false
|
|
property string readout: "--"
|
|
property string detailLeft: ""
|
|
property string detailRight: ""
|
|
height: 51
|
|
|
|
MicroText { x: 0; y: 1; text: metric.label; font.pixelSize: 7 }
|
|
Text {
|
|
anchors.right: parent.right
|
|
y: -3
|
|
text: metric.readout
|
|
color: root.inkColor
|
|
font.family: root.displayFont
|
|
font.pixelSize: root.compact ? 14 : 17
|
|
font.bold: true
|
|
}
|
|
SegmentMeter {
|
|
x: 0; y: 19
|
|
width: parent.width
|
|
height: 9
|
|
segments: 10
|
|
value: metric.value
|
|
ready: metric.ready
|
|
}
|
|
MicroText { x: 0; y: 34; text: metric.detailLeft }
|
|
MicroText { anchors.right: parent.right; y: 34; text: metric.detailRight; horizontalAlignment: Text.AlignRight }
|
|
}
|
|
|
|
component SegmentMeter: Row {
|
|
id: meter
|
|
property int segments: 10
|
|
property real value: 0
|
|
property bool ready: false
|
|
spacing: 2
|
|
Repeater {
|
|
model: meter.segments
|
|
Rectangle {
|
|
required property int index
|
|
width: Math.max(2, (meter.width - (meter.segments - 1) * meter.spacing) / meter.segments)
|
|
height: meter.height
|
|
readonly property bool on: meter.ready && index < Math.round(Math.max(0, Math.min(1, meter.value)) * meter.segments)
|
|
color: on ? root.accentColor : Qt.rgba(0.87, 0.87, 0.87, 0.06)
|
|
border.width: 1
|
|
border.color: on ? root.accentColor : Qt.rgba(0.87, 0.87, 0.87, 0.18)
|
|
}
|
|
}
|
|
}
|
|
|
|
component StateCell: Item {
|
|
id: state
|
|
property string code: "--"
|
|
property string label: ""
|
|
property bool active: false
|
|
width: root.compact ? 39 : 43
|
|
height: 42
|
|
|
|
Shape {
|
|
anchors.fill: parent
|
|
ShapePath {
|
|
fillColor: state.active ? Qt.rgba(0.91, 0.45, 0.16, 0.18) : "transparent"
|
|
strokeColor: state.active ? root.accentColor : root.hairColor
|
|
strokeWidth: 1
|
|
startX: 1; startY: 1
|
|
PathLine { x: parent.width - 7; y: 1 }
|
|
PathLine { x: parent.width - 1; y: 7 }
|
|
PathLine { x: parent.width - 1; y: parent.height - 1 }
|
|
PathLine { x: 7; y: parent.height - 1 }
|
|
PathLine { x: 1; y: parent.height - 7 }
|
|
PathLine { x: 1; y: 1 }
|
|
}
|
|
}
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
y: 7
|
|
text: state.code
|
|
color: state.active ? root.accentColor : root.inkColor
|
|
font.family: root.displayFont
|
|
font.pixelSize: 13
|
|
font.bold: true
|
|
}
|
|
MicroText { anchors.horizontalCenter: parent.horizontalCenter; y: 27; text: state.label }
|
|
}
|
|
|
|
component RadarGauge: Item {
|
|
id: radar
|
|
property real size: 58
|
|
property real level: 0
|
|
width: size
|
|
height: size
|
|
|
|
Repeater {
|
|
model: [1, 0.72, 0.36]
|
|
Rectangle {
|
|
required property int index
|
|
required property var modelData
|
|
anchors.centerIn: parent
|
|
width: radar.size * Number(modelData)
|
|
height: width
|
|
radius: width / 2
|
|
color: "transparent"
|
|
border.width: 1
|
|
border.color: index === 0 ? root.accentColor : root.hairColor
|
|
}
|
|
}
|
|
Rectangle { x: 0; y: parent.height / 2; width: parent.width; height: 1; color: root.hairColor }
|
|
Rectangle { x: parent.width / 2; y: 0; width: 1; height: parent.height; color: root.hairColor }
|
|
Rectangle { x: 12; y: 18; width: 4; height: 4; color: root.accentColor }
|
|
Rectangle { x: parent.width - 14; y: parent.height - 20; width: 4; height: 4; color: root.accentColor }
|
|
Rectangle { x: parent.width / 2; y: parent.height - 11; width: 4; height: 4; color: root.accentColor }
|
|
MicroText { anchors.right: parent.right; y: 3; text: "R:" + Math.round(radar.level * 99); color: root.accentColor }
|
|
}
|
|
|
|
component NetworkTrace: Item {
|
|
id: trace
|
|
property real level: 0
|
|
Rectangle { x: 0; y: parent.height - 1; width: parent.width; height: 1; color: root.hairColor }
|
|
Rectangle { x: 0; y: 0; width: 1; height: parent.height; color: root.hairColor }
|
|
Shape {
|
|
anchors.fill: parent
|
|
ShapePath {
|
|
fillColor: "transparent"
|
|
strokeColor: root.accentColor
|
|
strokeWidth: 1.2
|
|
startX: 0; startY: trace.height * 0.65
|
|
PathLine { x: trace.width * 0.10; y: trace.height * 0.65 }
|
|
PathLine { x: trace.width * 0.15; y: trace.height * (0.25 + trace.level * 0.15) }
|
|
PathLine { x: trace.width * 0.21; y: trace.height * 0.78 }
|
|
PathLine { x: trace.width * 0.31; y: trace.height * 0.56 }
|
|
PathLine { x: trace.width * 0.43; y: trace.height * 0.62 }
|
|
PathLine { x: trace.width * 0.49; y: trace.height * 0.18 }
|
|
PathLine { x: trace.width * 0.57; y: trace.height * 0.82 }
|
|
PathLine { x: trace.width * 0.68; y: trace.height * 0.58 }
|
|
PathLine { x: trace.width * 0.79; y: trace.height * 0.62 }
|
|
PathLine { x: trace.width * 0.85; y: trace.height * 0.34 }
|
|
PathLine { x: trace.width * 0.91; y: trace.height * 0.75 }
|
|
PathLine { x: trace.width; y: trace.height * 0.60 }
|
|
}
|
|
}
|
|
}
|
|
}
|