import QtQuick import QtQuick.Controls import QtQuick.Layouts import ISC // Editable stat box for scrubber readout (styled to match DTW ReadoutCard) Rectangle { id: edStat property string label property real value property string unit property string extraText: "" property bool editable: true signal valueEdited(real newValue) // Fires when the input field commits (Enter/focus loss), even if the // entered text was invalid — callers use it to hand focus back to the // timeline scrubber, matching the pre-extraction behavior. signal editingDone() Layout.fillWidth: true implicitHeight: edStatRow.implicitHeight + 16 radius: Theme.radiusSm color: Theme.subtleSectionBackground border.color: (edStat.editable && inputField.activeFocus) ? Theme.fieldBorderFocus : Theme.cardBorder border.width: (edStat.editable && inputField.activeFocus) ? Theme.borderStrong : Theme.borderThin RowLayout { id: edStatRow anchors.fill: parent anchors.margins: 8 spacing: 6 ColumnLayout { Layout.fillWidth: true spacing: 2 Label { text: edStat.label.toUpperCase() font.pixelSize: Theme.fontXs font.bold: true font.letterSpacing: 0.2 color: Theme.sideMutedText } RowLayout { spacing: 4 TextField { id: inputField readOnly: !edStat.editable hoverEnabled: edStat.editable font.pixelSize: Theme.fontLg font.bold: true font.family: Theme.codeFontFamily color: edStat.editable ? Theme.headingColor : Theme.sideMutedText verticalAlignment: TextInput.AlignVCenter horizontalAlignment: TextInput.AlignHCenter background: Rectangle { visible: edStat.editable color: Theme.fieldBackground radius: Theme.radiusXs border.color: inputField.activeFocus ? Theme.fieldBorderFocus : (inputField.hovered ? Theme.fieldBorderFocus : Theme.fieldBorder) border.width: 1 } padding: 0 leftPadding: edStat.editable ? 6 : 0 rightPadding: edStat.editable ? 6 : 0 topPadding: edStat.editable ? 5 : 0 bottomPadding: edStat.editable ? 5 : 0 selectByMouse: edStat.editable inputMethodHints: edStat.label === "Time" ? Qt.ImhFormattedNumbersOnly : Qt.ImhDigitsOnly Layout.preferredWidth: edStat.editable ? Math.max(36, contentWidth + 12) : contentWidth Layout.preferredHeight: edStat.editable ? 32 : implicitHeight text: edStat.value.toFixed(edStat.label === "Time" ? 1 : 0) onEditingFinished: { var val = parseFloat(text) if (!isNaN(val)) { edStat.valueEdited(val) } text = edStat.value.toFixed(edStat.label === "Time" ? 1 : 0) edStat.editingDone() } Connections { target: edStat function onValueChanged() { if (!inputField.activeFocus) { inputField.text = edStat.value.toFixed(edStat.label === "Time" ? 1 : 0) } } } } Label { text: edStat.unit font.pixelSize: Theme.fontLg font.bold: true font.family: Theme.codeFontFamily color: edStat.editable ? Theme.headingColor : Theme.sideMutedText Layout.alignment: Qt.AlignVCenter } } } Label { visible: edStat.extraText !== "" text: edStat.extraText font.pixelSize: Theme.fontLg font.bold: true font.family: Theme.codeFontFamily color: Theme.headingColor Layout.alignment: Qt.AlignVCenter } } }