Multiple fixes regarding blobs #66

Merged
zach merged 2 commits from blob-fix into main 2026-04-19 21:41:43 +02:00
13 changed files with 74 additions and 98 deletions
+1
View File
@@ -4,6 +4,7 @@ import Quickshell
Singleton { Singleton {
readonly property AppearanceConf.Anim anim: Config.appearance.anim readonly property AppearanceConf.Anim anim: Config.appearance.anim
readonly property AppearanceConf.Deform deform: Config.appearance.deform
readonly property AppearanceConf.FontStuff font: Config.appearance.font readonly property AppearanceConf.FontStuff font: Config.appearance.font
readonly property AppearanceConf.Padding padding: Config.appearance.padding readonly property AppearanceConf.Padding padding: Config.appearance.padding
// Literally just here to shorten accessing stuff :woe: // Literally just here to shorten accessing stuff :woe:
+5
View File
@@ -3,6 +3,8 @@ import Quickshell.Io
JsonObject { JsonObject {
property Anim anim: Anim { property Anim anim: Anim {
} }
property Deform deform: Deform {
}
property FontStuff font: FontStuff { property FontStuff font: FontStuff {
} }
property Padding padding: Padding { property Padding padding: Padding {
@@ -43,6 +45,9 @@ JsonObject {
property real scale: 1 property real scale: 1
property int small: 200 * scale property int small: 200 * scale
} }
component Deform: JsonObject {
property real scale: 1
}
component FontFamily: JsonObject { component FontFamily: JsonObject {
property string clock: "Rubik" property string clock: "Rubik"
property string material: "Material Symbols Rounded" property string material: "Material Symbols Rounded"
+3
View File
@@ -48,6 +48,9 @@ Singleton {
padding: { padding: {
scale: appearance.padding.scale scale: appearance.padding.scale
}, },
deform: {
scale: appearance.deform.scale
},
font: { font: {
family: { family: {
sans: appearance.font.family.sans, sans: appearance.font.family.sans,
+10 -9
View File
@@ -170,7 +170,7 @@ Variants {
PanelBg { PanelBg {
id: dashBg id: dashBg
deformAmount: 0 deformAmount: 0.15 * Config.appearance.deform.scale
panel: panels.dashboard panel: panels.dashboard
radius: Appearance.rounding.normal radius: Appearance.rounding.normal
} }
@@ -178,7 +178,7 @@ Variants {
PanelBg { PanelBg {
id: launcherBg id: launcherBg
deformAmount: 0 deformAmount: 0.15 * Config.appearance.deform.scale
panel: panels.launcher panel: panels.launcher
radius: Appearance.rounding.smallest + 5 radius: Appearance.rounding.smallest + 5
} }
@@ -187,7 +187,7 @@ Variants {
id: sidebarBg id: sidebarBg
bottomLeftRadius: 0 bottomLeftRadius: 0
deformAmount: 0 deformAmount: 0.1 * Config.appearance.deform.scale
exclude: panels.sidebar.offsetscale > 0.08 ? [] : [utilsBg] exclude: panels.sidebar.offsetscale > 0.08 ? [] : [utilsBg]
implicitHeight: panel.height * (1 / rawDeformMatrix.m22) + 2 implicitHeight: panel.height * (1 / rawDeformMatrix.m22) + 2
panel: panels.sidebar panel: panels.sidebar
@@ -196,7 +196,7 @@ Variants {
PanelBg { PanelBg {
id: osdBg id: osdBg
deformAmount: 0 deformAmount: 0.1 * Config.appearance.deform.scale
panel: panels.osd panel: panels.osd
radius: 20 radius: 20
} }
@@ -210,7 +210,7 @@ Variants {
PanelBg { PanelBg {
id: utilsBg id: utilsBg
deformAmount: panels.sidebar.visible ? 0 : 0 deformAmount: panels.sidebar.visible ? (0.1 * Config.appearance.deform.scale) : (0.1 * Config.appearance.deform.scale)
exclude: panels.sidebar.offsetScale > 0.08 ? [] : [sidebarBg] exclude: panels.sidebar.offsetScale > 0.08 ? [] : [sidebarBg]
panel: panels.utilities panel: panels.utilities
topLeftRadius: 0 topLeftRadius: 0
@@ -219,15 +219,16 @@ Variants {
PanelBg { PanelBg {
id: popoutBg id: popoutBg
deformAmount: 0 deformAmount: 0.15 * Config.appearance.deform.scale
implicitWidth: panels.popouts.width implicitWidth: panels.popouts.width
panel: panels.popoutsWrapper panel: panels.popoutsWrapper
radius: (panels.popouts.currentName.startsWith("audio") || panels.popouts.currentName.startsWith("updates")) ? Appearance.rounding.normal : Appearance.rounding.smallest
} }
PanelBg { PanelBg {
id: resourcesBg id: resourcesBg
deformAmount: 0 deformAmount: 0.15 * Config.appearance.deform.scale
panel: panels.resources panel: panels.resources
radius: Appearance.rounding.normal radius: Appearance.rounding.normal
} }
@@ -235,7 +236,7 @@ Variants {
PanelBg { PanelBg {
id: settingsBg id: settingsBg
deformAmount: 0 deformAmount: 0.1 * Config.appearance.deform.scale
panel: panels.settings panel: panels.settings
radius: Appearance.rounding.large radius: Appearance.rounding.large
topLeftRadius: Appearance.rounding.large + Appearance.padding.smaller topLeftRadius: Appearance.rounding.large + Appearance.padding.smaller
@@ -245,7 +246,7 @@ Variants {
PanelBg { PanelBg {
id: dockBg id: dockBg
deformAmount: 0 deformAmount: 0.15 * Config.appearance.deform.scale
panel: panels.dock panel: panels.dock
radius: Appearance.rounding.normal radius: Appearance.rounding.normal
} }
+2 -2
View File
@@ -26,8 +26,8 @@ Item {
Behavior on offsetScale { Behavior on offsetScale {
Anim { Anim {
duration: MaterialEasing.expressiveEffectsTime duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: MaterialEasing.expressiveEffects easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
} }
Behavior on x { Behavior on x {
+4 -3
View File
@@ -101,9 +101,10 @@ Item {
readonly property bool shouldBeActive: root.popouts.currentName === name readonly property bool shouldBeActive: root.popouts.currentName === name
active: false active: false
anchors.horizontalCenter: parent.horizontalCenter // anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top // anchors.top: parent.top
anchors.topMargin: 5 // anchors.topMargin: 5
anchors.centerIn: parent
opacity: 0 opacity: 0
scale: 0.8 scale: 0.8
+13 -3
View File
@@ -57,6 +57,16 @@ SettingsPage {
setting: "scale" setting: "scale"
step: 0.1 step: 0.1
} }
Separator {
}
SettingSpinBox {
name: "Deform animation scale"
object: Config.appearance.deform
setting: "scale"
step: 0.1
}
} }
SettingsSection { SettingsSection {
@@ -118,9 +128,9 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Session GIF speed"
max: 5 max: 5
min: 0 min: 0
name: "Session GIF speed"
object: Config.appearance.anim object: Config.appearance.anim
setting: "sessionGifSpeed" setting: "sessionGifSpeed"
step: 0.1 step: 0.1
@@ -144,9 +154,9 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Base opacity"
max: 1 max: 1
min: 0 min: 0
name: "Base opacity"
object: Config.appearance.transparency object: Config.appearance.transparency
setting: "base" setting: "base"
step: 0.05 step: 0.05
@@ -156,9 +166,9 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Layer opacity"
max: 1 max: 1
min: 0 min: 0
name: "Layer opacity"
object: Config.appearance.transparency object: Config.appearance.transparency
setting: "layers" setting: "layers"
step: 0.05 step: 0.05
+8 -1
View File
@@ -815,7 +815,14 @@ export const settingsIndex = [
category: "appearance", category: "appearance",
categoryName: "Appearance", categoryName: "Appearance",
section: "Scale", section: "Scale",
keywords: ["animation", "speed", "duration"], keywords: ["animation", "speed", "duration", "scale"],
},
{
name: "Deform animation scale",
category: "appearance",
categoryName: "Appearance",
section: "Scale",
keywords: ["animation", "deform", "scale"],
}, },
// Fonts section // Fonts section
{ {
+14 -3
View File
@@ -24,6 +24,7 @@ Item {
CustomRect { CustomRect {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: parent.implicitHeight implicitHeight: parent.implicitHeight
radius: Appearance.rounding.small radius: Appearance.rounding.small
@@ -31,8 +32,8 @@ Item {
Behavior on implicitHeight { Behavior on implicitHeight {
Anim { Anim {
duration: MaterialEasing.emphasizedDecelTime duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.emphasized easing.bezierCurve: MaterialEasing.expressiveEffects
} }
} }
} }
@@ -40,7 +41,11 @@ Item {
ColumnLayout { ColumnLayout {
id: layout id: layout
anchors.centerIn: parent // anchors.centerIn: parent
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.top: parent.top
implicitWidth: stack.currentItem ? stack.currentItem.childrenRect.height : 0 implicitWidth: stack.currentItem ? stack.currentItem.childrenRect.height : 0
spacing: 12 spacing: 12
@@ -98,6 +103,12 @@ Item {
Layout.preferredHeight: currentIndex === 0 ? vol.childrenRect.height : dev.childrenRect.height Layout.preferredHeight: currentIndex === 0 ? vol.childrenRect.height : dev.childrenRect.height
currentIndex: 0 currentIndex: 0
// Behavior on Layout.preferredHeight {
// Anim {
// duration: MaterialEasing.expressiveEffectsTime
// easing.bezierCurve: MaterialEasing.expressiveEffects
// }
// }
Behavior on currentIndex { Behavior on currentIndex {
SequentialAnimation { SequentialAnimation {
ParallelAnimation { ParallelAnimation {
+5 -5
View File
@@ -8,8 +8,8 @@ import qs.Config
Item { Item {
id: root id: root
property list<real> animCurve: MaterialEasing.expressiveEffects property list<real> animCurve: Appearance.anim.curves.expressiveDefaultSpatial
property int animLength: MaterialEasing.expressiveEffectsTime property int animLength: Appearance.anim.durations.expressiveDefaultSpatial
readonly property alias content: content readonly property alias content: content
readonly property Item current: (content.item as Content)?.current ?? null readonly property Item current: (content.item as Content)?.current ?? null
property real currentCenter property real currentCenter
@@ -73,9 +73,9 @@ Item {
Comp { Comp {
id: content id: content
anchors.horizontalCenter: parent.horizontalCenter // anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top // anchors.top: parent.top
// anchors.centerIn: parent anchors.centerIn: parent
shouldBeActive: root.hasCurrent && !root.detachedMode shouldBeActive: root.hasCurrent && !root.detachedMode
sourceComponent: Content { sourceComponent: Content {
+7 -3
View File
@@ -72,11 +72,15 @@ void BlobShape::geometryChange(const QRectF& newGeometry, const QRectF& oldGeome
// Accumulate sub-pixel drift so slow movements don't desync the shader // Accumulate sub-pixel drift so slow movements don't desync the shader
m_pendingDx += static_cast<float>(newGeometry.x() - oldGeometry.x()); m_pendingDx += static_cast<float>(newGeometry.x() - oldGeometry.x());
m_pendingDy += static_cast<float>(newGeometry.y() - oldGeometry.y()); m_pendingDy += static_cast<float>(newGeometry.y() - oldGeometry.y());
const auto dw = std::abs(newGeometry.width() - oldGeometry.width()); m_pendingDw += static_cast<float>(newGeometry.width() - oldGeometry.width());
const auto dh = std::abs(newGeometry.height() - oldGeometry.height()); m_pendingDh += static_cast<float>(newGeometry.height() - oldGeometry.height());
if (std::abs(m_pendingDx) > 0.5f || std::abs(m_pendingDy) > 0.5f || dw > 0.5 || dh > 0.5) {
if (std::abs(m_pendingDx) > 0.5f || std::abs(m_pendingDy) > 0.5f ||
std::abs(m_pendingDw) > 0.5f || std::abs(m_pendingDh) > 0.5f) {
m_pendingDx = 0; m_pendingDx = 0;
m_pendingDy = 0; m_pendingDy = 0;
m_pendingDw = 0;
m_pendingDh = 0;
m_group->markShapeDirty(this); m_group->markShapeDirty(this);
} }
} }
+2
View File
@@ -85,6 +85,8 @@ QVector<BlobRectData> m_cachedRects;
int m_cachedMyIndex = -2; int m_cachedMyIndex = -2;
float m_pendingDx = 0; float m_pendingDx = 0;
float m_pendingDy = 0; float m_pendingDy = 0;
float m_pendingDw = 0;
float m_pendingDh = 0;
bool m_cachedHasInverted = false; bool m_cachedHasInverted = false;
float m_cachedInvertedRadius = 0; float m_cachedInvertedRadius = 0;
float m_cachedInvertedOuter[4] = {}; float m_cachedInvertedOuter[4] = {};
-69
View File
@@ -138,75 +138,6 @@ void main() {
d *= scale; d *= scale;
} }
// Rect-to-rect edge sinks: track the same edge of neighboring rects
{
float rectSinkValue = 0.0;
vec2 iHalf = sh.xy;
float preOff = smoothFactor * (1.0 / 6.0);
for (int j = 0; j < rectCount; j++) {
if (j == i)
continue;
vec4 jRect = rectData[j * 5];
vec4 jProps = rectData[j * 5 + 1];
vec2 jSh = rectData[j * 5 + 3].xy;
vec2 jCtr = jRect.xy + jProps.yz;
// Per-edge containment: the other rect's full span on the
// perpendicular axis must be inside this rect for that edge.
bool hInside = (jCtr.y - jSh.y) >= (center.y - iHalf.y) &&
(jCtr.y + jSh.y) <= (center.y + iHalf.y);
bool vInside = (jCtr.x - jSh.x) >= (center.x - iHalf.x) &&
(jCtr.x + jSh.x) <= (center.x + iHalf.x);
// Top/Bottom: other rect's height must be inside this rect
float topPen =
hInside ? clamp((center.y - iHalf.y) - (jCtr.y - jSh.y) - preOff,
0.0, smoothFactor)
: 0.0;
float botPen =
hInside ? clamp((jCtr.y + jSh.y) - (center.y + iHalf.y) - preOff,
0.0, smoothFactor)
: 0.0;
// Left/Right: other rect's width must be inside this rect
float leftPen =
vInside ? clamp((center.x - iHalf.x) - (jCtr.x - jSh.x) - preOff,
0.0, smoothFactor)
: 0.0;
float rightPen =
vInside ? clamp((jCtr.x + jSh.x) - (center.x + iHalf.x) - preOff,
0.0, smoothFactor)
: 0.0;
// Lateral distance from pixel to other rect's extent along each edge
float hLat = max(abs(pixel.x - jCtr.x) - jSh.x, 0.0);
float vLat = max(abs(pixel.y - jCtr.y) - jSh.y, 0.0);
// Perpendicular proximity: full strength at edge, fade inside
float topZone =
1.0 - smoothstep(center.y - iHalf.y,
center.y - iHalf.y + smoothFactor, pixel.y);
float botZone = smoothstep(center.y + iHalf.y - smoothFactor,
center.y + iHalf.y, pixel.y);
float leftZone =
1.0 - smoothstep(center.x - iHalf.x,
center.x - iHalf.x + smoothFactor, pixel.x);
float rightZone = smoothstep(center.x + iHalf.x - smoothFactor,
center.x + iHalf.x, pixel.x);
float s = smoothFactor * 2.0;
float sink = max(max(topPen * smoothstep(s, 0.0, hLat) * topZone,
botPen * smoothstep(s, 0.0, hLat) * botZone),
max(leftPen * smoothstep(s, 0.0, vLat) * leftZone,
rightPen * smoothstep(s, 0.0, vLat) * rightZone));
rectSinkValue = max(rectSinkValue, sink);
}
d -= rectSinkValue;
}
mergedSdf = smin(mergedSdf, d, smoothFactor); mergedSdf = smin(mergedSdf, d, smoothFactor);
if (d < smoothFactor && d < minDist) { if (d < smoothFactor && d < minDist) {
minDist = d; minDist = d;