feat: redesign StatusTab UI with bento-grid layout and add CSV metadata editing capabilities
This commit is contained in:
+295
-305
@@ -30,36 +30,45 @@ ColumnLayout {
|
||||
radius: Theme.radiusSm
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.panelPadding
|
||||
spacing: 4
|
||||
Text {
|
||||
id: labelText
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
font.letterSpacing: 1.5
|
||||
font.family: Theme.uiFontFamily
|
||||
}
|
||||
Text {
|
||||
id: valueText
|
||||
color: active ? Theme.headingColor : Theme.sideMutedText
|
||||
font.pixelSize: valSize
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
Text {
|
||||
id: labelText
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontXs
|
||||
font.weight: Font.Medium
|
||||
font.letterSpacing: 1.2
|
||||
font.family: Theme.uiFontFamily
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
fontSizeMode: Text.HorizontalFit
|
||||
minimumPixelSize: Theme.fontMd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component GridCell : RowLayout {
|
||||
// Stacked stat block: small label over big value, centered in its grid
|
||||
// quadrant so the card's height is used instead of leaving dead space.
|
||||
component GridCell : ColumnLayout {
|
||||
property alias label: labelText.text
|
||||
property alias value: valueText.text
|
||||
property bool active: root.waferDetected
|
||||
|
||||
spacing: 8
|
||||
spacing: 2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
Text {
|
||||
id: labelText
|
||||
color: Theme.sideMutedText
|
||||
@@ -67,17 +76,15 @@ ColumnLayout {
|
||||
font.family: Theme.uiFontFamily
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Text {
|
||||
id: valueText
|
||||
color: active ? Theme.headingColor : Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.pixelSize: Theme.fontXl
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
Layout.alignment: Qt.AlignRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
|
||||
// ── Aliases for external wiring ──
|
||||
@@ -120,16 +127,64 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// ROW 1: Connection Status (100%)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 90
|
||||
Layout.maximumHeight: 90
|
||||
spacing: 8
|
||||
// Directory-only picker for the DIRECTORY card button — sets the save dir
|
||||
// without kicking off a parse/save of pending read data.
|
||||
FolderDialog {
|
||||
id: dirOnlyDialog
|
||||
title: "Choose a folder to save Data"
|
||||
onAccepted: deviceController.setSaveDataDir(root.cleanFolderUrl(selectedFolder))
|
||||
}
|
||||
|
||||
// Post-read metadata editor (C# parity: EditCSVMetadataDialog after read).
|
||||
// Cancel keeps the CSV, skips the sidecar — matching C# behavior loosely.
|
||||
Dialog {
|
||||
id: editCsvDialog
|
||||
parent: Overlay.overlay
|
||||
modal: true
|
||||
title: "Edit CSV Metadata"
|
||||
width: 460
|
||||
anchors.centerIn: parent
|
||||
standardButtons: Dialog.Save | Dialog.Cancel
|
||||
onAccepted: file_browser.saveMetadata(root.csvPath, metaWafer.text, metaDate.text, metaChamber.text, metaNotes.text, false, "")
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 6
|
||||
|
||||
Text {
|
||||
text: root.csvPath.split("/").pop()
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontXs
|
||||
elide: Text.ElideMiddle
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Label { text: "Wafer" }
|
||||
TextField { id: metaWafer; Layout.fillWidth: true }
|
||||
Label { text: "Date" }
|
||||
TextField { id: metaDate; Layout.fillWidth: true }
|
||||
Label { text: "Chamber" }
|
||||
TextField { id: metaChamber; Layout.fillWidth: true }
|
||||
Label { text: "Notes" }
|
||||
TextField { id: metaNotes; Layout.fillWidth: true }
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// ROWS 1-2 (3-column bento):
|
||||
// [Connection Status] [Total Runtime ] [Wafer & Sensor]
|
||||
// [Directory (span 2) ] [ (rowspan) ]
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 188
|
||||
Layout.maximumHeight: 188
|
||||
columns: 3
|
||||
rowSpacing: 8
|
||||
columnSpacing: 8
|
||||
|
||||
// ── Connection Status: two cells wide, top-left ──
|
||||
Rectangle {
|
||||
Layout.columnSpan: 2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Theme.cardBackground
|
||||
@@ -138,13 +193,9 @@ ColumnLayout {
|
||||
radius: Theme.radiusSm
|
||||
|
||||
ColumnLayout {
|
||||
id: connStatusCol
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.panelPadding
|
||||
anchors.rightMargin: Theme.panelPadding
|
||||
spacing: 8
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.panelPadding
|
||||
spacing: 6
|
||||
|
||||
Text {
|
||||
text: "CONNECTION STATUS"
|
||||
@@ -155,26 +206,11 @@ ColumnLayout {
|
||||
font.family: Theme.uiFontFamily
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 1
|
||||
Text {
|
||||
text: "HOST PC"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontXs
|
||||
font.family: Theme.uiFontFamily
|
||||
}
|
||||
Text {
|
||||
text: "localhost"
|
||||
color: Theme.headingColor
|
||||
font.pixelSize: Theme.fontMd
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
}
|
||||
}
|
||||
spacing: 8
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
@@ -239,221 +275,204 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 1
|
||||
Text {
|
||||
text: "COM PORT"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontXs
|
||||
font.family: Theme.uiFontFamily
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
Text {
|
||||
text: root.portName
|
||||
color: root.isConnected ? Theme.statusSuccessColor : Theme.headingColor
|
||||
font.pixelSize: Theme.fontMd
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// ROW 2: Wafer & Sensor + Directory (65%) | Total Runtime (35%)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 90
|
||||
Layout.maximumHeight: 90
|
||||
spacing: 8
|
||||
|
||||
RowLayout {
|
||||
Layout.preferredWidth: 65
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
spacing: 8
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Theme.cardBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
radius: Theme.radiusSm
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.panelPadding
|
||||
spacing: 6
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: "DIRECTORY"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
font.letterSpacing: 1.5
|
||||
font.family: Theme.uiFontFamily
|
||||
}
|
||||
Text {
|
||||
text: deviceController.saveDataDir || "Not configured"
|
||||
color: Theme.bodyColor
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.family: Theme.uiFontFamily
|
||||
font.italic: true
|
||||
opacity: 0.7
|
||||
elide: Text.ElideMiddle
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Rectangle {
|
||||
visible: root.csvPath !== ""
|
||||
width: sessionSavedLabel.implicitWidth + 12
|
||||
height: 18
|
||||
radius: 4
|
||||
color: Theme.fieldBackground
|
||||
border.color: Theme.sideBorder
|
||||
border.width: 1
|
||||
|
||||
Text {
|
||||
id: sessionSavedLabel
|
||||
anchors.centerIn: parent
|
||||
text: "SESSION SAVED"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontXs
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
font.letterSpacing: 0.6
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
Button {
|
||||
id: browseBtn
|
||||
text: "Save As"
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.weight: Font.Medium
|
||||
font.family: Theme.uiFontFamily
|
||||
implicitHeight: 24
|
||||
implicitWidth: 70
|
||||
hoverEnabled: true
|
||||
background: Rectangle {
|
||||
color: browseBtn.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
radius: Theme.radiusSm
|
||||
}
|
||||
contentItem: Text {
|
||||
text: browseBtn.text
|
||||
color: Theme.bodyColor
|
||||
font: browseBtn.font
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
onClicked: saveDirDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Theme.cardBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
radius: Theme.radiusSm
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
text: "WAFER & SENSOR DATA"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontXs
|
||||
text: root.portName
|
||||
color: root.isConnected ? Theme.statusSuccessColor : Theme.headingColor
|
||||
font.pixelSize: Theme.fontMd
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
font.letterSpacing: 0.6
|
||||
Layout.bottomMargin: 2
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Wafer & Sensor Data: far right, spans both rows ──
|
||||
Rectangle {
|
||||
Layout.rowSpan: 2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Theme.cardBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
radius: Theme.radiusSm
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.panelPadding
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
text: "WAFER & SENSOR DATA"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
font.letterSpacing: 0.6
|
||||
Layout.bottomMargin: 2
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
columns: 2
|
||||
rowSpacing: 6
|
||||
columnSpacing: 16
|
||||
|
||||
GridCell {
|
||||
id: waferInfoFamilyCell
|
||||
label: "Family Code"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 0 && info[0]) ? info[0] : "—";
|
||||
}
|
||||
}
|
||||
GridCell {
|
||||
id: waferSerialCell
|
||||
label: "Serial"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 1 && info[1]) ? info[1] : "—";
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Rectangle {
|
||||
Layout.columnSpan: 2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
columns: 2
|
||||
rowSpacing: 4
|
||||
columnSpacing: 16
|
||||
Layout.preferredHeight: 1
|
||||
color: Theme.cardBorder
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
GridCell {
|
||||
id: waferInfoFamilyCell
|
||||
label: "Family Code"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 0 && info[0]) ? info[0] : "—";
|
||||
}
|
||||
GridCell {
|
||||
id: waferCyclesCell
|
||||
label: "Cycles Completed"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 5 && info[5] !== undefined) ? String(info[5]) : "—";
|
||||
}
|
||||
GridCell {
|
||||
id: waferCyclesCell
|
||||
label: "Cycles Completed"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 5 && info[5] !== undefined) ? String(info[5]) : "—";
|
||||
}
|
||||
active: root.waferDetected
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.columnSpan: 2
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: Theme.cardBorder
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
GridCell {
|
||||
id: waferSerialCell
|
||||
label: "Serial"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 1 && info[1]) ? info[1] : "—";
|
||||
}
|
||||
}
|
||||
GridCell {
|
||||
id: waferSensorsCell
|
||||
label: "Sensors"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 2 && info[2]) ? String(info[2]) : "—";
|
||||
}
|
||||
active: root.waferDetected
|
||||
}
|
||||
GridCell {
|
||||
id: waferSensorsCell
|
||||
label: "Sensors"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 2 && info[2]) ? String(info[2]) : "—";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Directory: bottom-left cell ──
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Theme.cardBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
radius: Theme.radiusSm
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.panelPadding
|
||||
spacing: 6
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: "DIRECTORY"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
font.letterSpacing: 1.5
|
||||
font.family: Theme.uiFontFamily
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.csvPath !== ""
|
||||
implicitWidth: sessionSavedLabel.implicitWidth + 12
|
||||
implicitHeight: 18
|
||||
radius: 4
|
||||
color: Theme.fieldBackground
|
||||
border.color: Theme.sideBorder
|
||||
border.width: 1
|
||||
|
||||
Text {
|
||||
id: sessionSavedLabel
|
||||
anchors.centerIn: parent
|
||||
text: "SESSION SAVED"
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontXs
|
||||
font.weight: Font.Bold
|
||||
font.family: Theme.uiFontFamily
|
||||
font.letterSpacing: 0.6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 12
|
||||
|
||||
// Path pinned bottom-left
|
||||
Text {
|
||||
text: deviceController.saveDataDir || "Not configured"
|
||||
color: Theme.bodyColor
|
||||
font.pixelSize: Theme.fontMd
|
||||
font.family: Theme.uiFontFamily
|
||||
font.italic: true
|
||||
opacity: 0.7
|
||||
elide: Text.ElideMiddle
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Button {
|
||||
id: browseBtn
|
||||
text: "Select Folder"
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.weight: Font.Medium
|
||||
font.family: Theme.uiFontFamily
|
||||
implicitHeight: 24
|
||||
hoverEnabled: true
|
||||
background: Rectangle {
|
||||
color: browseBtn.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
|
||||
border.color: Theme.cardBorder
|
||||
border.width: 1
|
||||
radius: Theme.radiusSm
|
||||
}
|
||||
contentItem: Text {
|
||||
text: browseBtn.text
|
||||
color: Theme.bodyColor
|
||||
font: browseBtn.font
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
onClicked: dirOnlyDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Total Runtime: bottom center ──
|
||||
StatCard {
|
||||
id: runtimeCard
|
||||
Layout.preferredWidth: 35
|
||||
label: "TOTAL RUNTIME"
|
||||
value: {
|
||||
var info = deviceController.lastWaferInfo;
|
||||
return (info && info.length > 4 && info[4] !== undefined) ? info[4] + "s" : "—";
|
||||
if (!(info && info.length > 4 && info[4] !== undefined)) return "—";
|
||||
var secs = parseFloat(info[4]);
|
||||
if (isNaN(secs)) return info[4] + "s";
|
||||
var m = Math.floor(secs / 60);
|
||||
var s = Math.round(secs % 60);
|
||||
return secs + "s / " + m + ":" + (s < 10 ? "0" : "") + s + " min";
|
||||
}
|
||||
label: "TOTAL RUNTIME"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,10 +492,20 @@ ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 36
|
||||
color: Theme.subtleSectionBackground
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 36
|
||||
color: Theme.subtleSectionBackground
|
||||
radius: Theme.radiusMd
|
||||
|
||||
// Cover bottom corners so only top-left and top-right are rounded
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.radius
|
||||
color: parent.color
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
@@ -489,64 +518,22 @@ ColumnLayout {
|
||||
width: 14; height: 14
|
||||
sourceSize.width: 14
|
||||
sourceSize.height: 14
|
||||
color: Theme.bodyColor
|
||||
color: Theme.sideMutedText
|
||||
visible: root.csvPath !== ""
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
text: root.csvPath !== "" ? root.csvPath.split("/").pop() : "ACTIVITY LOG"
|
||||
color: Theme.bodyColor
|
||||
font.pixelSize: root.csvPath !== "" ? Theme.fontMd : Theme.fontSm
|
||||
font.letterSpacing: root.csvPath !== "" ? 0 : 1.8
|
||||
font.weight: Font.Medium
|
||||
text: (root.csvPath !== "" ? root.csvPath.split("/").pop() : "ACTIVITY LOG").toUpperCase()
|
||||
color: Theme.sideMutedText
|
||||
font.pixelSize: Theme.fontMd
|
||||
font.letterSpacing: 1.5
|
||||
font.bold: true
|
||||
font.family: Theme.uiFontFamily
|
||||
elide: Text.ElideMiddle
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Button {
|
||||
id: refreshSessionBtn
|
||||
text: "Refresh"
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.family: Theme.uiFontFamily
|
||||
implicitHeight: 24
|
||||
hoverEnabled: true
|
||||
background: Rectangle {
|
||||
color: refreshSessionBtn.hovered ? Theme.buttonNeutralHover : "transparent"
|
||||
radius: Theme.radiusSm
|
||||
}
|
||||
contentItem: Text {
|
||||
text: refreshSessionBtn.text
|
||||
color: Theme.bodyColor
|
||||
font: refreshSessionBtn.font
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
onClicked: deviceController.clearSession()
|
||||
}
|
||||
|
||||
Button {
|
||||
id: clearLogBtn
|
||||
text: "Clear"
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.family: Theme.uiFontFamily
|
||||
implicitHeight: 24
|
||||
hoverEnabled: true
|
||||
background: Rectangle {
|
||||
color: clearLogBtn.hovered ? Theme.buttonNeutralHover : "transparent"
|
||||
radius: Theme.radiusSm
|
||||
}
|
||||
contentItem: Text {
|
||||
text: clearLogBtn.text
|
||||
color: Theme.bodyColor
|
||||
font: clearLogBtn.font
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
onClicked: deviceController.clearActivityLog()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -567,7 +554,9 @@ ColumnLayout {
|
||||
TextArea {
|
||||
id: activityLog
|
||||
width: parent.width
|
||||
text: qsTr("Welcome — use the side rail to detect a wafer, or import data to review.")
|
||||
// Bound to backend so log survives tab switches (Loader
|
||||
// destroys this tab); clears only via Clear Log / restart.
|
||||
text: deviceController.activityLog || qsTr("Welcome — use the side rail to detect a wafer, or import data to review.")
|
||||
readOnly: true
|
||||
font.family: "monospace"
|
||||
font.pixelSize: Theme.fontSm
|
||||
@@ -578,12 +567,6 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: deviceController
|
||||
function onActivityLogUpdated(newLog) {
|
||||
activityLog.text = newLog ? newLog : qsTr("Welcome — use the side rail to detect a wafer, or import data to review.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
@@ -635,6 +618,13 @@ ColumnLayout {
|
||||
root.dataRows = result.rows;
|
||||
root.dataCols = result.cols;
|
||||
root.csvPath = result.csv_path || "";
|
||||
if (root.csvPath) {
|
||||
metaWafer.text = result.serialNumber || "";
|
||||
metaDate.text = Qt.formatDateTime(new Date(), "yyyy-MM-dd hh:mm:ss");
|
||||
metaChamber.text = settingsModel.chamberId || "";
|
||||
metaNotes.text = "";
|
||||
editCsvDialog.open();
|
||||
}
|
||||
} else {
|
||||
root.dataParsed = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user