feat(island): Add shadow to island and satellites support (#3798)

This commit is contained in:
Alex Hulbert
2026-10-16 00:10:35 -04:00
committed by GitHub
parent b08f3f8ea1
commit cd42276870
5 changed files with 70 additions and 15 deletions
+2 -1
View File
@@ -743,7 +743,8 @@ Item {
readonly property real barSurfaceThickness: Theme.px(effectiveBarThickness + surfaceSpacing + ((renderBarConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel && spansEdge ? _wingR : 0), _dpr) + _shadowBuffer
readonly property bool islandSheetOut: islandHost?.sheetOut ?? false
readonly property real hostThickness: isIsland ? (islandHost?.hostThickness ?? islandStripThickness) : Math.max(barSurfaceThickness, islandSheetOut ? islandHost.hostThickness : 0)
readonly property real islandSatelliteShadowBuffer: isIsland && islandSatellitesEnabled && !islandSatelliteBackground ? _shadowBuffer : 0
readonly property real hostThickness: isIsland ? Math.max(islandHost?.hostThickness ?? 0, islandStripThickness + islandSatelliteShadowBuffer) : Math.max(barSurfaceThickness, islandSheetOut ? islandHost.hostThickness : 0)
readonly property real hideSlideThickness: isIsland ? hostThickness : barSurfaceThickness
readonly property real surfaceImplicitHeight: !isVertical ? hostThickness : 0
readonly property real surfaceImplicitWidth: isVertical ? hostThickness : 0
+38 -4
View File
@@ -75,6 +75,9 @@ Item {
readonly property real islandOpacity: Math.max(0, Math.min(1, root.transparency))
readonly property color effectiveSurfaceColor: root.embedded ? root.bandColor : root.highContrast ? Theme.surfaceContainerHighest : Theme.withAlpha(root.surfaceColor, root.islandOpacity)
readonly property real surfaceOpacity: root.effectiveSurfaceColor.a
readonly property bool shadowEnabled: !root.chromeless && root.surfaceOpacity > 0 && Theme.elevationEnabled && SettingsData.barElevationEnabled
readonly property string autoBarShadowDirection: root.controller.edge
readonly property string effectiveShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection
readonly property real currentSurfaceRadius: Math.max(0, motion.currentTopLeftRadius, motion.currentBottomLeftRadius)
readonly property color notificationAccentColor: {
if (!root.controller.notificationActive)
@@ -364,6 +367,13 @@ Item {
height: (motion.running ? Math.max(root.motionStartBounds.y + root.motionStartBounds.height, root.targetVisualY + motion.targetHeight) : root.targetVisualY + motion.targetHeight) + overshootBudget - y
}
Loader {
anchors.fill: island
z: island.z - 1
active: root.shadowEnabled && !root.embedded
sourceComponent: shadowComponent
}
MorphSurface {
id: island
motion: root.surfaceMotion
@@ -531,15 +541,24 @@ Item {
active: root.embedded
sourceComponent: Item {
id: overhangClip
readonly property real shadowPad: root.shadowEnabled ? Theme.elevationRenderPadding(Theme.elevationLevel2, root.effectiveShadowDirection, Theme.spacingXS, Theme.spacingS, Theme.spacingL) : 0
visible: root.embeddedOverhang > 0
clip: true
x: root.isVertical ? (root.farEdge ? -root.embeddedOverhang : root.crossExtent) : 0
y: root.isVertical ? 0 : (root.farEdge ? -root.embeddedOverhang : root.crossExtent)
width: root.isVertical ? root.embeddedOverhang : root.width
height: root.isVertical ? root.height : root.embeddedOverhang
x: root.isVertical ? (root.farEdge ? -root.embeddedOverhang - shadowPad : root.crossExtent) : -shadowPad
y: root.isVertical ? -shadowPad : (root.farEdge ? -root.embeddedOverhang - shadowPad : root.crossExtent)
width: root.isVertical ? root.embeddedOverhang + shadowPad : root.width + 2 * shadowPad
height: root.isVertical ? root.height + 2 * shadowPad : root.embeddedOverhang + shadowPad
Loader {
anchors.fill: overhang
active: root.shadowEnabled
sourceComponent: shadowComponent
}
MorphSurface {
id: overhang
motion: root.surfaceMotion
x: root.currentVisualX - overhangClip.x
y: root.currentVisualY - overhangClip.y
@@ -576,6 +595,21 @@ Item {
}
}
Component {
id: shadowComponent
ElevationShadow {
level: Theme.elevationLevel2
direction: root.effectiveShadowDirection
fallbackOffset: Theme.spacingXS
targetColor: "transparent"
topLeftRadius: island.topLeftRadius
topRightRadius: island.topRightRadius
bottomLeftRadius: island.bottomLeftRadius
bottomRightRadius: island.bottomRightRadius
}
}
Component {
id: compactHomeComponent
+3 -2
View File
@@ -170,8 +170,9 @@ Item {
readonly property int destinationMaxHeight: Math.max(destinationMinHeight, Math.min(destinationMaxHeightLimit, (root.screen?.height ?? referenceScreenHeight) - screenMargin))
readonly property int maxActivityHeight: Math.max(root.heldEditSurfaceHeight, controller.dashboardHeight, controller.controlCenterHeight, controller.launcherExpandedTarget.height, controller.clipboardExpandedTarget.height, controller.powerMenuExpandedTarget.height, destinationMaxHeight)
readonly property int maxActivityWidth: Math.max(controller.dashboardMaxWidth, controller.controlCenterMaxWidth, controller.launcherExpandedTarget.width, controller.clipboardExpandedTarget.width, controller.powerMenuExpandedTarget.width, Math.min(activityMaxWidth, Math.max(activityMinWidth, (root.screen?.width ?? referenceScreenWidth) - screenMargin)))
readonly property int hostThickness: outerGap + nearInset + (root.isVertical ? maxActivityWidth : maxActivityHeight) + Theme.spacingS
readonly property real maximumAlongOffset: root.isVertical ? Math.max(0, (height - maxActivityHeight) / 2 - Theme.spacingS) : Math.max(0, (width - maxActivityWidth) / 2 - Theme.spacingS)
readonly property real shadowPadding: surface.shadowEnabled ? Theme.elevationRenderPadding(Theme.elevationLevel2, surface.effectiveShadowDirection, Theme.spacingXS, Theme.spacingS, Theme.spacingL) : 0
readonly property int hostThickness: outerGap + nearInset + (root.isVertical ? maxActivityWidth : maxActivityHeight) + Theme.spacingS + shadowPadding
readonly property real maximumAlongOffset: root.isVertical ? Math.max(0, (height - maxActivityHeight) / 2 - Theme.spacingS - shadowPadding) : Math.max(0, (width - maxActivityWidth) / 2 - Theme.spacingS - shadowPadding)
readonly property bool scrollEnabled: root.barConfig?.scrollEnabled ?? true
property bool keyboardFocusArmed: true
readonly property int keyboardFocusPolicy: KeyboardFocus.keyboardFocus(controller.keyboardDismissRequested && root.keyboardFocusArmed && !controller.keyboardYielded, null)
@@ -30,8 +30,8 @@ PanelWindow {
readonly property var storedAnchor: SessionData.islandFreePositions[root.positionKey] ?? null
readonly property real storedAnchorX: root.clampAnchorX((typeof root.storedAnchor?.x === "number" ? root.storedAnchor.x : 0.5) * root.screenWidth)
readonly property real storedAnchorY: root.clampAnchorY((typeof root.storedAnchor?.y === "number" ? root.storedAnchor.y : 0.5) * root.screenHeight)
readonly property int surfaceX: Math.floor(body.currentVisualX - root.hitPadding)
readonly property int surfaceY: Math.floor(body.currentVisualY - root.hitPadding)
readonly property int surfaceX: Math.floor(body.currentVisualX - root.hitPadding - body.shadowPadding)
readonly property int surfaceY: Math.floor(body.currentVisualY - root.hitPadding - body.shadowPadding)
readonly property bool expanded: body.expanded
readonly property bool pointerInside: body.islandController.pointerInside
@@ -130,8 +130,8 @@ PanelWindow {
left: root.surfaceX
top: root.surfaceY
}
implicitWidth: Math.ceil(body.currentVisualX + body.currentVisualWidth + root.hitPadding) - root.surfaceX
implicitHeight: Math.ceil(body.currentVisualY + body.currentVisualHeight + root.hitPadding) - root.surfaceY
implicitWidth: Math.ceil(body.currentVisualX + body.currentVisualWidth + root.hitPadding + body.shadowPadding) - root.surfaceX
implicitHeight: Math.ceil(body.currentVisualY + body.currentVisualHeight + root.hitPadding + body.shadowPadding) - root.surfaceY
Component.onCompleted: {
root.wake();
@@ -164,6 +164,7 @@ PanelWindow {
Item {
id: hitTarget
anchors.fill: parent
anchors.margins: body.shadowPadding
}
// Keep the animated buffer tight; the unmoving input-only window catches outside clicks.
@@ -185,10 +186,10 @@ PanelWindow {
width: dismissWindow.width
height: dismissWindow.height
Region {
x: root.surfaceX
y: root.surfaceY
width: root.width
height: root.height
x: root.surfaceX + hitTarget.x
y: root.surfaceY + hitTarget.y
width: hitTarget.width
height: hitTarget.height
intersection: Intersection.Subtract
}
}
@@ -90,6 +90,9 @@ Item {
return BarMetrics.widgetFill(barConfig);
}
property color fillColor: defaultFillColor
readonly property bool shadowEnabled: barConfig?.island === true && !SettingsData.islandSetting(barConfig, "islandSatelliteBackground") && !noBackground && fillColor.a > 0 && Theme.elevationEnabled && SettingsData.barElevationEnabled
readonly property string autoBarShadowDirection: axis?.edge ?? "top"
readonly property string effectiveShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection
property real topLeftRadius: cornerRadius(startJoined)
property real topRightRadius: cornerRadius(isVerticalOrientation ? startJoined : endJoined)
@@ -242,6 +245,21 @@ Item {
width: root.isVerticalOrientation ? visualContent.width : Math.max(0, length)
height: root.isVerticalOrientation ? Math.max(0, length) : visualContent.height
Loader {
anchors.fill: parent
active: root.shadowEnabled && width > 0 && height > 0
sourceComponent: ElevationShadow {
level: BarMetrics.elevationLevel
direction: root.effectiveShadowDirection
fallbackOffset: Theme.spacingXS
targetColor: "transparent"
topLeftRadius: fill.topLeftRadius
topRightRadius: fill.topRightRadius
bottomLeftRadius: fill.bottomLeftRadius
bottomRightRadius: fill.bottomRightRadius
}
}
Rectangle {
anchors.fill: parent
anchors.margins: -root.outlineThickness