From 8bada1d61aceab5c903c684c4a3c2d9241d955f4 Mon Sep 17 00:00:00 2001 From: 28allday Date: Sat, 13 Jun 2026 23:34:44 +0100 Subject: [PATCH] =?UTF-8?q?feat(bar):=20popouts=20drop=20down=20from=20the?= =?UTF-8?q?=20top=20bar=20=E2=80=94=20Phase=20B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bar hover fly-outs (wifi/audio/bluetooth/tray/active-window) slid out sideways from the old left edge; now they drop DOWN from the top bar: - ClipWrapper.qml: the collapsing/slide axis is now height (was width); the popout is positioned along the bar by x (from the hovered widget's x-centre, via currentCenter) and docks at the top edge; the dock<->detach animation guard moves to the x (along-bar) axis. The content slides in via a negative top margin instead of left margin. - Wrapper.qml: mirror the size-transition animation guards (height is now the always-animated extent axis, width the gated along-bar axis). Verified live in the dev VM: all popouts open downward under their widget. Co-Authored-By: Claude Opus 4.8 (1M context) --- modules/bar/popouts/ClipWrapper.qml | 29 ++++++++++++++++------------- modules/bar/popouts/Wrapper.qml | 4 ++-- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/modules/bar/popouts/ClipWrapper.qml b/modules/bar/popouts/ClipWrapper.qml index 99785219..c18d6496 100644 --- a/modules/bar/popouts/ClipWrapper.qml +++ b/modules/bar/popouts/ClipWrapper.qml @@ -12,21 +12,24 @@ Item { required property real borderThickness readonly property alias content: content - property real offsetScale: x > 0 || content.hasCurrent ? 0 : 1 + property real offsetScale: y > 0 || content.hasCurrent ? 0 : 1 visible: width > 0 && height > 0 clip: true - implicitWidth: content.implicitWidth * (1 - offsetScale) - implicitHeight: content.implicitHeight + // NoSignal top bar: popouts drop DOWN from the bar. The collapsing axis is + // now height (was width for the vertical left bar); position along the bar + // is x (from the hovered widget's x-centre), the docked edge is the top. + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight * (1 - offsetScale) - x: content.isDetached ? (parent.width - content.nonAnimWidth) / 2 : 0 - y: { + y: content.isDetached ? (parent.height - content.nonAnimHeight) / 2 : 0 + x: { if (content.isDetached) - return (parent.height - content.nonAnimHeight) / 2; + return (parent.width - content.nonAnimWidth) / 2; - const off = content.currentCenter - borderThickness - content.nonAnimHeight / 2; - const diff = parent.height - Math.floor(off + content.nonAnimHeight); + const off = content.currentCenter - borderThickness - content.nonAnimWidth / 2; + const diff = parent.width - Math.floor(off + content.nonAnimWidth); if (diff < 0) return off + diff; return Math.max(off, 0); @@ -36,14 +39,14 @@ Item { Anim {} } - Behavior on x { + Behavior on y { Anim { duration: content.animLength easing: content.animCurve } } - Behavior on y { + Behavior on x { enabled: root.offsetScale < 1 Anim { @@ -58,8 +61,8 @@ Item { screen: root.screen offsetScale: root.offsetScale - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: (-implicitWidth - 5) * root.offsetScale + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: (-implicitHeight - 5) * root.offsetScale } } diff --git a/modules/bar/popouts/Wrapper.qml b/modules/bar/popouts/Wrapper.qml index 97589f9a..eaa8bd68 100644 --- a/modules/bar/popouts/Wrapper.qml +++ b/modules/bar/popouts/Wrapper.qml @@ -149,14 +149,14 @@ Item { } } - Behavior on implicitWidth { + Behavior on implicitHeight { Anim { duration: root.animLength easing: root.animCurve } } - Behavior on implicitHeight { + Behavior on implicitWidth { enabled: root.offsetScale < 1 Anim {