import QtQuick import QtQuick.Controls.Material import QtQuick.Controls import QtQuick.Layouts import "." import TactileIPC 1.0 Rectangle { id: root width: 340 color: Backend.lightMode ? "#F5F5F5" : "#2C2C2C" radius: 8 border.color: Qt.rgba(0, 0, 0, 0.08) property color accentColor: "#43a047" function tr(text) { I18n.retranslateToken return qsTr(text) } Material.theme: Backend.lightMode ? Material.Light : Material.Dark Material.accent: Material.Green Material.primary: Material.Green ScrollView { id: scrollView anchors.fill: parent ScrollBar.vertical.policy: ScrollBar.AlwaysOff ScrollBar.horizontal.policy: ScrollBar.AlwaysOff contentWidth: scrollView.availableWidth contentHeight: contentLayout.implicitHeight + 24 ColumnLayout { id: contentLayout x: 12 y: 12 width: scrollView.availableWidth - 24 spacing: 12 LiveTrendCard { id: card Layout.fillWidth: true Layout.preferredHeight: 180 title: root.tr("Payload Sum") Connections { target: Backend.data function onMetricsChanged() { if (Backend.data.frameCount > 0) card.plot.append(Backend.data.metricSum) } } } CollapsiblePanel { title: root.tr("Live Trend") expanded: true Layout.fillWidth: true /* Canvas { id: trendCanvas Layout.fillWidth: true Layout.preferredHeight: 180 property var samples: [0.08, 0.24, 0.52, 0.41, 0.63, 0.47, 0.72, 0.58, 0.82, 0.69] onPaint: { const ctx = getContext("2d") const w = width const h = height ctx.clearRect(0, 0, w, h) ctx.strokeStyle = "#D8EAD9" ctx.lineWidth = 1 for (let i = 1; i < 5; i++) { const y = (h / 5) * i ctx.beginPath() ctx.moveTo(0, y) ctx.lineTo(w, y) ctx.stroke() } ctx.strokeStyle = root.accentColor ctx.lineWidth = 2 ctx.beginPath() for (let i = 0; i < samples.length; i++) { const x = (w - 12) * (i / (samples.length - 1)) + 6 const y = h - (h - 12) * samples[i] - 6 if (i === 0) ctx.moveTo(x, y) else ctx.lineTo(x, y) } ctx.stroke() } onWidthChanged: requestPaint() onHeightChanged: requestPaint() Component.onCompleted: requestPaint() } */ } CollapsiblePanel { title: root.tr("Metrics") expanded: true Layout.fillWidth: true RowLayout { Layout.fillWidth: true spacing: 8 Rectangle { Layout.fillWidth: true radius: 6 color: Qt.rgba(0, 0, 0, 0.03) border.color: Qt.rgba(0, 0, 0, 0.08) height: 72 Column { anchors.centerIn: parent spacing: 4 Label { text: root.tr("峰值"); font.pixelSize: 12 } Label { text: Backend.data.metricPeak.toFixed(0); font.pixelSize: 18; font.bold: true } } } Rectangle { Layout.fillWidth: true radius: 6 color: Qt.rgba(0, 0, 0, 0.03) border.color: Qt.rgba(0, 0, 0, 0.08) height: 72 Column { anchors.centerIn: parent spacing: 4 Label { text: root.tr("均方根"); font.pixelSize: 12 } Label { text: Backend.data.metricRms.toFixed(0); font.pixelSize: 18; font.bold: true } } } } RowLayout { Layout.fillWidth: true spacing: 8 Rectangle { Layout.fillWidth: true radius: 6 color: Qt.rgba(0, 0, 0, 0.03) border.color: Qt.rgba(0, 0, 0, 0.08) height: 72 Column { anchors.centerIn: parent spacing: 4 Label { text: root.tr("平均值"); font.pixelSize: 12 } Label { text: Backend.data.metricAvg.toFixed(0); font.pixelSize: 18; font.bold: true } } } Rectangle { Layout.fillWidth: true radius: 6 color: Qt.rgba(0, 0, 0, 0.03) border.color: Qt.rgba(0, 0, 0, 0.08) height: 72 Column { anchors.centerIn: parent spacing: 4 Label { text: root.tr("变化量"); font.pixelSize: 12 } Label { text: Backend.data.metricDelta.toFixed(0); font.pixelSize: 18; font.bold: true } } } } } CollapsiblePanel { title: root.tr("Session") expanded: true Layout.fillWidth: true RowLayout { Layout.fillWidth: true spacing: 8 Label { text: root.tr("Frames"); Layout.preferredWidth: 80 } Label { text: Backend.data.frameCount; Layout.fillWidth: true; horizontalAlignment: Text.AlignRight } } RowLayout { Layout.fillWidth: true spacing: 8 Label { text: root.tr("Playback"); Layout.preferredWidth: 80 } Label { text: Backend.data.playbackRunning ? root.tr("Running") : root.tr("Idle") Layout.fillWidth: true horizontalAlignment: Text.AlignRight } } } CollapsiblePanel { title: root.tr("Legend") expanded: true Layout.fillWidth: true Legend { Layout.alignment: Qt.AlignHCenter Layout.preferredHeight: 200 barWidth: 36 minValue: Backend.rangeMin maxValue: Backend.rangeMax colorLow: Backend.colorLow colorMid: Backend.colorMid colorHigh: Backend.colorHigh } } Item { Layout.fillHeight: true } } } }