style(ui): minor styling adjustments for AboutDialog and OverlapMapCard
CI / preflight (push) Waiting to run

This commit is contained in:
jack
2026-07-13 13:41:13 -07:00
parent 5060df1527
commit 8707d467f5
5 changed files with 203 additions and 78 deletions
-1
View File
@@ -37,7 +37,6 @@ moc_*.cpp
# Build / packaging artifacts
build/
dist/
*.spec
*.icns
*.ico
+21 -5
View File
@@ -3,6 +3,7 @@ import QtQuick.Controls
import QtQuick.Dialogs
import QtQuick.Layouts
import ISC
import ISC.Tabs.components
Popup {
id: root
@@ -133,13 +134,28 @@ Popup {
Label { text: modelData.mfgDate; font.pixelSize: Theme.fontMd; color: Theme.bodyColor; Layout.preferredWidth: 120 }
Label { text: modelData.level; font.pixelSize: Theme.fontMd; color: Theme.bodyColor; Layout.preferredWidth: 80 }
Label { text: modelData.licDate; font.pixelSize: Theme.fontMd; color: Theme.bodyColor; Layout.fillWidth: true }
ToolButton {
Button {
id: removeLicenseBtn
Layout.preferredWidth: 28
text: "✕"
font.pixelSize: Theme.fontSm
ToolTip.visible: hovered
ToolTip.text: "Remove license"
implicitHeight: 28
hoverEnabled: true
background: Rectangle {
color: removeLicenseBtn.pressed ? Theme.buttonPressed : removeLicenseBtn.hovered ? Theme.buttonNeutralHover : "transparent"
radius: Theme.radiusSm
}
contentItem: Text {
text: "✕"
font.pixelSize: Theme.fontSm
color: Theme.bodyColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: licenseModel.removeLicense(modelData.serial, modelData.level)
AppToolTip {
visible: removeLicenseBtn.hovered
text: "Remove license"
}
}
}
}
+16 -9
View File
@@ -124,16 +124,22 @@ Rectangle {
licenseModel.startReplayTrial()
}
}
function onParsedDataReady(result) {
if (result.success && result.csv_path) {
streamController.loadFile(result.csv_path)
// Fires while still on Status(0), before the tab switch below —
// the generic per-tab tracker only attributes picks made while
// already on Map/Graph, so record this one explicitly.
root.mapReviewFile = result.csv_path
if (root.selectedTabIndex === 0 && licenseModel.licenses.length > 0) {
}
Connections {
// Deferred until the post-read metadata dialog (StatusTab.qml) closes —
// jumping tabs from onParsedDataReady directly would deactivate the
// Status Loader (StackLayout.index !== selectedTabIndex) and tear down
// the dialog before the technician could see or use it.
target: statusTabLoader.item
function onCsvMetadataDialogClosed(csvPath) {
if (!csvPath) return
streamController.loadFile(csvPath)
// Fires while still on Status(0), before the tab switch below —
// the generic per-tab tracker only attributes picks made while
// already on Map/Graph, so record this one explicitly.
root.mapReviewFile = csvPath
if (root.selectedTabIndex === 0 && licenseModel.licenses.length > 0) {
root.selectedTabIndex = 2
}
}
}
}
@@ -764,6 +770,7 @@ Rectangle {
currentIndex: root.selectedTabIndex
Loader {
id: statusTabLoader
source: "Tabs/StatusTab.qml"
active: StackLayout.index === root.selectedTabIndex
}
+165 -63
View File
@@ -15,6 +15,12 @@ ColumnLayout {
anchors.margins: Theme.panelPadding
spacing: 8
// Fired once the post-read metadata dialog is dismissed (Save or Cancel),
// so HomePage can defer its auto-jump-to-Map until after the technician
// has had a chance to edit metadata — jumping tabs immediately would
// deactivate this Loader's item and kill the dialog mid-display.
signal csvMetadataDialogClosed(string csvPath)
// ── Reusable Inline Components ──
component StatCard : Rectangle {
property alias value: valueText.text
@@ -147,31 +153,127 @@ ColumnLayout {
id: editCsvDialog
parent: Overlay.overlay
modal: true
title: "Edit CSV Metadata"
width: 460
anchors.centerIn: parent
standardButtons: Dialog.Save | Dialog.Cancel
standardButtons: Dialog.NoButton
padding: 20
onAccepted: file_browser.saveMetadata(root.csvPath, metaWafer.text, metaDate.text, metaChamber.text, metaNotes.text, false, "")
onClosed: root.csvMetadataDialogClosed(root.csvPath)
background: Rectangle {
radius: Theme.radiusLg
color: Theme.cardBackground
border.color: Theme.cardBorder
border.width: Theme.borderThin
}
component MetaField: TextField {
id: metaField
Layout.fillWidth: true
color: Theme.fieldText
placeholderTextColor: Theme.fieldPlaceholder
selectedTextColor: Theme.fieldBackground
selectionColor: Theme.fieldText
font.pixelSize: Theme.fontMd
background: Rectangle {
radius: Theme.radiusXs
color: Theme.fieldBackground
border.width: metaField.activeFocus ? Theme.borderStrong : Theme.borderThin
border.color: metaField.activeFocus ? Theme.fieldBorderFocus : Theme.fieldBorder
Behavior on border.color {
ColorAnimation { duration: Theme.durationFast }
}
}
}
ColumnLayout {
anchors.fill: parent
spacing: 6
// ── header ───────────────────────────────────────────────
Label {
text: "EDIT CSV METADATA"
color: Theme.headingColor
font.pixelSize: Theme.fontLg
font.bold: true
font.letterSpacing: 1
Layout.fillWidth: true
}
Text {
text: root.csvPath.split("/").pop()
color: Theme.sideMutedText
font.pixelSize: Theme.fontXs
elide: Text.ElideMiddle
Layout.fillWidth: true
Layout.bottomMargin: 4
}
Rectangle {
Layout.fillWidth: true
Layout.bottomMargin: 8
height: 1
color: Theme.cardBorder
}
Label { text: "Wafer"; color: Theme.bodyColor; font.pixelSize: Theme.fontXs }
MetaField { id: metaWafer }
Label { text: "Date"; color: Theme.bodyColor; font.pixelSize: Theme.fontXs; Layout.topMargin: 6 }
MetaField { id: metaDate }
Label { text: "Chamber"; color: Theme.bodyColor; font.pixelSize: Theme.fontXs; Layout.topMargin: 6 }
MetaField { id: metaChamber }
Label { text: "Notes"; color: Theme.bodyColor; font.pixelSize: Theme.fontXs; Layout.topMargin: 6 }
MetaField { id: metaNotes }
// ── buttons ───────────────────────────────────────────────
RowLayout {
Layout.fillWidth: true
Layout.topMargin: 14
spacing: 8
Button {
id: cancelCsvBtn
text: "Cancel"
Layout.fillWidth: true
hoverEnabled: true
background: Rectangle {
radius: Theme.radiusSm
color: cancelCsvBtn.down ? Theme.buttonNeutralPressed : cancelCsvBtn.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
border.width: Theme.borderThin
border.color: Theme.fieldBorder
}
contentItem: Text {
text: cancelCsvBtn.text
color: Theme.buttonNeutralText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: Theme.fontSm
}
onClicked: editCsvDialog.reject()
}
Button {
id: saveCsvBtn
text: "Save"
Layout.fillWidth: true
hoverEnabled: true
background: Rectangle {
radius: Theme.radiusSm
color: saveCsvBtn.hovered ? Qt.lighter(Theme.primaryAccent, 1.1) : Theme.primaryAccent
border.width: Theme.borderThin
border.color: Theme.primaryAccent
}
contentItem: Text {
text: saveCsvBtn.text
color: Theme.tone100
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: Theme.fontSm
}
onClicked: editCsvDialog.accept()
}
}
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 }
}
}
@@ -214,74 +316,74 @@ ColumnLayout {
Item { Layout.fillHeight: true }
RowLayout {
// Badge cluster centers on the full card width; port name overlays
// the right edge independently so a long port string can't drag
// the centered badge off-center (was sharing width via RowLayout).
Item {
Layout.fillWidth: true
spacing: 8
Layout.preferredHeight: 22
Item {
Layout.fillWidth: true
implicitHeight: 22
Row {
anchors.centerIn: parent
spacing: 5
Repeater {
model: 4
Rectangle {
width: 4; height: 4; radius: 2
anchors.verticalCenter: parent.verticalCenter
color: root.isConnected ? Theme.statusSuccessColor : (root.isBusy ? Theme.statusWarningColor : Theme.sideMutedText)
opacity: (root.isConnected || root.isBusy) ? 1.0 : 0.3
SequentialAnimation on opacity {
running: root.isConnected || root.isBusy
loops: Animation.Infinite
NumberAnimation { to: 0.3; duration: 1400 }
NumberAnimation { to: 1.0; duration: 1400 }
}
}
}
Row {
anchors.centerIn: parent
spacing: 5
Repeater {
model: 4
Rectangle {
width: 4; height: 4; radius: 2
anchors.verticalCenter: parent.verticalCenter
width: statusPillText.implicitWidth + 16
height: 20
radius: 10
color: root.isConnected ? Theme.statusSuccessColor : (root.isBusy ? Theme.statusWarningColor : Theme.statusErrorColor)
color: root.isConnected ? Theme.statusSuccessColor : (root.isBusy ? Theme.statusWarningColor : Theme.sideMutedText)
opacity: (root.isConnected || root.isBusy) ? 1.0 : 0.3
Text {
id: statusPillText
anchors.centerIn: parent
text: root.isConnected ? "ACTIVE" : (root.isBusy ? deviceController.connectionStatus.replace("...", "").toUpperCase() : "INACTIVE")
color: Theme.statusBadgeText
font.pixelSize: Theme.fontXs
font.weight: Font.Bold
font.family: Theme.uiFontFamily
font.letterSpacing: 0.6
SequentialAnimation on opacity {
running: root.isConnected || root.isBusy
loops: Animation.Infinite
NumberAnimation { to: 0.3; duration: 1400 }
NumberAnimation { to: 1.0; duration: 1400 }
}
}
}
Repeater {
model: 4
Rectangle {
width: 4; height: 4; radius: 2
anchors.verticalCenter: parent.verticalCenter
color: root.isConnected ? Theme.statusSuccessColor : (root.isBusy ? Theme.statusWarningColor : Theme.sideMutedText)
opacity: (root.isConnected || root.isBusy) ? 1.0 : 0.3
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: statusPillText.implicitWidth + 16
height: 20
radius: 10
color: root.isConnected ? Theme.statusSuccessColor : (root.isBusy ? Theme.statusWarningColor : Theme.statusErrorColor)
SequentialAnimation on opacity {
running: root.isConnected || root.isBusy
loops: Animation.Infinite
NumberAnimation { to: 0.3; duration: 1400 }
NumberAnimation { to: 1.0; duration: 1400 }
}
Text {
id: statusPillText
anchors.centerIn: parent
text: root.isConnected ? "ACTIVE" : (root.isBusy ? deviceController.connectionStatus.replace("...", "").toUpperCase() : "INACTIVE")
color: Theme.statusBadgeText
font.pixelSize: Theme.fontXs
font.weight: Font.Bold
font.family: Theme.uiFontFamily
font.letterSpacing: 0.6
}
}
Repeater {
model: 4
Rectangle {
width: 4; height: 4; radius: 2
anchors.verticalCenter: parent.verticalCenter
color: root.isConnected ? Theme.statusSuccessColor : (root.isBusy ? Theme.statusWarningColor : Theme.sideMutedText)
opacity: (root.isConnected || root.isBusy) ? 1.0 : 0.3
SequentialAnimation on opacity {
running: root.isConnected || root.isBusy
loops: Animation.Infinite
NumberAnimation { to: 0.3; duration: 1400 }
NumberAnimation { to: 1.0; duration: 1400 }
}
}
}
}
Text {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: root.portName
color: root.isConnected ? Theme.statusSuccessColor : Theme.headingColor
font.pixelSize: Theme.fontMd
@@ -612,7 +714,7 @@ ColumnLayout {
root.dataCols = 0;
root.csvPath = "";
if (result && result.success === true)
saveDirDialog.open();
root.parseAndSavePendingRead();
}
}
@@ -53,6 +53,7 @@ PanelBox {
margin: 1.0
blend: card.blendAmount / 100
showLabels: true
showExtremes: false
ringColor: Theme.waferRingColor
axisColor: Theme.waferAxisColor
lowColor: Theme.sensorLow