feat: add recording toggle, stream stats UI
This commit is contained in:
@@ -205,33 +205,37 @@ Item {
|
||||
font.letterSpacing: 1.2
|
||||
}
|
||||
}
|
||||
|
||||
// Record start/stop toggle (Live mode)
|
||||
Button {
|
||||
visible: streamController.mode === "live"
|
||||
enabled: streamController.state !== "idle" || streamController.recording
|
||||
text: streamController.recording ? "Stop REC" : "Record"
|
||||
onClicked: {
|
||||
if (streamController.recording) {
|
||||
streamController.stopRecording();
|
||||
} else {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
var serial = (info && info.length > 1) ? info[1] : "";
|
||||
var ts = Qt.formatDateTime(new Date(), "yyyyMMdd_HHmmss");
|
||||
var name = "live_" + (serial ? serial + "_" : "") + ts + ".csv";
|
||||
streamController.startRecording(deviceController.saveDataDir + "/" + name, serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LIVE timer
|
||||
// RowLayout {
|
||||
// spacing: 5
|
||||
// visible: streamController.mode === "live" && streamController.state !== "idle"
|
||||
// Rectangle {
|
||||
// width: 7; height: 7; radius: 4
|
||||
// color: Theme.liveColor
|
||||
// }
|
||||
// Label {
|
||||
// text: "LIVE " + root.fmtTime(root._liveSecs)
|
||||
// color: Theme.liveColor
|
||||
// font.pixelSize: Theme.fontXs
|
||||
// font.weight: Font.Medium
|
||||
// font.letterSpacing: 0.8
|
||||
// }
|
||||
// }
|
||||
// Stream statistics popup (Live mode)
|
||||
Button {
|
||||
visible: streamController.mode === "live"
|
||||
text: "Stats"
|
||||
onClicked: streamStatsDialog.open()
|
||||
}
|
||||
|
||||
StreamStatsDialog {
|
||||
id: streamStatsDialog
|
||||
elapsedSecs: root._liveSecs
|
||||
}
|
||||
|
||||
// IDLE label (review / not connected)
|
||||
// Label {
|
||||
// visible: streamController.mode === "review" || streamController.state === "idle"
|
||||
// text: streamController.state.toUpperCas`e`()
|
||||
// color: Theme.bodyColor
|
||||
// font.pixelSize: Theme.fontXs
|
||||
// font.weight: Font.Medium
|
||||
// font.letterSpacing: 1.2
|
||||
// }
|
||||
Button {
|
||||
text: "Export PNG"
|
||||
onClicked: exportDialog.open()
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import ISC
|
||||
|
||||
// ===== Stream Stats Dialog =====
|
||||
// Popup showing live stream statistics: received frames, errors,
|
||||
// resync count, and elapsed time. Opened from the Live toolbar.
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
modal: true
|
||||
dim: true
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
width: 320
|
||||
implicitHeight: content.implicitHeight + 40
|
||||
anchors.centerIn: Overlay.overlay
|
||||
|
||||
// Elapsed seconds supplied by the Live timer in WaferMapTab.
|
||||
property int elapsedSecs: 0
|
||||
|
||||
function fmtTime(s) {
|
||||
var m = Math.floor(s / 60);
|
||||
var ss = s % 60;
|
||||
return (m < 10 ? "0" : "") + m + ":" + (ss < 10 ? "0" : "") + ss;
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
radius: Theme.radiusMd
|
||||
color: Theme.cardBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
component StatRow: RowLayout {
|
||||
property string label
|
||||
property string value
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Label {
|
||||
text: label
|
||||
color: Theme.bodyColor
|
||||
font.pixelSize: Theme.fontXs
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Label {
|
||||
text: value
|
||||
color: Theme.headingColor
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
spacing: 16
|
||||
|
||||
// ── Header ────────────────────────────────────────────────
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Label {
|
||||
text: "STREAM DATA"
|
||||
font.pixelSize: Theme.fontLg
|
||||
font.bold: true
|
||||
color: Theme.headingColor
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "✕"
|
||||
flat: true
|
||||
Layout.preferredWidth: 32
|
||||
Layout.preferredHeight: 32
|
||||
onClicked: root.close()
|
||||
|
||||
background: Rectangle {
|
||||
radius: Theme.radiusXs
|
||||
color: parent.hovered ? Theme.buttonNeutralHover : "transparent"
|
||||
}
|
||||
contentItem: Label {
|
||||
text: parent.text
|
||||
color: Theme.bodyColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Stats box ─────────────────────────────────────────────
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: statRows.implicitHeight + 20
|
||||
radius: Theme.radiusSm
|
||||
color: Theme.subtleSectionBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
id: statRows
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 8
|
||||
|
||||
StatRow {
|
||||
label: "Received frames"
|
||||
value: streamController.receivedCount
|
||||
}
|
||||
StatRow {
|
||||
label: "Errors"
|
||||
value: streamController.errorCount
|
||||
}
|
||||
StatRow {
|
||||
label: "Resyncs"
|
||||
value: streamController.resyncCount
|
||||
}
|
||||
StatRow {
|
||||
label: "Elapsed"
|
||||
value: root.fmtTime(root.elapsedSecs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,4 @@ WaferMapView 1.0 WaferMapView.qml
|
||||
ReplaceSensorDialog 1.0 ReplaceSensorDialog.qml
|
||||
RailActionButton 1.0 RailActionButton.qml
|
||||
SplitDialog 1.0 SplitDialog.qml
|
||||
StreamStatsDialog 1.0 StreamStatsDialog.qml
|
||||
Reference in New Issue
Block a user