223 lines
7.9 KiB
QML
223 lines
7.9 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
import ISC
|
|
import ISC.Wafer
|
|
|
|
// ===== Graph Tab =====
|
|
// Displays sensor temperature line charts using GraphQuickItem.
|
|
// Gets data from deviceController.getChartData() (parsed CSV, batch read)
|
|
// or from streamController.trendData (live streaming trend).
|
|
Item {
|
|
id: root
|
|
anchors.fill: parent
|
|
|
|
property var _chartData: null // cached result from getChartData()
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: Theme.panelPadding
|
|
spacing: Theme.rightPaneGap
|
|
|
|
// ── Toolbar ───────────────────────────────────────────────────────────
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 10
|
|
|
|
Label {
|
|
text: "Line Chart"
|
|
color: Theme.headingColor
|
|
font.pixelSize: Theme.fontSm
|
|
font.bold: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
// Refresh button — pulls data from deviceController
|
|
Button {
|
|
id: refreshBtn
|
|
text: "REFRESH"
|
|
font.pixelSize: Theme.fontXs
|
|
font.weight: Font.Medium
|
|
implicitHeight: 26
|
|
implicitWidth: 72
|
|
hoverEnabled: true
|
|
background: Rectangle {
|
|
color: parent.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
|
|
border.color: Theme.cardBorder
|
|
border.width: 1
|
|
radius: Theme.radiusSm
|
|
}
|
|
contentItem: Text {
|
|
text: parent.text
|
|
color: Theme.headingColor
|
|
font: parent.font
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
onClicked: reloadData()
|
|
}
|
|
}
|
|
|
|
// ── Mode selector (Trend / Full chart) ─────────────────────────────
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 8
|
|
|
|
Label {
|
|
text: "Source:"
|
|
color: Theme.bodyColor
|
|
font.pixelSize: Theme.fontXs
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
|
|
ComboBox {
|
|
id: sourceSelector
|
|
model: ["Parsed Data", "Live Trend"]
|
|
currentIndex: 0
|
|
implicitHeight: 26
|
|
font.pixelSize: Theme.fontXs
|
|
background: Rectangle {
|
|
color: Theme.fieldBackground
|
|
border.color: Theme.fieldBorder
|
|
border.width: 1
|
|
radius: Theme.radiusSm
|
|
}
|
|
contentItem: Text {
|
|
text: sourceSelector.displayText
|
|
color: Theme.fieldText
|
|
font: sourceSelector.font
|
|
horizontalAlignment: Text.AlignLeft
|
|
verticalAlignment: Text.AlignVCenter
|
|
leftPadding: 8
|
|
}
|
|
onCurrentIndexChanged: reloadData()
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
Label {
|
|
id: statusLabel
|
|
text: "Ready"
|
|
color: Theme.bodyColor
|
|
font.pixelSize: Theme.fontXs
|
|
font.italic: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
}
|
|
|
|
// ── Chart Area ─────────────────────────────────────────────────────────
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
color: Theme.cardBackground
|
|
border.color: Theme.cardBorder
|
|
border.width: 1
|
|
radius: Theme.radiusMd
|
|
clip: true
|
|
|
|
GraphQuickItem {
|
|
id: graph
|
|
anchors.fill: parent
|
|
anchors.margins: 2
|
|
backgroundColor: Theme.cardBackground
|
|
gridColor: Theme.softBorder
|
|
axisColor: Theme.bodyColor
|
|
textColor: Theme.headingColor
|
|
seriesColors: [Theme.sensorLow, Theme.sensorHigh, Theme.sensorInRange, "#FFA726", "#AB47BC", "#00BCD4"]
|
|
showLegend: true
|
|
}
|
|
}
|
|
}
|
|
|
|
// ── Data Loading ────────────────────────────────────────────────────────────
|
|
|
|
function reloadData() {
|
|
if (sourceSelector.currentIndex === 0) {
|
|
// Parsed data from DeviceController
|
|
loadParsedData();
|
|
} else {
|
|
// Live trend from SessionController
|
|
loadLiveTrend();
|
|
}
|
|
}
|
|
|
|
function loadParsedData() {
|
|
statusLabel.text = "Loading...";
|
|
var result = deviceController.getChartData();
|
|
if (!result || !result.success) {
|
|
graph.seriesData = [];
|
|
graph.sensorNames = [];
|
|
graph.title = "Sensor Temperature Over Time";
|
|
statusLabel.text = "No data — read a wafer first";
|
|
return;
|
|
}
|
|
|
|
graph.seriesData = result.series || [];
|
|
graph.sensorNames = result.sensor_names || [];
|
|
graph.title = "Sensor Temperature Over Time";
|
|
statusLabel.text = (result.series ? result.series.length : 0) + " sensors loaded";
|
|
}
|
|
|
|
function loadLiveTrend() {
|
|
// Live trend: connects to streamController.trendData
|
|
// The trend data comes as a JSON array of per-frame averages
|
|
statusLabel.text = "Connecting to live trend...";
|
|
// We need at least one data point
|
|
if (streamController.stats && streamController.stats.avg !== undefined) {
|
|
// Build a single-series graph from the trend buffer
|
|
// For now show a placeholder — the trendData signal handles updates
|
|
graph.title = "Live Average Temperature";
|
|
graph.yLabel = "Avg Temperature (°C)";
|
|
graph.xLabel = "Time (s)";
|
|
statusLabel.text = "Live trend — waiting for data...";
|
|
} else {
|
|
statusLabel.text = "No live data — start a stream on the Wafer Map tab";
|
|
}
|
|
}
|
|
|
|
// ── Connections ─────────────────────────────────────────────────────────────
|
|
|
|
Connections {
|
|
target: deviceController
|
|
function onParsedDataReady(result) {
|
|
if (sourceSelector.currentIndex === 0) {
|
|
root.reloadData();
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: streamController
|
|
function onTrendData(avgsJson) {
|
|
if (sourceSelector.currentIndex === 1) {
|
|
try {
|
|
var avgs = JSON.parse(avgsJson);
|
|
if (avgs && avgs.length > 0) {
|
|
graph.seriesData = [avgs];
|
|
graph.sensorNames = ["Average"];
|
|
graph.title = "Live Average Temperature";
|
|
graph.yLabel = "Avg Temperature (°C)";
|
|
graph.xLabel = "Frame";
|
|
statusLabel.text = "Live: " + avgs.length + " data points";
|
|
}
|
|
} catch (e) {
|
|
// ignore parse errors
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// On startup, try to load parsed data if available
|
|
Component.onCompleted: {
|
|
if (deviceController.dataRowCount > 0) {
|
|
reloadData();
|
|
}
|
|
}
|
|
}
|