mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-03 20:32:07 -04:00
(frameInMotion): Initial Unified Frame Connected Mode
This commit is contained in:
@@ -143,8 +143,13 @@ Singleton {
|
|||||||
return variantDuration(baseDuration, false) + variantExitCleanupPadding();
|
return variantDuration(baseDuration, false) + variantExitCleanupPadding();
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isDirectionalEffect: typeof SettingsData !== "undefined" && SettingsData.motionEffect === 1
|
readonly property bool isDirectionalEffect: isConnectedEffect
|
||||||
|
|| (typeof SettingsData !== "undefined" && SettingsData.motionEffect === 1)
|
||||||
readonly property bool isDepthEffect: typeof SettingsData !== "undefined" && SettingsData.motionEffect === 2
|
readonly property bool isDepthEffect: typeof SettingsData !== "undefined" && SettingsData.motionEffect === 2
|
||||||
|
readonly property bool isConnectedEffect: typeof SettingsData !== "undefined"
|
||||||
|
&& SettingsData.frameEnabled
|
||||||
|
&& SettingsData.motionEffect === 1
|
||||||
|
&& SettingsData.directionalAnimationMode === 3
|
||||||
|
|
||||||
readonly property real effectScaleCollapsed: {
|
readonly property real effectScaleCollapsed: {
|
||||||
if (typeof SettingsData === "undefined")
|
if (typeof SettingsData === "undefined")
|
||||||
|
|||||||
@@ -13,8 +13,13 @@ Item {
|
|||||||
|
|
||||||
property color targetColor: "white"
|
property color targetColor: "white"
|
||||||
property real targetRadius: Theme.cornerRadius
|
property real targetRadius: Theme.cornerRadius
|
||||||
|
property real topLeftRadius: targetRadius
|
||||||
|
property real topRightRadius: targetRadius
|
||||||
|
property real bottomLeftRadius: targetRadius
|
||||||
|
property real bottomRightRadius: targetRadius
|
||||||
property color borderColor: "transparent"
|
property color borderColor: "transparent"
|
||||||
property real borderWidth: 0
|
property real borderWidth: 0
|
||||||
|
property bool useCustomSource: false
|
||||||
|
|
||||||
property bool shadowEnabled: Theme.elevationEnabled
|
property bool shadowEnabled: Theme.elevationEnabled
|
||||||
property real shadowBlurPx: level && level.blurPx !== undefined ? level.blurPx : 0
|
property real shadowBlurPx: level && level.blurPx !== undefined ? level.blurPx : 0
|
||||||
@@ -46,7 +51,11 @@ Item {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: sourceRect
|
id: sourceRect
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
radius: root.targetRadius
|
visible: !root.useCustomSource
|
||||||
|
topLeftRadius: root.topLeftRadius
|
||||||
|
topRightRadius: root.topRightRadius
|
||||||
|
bottomLeftRadius: root.bottomLeftRadius
|
||||||
|
bottomRightRadius: root.bottomRightRadius
|
||||||
color: root.targetColor
|
color: root.targetColor
|
||||||
border.color: root.borderColor
|
border.color: root.borderColor
|
||||||
border.width: root.borderWidth
|
border.width: root.borderWidth
|
||||||
|
|||||||
@@ -235,6 +235,8 @@ Singleton {
|
|||||||
onFrameShowOnOverviewChanged: saveSettings()
|
onFrameShowOnOverviewChanged: saveSettings()
|
||||||
property bool frameBlurEnabled: true
|
property bool frameBlurEnabled: true
|
||||||
onFrameBlurEnabledChanged: saveSettings()
|
onFrameBlurEnabledChanged: saveSettings()
|
||||||
|
property int previousDirectionalMode: 1
|
||||||
|
onPreviousDirectionalModeChanged: saveSettings()
|
||||||
|
|
||||||
readonly property color effectiveFrameColor: {
|
readonly property color effectiveFrameColor: {
|
||||||
const fc = frameColor;
|
const fc = frameColor;
|
||||||
@@ -1590,34 +1592,36 @@ Singleton {
|
|||||||
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top);
|
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top);
|
||||||
const rawBottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0);
|
const rawBottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0);
|
||||||
const bottomGap = Math.max(0, rawBottomGap);
|
const bottomGap = Math.max(0, rawBottomGap);
|
||||||
|
const isConnected = frameEnabled && motionEffect === 1 && directionalAnimationMode === 3;
|
||||||
|
|
||||||
const useAutoGaps = (barConfig && barConfig.popupGapsAuto !== undefined) ? barConfig.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true);
|
const useAutoGaps = (barConfig && barConfig.popupGapsAuto !== undefined) ? barConfig.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true);
|
||||||
const manualGapValue = (barConfig && barConfig.popupGapsManual !== undefined) ? barConfig.popupGapsManual : (defaultBar?.popupGapsManual ?? 4);
|
const manualGapValue = (barConfig && barConfig.popupGapsManual !== undefined) ? barConfig.popupGapsManual : (defaultBar?.popupGapsManual ?? 4);
|
||||||
const popupGap = useAutoGaps ? Math.max(4, spacing) : manualGapValue;
|
const popupGap = isConnected ? 0 : (useAutoGaps ? Math.max(4, spacing) : manualGapValue);
|
||||||
|
const edgeSpacing = isConnected ? 0 : spacing;
|
||||||
|
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case SettingsData.Position.Left:
|
case SettingsData.Position.Left:
|
||||||
return {
|
return {
|
||||||
"x": barThickness + spacing + popupGap,
|
"x": barThickness + edgeSpacing + popupGap,
|
||||||
"y": relativeY,
|
"y": relativeY,
|
||||||
"width": widgetWidth
|
"width": widgetWidth
|
||||||
};
|
};
|
||||||
case SettingsData.Position.Right:
|
case SettingsData.Position.Right:
|
||||||
return {
|
return {
|
||||||
"x": (screen?.width || 0) - (barThickness + spacing + popupGap),
|
"x": (screen?.width || 0) - (barThickness + edgeSpacing + popupGap),
|
||||||
"y": relativeY,
|
"y": relativeY,
|
||||||
"width": widgetWidth
|
"width": widgetWidth
|
||||||
};
|
};
|
||||||
case SettingsData.Position.Bottom:
|
case SettingsData.Position.Bottom:
|
||||||
return {
|
return {
|
||||||
"x": relativeX,
|
"x": relativeX,
|
||||||
"y": (screen?.height || 0) - (barThickness + spacing + bottomGap + popupGap),
|
"y": (screen?.height || 0) - (barThickness + edgeSpacing + bottomGap + popupGap),
|
||||||
"width": widgetWidth
|
"width": widgetWidth
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
"x": relativeX,
|
"x": relativeX,
|
||||||
"y": barThickness + spacing + bottomGap + popupGap,
|
"y": barThickness + edgeSpacing + bottomGap + popupGap,
|
||||||
"width": widgetWidth
|
"width": widgetWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -972,6 +972,22 @@ Singleton {
|
|||||||
readonly property real variantOpacityDurationScale: AnimVariants.variantOpacityDurationScale
|
readonly property real variantOpacityDurationScale: AnimVariants.variantOpacityDurationScale
|
||||||
readonly property bool isDirectionalEffect: AnimVariants.isDirectionalEffect
|
readonly property bool isDirectionalEffect: AnimVariants.isDirectionalEffect
|
||||||
readonly property bool isDepthEffect: AnimVariants.isDepthEffect
|
readonly property bool isDepthEffect: AnimVariants.isDepthEffect
|
||||||
|
readonly property bool isConnectedEffect: AnimVariants.isConnectedEffect
|
||||||
|
readonly property real connectedCornerRadius: {
|
||||||
|
if (typeof SettingsData === "undefined") return 12;
|
||||||
|
return SettingsData.frameEnabled ? SettingsData.frameRounding : cornerRadius;
|
||||||
|
}
|
||||||
|
readonly property color connectedSurfaceColor: {
|
||||||
|
if (typeof SettingsData === "undefined")
|
||||||
|
return withAlpha(surfaceContainer, popupTransparency);
|
||||||
|
return isConnectedEffect
|
||||||
|
? Qt.rgba(SettingsData.effectiveFrameColor.r, SettingsData.effectiveFrameColor.g, SettingsData.effectiveFrameColor.b, SettingsData.frameOpacity)
|
||||||
|
: withAlpha(surfaceContainer, popupTransparency);
|
||||||
|
}
|
||||||
|
readonly property real connectedSurfaceRadius: isConnectedEffect ? connectedCornerRadius : cornerRadius
|
||||||
|
readonly property bool connectedSurfaceBlurEnabled: (typeof SettingsData === "undefined")
|
||||||
|
? true
|
||||||
|
: (!isConnectedEffect || SettingsData.frameBlurEnabled)
|
||||||
readonly property real effectScaleCollapsed: AnimVariants.effectScaleCollapsed
|
readonly property real effectScaleCollapsed: AnimVariants.effectScaleCollapsed
|
||||||
readonly property real effectAnimOffset: AnimVariants.effectAnimOffset
|
readonly property real effectAnimOffset: AnimVariants.effectAnimOffset
|
||||||
function variantDuration(baseDuration, entering) { return AnimVariants.variantDuration(baseDuration, entering); }
|
function variantDuration(baseDuration, entering) { return AnimVariants.variantDuration(baseDuration, entering); }
|
||||||
@@ -1143,7 +1159,11 @@ Singleton {
|
|||||||
property real iconSizeLarge: 32
|
property real iconSizeLarge: 32
|
||||||
|
|
||||||
property real panelTransparency: 0.85
|
property real panelTransparency: 0.85
|
||||||
property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0
|
property real popupTransparency: {
|
||||||
|
if (typeof SettingsData === "undefined")
|
||||||
|
return 1.0;
|
||||||
|
return SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
function screenTransition() {
|
function screenTransition() {
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
@@ -1842,6 +1862,12 @@ Singleton {
|
|||||||
return Qt.rgba(c.r, c.g, c.b, a);
|
return Qt.rgba(c.r, c.g, c.b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function popupLayerColor(baseColor) {
|
||||||
|
if (isConnectedEffect)
|
||||||
|
return connectedSurfaceColor;
|
||||||
|
return withAlpha(baseColor, popupTransparency);
|
||||||
|
}
|
||||||
|
|
||||||
function blendAlpha(c, a) {
|
function blendAlpha(c, a) {
|
||||||
return Qt.rgba(c.r, c.g, c.b, c.a * a);
|
return Qt.rgba(c.r, c.g, c.b, c.a * a);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ var SPEC = {
|
|||||||
animationVariant: { def: 0 },
|
animationVariant: { def: 0 },
|
||||||
motionEffect: { def: 0 },
|
motionEffect: { def: 0 },
|
||||||
directionalAnimationMode: { def: 0 },
|
directionalAnimationMode: { def: 0 },
|
||||||
|
previousDirectionalMode: { def: 1 },
|
||||||
m3ElevationEnabled: { def: true },
|
m3ElevationEnabled: { def: true },
|
||||||
m3ElevationIntensity: { def: 12 },
|
m3ElevationIntensity: { def: 12 },
|
||||||
m3ElevationOpacity: { def: 30 },
|
m3ElevationOpacity: { def: 30 },
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Quickshell
|
|||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -34,6 +35,12 @@ Item {
|
|||||||
property color borderColor: Theme.outlineMedium
|
property color borderColor: Theme.outlineMedium
|
||||||
property real borderWidth: 0
|
property real borderWidth: 0
|
||||||
property real cornerRadius: Theme.cornerRadius
|
property real cornerRadius: Theme.cornerRadius
|
||||||
|
readonly property bool connectedSurfaceOverride: Theme.isConnectedEffect
|
||||||
|
readonly property color effectiveBackgroundColor: connectedSurfaceOverride ? Theme.connectedSurfaceColor : backgroundColor
|
||||||
|
readonly property color effectiveBorderColor: connectedSurfaceOverride ? "transparent" : borderColor
|
||||||
|
readonly property real effectiveBorderWidth: connectedSurfaceOverride ? 0 : borderWidth
|
||||||
|
readonly property real effectiveCornerRadius: connectedSurfaceOverride ? Theme.connectedSurfaceRadius : cornerRadius
|
||||||
|
readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled
|
||||||
property bool enableShadow: true
|
property bool enableShadow: true
|
||||||
property alias modalFocusScope: focusScope
|
property alias modalFocusScope: focusScope
|
||||||
property bool shouldBeVisible: false
|
property bool shouldBeVisible: false
|
||||||
@@ -163,6 +170,8 @@ Item {
|
|||||||
readonly property real shadowFallbackOffset: 6
|
readonly property real shadowFallbackOffset: 6
|
||||||
readonly property real shadowRenderPadding: (root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, Theme.elevationLightDirection, shadowFallbackOffset, 8, 16) : 0
|
readonly property real shadowRenderPadding: (root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, Theme.elevationLightDirection, shadowFallbackOffset, 8, 16) : 0
|
||||||
readonly property real shadowMotionPadding: {
|
readonly property real shadowMotionPadding: {
|
||||||
|
if (Theme.isConnectedEffect)
|
||||||
|
return 0;
|
||||||
if (typeof SettingsData !== "undefined" && SettingsData.directionalAnimationMode > 0 && Theme.isDirectionalEffect)
|
if (typeof SettingsData !== "undefined" && SettingsData.directionalAnimationMode > 0 && Theme.isDirectionalEffect)
|
||||||
return 0; // Wayland native overlap mask
|
return 0; // Wayland native overlap mask
|
||||||
if (animationType === "slide")
|
if (animationType === "slide")
|
||||||
@@ -244,7 +253,7 @@ Item {
|
|||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
enabled: root.animationsEnabled && !Theme.isDirectionalEffect
|
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
@@ -259,6 +268,17 @@ Item {
|
|||||||
visible: false
|
visible: false
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
WindowBlur {
|
||||||
|
targetWindow: contentWindow
|
||||||
|
blurEnabled: root.effectiveBlurEnabled
|
||||||
|
readonly property real s: Math.min(1, modalContainer.scaleValue)
|
||||||
|
blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr)
|
||||||
|
blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr)
|
||||||
|
blurWidth: (root.shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.width * s : 0
|
||||||
|
blurHeight: (root.shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.height * s : 0
|
||||||
|
blurRadius: root.effectiveCornerRadius
|
||||||
|
}
|
||||||
|
|
||||||
WlrLayershell.namespace: root.layerNamespace
|
WlrLayershell.namespace: root.layerNamespace
|
||||||
WlrLayershell.layer: {
|
WlrLayershell.layer: {
|
||||||
if (root.useOverlayLayer)
|
if (root.useOverlayLayer)
|
||||||
@@ -333,7 +353,7 @@ Item {
|
|||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
enabled: root.animationsEnabled && !Theme.isDirectionalEffect
|
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
@@ -487,12 +507,12 @@ Item {
|
|||||||
id: animatedContent
|
id: animatedContent
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: false
|
clip: false
|
||||||
opacity: Theme.isDirectionalEffect ? 1 : (root.shouldBeVisible ? 1 : 0)
|
opacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (root.shouldBeVisible ? 1 : 0)
|
||||||
scale: modalContainer.scaleValue
|
scale: modalContainer.scaleValue
|
||||||
transformOrigin: Item.Center
|
transformOrigin: Item.Center
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
enabled: root.animationsEnabled && !Theme.isDirectionalEffect
|
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: Math.round(Theme.variantDuration(animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
duration: Math.round(Theme.variantDuration(animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
@@ -505,13 +525,22 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
level: root.shadowLevel
|
level: root.shadowLevel
|
||||||
fallbackOffset: root.shadowFallbackOffset
|
fallbackOffset: root.shadowFallbackOffset
|
||||||
targetRadius: root.cornerRadius
|
targetRadius: root.effectiveCornerRadius
|
||||||
targetColor: root.backgroundColor
|
targetColor: root.effectiveBackgroundColor
|
||||||
borderColor: root.borderColor
|
borderColor: root.effectiveBorderColor
|
||||||
borderWidth: root.borderWidth
|
borderWidth: root.effectiveBorderWidth
|
||||||
shadowEnabled: root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
|
shadowEnabled: root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: root.effectiveCornerRadius
|
||||||
|
color: "transparent"
|
||||||
|
border.color: root.connectedSurfaceOverride ? "transparent" : BlurService.borderColor
|
||||||
|
border.width: root.connectedSurfaceOverride ? 0 : BlurService.borderWidth
|
||||||
|
z: 100
|
||||||
|
}
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: root.shouldBeVisible
|
focus: root.shouldBeVisible
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -65,8 +66,9 @@ Item {
|
|||||||
readonly property real modalX: (screenWidth - modalWidth) / 2
|
readonly property real modalX: (screenWidth - modalWidth) / 2
|
||||||
readonly property real modalY: (screenHeight - modalHeight) / 2
|
readonly property real modalY: (screenHeight - modalHeight) / 2
|
||||||
|
|
||||||
readonly property color backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
readonly property bool connectedSurfaceOverride: Theme.isConnectedEffect
|
||||||
readonly property real cornerRadius: Theme.cornerRadius
|
readonly property color backgroundColor: connectedSurfaceOverride ? Theme.connectedSurfaceColor : Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||||
|
readonly property real cornerRadius: connectedSurfaceOverride ? Theme.connectedSurfaceRadius : Theme.cornerRadius
|
||||||
readonly property color borderColor: {
|
readonly property color borderColor: {
|
||||||
if (!SettingsData.dankLauncherV2BorderEnabled)
|
if (!SettingsData.dankLauncherV2BorderEnabled)
|
||||||
return Theme.outlineMedium;
|
return Theme.outlineMedium;
|
||||||
@@ -84,6 +86,9 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 0
|
readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 0
|
||||||
|
readonly property color effectiveBorderColor: connectedSurfaceOverride ? "transparent" : borderColor
|
||||||
|
readonly property int effectiveBorderWidth: connectedSurfaceOverride ? 0 : borderWidth
|
||||||
|
readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled
|
||||||
|
|
||||||
// Shadow padding for the content window (render padding only, no motion padding)
|
// Shadow padding for the content window (render padding only, no motion padding)
|
||||||
readonly property var shadowLevel: Theme.elevationLevel3
|
readonly property var shadowLevel: Theme.elevationLevel3
|
||||||
@@ -97,13 +102,13 @@ Item {
|
|||||||
|
|
||||||
// For directional/depth: window extends from screen top (content slides within)
|
// For directional/depth: window extends from screen top (content slides within)
|
||||||
// For standard: small window tightly around the modal + shadow padding
|
// For standard: small window tightly around the modal + shadow padding
|
||||||
readonly property bool _needsExtendedWindow: Theme.isDirectionalEffect || Theme.isDepthEffect
|
readonly property bool _needsExtendedWindow: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) || Theme.isDepthEffect
|
||||||
// Content window geometry
|
// Content window geometry
|
||||||
readonly property real _cwMarginLeft: Theme.snap(alignedX - shadowPad, dpr)
|
readonly property real _cwMarginLeft: Theme.snap(alignedX - shadowPad, dpr)
|
||||||
readonly property real _cwMarginTop: _needsExtendedWindow ? 0 : Theme.snap(alignedY - shadowPad, dpr)
|
readonly property real _cwMarginTop: _needsExtendedWindow ? 0 : Theme.snap(alignedY - shadowPad, dpr)
|
||||||
readonly property real _cwWidth: alignedWidth + shadowPad * 2
|
readonly property real _cwWidth: alignedWidth + shadowPad * 2
|
||||||
readonly property real _cwHeight: {
|
readonly property real _cwHeight: {
|
||||||
if (Theme.isDirectionalEffect)
|
if (Theme.isDirectionalEffect && !Theme.isConnectedEffect)
|
||||||
return screenHeight + shadowPad;
|
return screenHeight + shadowPad;
|
||||||
if (Theme.isDepthEffect)
|
if (Theme.isDepthEffect)
|
||||||
return alignedY + alignedHeight + shadowPad;
|
return alignedY + alignedHeight + shadowPad;
|
||||||
@@ -387,7 +392,7 @@ Item {
|
|||||||
visible: launcherMotionVisible || opacity > 0
|
visible: launcherMotionVisible || opacity > 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
enabled: root.animationsEnabled && !Theme.isDirectionalEffect
|
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
|
||||||
DankAnim {
|
DankAnim {
|
||||||
duration: Math.round(Theme.variantDuration(Theme.modalAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
|
duration: Math.round(Theme.variantDuration(Theme.modalAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
|
||||||
easing.bezierCurve: launcherMotionVisible ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
|
easing.bezierCurve: launcherMotionVisible ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
|
||||||
@@ -408,6 +413,17 @@ Item {
|
|||||||
visible: false
|
visible: false
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
WindowBlur {
|
||||||
|
targetWindow: contentWindow
|
||||||
|
blurEnabled: root.effectiveBlurEnabled
|
||||||
|
readonly property real s: Math.min(1, contentContainer.scaleValue)
|
||||||
|
blurX: root._ccX + root.alignedWidth * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr)
|
||||||
|
blurY: root._ccY + root.alignedHeight * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr)
|
||||||
|
blurWidth: (root.spotlightOpen || root.isClosing) && contentWrapper.opacity > 0 ? root.alignedWidth * s : 0
|
||||||
|
blurHeight: (root.spotlightOpen || root.isClosing) && contentWrapper.opacity > 0 ? root.alignedHeight * s : 0
|
||||||
|
blurRadius: root.cornerRadius
|
||||||
|
}
|
||||||
|
|
||||||
WlrLayershell.namespace: "dms:spotlight"
|
WlrLayershell.namespace: "dms:spotlight"
|
||||||
WlrLayershell.layer: {
|
WlrLayershell.layer: {
|
||||||
switch (Quickshell.env("DMS_MODAL_LAYER")) {
|
switch (Quickshell.env("DMS_MODAL_LAYER")) {
|
||||||
@@ -572,8 +588,8 @@ Item {
|
|||||||
level: root.shadowLevel
|
level: root.shadowLevel
|
||||||
fallbackOffset: root.shadowFallbackOffset
|
fallbackOffset: root.shadowFallbackOffset
|
||||||
targetColor: root.backgroundColor
|
targetColor: root.backgroundColor
|
||||||
borderColor: root.borderColor
|
borderColor: root.effectiveBorderColor
|
||||||
borderWidth: root.borderWidth
|
borderWidth: root.effectiveBorderWidth
|
||||||
targetRadius: root.cornerRadius
|
targetRadius: root.cornerRadius
|
||||||
shadowEnabled: Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
|
shadowEnabled: Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
|
||||||
}
|
}
|
||||||
@@ -583,14 +599,14 @@ Item {
|
|||||||
id: contentWrapper
|
id: contentWrapper
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
opacity: Theme.isDirectionalEffect ? 1 : (launcherMotionVisible ? 1 : 0)
|
opacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (launcherMotionVisible ? 1 : 0)
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
scale: contentContainer.scaleValue
|
scale: contentContainer.scaleValue
|
||||||
x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
|
x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
|
||||||
y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
|
y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
enabled: root.animationsEnabled && !Theme.isDirectionalEffect
|
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
|
||||||
DankAnim {
|
DankAnim {
|
||||||
duration: Math.round(Theme.variantDuration(Theme.modalAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
|
duration: Math.round(Theme.variantDuration(Theme.modalAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
|
||||||
easing.bezierCurve: launcherMotionVisible ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
|
easing.bezierCurve: launcherMotionVisible ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ Variants {
|
|||||||
|
|
||||||
WindowBlur {
|
WindowBlur {
|
||||||
targetWindow: dock
|
targetWindow: dock
|
||||||
blurX: dockBackground.x + dockContainer.x + dockMouseArea.x + dockCore.x + dockSlide.x
|
blurEnabled: dock.effectiveBlurEnabled
|
||||||
blurY: dockBackground.y + dockContainer.y + dockMouseArea.y + dockCore.y + dockSlide.y
|
blurX: dockBackground.x + dockContainer.x + dockMouseArea.x + dockCore.x + dockSlide.x - dock.horizontalConnectorExtent
|
||||||
blurWidth: dock.hasApps && dock.reveal ? dockBackground.width : 0
|
blurY: dockBackground.y + dockContainer.y + dockMouseArea.y + dockCore.y + dockSlide.y - dock.verticalConnectorExtent
|
||||||
blurHeight: dock.hasApps && dock.reveal ? dockBackground.height : 0
|
blurWidth: dock.hasApps && dock.reveal ? dockBackground.width + dock.horizontalConnectorExtent * 2 : 0
|
||||||
blurRadius: Theme.cornerRadius
|
blurHeight: dock.hasApps && dock.reveal ? dockBackground.height + dock.verticalConnectorExtent * 2 : 0
|
||||||
|
blurRadius: dock.surfaceRadius
|
||||||
}
|
}
|
||||||
|
|
||||||
WlrLayershell.namespace: "dms:dock"
|
WlrLayershell.namespace: "dms:dock"
|
||||||
@@ -42,6 +43,29 @@ Variants {
|
|||||||
property real backgroundTransparency: SettingsData.dockTransparency
|
property real backgroundTransparency: SettingsData.dockTransparency
|
||||||
property bool groupByApp: SettingsData.dockGroupByApp
|
property bool groupByApp: SettingsData.dockGroupByApp
|
||||||
readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0
|
readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0
|
||||||
|
readonly property string connectedBarSide: SettingsData.dockPosition === SettingsData.Position.Top ? "top"
|
||||||
|
: SettingsData.dockPosition === SettingsData.Position.Bottom ? "bottom"
|
||||||
|
: SettingsData.dockPosition === SettingsData.Position.Left ? "left" : "right"
|
||||||
|
readonly property bool connectedBarActiveOnEdge: Theme.isConnectedEffect
|
||||||
|
&& !!(dock.screen || modelData)
|
||||||
|
&& SettingsData.getActiveBarEdgesForScreen(dock.screen || modelData).includes(connectedBarSide)
|
||||||
|
readonly property real connectedJoinInset: {
|
||||||
|
if (!Theme.isConnectedEffect)
|
||||||
|
return 0;
|
||||||
|
return connectedBarActiveOnEdge ? SettingsData.frameBarSize : SettingsData.frameThickness;
|
||||||
|
}
|
||||||
|
readonly property real surfaceRadius: Theme.connectedSurfaceRadius
|
||||||
|
readonly property color surfaceColor: Theme.isConnectedEffect
|
||||||
|
? Theme.connectedSurfaceColor
|
||||||
|
: Theme.withAlpha(Theme.surfaceContainer, backgroundTransparency)
|
||||||
|
readonly property color surfaceBorderColor: Theme.isConnectedEffect ? "transparent" : BlurService.borderColor
|
||||||
|
readonly property real surfaceBorderWidth: Theme.isConnectedEffect ? 0 : BlurService.borderWidth
|
||||||
|
readonly property real surfaceTopLeftRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Top || SettingsData.dockPosition === SettingsData.Position.Left) ? 0 : surfaceRadius
|
||||||
|
readonly property real surfaceTopRightRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Top || SettingsData.dockPosition === SettingsData.Position.Right) ? 0 : surfaceRadius
|
||||||
|
readonly property real surfaceBottomLeftRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Bottom || SettingsData.dockPosition === SettingsData.Position.Left) ? 0 : surfaceRadius
|
||||||
|
readonly property real surfaceBottomRightRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Bottom || SettingsData.dockPosition === SettingsData.Position.Right) ? 0 : surfaceRadius
|
||||||
|
readonly property real horizontalConnectorExtent: Theme.isConnectedEffect && !isVertical ? Theme.connectedCornerRadius : 0
|
||||||
|
readonly property real verticalConnectorExtent: Theme.isConnectedEffect && isVertical ? Theme.connectedCornerRadius : 0
|
||||||
|
|
||||||
readonly property int hasApps: dockApps.implicitWidth > 0 || dockApps.implicitHeight > 0
|
readonly property int hasApps: dockApps.implicitWidth > 0 || dockApps.implicitHeight > 0
|
||||||
|
|
||||||
@@ -113,13 +137,57 @@ Variants {
|
|||||||
return getBarHeight(leftBar);
|
return getBarHeight(leftBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real dockMargin: SettingsData.dockSpacing
|
readonly property real dockMargin: SettingsData.dockMargin
|
||||||
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin
|
readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled
|
||||||
|
readonly property real effectiveDockBottomGap: Theme.isConnectedEffect ? 0 : SettingsData.dockBottomGap
|
||||||
|
readonly property real effectiveDockMargin: Theme.isConnectedEffect ? 0 : SettingsData.dockMargin
|
||||||
|
readonly property real positionSpacing: barSpacing + effectiveDockBottomGap + effectiveDockMargin
|
||||||
|
readonly property real joinedEdgeMargin: Theme.isConnectedEffect ? 0 : (barSpacing + effectiveDockMargin + 1 + dock.borderThickness)
|
||||||
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
|
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
|
||||||
function px(v) {
|
function px(v) {
|
||||||
return Math.round(v * _dpr) / _dpr;
|
return Math.round(v * _dpr) / _dpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function connectorWidth(spacing) {
|
||||||
|
return dock.isVertical ? (spacing + Theme.connectedCornerRadius) : Theme.connectedCornerRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorHeight(spacing) {
|
||||||
|
return dock.isVertical ? Theme.connectedCornerRadius : (spacing + Theme.connectedCornerRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorSeamX(baseX, bodyWidth, placement) {
|
||||||
|
if (!dock.isVertical)
|
||||||
|
return placement === "left" ? baseX : baseX + bodyWidth;
|
||||||
|
return SettingsData.dockPosition === SettingsData.Position.Left ? baseX : baseX + bodyWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorSeamY(baseY, bodyHeight, placement) {
|
||||||
|
if (SettingsData.dockPosition === SettingsData.Position.Top)
|
||||||
|
return baseY;
|
||||||
|
if (SettingsData.dockPosition === SettingsData.Position.Bottom)
|
||||||
|
return baseY + bodyHeight;
|
||||||
|
return placement === "left" ? baseY : baseY + bodyHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorX(baseX, bodyWidth, placement, spacing) {
|
||||||
|
const seamX = connectorSeamX(baseX, bodyWidth, placement);
|
||||||
|
const width = connectorWidth(spacing);
|
||||||
|
if (!dock.isVertical)
|
||||||
|
return placement === "left" ? seamX - width : seamX;
|
||||||
|
return SettingsData.dockPosition === SettingsData.Position.Left ? seamX : seamX - width;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorY(baseY, bodyHeight, placement, spacing) {
|
||||||
|
const seamY = connectorSeamY(baseY, bodyHeight, placement);
|
||||||
|
const height = connectorHeight(spacing);
|
||||||
|
if (SettingsData.dockPosition === SettingsData.Position.Top)
|
||||||
|
return seamY;
|
||||||
|
if (SettingsData.dockPosition === SettingsData.Position.Bottom)
|
||||||
|
return seamY - height;
|
||||||
|
return placement === "left" ? seamY - height : seamY;
|
||||||
|
}
|
||||||
|
|
||||||
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
|
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
|
||||||
property bool revealSticky: false
|
property bool revealSticky: false
|
||||||
|
|
||||||
@@ -130,7 +198,7 @@ Variants {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const screenName = dock.modelData?.name ?? "";
|
const screenName = dock.modelData?.name ?? "";
|
||||||
const dockThickness = effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin;
|
const dockThickness = dock.connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin;
|
||||||
const screenWidth = dock.screen?.width ?? 0;
|
const screenWidth = dock.screen?.width ?? 0;
|
||||||
const screenHeight = dock.screen?.height ?? 0;
|
const screenHeight = dock.screen?.height ?? 0;
|
||||||
|
|
||||||
@@ -302,13 +370,13 @@ Variants {
|
|||||||
return -1;
|
return -1;
|
||||||
if (barSpacing > 0)
|
if (barSpacing > 0)
|
||||||
return -1;
|
return -1;
|
||||||
return px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin);
|
return px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockBottomGap + effectiveDockMargin);
|
||||||
}
|
}
|
||||||
|
|
||||||
property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35)
|
property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35)
|
||||||
|
|
||||||
implicitWidth: isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
|
implicitWidth: isVertical ? (px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
|
||||||
implicitHeight: !isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
|
implicitHeight: !isVertical ? (px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: maskItem
|
id: maskItem
|
||||||
@@ -318,17 +386,17 @@ Variants {
|
|||||||
x: {
|
x: {
|
||||||
const baseX = dockCore.x + dockMouseArea.x;
|
const baseX = dockCore.x + dockMouseArea.x;
|
||||||
if (isVertical && SettingsData.dockPosition === SettingsData.Position.Right)
|
if (isVertical && SettingsData.dockPosition === SettingsData.Position.Right)
|
||||||
return baseX - (expanded ? animationHeadroom + borderThickness : 0);
|
return baseX - (expanded ? animationHeadroom + borderThickness + dock.horizontalConnectorExtent : 0);
|
||||||
return baseX - (expanded ? borderThickness : 0);
|
return baseX - (expanded ? borderThickness + dock.horizontalConnectorExtent : 0);
|
||||||
}
|
}
|
||||||
y: {
|
y: {
|
||||||
const baseY = dockCore.y + dockMouseArea.y;
|
const baseY = dockCore.y + dockMouseArea.y;
|
||||||
if (!isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom)
|
if (!isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom)
|
||||||
return baseY - (expanded ? animationHeadroom + borderThickness : 0);
|
return baseY - (expanded ? animationHeadroom + borderThickness + dock.verticalConnectorExtent : 0);
|
||||||
return baseY - (expanded ? borderThickness : 0);
|
return baseY - (expanded ? borderThickness + dock.verticalConnectorExtent : 0);
|
||||||
}
|
}
|
||||||
width: dockMouseArea.width + (isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 : 0)
|
width: dockMouseArea.width + (isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 + dock.horizontalConnectorExtent * 2 : 0)
|
||||||
height: dockMouseArea.height + (!isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 : 0)
|
height: dockMouseArea.height + (!isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 + dock.verticalConnectorExtent * 2 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
mask: Region {
|
mask: Region {
|
||||||
@@ -388,7 +456,7 @@ Variants {
|
|||||||
const screenHeight = dock.screen ? dock.screen.height : 0;
|
const screenHeight = dock.screen ? dock.screen.height : 0;
|
||||||
|
|
||||||
const gap = Theme.spacingS;
|
const gap = Theme.spacingS;
|
||||||
const bgMargin = barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness;
|
const bgMargin = dock.joinedEdgeMargin + dock.connectedJoinInset;
|
||||||
const btnW = dock.hoveredButton.width;
|
const btnW = dock.hoveredButton.width;
|
||||||
const btnH = dock.hoveredButton.height;
|
const btnH = dock.hoveredButton.height;
|
||||||
|
|
||||||
@@ -459,11 +527,11 @@ Variants {
|
|||||||
// Keep the taller hit area regardless of the reveal state to prevent shrinking loop
|
// Keep the taller hit area regardless of the reveal state to prevent shrinking loop
|
||||||
return Math.min(Math.max(dockBackground.height + 64, 200), maxDockHeight);
|
return Math.min(Math.max(dockBackground.height + 64, 200), maxDockHeight);
|
||||||
}
|
}
|
||||||
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
|
return dock.reveal ? px(dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin) : 1;
|
||||||
}
|
}
|
||||||
width: {
|
width: {
|
||||||
if (dock.isVertical) {
|
if (dock.isVertical) {
|
||||||
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
|
return dock.reveal ? px(dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin) : 1;
|
||||||
}
|
}
|
||||||
// Keep the wider hit area regardless of the reveal state to prevent shrinking loop
|
// Keep the wider hit area regardless of the reveal state to prevent shrinking loop
|
||||||
return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth);
|
return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth);
|
||||||
@@ -505,7 +573,7 @@ Variants {
|
|||||||
return 0;
|
return 0;
|
||||||
if (dock.reveal)
|
if (dock.reveal)
|
||||||
return 0;
|
return 0;
|
||||||
const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10;
|
const hideDistance = dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin + 10;
|
||||||
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
||||||
return hideDistance;
|
return hideDistance;
|
||||||
} else {
|
} else {
|
||||||
@@ -517,7 +585,7 @@ Variants {
|
|||||||
return 0;
|
return 0;
|
||||||
if (dock.reveal)
|
if (dock.reveal)
|
||||||
return 0;
|
return 0;
|
||||||
const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10;
|
const hideDistance = dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin + 10;
|
||||||
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
|
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
|
||||||
return hideDistance;
|
return hideDistance;
|
||||||
} else {
|
} else {
|
||||||
@@ -528,16 +596,26 @@ Variants {
|
|||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
id: slideXAnimation
|
id: slideXAnimation
|
||||||
duration: Theme.shortDuration
|
duration: Theme.isConnectedEffect
|
||||||
easing.type: Easing.OutCubic
|
? Theme.variantDuration(Theme.popoutAnimationDuration, dock.reveal)
|
||||||
|
: Theme.shortDuration
|
||||||
|
easing.type: Theme.isConnectedEffect ? Easing.BezierSpline : Easing.OutCubic
|
||||||
|
easing.bezierCurve: Theme.isConnectedEffect
|
||||||
|
? (dock.reveal ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve)
|
||||||
|
: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on y {
|
Behavior on y {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
id: slideYAnimation
|
id: slideYAnimation
|
||||||
duration: Theme.shortDuration
|
duration: Theme.isConnectedEffect
|
||||||
easing.type: Easing.OutCubic
|
? Theme.variantDuration(Theme.popoutAnimationDuration, dock.reveal)
|
||||||
|
: Theme.shortDuration
|
||||||
|
easing.type: Theme.isConnectedEffect ? Easing.BezierSpline : Easing.OutCubic
|
||||||
|
easing.bezierCurve: Theme.isConnectedEffect
|
||||||
|
? (dock.reveal ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve)
|
||||||
|
: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -553,47 +631,76 @@ Variants {
|
|||||||
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
|
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
|
||||||
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
||||||
}
|
}
|
||||||
anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
|
anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
|
||||||
anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
|
anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
|
||||||
anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
|
anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
|
||||||
anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
|
anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
|
||||||
|
|
||||||
implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2)
|
implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2)
|
||||||
implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2)
|
implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2)
|
||||||
width: implicitWidth
|
width: implicitWidth
|
||||||
height: implicitHeight
|
height: implicitHeight
|
||||||
|
|
||||||
layer.enabled: true
|
// Avoid an offscreen texture seam where the connected dock meets the frame.
|
||||||
|
layer.enabled: !Theme.isConnectedEffect
|
||||||
clip: false
|
clip: false
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Theme.withAlpha(Theme.surfaceContainer, backgroundTransparency)
|
color: dock.surfaceColor
|
||||||
radius: Theme.cornerRadius
|
topLeftRadius: dock.surfaceTopLeftRadius
|
||||||
|
topRightRadius: dock.surfaceTopRightRadius
|
||||||
|
bottomLeftRadius: dock.surfaceBottomLeftRadius
|
||||||
|
bottomRightRadius: dock.surfaceBottomRightRadius
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
radius: Theme.cornerRadius
|
topLeftRadius: dock.surfaceTopLeftRadius
|
||||||
border.color: BlurService.borderColor
|
topRightRadius: dock.surfaceTopRightRadius
|
||||||
border.width: BlurService.borderWidth
|
bottomLeftRadius: dock.surfaceBottomLeftRadius
|
||||||
|
bottomRightRadius: dock.surfaceBottomRightRadius
|
||||||
|
border.color: dock.surfaceBorderColor
|
||||||
|
border.width: dock.surfaceBorderWidth
|
||||||
z: 100
|
z: 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
visible: Theme.isConnectedEffect && dock.reveal
|
||||||
|
barSide: dock.connectedBarSide
|
||||||
|
placement: "left"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: Theme.connectedCornerRadius
|
||||||
|
color: dock.surfaceColor
|
||||||
|
x: Theme.snap(dock.connectorX(dockBackground.x, dockBackground.width, placement, spacing), dock._dpr)
|
||||||
|
y: Theme.snap(dock.connectorY(dockBackground.y, dockBackground.height, placement, spacing), dock._dpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
visible: Theme.isConnectedEffect && dock.reveal
|
||||||
|
barSide: dock.connectedBarSide
|
||||||
|
placement: "right"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: Theme.connectedCornerRadius
|
||||||
|
color: dock.surfaceColor
|
||||||
|
x: Theme.snap(dock.connectorX(dockBackground.x, dockBackground.width, placement, spacing), dock._dpr)
|
||||||
|
y: Theme.snap(dock.connectorY(dockBackground.y, dockBackground.height, placement, spacing), dock._dpr)
|
||||||
|
}
|
||||||
|
|
||||||
Shape {
|
Shape {
|
||||||
id: dockBorderShape
|
id: dockBorderShape
|
||||||
x: dockBackground.x - borderThickness
|
x: dockBackground.x - borderThickness
|
||||||
y: dockBackground.y - borderThickness
|
y: dockBackground.y - borderThickness
|
||||||
width: dockBackground.width + borderThickness * 2
|
width: dockBackground.width + borderThickness * 2
|
||||||
height: dockBackground.height + borderThickness * 2
|
height: dockBackground.height + borderThickness * 2
|
||||||
visible: SettingsData.dockBorderEnabled && dock.hasApps
|
visible: SettingsData.dockBorderEnabled && dock.hasApps && !Theme.isConnectedEffect
|
||||||
preferredRendererType: Shape.CurveRenderer
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
||||||
readonly property real borderThickness: Math.max(1, dock.borderThickness)
|
readonly property real borderThickness: Math.max(1, dock.borderThickness)
|
||||||
readonly property real i: borderThickness / 2
|
readonly property real i: borderThickness / 2
|
||||||
readonly property real cr: Theme.cornerRadius
|
readonly property real cr: dock.surfaceRadius
|
||||||
readonly property real w: dockBackground.width
|
readonly property real w: dockBackground.width
|
||||||
readonly property real h: dockBackground.height
|
readonly property real h: dockBackground.height
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import qs.Modules.Settings.Widgets
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
readonly property bool connectedFrameModeActive: SettingsData.frameEnabled
|
||||||
|
&& SettingsData.motionEffect === 1
|
||||||
|
&& SettingsData.directionalAnimationMode === 3
|
||||||
|
|
||||||
FileBrowserModal {
|
FileBrowserModal {
|
||||||
id: dockLogoFileBrowser
|
id: dockLogoFileBrowser
|
||||||
@@ -544,6 +547,8 @@ Item {
|
|||||||
|
|
||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
text: I18n.tr("Exclusive Zone Offset")
|
text: I18n.tr("Exclusive Zone Offset")
|
||||||
|
enabled: !root.connectedFrameModeActive
|
||||||
|
opacity: root.connectedFrameModeActive ? 0.5 : 1.0
|
||||||
value: SettingsData.dockBottomGap
|
value: SettingsData.dockBottomGap
|
||||||
minimum: -100
|
minimum: -100
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -553,6 +558,8 @@ Item {
|
|||||||
|
|
||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
text: I18n.tr("Margin")
|
text: I18n.tr("Margin")
|
||||||
|
enabled: !root.connectedFrameModeActive
|
||||||
|
opacity: root.connectedFrameModeActive ? 0.5 : 1.0
|
||||||
value: SettingsData.dockMargin
|
value: SettingsData.dockMargin
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -561,11 +568,42 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
visible: root.connectedFrameModeActive
|
||||||
|
width: parent.width
|
||||||
|
implicitHeight: dockConnectedNote.implicitHeight + Theme.spacingS * 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: dockConnectedNote
|
||||||
|
x: Theme.spacingM
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "frame_source"
|
||||||
|
size: Theme.fontSizeMedium
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Connected Frame mode manages dock edge offset, transparency, blur, and border styling")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width - Theme.fontSizeMedium - Theme.spacingS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "opacity"
|
iconName: "opacity"
|
||||||
title: I18n.tr("Transparency")
|
title: I18n.tr("Transparency")
|
||||||
settingKey: "dockTransparency"
|
settingKey: "dockTransparency"
|
||||||
|
enabled: !root.connectedFrameModeActive
|
||||||
|
opacity: root.connectedFrameModeActive ? 0.5 : 1.0
|
||||||
|
|
||||||
SettingsSliderRow {
|
SettingsSliderRow {
|
||||||
text: I18n.tr("Dock Transparency")
|
text: I18n.tr("Dock Transparency")
|
||||||
@@ -585,6 +623,8 @@ Item {
|
|||||||
settingKey: "dockBorder"
|
settingKey: "dockBorder"
|
||||||
collapsible: true
|
collapsible: true
|
||||||
expanded: false
|
expanded: false
|
||||||
|
enabled: !root.connectedFrameModeActive
|
||||||
|
opacity: root.connectedFrameModeActive ? 0.5 : 1.0
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
text: I18n.tr("Border")
|
text: I18n.tr("Border")
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ Item {
|
|||||||
title: I18n.tr("Bar Integration")
|
title: I18n.tr("Bar Integration")
|
||||||
settingKey: "frameBarIntegration"
|
settingKey: "frameBarIntegration"
|
||||||
collapsible: true
|
collapsible: true
|
||||||
expanded: false
|
expanded: true
|
||||||
visible: SettingsData.frameEnabled
|
visible: SettingsData.frameEnabled
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
@@ -273,6 +273,31 @@ Item {
|
|||||||
checked: SettingsData.frameShowOnOverview
|
checked: SettingsData.frameShowOnOverview
|
||||||
onToggled: checked => SettingsData.set("frameShowOnOverview", checked)
|
onToggled: checked => SettingsData.set("frameShowOnOverview", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
visible: SettingsData.frameEnabled
|
||||||
|
settingKey: "directionalAnimationMode"
|
||||||
|
tags: ["frame", "connected", "popout", "corner", "animation"]
|
||||||
|
text: I18n.tr("Connected Mode")
|
||||||
|
description: I18n.tr("Popouts emerge flush from the bar edge as one continuous piece (based on Slide)")
|
||||||
|
checked: SettingsData.motionEffect === 1 && SettingsData.directionalAnimationMode === 3
|
||||||
|
onToggled: checked => {
|
||||||
|
if (checked) {
|
||||||
|
if (SettingsData.directionalAnimationMode !== 3)
|
||||||
|
SettingsData.set("previousDirectionalMode", SettingsData.directionalAnimationMode);
|
||||||
|
SettingsData.set("motionEffect", 1);
|
||||||
|
SettingsData.set("directionalAnimationMode", 3);
|
||||||
|
} else {
|
||||||
|
SettingsData.set("directionalAnimationMode", SettingsData.previousDirectionalMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onDirectionalAnimationModeChanged() {}
|
||||||
|
function onMotionEffectChanged() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Display Assignment ────────────────────────────────────────────
|
// ── Display Assignment ────────────────────────────────────────────
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import qs.Modules.Settings.Widgets
|
|||||||
Item {
|
Item {
|
||||||
id: themeColorsTab
|
id: themeColorsTab
|
||||||
|
|
||||||
|
readonly property bool connectedFrameModeActive: SettingsData.frameEnabled
|
||||||
|
&& SettingsData.motionEffect === 1
|
||||||
|
&& SettingsData.directionalAnimationMode === 3
|
||||||
property var cachedIconThemes: SettingsData.availableIconThemes
|
property var cachedIconThemes: SettingsData.availableIconThemes
|
||||||
property var cachedCursorThemes: SettingsData.availableCursorThemes
|
property var cachedCursorThemes: SettingsData.availableCursorThemes
|
||||||
property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label)
|
property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label)
|
||||||
@@ -1618,7 +1621,11 @@ Item {
|
|||||||
tags: ["popup", "transparency", "opacity", "modal"]
|
tags: ["popup", "transparency", "opacity", "modal"]
|
||||||
settingKey: "popupTransparency"
|
settingKey: "popupTransparency"
|
||||||
text: I18n.tr("Popup Transparency")
|
text: I18n.tr("Popup Transparency")
|
||||||
description: I18n.tr("Controls opacity of all popouts, modals, and their content layers")
|
description: themeColorsTab.connectedFrameModeActive
|
||||||
|
? I18n.tr("Connected Frame mode follows Frame Opacity for connected popouts, docks, and modal surfaces")
|
||||||
|
: I18n.tr("Controls opacity of all popouts, modals, and their content layers")
|
||||||
|
enabled: !themeColorsTab.connectedFrameModeActive
|
||||||
|
opacity: themeColorsTab.connectedFrameModeActive ? 0.5 : 1.0
|
||||||
value: Math.round(SettingsData.popupTransparency * 100)
|
value: Math.round(SettingsData.popupTransparency * 100)
|
||||||
minimum: 0
|
minimum: 0
|
||||||
maximum: 100
|
maximum: 100
|
||||||
@@ -1837,7 +1844,11 @@ Item {
|
|||||||
tags: ["blur", "background", "transparency", "glass", "frosted"]
|
tags: ["blur", "background", "transparency", "glass", "frosted"]
|
||||||
settingKey: "blurEnabled"
|
settingKey: "blurEnabled"
|
||||||
text: I18n.tr("Background Blur")
|
text: I18n.tr("Background Blur")
|
||||||
description: BlurService.available ? I18n.tr("Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.") : I18n.tr("Requires a newer version of Quickshell")
|
description: !BlurService.available
|
||||||
|
? I18n.tr("Requires a newer version of Quickshell")
|
||||||
|
: (themeColorsTab.connectedFrameModeActive
|
||||||
|
? I18n.tr("Connected Frame mode follows Frame Blur for connected surfaces while this remains the master blur availability toggle")
|
||||||
|
: I18n.tr("Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration."))
|
||||||
checked: SettingsData.blurEnabled ?? false
|
checked: SettingsData.blurEnabled ?? false
|
||||||
enabled: BlurService.available
|
enabled: BlurService.available
|
||||||
onToggled: checked => SettingsData.set("blurEnabled", checked)
|
onToggled: checked => SettingsData.set("blurEnabled", checked)
|
||||||
|
|||||||
@@ -203,17 +203,25 @@ Item {
|
|||||||
SettingsDropdownRow {
|
SettingsDropdownRow {
|
||||||
visible: SettingsData.motionEffect === 1
|
visible: SettingsData.motionEffect === 1
|
||||||
tab: "typography"
|
tab: "typography"
|
||||||
tags: ["animation", "directional", "behavior", "overlap", "sticky", "roll"]
|
tags: ["animation", "directional", "behavior", "overlap", "sticky", "roll", "connected"]
|
||||||
settingKey: "directionalAnimationMode"
|
settingKey: "directionalAnimationMode"
|
||||||
text: I18n.tr("Directional Behavior")
|
text: I18n.tr("Directional Behavior")
|
||||||
description: I18n.tr("How the popout emerges from the DankBar")
|
description: {
|
||||||
options: [I18n.tr("Overlap"), I18n.tr("Slide"), I18n.tr("Roll")]
|
if (SettingsData.directionalAnimationMode === 3 && SettingsData.frameEnabled)
|
||||||
|
return I18n.tr("Popouts emerge flush from the bar edge as a single continuous piece, with corner connectors bridging the junction");
|
||||||
|
return I18n.tr("How the popout emerges from the DankBar");
|
||||||
|
}
|
||||||
|
options: SettingsData.frameEnabled
|
||||||
|
? [I18n.tr("Overlap"), I18n.tr("Slide"), I18n.tr("Roll"), I18n.tr("Connected")]
|
||||||
|
: [I18n.tr("Overlap"), I18n.tr("Slide"), I18n.tr("Roll")]
|
||||||
currentValue: {
|
currentValue: {
|
||||||
switch (SettingsData.directionalAnimationMode) {
|
switch (SettingsData.directionalAnimationMode) {
|
||||||
case 1:
|
case 1:
|
||||||
return I18n.tr("Slide");
|
return I18n.tr("Slide");
|
||||||
case 2:
|
case 2:
|
||||||
return I18n.tr("Roll");
|
return I18n.tr("Roll");
|
||||||
|
case 3:
|
||||||
|
return SettingsData.frameEnabled ? I18n.tr("Connected") : I18n.tr("Slide");
|
||||||
default:
|
default:
|
||||||
return I18n.tr("Overlap");
|
return I18n.tr("Overlap");
|
||||||
}
|
}
|
||||||
@@ -223,7 +231,11 @@ Item {
|
|||||||
SettingsData.set("directionalAnimationMode", 1);
|
SettingsData.set("directionalAnimationMode", 1);
|
||||||
else if (value === I18n.tr("Roll"))
|
else if (value === I18n.tr("Roll"))
|
||||||
SettingsData.set("directionalAnimationMode", 2);
|
SettingsData.set("directionalAnimationMode", 2);
|
||||||
else
|
else if (value === I18n.tr("Connected") && SettingsData.frameEnabled) {
|
||||||
|
if (SettingsData.directionalAnimationMode !== 3)
|
||||||
|
SettingsData.set("previousDirectionalMode", SettingsData.directionalAnimationMode);
|
||||||
|
SettingsData.set("directionalAnimationMode", 3);
|
||||||
|
} else
|
||||||
SettingsData.set("directionalAnimationMode", 0);
|
SettingsData.set("directionalAnimationMode", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
152
quickshell/Widgets/ConnectedCorner.qml
Normal file
152
quickshell/Widgets/ConnectedCorner.qml
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
// ConnectedCorner — Seam-complement connector that fills the void between
|
||||||
|
// a bar's rounded corner and a popout's flush edge, creating a seamless junction.
|
||||||
|
//
|
||||||
|
// Usage: Place as a sibling to contentWrapper inside unrollCounteract (DankPopout)
|
||||||
|
// or as a sibling to dockBackground (Dock). Position using contentWrapper.x/y.
|
||||||
|
//
|
||||||
|
// barSide: "top" | "bottom" | "left" | "right" — which edge the bar is on
|
||||||
|
// placement: "left" | "right" — which lateral end of that edge
|
||||||
|
// spacing: gap between bar surface and popout surface (storedBarSpacing, ~4px)
|
||||||
|
// connectorRadius: bar corner radius to match (frameRounding or Theme.cornerRadius)
|
||||||
|
// color: fill color matching the popout surface
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string barSide: "top"
|
||||||
|
property string placement: "left"
|
||||||
|
property real spacing: 4
|
||||||
|
property real connectorRadius: 12
|
||||||
|
property color color: "transparent"
|
||||||
|
|
||||||
|
readonly property bool isHorizontalBar: barSide === "top" || barSide === "bottom"
|
||||||
|
readonly property bool isPlacementLeft: placement === "left"
|
||||||
|
readonly property string arcCorner: {
|
||||||
|
if (barSide === "top")
|
||||||
|
return isPlacementLeft ? "bottomLeft" : "bottomRight";
|
||||||
|
if (barSide === "bottom")
|
||||||
|
return isPlacementLeft ? "topLeft" : "topRight";
|
||||||
|
if (barSide === "left")
|
||||||
|
return isPlacementLeft ? "topRight" : "bottomRight";
|
||||||
|
return isPlacementLeft ? "topLeft" : "bottomLeft";
|
||||||
|
}
|
||||||
|
readonly property real pathStartX: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "topLeft":
|
||||||
|
return width;
|
||||||
|
case "topRight":
|
||||||
|
case "bottomLeft":
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real pathStartY: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "bottomRight":
|
||||||
|
return height;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real firstLineX: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "topLeft":
|
||||||
|
case "bottomLeft":
|
||||||
|
return width;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real firstLineY: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "topLeft":
|
||||||
|
case "topRight":
|
||||||
|
return height;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real secondLineX: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "topRight":
|
||||||
|
case "bottomLeft":
|
||||||
|
case "bottomRight":
|
||||||
|
return width;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real secondLineY: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "topLeft":
|
||||||
|
case "topRight":
|
||||||
|
case "bottomLeft":
|
||||||
|
return height;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real arcCenterX: arcCorner === "topRight" || arcCorner === "bottomRight" ? width : 0
|
||||||
|
readonly property real arcCenterY: arcCorner === "bottomLeft" || arcCorner === "bottomRight" ? height : 0
|
||||||
|
readonly property real arcStartAngle: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "topLeft":
|
||||||
|
case "topRight":
|
||||||
|
return 90;
|
||||||
|
case "bottomLeft":
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real arcSweepAngle: {
|
||||||
|
switch (arcCorner) {
|
||||||
|
case "topRight":
|
||||||
|
return 90;
|
||||||
|
default:
|
||||||
|
return -90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal bar: connector is tall (bridges vertical gap), narrow (corner radius wide)
|
||||||
|
// Vertical bar: connector is wide (bridges horizontal gap), short (corner radius tall)
|
||||||
|
width: isHorizontalBar ? connectorRadius : (spacing + connectorRadius)
|
||||||
|
height: isHorizontalBar ? (spacing + connectorRadius) : connectorRadius
|
||||||
|
|
||||||
|
Shape {
|
||||||
|
anchors.fill: parent
|
||||||
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
fillColor: root.color
|
||||||
|
strokeColor: "transparent"
|
||||||
|
strokeWidth: 0
|
||||||
|
startX: root.pathStartX
|
||||||
|
startY: root.pathStartY
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
x: root.firstLineX
|
||||||
|
y: root.firstLineY
|
||||||
|
}
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
x: root.secondLineX
|
||||||
|
y: root.secondLineY
|
||||||
|
}
|
||||||
|
|
||||||
|
PathAngleArc {
|
||||||
|
centerX: root.arcCenterX
|
||||||
|
centerY: root.arcCenterY
|
||||||
|
radiusX: root.width
|
||||||
|
radiusY: root.height
|
||||||
|
startAngle: root.arcStartAngle
|
||||||
|
sweepAngle: root.arcSweepAngle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,8 @@ Item {
|
|||||||
property var screen: null
|
property var screen: null
|
||||||
|
|
||||||
readonly property real effectiveBarThickness: {
|
readonly property real effectiveBarThickness: {
|
||||||
|
if (Theme.isConnectedEffect)
|
||||||
|
return Math.max(0, storedBarThickness);
|
||||||
const padding = storedBarConfig ? (storedBarConfig.innerPadding !== undefined ? storedBarConfig.innerPadding : 4) : 4;
|
const padding = storedBarConfig ? (storedBarConfig.innerPadding !== undefined ? storedBarConfig.innerPadding : 4) : 4;
|
||||||
return Math.max(26 + padding * 0.6, Theme.barHeight - 4 - (8 - padding)) + storedBarSpacing;
|
return Math.max(26 + padding * 0.6, Theme.barHeight - 4 - (8 - padding)) + storedBarSpacing;
|
||||||
}
|
}
|
||||||
@@ -68,6 +70,7 @@ Item {
|
|||||||
readonly property real barWidth: barBounds.width
|
readonly property real barWidth: barBounds.width
|
||||||
readonly property real barHeight: barBounds.height
|
readonly property real barHeight: barBounds.height
|
||||||
readonly property real barWingSize: barBounds.wingSize
|
readonly property real barWingSize: barBounds.wingSize
|
||||||
|
readonly property bool effectiveSurfaceBlurEnabled: Theme.connectedSurfaceBlurEnabled
|
||||||
|
|
||||||
signal opened
|
signal opened
|
||||||
signal popoutClosed
|
signal popoutClosed
|
||||||
@@ -254,11 +257,25 @@ Item {
|
|||||||
readonly property real screenWidth: screen ? screen.width : 0
|
readonly property real screenWidth: screen ? screen.width : 0
|
||||||
readonly property real screenHeight: screen ? screen.height : 0
|
readonly property real screenHeight: screen ? screen.height : 0
|
||||||
readonly property real dpr: screen ? screen.devicePixelRatio : 1
|
readonly property real dpr: screen ? screen.devicePixelRatio : 1
|
||||||
|
readonly property real frameInset: {
|
||||||
|
if (!SettingsData.frameEnabled) return 0;
|
||||||
|
const ft = SettingsData.frameThickness;
|
||||||
|
const fr = SettingsData.frameRounding;
|
||||||
|
const ccr = Theme.connectedCornerRadius;
|
||||||
|
if (Theme.isConnectedEffect)
|
||||||
|
return Math.max(ft * 4, ft + ccr * 2);
|
||||||
|
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true;
|
||||||
|
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 6;
|
||||||
|
const gap = useAutoGaps ? Math.max(6, storedBarSpacing) : manualGapValue;
|
||||||
|
return Math.max(ft + gap, fr);
|
||||||
|
}
|
||||||
|
|
||||||
readonly property var shadowLevel: Theme.elevationLevel3
|
readonly property var shadowLevel: Theme.elevationLevel3
|
||||||
readonly property real shadowFallbackOffset: 6
|
readonly property real shadowFallbackOffset: 6
|
||||||
readonly property real shadowRenderPadding: (Theme.elevationEnabled && SettingsData.popoutElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, effectiveShadowDirection, shadowFallbackOffset, 8, 16) : 0
|
readonly property real shadowRenderPadding: (Theme.elevationEnabled && SettingsData.popoutElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, effectiveShadowDirection, shadowFallbackOffset, 8, 16) : 0
|
||||||
readonly property real shadowMotionPadding: {
|
readonly property real shadowMotionPadding: {
|
||||||
|
if (Theme.isConnectedEffect)
|
||||||
|
return Math.max(storedBarSpacing + Theme.connectedCornerRadius + 4, 40);
|
||||||
if (Theme.isDirectionalEffect) {
|
if (Theme.isDirectionalEffect) {
|
||||||
if (typeof SettingsData !== "undefined" && SettingsData.directionalAnimationMode !== 0)
|
if (typeof SettingsData !== "undefined" && SettingsData.directionalAnimationMode !== 0)
|
||||||
return 16; // Slide Behind and Roll Out do not add animationOffset, enabling strict Wayland clipping.
|
return 16; // Slide Behind and Roll Out do not add animationOffset, enabling strict Wayland clipping.
|
||||||
@@ -271,6 +288,40 @@ Item {
|
|||||||
readonly property real shadowBuffer: Theme.snap(shadowRenderPadding + shadowMotionPadding, dpr)
|
readonly property real shadowBuffer: Theme.snap(shadowRenderPadding + shadowMotionPadding, dpr)
|
||||||
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
|
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
|
||||||
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
|
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
|
||||||
|
readonly property real connectedAnchorX: {
|
||||||
|
if (!Theme.isConnectedEffect)
|
||||||
|
return triggerX;
|
||||||
|
switch (effectiveBarPosition) {
|
||||||
|
case SettingsData.Position.Left:
|
||||||
|
return barX + barWidth;
|
||||||
|
case SettingsData.Position.Right:
|
||||||
|
return barX;
|
||||||
|
default:
|
||||||
|
return triggerX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readonly property real connectedAnchorY: {
|
||||||
|
if (!Theme.isConnectedEffect)
|
||||||
|
return triggerY;
|
||||||
|
switch (effectiveBarPosition) {
|
||||||
|
case SettingsData.Position.Top:
|
||||||
|
return barY + barHeight;
|
||||||
|
case SettingsData.Position.Bottom:
|
||||||
|
return barY;
|
||||||
|
default:
|
||||||
|
return triggerY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function adjacentBarClearance(exclusion) {
|
||||||
|
if (exclusion <= 0)
|
||||||
|
return 0;
|
||||||
|
if (!Theme.isConnectedEffect)
|
||||||
|
return exclusion;
|
||||||
|
// In a shared frame corner, the adjacent connected bar already occupies
|
||||||
|
// one rounded-corner radius before the popout's own connector begins.
|
||||||
|
return exclusion + Theme.connectedCornerRadius * 2;
|
||||||
|
}
|
||||||
|
|
||||||
onAlignedHeightChanged: {
|
onAlignedHeightChanged: {
|
||||||
if (!suspendShadowWhileResizing || !shouldBeVisible)
|
if (!suspendShadowWhileResizing || !shouldBeVisible)
|
||||||
@@ -295,17 +346,22 @@ Item {
|
|||||||
readonly property real alignedX: Theme.snap((() => {
|
readonly property real alignedX: Theme.snap((() => {
|
||||||
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true;
|
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true;
|
||||||
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4;
|
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4;
|
||||||
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue;
|
const rawPopupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue;
|
||||||
|
const popupGap = Theme.isConnectedEffect ? 0 : rawPopupGap;
|
||||||
|
const edgeGap = Math.max(popupGap, frameInset);
|
||||||
|
const anchorX = Theme.isConnectedEffect ? connectedAnchorX : triggerX;
|
||||||
|
|
||||||
switch (effectiveBarPosition) {
|
switch (effectiveBarPosition) {
|
||||||
case SettingsData.Position.Left:
|
case SettingsData.Position.Left:
|
||||||
return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, triggerX));
|
// bar on left: left side is bar-adjacent (popupGap), right side is frame-perpendicular (edgeGap)
|
||||||
|
return Math.max(popupGap, Math.min(screenWidth - popupWidth - edgeGap, anchorX));
|
||||||
case SettingsData.Position.Right:
|
case SettingsData.Position.Right:
|
||||||
return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, triggerX - popupWidth));
|
// bar on right: right side is bar-adjacent (popupGap), left side is frame-perpendicular (edgeGap)
|
||||||
|
return Math.max(edgeGap, Math.min(screenWidth - popupWidth - popupGap, anchorX - popupWidth));
|
||||||
default:
|
default:
|
||||||
const rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2);
|
const rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2);
|
||||||
const minX = adjacentBarInfo.leftBar > 0 ? adjacentBarInfo.leftBar : popupGap;
|
const minX = Math.max(edgeGap, adjacentBarClearance(adjacentBarInfo.leftBar));
|
||||||
const maxX = screenWidth - popupWidth - (adjacentBarInfo.rightBar > 0 ? adjacentBarInfo.rightBar : popupGap);
|
const maxX = screenWidth - popupWidth - Math.max(edgeGap, adjacentBarClearance(adjacentBarInfo.rightBar));
|
||||||
return Math.max(minX, Math.min(maxX, rawX));
|
return Math.max(minX, Math.min(maxX, rawX));
|
||||||
}
|
}
|
||||||
})(), dpr)
|
})(), dpr)
|
||||||
@@ -313,17 +369,22 @@ Item {
|
|||||||
readonly property real alignedY: Theme.snap((() => {
|
readonly property real alignedY: Theme.snap((() => {
|
||||||
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true;
|
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true;
|
||||||
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4;
|
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4;
|
||||||
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue;
|
const rawPopupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue;
|
||||||
|
const popupGap = Theme.isConnectedEffect ? 0 : rawPopupGap;
|
||||||
|
const edgeGap = Math.max(popupGap, frameInset);
|
||||||
|
const anchorY = Theme.isConnectedEffect ? connectedAnchorY : triggerY;
|
||||||
|
|
||||||
switch (effectiveBarPosition) {
|
switch (effectiveBarPosition) {
|
||||||
case SettingsData.Position.Bottom:
|
case SettingsData.Position.Bottom:
|
||||||
return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, triggerY - popupHeight));
|
// bar on bottom: bottom side is bar-adjacent (popupGap), top side is frame-perpendicular (edgeGap)
|
||||||
|
return Math.max(edgeGap, Math.min(screenHeight - popupHeight - popupGap, anchorY - popupHeight));
|
||||||
case SettingsData.Position.Top:
|
case SettingsData.Position.Top:
|
||||||
return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, triggerY));
|
// bar on top: top side is bar-adjacent (popupGap), bottom side is frame-perpendicular (edgeGap)
|
||||||
|
return Math.max(popupGap, Math.min(screenHeight - popupHeight - edgeGap, anchorY));
|
||||||
default:
|
default:
|
||||||
const rawY = triggerY - (popupHeight / 2);
|
const rawY = triggerY - (popupHeight / 2);
|
||||||
const minY = adjacentBarInfo.topBar > 0 ? adjacentBarInfo.topBar : popupGap;
|
const minY = Math.max(edgeGap, adjacentBarClearance(adjacentBarInfo.topBar));
|
||||||
const maxY = screenHeight - popupHeight - (adjacentBarInfo.bottomBar > 0 ? adjacentBarInfo.bottomBar : popupGap);
|
const maxY = screenHeight - popupHeight - Math.max(edgeGap, adjacentBarClearance(adjacentBarInfo.bottomBar));
|
||||||
return Math.max(minY, Math.min(maxY, rawY));
|
return Math.max(minY, Math.min(maxY, rawY));
|
||||||
}
|
}
|
||||||
})(), dpr)
|
})(), dpr)
|
||||||
@@ -472,6 +533,18 @@ Item {
|
|||||||
visible: false
|
visible: false
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
WindowBlur {
|
||||||
|
id: popoutBlur
|
||||||
|
targetWindow: contentWindow
|
||||||
|
blurEnabled: root.effectiveSurfaceBlurEnabled
|
||||||
|
readonly property real s: Math.min(1, contentContainer.scaleValue)
|
||||||
|
blurX: contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr) - contentContainer.horizontalConnectorExtent * s
|
||||||
|
blurY: contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr) - contentContainer.verticalConnectorExtent * s
|
||||||
|
blurWidth: (shouldBeVisible && contentWrapper.opacity > 0) ? (contentContainer.width + contentContainer.horizontalConnectorExtent * 2) * s : 0
|
||||||
|
blurHeight: (shouldBeVisible && contentWrapper.opacity > 0) ? (contentContainer.height + contentContainer.verticalConnectorExtent * 2) * s : 0
|
||||||
|
blurRadius: Theme.connectedSurfaceRadius
|
||||||
|
}
|
||||||
|
|
||||||
WlrLayershell.namespace: root.layerNamespace
|
WlrLayershell.namespace: root.layerNamespace
|
||||||
WlrLayershell.layer: {
|
WlrLayershell.layer: {
|
||||||
switch (Quickshell.env("DMS_POPOUT_LAYER")) {
|
switch (Quickshell.env("DMS_POPOUT_LAYER")) {
|
||||||
@@ -524,10 +597,10 @@ Item {
|
|||||||
Item {
|
Item {
|
||||||
id: contentMaskRect
|
id: contentMaskRect
|
||||||
visible: false
|
visible: false
|
||||||
x: contentContainer.x
|
x: contentContainer.x - contentContainer.horizontalConnectorExtent
|
||||||
y: contentContainer.y
|
y: contentContainer.y - contentContainer.verticalConnectorExtent
|
||||||
width: root.alignedWidth
|
width: root.alignedWidth + contentContainer.horizontalConnectorExtent * 2
|
||||||
height: root.alignedHeight
|
height: root.alignedHeight + contentContainer.verticalConnectorExtent * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -556,12 +629,66 @@ Item {
|
|||||||
readonly property bool barBottom: effectiveBarPosition === SettingsData.Position.Bottom
|
readonly property bool barBottom: effectiveBarPosition === SettingsData.Position.Bottom
|
||||||
readonly property bool barLeft: effectiveBarPosition === SettingsData.Position.Left
|
readonly property bool barLeft: effectiveBarPosition === SettingsData.Position.Left
|
||||||
readonly property bool barRight: effectiveBarPosition === SettingsData.Position.Right
|
readonly property bool barRight: effectiveBarPosition === SettingsData.Position.Right
|
||||||
|
readonly property string connectedBarSide: barTop ? "top" : (barBottom ? "bottom" : (barLeft ? "left" : "right"))
|
||||||
|
readonly property real surfaceRadius: Theme.connectedSurfaceRadius
|
||||||
|
readonly property color surfaceColor: Theme.popupLayerColor(Theme.surfaceContainer)
|
||||||
|
readonly property color surfaceBorderColor: Theme.isConnectedEffect
|
||||||
|
? "transparent"
|
||||||
|
: (BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium)
|
||||||
|
readonly property real surfaceBorderWidth: Theme.isConnectedEffect ? 0 : BlurService.borderWidth
|
||||||
|
readonly property real surfaceTopLeftRadius: Theme.isConnectedEffect && (barTop || barLeft) ? 0 : surfaceRadius
|
||||||
|
readonly property real surfaceTopRightRadius: Theme.isConnectedEffect && (barTop || barRight) ? 0 : surfaceRadius
|
||||||
|
readonly property real surfaceBottomLeftRadius: Theme.isConnectedEffect && (barBottom || barLeft) ? 0 : surfaceRadius
|
||||||
|
readonly property real surfaceBottomRightRadius: Theme.isConnectedEffect && (barBottom || barRight) ? 0 : surfaceRadius
|
||||||
readonly property bool directionalEffect: Theme.isDirectionalEffect
|
readonly property bool directionalEffect: Theme.isDirectionalEffect
|
||||||
readonly property bool depthEffect: Theme.isDepthEffect
|
readonly property bool depthEffect: Theme.isDepthEffect
|
||||||
readonly property real directionalTravelX: Math.max(root.animationOffset, root.alignedWidth + Theme.spacingL)
|
readonly property real directionalTravelX: Math.max(root.animationOffset, root.alignedWidth + Theme.spacingL)
|
||||||
readonly property real directionalTravelY: Math.max(root.animationOffset, root.alignedHeight + Theme.spacingL)
|
readonly property real directionalTravelY: Math.max(root.animationOffset, root.alignedHeight + Theme.spacingL)
|
||||||
readonly property real depthTravel: Math.max(root.animationOffset * 0.7, 28)
|
readonly property real depthTravel: Math.max(root.animationOffset * 0.7, 28)
|
||||||
readonly property real sectionTilt: (triggerSection === "left" ? -1 : (triggerSection === "right" ? 1 : 0))
|
readonly property real sectionTilt: (triggerSection === "left" ? -1 : (triggerSection === "right" ? 1 : 0))
|
||||||
|
readonly property real horizontalConnectorExtent: Theme.isConnectedEffect && (barTop || barBottom) ? Theme.connectedCornerRadius : 0
|
||||||
|
readonly property real verticalConnectorExtent: Theme.isConnectedEffect && (barLeft || barRight) ? Theme.connectedCornerRadius : 0
|
||||||
|
|
||||||
|
function connectorWidth(spacing) {
|
||||||
|
return (barTop || barBottom) ? Theme.connectedCornerRadius : (spacing + Theme.connectedCornerRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorHeight(spacing) {
|
||||||
|
return (barTop || barBottom) ? (spacing + Theme.connectedCornerRadius) : Theme.connectedCornerRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorSeamX(baseX, bodyWidth, placement) {
|
||||||
|
if (barTop || barBottom)
|
||||||
|
return placement === "left" ? baseX : baseX + bodyWidth;
|
||||||
|
return barLeft ? baseX : baseX + bodyWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorSeamY(baseY, bodyHeight, placement) {
|
||||||
|
if (barTop)
|
||||||
|
return baseY;
|
||||||
|
if (barBottom)
|
||||||
|
return baseY + bodyHeight;
|
||||||
|
return placement === "left" ? baseY : baseY + bodyHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorX(baseX, bodyWidth, placement, spacing) {
|
||||||
|
const seamX = connectorSeamX(baseX, bodyWidth, placement);
|
||||||
|
const width = connectorWidth(spacing);
|
||||||
|
if (barTop || barBottom)
|
||||||
|
return placement === "left" ? seamX - width : seamX;
|
||||||
|
return barLeft ? seamX : seamX - width;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorY(baseY, bodyHeight, placement, spacing) {
|
||||||
|
const seamY = connectorSeamY(baseY, bodyHeight, placement);
|
||||||
|
const height = connectorHeight(spacing);
|
||||||
|
if (barTop)
|
||||||
|
return seamY;
|
||||||
|
if (barBottom)
|
||||||
|
return seamY - height;
|
||||||
|
return placement === "left" ? seamY - height : seamY;
|
||||||
|
}
|
||||||
|
|
||||||
readonly property real offsetX: {
|
readonly property real offsetX: {
|
||||||
if (directionalEffect) {
|
if (directionalEffect) {
|
||||||
if (typeof SettingsData !== "undefined" && SettingsData.directionalAnimationMode === 2)
|
if (typeof SettingsData !== "undefined" && SettingsData.directionalAnimationMode === 2)
|
||||||
@@ -663,17 +790,38 @@ Item {
|
|||||||
Item {
|
Item {
|
||||||
id: directionalClipMask
|
id: directionalClipMask
|
||||||
|
|
||||||
readonly property bool shouldClip: typeof SettingsData !== "undefined" && SettingsData.directionalAnimationMode > 0 && Theme.isDirectionalEffect
|
readonly property bool shouldClip: Theme.isDirectionalEffect
|
||||||
|
&& typeof SettingsData !== "undefined"
|
||||||
|
&& SettingsData.directionalAnimationMode > 0
|
||||||
readonly property real clipOversize: 1000
|
readonly property real clipOversize: 1000
|
||||||
|
readonly property real connectedClipAllowance: Theme.isConnectedEffect
|
||||||
|
? Math.ceil(root.shadowRenderPadding + BlurService.borderWidth + 2)
|
||||||
|
: 0
|
||||||
|
|
||||||
clip: shouldClip
|
clip: shouldClip
|
||||||
|
|
||||||
// Bound the clipping strictly to the bar side, allowing massive overflow on the other 3 sides for shadows
|
// Bound the clipping strictly to the bar side, allowing massive overflow on the other 3 sides for shadows
|
||||||
x: shouldClip ? (contentContainer.barRight ? -clipOversize : (contentContainer.barLeft ? 0 : -clipOversize)) : 0
|
x: shouldClip ? (contentContainer.barLeft ? -connectedClipAllowance : -clipOversize) : 0
|
||||||
y: shouldClip ? (contentContainer.barBottom ? -clipOversize : (contentContainer.barTop ? 0 : -clipOversize)) : 0
|
y: shouldClip ? (contentContainer.barTop ? -connectedClipAllowance : -clipOversize) : 0
|
||||||
|
|
||||||
width: shouldClip ? parent.width + clipOversize + (contentContainer.barLeft || contentContainer.barRight ? 0 : clipOversize) : parent.width
|
width: {
|
||||||
height: shouldClip ? parent.height + clipOversize + (contentContainer.barTop || contentContainer.barBottom ? 0 : clipOversize) : parent.height
|
if (!shouldClip)
|
||||||
|
return parent.width;
|
||||||
|
if (contentContainer.barLeft)
|
||||||
|
return parent.width + connectedClipAllowance + clipOversize;
|
||||||
|
if (contentContainer.barRight)
|
||||||
|
return parent.width + clipOversize + connectedClipAllowance;
|
||||||
|
return parent.width + clipOversize * 2;
|
||||||
|
}
|
||||||
|
height: {
|
||||||
|
if (!shouldClip)
|
||||||
|
return parent.height;
|
||||||
|
if (contentContainer.barTop)
|
||||||
|
return parent.height + connectedClipAllowance + clipOversize;
|
||||||
|
if (contentContainer.barBottom)
|
||||||
|
return parent.height + clipOversize + connectedClipAllowance;
|
||||||
|
return parent.height + clipOversize * 2;
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: aligner
|
id: aligner
|
||||||
@@ -697,18 +845,75 @@ Item {
|
|||||||
|
|
||||||
ElevationShadow {
|
ElevationShadow {
|
||||||
id: shadowSource
|
id: shadowSource
|
||||||
width: parent.width
|
readonly property real connectorExtent: Theme.isConnectedEffect ? Theme.connectedCornerRadius : 0
|
||||||
height: parent.height
|
readonly property real extraLeft: Theme.isConnectedEffect && (contentContainer.barTop || contentContainer.barBottom) ? connectorExtent : 0
|
||||||
|
readonly property real extraRight: Theme.isConnectedEffect && (contentContainer.barTop || contentContainer.barBottom) ? connectorExtent : 0
|
||||||
|
readonly property real extraTop: Theme.isConnectedEffect && (contentContainer.barLeft || contentContainer.barRight) ? connectorExtent : 0
|
||||||
|
readonly property real extraBottom: Theme.isConnectedEffect && (contentContainer.barLeft || contentContainer.barRight) ? connectorExtent : 0
|
||||||
|
readonly property real bodyX: extraLeft
|
||||||
|
readonly property real bodyY: extraTop
|
||||||
|
readonly property real bodyWidth: parent.width
|
||||||
|
readonly property real bodyHeight: parent.height
|
||||||
|
|
||||||
|
width: parent.width + extraLeft + extraRight
|
||||||
|
height: parent.height + extraTop + extraBottom
|
||||||
opacity: contentWrapper.opacity
|
opacity: contentWrapper.opacity
|
||||||
scale: contentWrapper.scale
|
scale: contentWrapper.scale
|
||||||
x: contentWrapper.x
|
x: contentWrapper.x - extraLeft
|
||||||
y: contentWrapper.y
|
y: contentWrapper.y - extraTop
|
||||||
level: root.shadowLevel
|
level: root.shadowLevel
|
||||||
direction: root.effectiveShadowDirection
|
direction: root.effectiveShadowDirection
|
||||||
fallbackOffset: root.shadowFallbackOffset
|
fallbackOffset: root.shadowFallbackOffset
|
||||||
targetRadius: Theme.cornerRadius
|
targetRadius: contentContainer.surfaceRadius
|
||||||
targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
topLeftRadius: contentContainer.surfaceTopLeftRadius
|
||||||
|
topRightRadius: contentContainer.surfaceTopRightRadius
|
||||||
|
bottomLeftRadius: contentContainer.surfaceBottomLeftRadius
|
||||||
|
bottomRightRadius: contentContainer.surfaceBottomRightRadius
|
||||||
|
targetColor: contentContainer.surfaceColor
|
||||||
|
borderColor: contentContainer.surfaceBorderColor
|
||||||
|
borderWidth: contentContainer.surfaceBorderWidth
|
||||||
|
useCustomSource: Theme.isConnectedEffect
|
||||||
shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive)
|
shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive)
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: Theme.isConnectedEffect
|
||||||
|
clip: false
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
x: shadowSource.bodyX
|
||||||
|
y: shadowSource.bodyY
|
||||||
|
width: shadowSource.bodyWidth
|
||||||
|
height: shadowSource.bodyHeight
|
||||||
|
topLeftRadius: contentContainer.surfaceTopLeftRadius
|
||||||
|
topRightRadius: contentContainer.surfaceTopRightRadius
|
||||||
|
bottomLeftRadius: contentContainer.surfaceBottomLeftRadius
|
||||||
|
bottomRightRadius: contentContainer.surfaceBottomRightRadius
|
||||||
|
color: contentContainer.surfaceColor
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
visible: Theme.isConnectedEffect
|
||||||
|
barSide: contentContainer.connectedBarSide
|
||||||
|
placement: "left"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: Theme.connectedCornerRadius
|
||||||
|
color: contentContainer.surfaceColor
|
||||||
|
x: Theme.snap(contentContainer.connectorX(shadowSource.bodyX, shadowSource.bodyWidth, placement, spacing), root.dpr)
|
||||||
|
y: Theme.snap(contentContainer.connectorY(shadowSource.bodyY, shadowSource.bodyHeight, placement, spacing), root.dpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
visible: Theme.isConnectedEffect
|
||||||
|
barSide: contentContainer.connectedBarSide
|
||||||
|
placement: "right"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: Theme.connectedCornerRadius
|
||||||
|
color: contentContainer.surfaceColor
|
||||||
|
x: Theme.snap(contentContainer.connectorX(shadowSource.bodyX, shadowSource.bodyWidth, placement, spacing), root.dpr)
|
||||||
|
y: Theme.snap(contentContainer.connectorY(shadowSource.bodyY, shadowSource.bodyHeight, placement, spacing), root.dpr)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -735,12 +940,43 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
radius: Theme.cornerRadius
|
clip: false
|
||||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
visible: !Theme.isConnectedEffect
|
||||||
border.color: Theme.outlineMedium
|
|
||||||
border.width: 0
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
topLeftRadius: contentContainer.surfaceTopLeftRadius
|
||||||
|
topRightRadius: contentContainer.surfaceTopRightRadius
|
||||||
|
bottomLeftRadius: contentContainer.surfaceBottomLeftRadius
|
||||||
|
bottomRightRadius: contentContainer.surfaceBottomRightRadius
|
||||||
|
color: contentContainer.surfaceColor
|
||||||
|
border.color: contentContainer.surfaceBorderColor
|
||||||
|
border.width: contentContainer.surfaceBorderWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
visible: Theme.isConnectedEffect
|
||||||
|
barSide: contentContainer.connectedBarSide
|
||||||
|
placement: "left"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: Theme.connectedCornerRadius
|
||||||
|
color: contentContainer.surfaceColor
|
||||||
|
x: Theme.snap(contentContainer.connectorX(0, contentWrapper.width, placement, spacing), root.dpr)
|
||||||
|
y: Theme.snap(contentContainer.connectorY(0, contentWrapper.height, placement, spacing), root.dpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedCorner {
|
||||||
|
visible: Theme.isConnectedEffect
|
||||||
|
barSide: contentContainer.connectedBarSide
|
||||||
|
placement: "right"
|
||||||
|
spacing: 0
|
||||||
|
connectorRadius: Theme.connectedCornerRadius
|
||||||
|
color: contentContainer.surfaceColor
|
||||||
|
x: Theme.snap(contentContainer.connectorX(0, contentWrapper.width, placement, spacing), root.dpr)
|
||||||
|
y: Theme.snap(contentContainer.connectorY(0, contentWrapper.height, placement, spacing), root.dpr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -8,6 +9,7 @@ Item {
|
|||||||
|
|
||||||
required property var targetWindow
|
required property var targetWindow
|
||||||
property var blurItem: null
|
property var blurItem: null
|
||||||
|
property bool blurEnabled: Theme.connectedSurfaceBlurEnabled
|
||||||
property real blurX: 0
|
property real blurX: 0
|
||||||
property real blurY: 0
|
property real blurY: 0
|
||||||
property real blurWidth: 0
|
property real blurWidth: 0
|
||||||
@@ -17,7 +19,7 @@ Item {
|
|||||||
property var _region: null
|
property var _region: null
|
||||||
|
|
||||||
function _apply() {
|
function _apply() {
|
||||||
if (!BlurService.enabled || !targetWindow) {
|
if (!blurEnabled || !BlurService.enabled || !targetWindow) {
|
||||||
_cleanup();
|
_cleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -43,6 +45,8 @@ Item {
|
|||||||
_region = null;
|
_region = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBlurEnabledChanged: _apply()
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: BlurService
|
target: BlurService
|
||||||
function onEnabledChanged() {
|
function onEnabledChanged() {
|
||||||
|
|||||||
Reference in New Issue
Block a user