From 60ba555de6b4361e2b4e6d0c164f9f444b9a68cc Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:58:52 +0100 Subject: [PATCH] refactor bar widget shape background and make it work at the right edge --- .../ii/modules/hefty/topLayer/bar/HBar.qml | 1 - .../bar/HBarWidgetShapeBackground.qml | 112 ++++++++++++++++++ .../hefty/topLayer/bar/widgets/HTime.qml | 104 ++-------------- .../hefty/topLayer/bar/widgets/Invisible.qml | 3 + .../topLayer/bar/widgets/InvisibleFill.qml | 9 ++ 5 files changed, 135 insertions(+), 94 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBarWidgetShapeBackground.qml create mode 100644 dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/InvisibleFill.qml diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBar.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBar.qml index 95eade0fe..223f7ad5a 100644 --- a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBar.qml +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBar.qml @@ -55,7 +55,6 @@ HAbstractMorphedPanel { // Background function getBackgroundPolygon() { - print("Generating background polygon for HBar") // It's certainly cleaner to have the below props declared outside, but we do this // to make sure a config change only makes this re-evaluate exactly once const bottom = root.atBottom diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBarWidgetShapeBackground.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBarWidgetShapeBackground.qml new file mode 100644 index 000000000..0756efb03 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBarWidgetShapeBackground.qml @@ -0,0 +1,112 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts +import Quickshell + +import qs.modules.common as C +import qs.modules.common.functions as F +import qs.services as S +import qs.modules.common.widgets as W +import qs.modules.common.widgets.shapes as Shapes +import "../../../common/widgets/shapes/material-shapes.js" as MaterialShapes +import "../../../common/widgets/shapes/shapes/corner-rounding.js" as CornerRounding +import "../../../common/widgets/shapes/geometry/offset.js" as Offset + +// TODO: generalize this shi for vertical +Shapes.ShapeCanvas { + id: bgShape + + property bool atBottom: root.atBottom + property bool showPopup: root.showPopup + property real backgroundWidth: containerRoot.backgroundWidth + property real backgroundHeight: containerRoot.backgroundHeight + property real popupWidth: 400 + property real popupHeight: 500 + property real startRadius: containerRoot.getBackgroundRadius(containerRoot.startSide) + property real endRadius: containerRoot.getBackgroundRadius(containerRoot.endSide) + property real baseMargin: (parent.height - containerShape.height) / 2 + + property alias containerShape: containerShape + property alias popupShape: popupShape + + // mapToGlobal is not reactive so we gotta hook manually + property real xInGlobal + function updateXInGlobal() { + xInGlobal = mapToGlobal(0, 0).x + xOffset; + } + Component.onCompleted: updateXInGlobal(); + onXChanged: updateXInGlobal(); + readonly property real minPopupXOffset: -xInGlobal + baseMargin + readonly property real maxPopupXOffset: { + const maxPopupX = QsWindow.window.screen.width - popupWidth - baseMargin; + const maxOffset = maxPopupX - xInGlobal; + return maxOffset + } + readonly property real popupXOffset: Math.min(Math.max(-(popupWidth - containerShape.width) / 2, minPopupXOffset), maxPopupXOffset) + + anchors { + left: parent.left + leftMargin: -xOffset + top: parent.top + topMargin: { + if (!bgShape.atBottom || !bgShape.showPopup) + return baseMargin; + else + return baseMargin - popupShape.height - bgShape.spacing; + } + } + width: bgShape.showPopup ? Math.max(backgroundWidth, popupWidth) : backgroundWidth + height: bgShape.showPopup ? (containerShape.height + popupShape.height + bgShape.spacing) : containerShape.height + color: bgShape.showPopup || progress < 1 ? C.Appearance.colors.colLayer3Base : C.Appearance.colors.colLayer1 + xOffset: showPopup ? -popupXOffset : 0 + yOffset: bgShape.atBottom ? (height - containerShape.height) : 0 + animation: Anim {} + + Behavior on width { + Anim {} + } + Behavior on height { + Anim {} + } + Behavior on anchors.topMargin { + Anim {} + } + Behavior on xOffset { + Anim {} + } + + polygonIsNormalized: false + property real spacing: baseMargin * 2 + W.AxisRectangularContainerShape { + id: containerShape + width: bgShape.backgroundWidth + height: bgShape.backgroundHeight + startRadius: bgShape.startRadius + endRadius: bgShape.endRadius + } + W.RectangularContainerShape { + id: popupShape + width: bgShape.popupWidth + height: bgShape.popupHeight + radius: C.Appearance.rounding.large + xOffset: bgShape.popupXOffset + yOffset: bgShape.atBottom ? -(popupShape.height + bgShape.spacing) : (containerShape.height + bgShape.spacing) + } + + roundedPolygon: { + if (!bgShape.showPopup) + return containerShape.getFullShape(); + // return popupShape.getFullShape(); // debug + const points = [...(bgShape.atBottom ? containerShape.getFirstBottomPoints() : [...popupShape.getFirstBottomPoints(), popupShape.getBottomLeftPoint(), ...popupShape.leftPoints, popupShape.getTopLeftPoint(),]), containerShape.getBottomLeftPoint(0, bgShape.spacing * (!bgShape.atBottom ? 1 : 0), containerShape.radiusLimit), + // ...containerShape.leftPoints, + containerShape.getTopLeftPoint(0, bgShape.spacing * (bgShape.atBottom ? -1 : 0), containerShape.radiusLimit), ...(!bgShape.atBottom ? containerShape.topPoints : [popupShape.getBottomLeftPoint(), ...popupShape.leftPoints, popupShape.getTopLeftPoint(), ...popupShape.topPoints, popupShape.getTopRightPoint(), ...popupShape.rightPoints, popupShape.getBottomRightPoint(),]), containerShape.getTopRightPoint(0, bgShape.spacing * (bgShape.atBottom ? -1 : 0), containerShape.radiusLimit), + // ...containerShape.rightPoints, + containerShape.getBottomRightPoint(0, bgShape.spacing * (!bgShape.atBottom ? 1 : 0), containerShape.radiusLimit), ...(bgShape.atBottom ? containerShape.getLastBottomPoints() : [popupShape.getTopRightPoint(), ...popupShape.rightPoints, popupShape.getBottomRightPoint(), ...popupShape.getLastBottomPoints(),]),]; + return MaterialShapes.customPolygon(points); + } + + component Anim: SpringAnimation { + spring: 3.5 + damping: 0.35 + } +} diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml index cfbb1fc86..dc244c5a2 100644 --- a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/HTime.qml @@ -22,112 +22,30 @@ HBarWidgetContainer { target: root function onShowPopupChanged() { if (root.showPopup) { - morphedPanelParent.addAttachedMaskItem(bgShape); + containerRoot.morphedPanelParent.addAttachedMaskItem(bgShape); } else { - morphedPanelParent.removeAttachedMaskItem(bgShape); + containerRoot.morphedPanelParent.removeAttachedMaskItem(bgShape); } } } Connections { - target: morphedPanelParent + target: containerRoot.morphedPanelParent function onFocusGrabDismissed() { root.showPopup = false; } } // Background container shape - background: Shapes.ShapeCanvas { + background: HBarWidgetShapeBackground { id: bgShape - property real baseTopMargin: (parent.height - containerShape.height) / 2 - anchors { - horizontalCenter: parent.horizontalCenter - top: parent.top - topMargin: { - if (!root.atBottom || !root.showPopup) return baseTopMargin; - else return baseTopMargin - popupShape.height - bgShape.spacing; - } - } - width: root.showPopup ? Math.max(containerShape.width, popupShape.width) : containerShape.width - height: root.showPopup ? (containerShape.height + popupShape.height + bgShape.spacing) : containerShape.height - color: root.showPopup || progress < 1 ? C.Appearance.colors.colLayer3Base : C.Appearance.colors.colLayer1 - // color: "green" - // debug: true - xOffset: (width - containerShape.width) / 2 - yOffset: root.atBottom ? (height - containerShape.height) : 0 - animation: Anim {} - Behavior on width { - Anim {} - } - Behavior on height { - Anim {} - } - Behavior on anchors.topMargin { - Anim {} - } - - // Rectangle { - // anchors.fill: parent - // } - - polygonIsNormalized: false - property real spacing: baseTopMargin * 2 - W.AxisRectangularContainerShape { - id: containerShape - width: containerRoot.backgroundWidth - height: containerRoot.backgroundHeight - startRadius: containerRoot.getBackgroundRadius(containerRoot.startSide) - endRadius: containerRoot.getBackgroundRadius(containerRoot.endSide) - } - W.RectangularContainerShape { - id: popupShape - width: 400 // TODO - height: 500 // TODO - radius: C.Appearance.rounding.large - xOffset: -(width - containerShape.width) / 2 - yOffset: root.atBottom ? -(popupShape.height + bgShape.spacing) : (containerShape.height + bgShape.spacing) - } - - - roundedPolygon: { - if (!root.showPopup) return containerShape.getFullShape() - // return popupShape.getFullShape(); // debug - const points = [ - ...(root.atBottom ? containerShape.getFirstBottomPoints() : [ - ...popupShape.getFirstBottomPoints(), - popupShape.getBottomLeftPoint(), - ...popupShape.leftPoints, - popupShape.getTopLeftPoint(), - ]), - containerShape.getBottomLeftPoint(0, bgShape.spacing * (!root.atBottom ? 1 : 0), containerShape.radiusLimit), - // ...containerShape.leftPoints, - containerShape.getTopLeftPoint(0, bgShape.spacing * (root.atBottom ? -1 : 0), containerShape.radiusLimit), - ...(!root.atBottom ? containerShape.topPoints : [ - popupShape.getBottomLeftPoint(), - ...popupShape.leftPoints, - popupShape.getTopLeftPoint(), - ...popupShape.topPoints, - popupShape.getTopRightPoint(), - ...popupShape.rightPoints, - popupShape.getBottomRightPoint(), - ]), - containerShape.getTopRightPoint(0, bgShape.spacing * (root.atBottom ? -1 : 0), containerShape.radiusLimit), - // ...containerShape.rightPoints, - containerShape.getBottomRightPoint(0, bgShape.spacing * (!root.atBottom ? 1 : 0), containerShape.radiusLimit), - ...(root.atBottom ? containerShape.getLastBottomPoints() : [ - popupShape.getTopRightPoint(), - ...popupShape.rightPoints, - popupShape.getBottomRightPoint(), - ...popupShape.getLastBottomPoints(), - ]), - ]; - return MaterialShapes.customPolygon(points); - } - - component Anim: SpringAnimation { - spring: 3.5 - damping: 0.35 - } + atBottom: root.atBottom + showPopup: root.showPopup + backgroundWidth: containerRoot.backgroundWidth + backgroundHeight: containerRoot.backgroundHeight + startRadius: containerRoot.getBackgroundRadius(containerRoot.startSide) + endRadius: containerRoot.getBackgroundRadius(containerRoot.endSide) + baseMargin: (parent.height - containerShape.height) / 2 // TODO vertical } // The button on the bar diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/Invisible.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/Invisible.qml index 08b2d0fb5..d32a22e33 100644 --- a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/Invisible.qml +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/Invisible.qml @@ -1,6 +1,9 @@ pragma ComponentBehavior: Bound import QtQuick +import QtQuick.Layouts Item { visible: false + Layout.fillWidth: false + Layout.fillHeight: false } diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/InvisibleFill.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/InvisibleFill.qml new file mode 100644 index 000000000..bc8a87b43 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/widgets/InvisibleFill.qml @@ -0,0 +1,9 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts + +Item { + visible: false + Layout.fillHeight: true + Layout.fillWidth: true +}