feat: sdf blob based drawers

This commit is contained in:
2 * r + 2 * t 2026-03-25 12:04:55 +11:00
parent f15b902c0e
commit 87f33d55ee
11 changed files with 273 additions and 114 deletions

View file

@ -15,7 +15,8 @@ Item {
required property ShellScreen screen required property ShellScreen screen
readonly property real nonAnimWidth: x > 0 || hasCurrent ? children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth : 0 readonly property real shownWidth: children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth
readonly property real nonAnimWidth: x > 0 || hasCurrent ? shownWidth : 0
readonly property real nonAnimHeight: children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight readonly property real nonAnimHeight: children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight
readonly property Item current: (content.item as Content)?.current ?? null readonly property Item current: (content.item as Content)?.current ?? null

View file

@ -30,8 +30,9 @@ Item {
readonly property real nonAnimHeight: state === "visible" ? ((content.item as Content)?.nonAnimHeight ?? 0) : 0 readonly property real nonAnimHeight: state === "visible" ? ((content.item as Content)?.nonAnimHeight ?? 0) : 0
visible: height > 0 visible: anchors.topMargin > -implicitHeight - 5
implicitHeight: 0 anchors.topMargin: -implicitHeight - 5
implicitHeight: content.implicitHeight
implicitWidth: content.implicitWidth implicitWidth: content.implicitWidth
onStateChanged: { onStateChanged: {
@ -46,32 +47,35 @@ Item {
when: root.visibilities.dashboard && Config.dashboard.enabled when: root.visibilities.dashboard && Config.dashboard.enabled
PropertyChanges { PropertyChanges {
root.implicitHeight: content.implicitHeight // root.implicitHeight: content.implicitHeight
root.anchors.topMargin: 0
} }
} }
transitions: [ transitions: [
Transition { Transition {
from: "" // from: ""
to: "visible" // to: "visible"
Anim { Anim {
target: root target: root.anchors
property: "implicitHeight" property: "topMargin"
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
}, }
Transition { // Transition {
from: "visible" // from: "visible"
to: "" // to: ""
// Anim {
// target: root.anchors
// property: "topMargin"
// easing.bezierCurve: Appearance.anim.curves.emphasized
// }
// }
Anim {
target: root
property: "implicitHeight"
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
] ]
Timer { Timer {

View file

@ -6,6 +6,7 @@ import QtQuick.Effects
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Wayland import Quickshell.Wayland
import Caelestia.Blobs
import qs.components import qs.components
import qs.components.containers import qs.components.containers
import qs.services import qs.services
@ -123,13 +124,113 @@ Variants {
shadowColor: Qt.alpha(Colours.palette.m3shadow, 0.7) shadowColor: Qt.alpha(Colours.palette.m3shadow, 0.7)
} }
Border { // Border {
// bar: bar
// }
// Backgrounds {
// panels: panels
// bar: bar
// }
BlobGroup {
id: blobGroup
color: Colours.palette.m3surface
}
BlobInvertedRect {
anchors.fill: parent
anchors.margins: -50 // Make border thicker to smooth out bulge from closed drawers
group: blobGroup
radius: Config.border.rounding
borderLeft: bar.implicitWidth - anchors.margins
borderRight: Config.border.thickness - anchors.margins
borderTop: Config.border.thickness - anchors.margins
borderBottom: Config.border.thickness - anchors.margins
}
PanelBg {
id: dashBg
group: blobGroup
panel: panels.dashboard
bar: bar bar: bar
} }
Backgrounds { PanelBg {
panels: panels id: launcherBg
group: blobGroup
panel: panels.launcher
bar: bar bar: bar
deformAmount: 0.1
}
PanelBg {
id: sessionBg
group: blobGroup
panel: panels.session
bar: bar
}
PanelBg {
id: sidebarBg
group: blobGroup
panel: panels.sidebar
bar: bar
deformAmount: 0
}
PanelBg {
id: osdBg
group: blobGroup
panel: panels.osd
bar: bar
}
PanelBg {
id: notifsBg
group: blobGroup
panel: panels.notifications
bar: bar
}
PanelBg {
id: utilsBg
group: blobGroup
panel: panels.utilities
bar: bar
}
PanelBg {
id: popoutBg
group: blobGroup
panel: panels.popouts
bar: bar
x: bar.implicitWidth - (panels.popouts.isDetached ? -(win.width - panels.popouts.shownWidth) / 2 : panels.popouts.hasCurrent ? 0 : panels.popouts.shownWidth + 5)
implicitWidth: panels.popouts.shownWidth
Behavior on x {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
Behavior on implicitWidth {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
} }
} }
@ -152,6 +253,31 @@ Variants {
screen: scope.modelData screen: scope.modelData
visibilities: visibilities visibilities: visibilities
bar: bar bar: bar
dashboard.transform: Matrix4x4 {
matrix: dashBg.deformMatrix
}
launcher.transform: Matrix4x4 {
matrix: launcherBg.deformMatrix
}
session.transform: Matrix4x4 {
matrix: sessionBg.deformMatrix
}
sidebar.transform: Matrix4x4 {
matrix: sidebarBg.deformMatrix
}
osd.transform: Matrix4x4 {
matrix: osdBg.deformMatrix
}
notifications.transform: Matrix4x4 {
matrix: notifsBg.deformMatrix
}
utilities.transform: Matrix4x4 {
matrix: utilsBg.deformMatrix
}
popouts.transform: Matrix4x4 {
matrix: popoutBg.deformMatrix
}
} }
BarWrapper { BarWrapper {
@ -171,4 +297,17 @@ Variants {
} }
} }
} }
component PanelBg: BlobRect {
required property Item panel
required property Item bar
property real deformAmount: 0.15
x: panel.x + bar.implicitWidth
y: panel.y + Config.border.thickness
implicitWidth: panel.width
implicitHeight: panel.height
radius: Config.border.rounding
deformScale: deformAmount / 10000
}
} }

View file

@ -102,7 +102,7 @@ CustomMouseArea {
visibilities.bar = false; visibilities.bar = false;
} }
if (panels.sidebar.width === 0) { if (panels.sidebar.anchors.rightMargin === -panels.sidebar.implicitWidth - 5) {
// Show osd on hover // Show osd on hover
const showOsd = inRightPanel(panels.osd, x, y); const showOsd = inRightPanel(panels.osd, x, y);

View file

@ -42,8 +42,8 @@ Item {
visibilities: root.visibilities visibilities: root.visibilities
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: session.left
anchors.rightMargin: session.width + sidebar.width // anchors.rightMargin: session.width + sidebar.width
} }
Notifications.Wrapper { Notifications.Wrapper {
@ -66,8 +66,8 @@ Item {
panels: root panels: root
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: sidebar.left
anchors.rightMargin: sidebar.width // anchors.rightMargin: sidebar.width
} }
Launcher.Wrapper { Launcher.Wrapper {

View file

@ -24,8 +24,9 @@ Item {
onMaxHeightChanged: timer.start() onMaxHeightChanged: timer.start()
visible: height > 0 visible: anchors.bottomMargin > -implicitHeight - 5
implicitHeight: 0 anchors.bottomMargin: -implicitHeight - 5
implicitHeight: content.implicitHeight
implicitWidth: content.implicitWidth implicitWidth: content.implicitWidth
onShouldBeActiveChanged: { onShouldBeActiveChanged: {
@ -43,28 +44,30 @@ Item {
id: showAnim id: showAnim
Anim { Anim {
target: root target: root.anchors
property: "implicitHeight" property: "bottomMargin"
to: root.contentHeight to: 0
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
ScriptAction { // ScriptAction {
script: root.implicitHeight = Qt.binding(() => content.implicitHeight) // script: root.implicitHeight = Qt.binding(() => content.implicitHeight)
} // }
} }
SequentialAnimation { SequentialAnimation {
id: hideAnim id: hideAnim
ScriptAction { // ScriptAction {
script: root.implicitHeight = root.implicitHeight // script: root.implicitHeight = root.implicitHeight
} // }
Anim { Anim {
target: root target: root.anchors
property: "implicitHeight" property: "bottomMargin"
to: 0 to: -content.implicitHeight - 5
easing.bezierCurve: Appearance.anim.curves.emphasized // easing.bezierCurve: Appearance.anim.curves.emphasized
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
} }

View file

@ -10,23 +10,24 @@ Item {
property alias osdPanel: content.osdPanel property alias osdPanel: content.osdPanel
property alias sessionPanel: content.sessionPanel property alias sessionPanel: content.sessionPanel
visible: height > 0 visible: anchors.topMargin > -implicitHeight - 5
anchors.topMargin: -5
implicitWidth: Math.max(sidebarPanel.width, content.implicitWidth) implicitWidth: Math.max(sidebarPanel.width, content.implicitWidth)
implicitHeight: content.implicitHeight implicitHeight: content.implicitHeight
states: State { states: State {
name: "hidden" name: "hidden"
when: root.visibilities.sidebar && Config.sidebar.enabled // when: root.visibilities.sidebar && Config.sidebar.enabled
PropertyChanges { PropertyChanges {
root.implicitHeight: 0 root.anchors.topMargin: -implicitHeight - 5
} }
} }
transitions: Transition { transitions: Transition {
Anim { Anim {
target: root target: root.anchors
property: "implicitHeight" property: "topMargin"
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }

View file

@ -34,8 +34,9 @@ Item {
brightness = root.monitor?.brightness ?? 0; brightness = root.monitor?.brightness ?? 0;
} }
visible: width > 0 visible: anchors.rightMargin > -implicitWidth
implicitWidth: 0 anchors.rightMargin: -implicitWidth
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight implicitHeight: content.implicitHeight
states: State { states: State {
@ -43,31 +44,33 @@ Item {
when: root.shouldBeActive when: root.shouldBeActive
PropertyChanges { PropertyChanges {
root.implicitWidth: content.implicitWidth root.anchors.rightMargin: 0
} }
} }
transitions: [ transitions: [
Transition { Transition {
from: "" // from: ""
to: "visible" // to: "visible"
Anim { Anim {
target: root target: root.anchors
property: "implicitWidth" property: "rightMargin"
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
}, }
Transition { // Transition {
from: "visible" // from: "visible"
to: "" // to: ""
// Anim {
// target: root
// property: "implicitWidth"
// easing.bezierCurve: Appearance.anim.curves.emphasized
// }
// }
Anim {
target: root
property: "implicitWidth"
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
] ]
Connections { Connections {

View file

@ -11,8 +11,9 @@ Item {
required property var panels required property var panels
readonly property real nonAnimWidth: content.implicitWidth readonly property real nonAnimWidth: content.implicitWidth
visible: width > 0 visible: anchors.rightMargin > -implicitWidth - 1
implicitWidth: 0 anchors.rightMargin: -implicitWidth - 1
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight implicitHeight: content.implicitHeight
states: State { states: State {
@ -20,31 +21,33 @@ Item {
when: root.visibilities.session && Config.session.enabled when: root.visibilities.session && Config.session.enabled
PropertyChanges { PropertyChanges {
root.implicitWidth: root.nonAnimWidth root.anchors.rightMargin: 0
} }
} }
transitions: [ transitions: [
Transition { Transition {
from: "" // from: ""
to: "visible" // to: "visible"
Anim { Anim {
target: root target: root.anchors
property: "implicitWidth" property: "rightMargin"
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
}, }
Transition { // Transition {
from: "visible" // from: "visible"
to: "" // to: ""
// Anim {
// target: root
// property: "implicitWidth"
// easing.bezierCurve: root.panels.osd.width > 0 ? Appearance.anim.curves.expressiveDefaultSpatial : Appearance.anim.curves.emphasized
// }
// }
Anim {
target: root
property: "implicitWidth"
easing.bezierCurve: root.panels.osd.width > 0 ? Appearance.anim.curves.expressiveDefaultSpatial : Appearance.anim.curves.emphasized
}
}
] ]
Loader { Loader {

View file

@ -11,40 +11,43 @@ Item {
required property var panels required property var panels
readonly property Props props: Props {} readonly property Props props: Props {}
visible: width > 0 visible: anchors.rightMargin > -implicitWidth - 5
implicitWidth: 0 anchors.rightMargin: -implicitWidth - 5
implicitWidth: Config.sidebar.sizes.width
states: State { states: State {
name: "visible" name: "visible"
when: root.visibilities.sidebar && Config.sidebar.enabled when: root.visibilities.sidebar && Config.sidebar.enabled
PropertyChanges { PropertyChanges {
root.implicitWidth: Config.sidebar.sizes.width root.anchors.rightMargin: 0
} }
} }
transitions: [ transitions: [
Transition { Transition {
from: "" // from: ""
to: "visible" // to: "visible"
Anim { Anim {
target: root target: root.anchors
property: "implicitWidth" property: "rightMargin"
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
}, }
Transition { // Transition {
from: "visible" // from: "visible"
to: "" // to: ""
// Anim {
// target: root
// property: "implicitWidth"
// easing.bezierCurve: root.panels.osd.width > 0 || root.panels.session.width > 0 ? Appearance.anim.curves.expressiveDefaultSpatial : Appearance.anim.curves.emphasized
// }
// }
Anim {
target: root
property: "implicitWidth"
easing.bezierCurve: root.panels.osd.width > 0 || root.panels.session.width > 0 ? Appearance.anim.curves.expressiveDefaultSpatial : Appearance.anim.curves.emphasized
}
}
] ]
Loader { Loader {

View file

@ -22,8 +22,9 @@ Item {
} }
readonly property bool shouldBeActive: visibilities.sidebar || (visibilities.utilities && Config.utilities.enabled && !(visibilities.session && Config.session.enabled)) readonly property bool shouldBeActive: visibilities.sidebar || (visibilities.utilities && Config.utilities.enabled && !(visibilities.session && Config.session.enabled))
visible: height > 0 visible: anchors.bottomMargin > -implicitHeight - 5
implicitHeight: 0 anchors.bottomMargin: -implicitHeight - 5
implicitHeight: content.implicitHeight
implicitWidth: sidebar.visible ? sidebar.width : Config.utilities.sizes.width implicitWidth: sidebar.visible ? sidebar.width : Config.utilities.sizes.width
onStateChanged: { onStateChanged: {
@ -38,32 +39,33 @@ Item {
when: root.shouldBeActive when: root.shouldBeActive
PropertyChanges { PropertyChanges {
root.implicitHeight: content.implicitHeight + Appearance.padding.large * 2 root.anchors.bottomMargin: 0
} }
} }
transitions: [ transitions: [
Transition { Transition {
from: "" // from: ""
to: "visible" // to: "visible"
Anim { Anim {
target: root target: root.anchors
property: "implicitHeight" property: "bottomMargin"
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
}, }
Transition { // Transition {
from: "visible" // from: "visible"
to: "" // to: ""
// Anim {
// target: root
// property: "implicitHeight"
// easing.bezierCurve: Appearance.anim.curves.emphasized
// }
// }
Anim {
target: root
property: "implicitHeight"
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
] ]
Timer { Timer {