From 66adb31ac624090d5f556fc5ef071dbf7dab82b3 Mon Sep 17 00:00:00 2001 From: gitcoder89431 Date: Thu, 15 Oct 2026 08:43:42 -0500 Subject: [PATCH] fix: align compact notch title spinners with text --- .../ruixen.notch/CompactWindowTitle.qml | 60 +++++++++++++++++++ bars/widgets/ruixen.notch/Overlay.qml | 5 +- 2 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 bars/widgets/ruixen.notch/CompactWindowTitle.qml diff --git a/bars/widgets/ruixen.notch/CompactWindowTitle.qml b/bars/widgets/ruixen.notch/CompactWindowTitle.qml new file mode 100644 index 0000000..49f18a1 --- /dev/null +++ b/bars/widgets/ruixen.notch/CompactWindowTitle.qml @@ -0,0 +1,60 @@ +import QtQuick + +Item { + id: root + + property string text: "" + property alias font: titleLabel.font + property alias color: titleLabel.color + + // Codex's ten braille spinner frames occupy the upper three rows of + // an eight-dot cell. Sharing the title's baseline leaves them raised. + // Split only this leading spinner; ordinary window titles stay intact. + readonly property var spinnerMatch: text.match(/^([\u280b\u2819\u2839\u2838\u283c\u2834\u2826\u2827\u2807\u280f])(\s+)(.+)$/) + readonly property bool hasSpinner: spinnerMatch !== null + + TextMetrics { + id: letterMetrics + font: titleLabel.font + text: "M" + } + TextMetrics { + id: spinnerMetrics + font: titleLabel.font + // Measure the whole six-dot grid, never the current frame: sparse + // frames must rotate in place rather than bob up and down. + text: "\u283f" + } + readonly property real spinnerBaselineShift: + letterMetrics.tightBoundingRect.y + letterMetrics.tightBoundingRect.height / 2 + - spinnerMetrics.tightBoundingRect.y - spinnerMetrics.tightBoundingRect.height / 2 + + Item { + anchors.horizontalCenter: parent.horizontalCenter + width: Math.min(root.width, titleLabel.implicitWidth + (root.hasSpinner ? spinnerLabel.implicitWidth : 0)) + height: root.height + + Text { + id: spinnerLabel + visible: root.hasSpinner + text: root.hasSpinner ? root.spinnerMatch[1] + root.spinnerMatch[2] : "" + textFormat: Text.PlainText + font: titleLabel.font + color: titleLabel.color + anchors.baseline: titleLabel.baseline + anchors.baselineOffset: root.spinnerBaselineShift + } + + Text { + id: titleLabel + x: root.hasSpinner ? spinnerLabel.implicitWidth : 0 + width: Math.max(0, parent.width - x) + height: parent.height + text: root.hasSpinner ? root.spinnerMatch[3] : root.text + textFormat: Text.PlainText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + } +} diff --git a/bars/widgets/ruixen.notch/Overlay.qml b/bars/widgets/ruixen.notch/Overlay.qml index 1a2fb3b..32205ee 100644 --- a/bars/widgets/ruixen.notch/Overlay.qml +++ b/bars/widgets/ruixen.notch/Overlay.qml @@ -2545,7 +2545,7 @@ Item { // everything, say), rather than leaving the pill blank. // No toggle of its own -- unconditional whenever there's // no media, see nowPlayingSlot's own header comment for why. - Text { + CompactWindowTitle { anchors.fill: parent visible: !root.hasMedia text: root.compactWindowTitle !== "" ? root.compactWindowTitle : "~" @@ -2556,9 +2556,6 @@ Item { color: root.textColor font.family: root.fontFamily font.pixelSize: Style.font.bodySmall - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight } } }