refactor bar widget shape background and make it work at the right edge

This commit is contained in:
end-4
2026-02-20 22:58:52 +01:00
parent 485c40406d
commit 60ba555de6
5 changed files with 135 additions and 94 deletions
@@ -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
@@ -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
}
}
@@ -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
@@ -1,6 +1,9 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
Item {
visible: false
Layout.fillWidth: false
Layout.fillHeight: false
}
@@ -0,0 +1,9 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
Item {
visible: false
Layout.fillHeight: true
Layout.fillWidth: true
}