1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-28 15:32:50 -05:00

dankbar: support multiple bars and per-display bars

- Migrate settings to v2
  - Up to 4 bars
  - Per-bar settings instead of global
This commit is contained in:
bbedward
2025-11-22 15:28:06 -05:00
parent 4f32376f22
commit a3a27e07fa
69 changed files with 5567 additions and 3846 deletions

View File

@@ -78,14 +78,19 @@ PanelWindow {
readonly property bool isVerticalLayout: SettingsData.osdPosition === SettingsData.Position.LeftCenter || SettingsData.osdPosition === SettingsData.Position.RightCenter
readonly property real barThickness: {
if (!SettingsData.dankBarVisible) return 0
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
return Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar || !(defaultBar.visible ?? true)) return 0
const innerPadding = defaultBar.innerPadding ?? 4
const widgetThickness = Math.max(20, 26 + innerPadding * 0.6)
return Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding))
}
readonly property real barOffset: {
if (!SettingsData.dankBarVisible) return 0
return barThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar || !(defaultBar.visible ?? true)) return 0
const spacing = defaultBar.spacing ?? 4
const bottomGap = defaultBar.bottomGap ?? 0
return barThickness + spacing + bottomGap
}
readonly property real dockThickness: {
@@ -102,23 +107,26 @@ PanelWindow {
const margin = Theme.spacingM
const centerX = (screenWidth - alignedWidth) / 2
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
switch (SettingsData.osdPosition) {
case SettingsData.Position.Left:
case SettingsData.Position.Bottom:
const leftBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Left ? barOffset : 0
const leftBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0
const leftDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
return Theme.snap(margin + Math.max(leftBarOffset, leftDockOffset), dpr)
case SettingsData.Position.Top:
case SettingsData.Position.Right:
const rightBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Right ? barOffset : 0
const rightBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0
const rightDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightBarOffset, rightDockOffset), dpr)
case SettingsData.Position.LeftCenter:
const leftCenterBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Left ? barOffset : 0
const leftCenterBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0
const leftCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
return Theme.snap(margin + Math.max(leftCenterBarOffset, leftCenterDockOffset), dpr)
case SettingsData.Position.RightCenter:
const rightCenterBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Right ? barOffset : 0
const rightCenterBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0
const rightCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightCenterBarOffset, rightCenterDockOffset), dpr)
case SettingsData.Position.TopCenter:
@@ -132,17 +140,20 @@ PanelWindow {
const margin = Theme.spacingM
const centerY = (screenHeight - alignedHeight) / 2
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
switch (SettingsData.osdPosition) {
case SettingsData.Position.Top:
case SettingsData.Position.Left:
case SettingsData.Position.TopCenter:
const topBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Top ? barOffset : 0
const topBarOffset = barPos === SettingsData.Position.Top ? barOffset : 0
const topDockOffset = SettingsData.dockPosition === SettingsData.Position.Top ? dockOffset : 0
return Theme.snap(margin + Math.max(topBarOffset, topDockOffset), dpr)
case SettingsData.Position.Right:
case SettingsData.Position.Bottom:
case SettingsData.Position.BottomCenter:
const bottomBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barOffset : 0
const bottomBarOffset = barPos === SettingsData.Position.Bottom ? barOffset : 0
const bottomDockOffset = SettingsData.dockPosition === SettingsData.Position.Bottom ? dockOffset : 0
return Theme.snap(screenHeight - alignedHeight - margin - Math.max(bottomBarOffset, bottomDockOffset), dpr)
case SettingsData.Position.LeftCenter:
@@ -217,14 +228,15 @@ PanelWindow {
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / blurMax))
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest

View File

@@ -29,15 +29,23 @@ PanelWindow {
property list<real> animationExitCurve: Theme.expressiveCurves.emphasized
property bool shouldBeVisible: false
property real storedBarThickness: Theme.barHeight - 4
property real storedBarSpacing: 4
property var storedBarConfig: null
property var adjacentBarInfo: ({ "topBar": 0, "bottomBar": 0, "leftBar": 0, "rightBar": 0 })
visible: false
readonly property real effectiveBarThickness: Math.max(26 + SettingsData.dankBarInnerPadding * 0.6, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing
readonly property real effectiveBarThickness: {
const padding = storedBarConfig ? (storedBarConfig.innerPadding !== undefined ? storedBarConfig.innerPadding : 4) : 4
return Math.max(26 + padding * 0.6, Theme.barHeight - 4 - (8 - padding)) + storedBarSpacing
}
readonly property var barBounds: {
if (!root.screen) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
return SettingsData.getBarBounds(root.screen, effectiveBarThickness)
return SettingsData.getBarBounds(root.screen, effectiveBarThickness, effectiveBarPosition, storedBarConfig)
}
readonly property real barX: barBounds.x
@@ -50,6 +58,31 @@ PanelWindow {
signal popoutClosed
signal backgroundClicked
function setBarContext(position, bottomGap) {
effectiveBarPosition = position !== undefined ? position : 0
effectiveBarBottomGap = bottomGap !== undefined ? bottomGap : 0
}
function setTriggerPosition(x, y, width, section, screen, barPosition, barThickness, barSpacing, barConfig) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
root.screen = screen
storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4)
storedBarSpacing = barSpacing !== undefined ? barSpacing : 4
storedBarConfig = barConfig
const pos = barPosition !== undefined ? barPosition : 0
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0
// Get adjacent bar info for proper positioning
adjacentBarInfo = SettingsData.getAdjacentBarInfo(screen, pos, barConfig)
setBarContext(pos, bottomGap)
}
function open() {
closeTimer.stop()
shouldBeVisible = true
@@ -115,75 +148,71 @@ PanelWindow {
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
property int effectiveBarPosition: 0
property real effectiveBarBottomGap: 0
readonly property real alignedX: Theme.snap((() => {
if (SettingsData.dankBarPosition === SettingsData.Position.Left) {
return triggerY + SettingsData.dankBarBottomGap
} else if (SettingsData.dankBarPosition === SettingsData.Position.Right) {
return screenWidth - triggerY - SettingsData.dankBarBottomGap - popupWidth
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
let rawX = 0
if (effectiveBarPosition === SettingsData.Position.Left) {
rawX = triggerX
} else if (effectiveBarPosition === SettingsData.Position.Right) {
rawX = triggerX - popupWidth
} else {
const centerX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
return Math.max(Theme.popupDistance, Math.min(screenWidth - popupWidth - Theme.popupDistance, centerX))
rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
const minX = adjacentBarInfo.leftBar > 0 ? adjacentBarInfo.leftBar : popupGap
const maxX = screenWidth - popupWidth - (adjacentBarInfo.rightBar > 0 ? adjacentBarInfo.rightBar : popupGap)
return Math.max(minX, Math.min(maxX, rawX))
}
return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, rawX))
})(), dpr)
readonly property real alignedY: Theme.snap((() => {
if (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right) {
const centerY = triggerX + (triggerWidth / 2) - (popupHeight / 2)
return Math.max(Theme.popupDistance, Math.min(screenHeight - popupHeight - Theme.popupDistance, centerY))
} else if (SettingsData.dankBarPosition === SettingsData.Position.Bottom) {
return Math.max(Theme.popupDistance, screenHeight - triggerY - popupHeight)
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
let rawY = 0
if (effectiveBarPosition === SettingsData.Position.Bottom) {
rawY = triggerY - popupHeight
} else if (effectiveBarPosition === SettingsData.Position.Top) {
rawY = triggerY
} else {
return Math.min(screenHeight - popupHeight - Theme.popupDistance, triggerY)
rawY = triggerY - (popupHeight / 2)
const minY = adjacentBarInfo.topBar > 0 ? adjacentBarInfo.topBar : popupGap
const maxY = screenHeight - popupHeight - (adjacentBarInfo.bottomBar > 0 ? adjacentBarInfo.bottomBar : popupGap)
return Math.max(minY, Math.min(maxY, rawY))
}
return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, rawY))
})(), dpr)
readonly property real maskX: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Left:
return root.barWidth > 0 ? root.barWidth : 0
case SettingsData.Position.Right:
case SettingsData.Position.Top:
case SettingsData.Position.Bottom:
default:
return 0
}
const triggeringBarX = (effectiveBarPosition === SettingsData.Position.Left && root.barWidth > 0) ? root.barWidth : 0
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0
return Math.max(triggeringBarX, adjacentLeftBar)
}
readonly property real maskY: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Top:
return root.barHeight > 0 ? root.barHeight : 0
case SettingsData.Position.Bottom:
case SettingsData.Position.Left:
case SettingsData.Position.Right:
default:
return 0
}
const triggeringBarY = (effectiveBarPosition === SettingsData.Position.Top && root.barHeight > 0) ? root.barHeight : 0
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0
return Math.max(triggeringBarY, adjacentTopBar)
}
readonly property real maskWidth: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Left:
return root.barWidth > 0 ? root.width - root.barWidth : root.width
case SettingsData.Position.Right:
return root.barWidth > 0 ? root.width - root.barWidth : root.width
case SettingsData.Position.Top:
case SettingsData.Position.Bottom:
default:
return root.width
}
const triggeringBarRight = (effectiveBarPosition === SettingsData.Position.Right && root.barWidth > 0) ? root.barWidth : 0
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0
const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar)
return Math.max(100, root.width - maskX - rightExclusion)
}
readonly property real maskHeight: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Top:
return root.barHeight > 0 ? root.height - root.barHeight : root.height
case SettingsData.Position.Bottom:
return root.barHeight > 0 ? root.height - root.barHeight : root.height
case SettingsData.Position.Left:
case SettingsData.Position.Right:
default:
return root.height
}
const triggeringBarBottom = (effectiveBarPosition === SettingsData.Position.Bottom && root.barHeight > 0) ? root.barHeight : 0
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0
const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar)
return Math.max(100, root.height - maskY - bottomExclusion)
}
mask: Region {
@@ -222,10 +251,10 @@ PanelWindow {
width: alignedWidth
height: alignedHeight
readonly property bool barTop: SettingsData.dankBarPosition === SettingsData.Position.Top
readonly property bool barBottom: SettingsData.dankBarPosition === SettingsData.Position.Bottom
readonly property bool barLeft: SettingsData.dankBarPosition === SettingsData.Position.Left
readonly property bool barRight: SettingsData.dankBarPosition === SettingsData.Position.Right
readonly property bool barTop: effectiveBarPosition === SettingsData.Position.Top
readonly property bool barBottom: effectiveBarPosition === SettingsData.Position.Bottom
readonly property bool barLeft: effectiveBarPosition === SettingsData.Position.Left
readonly property bool barRight: effectiveBarPosition === SettingsData.Position.Right
readonly property real offsetX: barLeft ? root.animationOffset : (barRight ? -root.animationOffset : 0)
readonly property real offsetY: barBottom ? -root.animationOffset : (barTop ? root.animationOffset : 0)
@@ -303,14 +332,15 @@ PanelWindow {
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / blurMax))
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest

View File

@@ -28,9 +28,8 @@ Item {
function handleClick() {
if (!enabled) return
checked = !checked
clicked()
toggled(checked)
toggled(!checked)
}
StyledRect {

View File

@@ -50,13 +50,22 @@ PanelWindow {
margins {
left: {
if (alignLeft) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX)))
if (alignRight) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX - implicitWidth)))
return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX - implicitWidth / 2)))
const screenWidth = targetScreen?.width ?? Screen.width
if (alignLeft) {
return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX)))
} else if (alignRight) {
return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX - implicitWidth)))
} else {
return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX - implicitWidth / 2)))
}
}
top: {
if (alignLeft || alignRight) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.height ?? Screen.height) - implicitHeight - Theme.spacingS, targetY - implicitHeight / 2)))
return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.height ?? Screen.height) - implicitHeight - Theme.spacingS, targetY)))
const screenHeight = targetScreen?.height ?? Screen.height
if (alignLeft || alignRight) {
return Math.round(Math.max(Theme.spacingS, Math.min(screenHeight - implicitHeight - Theme.spacingS, targetY - implicitHeight / 2)))
} else {
return Math.round(Math.max(Theme.spacingS, Math.min(screenHeight - implicitHeight - Theme.spacingS, targetY)))
}
}
}

View File

@@ -45,24 +45,28 @@ Item {
Component.onCompleted: {
Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $ID"], (output, exitCode) => {
if (exitCode !== 0) return
if (!root || exitCode !== 0 || !output) return
const distroId = output.trim()
if (!distroId) return
// Nerd fonts are better than images usually
const supportedDistroNFs = ["debian", "arch", "archcraft", "fedora", "nixos", "ubuntu", "guix", "gentoo", "endeavouros", "manjaro", "opensuse"]
if (supportedDistroNFs.includes(distroId)) {
if (!root) return
root.useNerdFont = true
root.nerdFontIcon = distroId
return
}
Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $LOGO"], (logoOutput, logoExitCode) => {
if (logoExitCode !== 0) return
if (!root || !iconImage || logoExitCode !== 0 || !logoOutput) return
const logo = logoOutput.trim()
if (!logo) return
if (logo === "cachyos") {
iconImage.source = "file:///usr/share/icons/cachyos.svg"
return
} else if (logo === "guix-icon") {
}
if (logo === "guix-icon") {
iconImage.source = "file:///run/current-system/profile/share/icons/hicolor/scalable/apps/guix-icon.svg"
return
}