1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-10 06:19:36 -04:00

fix(Dock): Refactor & Fix Dock in FrameModes. Updates to Zone offset in Standalone & Connected modes

- Fixed hairline seam in some connected mode variants
- Moved dock-related properties to a new DockGeometry component for a future base
This commit is contained in:
purian23
2026-05-09 17:37:42 -04:00
parent faa30c4d48
commit 7f6486b3e7
4 changed files with 146 additions and 35 deletions

View File

@@ -46,14 +46,10 @@ Variants {
property bool groupByApp: SettingsData.dockGroupByApp
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 connectedBarActiveOnEdge ? SettingsData.frameBarSize : SettingsData.frameThickness;
if (SettingsData.frameEnabled)
return SettingsData.frameEdgeInsetForSide(dock.screen || modelData, dock.connectedBarSide);
return 0;
}
readonly property bool frameDockExclusionActive: dockGeometry.frameExclusionActive
readonly property bool connectedBarActiveOnEdge: dockGeometry.connectedBarActiveOnEdge
readonly property real connectedJoinInset: dockGeometry.connectedJoinInset
readonly property real dockFrameInset: dockGeometry.frameInset
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
@@ -68,7 +64,7 @@ Variants {
readonly property int hasApps: dockApps.implicitWidth > 0 || dockApps.implicitHeight > 0
readonly property real widgetHeight: SettingsData.dockIconSize
readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 + borderThickness * 2
readonly property real effectiveBarHeight: dockGeometry.visualThickness
function getBarHeight(barConfig) {
if (!barConfig)
return 0;
@@ -137,15 +133,32 @@ Variants {
readonly property real dockMargin: 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 effectiveDockBottomGap: dockGeometry.visualOffset
readonly property real effectiveDockMargin: dockGeometry.effectiveMargin
readonly property real positionSpacing: barSpacing + effectiveDockBottomGap + effectiveDockMargin
readonly property real joinedEdgeMargin: Theme.isConnectedEffect ? 0 : (barSpacing + effectiveDockMargin + 1 + dock.borderThickness)
readonly property real joinedEdgeMargin: dockGeometry.joinedEdgeMargin
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
function px(v) {
return Math.round(v * _dpr) / _dpr;
}
DockGeometry {
id: dockGeometry
screen: dock.screen || dock.modelData
edge: dock.connectedBarSide
dockVisible: dock.visible
autoHide: dock.autoHide
hasFullscreenToplevel: dock.hasFullscreenToplevel
iconSize: dock.widgetHeight
spacing: SettingsData.dockSpacing
borderThickness: dock.borderThickness
offset: SettingsData.dockBottomGap
margin: SettingsData.dockMargin
barSpacing: dock.barSpacing
dpr: dock._dpr
}
// Dock window origin in screen-relative coordinates (FrameWindow space).
function _dockWindowOriginX() {
if (!dock.isVertical)
@@ -231,7 +244,7 @@ Variants {
return false;
const screenName = dock.modelData?.name ?? "";
const dockThickness = dock.connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin;
const dockThickness = dockGeometry.motionThickness;
const screenWidth = dock.screen?.width ?? 0;
const screenHeight = dock.screen?.height ?? 0;
@@ -434,20 +447,21 @@ Variants {
}
color: "transparent"
readonly property real dockReserveZone: dockGeometry.reserveZone
readonly property bool shouldReserveDockSpace: dockGeometry.shouldReserveSpace
exclusiveZone: {
if (dock.hasFullscreenToplevel)
if (!dock.shouldReserveDockSpace)
return -1;
if (!SettingsData.showDock || autoHide)
if (dock.frameDockExclusionActive)
return -1;
if (barSpacing > 0)
return -1;
return px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockBottomGap + effectiveDockMargin);
return dock.dockReserveZone;
}
property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35)
implicitWidth: isVertical ? (px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
implicitHeight: !isVertical ? (px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
implicitWidth: isVertical ? (px(dockGeometry.surfaceThickness + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
implicitHeight: !isVertical ? (px(dockGeometry.surfaceThickness + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
Item {
id: maskItem
@@ -474,6 +488,28 @@ Variants {
item: maskItem
}
PanelWindow {
id: dockExclusion
screen: dock.screen || dock.modelData
visible: dock.frameDockExclusionActive && dock.shouldReserveDockSpace
color: "transparent"
mask: Region {}
implicitWidth: dock.isVertical ? dock.dockReserveZone : 1
implicitHeight: dock.isVertical ? 1 : dock.dockReserveZone
exclusiveZone: visible ? dock.dockReserveZone : -1
WlrLayershell.namespace: "dms:dock-exclusion"
WlrLayershell.layer: WlrLayer.Top
anchors {
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top) : true
bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom) : true
left: !dock.isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Left)
right: !dock.isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Right)
}
}
property var hoveredButton: {
if (!dockApps.children[0]) {
return null;
@@ -527,7 +563,7 @@ Variants {
const screenHeight = dock.screen ? dock.screen.height : 0;
const gap = Theme.spacingS;
const bgMargin = dock.joinedEdgeMargin + dock.connectedJoinInset;
const bgMargin = dockGeometry.bodyEdgeMargin;
const btnW = dock.hoveredButton.width;
const btnH = dock.hoveredButton.height;
@@ -598,11 +634,11 @@ Variants {
// 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 dock.reveal ? px(dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin) : 1;
return dock.reveal ? px(dockGeometry.motionThickness) : 1;
}
width: {
if (dock.isVertical) {
return dock.reveal ? px(dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin) : 1;
return dock.reveal ? px(dockGeometry.motionThickness) : 1;
}
// Keep the wider hit area regardless of the reveal state to prevent shrinking loop
return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth);
@@ -648,7 +684,7 @@ Variants {
const retractDist = dockBackground.width + SettingsData.dockSpacing + 10;
return SettingsData.dockPosition === SettingsData.Position.Right ? retractDist : -retractDist;
}
const hideDistance = dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin + 10;
const hideDistance = dockGeometry.motionThickness + 10;
if (SettingsData.dockPosition === SettingsData.Position.Right) {
return hideDistance;
} else {
@@ -664,7 +700,7 @@ Variants {
const retractDist = dockBackground.height + SettingsData.dockSpacing + 10;
return SettingsData.dockPosition === SettingsData.Position.Bottom ? retractDist : -retractDist;
}
const hideDistance = dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin + 10;
const hideDistance = dockGeometry.motionThickness + 10;
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
return hideDistance;
} else {
@@ -709,10 +745,10 @@ Variants {
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
}
anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? dockGeometry.bodyEdgeMargin : 0
anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? dockGeometry.bodyEdgeMargin : 0
anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? dockGeometry.bodyEdgeMargin : 0
anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? dockGeometry.bodyEdgeMargin : 0
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)

View File

@@ -0,0 +1,61 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
QtObject {
id: root
property var screen: null
property string edge: "bottom"
property bool dockVisible: false
property bool autoHide: false
property bool hasFullscreenToplevel: false
property real iconSize: 40
property real spacing: 4
property real borderThickness: 0
property real offset: 0
property real margin: 0
property real barSpacing: 0
property real dpr: 1
function px(value) {
return Math.round(value * dpr) / dpr;
}
readonly property bool frameExclusionActive: SettingsData.frameEnabled && !!screen && SettingsData.isScreenInPreferences(screen, SettingsData.frameScreenPreferences)
readonly property bool connectedMode: Theme.isConnectedEffect
readonly property bool connectedBarActiveOnEdge: connectedMode && !!screen && SettingsData.getActiveBarEdgesForScreen(screen).includes(edge)
readonly property real connectedJoinInset: {
if (connectedMode)
return connectedBarActiveOnEdge ? SettingsData.frameBarSize : SettingsData.frameThickness;
if (SettingsData.frameEnabled)
return SettingsData.frameEdgeInsetForSide(screen, edge);
return 0;
}
readonly property real frameInset: {
if (!frameExclusionActive)
return 0;
if (connectedMode)
return connectedJoinInset;
return SettingsData.frameThickness;
}
readonly property real effectiveMargin: connectedMode ? 0 : margin
readonly property real visualOffset: connectedMode ? 0 : offset
readonly property real reserveOffset: offset
readonly property real joinedEdgeMargin: connectedMode ? 0 : (barSpacing + effectiveMargin + 1 + borderThickness)
readonly property real bodyEdgeMargin: frameInset + joinedEdgeMargin
readonly property real bodyThickness: iconSize + spacing * 2 + borderThickness * 2
readonly property real visualThickness: bodyThickness + 10
readonly property real surfaceThickness: frameInset + visualThickness + spacing + effectiveMargin
readonly property real motionThickness: surfaceThickness + visualOffset
// Frame/bar edge exclusions already reserve the edge itself, so the dock
// reservation covers only the dock body and user offset beyond that edge.
readonly property real reserveZone: px(bodyThickness + reserveOffset + effectiveMargin)
readonly property bool shouldReserveSpace: dockVisible && !hasFullscreenToplevel && !autoHide && barSpacing <= 0
}

View File

@@ -91,6 +91,8 @@ PanelWindow {
readonly property real _popoutFillOverlapYValue: (ConnectedModeState.popoutBarSide === "left" || ConnectedModeState.popoutBarSide === "right") ? win._seamOverlap : 0
readonly property real _dockFillOverlapXValue: win._dockHorizontal ? win._seamOverlap : 0
readonly property real _dockFillOverlapYValue: (win._dockState.barSide === "left" || win._dockState.barSide === "right") ? win._seamOverlap : 0
readonly property real _dockJoinOverlapXValue: ConnectorGeometry.isVertical(win._dockState.barSide) ? win._seamOverlap : 0
readonly property real _dockJoinOverlapYValue: ConnectorGeometry.isHorizontal(win._dockState.barSide) ? win._seamOverlap : 0
readonly property real _notifSideUnderlapValue: ConnectorGeometry.isVertical(win._notifState.barSide) ? win._seamOverlap : 0
readonly property real _notifStartUnderlapValue: win._notifState.omitStartConnector ? win._seamOverlap : 0
readonly property real _notifEndUnderlapValue: win._notifState.omitEndConnector ? win._seamOverlap : 0
@@ -1117,6 +1119,14 @@ PanelWindow {
return ((win._dockState.barSide === "left" || win._dockState.barSide === "right") ? win._dockConnectorRadiusValue : 0) - win._dockFillOverlapYValue;
}
function _dockJoinOverlapXOffset() {
return win._dockState.barSide === "left" ? -win._dockJoinOverlapXValue : 0;
}
function _dockJoinOverlapYOffset() {
return win._dockState.barSide === "top" ? -win._dockJoinOverlapYValue : 0;
}
function _farConnectorBarSide(sourceSide, placement) {
if (sourceSide === "top" || sourceSide === "bottom")
return placement === "left" ? "left" : "right";
@@ -1359,10 +1369,10 @@ PanelWindow {
Rectangle {
id: _dockFill
x: win._dockBodyXInChrome()
y: win._dockBodyYInChrome()
width: _dockBodyBlurAnchor.width + win._dockFillOverlapXValue * 2
height: _dockBodyBlurAnchor.height + win._dockFillOverlapYValue * 2
x: win._dockBodyXInChrome() + win._dockJoinOverlapXOffset()
y: win._dockBodyYInChrome() + win._dockJoinOverlapYOffset()
width: _dockBodyBlurAnchor.width + win._dockFillOverlapXValue * 2 + win._dockJoinOverlapXValue
height: _dockBodyBlurAnchor.height + win._dockFillOverlapYValue * 2 + win._dockJoinOverlapYValue
color: win._opaqueSurfaceColor
z: 1

View File

@@ -10,6 +10,7 @@ Item {
property var parentModal: null
readonly property bool connectedFrameModeActive: SettingsData.connectedFrameModeActive
readonly property bool connectedPersistentDockActive: connectedFrameModeActive && SettingsData.showDock && !SettingsData.dockAutoHide && !SettingsData.dockSmartAutoHide
FileBrowserModal {
id: dockLogoFileBrowser
@@ -611,16 +612,18 @@ Item {
value: SettingsData.dockSpacing
minimum: 0
maximum: 32
unit: "px"
defaultValue: 8
onSliderValueChanged: newValue => SettingsData.set("dockSpacing", newValue)
}
SettingsSliderRow {
text: I18n.tr("Exclusive Zone Offset")
visible: !root.connectedFrameModeActive
visible: !root.connectedFrameModeActive || root.connectedPersistentDockActive
value: SettingsData.dockBottomGap
minimum: -100
maximum: 100
unit: "px"
defaultValue: 0
onSliderValueChanged: newValue => SettingsData.set("dockBottomGap", newValue)
}
@@ -631,6 +634,7 @@ Item {
value: SettingsData.dockMargin
minimum: 0
maximum: 100
unit: "px"
defaultValue: 0
onSliderValueChanged: newValue => SettingsData.set("dockMargin", newValue)
}
@@ -639,7 +643,7 @@ Item {
SettingsControlledByFrame {
visible: root.connectedFrameModeActive
parentModal: root.parentModal
settingLabel: I18n.tr("Dock spacing, transparency, and border")
settingLabel: I18n.tr("Dock margin, transparency, and border")
reason: I18n.tr("Managed by Frame in Connected Mode")
}