1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-29 16:02:51 -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

@@ -9,155 +9,167 @@ Singleton {
property var currentPopoutsByScreen: ({}) property var currentPopoutsByScreen: ({})
property var currentPopoutTriggers: ({}) property var currentPopoutTriggers: ({})
function showPopout(popout) { signal popoutOpening
if (!popout || !popout.screen) return signal popoutChanged
const screenName = popout.screen.name function showPopout(popout) {
if (!popout || !popout.screen)
return;
popoutOpening();
const screenName = popout.screen.name;
for (const otherScreenName in currentPopoutsByScreen) { for (const otherScreenName in currentPopoutsByScreen) {
const otherPopout = currentPopoutsByScreen[otherScreenName] const otherPopout = currentPopoutsByScreen[otherScreenName];
if (!otherPopout || otherPopout === popout) continue if (!otherPopout || otherPopout === popout)
continue;
if (otherPopout.dashVisible !== undefined) { if (otherPopout.dashVisible !== undefined) {
otherPopout.dashVisible = false otherPopout.dashVisible = false;
} else if (otherPopout.notificationHistoryVisible !== undefined) { } else if (otherPopout.notificationHistoryVisible !== undefined) {
otherPopout.notificationHistoryVisible = false otherPopout.notificationHistoryVisible = false;
} else { } else {
otherPopout.close() otherPopout.close();
} }
} }
currentPopoutsByScreen[screenName] = popout currentPopoutsByScreen[screenName] = popout;
ModalManager.closeAllModalsExcept(null) popoutChanged();
TrayMenuManager.closeAllMenus() ModalManager.closeAllModalsExcept(null);
} }
function hidePopout(popout) { function hidePopout(popout) {
if (!popout || !popout.screen) return if (!popout || !popout.screen)
return;
const screenName = popout.screen.name const screenName = popout.screen.name;
if (currentPopoutsByScreen[screenName] === popout) { if (currentPopoutsByScreen[screenName] === popout) {
currentPopoutsByScreen[screenName] = null currentPopoutsByScreen[screenName] = null;
currentPopoutTriggers[screenName] = null currentPopoutTriggers[screenName] = null;
popoutChanged();
} }
} }
function closeAllPopouts() { function closeAllPopouts() {
for (const screenName in currentPopoutsByScreen) { for (const screenName in currentPopoutsByScreen) {
const popout = currentPopoutsByScreen[screenName] const popout = currentPopoutsByScreen[screenName];
if (!popout) continue if (!popout)
continue;
if (popout.dashVisible !== undefined) { if (popout.dashVisible !== undefined) {
popout.dashVisible = false popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) { } else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false popout.notificationHistoryVisible = false;
} else { } else {
popout.close() popout.close();
} }
} }
currentPopoutsByScreen = {} currentPopoutsByScreen = {};
} }
function getActivePopout(screen) { function getActivePopout(screen) {
if (!screen) return null if (!screen)
return currentPopoutsByScreen[screen.name] || null return null;
return currentPopoutsByScreen[screen.name] || null;
} }
function requestPopout(popout, tabIndex, triggerSource) { function requestPopout(popout, tabIndex, triggerSource) {
if (!popout || !popout.screen) return if (!popout || !popout.screen)
return;
const screenName = popout.screen.name;
const currentPopout = currentPopoutsByScreen[screenName];
const triggerId = triggerSource !== undefined ? triggerSource : tabIndex;
const screenName = popout.screen.name const willOpen = !(currentPopout === popout && popout.shouldBeVisible && triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId);
const currentPopout = currentPopoutsByScreen[screenName] if (willOpen) {
const triggerId = triggerSource !== undefined ? triggerSource : tabIndex popoutOpening();
}
let justClosedSamePopout = false let justClosedSamePopout = false;
for (const otherScreenName in currentPopoutsByScreen) { for (const otherScreenName in currentPopoutsByScreen) {
if (otherScreenName === screenName) continue if (otherScreenName === screenName)
const otherPopout = currentPopoutsByScreen[otherScreenName] continue;
if (!otherPopout) continue const otherPopout = currentPopoutsByScreen[otherScreenName];
if (!otherPopout)
continue;
if (otherPopout === popout) { if (otherPopout === popout) {
justClosedSamePopout = true justClosedSamePopout = true;
} }
if (otherPopout.dashVisible !== undefined) { if (otherPopout.dashVisible !== undefined) {
otherPopout.dashVisible = false otherPopout.dashVisible = false;
} else if (otherPopout.notificationHistoryVisible !== undefined) { } else if (otherPopout.notificationHistoryVisible !== undefined) {
otherPopout.notificationHistoryVisible = false otherPopout.notificationHistoryVisible = false;
} else { } else {
otherPopout.close() otherPopout.close();
} }
} }
if (currentPopout && currentPopout !== popout) { if (currentPopout && currentPopout !== popout) {
if (currentPopout.dashVisible !== undefined) { if (currentPopout.dashVisible !== undefined) {
currentPopout.dashVisible = false currentPopout.dashVisible = false;
} else if (currentPopout.notificationHistoryVisible !== undefined) { } else if (currentPopout.notificationHistoryVisible !== undefined) {
currentPopout.notificationHistoryVisible = false currentPopout.notificationHistoryVisible = false;
} else { } else {
currentPopout.close() currentPopout.close();
} }
} }
if (currentPopout === popout && popout.shouldBeVisible) { if (currentPopout === popout && popout.shouldBeVisible) {
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) { if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) {
if (popout.dashVisible !== undefined) { if (popout.dashVisible !== undefined) {
popout.dashVisible = false popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) { } else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false popout.notificationHistoryVisible = false;
} else { } else {
popout.close() popout.close();
} }
return return;
} }
if (triggerId === undefined) { if (triggerId === undefined) {
if (popout.dashVisible !== undefined) { if (popout.dashVisible !== undefined) {
popout.dashVisible = false popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) { } else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false popout.notificationHistoryVisible = false;
} else { } else {
popout.close() popout.close();
} }
return return;
} }
if (tabIndex !== undefined && popout.currentTabIndex !== undefined) { if (tabIndex !== undefined && popout.currentTabIndex !== undefined) {
popout.currentTabIndex = tabIndex popout.currentTabIndex = tabIndex;
} }
currentPopoutTriggers[screenName] = triggerId currentPopoutTriggers[screenName] = triggerId;
return
} }
currentPopoutTriggers[screenName] = triggerId currentPopoutTriggers[screenName] = triggerId;
currentPopoutsByScreen[screenName] = popout currentPopoutsByScreen[screenName] = popout;
popoutChanged();
if (tabIndex !== undefined && popout.currentTabIndex !== undefined) { if (tabIndex !== undefined && popout.currentTabIndex !== undefined) {
popout.currentTabIndex = tabIndex popout.currentTabIndex = tabIndex;
} }
if (currentPopout !== popout) { if (currentPopout !== popout) {
ModalManager.closeAllModalsExcept(null) ModalManager.closeAllModalsExcept(null);
} }
TrayMenuManager.closeAllMenus()
if (justClosedSamePopout) { if (justClosedSamePopout) {
Qt.callLater(() => { Qt.callLater(() => {
if (popout.dashVisible !== undefined) { if (popout.dashVisible !== undefined) {
popout.dashVisible = true popout.dashVisible = true;
} else if (popout.notificationHistoryVisible !== undefined) { } else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = true popout.notificationHistoryVisible = true;
} else { } else {
popout.open() popout.open();
} }
}) });
} else { } else {
if (popout.dashVisible !== undefined) { if (popout.dashVisible !== undefined) {
popout.dashVisible = true popout.dashVisible = true;
} else if (popout.notificationHistoryVisible !== undefined) { } else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = true popout.notificationHistoryVisible = true;
} else { } else {
popout.open() popout.open();
} }
} }
} }

View File

@@ -67,13 +67,21 @@ Singleton {
}) })
out.streamFinished.connect(function() { out.streamFinished.connect(function() {
capturedOut = out.text || "" try {
capturedOut = out.text || ""
} catch (e) {
capturedOut = ""
}
outSeen = true outSeen = true
maybeComplete() maybeComplete()
}) })
err.streamFinished.connect(function() { err.streamFinished.connect(function() {
capturedErr = err.text || "" try {
capturedErr = err.text || ""
} catch (e) {
capturedErr = ""
}
errSeen = true errSeen = true
maybeComplete() maybeComplete()
}) })
@@ -88,8 +96,14 @@ Singleton {
function maybeComplete() { function maybeComplete() {
if (!exitSeen || !outSeen || !errSeen) return if (!exitSeen || !outSeen || !errSeen) return
timeoutTimer.stop() timeoutTimer.stop()
if (typeof entry.callback === "function") { if (entry && entry.callback && typeof entry.callback === "function") {
try { entry.callback(capturedOut, exitCodeValue) } catch (e) { console.warn("runCommand callback error:", e) } try {
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : ""
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1
entry.callback(safeOutput, safeExitCode)
} catch (e) {
console.warn("runCommand callback error for command:", entry.command, "Error:", e)
}
} }
try { proc.destroy() } catch (_) {} try { proc.destroy() } catch (_) {}
try { timeoutTimer.destroy() } catch (_) {} try { timeoutTimer.destroy() } catch (_) {}

View File

@@ -15,7 +15,7 @@ import "settings/SettingsStore.js" as Store
Singleton { Singleton {
id: root id: root
readonly property int settingsConfigVersion: 1 readonly property int settingsConfigVersion: 2
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true" readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
@@ -70,8 +70,6 @@ Singleton {
property string matugenScheme: "scheme-tonal-spot" property string matugenScheme: "scheme-tonal-spot"
property bool runUserMatugenTemplates: true property bool runUserMatugenTemplates: true
property string matugenTargetMonitor: "" property string matugenTargetMonitor: ""
property real dankBarTransparency: 1.0
property real dankBarWidgetTransparency: 1.0
property real popupTransparency: 1.0 property real popupTransparency: 1.0
property real dockTransparency: 1 property real dockTransparency: 1
property string widgetBackgroundColor: "sch" property string widgetBackgroundColor: "sch"
@@ -168,10 +166,6 @@ Singleton {
property string lockDateFormat: "" property string lockDateFormat: ""
property int mediaSize: 1 property int mediaSize: 1
property var dankBarLeftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"]
property var dankBarCenterWidgets: ["music", "clock", "weather"]
property var dankBarRightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
property var dankBarWidgetOrder: []
property string appLauncherViewMode: "list" property string appLauncherViewMode: "list"
property string spotlightModalViewMode: "list" property string spotlightModalViewMode: "list"
@@ -268,39 +262,9 @@ Singleton {
property string dockIndicatorStyle: "circle" property string dockIndicatorStyle: "circle"
property bool notificationOverlayEnabled: false property bool notificationOverlayEnabled: false
property bool dankBarAutoHide: false
property int dankBarAutoHideDelay: 250
property bool dankBarOpenOnOverview: false
property bool dankBarVisible: true
property int overviewRows: 2 property int overviewRows: 2
property int overviewColumns: 5 property int overviewColumns: 5
property real overviewScale: 0.16 property real overviewScale: 0.16
property real dankBarSpacing: 4
property real dankBarBottomGap: 0
property real dankBarInnerPadding: 4
property int dankBarPosition: SettingsData.Position.Top
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
onDankBarAutoHideDelayChanged: saveSettings()
property bool dankBarSquareCorners: false
property bool dankBarNoBackground: false
property bool dankBarGothCornersEnabled: false
property bool dankBarGothCornerRadiusOverride: false
property real dankBarGothCornerRadiusValue: 12
property bool dankBarBorderEnabled: false
property string dankBarBorderColor: "surfaceText"
property real dankBarBorderOpacity: 1.0
property real dankBarBorderThickness: 1
onDankBarGothCornerRadiusOverrideChanged: saveSettings()
onDankBarGothCornerRadiusValueChanged: saveSettings()
onDankBarBorderColorChanged: saveSettings()
onDankBarBorderOpacityChanged: saveSettings()
onDankBarBorderThicknessChanged: saveSettings()
property bool popupGapsAuto: true
property int popupGapsManual: 4
property bool modalDarkenBackground: true property bool modalDarkenBackground: true
@@ -343,6 +307,39 @@ Singleton {
property var screenPreferences: ({}) property var screenPreferences: ({})
property var showOnLastDisplay: ({}) property var showOnLastDisplay: ({})
property var barConfigs: [{
id: "default",
name: "Main Bar",
enabled: true,
position: 0,
screenPreferences: ["all"],
showOnLastDisplay: true,
leftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"],
centerWidgets: ["music", "clock", "weather"],
rightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"],
spacing: 4,
innerPadding: 4,
bottomGap: 0,
transparency: 1.0,
widgetTransparency: 1.0,
squareCorners: false,
noBackground: false,
gothCornersEnabled: false,
gothCornerRadiusOverride: false,
gothCornerRadiusValue: 12,
borderEnabled: false,
borderColor: "surfaceText",
borderOpacity: 1.0,
borderThickness: 1,
fontScale: 1.0,
autoHide: false,
autoHideDelay: 250,
openOnOverview: false,
visible: true,
popupGapsAuto: true,
popupGapsManual: 4
}]
signal forceDankBarLayoutRefresh signal forceDankBarLayoutRefresh
signal forceDockLayoutRefresh signal forceDockLayoutRefresh
signal widgetDataChanged signal widgetDataChanged
@@ -456,7 +453,8 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
applyStoredTheme: applyStoredTheme, applyStoredTheme: applyStoredTheme,
regenSystemThemes: regenSystemThemes, regenSystemThemes: regenSystemThemes,
updateNiriLayout: updateNiriLayout, updateNiriLayout: updateNiriLayout,
applyStoredIconTheme: applyStoredIconTheme applyStoredIconTheme: applyStoredIconTheme,
updateBarConfigs: updateBarConfigs
}) })
function set(key, value) { function set(key, value) {
@@ -467,24 +465,22 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
_loading = true _loading = true
try { try {
const txt = settingsFile.text() const txt = settingsFile.text()
const obj = (txt && txt.trim()) ? JSON.parse(txt) : null let obj = (txt && txt.trim()) ? JSON.parse(txt) : null
const oldVersion = obj?.configVersion ?? 0
if (oldVersion < settingsConfigVersion) {
const migrated = Store.migrateToVersion(obj, settingsConfigVersion)
if (migrated) {
settingsFile.setText(JSON.stringify(migrated, null, 2))
obj = migrated
}
}
Store.parse(root, obj) Store.parse(root, obj)
const shouldMigrate = Store.migrate(root, obj)
applyStoredTheme() applyStoredTheme()
applyStoredIconTheme() applyStoredIconTheme()
Processes.detectIcons() Processes.detectIcons()
Processes.detectQtTools() Processes.detectQtTools()
if (obj && obj.configVersion === undefined) {
const cleaned = Store.cleanup(txt)
if (cleaned) {
settingsFile.setText(cleaned)
}
saveSettings()
}
if (shouldMigrate) {
savePluginSettings()
saveSettings()
}
} catch (e) { } catch (e) {
console.warn("SettingsData: Failed to load settings:", e.message) console.warn("SettingsData: Failed to load settings:", e.message)
applyStoredTheme() applyStoredTheme()
@@ -548,7 +544,10 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
} }
function initializeListModels() { function initializeListModels() {
Lists.init(leftWidgetsModel, centerWidgetsModel, rightWidgetsModel, dankBarLeftWidgets, dankBarCenterWidgets, dankBarRightWidgets) const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
Lists.init(leftWidgetsModel, centerWidgetsModel, rightWidgetsModel, defaultBar.leftWidgets, defaultBar.centerWidgets, defaultBar.rightWidgets)
}
} }
function updateListModel(listModel, order) { function updateListModel(listModel, order) {
@@ -579,77 +578,302 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
} }
function getPopupYPosition(barHeight) { function getPopupYPosition(barHeight) {
const gothOffset = dankBarGothCornersEnabled ? Theme.cornerRadius : 0 const defaultBar = barConfigs[0] || getBarConfig("default")
return barHeight + dankBarSpacing + dankBarBottomGap - gothOffset + Theme.popupDistance const gothOffset = defaultBar?.gothCornersEnabled ? Theme.cornerRadius : 0
const spacing = defaultBar?.spacing ?? 4
const bottomGap = defaultBar?.bottomGap ?? 0
return barHeight + spacing + bottomGap - gothOffset + Theme.popupDistance
} }
function getPopupTriggerPosition(globalPos, screen, barThickness, widgetWidth) { function getPopupTriggerPosition(globalPos, screen, barThickness, widgetWidth, barSpacing, barPosition, barConfig) {
const screenX = screen ? screen.x : 0 const screenX = screen ? screen.x : 0
const screenY = screen ? screen.y : 0 const screenY = screen ? screen.y : 0
const relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX
const relativeY = globalPos.y - screenY const relativeY = globalPos.y - screenY
const defaultBar = barConfigs[0] || getBarConfig("default")
const spacing = barSpacing !== undefined ? barSpacing : (defaultBar?.spacing ?? 4)
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top)
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0)
if (dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right) { const useAutoGaps = (barConfig && barConfig.popupGapsAuto !== undefined) ? barConfig.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true)
const manualGapValue = (barConfig && barConfig.popupGapsManual !== undefined) ? barConfig.popupGapsManual : (defaultBar?.popupGapsManual ?? 4)
const popupGap = useAutoGaps ? Math.max(4, spacing) : manualGapValue
switch (position) {
case SettingsData.Position.Left:
return { return {
"x": relativeY, "x": barThickness + spacing + popupGap,
"y": barThickness + dankBarSpacing + Theme.popupDistance, "y": relativeY,
"width": widgetWidth
}
case SettingsData.Position.Right:
return {
"x": (screen?.width || 0) - (barThickness + spacing + popupGap),
"y": relativeY,
"width": widgetWidth
}
case SettingsData.Position.Bottom:
return {
"x": relativeX,
"y": (screen?.height || 0) - (barThickness + spacing + bottomGap + popupGap),
"width": widgetWidth
}
default:
return {
"x": relativeX,
"y": barThickness + spacing + bottomGap + popupGap,
"width": widgetWidth "width": widgetWidth
} }
} }
return {
"x": relativeX,
"y": barThickness + dankBarSpacing + Theme.popupDistance,
"width": widgetWidth
}
} }
function getBarBounds(screen, barThickness) { function getAdjacentBarInfo(screen, barPosition, barConfig) {
if (!screen || !barConfig) {
return { "topBar": 0, "bottomBar": 0, "leftBar": 0, "rightBar": 0 }
}
if (barConfig.autoHide) {
return { "topBar": 0, "bottomBar": 0, "leftBar": 0, "rightBar": 0 }
}
const enabledBars = getEnabledBarConfigs()
const defaultBar = barConfigs[0] || getBarConfig("default")
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top)
let topBar = 0
let bottomBar = 0
let leftBar = 0
let rightBar = 0
for (let i = 0; i < enabledBars.length; i++) {
const other = enabledBars[i]
if (other.id === barConfig.id) continue
if (other.autoHide) continue
const otherScreens = other.screenPreferences || ["all"]
const barScreens = barConfig.screenPreferences || ["all"]
const onSameScreen = otherScreens.includes("all") || barScreens.includes("all") ||
otherScreens.some(s => isScreenInPreferences(screen, [s]))
if (!onSameScreen) continue
const otherSpacing = other.spacing !== undefined ? other.spacing : (defaultBar?.spacing ?? 4)
const otherPadding = other.innerPadding !== undefined ? other.innerPadding : (defaultBar?.innerPadding ?? 4)
const otherThickness = Math.max(26 + otherPadding * 0.6, Theme.barHeight - 4 - (8 - otherPadding)) + otherSpacing
const useAutoGaps = other.popupGapsAuto !== undefined ? other.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true)
const manualGap = other.popupGapsManual !== undefined ? other.popupGapsManual : (defaultBar?.popupGapsManual ?? 4)
const popupGap = useAutoGaps ? Math.max(4, otherSpacing) : manualGap
switch (other.position) {
case SettingsData.Position.Top:
topBar = Math.max(topBar, otherThickness + popupGap)
break
case SettingsData.Position.Bottom:
bottomBar = Math.max(bottomBar, otherThickness + popupGap)
break
case SettingsData.Position.Left:
leftBar = Math.max(leftBar, otherThickness + popupGap)
break
case SettingsData.Position.Right:
rightBar = Math.max(rightBar, otherThickness + popupGap)
break
}
}
return { "topBar": topBar, "bottomBar": bottomBar, "leftBar": leftBar, "rightBar": rightBar }
}
function getBarBounds(screen, barThickness, barPosition, barConfig) {
if (!screen) { if (!screen) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 } return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
} }
const wingRadius = dankBarGothCornerRadiusOverride ? dankBarGothCornerRadiusValue : Theme.cornerRadius const defaultBar = barConfigs[0] || getBarConfig("default")
const wingSize = dankBarGothCornersEnabled ? Math.max(0, wingRadius) : 0 const wingRadius = (defaultBar?.gothCornerRadiusOverride ?? false) ? (defaultBar?.gothCornerRadiusValue ?? 12) : Theme.cornerRadius
const wingSize = (defaultBar?.gothCornersEnabled ?? false) ? Math.max(0, wingRadius) : 0
const screenWidth = screen.width const screenWidth = screen.width
const screenHeight = screen.height const screenHeight = screen.height
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top)
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0)
if (dankBarPosition === SettingsData.Position.Top) { let topOffset = 0
return { let bottomOffset = 0
"x": 0, let leftOffset = 0
"y": 0, let rightOffset = 0
"width": screenWidth,
"height": barThickness + dankBarSpacing + wingSize, if (barConfig) {
"wingSize": wingSize const enabledBars = getEnabledBarConfigs()
} for (let i = 0; i < enabledBars.length; i++) {
} else if (dankBarPosition === SettingsData.Position.Bottom) { const other = enabledBars[i]
return { if (other.id === barConfig.id) continue
"x": 0,
"y": screenHeight - barThickness - dankBarSpacing - wingSize, const otherScreens = other.screenPreferences || ["all"]
"width": screenWidth, const barScreens = barConfig.screenPreferences || ["all"]
"height": barThickness + dankBarSpacing + wingSize, const onSameScreen = otherScreens.includes("all") || barScreens.includes("all") ||
"wingSize": wingSize otherScreens.some(s => isScreenInPreferences(screen, [s]))
}
} else if (dankBarPosition === SettingsData.Position.Left) { if (!onSameScreen) continue
return {
"x": 0, const otherSpacing = other.spacing !== undefined ? other.spacing : (defaultBar?.spacing ?? 4)
"y": 0, const otherPadding = other.innerPadding !== undefined ? other.innerPadding : (defaultBar?.innerPadding ?? 4)
"width": barThickness + dankBarSpacing + wingSize, const otherThickness = Math.max(26 + otherPadding * 0.6, Theme.barHeight - 4 - (8 - otherPadding)) + otherSpacing + wingSize
"height": screenHeight, const otherBottomGap = other.bottomGap !== undefined ? other.bottomGap : (defaultBar?.bottomGap ?? 0)
"wingSize": wingSize
} switch (other.position) {
} else if (dankBarPosition === SettingsData.Position.Right) { case SettingsData.Position.Top:
return { if (position === SettingsData.Position.Top && other.id < barConfig.id) {
"x": screenWidth - barThickness - dankBarSpacing - wingSize, topOffset += otherThickness // Simple stacking for same pos
"y": 0, } else if (position === SettingsData.Position.Left || position === SettingsData.Position.Right) {
"width": barThickness + dankBarSpacing + wingSize, topOffset = Math.max(topOffset, otherThickness)
"height": screenHeight, }
"wingSize": wingSize break
case SettingsData.Position.Bottom:
if (position === SettingsData.Position.Bottom && other.id < barConfig.id) {
bottomOffset += (otherThickness + otherBottomGap)
} else if (position === SettingsData.Position.Left || position === SettingsData.Position.Right) {
bottomOffset = Math.max(bottomOffset, otherThickness + otherBottomGap)
}
break
case SettingsData.Position.Left:
if (position === SettingsData.Position.Top || position === SettingsData.Position.Bottom) {
leftOffset = Math.max(leftOffset, otherThickness)
} else if (position === SettingsData.Position.Left && other.id < barConfig.id) {
leftOffset += otherThickness
}
break
case SettingsData.Position.Right:
if (position === SettingsData.Position.Top || position === SettingsData.Position.Bottom) {
rightOffset = Math.max(rightOffset, otherThickness)
} else if (position === SettingsData.Position.Right && other.id < barConfig.id) {
rightOffset += otherThickness
}
break
}
} }
} }
switch (position) {
case SettingsData.Position.Top:
return {
"x": leftOffset,
"y": topOffset + bottomGap,
"width": screenWidth - leftOffset - rightOffset,
"height": barThickness + wingSize,
"wingSize": wingSize
}
case SettingsData.Position.Bottom:
return {
"x": leftOffset,
"y": screenHeight - barThickness - wingSize - bottomGap - bottomOffset,
"width": screenWidth - leftOffset - rightOffset,
"height": barThickness + wingSize,
"wingSize": wingSize
}
case SettingsData.Position.Left:
return {
"x": 0,
"y": topOffset,
"width": barThickness + wingSize,
"height": screenHeight - topOffset - bottomOffset,
"wingSize": wingSize
}
case SettingsData.Position.Right:
return {
"x": screenWidth - barThickness - wingSize,
"y": topOffset,
"width": barThickness + wingSize,
"height": screenHeight - topOffset - bottomOffset,
"wingSize": wingSize
}
}
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 } return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
} }
function updateBarConfigs() {
barConfigsChanged()
saveSettings()
}
function getBarConfig(barId) {
return barConfigs.find(cfg => cfg.id === barId) || null
}
function addBarConfig(config) {
const configs = JSON.parse(JSON.stringify(barConfigs))
configs.push(config)
barConfigs = configs
updateBarConfigs()
}
function updateBarConfig(barId, updates) {
const configs = JSON.parse(JSON.stringify(barConfigs))
const index = configs.findIndex(cfg => cfg.id === barId)
if (index === -1) return
const positionChanged = updates.position !== undefined && configs[index].position !== updates.position
Object.assign(configs[index], updates)
barConfigs = configs
updateBarConfigs()
if (positionChanged) {
NotificationService.clearAllPopups()
}
}
function checkBarCollisions(barId) {
const bar = getBarConfig(barId)
if (!bar || !bar.enabled) return []
const conflicts = []
const enabledBars = getEnabledBarConfigs()
for (let i = 0; i < enabledBars.length; i++) {
const other = enabledBars[i]
if (other.id === barId) continue
const samePosition = bar.position === other.position
if (!samePosition) continue
const barScreens = bar.screenPreferences || ["all"]
const otherScreens = other.screenPreferences || ["all"]
const hasAll = barScreens.includes("all") || otherScreens.includes("all")
if (hasAll) {
conflicts.push({
barId: other.id,
barName: other.name,
reason: "Same position on all screens"
})
continue
}
const overlapping = barScreens.some(screen => otherScreens.includes(screen))
if (overlapping) {
conflicts.push({
barId: other.id,
barName: other.name,
reason: "Same position on overlapping screens"
})
}
}
return conflicts
}
function deleteBarConfig(barId) {
if (barId === "default") return
const configs = barConfigs.filter(cfg => cfg.id !== barId)
barConfigs = configs
updateBarConfigs()
}
function getEnabledBarConfigs() {
return barConfigs.filter(cfg => cfg.enabled)
}
function getScreenDisplayName(screen) { function getScreenDisplayName(screen) {
if (!screen) return "" if (!screen) return ""
if (displayNameMode === "model" && screen.model) { if (displayNameMode === "model" && screen.model) {
@@ -686,6 +910,7 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
} }
function sendTestNotifications() { function sendTestNotifications() {
NotificationService.clearAllPopups()
sendTestNotification(0) sendTestNotification(0)
testNotifTimer1.start() testNotifTimer1.start()
testNotifTimer2.start() testNotifTimer2.start()
@@ -765,20 +990,22 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
function setShowDock(enabled) { function setShowDock(enabled) {
showDock = enabled showDock = enabled
if (enabled && dockPosition === dankBarPosition) { const defaultBar = barConfigs[0] || getBarConfig("default")
if (dankBarPosition === SettingsData.Position.Top) { const barPos = defaultBar?.position ?? SettingsData.Position.Top
if (enabled && dockPosition === barPos) {
if (barPos === SettingsData.Position.Top) {
setDockPosition(SettingsData.Position.Bottom) setDockPosition(SettingsData.Position.Bottom)
return return
} }
if (dankBarPosition === SettingsData.Position.Bottom) { if (barPos === SettingsData.Position.Bottom) {
setDockPosition(SettingsData.Position.Top) setDockPosition(SettingsData.Position.Top)
return return
} }
if (dankBarPosition === SettingsData.Position.Left) { if (barPos === SettingsData.Position.Left) {
setDockPosition(SettingsData.Position.Right) setDockPosition(SettingsData.Position.Right)
return return
} }
if (dankBarPosition === SettingsData.Position.Right) { if (barPos === SettingsData.Position.Right) {
setDockPosition(SettingsData.Position.Left) setDockPosition(SettingsData.Position.Left)
return return
} }
@@ -788,16 +1015,18 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
function setDockPosition(position) { function setDockPosition(position) {
dockPosition = position dockPosition = position
if (position === SettingsData.Position.Bottom && dankBarPosition === SettingsData.Position.Bottom && showDock) { const defaultBar = barConfigs[0] || getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
if (position === SettingsData.Position.Bottom && barPos === SettingsData.Position.Bottom && showDock) {
setDankBarPosition(SettingsData.Position.Top) setDankBarPosition(SettingsData.Position.Top)
} }
if (position === SettingsData.Position.Top && dankBarPosition === SettingsData.Position.Top && showDock) { if (position === SettingsData.Position.Top && barPos === SettingsData.Position.Top && showDock) {
setDankBarPosition(SettingsData.Position.Bottom) setDankBarPosition(SettingsData.Position.Bottom)
} }
if (position === SettingsData.Position.Left && dankBarPosition === SettingsData.Position.Left && showDock) { if (position === SettingsData.Position.Left && barPos === SettingsData.Position.Left && showDock) {
setDankBarPosition(SettingsData.Position.Right) setDankBarPosition(SettingsData.Position.Right)
} }
if (position === SettingsData.Position.Right && dankBarPosition === SettingsData.Position.Right && showDock) { if (position === SettingsData.Position.Right && barPos === SettingsData.Position.Right && showDock) {
setDankBarPosition(SettingsData.Position.Left) setDankBarPosition(SettingsData.Position.Left)
} }
saveSettings() saveSettings()
@@ -805,14 +1034,19 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
} }
function setDankBarSpacing(spacing) { function setDankBarSpacing(spacing) {
set("dankBarSpacing", spacing) const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
updateBarConfig(defaultBar.id, { spacing: spacing })
}
if (typeof NiriService !== "undefined" && CompositorService.isNiri) { if (typeof NiriService !== "undefined" && CompositorService.isNiri) {
NiriService.generateNiriLayoutConfig() NiriService.generateNiriLayoutConfig()
} }
} }
function setDankBarPosition(position) { function setDankBarPosition(position) {
dankBarPosition = position const defaultBar = barConfigs[0] || getBarConfig("default")
if (!defaultBar) return
if (position === SettingsData.Position.Bottom && dockPosition === SettingsData.Position.Bottom && showDock) { if (position === SettingsData.Position.Bottom && dockPosition === SettingsData.Position.Bottom && showDock) {
setDockPosition(SettingsData.Position.Top) setDockPosition(SettingsData.Position.Top)
return return
@@ -829,34 +1063,45 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
setDockPosition(SettingsData.Position.Left) setDockPosition(SettingsData.Position.Left)
return return
} }
saveSettings() updateBarConfig(defaultBar.id, { position: position })
} }
function setDankBarLeftWidgets(order) { function setDankBarLeftWidgets(order) {
dankBarLeftWidgets = order const defaultBar = barConfigs[0] || getBarConfig("default")
updateListModel(leftWidgetsModel, order) if (defaultBar) {
saveSettings() updateBarConfig(defaultBar.id, { leftWidgets: order })
updateListModel(leftWidgetsModel, order)
}
} }
function setDankBarCenterWidgets(order) { function setDankBarCenterWidgets(order) {
dankBarCenterWidgets = order const defaultBar = barConfigs[0] || getBarConfig("default")
updateListModel(centerWidgetsModel, order) if (defaultBar) {
saveSettings() updateBarConfig(defaultBar.id, { centerWidgets: order })
updateListModel(centerWidgetsModel, order)
}
} }
function setDankBarRightWidgets(order) { function setDankBarRightWidgets(order) {
dankBarRightWidgets = order const defaultBar = barConfigs[0] || getBarConfig("default")
updateListModel(rightWidgetsModel, order) if (defaultBar) {
saveSettings() updateBarConfig(defaultBar.id, { rightWidgets: order })
updateListModel(rightWidgetsModel, order)
}
} }
function resetDankBarWidgetsToDefault() { function resetDankBarWidgetsToDefault() {
var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"] var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"]
var defaultCenter = ["music", "clock", "weather"] var defaultCenter = ["music", "clock", "weather"]
var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"] var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"]
dankBarLeftWidgets = defaultLeft const defaultBar = barConfigs[0] || getBarConfig("default")
dankBarCenterWidgets = defaultCenter if (defaultBar) {
dankBarRightWidgets = defaultRight updateBarConfig(defaultBar.id, {
leftWidgets: defaultLeft,
centerWidgets: defaultCenter,
rightWidgets: defaultRight
})
}
updateListModel(leftWidgetsModel, defaultLeft) updateListModel(leftWidgetsModel, defaultLeft)
updateListModel(centerWidgetsModel, defaultCenter) updateListModel(centerWidgetsModel, defaultCenter)
updateListModel(rightWidgetsModel, defaultRight) updateListModel(rightWidgetsModel, defaultRight)
@@ -876,7 +1121,6 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
showBattery = true showBattery = true
showControlCenterButton = true showControlCenterButton = true
showCapsLockIndicator = true showCapsLockIndicator = true
saveSettings()
} }
function setWorkspaceNameIcon(workspaceName, iconData) { function setWorkspaceNameIcon(workspaceName, iconData) {
@@ -900,8 +1144,10 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
} }
function toggleDankBarVisible() { function toggleDankBarVisible() {
dankBarVisible = !dankBarVisible const defaultBar = barConfigs[0] || getBarConfig("default")
saveSettings() if (defaultBar) {
updateBarConfig(defaultBar.id, { visible: !defaultBar.visible })
}
} }
function toggleShowDock() { function toggleShowDock() {
@@ -1028,31 +1274,6 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
property bool pluginSettingsFileExists: false property bool pluginSettingsFileExists: false
IpcHandler {
function reveal(): string {
root.dankBarVisible = true
root.saveSettings()
return "BAR_SHOW_SUCCESS"
}
function hide(): string {
root.dankBarVisible = false
root.saveSettings()
return "BAR_HIDE_SUCCESS"
}
function toggle(): string {
root.toggleDankBarVisible()
return root.dankBarVisible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"
}
function status(): string {
return root.dankBarVisible ? "visible" : "hidden"
}
target: "bar"
}
IpcHandler { IpcHandler {
function reveal(): string { function reveal(): string {
root.setShowDock(true) root.setShowDock(true)

View File

@@ -15,6 +15,7 @@ import "StockThemes.js" as StockThemes
Singleton { Singleton {
id: root id: root
readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericCacheLocation).toString()) + "/DankMaterialShell" readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericCacheLocation).toString()) + "/DankMaterialShell"
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true" readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
@@ -22,7 +23,12 @@ Singleton {
readonly property real popupDistance: { readonly property real popupDistance: {
if (typeof SettingsData === "undefined") if (typeof SettingsData === "undefined")
return 4 return 4
return SettingsData.popupGapsAuto ? Math.max(4, SettingsData.dankBarSpacing) : SettingsData.popupGapsManual const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar) return 4
const useAuto = defaultBar.popupGapsAuto ?? true
const manualValue = defaultBar.popupGapsManual ?? 4
const spacing = defaultBar.spacing ?? 4
return useAuto ? Math.max(4, spacing) : manualValue
} }
property string currentTheme: "blue" property string currentTheme: "blue"
@@ -465,7 +471,6 @@ Singleton {
property real iconSizeLarge: 32 property real iconSizeLarge: 32
property real panelTransparency: 0.85 property real panelTransparency: 0.85
property real widgetTransparency: typeof SettingsData !== "undefined" && SettingsData.dankBarWidgetTransparency !== undefined ? SettingsData.dankBarWidgetTransparency : 1.0
property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0 property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0
function screenTransition() { function screenTransition() {
@@ -650,20 +655,6 @@ Singleton {
return isLightMode ? Qt.darker(baseColor, factor) : Qt.lighter(baseColor, factor) return isLightMode ? Qt.darker(baseColor, factor) : Qt.lighter(baseColor, factor)
} }
property var widgetBackground: {
const colorMode = typeof SettingsData !== "undefined" ? SettingsData.widgetBackgroundColor : "sch"
switch (colorMode) {
case "s":
return Qt.rgba(surface.r, surface.g, surface.b, widgetTransparency)
case "sc":
return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, widgetTransparency)
case "sch":
return Qt.rgba(surfaceContainerHigh.r, surfaceContainerHigh.g, surfaceContainerHigh.b, widgetTransparency)
case "sth":
default:
return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, widgetTransparency)
}
}
property color widgetIconColor: { property color widgetIconColor: {
if (typeof SettingsData === "undefined") { if (typeof SettingsData === "undefined") {
@@ -703,9 +694,9 @@ Singleton {
return Math.round((barThickness / 48) * (iconSize + defaultOffset)) return Math.round((barThickness / 48) * (iconSize + defaultOffset))
} }
function barTextSize(barThickness) { function barTextSize(barThickness, fontScale) {
const scale = barThickness / 48 const scale = barThickness / 48
const dankBarScale = (typeof SettingsData !== "undefined" ? SettingsData.dankBarFontScale : 1.0) const dankBarScale = fontScale !== undefined ? fontScale : 1.0
if (scale <= 0.75) if (scale <= 0.75)
return Math.round(fontSizeSmall * 0.9 * dankBarScale) return Math.round(fontSizeSmall * 0.9 * dankBarScale)
if (scale >= 1.25) if (scale >= 1.25)

View File

@@ -6,26 +6,30 @@ import QtQuick
Singleton { Singleton {
id: root id: root
property var activeTrayBars: ({}) property var activeTrayMenus: ({})
function register(screenName, trayBar) { function registerMenu(screenName, menu) {
if (!screenName || !trayBar) return if (!screenName || !menu) return
activeTrayBars[screenName] = trayBar const newMenus = Object.assign({}, activeTrayMenus)
newMenus[screenName] = menu
activeTrayMenus = newMenus
} }
function unregister(screenName) { function unregisterMenu(screenName) {
if (!screenName) return if (!screenName) return
delete activeTrayBars[screenName] const newMenus = Object.assign({}, activeTrayMenus)
delete newMenus[screenName]
activeTrayMenus = newMenus
} }
function closeAllMenus() { function closeAllMenus() {
for (const screenName in activeTrayBars) { for (const screenName in activeTrayMenus) {
const trayBar = activeTrayBars[screenName] const menu = activeTrayMenus[screenName]
if (!trayBar) continue if (!menu) continue
if (typeof menu.close === "function") {
trayBar.menuOpen = false menu.close()
if (trayBar.currentTrayMenu) { } else if (menu.showMenu !== undefined) {
trayBar.currentTrayMenu.showMenu = false menu.showMenu = false
} }
} }
} }

View File

@@ -12,8 +12,6 @@ var SPEC = {
runUserMatugenTemplates: { def: true, onChange: "regenSystemThemes" }, runUserMatugenTemplates: { def: true, onChange: "regenSystemThemes" },
matugenTargetMonitor: { def: "", onChange: "regenSystemThemes" }, matugenTargetMonitor: { def: "", onChange: "regenSystemThemes" },
dankBarTransparency: { def: 1.0, coerce: percentToUnit, migrate: ["topBarTransparency"] },
dankBarWidgetTransparency: { def: 1.0, coerce: percentToUnit, migrate: ["topBarWidgetTransparency"] },
popupTransparency: { def: 1.0, coerce: percentToUnit }, popupTransparency: { def: 1.0, coerce: percentToUnit },
dockTransparency: { def: 1.0, coerce: percentToUnit }, dockTransparency: { def: 1.0, coerce: percentToUnit },
@@ -89,11 +87,6 @@ var SPEC = {
lockDateFormat: { def: "" }, lockDateFormat: { def: "" },
mediaSize: { def: 1 }, mediaSize: { def: 1 },
dankBarLeftWidgets: { def: ["launcherButton", "workspaceSwitcher", "focusedWindow"], migrate: ["topBarLeftWidgets"] },
dankBarCenterWidgets: { def: ["music", "clock", "weather"], migrate: ["topBarCenterWidgets"] },
dankBarRightWidgets: { def: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"], migrate: ["topBarRightWidgets"] },
dankBarWidgetOrder: { def: [] },
appLauncherViewMode: { def: "list" }, appLauncherViewMode: { def: "list" },
spotlightModalViewMode: { def: "list" }, spotlightModalViewMode: { def: "list" },
sortAppsAlphabetically: { def: false }, sortAppsAlphabetically: { def: false },
@@ -127,7 +120,6 @@ var SPEC = {
monoFontFamily: { def: "Fira Code" }, monoFontFamily: { def: "Fira Code" },
fontWeight: { def: 400 }, fontWeight: { def: 400 },
fontScale: { def: 1.0 }, fontScale: { def: 1.0 },
dankBarFontScale: { def: 1.0 },
notepadUseMonospace: { def: true }, notepadUseMonospace: { def: true },
notepadFontFamily: { def: "" }, notepadFontFamily: { def: "" },
@@ -177,31 +169,9 @@ var SPEC = {
dockIndicatorStyle: { def: "circle" }, dockIndicatorStyle: { def: "circle" },
notificationOverlayEnabled: { def: false }, notificationOverlayEnabled: { def: false },
dankBarAutoHide: { def: false, migrate: ["topBarAutoHide"] },
dankBarAutoHideDelay: { def: 250 },
dankBarOpenOnOverview: { def: false, migrate: ["topBarOpenOnOverview"] },
dankBarVisible: { def: true, migrate: ["topBarVisible"] },
overviewRows: { def: 2, persist: false }, overviewRows: { def: 2, persist: false },
overviewColumns: { def: 5, persist: false }, overviewColumns: { def: 5, persist: false },
overviewScale: { def: 0.16, persist: false }, overviewScale: { def: 0.16, persist: false },
dankBarSpacing: { def: 4, migrate: ["topBarSpacing"], onChange: "updateNiriLayout" },
dankBarBottomGap: { def: 0, migrate: ["topBarBottomGap"] },
dankBarInnerPadding: { def: 4, migrate: ["topBarInnerPadding"] },
dankBarPosition: { def: 0, migrate: ["dankBarAtBottom", "topBarAtBottom"] },
dankBarIsVertical: { def: false, persist: false },
dankBarSquareCorners: { def: false, migrate: ["topBarSquareCorners"] },
dankBarNoBackground: { def: false, migrate: ["topBarNoBackground"] },
dankBarGothCornersEnabled: { def: false, migrate: ["topBarGothCornersEnabled"] },
dankBarGothCornerRadiusOverride: { def: false },
dankBarGothCornerRadiusValue: { def: 12 },
dankBarBorderEnabled: { def: false },
dankBarBorderColor: { def: "surfaceText" },
dankBarBorderOpacity: { def: 1.0 },
dankBarBorderThickness: { def: 1 },
popupGapsAuto: { def: true },
popupGapsManual: { def: 4 },
modalDarkenBackground: { def: true }, modalDarkenBackground: { def: true },
@@ -242,7 +212,40 @@ var SPEC = {
displayNameMode: { def: "system" }, displayNameMode: { def: "system" },
screenPreferences: { def: {} }, screenPreferences: { def: {} },
showOnLastDisplay: { def: {} } showOnLastDisplay: { def: {} },
barConfigs: { def: [{
id: "default",
name: "Main Bar",
enabled: true,
position: 0,
screenPreferences: ["all"],
showOnLastDisplay: true,
leftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"],
centerWidgets: ["music", "clock", "weather"],
rightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"],
spacing: 4,
innerPadding: 4,
bottomGap: 0,
transparency: 1.0,
widgetTransparency: 1.0,
squareCorners: false,
noBackground: false,
gothCornersEnabled: false,
gothCornerRadiusOverride: false,
gothCornerRadiusValue: 12,
borderEnabled: false,
borderColor: "surfaceText",
borderOpacity: 1.0,
borderThickness: 1,
fontScale: 1.0,
autoHide: false,
autoHideDelay: 250,
openOnOverview: false,
visible: true,
popupGapsAuto: true,
popupGapsManual: 4
}], onChange: "updateBarConfigs" }
}; };
function getValidKeys() { function getValidKeys() {

View File

@@ -5,6 +5,7 @@
function parse(root, jsonObj) { function parse(root, jsonObj) {
var SPEC = SpecModule.SPEC; var SPEC = SpecModule.SPEC;
for (var k in SPEC) { for (var k in SPEC) {
if (k === "pluginSettings") continue;
var spec = SPEC[k]; var spec = SPEC[k];
root[k] = spec.def; root[k] = spec.def;
} }
@@ -13,6 +14,7 @@ function parse(root, jsonObj) {
for (var k in jsonObj) { for (var k in jsonObj) {
if (!SPEC[k]) continue; if (!SPEC[k]) continue;
if (k === "pluginSettings") continue;
var raw = jsonObj[k]; var raw = jsonObj[k];
var spec = SPEC[k]; var spec = SPEC[k];
var coerce = spec.coerce; var coerce = spec.coerce;
@@ -25,72 +27,93 @@ function toJson(root) {
var out = {}; var out = {};
for (var k in SPEC) { for (var k in SPEC) {
if (SPEC[k].persist === false) continue; if (SPEC[k].persist === false) continue;
if (k === "pluginSettings") continue;
out[k] = root[k]; out[k] = root[k];
} }
out.configVersion = root.settingsConfigVersion; out.configVersion = root.settingsConfigVersion;
return out; return out;
} }
function migrate(root, jsonObj) { function migrateToVersion(obj, targetVersion) {
var SPEC = SpecModule.SPEC; if (!obj) return null;
if (!jsonObj) return;
if (jsonObj.themeIndex !== undefined || jsonObj.themeIsDynamic !== undefined) { var settings = JSON.parse(JSON.stringify(obj));
var themeNames = ["blue", "deepBlue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral"]; var currentVersion = settings.configVersion || 0;
if (jsonObj.themeIsDynamic) {
root.currentThemeName = "dynamic"; if (currentVersion >= targetVersion) {
} else if (jsonObj.themeIndex >= 0 && jsonObj.themeIndex < themeNames.length) { return null;
root.currentThemeName = themeNames[jsonObj.themeIndex];
}
console.info("Auto-migrated theme from index", jsonObj.themeIndex, "to", root.currentThemeName);
} }
if ((jsonObj.dankBarWidgetOrder && jsonObj.dankBarWidgetOrder.length > 0) || if (currentVersion < 2) {
(jsonObj.topBarWidgetOrder && jsonObj.topBarWidgetOrder.length > 0)) { console.info("Migrating settings from version", currentVersion, "to version 2");
if (jsonObj.dankBarLeftWidgets === undefined && jsonObj.dankBarCenterWidgets === undefined && jsonObj.dankBarRightWidgets === undefined) {
var widgetOrder = jsonObj.dankBarWidgetOrder || jsonObj.topBarWidgetOrder;
root.dankBarLeftWidgets = widgetOrder.filter(function(w) { return ["launcherButton", "workspaceSwitcher", "focusedWindow"].indexOf(w) >= 0; });
root.dankBarCenterWidgets = widgetOrder.filter(function(w) { return ["clock", "music", "weather"].indexOf(w) >= 0; });
root.dankBarRightWidgets = widgetOrder.filter(function(w) { return ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].indexOf(w) >= 0; });
}
}
if (jsonObj.useOSLogo !== undefined) { if (settings.barConfigs === undefined) {
root.launcherLogoMode = jsonObj.useOSLogo ? "os" : "apps"; var position = 0;
root.launcherLogoColorOverride = jsonObj.osLogoColorOverride !== undefined ? jsonObj.osLogoColorOverride : ""; if (settings.dankBarAtBottom !== undefined || settings.topBarAtBottom !== undefined) {
root.launcherLogoBrightness = jsonObj.osLogoBrightness !== undefined ? jsonObj.osLogoBrightness : 0.5; var atBottom = settings.dankBarAtBottom !== undefined ? settings.dankBarAtBottom : settings.topBarAtBottom;
root.launcherLogoContrast = jsonObj.osLogoContrast !== undefined ? jsonObj.osLogoContrast : 1; position = atBottom ? 1 : 0;
} } else if (settings.dankBarPosition !== undefined) {
position = settings.dankBarPosition;
if (jsonObj.mediaCompactMode !== undefined && jsonObj.mediaSize === undefined) {
root.mediaSize = jsonObj.mediaCompactMode ? 0 : 1;
}
for (var k in SPEC) {
var spec = SPEC[k];
if (!spec.migrate) continue;
for (var i = 0; i < spec.migrate.length; i++) {
var oldKey = spec.migrate[i];
if (jsonObj[oldKey] !== undefined && jsonObj[k] === undefined) {
var raw = jsonObj[oldKey];
var coerce = spec.coerce;
root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw;
break;
} }
var defaultConfig = {
id: "default",
name: "Main Bar",
enabled: true,
position: position,
screenPreferences: ["all"],
showOnLastDisplay: true,
leftWidgets: settings.dankBarLeftWidgets || ["launcherButton", "workspaceSwitcher", "focusedWindow"],
centerWidgets: settings.dankBarCenterWidgets || ["music", "clock", "weather"],
rightWidgets: settings.dankBarRightWidgets || ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"],
spacing: settings.dankBarSpacing !== undefined ? settings.dankBarSpacing : 4,
innerPadding: settings.dankBarInnerPadding !== undefined ? settings.dankBarInnerPadding : 4,
bottomGap: settings.dankBarBottomGap !== undefined ? settings.dankBarBottomGap : 0,
transparency: settings.dankBarTransparency !== undefined ? settings.dankBarTransparency : 1.0,
widgetTransparency: settings.dankBarWidgetTransparency !== undefined ? settings.dankBarWidgetTransparency : 1.0,
squareCorners: settings.dankBarSquareCorners !== undefined ? settings.dankBarSquareCorners : false,
noBackground: settings.dankBarNoBackground !== undefined ? settings.dankBarNoBackground : false,
gothCornersEnabled: settings.dankBarGothCornersEnabled !== undefined ? settings.dankBarGothCornersEnabled : false,
gothCornerRadiusOverride: settings.dankBarGothCornerRadiusOverride !== undefined ? settings.dankBarGothCornerRadiusOverride : false,
gothCornerRadiusValue: settings.dankBarGothCornerRadiusValue !== undefined ? settings.dankBarGothCornerRadiusValue : 12,
borderEnabled: settings.dankBarBorderEnabled !== undefined ? settings.dankBarBorderEnabled : false,
borderColor: settings.dankBarBorderColor || "surfaceText",
borderOpacity: settings.dankBarBorderOpacity !== undefined ? settings.dankBarBorderOpacity : 1.0,
borderThickness: settings.dankBarBorderThickness !== undefined ? settings.dankBarBorderThickness : 1,
fontScale: settings.dankBarFontScale !== undefined ? settings.dankBarFontScale : 1.0,
autoHide: settings.dankBarAutoHide !== undefined ? settings.dankBarAutoHide : false,
autoHideDelay: settings.dankBarAutoHideDelay !== undefined ? settings.dankBarAutoHideDelay : 250,
openOnOverview: settings.dankBarOpenOnOverview !== undefined ? settings.dankBarOpenOnOverview : false,
visible: settings.dankBarVisible !== undefined ? settings.dankBarVisible : true,
popupGapsAuto: settings.popupGapsAuto !== undefined ? settings.popupGapsAuto : true,
popupGapsManual: settings.popupGapsManual !== undefined ? settings.popupGapsManual : 4
};
settings.barConfigs = [defaultConfig];
var legacyKeys = [
"dankBarLeftWidgets", "dankBarCenterWidgets", "dankBarRightWidgets",
"dankBarWidgetOrder", "dankBarAutoHide", "dankBarAutoHideDelay",
"dankBarOpenOnOverview", "dankBarVisible", "dankBarSpacing",
"dankBarBottomGap", "dankBarInnerPadding", "dankBarPosition",
"dankBarSquareCorners", "dankBarNoBackground", "dankBarGothCornersEnabled",
"dankBarGothCornerRadiusOverride", "dankBarGothCornerRadiusValue",
"dankBarBorderEnabled", "dankBarBorderColor", "dankBarBorderOpacity",
"dankBarBorderThickness", "popupGapsAuto", "popupGapsManual",
"dankBarAtBottom", "topBarAtBottom", "dankBarTransparency", "dankBarWidgetTransparency"
];
for (var i = 0; i < legacyKeys.length; i++) {
delete settings[legacyKeys[i]];
}
console.info("Migrated single bar settings to barConfigs");
} }
settings.configVersion = 2;
} }
if (jsonObj.dankBarAtBottom !== undefined || jsonObj.topBarAtBottom !== undefined) { return settings;
var atBottom = jsonObj.dankBarAtBottom !== undefined ? jsonObj.dankBarAtBottom : jsonObj.topBarAtBottom;
root.dankBarPosition = atBottom ? 1 : 0;
}
if (jsonObj.pluginSettings !== undefined) {
root.pluginSettings = jsonObj.pluginSettings;
return true;
}
return false;
} }
function cleanup(fileText) { function cleanup(fileText) {
@@ -104,7 +127,6 @@ function cleanup(fileText) {
for (var key in settings) { for (var key in settings) {
if (validKeys.indexOf(key) < 0) { if (validKeys.indexOf(key) < 0) {
console.log("SettingsData: Removing unused key:", key);
delete settings[key]; delete settings[key];
needsSave = true; needsSave = true;
} }

View File

@@ -66,38 +66,32 @@ Item {
id: lock id: lock
} }
Loader { Repeater {
id: dankBarLoader id: dankBarRepeater
asynchronous: false model: ScriptModel {
values: SettingsData.barConfigs
}
property var currentPosition: SettingsData.dankBarPosition
property bool initialized: false
property var hyprlandOverviewLoaderRef: hyprlandOverviewLoader property var hyprlandOverviewLoaderRef: hyprlandOverviewLoader
sourceComponent: DankBar { delegate: Loader {
hyprlandOverviewLoader: dankBarLoader.hyprlandOverviewLoaderRef id: barLoader
active: modelData.enabled
asynchronous: false
onColorPickerRequested: { sourceComponent: DankBar {
if (colorPickerModal.shouldBeVisible) { barConfig: modelData
colorPickerModal.close() hyprlandOverviewLoader: dankBarRepeater.hyprlandOverviewLoaderRef
} else {
colorPickerModal.show() onColorPickerRequested: {
if (colorPickerModal.shouldBeVisible) {
colorPickerModal.close()
} else {
colorPickerModal.show()
}
} }
} }
} }
Component.onCompleted: {
initialized = true
}
onCurrentPositionChanged: {
if (!initialized)
return
const component = sourceComponent
sourceComponent = null
sourceComponent = component
}
} }
Loader { Loader {
@@ -126,7 +120,6 @@ Item {
if (!initialized) if (!initialized)
return return
console.log("DEBUG: Dock position changed to:", currentPosition, "- recreating dock")
const comp = sourceComponent const comp = sourceComponent
sourceComponent = null sourceComponent = null
sourceComponent = comp sourceComponent = comp
@@ -137,7 +130,7 @@ Item {
id: dankDashPopoutLoader id: dankDashPopoutLoader
active: false active: false
asynchronous: true asynchronous: false
sourceComponent: Component { sourceComponent: Component {
DankDashPopout { DankDashPopout {
@@ -513,7 +506,7 @@ Item {
dankDashPopoutLoader: dankDashPopoutLoader dankDashPopoutLoader: dankDashPopoutLoader
notepadSlideoutVariants: notepadSlideoutVariants notepadSlideoutVariants: notepadSlideoutVariants
hyprKeybindsModalLoader: hyprKeybindsModalLoader hyprKeybindsModalLoader: hyprKeybindsModalLoader
dankBarLoader: dankBarLoader dankBarRepeater: dankBarRepeater
hyprlandOverviewLoader: hyprlandOverviewLoader hyprlandOverviewLoader: hyprlandOverviewLoader
} }

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Hyprland import Quickshell.Hyprland
import qs.Common import qs.Common
@@ -14,36 +13,43 @@ Item {
required property var dankDashPopoutLoader required property var dankDashPopoutLoader
required property var notepadSlideoutVariants required property var notepadSlideoutVariants
required property var hyprKeybindsModalLoader required property var hyprKeybindsModalLoader
required property var dankBarLoader required property var dankBarRepeater
required property var hyprlandOverviewLoader required property var hyprlandOverviewLoader
function getFirstBar() {
if (!root.dankBarRepeater || root.dankBarRepeater.count === 0)
return null;
const firstLoader = root.dankBarRepeater.itemAt(0);
return firstLoader ? firstLoader.item : null;
}
IpcHandler { IpcHandler {
function open() { function open() {
root.powerMenuModalLoader.active = true root.powerMenuModalLoader.active = true;
if (root.powerMenuModalLoader.item) if (root.powerMenuModalLoader.item)
root.powerMenuModalLoader.item.openCentered() root.powerMenuModalLoader.item.openCentered();
return "POWERMENU_OPEN_SUCCESS" return "POWERMENU_OPEN_SUCCESS";
} }
function close() { function close() {
if (root.powerMenuModalLoader.item) if (root.powerMenuModalLoader.item)
root.powerMenuModalLoader.item.close() root.powerMenuModalLoader.item.close();
return "POWERMENU_CLOSE_SUCCESS" return "POWERMENU_CLOSE_SUCCESS";
} }
function toggle() { function toggle() {
root.powerMenuModalLoader.active = true root.powerMenuModalLoader.active = true;
if (root.powerMenuModalLoader.item) { if (root.powerMenuModalLoader.item) {
if (root.powerMenuModalLoader.item.shouldBeVisible) { if (root.powerMenuModalLoader.item.shouldBeVisible) {
root.powerMenuModalLoader.item.close() root.powerMenuModalLoader.item.close();
} else { } else {
root.powerMenuModalLoader.item.openCentered() root.powerMenuModalLoader.item.openCentered();
} }
} }
return "POWERMENU_TOGGLE_SUCCESS" return "POWERMENU_TOGGLE_SUCCESS";
} }
target: "powermenu" target: "powermenu"
@@ -51,26 +57,26 @@ Item {
IpcHandler { IpcHandler {
function open(): string { function open(): string {
root.processListModalLoader.active = true root.processListModalLoader.active = true;
if (root.processListModalLoader.item) if (root.processListModalLoader.item)
root.processListModalLoader.item.show() root.processListModalLoader.item.show();
return "PROCESSLIST_OPEN_SUCCESS" return "PROCESSLIST_OPEN_SUCCESS";
} }
function close(): string { function close(): string {
if (root.processListModalLoader.item) if (root.processListModalLoader.item)
root.processListModalLoader.item.hide() root.processListModalLoader.item.hide();
return "PROCESSLIST_CLOSE_SUCCESS" return "PROCESSLIST_CLOSE_SUCCESS";
} }
function toggle(): string { function toggle(): string {
root.processListModalLoader.active = true root.processListModalLoader.active = true;
if (root.processListModalLoader.item) if (root.processListModalLoader.item)
root.processListModalLoader.item.toggle() root.processListModalLoader.item.toggle();
return "PROCESSLIST_TOGGLE_SUCCESS" return "PROCESSLIST_TOGGLE_SUCCESS";
} }
target: "processlist" target: "processlist"
@@ -78,27 +84,33 @@ Item {
IpcHandler { IpcHandler {
function open(): string { function open(): string {
if (root.dankBarLoader.item) { const bar = root.getFirstBar();
root.dankBarLoader.item.triggerControlCenterOnFocusedScreen() if (bar) {
return "CONTROL_CENTER_OPEN_SUCCESS" bar.triggerControlCenterOnFocusedScreen();
return "CONTROL_CENTER_OPEN_SUCCESS";
} }
return "CONTROL_CENTER_OPEN_FAILED" return "CONTROL_CENTER_OPEN_FAILED";
} }
function close(): string { function hide(): string {
if (root.controlCenterLoader.item) { if (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) {
root.controlCenterLoader.item.close() root.controlCenterLoader.item.close();
return "CONTROL_CENTER_CLOSE_SUCCESS" return "CONTROL_CENTER_HIDE_SUCCESS";
} }
return "CONTROL_CENTER_CLOSE_FAILED" return "CONTROL_CENTER_HIDE_FAILED";
} }
function toggle(): string { function toggle(): string {
if (root.dankBarLoader.item) { const bar = root.getFirstBar();
root.dankBarLoader.item.triggerControlCenterOnFocusedScreen() if (bar) {
return "CONTROL_CENTER_TOGGLE_SUCCESS" bar.triggerControlCenterOnFocusedScreen();
return "CONTROL_CENTER_TOGGLE_SUCCESS";
} }
return "CONTROL_CENTER_TOGGLE_FAILED" return "CONTROL_CENTER_TOGGLE_FAILED";
}
function status(): string {
return (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) ? "visible" : "hidden";
} }
target: "control-center" target: "control-center"
@@ -106,55 +118,56 @@ Item {
IpcHandler { IpcHandler {
function open(tab: string): string { function open(tab: string): string {
root.dankDashPopoutLoader.active = true root.dankDashPopoutLoader.active = true;
if (root.dankDashPopoutLoader.item) { if (root.dankDashPopoutLoader.item) {
switch (tab.toLowerCase()) { switch (tab.toLowerCase()) {
case "media": case "media":
root.dankDashPopoutLoader.item.currentTabIndex = 1 root.dankDashPopoutLoader.item.currentTabIndex = 1;
break break;
case "weather": case "weather":
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0 root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0;
break break;
default: default:
root.dankDashPopoutLoader.item.currentTabIndex = 0 root.dankDashPopoutLoader.item.currentTabIndex = 0;
break break;
} }
root.dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen) root.dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen);
root.dankDashPopoutLoader.item.dashVisible = true root.dankDashPopoutLoader.item.dashVisible = true;
return "DASH_OPEN_SUCCESS" return "DASH_OPEN_SUCCESS";
} }
return "DASH_OPEN_FAILED" return "DASH_OPEN_FAILED";
} }
function close(): string { function close(): string {
if (root.dankDashPopoutLoader.item) { if (root.dankDashPopoutLoader.item) {
root.dankDashPopoutLoader.item.dashVisible = false root.dankDashPopoutLoader.item.dashVisible = false;
return "DASH_CLOSE_SUCCESS" return "DASH_CLOSE_SUCCESS";
} }
return "DASH_CLOSE_FAILED" return "DASH_CLOSE_FAILED";
} }
function toggle(tab: string): string { function toggle(tab: string): string {
if (root.dankBarLoader.item && root.dankBarLoader.item.triggerWallpaperBrowserOnFocusedScreen()) { const bar = root.getFirstBar();
if (bar && bar.triggerWallpaperBrowserOnFocusedScreen()) {
if (root.dankDashPopoutLoader.item) { if (root.dankDashPopoutLoader.item) {
switch (tab.toLowerCase()) { switch (tab.toLowerCase()) {
case "media": case "media":
root.dankDashPopoutLoader.item.currentTabIndex = 1 root.dankDashPopoutLoader.item.currentTabIndex = 1;
break break;
case "wallpaper": case "wallpaper":
root.dankDashPopoutLoader.item.currentTabIndex = 2 root.dankDashPopoutLoader.item.currentTabIndex = 2;
break break;
case "weather": case "weather":
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0 root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0;
break break;
default: default:
root.dankDashPopoutLoader.item.currentTabIndex = 0 root.dankDashPopoutLoader.item.currentTabIndex = 0;
break break;
} }
} }
return "DASH_TOGGLE_SUCCESS" return "DASH_TOGGLE_SUCCESS";
} }
return "DASH_TOGGLE_FAILED" return "DASH_TOGGLE_FAILED";
} }
target: "dash" target: "dash"
@@ -163,68 +176,68 @@ Item {
IpcHandler { IpcHandler {
function getFocusedScreenName() { function getFocusedScreenName() {
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
return Hyprland.focusedWorkspace.monitor.name return Hyprland.focusedWorkspace.monitor.name;
} }
if (CompositorService.isNiri && NiriService.currentOutput) { if (CompositorService.isNiri && NiriService.currentOutput) {
return NiriService.currentOutput return NiriService.currentOutput;
} }
return "" return "";
} }
function getActiveNotepadInstance() { function getActiveNotepadInstance() {
if (root.notepadSlideoutVariants.instances.length === 0) { if (root.notepadSlideoutVariants.instances.length === 0) {
return null return null;
} }
if (root.notepadSlideoutVariants.instances.length === 1) { if (root.notepadSlideoutVariants.instances.length === 1) {
return root.notepadSlideoutVariants.instances[0] return root.notepadSlideoutVariants.instances[0];
} }
var focusedScreen = getFocusedScreenName() var focusedScreen = getFocusedScreenName();
if (focusedScreen && root.notepadSlideoutVariants.instances.length > 0) { if (focusedScreen && root.notepadSlideoutVariants.instances.length > 0) {
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) { for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
var slideout = root.notepadSlideoutVariants.instances[i] var slideout = root.notepadSlideoutVariants.instances[i];
if (slideout.modelData && slideout.modelData.name === focusedScreen) { if (slideout.modelData && slideout.modelData.name === focusedScreen) {
return slideout return slideout;
} }
} }
} }
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) { for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
var slideout = root.notepadSlideoutVariants.instances[i] var slideout = root.notepadSlideoutVariants.instances[i];
if (slideout.isVisible) { if (slideout.isVisible) {
return slideout return slideout;
} }
} }
return root.notepadSlideoutVariants.instances[0] return root.notepadSlideoutVariants.instances[0];
} }
function open(): string { function open(): string {
var instance = getActiveNotepadInstance() var instance = getActiveNotepadInstance();
if (instance) { if (instance) {
instance.show() instance.show();
return "NOTEPAD_OPEN_SUCCESS" return "NOTEPAD_OPEN_SUCCESS";
} }
return "NOTEPAD_OPEN_FAILED" return "NOTEPAD_OPEN_FAILED";
} }
function close(): string { function close(): string {
var instance = getActiveNotepadInstance() var instance = getActiveNotepadInstance();
if (instance) { if (instance) {
instance.hide() instance.hide();
return "NOTEPAD_CLOSE_SUCCESS" return "NOTEPAD_CLOSE_SUCCESS";
} }
return "NOTEPAD_CLOSE_FAILED" return "NOTEPAD_CLOSE_FAILED";
} }
function toggle(): string { function toggle(): string {
var instance = getActiveNotepadInstance() var instance = getActiveNotepadInstance();
if (instance) { if (instance) {
instance.toggle() instance.toggle();
return "NOTEPAD_TOGGLE_SUCCESS" return "NOTEPAD_TOGGLE_SUCCESS";
} }
return "NOTEPAD_TOGGLE_FAILED" return "NOTEPAD_TOGGLE_FAILED";
} }
target: "notepad" target: "notepad"
@@ -232,31 +245,31 @@ Item {
IpcHandler { IpcHandler {
function toggle(): string { function toggle(): string {
SessionService.toggleIdleInhibit() SessionService.toggleIdleInhibit();
return SessionService.idleInhibited ? "Idle inhibit enabled" : "Idle inhibit disabled" return SessionService.idleInhibited ? "Idle inhibit enabled" : "Idle inhibit disabled";
} }
function enable(): string { function enable(): string {
SessionService.enableIdleInhibit() SessionService.enableIdleInhibit();
return "Idle inhibit enabled" return "Idle inhibit enabled";
} }
function disable(): string { function disable(): string {
SessionService.disableIdleInhibit() SessionService.disableIdleInhibit();
return "Idle inhibit disabled" return "Idle inhibit disabled";
} }
function status(): string { function status(): string {
return SessionService.idleInhibited ? "Idle inhibit is enabled" : "Idle inhibit is disabled" return SessionService.idleInhibited ? "Idle inhibit is enabled" : "Idle inhibit is disabled";
} }
function reason(newReason: string): string { function reason(newReason: string): string {
if (!newReason) { if (!newReason) {
return `Current reason: ${SessionService.inhibitReason}` return `Current reason: ${SessionService.inhibitReason}`;
} }
SessionService.setInhibitReason(newReason) SessionService.setInhibitReason(newReason);
return `Inhibit reason set to: ${newReason}` return `Inhibit reason set to: ${newReason}`;
} }
target: "inhibit" target: "inhibit"
@@ -264,42 +277,42 @@ Item {
IpcHandler { IpcHandler {
function list(): string { function list(): string {
return MprisController.availablePlayers.map(p => p.identity).join("\n") return MprisController.availablePlayers.map(p => p.identity).join("\n");
} }
function play(): void { function play(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canPlay) { if (MprisController.activePlayer && MprisController.activePlayer.canPlay) {
MprisController.activePlayer.play() MprisController.activePlayer.play();
} }
} }
function pause(): void { function pause(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canPause) { if (MprisController.activePlayer && MprisController.activePlayer.canPause) {
MprisController.activePlayer.pause() MprisController.activePlayer.pause();
} }
} }
function playPause(): void { function playPause(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canTogglePlaying) { if (MprisController.activePlayer && MprisController.activePlayer.canTogglePlaying) {
MprisController.activePlayer.togglePlaying() MprisController.activePlayer.togglePlaying();
} }
} }
function previous(): void { function previous(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canGoPrevious) { if (MprisController.activePlayer && MprisController.activePlayer.canGoPrevious) {
MprisController.activePlayer.previous() MprisController.activePlayer.previous();
} }
} }
function next(): void { function next(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canGoNext) { if (MprisController.activePlayer && MprisController.activePlayer.canGoNext) {
MprisController.activePlayer.next() MprisController.activePlayer.next();
} }
} }
function stop(): void { function stop(): void {
if (MprisController.activePlayer) { if (MprisController.activePlayer) {
MprisController.activePlayer.stop() MprisController.activePlayer.stop();
} }
} }
@@ -309,78 +322,78 @@ Item {
IpcHandler { IpcHandler {
function toggle(provider: string): string { function toggle(provider: string): string {
if (!provider) { if (!provider) {
return "ERROR: No provider specified" return "ERROR: No provider specified";
} }
KeybindsService.loadProvider(provider) KeybindsService.loadProvider(provider);
root.hyprKeybindsModalLoader.active = true root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) { if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
root.hyprKeybindsModalLoader.item.close() root.hyprKeybindsModalLoader.item.close();
} else { } else {
root.hyprKeybindsModalLoader.item.open() root.hyprKeybindsModalLoader.item.open();
} }
return `KEYBINDS_TOGGLE_SUCCESS: ${provider}` return `KEYBINDS_TOGGLE_SUCCESS: ${provider}`;
} }
return `KEYBINDS_TOGGLE_FAILED: ${provider}` return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
} }
function toggleWithPath(provider: string, path: string): string { function toggleWithPath(provider: string, path: string): string {
if (!provider) { if (!provider) {
return "ERROR: No provider specified" return "ERROR: No provider specified";
} }
KeybindsService.loadProviderWithPath(provider, path) KeybindsService.loadProviderWithPath(provider, path);
root.hyprKeybindsModalLoader.active = true root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) { if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
root.hyprKeybindsModalLoader.item.close() root.hyprKeybindsModalLoader.item.close();
} else { } else {
root.hyprKeybindsModalLoader.item.open() root.hyprKeybindsModalLoader.item.open();
} }
return `KEYBINDS_TOGGLE_SUCCESS: ${provider} (${path})` return `KEYBINDS_TOGGLE_SUCCESS: ${provider} (${path})`;
} }
return `KEYBINDS_TOGGLE_FAILED: ${provider}` return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
} }
function open(provider: string): string { function open(provider: string): string {
if (!provider) { if (!provider) {
return "ERROR: No provider specified" return "ERROR: No provider specified";
} }
KeybindsService.loadProvider(provider) KeybindsService.loadProvider(provider);
root.hyprKeybindsModalLoader.active = true root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.open() root.hyprKeybindsModalLoader.item.open();
return `KEYBINDS_OPEN_SUCCESS: ${provider}` return `KEYBINDS_OPEN_SUCCESS: ${provider}`;
} }
return `KEYBINDS_OPEN_FAILED: ${provider}` return `KEYBINDS_OPEN_FAILED: ${provider}`;
} }
function openWithPath(provider: string, path: string): string { function openWithPath(provider: string, path: string): string {
if (!provider) { if (!provider) {
return "ERROR: No provider specified" return "ERROR: No provider specified";
} }
KeybindsService.loadProviderWithPath(provider, path) KeybindsService.loadProviderWithPath(provider, path);
root.hyprKeybindsModalLoader.active = true root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.open() root.hyprKeybindsModalLoader.item.open();
return `KEYBINDS_OPEN_SUCCESS: ${provider} (${path})` return `KEYBINDS_OPEN_SUCCESS: ${provider} (${path})`;
} }
return `KEYBINDS_OPEN_FAILED: ${provider}` return `KEYBINDS_OPEN_FAILED: ${provider}`;
} }
function close(): string { function close(): string {
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.close() root.hyprKeybindsModalLoader.item.close();
return "KEYBINDS_CLOSE_SUCCESS" return "KEYBINDS_CLOSE_SUCCESS";
} }
return "KEYBINDS_CLOSE_FAILED" return "KEYBINDS_CLOSE_FAILED";
} }
target: "keybinds" target: "keybinds"
@@ -389,67 +402,67 @@ Item {
IpcHandler { IpcHandler {
function openBinds(): string { function openBinds(): string {
if (!CompositorService.isHyprland) { if (!CompositorService.isHyprland) {
return "HYPR_NOT_AVAILABLE" return "HYPR_NOT_AVAILABLE";
} }
KeybindsService.loadProvider("hyprland") KeybindsService.loadProvider("hyprland");
root.hyprKeybindsModalLoader.active = true root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.open() root.hyprKeybindsModalLoader.item.open();
return "HYPR_KEYBINDS_OPEN_SUCCESS" return "HYPR_KEYBINDS_OPEN_SUCCESS";
} }
return "HYPR_KEYBINDS_OPEN_FAILED" return "HYPR_KEYBINDS_OPEN_FAILED";
} }
function closeBinds(): string { function closeBinds(): string {
if (!CompositorService.isHyprland) { if (!CompositorService.isHyprland) {
return "HYPR_NOT_AVAILABLE" return "HYPR_NOT_AVAILABLE";
} }
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.close() root.hyprKeybindsModalLoader.item.close();
return "HYPR_KEYBINDS_CLOSE_SUCCESS" return "HYPR_KEYBINDS_CLOSE_SUCCESS";
} }
return "HYPR_KEYBINDS_CLOSE_FAILED" return "HYPR_KEYBINDS_CLOSE_FAILED";
} }
function toggleBinds(): string { function toggleBinds(): string {
if (!CompositorService.isHyprland) { if (!CompositorService.isHyprland) {
return "HYPR_NOT_AVAILABLE" return "HYPR_NOT_AVAILABLE";
} }
KeybindsService.loadProvider("hyprland") KeybindsService.loadProvider("hyprland");
root.hyprKeybindsModalLoader.active = true root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) { if (root.hyprKeybindsModalLoader.item) {
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) { if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
root.hyprKeybindsModalLoader.item.close() root.hyprKeybindsModalLoader.item.close();
} else { } else {
root.hyprKeybindsModalLoader.item.open() root.hyprKeybindsModalLoader.item.open();
} }
return "HYPR_KEYBINDS_TOGGLE_SUCCESS" return "HYPR_KEYBINDS_TOGGLE_SUCCESS";
} }
return "HYPR_KEYBINDS_TOGGLE_FAILED" return "HYPR_KEYBINDS_TOGGLE_FAILED";
} }
function toggleOverview(): string { function toggleOverview(): string {
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) { if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
return "HYPR_NOT_AVAILABLE" return "HYPR_NOT_AVAILABLE";
} }
root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen;
return root.hyprlandOverviewLoader.item.overviewOpen ? "OVERVIEW_OPEN_SUCCESS" : "OVERVIEW_CLOSE_SUCCESS" return root.hyprlandOverviewLoader.item.overviewOpen ? "OVERVIEW_OPEN_SUCCESS" : "OVERVIEW_CLOSE_SUCCESS";
} }
function closeOverview(): string { function closeOverview(): string {
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) { if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
return "HYPR_NOT_AVAILABLE" return "HYPR_NOT_AVAILABLE";
} }
root.hyprlandOverviewLoader.item.overviewOpen = false root.hyprlandOverviewLoader.item.overviewOpen = false;
return "OVERVIEW_CLOSE_SUCCESS" return "OVERVIEW_CLOSE_SUCCESS";
} }
function openOverview(): string { function openOverview(): string {
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) { if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
return "HYPR_NOT_AVAILABLE" return "HYPR_NOT_AVAILABLE";
} }
root.hyprlandOverviewLoader.item.overviewOpen = true root.hyprlandOverviewLoader.item.overviewOpen = true;
return "OVERVIEW_OPEN_SUCCESS" return "OVERVIEW_OPEN_SUCCESS";
} }
target: "hypr" target: "hypr"
@@ -457,12 +470,63 @@ Item {
IpcHandler { IpcHandler {
function wallpaper(): string { function wallpaper(): string {
if (root.dankBarLoader.item && root.dankBarLoader.item.triggerWallpaperBrowserOnFocusedScreen()) { const bar = root.getFirstBar();
return "SUCCESS: Toggled wallpaper browser" if (bar && bar.triggerWallpaperBrowserOnFocusedScreen()) {
return "SUCCESS: Toggled wallpaper browser";
} }
return "ERROR: Failed to toggle wallpaper browser" return "ERROR: Failed to toggle wallpaper browser";
} }
target: "dankdash" target: "dankdash"
} }
IpcHandler {
function reveal(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
SettingsData.updateBarConfig(bar.id, {
visible: true
});
return `BAR_${index}_SHOW_SUCCESS`;
}
function hide(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
SettingsData.updateBarConfig(bar.id, {
visible: false
});
return `BAR_${index}_HIDE_SUCCESS`;
}
function toggle(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
const newVisible = !(bar.visible ?? true);
SettingsData.updateBarConfig(bar.id, {
visible: newVisible
});
return newVisible ? `BAR_${index}_SHOW_SUCCESS` : `BAR_${index}_HIDE_SUCCESS`;
}
function status(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
return (bar.visible ?? true) ? "visible" : "hidden";
}
target: "bar"
}
} }

View File

@@ -192,8 +192,8 @@ DankModal {
positioning: parentBounds.width > 0 ? "custom" : "center" positioning: parentBounds.width > 0 ? "custom" : "center"
customPosition: { customPosition: {
if (parentBounds.width > 0) { if (parentBounds.width > 0) {
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) const effectiveBarThickness = Math.max(26 + (SettingsData.barConfigs[0]?.innerPadding ?? 4) * 0.6 + (SettingsData.barConfigs[0]?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (SettingsData.barConfigs[0]?.innerPadding ?? 4)))
const barExclusionZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap const barExclusionZone = effectiveBarThickness + (SettingsData.barConfigs[0]?.spacing ?? 4) + (SettingsData.barConfigs[0]?.bottomGap ?? 0)
const screenW = parentScreen?.width ?? 1920 const screenW = parentScreen?.width ?? 1920
const screenH = parentScreen?.height ?? 1080 const screenH = parentScreen?.height ?? 1080
const margin = Theme.spacingL const margin = Theme.spacingL
@@ -201,8 +201,8 @@ DankModal {
let targetX = parentBounds.x + (parentBounds.width - width) / 2 let targetX = parentBounds.x + (parentBounds.width - width) / 2
let targetY = parentBounds.y + (parentBounds.height - height) / 2 let targetY = parentBounds.y + (parentBounds.height - height) / 2
const minY = SettingsData.dankBarPosition === SettingsData.Position.Top ? barExclusionZone + margin : margin const minY = (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Top ? barExclusionZone + margin : margin
const maxY = SettingsData.dankBarPosition === SettingsData.Position.Bottom ? screenH - height - barExclusionZone - margin : screenH - height - margin const maxY = (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Bottom ? screenH - height - barExclusionZone - margin : screenH - height - margin
targetY = Math.max(minY, Math.min(maxY, targetY)) targetY = Math.max(minY, Math.min(maxY, targetY))

View File

@@ -21,18 +21,8 @@ DankPopout {
open() open()
} }
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
}
popupWidth: 520 popupWidth: 520
popupHeight: 600 popupHeight: 600
triggerX: Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 40 triggerWidth: 40
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen

View File

@@ -189,6 +189,7 @@ Variants {
MultiEffect { MultiEffect {
anchors.fill: parent anchors.fill: parent
source: currentWallpaper source: currentWallpaper
visible: currentWallpaper.source !== ""
blurEnabled: true blurEnabled: true
blur: 0.8 blur: 0.8
blurMax: 75 blurMax: 75
@@ -199,6 +200,7 @@ Variants {
MultiEffect { MultiEffect {
anchors.fill: parent anchors.fill: parent
source: nextWallpaper source: nextWallpaper
visible: nextWallpaper.source !== ""
blurEnabled: true blurEnabled: true
blur: 0.8 blur: 0.8
blurMax: 75 blurMax: 75

View File

@@ -51,10 +51,6 @@ DankPopout {
readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
function setTriggerPosition(x, y, width, section, screen) {
StateUtils.setTriggerPosition(root, x, y, width, section, screen)
}
function openWithSection(section) { function openWithSection(section) {
StateUtils.openWithSection(root, section) StateUtils.openWithSection(root, section)
} }
@@ -70,8 +66,8 @@ DankPopout {
const contentHeight = contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400 const contentHeight = contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400
return Math.min(maxHeight, contentHeight) return Math.min(maxHeight, contentHeight)
} }
triggerX: (triggerScreen?.width ?? 1920) - 600 - Theme.spacingL triggerX: 0
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing triggerY: 0
triggerWidth: 80 triggerWidth: 80
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen

View File

@@ -8,15 +8,17 @@ Item {
required property var barWindow required property var barWindow
required property var axis required property var axis
required property var barConfig
anchors.fill: parent anchors.fill: parent
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.leftMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0) readonly property bool gothEnabled: barConfig?.gothCornersEnabled ?? false
anchors.rightMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0) anchors.leftMargin: -(gothEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0)
anchors.topMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0) anchors.rightMargin: -(gothEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0)
anchors.bottomMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0) anchors.topMargin: -(gothEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0)
anchors.bottomMargin: -(gothEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0)
readonly property real dpr: CompositorService.getScreenScale(barWindow.screen) readonly property real dpr: CompositorService.getScreenScale(barWindow.screen)
@@ -65,8 +67,8 @@ Item {
readonly property real correctHeight: Theme.px(root.height, dpr) readonly property real correctHeight: Theme.px(root.height, dpr)
canvasSize: Qt.size(correctWidth, correctHeight) canvasSize: Qt.size(correctWidth, correctHeight)
property real wing: SettingsData.dankBarGothCornersEnabled ? Theme.px(barWindow._wingR, dpr) : 0 property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.px(Theme.cornerRadius, dpr) property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr)
onWingChanged: root.requestRepaint() onWingChanged: root.requestRepaint()
onRtChanged: root.requestRepaint() onRtChanged: root.requestRepaint()
@@ -83,6 +85,8 @@ Item {
Connections { Connections {
target: barWindow target: barWindow
function on_BgColorChanged() { root.requestRepaint() } function on_BgColorChanged() { root.requestRepaint() }
function onGothCornersEnabledChanged() { root.requestRepaint() }
function onWingtipsRadiusChanged() { root.requestRepaint() }
} }
Connections { Connections {
@@ -91,12 +95,6 @@ Item {
function onSurfaceContainerChanged() { root.requestRepaint() } function onSurfaceContainerChanged() { root.requestRepaint() }
} }
Connections {
target: SettingsData
function onDankBarGothCornerRadiusOverrideChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusValueChanged() { root.requestRepaint() }
}
onPaint: { onPaint: {
const ctx = getContext("2d") const ctx = getContext("2d")
const W = barWindow.isVertical ? correctHeight : correctWidth const W = barWindow.isVertical ? correctHeight : correctWidth
@@ -104,10 +102,11 @@ Item {
const R = wing const R = wing
const RT = rt const RT = rt
const H = H_raw - (R > 0 ? R : 0) const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top const barPos = barConfig?.position ?? 0
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom const isTop = barPos === SettingsData.Position.Top
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left const isBottom = barPos === SettingsData.Position.Bottom
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right const isLeft = barPos === SettingsData.Position.Left
const isRight = barPos === SettingsData.Position.Right
function drawTopPath() { function drawTopPath() {
ctx.beginPath() ctx.beginPath()
@@ -168,8 +167,8 @@ Item {
readonly property real correctHeight: Theme.px(root.height, dpr) readonly property real correctHeight: Theme.px(root.height, dpr)
canvasSize: Qt.size(correctWidth, correctHeight) canvasSize: Qt.size(correctWidth, correctHeight)
property real wing: SettingsData.dankBarGothCornersEnabled ? Theme.px(barWindow._wingR, dpr) : 0 property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.px(Theme.cornerRadius, dpr) property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr)
property real alphaTint: (barWindow._bgColor?.a ?? 1) < 0.99 ? (Theme.stateLayerOpacity ?? 0) : 0 property real alphaTint: (barWindow._bgColor?.a ?? 1) < 0.99 ? (Theme.stateLayerOpacity ?? 0) : 0
onWingChanged: root.requestRepaint() onWingChanged: root.requestRepaint()
@@ -188,6 +187,8 @@ Item {
Connections { Connections {
target: barWindow target: barWindow
function on_BgColorChanged() { root.requestRepaint() } function on_BgColorChanged() { root.requestRepaint() }
function onGothCornersEnabledChanged() { root.requestRepaint() }
function onWingtipsRadiusChanged() { root.requestRepaint() }
} }
Connections { Connections {
@@ -196,12 +197,6 @@ Item {
function onSurfaceChanged() { root.requestRepaint() } function onSurfaceChanged() { root.requestRepaint() }
} }
Connections {
target: SettingsData
function onDankBarGothCornerRadiusOverrideChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusValueChanged() { root.requestRepaint() }
}
onPaint: { onPaint: {
const ctx = getContext("2d") const ctx = getContext("2d")
const W = barWindow.isVertical ? correctHeight : correctWidth const W = barWindow.isVertical ? correctHeight : correctWidth
@@ -209,10 +204,11 @@ Item {
const R = wing const R = wing
const RT = rt const RT = rt
const H = H_raw - (R > 0 ? R : 0) const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top const barPos = barConfig?.position ?? 0
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom const isTop = barPos === SettingsData.Position.Top
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left const isBottom = barPos === SettingsData.Position.Bottom
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right const isLeft = barPos === SettingsData.Position.Left
const isRight = barPos === SettingsData.Position.Right
function drawTopPath() { function drawTopPath() {
ctx.beginPath() ctx.beginPath()
@@ -265,7 +261,7 @@ Item {
Canvas { Canvas {
id: barBorder id: barBorder
anchors.fill: parent anchors.fill: parent
visible: SettingsData.dankBarBorderEnabled visible: barConfig?.borderEnabled ?? false
renderTarget: Canvas.FramebufferObject renderTarget: Canvas.FramebufferObject
renderStrategy: Canvas.Cooperative renderStrategy: Canvas.Cooperative
@@ -273,9 +269,9 @@ Item {
readonly property real correctHeight: Theme.px(root.height, dpr) readonly property real correctHeight: Theme.px(root.height, dpr)
canvasSize: Qt.size(correctWidth, correctHeight) canvasSize: Qt.size(correctWidth, correctHeight)
property real wing: SettingsData.dankBarGothCornersEnabled ? Theme.px(barWindow._wingR, dpr) : 0 property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.px(Theme.cornerRadius, dpr) property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr)
property bool borderEnabled: SettingsData.dankBarBorderEnabled property bool borderEnabled: barConfig?.borderEnabled ?? false
antialiasing: rt > 0 || wing > 0 antialiasing: rt > 0 || wing > 0
@@ -302,15 +298,9 @@ Item {
} }
Connections { Connections {
target: SettingsData target: barWindow
function onDankBarBorderColorChanged() { root.requestRepaint() } function onGothCornersEnabledChanged() { root.requestRepaint() }
function onDankBarBorderOpacityChanged() { root.requestRepaint() } function onWingtipsRadiusChanged() { root.requestRepaint() }
function onDankBarBorderThicknessChanged() { root.requestRepaint() }
function onDankBarSpacingChanged() { root.requestRepaint() }
function onDankBarSquareCornersChanged() { root.requestRepaint() }
function onDankBarTransparencyChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusOverrideChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusValueChanged() { root.requestRepaint() }
} }
onPaint: { onPaint: {
@@ -322,12 +312,13 @@ Item {
const R = wing const R = wing
const RT = rt const RT = rt
const H = H_raw - (R > 0 ? R : 0) const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top const barPos = barConfig?.position ?? 0
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom const isTop = barPos === SettingsData.Position.Top
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left const isBottom = barPos === SettingsData.Position.Bottom
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right const isLeft = barPos === SettingsData.Position.Left
const isRight = barPos === SettingsData.Position.Right
const spacing = SettingsData.dankBarSpacing const spacing = barConfig?.spacing ?? 4
const hasEdgeGap = spacing > 0 || RT > 0 const hasEdgeGap = spacing > 0 || RT > 0
ctx.reset() ctx.reset()
@@ -345,14 +336,14 @@ Item {
ctx.rotate(Math.PI / 2) ctx.rotate(Math.PI / 2)
} }
const uiThickness = Math.max(1, SettingsData.dankBarBorderThickness ?? 1) const uiThickness = Math.max(1, barConfig?.borderThickness ?? 1)
const devThickness = Math.max(1, Math.round(Theme.px(uiThickness, dpr))) const devThickness = Math.max(1, Math.round(Theme.px(uiThickness, dpr)))
const key = SettingsData.dankBarBorderColor || "surfaceText" const key = barConfig?.borderColor || "surfaceText"
const base = (key === "surfaceText") ? Theme.surfaceText const base = (key === "surfaceText") ? Theme.surfaceText
: (key === "primary") ? Theme.primary : (key === "primary") ? Theme.primary
: Theme.secondary : Theme.secondary
const color = Theme.withAlpha(base, SettingsData.dankBarBorderOpacity ?? 1.0) const color = Theme.withAlpha(base, barConfig?.borderOpacity ?? 1.0)
ctx.globalCompositeOperation = "source-over" ctx.globalCompositeOperation = "source-over"
ctx.fillStyle = color ctx.fillStyle = color

View File

@@ -13,6 +13,8 @@ Item {
property var parentScreen: null property var parentScreen: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool overrideAxisLayout: false property bool overrideAxisLayout: false
property bool forceVerticalLayout: false property bool forceVerticalLayout: false
@@ -25,238 +27,238 @@ Item {
function updateLayout() { function updateLayout() {
if ((isVertical ? height : width) <= 0 || !visible) { if ((isVertical ? height : width) <= 0 || !visible) {
return return;
} }
centerWidgets = [] centerWidgets = [];
totalWidgets = 0 totalWidgets = 0;
totalSize = 0 totalSize = 0;
let configuredWidgets = 0 let configuredWidgets = 0;
let configuredMiddleWidget = null let configuredMiddleWidget = null;
let configuredLeftWidget = null let configuredLeftWidget = null;
let configuredRightWidget = null let configuredRightWidget = null;
for (var i = 0; i < centerRepeater.count; i++) { for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i) const item = centerRepeater.itemAt(i);
if (item && getWidgetVisible(item.widgetId)) { if (item && getWidgetVisible(item.widgetId)) {
configuredWidgets++ configuredWidgets++;
} }
} }
const isOddConfigured = configuredWidgets % 2 === 1 const isOddConfigured = configuredWidgets % 2 === 1;
const configuredMiddlePos = Math.floor(configuredWidgets / 2) const configuredMiddlePos = Math.floor(configuredWidgets / 2);
const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1) const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1);
const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2) const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2);
let currentConfigIndex = 0 let currentConfigIndex = 0;
for (var i = 0; i < centerRepeater.count; i++) { for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i) const item = centerRepeater.itemAt(i);
if (item && getWidgetVisible(item.widgetId)) { if (item && getWidgetVisible(item.widgetId)) {
if (isOddConfigured && currentConfigIndex === configuredMiddlePos && item.active && item.item) { if (isOddConfigured && currentConfigIndex === configuredMiddlePos && item.active && item.item) {
configuredMiddleWidget = item.item configuredMiddleWidget = item.item;
} }
if (!isOddConfigured && currentConfigIndex === configuredLeftPos && item.active && item.item) { if (!isOddConfigured && currentConfigIndex === configuredLeftPos && item.active && item.item) {
configuredLeftWidget = item.item configuredLeftWidget = item.item;
} }
if (!isOddConfigured && currentConfigIndex === configuredRightPos && item.active && item.item) { if (!isOddConfigured && currentConfigIndex === configuredRightPos && item.active && item.item) {
configuredRightWidget = item.item configuredRightWidget = item.item;
} }
if (item.active && item.item) { if (item.active && item.item) {
centerWidgets.push(item.item) centerWidgets.push(item.item);
totalWidgets++ totalWidgets++;
totalSize += isVertical ? item.item.height : item.item.width totalSize += isVertical ? item.item.height : item.item.width;
} }
currentConfigIndex++ currentConfigIndex++;
} }
} }
if (totalWidgets === 0) { if (totalWidgets === 0) {
return return;
} }
if (totalWidgets > 1) { if (totalWidgets > 1) {
totalSize += spacing * (totalWidgets - 1) totalSize += spacing * (totalWidgets - 1);
} }
positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget);
} }
function positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) { function positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) {
const parentCenter = (isVertical ? height : width) / 2 const parentCenter = (isVertical ? height : width) / 2;
const isOddConfigured = configuredWidgets % 2 === 1 const isOddConfigured = configuredWidgets % 2 === 1;
centerWidgets.forEach(widget => { centerWidgets.forEach(widget => {
if (isVertical) { if (isVertical) {
widget.anchors.verticalCenter = undefined widget.anchors.verticalCenter = undefined;
} else { } else {
widget.anchors.horizontalCenter = undefined widget.anchors.horizontalCenter = undefined;
} }
}) });
if (isOddConfigured && configuredMiddleWidget) { if (isOddConfigured && configuredMiddleWidget) {
const middleWidget = configuredMiddleWidget const middleWidget = configuredMiddleWidget;
const middleIndex = centerWidgets.indexOf(middleWidget) const middleIndex = centerWidgets.indexOf(middleWidget);
const middleSize = isVertical ? middleWidget.height : middleWidget.width const middleSize = isVertical ? middleWidget.height : middleWidget.width;
if (isVertical) { if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2) middleWidget.y = parentCenter - (middleSize / 2);
} else { } else {
middleWidget.x = parentCenter - (middleSize / 2) middleWidget.x = parentCenter - (middleSize / 2);
} }
let currentPos = isVertical ? middleWidget.y : middleWidget.x let currentPos = isVertical ? middleWidget.y : middleWidget.x;
for (var i = middleIndex - 1; i >= 0; i--) { for (var i = middleIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size) currentPos -= (spacing + size);
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
} }
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
for (var i = middleIndex + 1; i < totalWidgets; i++) { for (var i = middleIndex + 1; i < totalWidgets; i++) {
currentPos += spacing currentPos += spacing;
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
} }
} else { } else {
if (totalWidgets === 1) { if (totalWidgets === 1) {
const widget = centerWidgets[0] const widget = centerWidgets[0];
const size = isVertical ? widget.height : widget.width const size = isVertical ? widget.height : widget.width;
if (isVertical) { if (isVertical) {
widget.y = parentCenter - (size / 2) widget.y = parentCenter - (size / 2);
} else { } else {
widget.x = parentCenter - (size / 2) widget.x = parentCenter - (size / 2);
} }
return return;
} }
if (!configuredLeftWidget || !configuredRightWidget) { if (!configuredLeftWidget || !configuredRightWidget) {
if (totalWidgets % 2 === 1) { if (totalWidgets % 2 === 1) {
const middleIndex = Math.floor(totalWidgets / 2) const middleIndex = Math.floor(totalWidgets / 2);
const middleWidget = centerWidgets[middleIndex] const middleWidget = centerWidgets[middleIndex];
if (!middleWidget) { if (!middleWidget) {
return return;
} }
const middleSize = isVertical ? middleWidget.height : middleWidget.width const middleSize = isVertical ? middleWidget.height : middleWidget.width;
if (isVertical) { if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2) middleWidget.y = parentCenter - (middleSize / 2);
} else { } else {
middleWidget.x = parentCenter - (middleSize / 2) middleWidget.x = parentCenter - (middleSize / 2);
} }
let currentPos = isVertical ? middleWidget.y : middleWidget.x let currentPos = isVertical ? middleWidget.y : middleWidget.x;
for (var i = middleIndex - 1; i >= 0; i--) { for (var i = middleIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size) currentPos -= (spacing + size);
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
} }
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
for (var i = middleIndex + 1; i < totalWidgets; i++) { for (var i = middleIndex + 1; i < totalWidgets; i++) {
currentPos += spacing currentPos += spacing;
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
} }
} else { } else {
const leftIndex = (totalWidgets / 2) - 1 const leftIndex = (totalWidgets / 2) - 1;
const rightIndex = totalWidgets / 2 const rightIndex = totalWidgets / 2;
const fallbackLeft = centerWidgets[leftIndex] const fallbackLeft = centerWidgets[leftIndex];
const fallbackRight = centerWidgets[rightIndex] const fallbackRight = centerWidgets[rightIndex];
if (!fallbackLeft || !fallbackRight) { if (!fallbackLeft || !fallbackRight) {
return return;
} }
const halfSpacing = spacing / 2 const halfSpacing = spacing / 2;
const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width;
if (isVertical) { if (isVertical) {
fallbackLeft.y = parentCenter - halfSpacing - leftSize fallbackLeft.y = parentCenter - halfSpacing - leftSize;
fallbackRight.y = parentCenter + halfSpacing fallbackRight.y = parentCenter + halfSpacing;
} else { } else {
fallbackLeft.x = parentCenter - halfSpacing - leftSize fallbackLeft.x = parentCenter - halfSpacing - leftSize;
fallbackRight.x = parentCenter + halfSpacing fallbackRight.x = parentCenter + halfSpacing;
} }
let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x;
for (var i = leftIndex - 1; i >= 0; i--) { for (var i = leftIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size) currentPos -= (spacing + size);
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
} }
currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width) currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width);
for (var i = rightIndex + 1; i < totalWidgets; i++) { for (var i = rightIndex + 1; i < totalWidgets; i++) {
currentPos += spacing currentPos += spacing;
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
} }
} }
return return;
} }
const leftWidget = configuredLeftWidget const leftWidget = configuredLeftWidget;
const rightWidget = configuredRightWidget const rightWidget = configuredRightWidget;
const leftIndex = centerWidgets.indexOf(leftWidget) const leftIndex = centerWidgets.indexOf(leftWidget);
const rightIndex = centerWidgets.indexOf(rightWidget) const rightIndex = centerWidgets.indexOf(rightWidget);
const halfSpacing = spacing / 2 const halfSpacing = spacing / 2;
const leftSize = isVertical ? leftWidget.height : leftWidget.width const leftSize = isVertical ? leftWidget.height : leftWidget.width;
if (isVertical) { if (isVertical) {
leftWidget.y = parentCenter - halfSpacing - leftSize leftWidget.y = parentCenter - halfSpacing - leftSize;
rightWidget.y = parentCenter + halfSpacing rightWidget.y = parentCenter + halfSpacing;
} else { } else {
leftWidget.x = parentCenter - halfSpacing - leftSize leftWidget.x = parentCenter - halfSpacing - leftSize;
rightWidget.x = parentCenter + halfSpacing rightWidget.x = parentCenter + halfSpacing;
} }
let currentPos = isVertical ? leftWidget.y : leftWidget.x let currentPos = isVertical ? leftWidget.y : leftWidget.x;
for (var i = leftIndex - 1; i >= 0; i--) { for (var i = leftIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size) currentPos -= (spacing + size);
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
} }
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width) currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width);
for (var i = rightIndex + 1; i < totalWidgets; i++) { for (var i = rightIndex + 1; i < totalWidgets; i++) {
currentPos += spacing currentPos += spacing;
if (isVertical) { if (isVertical) {
centerWidgets[i].y = currentPos centerWidgets[i].y = currentPos;
} else { } else {
centerWidgets[i].x = currentPos centerWidgets[i].x = currentPos;
} }
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
} }
} }
} }
@@ -268,8 +270,8 @@ Item {
"cpuTemp": DgopService.dgopAvailable, "cpuTemp": DgopService.dgopAvailable,
"gpuTemp": DgopService.dgopAvailable, "gpuTemp": DgopService.dgopAvailable,
"network_speed_monitor": DgopService.dgopAvailable "network_speed_monitor": DgopService.dgopAvailable
} };
return widgetVisibility[widgetId] ?? true return widgetVisibility[widgetId] ?? true;
} }
function getWidgetComponent(widgetId) { function getWidgetComponent(widgetId) {
@@ -302,19 +304,19 @@ Item {
"notepadButton": "notepadButtonComponent", "notepadButton": "notepadButtonComponent",
"colorPicker": "colorPickerComponent", "colorPicker": "colorPickerComponent",
"systemUpdate": "systemUpdateComponent" "systemUpdate": "systemUpdateComponent"
} };
// For built-in components, get from components property // For built-in components, get from components property
const componentKey = baseMap[widgetId] const componentKey = baseMap[widgetId];
if (componentKey && root.components[componentKey]) { if (componentKey && root.components[componentKey]) {
return root.components[componentKey] return root.components[componentKey];
} }
// For plugin components, get from PluginService // For plugin components, get from PluginService
var parts = widgetId.split(":") var parts = widgetId.split(":");
var pluginId = parts[0] var pluginId = parts[0];
let pluginComponents = PluginService.getWidgetComponents() let pluginComponents = PluginService.getWidgetComponents();
return pluginComponents[pluginId] || null return pluginComponents[pluginId] || null;
} }
height: parent.height height: parent.height
@@ -329,24 +331,24 @@ Item {
} }
Component.onCompleted: { Component.onCompleted: {
layoutTimer.restart() layoutTimer.restart();
} }
onWidthChanged: { onWidthChanged: {
if (width > 0) { if (width > 0) {
layoutTimer.restart() layoutTimer.restart();
} }
} }
onHeightChanged: { onHeightChanged: {
if (height > 0) { if (height > 0) {
layoutTimer.restart() layoutTimer.restart();
} }
} }
onVisibleChanged: { onVisibleChanged: {
if (visible && (isVertical ? height : width) > 0) { if (visible && (isVertical ? height : width) > 0) {
layoutTimer.restart() layoutTimer.restart();
} }
} }
@@ -354,146 +356,149 @@ Item {
id: centerRepeater id: centerRepeater
model: root.widgetsModel model: root.widgetsModel
Loader { Loader {
property string widgetId: model.widgetId property var itemData: modelData
property var widgetData: model property string widgetId: itemData.widgetId
property int spacerSize: model.size || 20 property var widgetData: itemData
property int spacerSize: itemData.size || 20
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
active: root.getWidgetVisible(model.widgetId) && (model.widgetId !== "music" || MprisController.activePlayer !== null) active: root.getWidgetVisible(itemData.widgetId) && (itemData.widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: root.getWidgetComponent(model.widgetId) sourceComponent: root.getWidgetComponent(itemData.widgetId)
opacity: (model.enabled !== false) ? 1 : 0 opacity: (itemData.enabled !== false) ? 1 : 0
asynchronous: false asynchronous: false
onLoaded: { onLoaded: {
if (!item) { if (!item) {
return return;
} }
item.widthChanged.connect(() => layoutTimer.restart()) item.widthChanged.connect(() => {
item.heightChanged.connect(() => layoutTimer.restart()) if (layoutTimer)
layoutTimer.restart();
});
item.heightChanged.connect(() => {
if (layoutTimer)
layoutTimer.restart();
});
if (root.axis && "axis" in item) { if (root.axis && "axis" in item) {
item.axis = Qt.binding(() => root.axis) item.axis = Qt.binding(() => root.axis);
} }
if (root.axis && "isVertical" in item) { if (root.axis && "isVertical" in item) {
try { try {
item.isVertical = Qt.binding(() => root.axis.isVertical) item.isVertical = Qt.binding(() => root.axis.isVertical);
} catch (e) { } catch (e) {}
}
} }
// Inject properties for plugin widgets // Inject properties for plugin widgets
if ("section" in item) { if ("section" in item) {
item.section = root.section item.section = root.section;
} }
if ("parentScreen" in item) { if ("parentScreen" in item) {
item.parentScreen = Qt.binding(() => root.parentScreen) item.parentScreen = Qt.binding(() => root.parentScreen);
} }
if ("widgetThickness" in item) { if ("widgetThickness" in item) {
item.widgetThickness = Qt.binding(() => root.widgetThickness) item.widgetThickness = Qt.binding(() => root.widgetThickness);
} }
if ("barThickness" in item) { if ("barThickness" in item) {
item.barThickness = Qt.binding(() => root.barThickness) item.barThickness = Qt.binding(() => root.barThickness);
}
if ("barSpacing" in item) {
item.barSpacing = Qt.binding(() => root.barSpacing);
}
if ("barConfig" in item) {
item.barConfig = Qt.binding(() => root.barConfig);
} }
if ("sectionSpacing" in item) { if ("sectionSpacing" in item) {
item.sectionSpacing = Qt.binding(() => root.spacing) item.sectionSpacing = Qt.binding(() => root.spacing);
} }
if ("isFirst" in item) { if ("isFirst" in item) {
item.isFirst = Qt.binding(() => { item.isFirst = Qt.binding(() => {
for (var i = 0; i < centerRepeater.count; i++) { for (var i = 0; i < centerRepeater.count; i++) {
const checkItem = centerRepeater.itemAt(i) const checkItem = centerRepeater.itemAt(i);
if (checkItem && checkItem.active && checkItem.item) { if (checkItem && checkItem.active && checkItem.item) {
return checkItem.item === item return checkItem.item === item;
} }
} }
return false return false;
}) });
} }
if ("isLast" in item) { if ("isLast" in item) {
item.isLast = Qt.binding(() => { item.isLast = Qt.binding(() => {
for (var i = centerRepeater.count - 1; i >= 0; i--) { for (var i = centerRepeater.count - 1; i >= 0; i--) {
const checkItem = centerRepeater.itemAt(i) const checkItem = centerRepeater.itemAt(i);
if (checkItem && checkItem.active && checkItem.item) { if (checkItem && checkItem.active && checkItem.item) {
return checkItem.item === item return checkItem.item === item;
} }
} }
return false return false;
}) });
} }
if ("isLeftBarEdge" in item) { if ("isLeftBarEdge" in item) {
item.isLeftBarEdge = false item.isLeftBarEdge = false;
} }
if ("isRightBarEdge" in item) { if ("isRightBarEdge" in item) {
item.isRightBarEdge = false item.isRightBarEdge = false;
} }
if ("isTopBarEdge" in item) { if ("isTopBarEdge" in item) {
item.isTopBarEdge = false item.isTopBarEdge = false;
} }
if ("isBottomBarEdge" in item) { if ("isBottomBarEdge" in item) {
item.isBottomBarEdge = false item.isBottomBarEdge = false;
} }
if (item.pluginService !== undefined) { if (item.pluginService !== undefined) {
var parts = model.widgetId.split(":") var parts = model.widgetId.split(":");
var pluginId = parts[0] var pluginId = parts[0];
var variantId = parts.length > 1 ? parts[1] : null var variantId = parts.length > 1 ? parts[1] : null;
if (item.pluginId !== undefined) { if (item.pluginId !== undefined) {
item.pluginId = pluginId item.pluginId = pluginId;
} }
if (item.variantId !== undefined) { if (item.variantId !== undefined) {
item.variantId = variantId item.variantId = variantId;
} }
if (item.variantData !== undefined && variantId) { if (item.variantData !== undefined && variantId) {
item.variantData = PluginService.getPluginVariantData(pluginId, variantId) item.variantData = PluginService.getPluginVariantData(pluginId, variantId);
} }
item.pluginService = PluginService item.pluginService = PluginService;
} }
if (item.popoutService !== undefined) { if (item.popoutService !== undefined) {
item.popoutService = PopoutService item.popoutService = PopoutService;
} }
layoutTimer.restart() layoutTimer.restart();
} }
onActiveChanged: { onActiveChanged: {
layoutTimer.restart() layoutTimer.restart();
} }
} }
} }
Connections {
target: widgetsModel
function onCountChanged() {
layoutTimer.restart()
}
}
// Listen for plugin changes and refresh components
Connections { Connections {
target: PluginService target: PluginService
function onPluginLoaded(pluginId) { function onPluginLoaded(pluginId) {
// Force refresh of component lookups // Force refresh of component lookups
for (var i = 0; i < centerRepeater.count; i++) { for (var i = 0; i < centerRepeater.count; i++) {
var item = centerRepeater.itemAt(i) var item = centerRepeater.itemAt(i);
if (item && item.widgetId.startsWith(pluginId)) { if (item && item.widgetId.startsWith(pluginId)) {
item.sourceComponent = root.getWidgetComponent(item.widgetId) item.sourceComponent = root.getWidgetComponent(item.widgetId);
} }
} }
} }
function onPluginUnloaded(pluginId) { function onPluginUnloaded(pluginId) {
// Force refresh of component lookups // Force refresh of component lookups
for (var i = 0; i < centerRepeater.count; i++) { for (var i = 0; i < centerRepeater.count; i++) {
var item = centerRepeater.itemAt(i) var item = centerRepeater.itemAt(i);
if (item && item.widgetId.startsWith(pluginId)) { if (item && item.widgetId.startsWith(pluginId)) {
item.sourceComponent = root.getWidgetComponent(item.widgetId) item.sourceComponent = root.getWidgetComponent(item.widgetId);
} }
} }
} }
} }
} }

View File

@@ -1,92 +1,169 @@
import QtQuick import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Shapes
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.I3 import Quickshell.I3
import Quickshell.Io
import Quickshell.Services.Mpris
import Quickshell.Services.Notifications
import Quickshell.Services.SystemTray
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Modules
import qs.Modules.DankBar.Widgets
import qs.Modules.DankBar.Popouts
import qs.Services import qs.Services
import qs.Widgets
Item { Item {
id: root id: root
required property var barConfig
signal colorPickerRequested signal colorPickerRequested
signal barReady(var barConfig)
property alias barVariants: barVariants property alias barVariants: barVariants
property var hyprlandOverviewLoader: null property var hyprlandOverviewLoader: null
property bool systemTrayMenuOpen: false property bool systemTrayMenuOpen: false
property alias leftWidgetsModel: leftWidgetsModel
property alias centerWidgetsModel: centerWidgetsModel
property alias rightWidgetsModel: rightWidgetsModel
ScriptModel {
id: leftWidgetsModel
values: {
root.barConfig;
const leftWidgets = root.barConfig?.leftWidgets || [];
return leftWidgets.map((w, index) => {
if (typeof w === "string") {
return {
widgetId: w,
id: w + "_" + index,
enabled: true
};
} else {
const obj = Object.assign({}, w);
obj.widgetId = w.id || w.widgetId;
obj.id = (w.id || w.widgetId) + "_" + index;
obj.enabled = w.enabled !== false;
return obj;
}
});
}
}
ScriptModel {
id: centerWidgetsModel
values: {
root.barConfig;
const centerWidgets = root.barConfig?.centerWidgets || [];
return centerWidgets.map((w, index) => {
if (typeof w === "string") {
return {
widgetId: w,
id: w + "_" + index,
enabled: true
};
} else {
const obj = Object.assign({}, w);
obj.widgetId = w.id || w.widgetId;
obj.id = (w.id || w.widgetId) + "_" + index;
obj.enabled = w.enabled !== false;
return obj;
}
});
}
}
ScriptModel {
id: rightWidgetsModel
values: {
root.barConfig;
const rightWidgets = root.barConfig?.rightWidgets || [];
return rightWidgets.map((w, index) => {
if (typeof w === "string") {
return {
widgetId: w,
id: w + "_" + index,
enabled: true
};
} else {
const obj = Object.assign({}, w);
obj.widgetId = w.id || w.widgetId;
obj.id = (w.id || w.widgetId) + "_" + index;
obj.enabled = w.enabled !== false;
return obj;
}
});
}
}
function triggerControlCenterOnFocusedScreen() { function triggerControlCenterOnFocusedScreen() {
let focusedScreenName = "" let focusedScreenName = "";
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
focusedScreenName = Hyprland.focusedWorkspace.monitor.name focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
} else if (CompositorService.isNiri && NiriService.currentOutput) { } else if (CompositorService.isNiri && NiriService.currentOutput) {
focusedScreenName = NiriService.currentOutput focusedScreenName = NiriService.currentOutput;
} else if (CompositorService.isSway) { } else if (CompositorService.isSway) {
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true) const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
focusedScreenName = focusedWs?.monitor?.name || "" focusedScreenName = focusedWs?.monitor?.name || "";
} }
if (!focusedScreenName && barVariants.instances.length > 0) { if (!focusedScreenName && barVariants.instances.length > 0) {
const firstBar = barVariants.instances[0] const firstBar = barVariants.instances[0];
firstBar.triggerControlCenter() firstBar.triggerControlCenter();
return true return true;
} }
for (var i = 0; i < barVariants.instances.length; i++) { for (var i = 0; i < barVariants.instances.length; i++) {
const barInstance = barVariants.instances[i] const barInstance = barVariants.instances[i];
if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) { if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) {
barInstance.triggerControlCenter() barInstance.triggerControlCenter();
return true return true;
} }
} }
return false return false;
} }
function triggerWallpaperBrowserOnFocusedScreen() { function triggerWallpaperBrowserOnFocusedScreen() {
let focusedScreenName = "" let focusedScreenName = "";
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
focusedScreenName = Hyprland.focusedWorkspace.monitor.name focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
} else if (CompositorService.isNiri && NiriService.currentOutput) { } else if (CompositorService.isNiri && NiriService.currentOutput) {
focusedScreenName = NiriService.currentOutput focusedScreenName = NiriService.currentOutput;
} else if (CompositorService.isSway) { } else if (CompositorService.isSway) {
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true) const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
focusedScreenName = focusedWs?.monitor?.name || "" focusedScreenName = focusedWs?.monitor?.name || "";
} }
if (!focusedScreenName && barVariants.instances.length > 0) { if (!focusedScreenName && barVariants.instances.length > 0) {
const firstBar = barVariants.instances[0] const firstBar = barVariants.instances[0];
firstBar.triggerWallpaperBrowser() firstBar.triggerWallpaperBrowser();
return true return true;
} }
for (var i = 0; i < barVariants.instances.length; i++) { for (var i = 0; i < barVariants.instances.length; i++) {
const barInstance = barVariants.instances[i] const barInstance = barVariants.instances[i];
if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) { if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) {
barInstance.triggerWallpaperBrowser() barInstance.triggerWallpaperBrowser();
return true return true;
} }
} }
return false return false;
} }
Variants { Variants {
id: barVariants id: barVariants
model: SettingsData.getFilteredScreens("dankBar") model: {
const prefs = root.barConfig?.screenPreferences || ["all"];
if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) {
return Quickshell.screens;
}
const filtered = Quickshell.screens.filter(screen => SettingsData.isScreenInPreferences(screen, prefs));
if (filtered.length === 0 && root.barConfig?.showOnLastDisplay && Quickshell.screens.length === 1) {
return Quickshell.screens;
}
return filtered;
}
delegate: DankBarWindow { delegate: DankBarWindow {
rootWindow: root rootWindow: root
barConfig: root.barConfig
leftWidgetsModel: root.leftWidgetsModel
centerWidgetsModel: root.centerWidgetsModel
rightWidgetsModel: root.rightWidgetsModel
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +1,113 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Shapes
import Quickshell import Quickshell
import Quickshell.Hyprland
import Quickshell.I3
import Quickshell.Io
import Quickshell.Services.Mpris
import Quickshell.Services.Notifications
import Quickshell.Services.SystemTray
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Modules
import qs.Modules.DankBar.Widgets
import qs.Modules.DankBar.Popouts
import qs.Services import qs.Services
import qs.Widgets
PanelWindow { PanelWindow {
id: barWindow id: barWindow
required property var rootWindow required property var rootWindow
required property var barConfig
property var modelData: item property var modelData: item
property var hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null property var hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null
property var leftWidgetsModel
property var centerWidgetsModel
property var rightWidgetsModel
property var controlCenterButtonRef: null property var controlCenterButtonRef: null
property var clockButtonRef: null property var clockButtonRef: null
function triggerControlCenter() { function triggerControlCenter() {
controlCenterLoader.active = true controlCenterLoader.active = true;
if (!controlCenterLoader.item) { if (!controlCenterLoader.item) {
return return;
} }
if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) { if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) {
const globalPos = controlCenterButtonRef.mapToGlobal(0, 0) const globalPos = controlCenterButtonRef.mapToGlobal(0, 0);
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width) // Calculate barPosition from axis.edge
const section = controlCenterButtonRef.section || "right" const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1));
controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width, barConfig?.spacing ?? 4, barPosition, barConfig);
const section = controlCenterButtonRef.section || "right";
controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig);
} else { } else {
controlCenterLoader.item.triggerScreen = barWindow.screen controlCenterLoader.item.triggerScreen = barWindow.screen;
} }
controlCenterLoader.item.toggle() controlCenterLoader.item.toggle();
if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) {
NetworkService.scanWifi() NetworkService.scanWifi();
} }
} }
function triggerWallpaperBrowser() { function triggerWallpaperBrowser() {
dankDashPopoutLoader.active = true dankDashPopoutLoader.active = true;
if (!dankDashPopoutLoader.item) { if (!dankDashPopoutLoader.item) {
return return;
} }
if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) { if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) {
const globalPos = clockButtonRef.visualContent.mapToGlobal(0, 0) // Calculate barPosition from axis.edge
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clockButtonRef.visualWidth) const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1));
const section = clockButtonRef.section || "center" const section = clockButtonRef.section || "center";
dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen)
// For center section widgets, use center section bounds for DankDash centering
let triggerPos, triggerWidth;
if (section === "center") {
const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? topBarContent.vCenterSection : topBarContent.vCenterSection) : topBarContent.hCenterSection;
if (centerSection) {
// For vertical bars, use center Y of section; for horizontal, use left edge
if (barWindow.isVertical) {
const centerY = centerSection.height / 2;
const centerGlobalPos = centerSection.mapToGlobal(0, centerY);
triggerPos = centerGlobalPos;
triggerWidth = centerSection.height;
} else {
// For horizontal bars, use left edge (DankPopout will center it)
const centerGlobalPos = centerSection.mapToGlobal(0, 0);
triggerPos = centerGlobalPos;
triggerWidth = centerSection.width;
}
} else {
triggerPos = clockButtonRef.visualContent.mapToGlobal(0, 0);
triggerWidth = clockButtonRef.visualWidth;
}
} else {
triggerPos = clockButtonRef.visualContent.mapToGlobal(0, 0);
triggerWidth = clockButtonRef.visualWidth;
}
const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, barConfig?.spacing ?? 4, barPosition, barConfig);
dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig);
} else { } else {
dankDashPopoutLoader.item.triggerScreen = barWindow.screen dankDashPopoutLoader.item.triggerScreen = barWindow.screen;
} }
PopoutManager.requestPopout(dankDashPopoutLoader.item, 2) PopoutManager.requestPopout(dankDashPopoutLoader.item, 2, (barConfig?.id ?? "default") + "-2");
} }
readonly property var dBarLayer: { readonly property var dBarLayer: {
switch (Quickshell.env("DMS_DANKBAR_LAYER")) { switch (Quickshell.env("DMS_DANKBAR_LAYER")) {
case "bottom": case "bottom":
return WlrLayer.Bottom return WlrLayer.Bottom;
case "overlay": case "overlay":
return WlrLayer.Overlay return WlrLayer.Overlay;
case "background": case "background":
return WlrLayer.background return WlrLayer.background;
default: default:
return WlrLayer.Top return WlrLayer.Top;
} }
} }
WlrLayershell.layer: dBarLayer WlrLayershell.layer: {
if ((barConfig?.autoHide ?? false) && topBarCore.reveal) {
return WlrLayer.Overlay;
}
return dBarLayer;
}
WlrLayershell.namespace: "dms:bar" WlrLayershell.namespace: "dms:bar"
signal colorPickerRequested signal colorPickerRequested
@@ -92,39 +119,134 @@ PanelWindow {
AxisContext { AxisContext {
id: axis id: axis
edge: { edge: {
switch (SettingsData.dankBarPosition) { switch (barConfig?.position ?? 0) {
case SettingsData.Position.Top: case SettingsData.Position.Top:
return "top" return "top";
case SettingsData.Position.Bottom: case SettingsData.Position.Bottom:
return "bottom" return "bottom";
case SettingsData.Position.Left: case SettingsData.Position.Left:
return "left" return "left";
case SettingsData.Position.Right: case SettingsData.Position.Right:
return "right" return "right";
default: default:
return "top" return "top";
} }
} }
} }
readonly property bool isVertical: axis.isVertical readonly property bool isVertical: axis.isVertical
property bool gothCornersEnabled: SettingsData.dankBarGothCornersEnabled property bool gothCornersEnabled: barConfig?.gothCornersEnabled ?? false
property real wingtipsRadius: SettingsData.dankBarGothCornerRadiusOverride ? SettingsData.dankBarGothCornerRadiusValue : Theme.cornerRadius property real wingtipsRadius: barConfig?.gothCornerRadiusOverride ? (barConfig?.gothCornerRadiusValue ?? 12) : Theme.cornerRadius
readonly property real _wingR: Math.max(0, wingtipsRadius) readonly property real _wingR: Math.max(0, wingtipsRadius)
readonly property color _surfaceContainer: Theme.surfaceContainer readonly property color _surfaceContainer: Theme.surfaceContainer
readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? (barConfig?.transparency ?? 1.0)
readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha) readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha)
readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen) readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen)
property string screenName: modelData.name property string screenName: modelData.name
readonly property int notificationCount: NotificationService.notifications.length readonly property int notificationCount: NotificationService.notifications.length
readonly property real effectiveBarThickness: Math.max(barWindow.widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) readonly property real effectiveBarThickness: Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4)))
readonly property real widgetThickness: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6) readonly property real widgetThickness: Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6)
readonly property bool hasAdjacentTopBar: {
if (barConfig?.autoHide ?? false)
return false;
if (!isVertical)
return false;
return SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Top && bc.position !== 0)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
}
readonly property bool hasAdjacentBottomBar: {
if (barConfig?.autoHide ?? false)
return false;
if (!isVertical)
return false;
const result = SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Bottom && bc.position !== 1)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
return result;
}
readonly property bool hasAdjacentLeftBar: {
if (barConfig?.autoHide ?? false)
return false;
if (isVertical)
return false;
const result = SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Left && bc.position !== 2)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
return result;
}
readonly property bool hasAdjacentRightBar: {
if (barConfig?.autoHide ?? false)
return false;
if (isVertical)
return false;
const result = SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Right && bc.position !== 3)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
return result;
}
screen: modelData screen: modelData
implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0 implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + (barConfig?.spacing ?? 4) + ((barConfig?.gothCornersEnabled ?? false) ? _wingR : 0), _dpr) : 0
implicitWidth: isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0 implicitWidth: isVertical ? Theme.px(effectiveBarThickness + (barConfig?.spacing ?? 4) + ((barConfig?.gothCornersEnabled ?? false) ? _wingR : 0), _dpr) : 0
color: "transparent" color: "transparent"
property var nativeInhibitor: null property var nativeInhibitor: null
@@ -132,18 +254,18 @@ PanelWindow {
Component.onCompleted: { Component.onCompleted: {
if (SettingsData.forceStatusBarLayoutRefresh) { if (SettingsData.forceStatusBarLayoutRefresh) {
SettingsData.forceStatusBarLayoutRefresh.connect(() => { SettingsData.forceStatusBarLayoutRefresh.connect(() => {
Qt.callLater(() => { Qt.callLater(() => {
stackContainer.visible = false stackContainer.visible = false;
Qt.callLater(() => { Qt.callLater(() => {
stackContainer.visible = true stackContainer.visible = true;
}) });
}) });
}) });
} }
updateGpuTempConfig() updateGpuTempConfig();
inhibitorInitTimer.start() inhibitorInitTimer.start();
} }
Timer { Timer {
@@ -152,7 +274,7 @@ PanelWindow {
repeat: false repeat: false
onTriggered: { onTriggered: {
if (SessionService.nativeInhibitorAvailable) { if (SessionService.nativeInhibitorAvailable) {
createNativeInhibitor() createNativeInhibitor();
} }
} }
} }
@@ -160,32 +282,35 @@ PanelWindow {
Connections { Connections {
target: PluginService target: PluginService
function onPluginLoaded(pluginId) { function onPluginLoaded(pluginId) {
console.info("DankBar: Plugin loaded:", pluginId) console.info("DankBar: Plugin loaded:", pluginId);
SettingsData.widgetDataChanged() SettingsData.widgetDataChanged();
} }
function onPluginUnloaded(pluginId) { function onPluginUnloaded(pluginId) {
console.info("DankBar: Plugin unloaded:", pluginId) console.info("DankBar: Plugin unloaded:", pluginId);
SettingsData.widgetDataChanged() SettingsData.widgetDataChanged();
} }
} }
function updateGpuTempConfig() { function updateGpuTempConfig() {
const allWidgets = [...(SettingsData.dankBarLeftWidgets || []), ...(SettingsData.dankBarCenterWidgets || []), ...(SettingsData.dankBarRightWidgets || [])] const leftWidgets = barConfig?.leftWidgets || [];
const centerWidgets = barConfig?.centerWidgets || [];
const rightWidgets = barConfig?.rightWidgets || [];
const allWidgets = [...leftWidgets, ...centerWidgets, ...rightWidgets];
const hasGpuTempWidget = allWidgets.some(widget => { const hasGpuTempWidget = allWidgets.some(widget => {
const widgetId = typeof widget === "string" ? widget : widget.id const widgetId = typeof widget === "string" ? widget : widget.id;
const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false) const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false);
return widgetId === "gpuTemp" && widgetEnabled return widgetId === "gpuTemp" && widgetEnabled;
}) });
DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled;
DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled;
DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled;
} }
function createNativeInhibitor() { function createNativeInhibitor() {
if (!SessionService.nativeInhibitorAvailable) { if (!SessionService.nativeInhibitorAvailable) {
return return;
} }
try { try {
@@ -196,121 +321,88 @@ PanelWindow {
IdleInhibitor { IdleInhibitor {
enabled: false enabled: false
} }
` `;
nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor") nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor");
nativeInhibitor.window = barWindow nativeInhibitor.window = barWindow;
nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited) nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited);
nativeInhibitor.enabledChanged.connect(function () { nativeInhibitor.enabledChanged.connect(function () {
console.log("DankBar: Native inhibitor enabled changed to:", nativeInhibitor.enabled)
if (SessionService.idleInhibited !== nativeInhibitor.enabled) { if (SessionService.idleInhibited !== nativeInhibitor.enabled) {
SessionService.idleInhibited = nativeInhibitor.enabled SessionService.idleInhibited = nativeInhibitor.enabled;
SessionService.inhibitorChanged() SessionService.inhibitorChanged();
} }
}) });
console.log("DankBar: Created native Wayland IdleInhibitor for", barWindow.screenName)
} catch (e) { } catch (e) {
console.warn("DankBar: Failed to create native IdleInhibitor:", e) nativeInhibitor = null;
nativeInhibitor = null
} }
} }
Connections { Connections {
function onDankBarLeftWidgetsChanged() { function onBarConfigChanged() {
barWindow.updateGpuTempConfig() barWindow.updateGpuTempConfig();
} }
function onDankBarCenterWidgetsChanged() { target: rootWindow
barWindow.updateGpuTempConfig()
}
function onDankBarRightWidgetsChanged() {
barWindow.updateGpuTempConfig()
}
target: SettingsData
} }
Connections { Connections {
function onNvidiaGpuTempEnabledChanged() { function onNvidiaGpuTempEnabledChanged() {
barWindow.updateGpuTempConfig() barWindow.updateGpuTempConfig();
} }
function onNonNvidiaGpuTempEnabledChanged() { function onNonNvidiaGpuTempEnabledChanged() {
barWindow.updateGpuTempConfig() barWindow.updateGpuTempConfig();
} }
target: SessionData target: SessionData
} }
Connections {
target: barWindow.screen
function onGeometryChanged() {
Qt.callLater(forceWidgetRefresh)
}
}
Timer { readonly property int barPos: barConfig?.position ?? 0
id: refreshTimer
interval: 0
running: false
repeat: false
onTriggered: {
forceWidgetRefresh()
}
}
Connections { anchors.top: !isVertical ? (barPos === SettingsData.Position.Top) : true
target: axis anchors.bottom: !isVertical ? (barPos === SettingsData.Position.Bottom) : true
function onChanged() { anchors.left: !isVertical ? true : (barPos === SettingsData.Position.Left)
Qt.application.active anchors.right: !isVertical ? true : (barPos === SettingsData.Position.Right)
refreshTimer.restart()
}
}
anchors.top: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Top) : true exclusiveZone: (!(barConfig?.visible ?? true) || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4) + (barConfig?.bottomGap ?? 0))
anchors.bottom: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom) : true
anchors.left: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Left)
anchors.right: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Right)
exclusiveZone: (!SettingsData.dankBarVisible || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap)
Item { Item {
id: inputMask id: inputMask
readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4), barWindow._dpr)
readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false)
readonly property bool effectiveVisible: SettingsData.dankBarVisible || inOverviewWithShow readonly property bool effectiveVisible: (barConfig?.visible ?? true) || inOverviewWithShow
readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide) readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide)
readonly property int maskThickness: showing ? barThickness : 1 readonly property int maskThickness: showing ? barThickness : 1
x: { x: {
if (!axis.isVertical) { if (!axis.isVertical) {
return 0 return 0;
} else { } else {
switch (SettingsData.dankBarPosition) { switch (barPos) {
case SettingsData.Position.Left: case SettingsData.Position.Left:
return 0 return 0;
case SettingsData.Position.Right: case SettingsData.Position.Right:
return parent.width - maskThickness return parent.width - maskThickness;
default: default:
return 0 return 0;
} }
} }
} }
y: { y: {
if (axis.isVertical) { if (axis.isVertical) {
return 0 return 0;
} else { } else {
switch (SettingsData.dankBarPosition) { switch (barPos) {
case SettingsData.Position.Top: case SettingsData.Position.Top:
return 0 return 0;
case SettingsData.Position.Bottom: case SettingsData.Position.Bottom:
return parent.height - maskThickness return parent.height - maskThickness;
default: default:
return 0 return 0;
} }
} }
} }
@@ -327,112 +419,97 @@ PanelWindow {
anchors.fill: parent anchors.fill: parent
layer.enabled: true layer.enabled: true
property real backgroundTransparency: SettingsData.dankBarTransparency property real backgroundTransparency: barConfig?.transparency ?? 1.0
property bool autoHide: SettingsData.dankBarAutoHide property bool autoHide: barConfig?.autoHide ?? false
property bool revealSticky: false property bool revealSticky: false
Timer { Timer {
id: revealHold id: revealHold
interval: SettingsData.dankBarAutoHideDelay interval: barConfig?.autoHideDelay ?? 250
repeat: false repeat: false
onTriggered: topBarCore.revealSticky = false onTriggered: {
if (!topBarMouseArea.containsMouse && !topBarCore.hasActivePopout) {
topBarCore.revealSticky = false;
}
}
} }
property bool reveal: { property bool reveal: {
if (CompositorService.isNiri && NiriService.inOverview) { if (CompositorService.isNiri && NiriService.inOverview) {
return SettingsData.dankBarOpenOnOverview || topBarMouseArea.containsMouse || hasActivePopout || revealSticky return (barConfig?.openOnOverview ?? false) || topBarMouseArea.containsMouse || hasActivePopout || revealSticky;
} }
return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky) return (barConfig?.visible ?? true) && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky);
} }
readonly property bool hasActivePopout: { property bool hasActivePopout: false
const loaders = [{
"loader": appDrawerLoader, onHasActivePopoutChanged: evaluateReveal()
"prop": "shouldBeVisible"
}, { Connections {
"loader": dankDashPopoutLoader, target: PopoutManager
"prop": "shouldBeVisible" function onPopoutChanged() {
}, { const screenName = barWindow.screen.name;
"loader": processListPopoutLoader, const activePopout = PopoutManager.currentPopoutsByScreen[screenName];
"prop": "shouldBeVisible" const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName];
}, { const trayOpen = rootWindow.systemTrayMenuOpen;
"loader": notificationCenterLoader,
"prop": "shouldBeVisible" topBarCore.hasActivePopout = !!(activePopout || activeTrayMenu || trayOpen);
}, { }
"loader": batteryPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": layoutPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": vpnPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": controlCenterLoader,
"prop": "shouldBeVisible"
}, {
"loader": clipboardHistoryModalPopup,
"prop": "visible"
}, {
"loader": systemUpdateLoader,
"prop": "shouldBeVisible"
}]
return loaders.some(item => {
if (item.loader && item.loader.item) {
return item.loader.item[item.prop]
}
return false
}) || rootWindow.systemTrayMenuOpen
} }
Connections { Connections {
function onDankBarTransparencyChanged() { function onBarConfigChanged() {
topBarCore.backgroundTransparency = SettingsData.dankBarTransparency topBarCore.backgroundTransparency = barConfig?.transparency ?? 1.0;
topBarCore.autoHide = barConfig?.autoHide ?? false;
revealHold.interval = barConfig?.autoHideDelay ?? 250;
} }
target: SettingsData target: rootWindow
}
function evaluateReveal() {
if (!autoHide)
return;
if (topBarMouseArea.containsMouse || hasActivePopout) {
revealSticky = true;
revealHold.stop();
return;
}
revealHold.restart();
} }
Connections { Connections {
target: topBarMouseArea target: topBarMouseArea
function onContainsMouseChanged() { function onContainsMouseChanged() {
if (topBarMouseArea.containsMouse) { topBarCore.evaluateReveal();
topBarCore.revealSticky = true
revealHold.stop()
} else {
if (topBarCore.autoHide && !topBarCore.hasActivePopout) {
revealHold.restart()
}
}
} }
} }
onHasActivePopoutChanged: { Connections {
if (hasActivePopout) { target: PopoutManager
revealSticky = true function onPopoutOpening() {
revealHold.stop() topBarCore.evaluateReveal();
} else if (autoHide && !topBarMouseArea.containsMouse) {
revealSticky = true
revealHold.restart()
} }
} }
MouseArea { MouseArea {
id: topBarMouseArea id: topBarMouseArea
y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0 y: !barWindow.isVertical ? (barPos === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0 x: barWindow.isVertical ? (barPos === SettingsData.Position.Right ? parent.width - width : 0) : 0
height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4), barWindow._dpr) : undefined
width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4), barWindow._dpr) : undefined
anchors { anchors {
left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined) left: !barWindow.isVertical ? parent.left : (barPos === SettingsData.Position.Left ? parent.left : undefined)
right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined) right: !barWindow.isVertical ? parent.right : (barPos === SettingsData.Position.Right ? parent.right : undefined)
top: barWindow.isVertical ? parent.top : undefined top: barWindow.isVertical ? parent.top : undefined
bottom: barWindow.isVertical ? parent.bottom : undefined bottom: barWindow.isVertical ? parent.bottom : undefined
} }
readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false)
hoverEnabled: SettingsData.dankBarAutoHide && !inOverview hoverEnabled: (barConfig?.autoHide ?? false) && !inOverview && !topBarCore.hasActivePopout
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
enabled: SettingsData.dankBarAutoHide && !inOverview enabled: (barConfig?.autoHide ?? false) && !inOverview
Item { Item {
id: topBarContainer id: topBarContainer
@@ -440,8 +517,8 @@ PanelWindow {
transform: Translate { transform: Translate {
id: topBarSlide id: topBarSlide
x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0 x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0
y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0 y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0
Behavior on x { Behavior on x {
NumberAnimation { NumberAnimation {
@@ -460,16 +537,18 @@ PanelWindow {
Item { Item {
id: barUnitInset id: barUnitInset
property int spacingPx: Theme.px(barConfig?.spacing ?? 4, barWindow._dpr)
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "left" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) anchors.leftMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "left" ? spacingPx : 0)
anchors.rightMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "right" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) anchors.rightMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "right" ? spacingPx : 0)
anchors.topMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? 0 : Theme.px(SettingsData.dankBarSpacing, barWindow._dpr)) anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? 0 : spacingPx)
anchors.bottomMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? spacingPx : 0)
BarCanvas { BarCanvas {
id: barBackground id: barBackground
barWindow: barWindow barWindow: barWindow
axis: axis axis: axis
barConfig: barWindow.barConfig
} }
MouseArea { MouseArea {
@@ -491,39 +570,39 @@ PanelWindow {
onWheel: wheel => { onWheel: wheel => {
if (actionInProgress) { if (actionInProgress) {
wheel.accepted = false wheel.accepted = false;
return return;
} }
const deltaY = wheel.angleDelta.y const deltaY = wheel.angleDelta.y;
const deltaX = wheel.angleDelta.x const deltaX = wheel.angleDelta.x;
if (CompositorService.isNiri && Math.abs(deltaX) > Math.abs(deltaY)) { if (CompositorService.isNiri && Math.abs(deltaX) > Math.abs(deltaY)) {
topBarContent.switchApp(deltaX) topBarContent.switchApp(deltaX);
wheel.accepted = false wheel.accepted = false;
return return;
} }
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0 const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0;
const direction = deltaY < 0 ? 1 : -1 const direction = deltaY < 0 ? 1 : -1;
if (isMouseWheel) { if (isMouseWheel) {
topBarContent.switchWorkspace(direction) topBarContent.switchWorkspace(direction);
actionInProgress = true actionInProgress = true;
cooldownTimer.restart() cooldownTimer.restart();
} else { } else {
scrollAccumulator += deltaY scrollAccumulator += deltaY;
if (Math.abs(scrollAccumulator) >= touchpadThreshold) { if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
const touchDirection = scrollAccumulator < 0 ? 1 : -1 const touchDirection = scrollAccumulator < 0 ? 1 : -1;
topBarContent.switchWorkspace(touchDirection) topBarContent.switchWorkspace(touchDirection);
scrollAccumulator = 0 scrollAccumulator = 0;
actionInProgress = true actionInProgress = true;
cooldownTimer.restart() cooldownTimer.restart();
} }
} }
wheel.accepted = false wheel.accepted = false;
} }
} }
@@ -531,6 +610,10 @@ PanelWindow {
id: topBarContent id: topBarContent
barWindow: barWindow barWindow: barWindow
rootWindow: rootWindow rootWindow: rootWindow
barConfig: barWindow.barConfig
leftWidgetsModel: barWindow.leftWidgetsModel
centerWidgetsModel: barWindow.centerWidgetsModel
rightWidgetsModel: barWindow.rightWidgetsModel
} }
} }
} }

View File

@@ -11,13 +11,15 @@ Item {
property var parentScreen: null property var parentScreen: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool overrideAxisLayout: false property bool overrideAxisLayout: false
property bool forceVerticalLayout: false property bool forceVerticalLayout: false
readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false)
implicitHeight: layoutLoader.item ? (layoutLoader.item.implicitHeight || layoutLoader.item.height) : 0 implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0
implicitWidth: layoutLoader.item ? (layoutLoader.item.implicitWidth || layoutLoader.item.width) : 0 implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0
Loader { Loader {
id: layoutLoader id: layoutLoader
@@ -35,14 +37,15 @@ Item {
model: root.widgetsModel model: root.widgetsModel
Item { Item {
readonly property real rowSpacing: parent.widgetSpacing readonly property real rowSpacing: parent.widgetSpacing
property var itemData: modelData
width: widgetLoader.item ? widgetLoader.item.width : 0 width: widgetLoader.item ? widgetLoader.item.width : 0
height: widgetLoader.item ? widgetLoader.item.height : 0 height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost { WidgetHost {
id: widgetLoader id: widgetLoader
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
widgetId: model.widgetId widgetId: itemData.widgetId
widgetData: model widgetData: itemData
spacerSize: model.size || 20 spacerSize: itemData.size || 20
components: root.components components: root.components
isInColumn: false isInColumn: false
axis: root.axis axis: root.axis
@@ -50,8 +53,10 @@ Item {
parentScreen: root.parentScreen parentScreen: root.parentScreen
widgetThickness: root.widgetThickness widgetThickness: root.widgetThickness
barThickness: root.barThickness barThickness: root.barThickness
isFirst: model.index === 0 barSpacing: root.barSpacing
isLast: model.index === rowRepeater.count - 1 barConfig: root.barConfig
isFirst: index === 0
isLast: index === rowRepeater.count - 1
sectionSpacing: parent.rowSpacing sectionSpacing: parent.rowSpacing
isLeftBarEdge: true isLeftBarEdge: true
isRightBarEdge: false isRightBarEdge: false
@@ -64,22 +69,23 @@ Item {
Component { Component {
id: columnComp id: columnComp
Column { Column {
width: Math.max(parent.width, 200) width: parent.width
readonly property real widgetSpacing: noBackground ? 2 : Theme.spacingXS readonly property real widgetSpacing: noBackground ? 2 : Theme.spacingXS
spacing: widgetSpacing spacing: widgetSpacing
Repeater { Repeater {
id: columnRepeater id: columnRepeater
model: root.widgetsModel model: root.widgetsModel
Item { Item {
readonly property real columnSpacing: parent.widgetSpacing
width: parent.width width: parent.width
readonly property real columnSpacing: parent.widgetSpacing
property var itemData: modelData
height: widgetLoader.item ? widgetLoader.item.height : 0 height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost { WidgetHost {
id: widgetLoader id: widgetLoader
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
widgetId: model.widgetId widgetId: itemData.widgetId
widgetData: model widgetData: itemData
spacerSize: model.size || 20 spacerSize: itemData.size || 20
components: root.components components: root.components
isInColumn: true isInColumn: true
axis: root.axis axis: root.axis
@@ -87,8 +93,10 @@ Item {
parentScreen: root.parentScreen parentScreen: root.parentScreen
widgetThickness: root.widgetThickness widgetThickness: root.widgetThickness
barThickness: root.barThickness barThickness: root.barThickness
isFirst: model.index === 0 barSpacing: root.barSpacing
isLast: model.index === columnRepeater.count - 1 barConfig: root.barConfig
isFirst: index === 0
isLast: index === columnRepeater.count - 1
sectionSpacing: parent.columnSpacing sectionSpacing: parent.columnSpacing
isTopBarEdge: true isTopBarEdge: true
isBottomBarEdge: false isBottomBarEdge: false

View File

@@ -15,14 +15,6 @@ DankPopout {
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
function isActiveProfile(profile) { function isActiveProfile(profile) {
if (typeof PowerProfiles === "undefined") { if (typeof PowerProfiles === "undefined") {
return false; return false;
@@ -45,8 +37,6 @@ DankPopout {
popupWidth: 400 popupWidth: 400
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400 popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerWidth: 70 triggerWidth: 70
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen

View File

@@ -14,18 +14,30 @@ DankPopout {
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) { function setTriggerPosition(x, y, width, section, screen, barPosition, barThickness, barSpacing, barConfig) {
triggerX = x triggerX = x
triggerY = y triggerY = y
triggerWidth = width triggerWidth = width
triggerSection = section triggerSection = section
triggerScreen = screen 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
setBarContext(pos, bottomGap)
updateOutputState() updateOutputState()
} }
onScreenChanged: updateOutputState()
function updateOutputState() { function updateOutputState() {
if (triggerScreen && DwlService.dwlAvailable) { if (screen && DwlService.dwlAvailable) {
outputState = DwlService.getOutputState(triggerScreen.name) outputState = DwlService.getOutputState(screen.name)
} else { } else {
outputState = null outputState = null
} }
@@ -89,8 +101,6 @@ DankPopout {
popupWidth: 300 popupWidth: 300
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 550 popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 550
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerWidth: 70 triggerWidth: 70
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen
@@ -271,19 +281,13 @@ DankPopout {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
console.log("DWLLayoutPopout: Pressed layout", modelData, "at index", index)
console.log("DWLLayoutPopout: triggerScreen:", root.triggerScreen, "dwlAvailable:", DwlService.dwlAvailable)
if (!root.triggerScreen) { if (!root.triggerScreen) {
console.error("DWLLayoutPopout: triggerScreen is null!")
return return
} }
if (!DwlService.dwlAvailable) { if (!DwlService.dwlAvailable) {
console.error("DWLLayoutPopout: DwlService not available!")
return return
} }
console.log("DWLLayoutPopout: CALLING setLayout with output:", root.triggerScreen.name, "index:", index)
DwlService.setLayout(root.triggerScreen.name, index) DwlService.setLayout(root.triggerScreen.name, index)
root.close() root.close()
} }

View File

@@ -30,20 +30,9 @@ DankPopout {
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
popupWidth: 360 popupWidth: 360
popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 260) popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 260)
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerWidth: 70 triggerWidth: 70
positioning: ""
screen: triggerScreen screen: triggerScreen
shouldBeVisible: false shouldBeVisible: false

View File

@@ -11,6 +11,8 @@ Item {
property var parentScreen: null property var parentScreen: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool overrideAxisLayout: false property bool overrideAxisLayout: false
property bool forceVerticalLayout: false property bool forceVerticalLayout: false
@@ -37,14 +39,15 @@ Item {
model: root.widgetsModel model: root.widgetsModel
Item { Item {
readonly property real rowSpacing: parent.widgetSpacing readonly property real rowSpacing: parent.widgetSpacing
property var itemData: modelData
width: widgetLoader.item ? widgetLoader.item.width : 0 width: widgetLoader.item ? widgetLoader.item.width : 0
height: widgetLoader.item ? widgetLoader.item.height : 0 height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost { WidgetHost {
id: widgetLoader id: widgetLoader
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
widgetId: model.widgetId widgetId: itemData.widgetId
widgetData: model widgetData: itemData
spacerSize: model.size || 20 spacerSize: itemData.size || 20
components: root.components components: root.components
isInColumn: false isInColumn: false
axis: root.axis axis: root.axis
@@ -52,8 +55,10 @@ Item {
parentScreen: root.parentScreen parentScreen: root.parentScreen
widgetThickness: root.widgetThickness widgetThickness: root.widgetThickness
barThickness: root.barThickness barThickness: root.barThickness
isFirst: model.index === 0 barSpacing: root.barSpacing
isLast: model.index === rowRepeater.count - 1 barConfig: root.barConfig
isFirst: index === 0
isLast: index === rowRepeater.count - 1
sectionSpacing: parent.rowSpacing sectionSpacing: parent.rowSpacing
isLeftBarEdge: false isLeftBarEdge: false
isRightBarEdge: true isRightBarEdge: true
@@ -66,22 +71,23 @@ Item {
Component { Component {
id: columnComp id: columnComp
Column { Column {
width: parent ? parent.width : 0 width: parent.width
readonly property real widgetSpacing: noBackground ? 2 : Theme.spacingXS readonly property real widgetSpacing: noBackground ? 2 : Theme.spacingXS
spacing: widgetSpacing spacing: widgetSpacing
Repeater { Repeater {
id: columnRepeater id: columnRepeater
model: root.widgetsModel model: root.widgetsModel
Item { Item {
readonly property real columnSpacing: parent.widgetSpacing
width: parent.width width: parent.width
readonly property real columnSpacing: parent.widgetSpacing
property var itemData: modelData
height: widgetLoader.item ? widgetLoader.item.height : 0 height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost { WidgetHost {
id: widgetLoader id: widgetLoader
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
widgetId: model.widgetId widgetId: itemData.widgetId
widgetData: model widgetData: itemData
spacerSize: model.size || 20 spacerSize: itemData.size || 20
components: root.components components: root.components
isInColumn: true isInColumn: true
axis: root.axis axis: root.axis
@@ -89,8 +95,10 @@ Item {
parentScreen: root.parentScreen parentScreen: root.parentScreen
widgetThickness: root.widgetThickness widgetThickness: root.widgetThickness
barThickness: root.barThickness barThickness: root.barThickness
isFirst: model.index === 0 barSpacing: root.barSpacing
isLast: model.index === columnRepeater.count - 1 barConfig: root.barConfig
isFirst: index === 0
isLast: index === columnRepeater.count - 1
sectionSpacing: parent.columnSpacing sectionSpacing: parent.columnSpacing
isTopBarEdge: false isTopBarEdge: false
isBottomBarEdge: true isBottomBarEdge: true

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import Quickshell.Services.Mpris
import qs.Services import qs.Services
Loader { Loader {
@@ -15,6 +14,8 @@ Loader {
property var parentScreen: null property var parentScreen: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool isFirst: false property bool isFirst: false
property bool isLast: false property bool isLast: false
property real sectionSpacing: 0 property real sectionSpacing: 0
@@ -27,9 +28,7 @@ Loader {
readonly property bool orientationMatches: (axis?.isVertical ?? false) === isInColumn readonly property bool orientationMatches: (axis?.isVertical ?? false) === isInColumn
active: orientationMatches && active: orientationMatches && getWidgetVisible(widgetId, DgopService.dgopAvailable) && (widgetId !== "music" || MprisController.activePlayer !== null)
getWidgetVisible(widgetId, DgopService.dgopAvailable) &&
(widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: getWidgetComponent(widgetId, components) sourceComponent: getWidgetComponent(widgetId, components)
opacity: getWidgetEnabled(widgetData?.enabled) ? 1 : 0 opacity: getWidgetEnabled(widgetData?.enabled) ? 1 : 0
@@ -67,6 +66,22 @@ Loader {
restoreMode: Binding.RestoreNone restoreMode: Binding.RestoreNone
} }
Binding {
target: root.item
when: root.item && "barSpacing" in root.item
property: "barSpacing"
value: root.barSpacing
restoreMode: Binding.RestoreNone
}
Binding {
target: root.item
when: root.item && "barConfig" in root.item
property: "barConfig"
value: root.barConfig
restoreMode: Binding.RestoreNone
}
Binding { Binding {
target: root.item target: root.item
when: root.item && "axis" in root.item when: root.item && "axis" in root.item
@@ -141,33 +156,32 @@ Loader {
onLoaded: { onLoaded: {
if (item) { if (item) {
contentItemReady(item) contentItemReady(item);
if (axis && "isVertical" in item) { if (axis && "isVertical" in item) {
try { try {
item.isVertical = axis.isVertical item.isVertical = axis.isVertical;
} catch (e) { } catch (e) {}
}
} }
if (item.pluginService !== undefined) { if (item.pluginService !== undefined) {
var parts = widgetId.split(":") var parts = widgetId.split(":");
var pluginId = parts[0] var pluginId = parts[0];
var variantId = parts.length > 1 ? parts[1] : null var variantId = parts.length > 1 ? parts[1] : null;
if (item.pluginId !== undefined) { if (item.pluginId !== undefined) {
item.pluginId = pluginId item.pluginId = pluginId;
} }
if (item.variantId !== undefined) { if (item.variantId !== undefined) {
item.variantId = variantId item.variantId = variantId;
} }
if (item.variantData !== undefined && variantId) { if (item.variantData !== undefined && variantId) {
item.variantData = PluginService.getPluginVariantData(pluginId, variantId) item.variantData = PluginService.getPluginVariantData(pluginId, variantId);
} }
item.pluginService = PluginService item.pluginService = PluginService;
} }
if (item.popoutService !== undefined) { if (item.popoutService !== undefined) {
item.popoutService = PopoutService item.popoutService = PopoutService;
} }
} }
} }
@@ -203,17 +217,17 @@ Loader {
"colorPicker": components.colorPickerComponent, "colorPicker": components.colorPickerComponent,
"systemUpdate": components.systemUpdateComponent, "systemUpdate": components.systemUpdateComponent,
"layout": components.layoutComponent "layout": components.layoutComponent
} };
if (componentMap[widgetId]) { if (componentMap[widgetId]) {
return componentMap[widgetId] return componentMap[widgetId];
} }
var parts = widgetId.split(":") var parts = widgetId.split(":");
var pluginId = parts[0] var pluginId = parts[0];
let pluginMap = PluginService.getWidgetComponents() let pluginMap = PluginService.getWidgetComponents();
return pluginMap[pluginId] || null return pluginMap[pluginId] || null;
} }
function getWidgetVisible(widgetId, dgopAvailable) { function getWidgetVisible(widgetId, dgopAvailable) {
@@ -224,12 +238,12 @@ Loader {
"gpuTemp": dgopAvailable, "gpuTemp": dgopAvailable,
"network_speed_monitor": dgopAvailable, "network_speed_monitor": dgopAvailable,
"layout": CompositorService.isDwl && DwlService.dwlAvailable "layout": CompositorService.isDwl && DwlService.dwlAvailable
} };
return widgetVisibility[widgetId] ?? true return widgetVisibility[widgetId] ?? true;
} }
function getWidgetEnabled(enabled) { function getWidgetEnabled(enabled) {
return enabled !== false return enabled !== false;
} }
} }

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import Quickshell.Services.UPower
import qs.Common import qs.Common
import qs.Modules.Plugins import qs.Modules.Plugins
import qs.Services import qs.Services
@@ -11,7 +10,22 @@ BasePill {
property bool batteryPopupVisible: false property bool batteryPopupVisible: false
property var popoutTarget: null property var popoutTarget: null
signal toggleBatteryPopup() readonly property int barPosition: {
switch (axis?.edge) {
case "top":
return 0;
case "bottom":
return 1;
case "left":
return 2;
case "right":
return 3;
default:
return 0;
}
}
signal toggleBatteryPopup
visible: true visible: true
@@ -31,25 +45,25 @@ BasePill {
size: Theme.barIconSize(battery.barThickness) size: Theme.barIconSize(battery.barThickness)
color: { color: {
if (!BatteryService.batteryAvailable) { if (!BatteryService.batteryAvailable) {
return Theme.widgetIconColor return Theme.widgetIconColor;
} }
if (BatteryService.isLowBattery && !BatteryService.isCharging) { if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error return Theme.error;
} }
if (BatteryService.isCharging || BatteryService.isPluggedIn) { if (BatteryService.isCharging || BatteryService.isPluggedIn) {
return Theme.primary return Theme.primary;
} }
return Theme.widgetIconColor return Theme.widgetIconColor;
} }
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
StyledText { StyledText {
text: BatteryService.batteryLevel.toString() text: BatteryService.batteryLevel.toString()
font.pixelSize: Theme.barTextSize(battery.barThickness) font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: BatteryService.batteryAvailable visible: BatteryService.batteryAvailable
@@ -60,7 +74,7 @@ BasePill {
id: batteryContent id: batteryContent
visible: !battery.isVerticalOrientation visible: !battery.isVerticalOrientation
anchors.centerIn: parent anchors.centerIn: parent
spacing: SettingsData.dankBarNoBackground ? 1 : 2 spacing: (barConfig?.noBackground ?? false) ? 1 : 2
DankIcon { DankIcon {
name: BatteryService.getBatteryIcon() name: BatteryService.getBatteryIcon()
@@ -85,7 +99,7 @@ BasePill {
StyledText { StyledText {
text: `${BatteryService.batteryLevel}%` text: `${BatteryService.batteryLevel}%`
font.pixelSize: Theme.barTextSize(battery.barThickness) font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable visible: BatteryService.batteryAvailable
@@ -102,13 +116,7 @@ BasePill {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onPressed: { onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) { toggleBatteryPopup();
const globalPos = battery.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, battery.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
toggleBatteryPopup()
} }
} }
} }

View File

@@ -35,7 +35,7 @@ BasePill {
return String(display).padStart(2, '0').charAt(0) return String(display).padStart(2, '0').charAt(0)
} }
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -51,7 +51,7 @@ BasePill {
return String(display).padStart(2, '0').charAt(1) return String(display).padStart(2, '0').charAt(1)
} }
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -64,7 +64,7 @@ BasePill {
StyledText { StyledText {
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0) text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0)
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -72,7 +72,7 @@ BasePill {
StyledText { StyledText {
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1) text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1)
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -86,7 +86,7 @@ BasePill {
StyledText { StyledText {
text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(0) text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(0)
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -94,7 +94,7 @@ BasePill {
StyledText { StyledText {
text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(1) text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(1)
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -126,7 +126,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0') const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
return value.charAt(0) return value.charAt(0)
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary color: Theme.primary
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -140,7 +140,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0') const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
return value.charAt(1) return value.charAt(1)
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary color: Theme.primary
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -159,7 +159,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0') const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
return value.charAt(0) return value.charAt(0)
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary color: Theme.primary
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -173,7 +173,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0') const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
return value.charAt(1) return value.charAt(1)
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary color: Theme.primary
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom verticalAlignment: Text.AlignBottom
@@ -192,7 +192,7 @@ BasePill {
text: { text: {
return systemClock?.date?.toLocaleTimeString(Qt.locale(), SettingsData.getEffectiveTimeFormat()) return systemClock?.date?.toLocaleTimeString(Qt.locale(), SettingsData.getEffectiveTimeFormat())
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.baseline: dateText.baseline anchors.baseline: dateText.baseline
} }
@@ -214,7 +214,7 @@ BasePill {
} }
return systemClock?.date?.toLocaleDateString(Qt.locale(), "ddd d") return systemClock?.date?.toLocaleDateString(Qt.locale(), "ddd d")
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.clockCompactMode visible: !SettingsData.clockCompactMode
@@ -235,12 +235,6 @@ BasePill {
height: root.height + root.topMargin + root.bottomMargin height: root.height + root.topMargin + root.bottomMargin
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (root.popoutTarget && root.popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = root.parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.visualWidth)
root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen)
}
root.clockClicked() root.clockClicked()
} }
} }

View File

@@ -236,22 +236,4 @@ BasePill {
} }
} }
} }
MouseArea {
x: -root.leftMargin
y: -root.topMargin
width: root.width + root.leftMargin + root.rightMargin
height: root.height + root.topMargin + root.bottomMargin
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.clicked()
}
}
} }

View File

@@ -15,6 +15,8 @@ BasePill {
property var widgetData: null property var widgetData: null
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
signal cpuClicked()
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["cpu"]); DgopService.addRef(["cpu"]);
} }
@@ -58,7 +60,7 @@ BasePill {
return DgopService.cpuUsage.toFixed(0); return DgopService.cpuUsage.toFixed(0);
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -95,7 +97,7 @@ BasePill {
return DgopService.cpuUsage.toFixed(0) + "%"; return DgopService.cpuUsage.toFixed(0) + "%";
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -103,7 +105,7 @@ BasePill {
StyledTextMetrics { StyledTextMetrics {
id: cpuBaseline id: cpuBaseline
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100%" text: "100%"
} }
@@ -125,16 +127,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onPressed: { onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) { DgopService.setSortBy("cpu")
const globalPos = root.visualContent.mapToGlobal(0, 0) cpuClicked()
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("cpu");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "cpu");
}
} }
} }
} }

View File

@@ -15,6 +15,8 @@ BasePill {
property var widgetData: null property var widgetData: null
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
signal cpuTempClicked()
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["cpu"]); DgopService.addRef(["cpu"]);
} }
@@ -58,7 +60,7 @@ BasePill {
return Math.round(DgopService.cpuTemperature).toString(); return Math.round(DgopService.cpuTemperature).toString();
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -95,7 +97,7 @@ BasePill {
return Math.round(DgopService.cpuTemperature) + "°"; return Math.round(DgopService.cpuTemperature) + "°";
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -103,7 +105,7 @@ BasePill {
StyledTextMetrics { StyledTextMetrics {
id: tempBaseline id: tempBaseline
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100°" text: "100°"
} }
@@ -125,16 +127,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onPressed: { onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) { DgopService.setSortBy("cpu")
const globalPos = root.visualContent.mapToGlobal(0, 0) cpuTempClicked()
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("cpu");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "cpu_temp");
}
} }
} }
} }

View File

@@ -64,7 +64,7 @@ BasePill {
StyledText { StyledText {
text: layout.currentLayoutSymbol text: layout.currentLayoutSymbol
font.pixelSize: Theme.barTextSize(layout.barThickness) font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -74,7 +74,7 @@ BasePill {
id: layoutContent id: layoutContent
visible: !layout.isVerticalOrientation visible: !layout.isVerticalOrientation
anchors.centerIn: parent anchors.centerIn: parent
spacing: SettingsData.dankBarNoBackground ? 1 : 2 spacing: (barConfig?.noBackground ?? false) ? 1 : 2
DankIcon { DankIcon {
name: layout.getLayoutIcon(layout.currentLayoutSymbol) name: layout.getLayoutIcon(layout.currentLayoutSymbol)
@@ -85,7 +85,7 @@ BasePill {
StyledText { StyledText {
text: layout.currentLayoutSymbol text: layout.currentLayoutSymbol
font.pixelSize: Theme.barTextSize(layout.barThickness) font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@@ -94,12 +94,6 @@ BasePill {
} }
onClicked: { onClicked: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = layout.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, layout.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
toggleLayoutPopup() toggleLayoutPopup()
} }

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import QtQuick.Controls
import qs.Common import qs.Common
import qs.Modules.Plugins import qs.Modules.Plugins
import qs.Services import qs.Services
@@ -11,71 +10,90 @@ BasePill {
property var widgetData: null property var widgetData: null
property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/" property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/"
property bool isHovered: mouseArea.containsMouse property bool isHovered: mouseArea.containsMouse
property bool isAutoHideBar: false
property var selectedMount: { property var selectedMount: {
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
return null return null;
} }
const currentMountPath = root.mountPath || "/" const currentMountPath = root.mountPath || "/";
for (let i = 0; i < DgopService.diskMounts.length; i++) { for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === currentMountPath) { if (DgopService.diskMounts[i].mount === currentMountPath) {
return DgopService.diskMounts[i] return DgopService.diskMounts[i];
} }
} }
for (let i = 0; i < DgopService.diskMounts.length; i++) { for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === "/") { if (DgopService.diskMounts[i].mount === "/") {
return DgopService.diskMounts[i] return DgopService.diskMounts[i];
} }
} }
return DgopService.diskMounts[0] || null return DgopService.diskMounts[0] || null;
} }
property real diskUsagePercent: { property real diskUsagePercent: {
if (!selectedMount || !selectedMount.percent) { if (!selectedMount || !selectedMount.percent) {
return 0 return 0;
} }
const percentStr = selectedMount.percent.replace("%", "") const percentStr = selectedMount.percent.replace("%", "");
return parseFloat(percentStr) || 0 return parseFloat(percentStr) || 0;
} }
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["diskmounts"]) DgopService.addRef(["diskmounts"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["diskmounts"]) DgopService.removeRef(["diskmounts"]);
}
readonly property real minTooltipY: {
if (!parentScreen || !isVerticalOrientation) {
return 0;
}
if (isAutoHideBar) {
return 0;
}
if (parentScreen.y > 0) {
const spacing = barConfig?.spacing ?? 4;
const offset = barThickness + spacing;
return offset;
}
return 0;
} }
Connections { Connections {
function onWidgetDataChanged() { function onWidgetDataChanged() {
root.mountPath = Qt.binding(() => { root.mountPath = Qt.binding(() => {
return (root.widgetData && root.widgetData.mountPath !== undefined) ? root.widgetData.mountPath : "/" return (root.widgetData && root.widgetData.mountPath !== undefined) ? root.widgetData.mountPath : "/";
}) });
root.selectedMount = Qt.binding(() => { root.selectedMount = Qt.binding(() => {
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
return null return null;
} }
const currentMountPath = root.mountPath || "/" const currentMountPath = root.mountPath || "/";
for (let i = 0; i < DgopService.diskMounts.length; i++) { for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === currentMountPath) { if (DgopService.diskMounts[i].mount === currentMountPath) {
return DgopService.diskMounts[i] return DgopService.diskMounts[i];
} }
} }
for (let i = 0; i < DgopService.diskMounts.length; i++) { for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === "/") { if (DgopService.diskMounts[i].mount === "/") {
return DgopService.diskMounts[i] return DgopService.diskMounts[i];
} }
} }
return DgopService.diskMounts[0] || null return DgopService.diskMounts[0] || null;
}) });
} }
target: SettingsData target: SettingsData
@@ -97,12 +115,12 @@ BasePill {
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: { color: {
if (root.diskUsagePercent > 90) { if (root.diskUsagePercent > 90) {
return Theme.tempDanger return Theme.tempDanger;
} }
if (root.diskUsagePercent > 75) { if (root.diskUsagePercent > 75) {
return Theme.tempWarning return Theme.tempWarning;
} }
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -110,11 +128,11 @@ BasePill {
StyledText { StyledText {
text: { text: {
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) { if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
return "--" return "--";
} }
return root.diskUsagePercent.toFixed(0) return root.diskUsagePercent.toFixed(0);
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -131,12 +149,12 @@ BasePill {
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: { color: {
if (root.diskUsagePercent > 90) { if (root.diskUsagePercent > 90) {
return Theme.tempDanger return Theme.tempDanger;
} }
if (root.diskUsagePercent > 75) { if (root.diskUsagePercent > 75) {
return Theme.tempWarning return Theme.tempWarning;
} }
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@@ -144,11 +162,11 @@ BasePill {
StyledText { StyledText {
text: { text: {
if (!root.selectedMount) { if (!root.selectedMount) {
return "--" return "--";
} }
return root.selectedMount.mount return root.selectedMount.mount;
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -158,11 +176,11 @@ BasePill {
StyledText { StyledText {
text: { text: {
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) { if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
return "--%" return "--%";
} }
return root.diskUsagePercent.toFixed(0) + "%" return root.diskUsagePercent.toFixed(0) + "%";
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -170,7 +188,7 @@ BasePill {
StyledTextMetrics { StyledTextMetrics {
id: diskBaseline id: diskBaseline
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100%" text: "100%"
} }
@@ -200,24 +218,25 @@ BasePill {
hoverEnabled: root.isVerticalOrientation hoverEnabled: root.isVerticalOrientation
onEntered: { onEntered: {
if (root.isVerticalOrientation && root.selectedMount) { if (root.isVerticalOrientation && root.selectedMount) {
tooltipLoader.active = true tooltipLoader.active = true;
if (tooltipLoader.item) { if (tooltipLoader.item) {
const globalPos = mapToGlobal(width / 2, height / 2) const globalPos = mapToGlobal(width / 2, height / 2);
const currentScreen = root.parentScreen || Screen const currentScreen = root.parentScreen || Screen;
const screenX = currentScreen ? currentScreen.x : 0 const screenX = currentScreen ? currentScreen.x : 0;
const screenY = currentScreen ? currentScreen.y : 0 const screenY = currentScreen ? currentScreen.y : 0;
const relativeY = globalPos.y - screenY const relativeY = globalPos.y - screenY;
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS) const adjustedY = relativeY + root.minTooltipY;
const isLeft = root.axis?.edge === "left" const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS);
tooltipLoader.item.show(root.selectedMount.mount, screenX + tooltipX, relativeY, currentScreen, isLeft, !isLeft) const isLeft = root.axis?.edge === "left";
tooltipLoader.item.show(root.selectedMount.mount, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft);
} }
} }
} }
onExited: { onExited: {
if (tooltipLoader.item) { if (tooltipLoader.item) {
tooltipLoader.item.hide() tooltipLoader.item.hide();
} }
tooltipLoader.active = false tooltipLoader.active = false;
} }
} }
} }

View File

@@ -18,6 +18,23 @@ BasePill {
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
property var activeDesktopEntry: null property var activeDesktopEntry: null
property bool isHovered: mouseArea.containsMouse property bool isHovered: mouseArea.containsMouse
property bool isAutoHideBar: false
readonly property real minTooltipY: {
if (!parentScreen || !isVerticalOrientation) {
return 0
}
if (isAutoHideBar) {
return 0
}
if (parentScreen.y > 0) {
return barThickness + (barSpacing || 4)
}
return 0
}
Component.onCompleted: { Component.onCompleted: {
updateDesktopEntry() updateDesktopEntry()
@@ -80,7 +97,6 @@ BasePill {
return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id
} catch (e) { } catch (e) {
console.error("FocusedApp: hasWindowsOnCurrentWorkspace error:", e)
return false return false
} }
} }
@@ -167,7 +183,7 @@ BasePill {
const desktopEntry = DesktopEntries.heuristicLookup(activeWindow.appId); const desktopEntry = DesktopEntries.heuristicLookup(activeWindow.appId);
return desktopEntry && desktopEntry.name ? desktopEntry.name : activeWindow.appId; return desktopEntry && desktopEntry.name ? desktopEntry.name : activeWindow.appId;
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight elide: Text.ElideRight
@@ -178,7 +194,7 @@ BasePill {
StyledText { StyledText {
text: "•" text: "•"
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.outlineButton color: Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !compactMode && appText.text && titleText.text visible: !compactMode && appText.text && titleText.text
@@ -203,7 +219,7 @@ BasePill {
return title; return title;
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight elide: Text.ElideRight
@@ -229,14 +245,16 @@ BasePill {
const screenX = currentScreen ? currentScreen.x : 0 const screenX = currentScreen ? currentScreen.x : 0
const screenY = currentScreen ? currentScreen.y : 0 const screenY = currentScreen ? currentScreen.y : 0
const relativeY = globalPos.y - screenY const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS) // Add minTooltipY offset to account for top bar
const adjustedY = relativeY + root.minTooltipY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS)
const appName = activeDesktopEntry && activeDesktopEntry.name ? activeDesktopEntry.name : activeWindow.appId const appName = activeDesktopEntry && activeDesktopEntry.name ? activeDesktopEntry.name : activeWindow.appId
const title = activeWindow.title || "" const title = activeWindow.title || ""
const tooltipText = appName + (title ? " • " + title : "") const tooltipText = appName + (title ? " • " + title : "")
const isLeft = root.axis?.edge === "left" const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, currentScreen, isLeft, !isLeft) tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft)
} }
} }
} }

View File

@@ -15,6 +15,9 @@ BasePill {
property var widgetData: null property var widgetData: null
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0 property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
signal gpuTempClicked()
property real displayTemp: { property real displayTemp: {
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) { if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
return 0; return 0;
@@ -29,15 +32,18 @@ BasePill {
function updateWidgetPciId(pciId) { function updateWidgetPciId(pciId) {
const sections = ["left", "center", "right"]; const sections = ["left", "center", "right"];
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar) return
for (let s = 0; s < sections.length; s++) { for (let s = 0; s < sections.length; s++) {
const sectionId = sections[s]; const sectionId = sections[s];
let widgets = []; let widgets = [];
if (sectionId === "left") { if (sectionId === "left") {
widgets = SettingsData.dankBarLeftWidgets.slice(); widgets = (defaultBar.leftWidgets || []).slice();
} else if (sectionId === "center") { } else if (sectionId === "center") {
widgets = SettingsData.dankBarCenterWidgets.slice(); widgets = (defaultBar.centerWidgets || []).slice();
} else if (sectionId === "right") { } else if (sectionId === "right") {
widgets = SettingsData.dankBarRightWidgets.slice(); widgets = (defaultBar.rightWidgets || []).slice();
} }
for (let i = 0; i < widgets.length; i++) { for (let i = 0; i < widgets.length; i++) {
const widget = widgets[i]; const widget = widgets[i];
@@ -122,7 +128,7 @@ BasePill {
return Math.round(root.displayTemp).toString(); return Math.round(root.displayTemp).toString();
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -159,7 +165,7 @@ BasePill {
return Math.round(root.displayTemp) + "°"; return Math.round(root.displayTemp) + "°";
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -167,7 +173,7 @@ BasePill {
StyledTextMetrics { StyledTextMetrics {
id: gpuTempBaseline id: gpuTempBaseline
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100°" text: "100°"
} }
@@ -189,16 +195,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onPressed: { onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) { DgopService.setSortBy("cpu")
const globalPos = root.visualContent.mapToGlobal(0, 0) gpuTempClicked()
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("cpu");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "gpu_temp");
}
} }
} }

View File

@@ -50,7 +50,7 @@ BasePill {
} }
return root.currentLayout.substring(0, 2).toUpperCase() return root.currentLayout.substring(0, 2).toUpperCase()
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -64,7 +64,7 @@ BasePill {
StyledText { StyledText {
text: root.currentLayout text: root.currentLayout
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }

View File

@@ -174,7 +174,7 @@ BasePill {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: textContainer.displayText text: textContainer.displayText
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
x: needsScrolling ? -scrollOffset : 0 x: needsScrolling ? -scrollOffset : 0

View File

@@ -53,7 +53,7 @@ BasePill {
if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K" if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K"
return (rate / (1024 * 1024)).toFixed(0) + "M" return (rate / (1024 * 1024)).toFixed(0) + "M"
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.info color: Theme.info
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -65,7 +65,7 @@ BasePill {
if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K" if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K"
return (rate / (1024 * 1024)).toFixed(0) + "M" return (rate / (1024 * 1024)).toFixed(0) + "M"
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.error color: Theme.error
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -90,13 +90,13 @@ BasePill {
StyledText { StyledText {
text: "↓" text: "↓"
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.info color: Theme.info
} }
StyledText { StyledText {
text: DgopService.networkRxRate > 0 ? root.formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s" text: DgopService.networkRxRate > 0 ? root.formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s"
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -105,7 +105,7 @@ BasePill {
StyledTextMetrics { StyledTextMetrics {
id: rxBaseline id: rxBaseline
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "88.8 MB/s" text: "88.8 MB/s"
} }
@@ -126,13 +126,13 @@ BasePill {
StyledText { StyledText {
text: "↑" text: "↑"
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.error color: Theme.error
} }
StyledText { StyledText {
text: DgopService.networkTxRate > 0 ? root.formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s" text: DgopService.networkTxRate > 0 ? root.formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s"
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -141,7 +141,7 @@ BasePill {
StyledTextMetrics { StyledTextMetrics {
id: txBaseline id: txBaseline
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "88.8 MB/s" text: "88.8 MB/s"
} }

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import QtQuick.Controls
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
@@ -14,14 +13,15 @@ Item {
property var parentScreen: null property var parentScreen: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
property var barConfig: null
property bool showMicIcon: SettingsData.privacyShowMicIcon property bool showMicIcon: SettingsData.privacyShowMicIcon
property bool showCameraIcon: SettingsData.privacyShowCameraIcon property bool showCameraIcon: SettingsData.privacyShowCameraIcon
property bool showScreenSharingIcon: SettingsData.privacyShowScreenShareIcon property bool showScreenSharingIcon: SettingsData.privacyShowScreenShareIcon
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
readonly property bool hasActivePrivacy: showMicIcon || showCameraIcon || showScreenSharingIcon || PrivacyService.anyPrivacyActive readonly property bool hasActivePrivacy: showMicIcon || showCameraIcon || showScreenSharingIcon || PrivacyService.anyPrivacyActive
readonly property int activeCount: ( showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive) readonly property int activeCount: (showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive)
readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0 readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0 readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
readonly property real visualWidth: isVertical ? widgetThickness : (hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0) readonly property real visualWidth: isVertical ? widgetThickness : (hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0)
@@ -38,14 +38,15 @@ Item {
width: root.visualWidth width: root.visualWidth
height: root.visualHeight height: root.visualHeight
anchors.centerIn: parent anchors.centerIn: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.dankBarNoBackground) { if (barConfig?.noBackground ?? false) {
return "transparent" return "transparent";
} }
const baseColor = Theme.widgetBaseBackgroundColor const baseColor = privacyArea.containsMouse ? Theme.errorPressed : Theme.errorHover;
return Qt.rgba(privacyArea.containsMouse ? Theme.errorPressed.r : baseColor.r, privacyArea.containsMouse ? Theme.errorPressed.g : baseColor.g, privacyArea.containsMouse ? Theme.errorPressed.b : baseColor.b, (privacyArea.containsMouse ? Theme.errorPressed.a : baseColor.a) * Theme.widgetTransparency) const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
return Theme.withAlpha(baseColor, transparency);
} }
Column { Column {
@@ -61,10 +62,11 @@ Item {
DankIcon { DankIcon {
name: { name: {
const sourceAudio = AudioService.source?.audio const sourceAudio = AudioService.source?.audio;
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0 const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
if (muted) return "mic_off" if (muted)
return "mic" return "mic_off";
return "mic";
} }
size: Theme.iconSizeSmall size: Theme.iconSizeSmall
color: Theme.error color: Theme.error
@@ -128,10 +130,11 @@ Item {
DankIcon { DankIcon {
name: { name: {
const sourceAudio = AudioService.source?.audio const sourceAudio = AudioService.source?.audio;
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0 const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
if (muted) return "mic_off" if (muted)
return "mic" return "mic_off";
return "mic";
} }
size: Theme.iconSizeSmall size: Theme.iconSizeSmall
color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText
@@ -191,8 +194,7 @@ Item {
hoverEnabled: hasActivePrivacy hoverEnabled: hasActivePrivacy
enabled: hasActivePrivacy enabled: hasActivePrivacy
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {}
}
} }
Rectangle { Rectangle {
@@ -213,7 +215,7 @@ Item {
id: tooltipText id: tooltipText
anchors.centerIn: parent anchors.centerIn: parent
text: PrivacyService.getPrivacySummary() text: PrivacyService.getPrivacySummary()
font.pixelSize: Theme.barTextSize(barThickness) font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
} }

View File

@@ -17,6 +17,8 @@ BasePill {
property bool showSwap: (widgetData && widgetData.showSwap !== undefined) ? widgetData.showSwap : false property bool showSwap: (widgetData && widgetData.showSwap !== undefined) ? widgetData.showSwap : false
readonly property real swapUsage: DgopService.totalSwapKB > 0 ? (DgopService.usedSwapKB / DgopService.totalSwapKB) * 100 : 0 readonly property real swapUsage: DgopService.totalSwapKB > 0 ? (DgopService.usedSwapKB / DgopService.totalSwapKB) * 100 : 0
signal ramClicked()
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["memory"]); DgopService.addRef(["memory"]);
} }
@@ -60,7 +62,7 @@ BasePill {
return DgopService.memoryUsage.toFixed(0); return DgopService.memoryUsage.toFixed(0);
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -68,7 +70,7 @@ BasePill {
StyledText { StyledText {
visible: root.showSwap && DgopService.totalSwapKB > 0 visible: root.showSwap && DgopService.totalSwapKB > 0
text: root.swapUsage.toFixed(0) text: root.swapUsage.toFixed(0)
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -109,7 +111,7 @@ BasePill {
} }
return ramText; return ramText;
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
@@ -118,7 +120,7 @@ BasePill {
StyledTextMetrics { StyledTextMetrics {
id: ramBaseline id: ramBaseline
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: { text: {
if (!root.showSwap) { if (!root.showSwap) {
return "100%"; return "100%";
@@ -148,16 +150,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onPressed: { onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) { DgopService.setSortBy("memory")
const globalPos = root.visualContent.mapToGlobal(0, 0) ramClicked()
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("memory");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "memory");
}
} }
} }
} }

View File

@@ -11,6 +11,7 @@ import qs.Widgets
Item { Item {
id: root id: root
property var barConfig: null
property bool isVertical: axis?.isVertical ?? false property bool isVertical: axis?.isVertical ?? false
property var axis: null property var axis: null
property string section: "left" property string section: "left"
@@ -19,8 +20,46 @@ Item {
property var topBar: null property var topBar: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS property real barSpacing: 4
property bool isAutoHideBar: false
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
property Item windowRoot: (Window.window ? Window.window.contentItem : null) property Item windowRoot: (Window.window ? Window.window.contentItem : null)
readonly property real effectiveBarThickness: {
if (barThickness > 0 && barSpacing > 0) {
return barThickness + barSpacing
}
const innerPadding = barConfig?.innerPadding ?? 4
const spacing = barConfig?.spacing ?? 4
return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing
}
readonly property var barBounds: {
if (!parentScreen || !barConfig) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1))
return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig)
}
readonly property real barY: barBounds.y
readonly property real minTooltipY: {
if (!parentScreen || !isVertical) {
return 0
}
if (isAutoHideBar) {
return 0
}
if (parentScreen.y > 0) {
return effectiveBarThickness
}
return 0
}
property int _desktopEntriesUpdateTrigger: 0 property int _desktopEntriesUpdateTrigger: 0
property int _toplevelsUpdateTrigger: 0 property int _toplevelsUpdateTrigger: 0
@@ -75,7 +114,6 @@ Item {
}) })
return Array.from(appGroups.values()) return Array.from(appGroups.values())
} catch (e) { } catch (e) {
console.error("RunningApps: groupedWindows error:", e)
return [] return []
} }
} }
@@ -101,19 +139,20 @@ Item {
width: root.isVertical ? root.widgetThickness : root.calculatedSize width: root.isVertical ? root.widgetThickness : root.calculatedSize
height: root.isVertical ? root.calculatedSize : root.widgetThickness height: root.isVertical ? root.calculatedSize : root.widgetThickness
anchors.centerIn: parent anchors.centerIn: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
clip: false clip: false
color: { color: {
if (windowCount === 0) { if (windowCount === 0) {
return "transparent" return "transparent"
} }
if (SettingsData.dankBarNoBackground) { if ((barConfig?.noBackground ?? false)) {
return "transparent" return "transparent"
} }
const baseColor = Theme.widgetBaseBackgroundColor const baseColor = Theme.widgetBaseBackgroundColor
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency) const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0
return Theme.withAlpha(baseColor, transparency)
} }
} }
@@ -353,7 +392,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.runningAppsCompactMode visible: !SettingsData.runningAppsCompactMode
text: windowTitle text: windowTitle
font.pixelSize: Theme.barTextSize(barThickness) font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
elide: Text.ElideRight elide: Text.ElideRight
maximumLineCount: 1 maximumLineCount: 1
@@ -390,18 +429,25 @@ Item {
windowContextMenuLoader.active = true windowContextMenuLoader.active = true
if (windowContextMenuLoader.item) { if (windowContextMenuLoader.item) {
windowContextMenuLoader.item.currentWindow = toplevelObject windowContextMenuLoader.item.currentWindow = toplevelObject
// Pass bar context
windowContextMenuLoader.item.triggerBarConfig = root.barConfig
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1))
windowContextMenuLoader.item.triggerBarThickness = root.barThickness
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing
if (root.isVertical) { if (root.isVertical) {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2) const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
const screenX = root.parentScreen ? root.parentScreen.x : 0 const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0 const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY const relativeY = globalPos.y - screenY
const xPos = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS) // Add minTooltipY offset to account for top bar
windowContextMenuLoader.item.showAt(xPos, relativeY, true, root.axis?.edge) const adjustedY = relativeY + root.minTooltipY
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge)
} else { } else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0) const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0)
const screenX = root.parentScreen ? root.parentScreen.x : 0 const screenX = root.parentScreen ? root.parentScreen.x : 0
const relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX
const yPos = Theme.barHeight + SettingsData.dankBarSpacing - 7 const yPos = root.barThickness + root.barSpacing - 7
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top") windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top")
} }
} }
@@ -416,16 +462,18 @@ Item {
const screenX = root.parentScreen ? root.parentScreen.x : 0 const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0 const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS) const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS)
const isLeft = root.axis?.edge === "left" const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft) const adjustedY = relativeY + root.minTooltipY
const finalX = screenX + tooltipX
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft)
} else { } else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height) const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
const isBottom = root.axis?.edge === "bottom" const isBottom = root.axis?.edge === "bottom"
const tooltipY = isBottom const tooltipY = isBottom
? (screenHeight - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS - 35) ? (screenHeight - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS - 35)
: (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS)
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false) tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
} }
} }
@@ -586,7 +634,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.runningAppsCompactMode visible: !SettingsData.runningAppsCompactMode
text: windowTitle text: windowTitle
font.pixelSize: Theme.barTextSize(barThickness) font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
elide: Text.ElideRight elide: Text.ElideRight
maximumLineCount: 1 maximumLineCount: 1
@@ -623,18 +671,25 @@ Item {
windowContextMenuLoader.active = true windowContextMenuLoader.active = true
if (windowContextMenuLoader.item) { if (windowContextMenuLoader.item) {
windowContextMenuLoader.item.currentWindow = toplevelObject windowContextMenuLoader.item.currentWindow = toplevelObject
// Pass bar context
windowContextMenuLoader.item.triggerBarConfig = root.barConfig
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1))
windowContextMenuLoader.item.triggerBarThickness = root.barThickness
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing
if (root.isVertical) { if (root.isVertical) {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2) const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
const screenX = root.parentScreen ? root.parentScreen.x : 0 const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0 const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY const relativeY = globalPos.y - screenY
const xPos = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS) // Add minTooltipY offset to account for top bar
windowContextMenuLoader.item.showAt(xPos, relativeY, true, root.axis?.edge) const adjustedY = relativeY + root.minTooltipY
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge)
} else { } else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0) const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0)
const screenX = root.parentScreen ? root.parentScreen.x : 0 const screenX = root.parentScreen ? root.parentScreen.x : 0
const relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX
const yPos = Theme.barHeight + SettingsData.dankBarSpacing - 7 const yPos = root.barThickness + root.barSpacing - 7
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top") windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top")
} }
} }
@@ -649,16 +704,18 @@ Item {
const screenX = root.parentScreen ? root.parentScreen.x : 0 const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0 const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS) const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
const isLeft = root.axis?.edge === "left" const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft) const adjustedY = relativeY + root.minTooltipY
const finalX = screenX + tooltipX
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft)
} else { } else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height) const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
const isBottom = root.axis?.edge === "bottom" const isBottom = root.axis?.edge === "bottom"
const tooltipY = isBottom const tooltipY = isBottom
? (screenHeight - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS - 35) ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35)
: (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.barThickness + root.barSpacing + Theme.spacingXS)
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false) tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
} }
} }
@@ -699,6 +756,28 @@ Item {
property bool isVertical: false property bool isVertical: false
property string edge: "top" property string edge: "top"
// New properties for bar context
property int triggerBarPosition: (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top)
property real triggerBarThickness: 0
property real triggerBarSpacing: 0
property var triggerBarConfig: null
readonly property real effectiveBarThickness: {
if (triggerBarThickness > 0 && triggerBarSpacing > 0) {
return triggerBarThickness + triggerBarSpacing
}
return Math.max(26 + (barConfig?.innerPadding ?? 4) * 0.6, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))) + (barConfig?.spacing ?? 4)
}
property var barBounds: {
if (!contextMenuWindow.screen || !triggerBarConfig) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
return SettingsData.getBarBounds(contextMenuWindow.screen, effectiveBarThickness, triggerBarPosition, triggerBarConfig)
}
property real barY: barBounds.y
function showAt(x, y, vertical, barEdge) { function showAt(x, y, vertical, barEdge) {
screen = root.parentScreen screen = root.parentScreen
anchorPos = Qt.point(x, y) anchorPos = Qt.point(x, y)
@@ -752,7 +831,7 @@ Item {
} }
y: { y: {
if (contextMenuWindow.isVertical) { if (contextMenuWindow.isVertical) {
const top = 10 const top = Math.max(barY, 10)
const bottom = contextMenuWindow.height - height - 10 const bottom = contextMenuWindow.height - height - 10
const want = contextMenuWindow.anchorPos.y - height / 2 const want = contextMenuWindow.anchorPos.y - height / 2
return Math.max(top, Math.min(bottom, want)) return Math.max(top, Math.min(bottom, want))

File diff suppressed because it is too large Load Diff

View File

@@ -62,8 +62,8 @@ BasePill {
color: Theme.error color: Theme.error
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 6 anchors.rightMargin: (barConfig?.noBackground ?? false) ? 0 : 6
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 6 anchors.topMargin: (barConfig?.noBackground ?? false) ? 0 : 6
visible: root.isVerticalOrientation && root.hasUpdates && !root.isChecking visible: root.isVerticalOrientation && root.hasUpdates && !root.isChecking
} }
@@ -111,7 +111,7 @@ BasePill {
id: countText id: countText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: SystemUpdateService.updateCount.toString() text: SystemUpdateService.updateCount.toString()
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
visible: root.hasUpdates && !root.isChecking visible: root.hasUpdates && !root.isChecking
} }

View File

@@ -13,7 +13,26 @@ BasePill {
} }
property var popoutTarget: null property var popoutTarget: null
property var barConfig: null
property bool isHovered: clickArea.containsMouse property bool isHovered: clickArea.containsMouse
property real barSpacing: 4
property bool isAutoHideBar: false
readonly property real minTooltipY: {
if (!parentScreen || !isVerticalOrientation) {
return 0
}
if (isAutoHideBar) {
return 0
}
if (parentScreen.y > 0) {
return barThickness + barSpacing
}
return 0
}
signal toggleVpnPopup() signal toggleVpnPopup()
@@ -56,51 +75,47 @@ BasePill {
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
enabled: !DMSNetworkService.isBusy enabled: !DMSNetworkService.isBusy
onPressed: { onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) { root.toggleVpnPopup()
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.toggleVpnPopup();
} }
onEntered: { onEntered: {
if (root.parentScreen && !(popoutTarget && popoutTarget.shouldBeVisible)) { if (!root.parentScreen || (popoutTarget?.shouldBeVisible)) return
tooltipLoader.active = true
if (tooltipLoader.item) {
let tooltipText = ""
if (!DMSNetworkService.connected) {
tooltipText = "VPN Disconnected"
} else {
const names = DMSNetworkService.activeNames || []
if (names.length <= 1) {
const name = names[0] || ""
const maxLength = 25
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName
} else {
const name = names[0]
const maxLength = 20
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1)
}
}
if (root.isVerticalOrientation) { tooltipLoader.active = true
const globalPos = mapToGlobal(width / 2, height / 2) if (!tooltipLoader.item) return
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0 let tooltipText = ""
const relativeY = globalPos.y - screenY if (!DMSNetworkService.connected) {
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS) tooltipText = "VPN Disconnected"
const isLeft = root.axis?.edge === "left" } else {
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft) const names = DMSNetworkService.activeNames || []
} else { if (names.length <= 1) {
const globalPos = mapToGlobal(width / 2, height) const name = names[0] || ""
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS const maxLength = 25
tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false) const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
} tooltipText = "VPN Connected • " + displayName
} else {
const name = names[0]
const maxLength = 20
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1)
} }
} }
if (root.isVerticalOrientation) {
const globalPos = mapToGlobal(width / 2, height / 2)
const currentScreen = root.parentScreen || Screen
const screenX = currentScreen ? currentScreen.x : 0
const screenY = currentScreen ? currentScreen.y : 0
const relativeY = globalPos.y - screenY
const adjustedY = relativeY + root.minTooltipY
const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft)
} else {
const globalPos = mapToGlobal(width / 2, height)
const tooltipY = root.barThickness + root.barSpacing + Theme.spacingXS
tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
} }
onExited: { onExited: {
if (tooltipLoader.item) { if (tooltipLoader.item) {

View File

@@ -43,7 +43,7 @@ BasePill {
const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
return temp; return temp;
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
@@ -70,7 +70,7 @@ BasePill {
const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C"); return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C");
} }
font.pixelSize: Theme.barTextSize(root.barThickness) font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }

File diff suppressed because it is too large Load Diff

View File

@@ -18,30 +18,8 @@ DankPopout {
property var triggerScreen: null property var triggerScreen: null
property int currentTabIndex: 0 property int currentTabIndex: 0
function setTriggerPosition(x, y, width, section, screen) {
triggerSection = section
triggerScreen = screen
triggerY = y
if (section === "center" && (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)) {
const screenWidth = screen ? screen.width : Screen.width
triggerX = (screenWidth - popupWidth) / 2
triggerWidth = popupWidth
} else if (section === "center" && (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right)) {
const screenHeight = screen ? screen.height : Screen.height
triggerX = (screenHeight - popupHeight) / 2
triggerWidth = popupHeight
} else {
triggerX = x
triggerWidth = width
}
}
popupWidth: 700 popupWidth: 700
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500 popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500
triggerX: Screen.width - 620 - Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 80 triggerWidth: 80
screen: triggerScreen screen: triggerScreen
shouldBeVisible: dashVisible shouldBeVisible: dashVisible

View File

@@ -17,7 +17,7 @@ Item {
property MprisPlayer activePlayer: MprisController.activePlayer property MprisPlayer activePlayer: MprisController.activePlayer
property var allPlayers: MprisController.availablePlayers property var allPlayers: MprisController.availablePlayers
readonly property bool isRightEdge: SettingsData.dankBarPosition === SettingsData.Position.Right readonly property bool isRightEdge: (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Right
property var defaultSink: AudioService.sink property var defaultSink: AudioService.sink
// Palette that stays stable across track switches until new colors are ready // Palette that stays stable across track switches until new colors are ready

View File

@@ -37,18 +37,24 @@ Variants {
readonly property real widgetHeight: SettingsData.dockIconSize readonly property real widgetHeight: SettingsData.dockIconSize
readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10
readonly property real barSpacing: { readonly property real barSpacing: {
const barIsHorizontal = (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom) const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const barIsVertical = (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right) if (!defaultBar) return 0
const samePosition = (SettingsData.dockPosition === SettingsData.dankBarPosition)
const barPos = defaultBar.position ?? SettingsData.Position.Top
const barIsHorizontal = (barPos === SettingsData.Position.Top || barPos === SettingsData.Position.Bottom)
const barIsVertical = (barPos === SettingsData.Position.Left || barPos === SettingsData.Position.Right)
const samePosition = (SettingsData.dockPosition === barPos)
const dockIsHorizontal = !isVertical const dockIsHorizontal = !isVertical
const dockIsVertical = isVertical const dockIsVertical = isVertical
if (!SettingsData.dankBarVisible) return 0 if (!(defaultBar.visible ?? true)) return 0
const spacing = defaultBar.spacing ?? 4
const bottomGap = defaultBar.bottomGap ?? 0
if (dockIsHorizontal && barIsHorizontal && samePosition) { if (dockIsHorizontal && barIsHorizontal && samePosition) {
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap return spacing + effectiveBarHeight + bottomGap
} }
if (dockIsVertical && barIsVertical && samePosition) { if (dockIsVertical && barIsVertical && samePosition) {
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap return spacing + effectiveBarHeight + bottomGap
} }
return 0 return 0
} }

View File

@@ -8,7 +8,7 @@ Rectangle {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: Theme.widgetBackground color: Theme.surfaceContainerHigh
signal dismissed signal dismissed

View File

@@ -26,19 +26,8 @@ DankPopout {
} }
} }
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
}
popupWidth: 400 popupWidth: 400
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400 popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
triggerX: 0
triggerY: 0
triggerWidth: 40
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen
shouldBeVisible: notificationHistoryVisible shouldBeVisible: notificationHistoryVisible

View File

@@ -137,80 +137,55 @@ PanelWindow {
right: getRightMargin() right: getRightMargin()
} }
function getBarInfo() {
if (!screen) return { topBar: 0, bottomBar: 0, leftBar: 0, rightBar: 0 }
return SettingsData.getAdjacentBarInfo(screen, SettingsData.notificationPopupPosition, {
id: "notification-popup",
screenPreferences: [screen.name],
autoHide: false
})
}
function getTopMargin() { function getTopMargin() {
const popupPos = SettingsData.notificationPopupPosition const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left
if (!isTop) return 0 if (!isTop) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) const barInfo = getBarInfo()
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap const base = barInfo.topBar > 0 ? barInfo.topBar : Theme.popupDistance
let base = Theme.popupDistance
if (barPos === SettingsData.Position.Top) {
base = exclusiveZone
}
return base + screenY return base + screenY
} }
function getBottomMargin() { function getBottomMargin() {
const popupPos = SettingsData.notificationPopupPosition const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right
if (!isBottom) return 0 if (!isBottom) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) const barInfo = getBarInfo()
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap const base = barInfo.bottomBar > 0 ? barInfo.bottomBar : Theme.popupDistance
let base = Theme.popupDistance
if (barPos === SettingsData.Position.Bottom) {
base = exclusiveZone
}
return base + screenY return base + screenY
} }
function getLeftMargin() { function getLeftMargin() {
if (isTopCenter) { if (isTopCenter) return (screen.width - implicitWidth) / 2
return (screen.width - implicitWidth) / 2
}
const popupPos = SettingsData.notificationPopupPosition const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom
if (!isLeft) return 0 if (!isLeft) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) const barInfo = getBarInfo()
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap return barInfo.leftBar > 0 ? barInfo.leftBar : Theme.popupDistance
if (barPos === SettingsData.Position.Left) {
return exclusiveZone
}
return Theme.popupDistance
} }
function getRightMargin() { function getRightMargin() {
if (isTopCenter) return 0 if (isTopCenter) return 0
const popupPos = SettingsData.notificationPopupPosition const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right
if (!isRight) return 0 if (!isRight) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) const barInfo = getBarInfo()
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance
if (barPos === SettingsData.Position.Right) {
return exclusiveZone
}
return Theme.popupDistance
} }
readonly property real dpr: CompositorService.getScreenScale(win.screen) readonly property real dpr: CompositorService.getScreenScale(win.screen)
@@ -241,14 +216,15 @@ PanelWindow {
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr)) layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect { layer.effect: MultiEffect {
id: shadowFx id: shadowFx
autoPaddingEnabled: true autoPaddingEnabled: true
shadowEnabled: true shadowEnabled: true
blurEnabled: false blurEnabled: false
maskEnabled: false maskEnabled: false
property int blurMax: 64 shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / bgShadowLayer.blurMax))
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: { shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest

View File

@@ -1,7 +1,5 @@
import QtQuick import QtQuick
import qs.Common import qs.Common
import qs.Services
import qs.Widgets
Item { Item {
id: root id: root
@@ -12,6 +10,8 @@ Item {
property var parentScreen: null property var parentScreen: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property alias content: contentLoader.sourceComponent property alias content: contentLoader.sourceComponent
property bool isVerticalOrientation: axis?.isVertical ?? false property bool isVerticalOrientation: axis?.isVertical ?? false
property bool isFirst: false property bool isFirst: false
@@ -21,7 +21,7 @@ Item {
property bool isRightBarEdge: false property bool isRightBarEdge: false
property bool isTopBarEdge: false property bool isTopBarEdge: false
property bool isBottomBarEdge: false property bool isBottomBarEdge: false
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30)) readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property real visualWidth: isVerticalOrientation ? widgetThickness : (contentLoader.item ? (contentLoader.item.implicitWidth + horizontalPadding * 2) : 0) readonly property real visualWidth: isVerticalOrientation ? widgetThickness : (contentLoader.item ? (contentLoader.item.implicitWidth + horizontalPadding * 2) : 0)
readonly property real visualHeight: isVerticalOrientation ? (contentLoader.item ? (contentLoader.item.implicitHeight + horizontalPadding * 2) : 0) : widgetThickness readonly property real visualHeight: isVerticalOrientation ? (contentLoader.item ? (contentLoader.item.implicitHeight + horizontalPadding * 2) : 0) : widgetThickness
readonly property alias visualContent: visualContent readonly property alias visualContent: visualContent
@@ -32,8 +32,8 @@ Item {
readonly property real topMargin: isVerticalOrientation ? (isTopBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : 0 readonly property real topMargin: isVerticalOrientation ? (isTopBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : 0
readonly property real bottomMargin: isVerticalOrientation ? (isBottomBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : 0 readonly property real bottomMargin: isVerticalOrientation ? (isBottomBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : 0
signal clicked() signal clicked
signal rightClicked() signal rightClicked
width: isVerticalOrientation ? barThickness : visualWidth width: isVerticalOrientation ? barThickness : visualWidth
height: isVerticalOrientation ? visualHeight : barThickness height: isVerticalOrientation ? visualHeight : barThickness
@@ -43,15 +43,16 @@ Item {
width: root.visualWidth width: root.visualWidth
height: root.visualHeight height: root.visualHeight
anchors.centerIn: parent anchors.centerIn: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.dankBarNoBackground) { if (barConfig?.noBackground ?? false) {
return "transparent" return "transparent";
} }
const isHovered = mouseArea.containsMouse || (root.isHovered ?? false) const isHovered = mouseArea.containsMouse || (root.isHovered || false);
const baseColor = isHovered ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor const baseColor = isHovered ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency) const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
return Theme.withAlpha(baseColor, transparency);
} }
Loader { Loader {
@@ -73,16 +74,26 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: function (mouse) { onPressed: function (mouse) {
if (mouse.button === Qt.RightButton) { if (mouse.button === Qt.RightButton) {
root.rightClicked() root.rightClicked();
return return;
} }
if (popoutTarget && popoutTarget.setTriggerPosition) { if (popoutTarget) {
const globalPos = root.visualContent.mapToGlobal(0, 0) // Ensure bar context is set first if supported
const currentScreen = parentScreen || Screen if (popoutTarget.setBarContext) {
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth) const pos = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1));
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen) const bottomGap = root.barConfig ? (root.barConfig.bottomGap !== undefined ? root.barConfig.bottomGap : 0) : 0;
popoutTarget.setBarContext(pos, bottomGap);
}
if (popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1));
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth, root.barSpacing, barPosition, root.barConfig);
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, root.barSpacing, root.barConfig);
}
} }
root.clicked() root.clicked();
} }
} }
} }

View File

@@ -1,7 +1,5 @@
import QtQuick import QtQuick
import qs.Common import qs.Common
import qs.Services
import qs.Widgets
Item { Item {
id: root id: root
@@ -13,6 +11,8 @@ Item {
property var parentScreen: null property var parentScreen: null
property real widgetThickness: 30 property real widgetThickness: 30
property real barThickness: 48 property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property string pluginId: "" property string pluginId: ""
property var pluginService: null property var pluginService: null
@@ -33,8 +33,8 @@ Item {
property Component ccDetailContent: null property Component ccDetailContent: null
property real ccDetailHeight: 250 property real ccDetailHeight: 250
signal ccWidgetToggled() signal ccWidgetToggled
signal ccWidgetExpanded() signal ccWidgetExpanded
property var pluginData: ({}) property var pluginData: ({})
property var variants: [] property var variants: []
@@ -45,55 +45,55 @@ Item {
readonly property bool hasPopout: popoutContent !== null readonly property bool hasPopout: popoutContent !== null
Component.onCompleted: { Component.onCompleted: {
loadPluginData() loadPluginData();
} }
onPluginServiceChanged: { onPluginServiceChanged: {
loadPluginData() loadPluginData();
} }
onPluginIdChanged: { onPluginIdChanged: {
loadPluginData() loadPluginData();
} }
Connections { Connections {
target: pluginService target: pluginService
function onPluginDataChanged(changedPluginId) { function onPluginDataChanged(changedPluginId) {
if (changedPluginId === pluginId) { if (changedPluginId === pluginId) {
loadPluginData() loadPluginData();
} }
} }
} }
function loadPluginData() { function loadPluginData() {
if (!pluginService || !pluginId) { if (!pluginService || !pluginId) {
pluginData = {} pluginData = {};
variants = [] variants = [];
return return;
} }
pluginData = SettingsData.getPluginSettingsForPlugin(pluginId) pluginData = SettingsData.getPluginSettingsForPlugin(pluginId);
variants = pluginService.getPluginVariants(pluginId) variants = pluginService.getPluginVariants(pluginId);
} }
function createVariant(variantName, variantConfig) { function createVariant(variantName, variantConfig) {
if (!pluginService || !pluginId) { if (!pluginService || !pluginId) {
return null return null;
} }
return pluginService.createPluginVariant(pluginId, variantName, variantConfig) return pluginService.createPluginVariant(pluginId, variantName, variantConfig);
} }
function removeVariant(variantId) { function removeVariant(variantId) {
if (!pluginService || !pluginId) { if (!pluginService || !pluginId) {
return return;
} }
pluginService.removePluginVariant(pluginId, variantId) pluginService.removePluginVariant(pluginId, variantId);
} }
function updateVariant(variantId, variantConfig) { function updateVariant(variantId, variantConfig) {
if (!pluginService || !pluginId) { if (!pluginService || !pluginId) {
return return;
} }
pluginService.updatePluginVariant(pluginId, variantId, variantConfig) pluginService.updatePluginVariant(pluginId, variantId, variantConfig);
} }
width: isVertical ? (hasVerticalPill ? verticalPill.width : 0) : (hasHorizontalPill ? horizontalPill.width : 0) width: isVertical ? (hasVerticalPill ? verticalPill.width : 0) : (hasHorizontalPill ? horizontalPill.width : 0)
@@ -108,30 +108,32 @@ Item {
parentScreen: root.parentScreen parentScreen: root.parentScreen
widgetThickness: root.widgetThickness widgetThickness: root.widgetThickness
barThickness: root.barThickness barThickness: root.barThickness
barSpacing: root.barSpacing
barConfig: root.barConfig
content: root.horizontalBarPill content: root.horizontalBarPill
onClicked: { onClicked: {
if (pillClickAction) { if (pillClickAction) {
if (pillClickAction.length === 0) { if (pillClickAction.length === 0) {
pillClickAction() pillClickAction();
} else { } else {
const globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width) const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillClickAction(pos.x, pos.y, pos.width, section, currentScreen) pillClickAction(pos.x, pos.y, pos.width, section, currentScreen);
} }
} else if (hasPopout) { } else if (hasPopout) {
pluginPopout.toggle() pluginPopout.toggle();
} }
} }
onRightClicked: { onRightClicked: {
if (pillRightClickAction) { if (pillRightClickAction) {
if (pillRightClickAction.length === 0) { if (pillRightClickAction.length === 0) {
pillRightClickAction() pillRightClickAction();
} else { } else {
const globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width) const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen) pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen);
} }
} }
} }
@@ -146,31 +148,33 @@ Item {
parentScreen: root.parentScreen parentScreen: root.parentScreen
widgetThickness: root.widgetThickness widgetThickness: root.widgetThickness
barThickness: root.barThickness barThickness: root.barThickness
barSpacing: root.barSpacing
barConfig: root.barConfig
content: root.verticalBarPill content: root.verticalBarPill
isVerticalOrientation: true isVerticalOrientation: true
onClicked: { onClicked: {
if (pillClickAction) { if (pillClickAction) {
if (pillClickAction.length === 0) { if (pillClickAction.length === 0) {
pillClickAction() pillClickAction();
} else { } else {
const globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width) const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillClickAction(pos.x, pos.y, pos.width, section, currentScreen) pillClickAction(pos.x, pos.y, pos.width, section, currentScreen);
} }
} else if (hasPopout) { } else if (hasPopout) {
pluginPopout.toggle() pluginPopout.toggle();
} }
} }
onRightClicked: { onRightClicked: {
if (pillRightClickAction) { if (pillRightClickAction) {
if (pillRightClickAction.length === 0) { if (pillRightClickAction.length === 0) {
pillRightClickAction() pillRightClickAction();
} else { } else {
const globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width) const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen) pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen);
} }
} }
} }
@@ -178,7 +182,7 @@ Item {
function closePopout() { function closePopout() {
if (pluginPopout) { if (pluginPopout) {
pluginPopout.close() pluginPopout.close();
} }
} }

View File

@@ -13,14 +13,6 @@ DankPopout {
property real contentWidth: 400 property real contentWidth: 400
property real contentHeight: 0 property real contentHeight: 0
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
}
popupWidth: contentWidth popupWidth: contentWidth
popupHeight: contentHeight popupHeight: contentHeight
screen: triggerScreen screen: triggerScreen

View File

@@ -19,14 +19,6 @@ DankPopout {
property var parentWidget: null property var parentWidget: null
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
function hide() { function hide() {
close(); close();
if (processContextMenu.visible) { if (processContextMenu.visible) {
@@ -40,8 +32,6 @@ DankPopout {
popupWidth: 600 popupWidth: 600
popupHeight: 600 popupHeight: 600
triggerX: Screen.width - 600 - Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 55 triggerWidth: 55
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen

File diff suppressed because it is too large Load Diff

View File

@@ -9,53 +9,83 @@ import qs.Widgets
Item { Item {
id: displaysTab id: displaysTab
property var variantComponents: [{ function getBarComponentsFromSettings() {
"id": "dankBar", const bars = SettingsData.barConfigs || []
"name": "Dank Bar", return bars.map(bar => ({
"description": I18n.tr("System bar with widgets and system information"), "id": "bar:" + bar.id,
"icon": "toolbar" "name": bar.name || "Bar",
}, { "description": I18n.tr("Individual bar configuration"),
"id": "dock", "icon": "toolbar",
"name": I18n.tr("Application Dock"), "barId": bar.id
"description": I18n.tr("Bottom dock for pinned and running applications"), }))
"icon": "dock" }
}, {
"id": "notifications", property var variantComponents: getVariantComponentsList()
"name": I18n.tr("Notification Popups"),
"description": I18n.tr("Notification toast popups"), function getVariantComponentsList() {
"icon": "notifications" return [
}, { ...getBarComponentsFromSettings(),
"id": "wallpaper", {
"name": I18n.tr("Wallpaper"), "id": "dock",
"description": I18n.tr("Desktop background images"), "name": I18n.tr("Application Dock"),
"icon": "wallpaper" "description": I18n.tr("Bottom dock for pinned and running applications"),
}, { "icon": "dock"
"id": "osd", }, {
"name": I18n.tr("On-Screen Displays"), "id": "notifications",
"description": I18n.tr("Volume, brightness, and other system OSDs"), "name": I18n.tr("Notification Popups"),
"icon": "picture_in_picture" "description": I18n.tr("Notification toast popups"),
}, { "icon": "notifications"
"id": "toast", }, {
"name": I18n.tr("Toast Messages"), "id": "wallpaper",
"description": I18n.tr("System toast notifications"), "name": I18n.tr("Wallpaper"),
"icon": "campaign" "description": I18n.tr("Desktop background images"),
}, { "icon": "wallpaper"
"id": "notepad", }, {
"name": I18n.tr("Notepad Slideout"), "id": "osd",
"description": I18n.tr("Quick note-taking slideout panel"), "name": I18n.tr("On-Screen Displays"),
"icon": "sticky_note_2" "description": I18n.tr("Volume, brightness, and other system OSDs"),
}, { "icon": "picture_in_picture"
"id": "systemTray", }, {
"name": I18n.tr("System Tray"), "id": "toast",
"description": I18n.tr("System tray icons"), "name": I18n.tr("Toast Messages"),
"icon": "notifications" "description": I18n.tr("System toast notifications"),
}] "icon": "campaign"
}, {
"id": "notepad",
"name": I18n.tr("Notepad Slideout"),
"description": I18n.tr("Quick note-taking slideout panel"),
"icon": "sticky_note_2"
}, {
"id": "systemTray",
"name": I18n.tr("System Tray"),
"description": I18n.tr("System tray icons"),
"icon": "notifications"
}
]
}
Connections {
target: SettingsData
function onBarConfigsChanged() {
variantComponents = getVariantComponentsList()
}
}
function getScreenPreferences(componentId) { function getScreenPreferences(componentId) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
const barConfig = SettingsData.getBarConfig(barId)
return barConfig?.screenPreferences || ["all"]
}
return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"]; return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"];
} }
function setScreenPreferences(componentId, screenNames) { function setScreenPreferences(componentId, screenNames) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
SettingsData.updateBarConfig(barId, { screenPreferences: screenNames })
return
}
var prefs = SettingsData.screenPreferences || {}; var prefs = SettingsData.screenPreferences || {};
var newPrefs = Object.assign({}, prefs); var newPrefs = Object.assign({}, prefs);
newPrefs[componentId] = screenNames; newPrefs[componentId] = screenNames;
@@ -63,10 +93,20 @@ Item {
} }
function getShowOnLastDisplay(componentId) { function getShowOnLastDisplay(componentId) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
const barConfig = SettingsData.getBarConfig(barId)
return barConfig?.showOnLastDisplay ?? true
}
return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false; return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false;
} }
function setShowOnLastDisplay(componentId, enabled) { function setShowOnLastDisplay(componentId, enabled) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
SettingsData.updateBarConfig(barId, { showOnLastDisplay: enabled })
return
}
var prefs = SettingsData.showOnLastDisplay || {}; var prefs = SettingsData.showOnLastDisplay || {};
var newPrefs = Object.assign({}, prefs); var newPrefs = Object.assign({}, prefs);
newPrefs[componentId] = enabled; newPrefs[componentId] = enabled;
@@ -251,7 +291,6 @@ Item {
} }
onTabClicked: index => { onTabClicked: index => {
console.log("Tab clicked:", index, "Setting mode to:", index === 1 ? "location" : "time")
DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time") DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time")
currentIndex = index currentIndex = index
} }
@@ -756,8 +795,9 @@ Item {
displaysTab.setScreenPreferences(parent.componentId, ["all"]) displaysTab.setScreenPreferences(parent.componentId, ["all"])
} else { } else {
displaysTab.setScreenPreferences(parent.componentId, []) displaysTab.setScreenPreferences(parent.componentId, [])
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(parent.componentId)) { const cid = parent.componentId
displaysTab.setShowOnLastDisplay(parent.componentId, true) if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) {
displaysTab.setShowOnLastDisplay(cid, true)
} }
} }
} }
@@ -769,9 +809,11 @@ Item {
description: I18n.tr("Always show when there's only one connected display") description: I18n.tr("Always show when there's only one connected display")
checked: displaysTab.getShowOnLastDisplay(parent.componentId) checked: displaysTab.getShowOnLastDisplay(parent.componentId)
visible: { visible: {
var prefs = displaysTab.getScreenPreferences(parent.componentId) const prefs = displaysTab.getScreenPreferences(parent.componentId)
var isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all") const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
return !isAll && ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(parent.componentId) const cid = parent.componentId
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(cid) || cid.startsWith("bar:")
return !isAll && isRelevantComponent
} }
onToggled: (checked) => { onToggled: (checked) => {
displaysTab.setShowOnLastDisplay(parent.componentId, checked) displaysTab.setShowOnLastDisplay(parent.componentId, checked)
@@ -854,4 +896,4 @@ Item {
} }
} }

View File

@@ -755,43 +755,6 @@ Item {
} }
} }
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Dank Bar Transparency")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: I18n.tr("Controls opacity of the DankBar panel background")
font.pixelSize: Theme.fontSizeSmall - 2
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
DankSlider {
width: parent.width
height: 24
value: Math.round(
SettingsData.dankBarTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
onSliderValueChanged: newValue => {
SettingsData.set("dankBarTransparency",
newValue / 100)
}
}
}
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -808,14 +771,14 @@ Item {
StyledText { StyledText {
id: transparencyLabel id: transparencyLabel
text: I18n.tr("Dank Bar Widget Transparency") text: I18n.tr("Widget Background Color")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} }
StyledText { StyledText {
text: I18n.tr("Controls opacity of individual widgets inside DankBar") text: I18n.tr("Choose the background color for widgets")
font.pixelSize: Theme.fontSizeSmall - 2 font.pixelSize: Theme.fontSizeSmall - 2
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
width: parent.width width: parent.width
@@ -855,23 +818,6 @@ Item {
} }
} }
} }
DankSlider {
width: parent.width
height: 24
value: Math.round(
SettingsData.dankBarWidgetTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
onSliderValueChanged: newValue => {
SettingsData.set("dankBarWidgetTransparency",
newValue / 100)
}
}
} }
Column { Column {

View File

@@ -11,22 +11,12 @@ DankPopout {
property var parentWidget: null property var parentWidget: null
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
Ref { Ref {
service: SystemUpdateService service: SystemUpdateService
} }
popupWidth: 400 popupWidth: 400
popupHeight: 500 popupHeight: 500
triggerX: Screen.width - 600 - Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 55 triggerWidth: 55
positioning: "" positioning: ""
screen: triggerScreen screen: triggerScreen

View File

@@ -72,7 +72,7 @@ PanelWindow {
width: shouldBeVisible ? Math.min(900, messageText.implicitWidth + statusIcon.width + Theme.spacingM + (ToastService.hasDetails ? (expandButton.width + closeButton.width + 4) : (ToastService.currentLevel === ToastService.levelError ? closeButton.width + Theme.spacingS : 0)) + Theme.spacingL * 2 + Theme.spacingM * 2) : frozenWidth width: shouldBeVisible ? Math.min(900, messageText.implicitWidth + statusIcon.width + Theme.spacingM + (ToastService.hasDetails ? (expandButton.width + closeButton.width + 4) : (ToastService.currentLevel === ToastService.levelError ? closeButton.width + Theme.spacingS : 0)) + Theme.spacingL * 2 + Theme.spacingM * 2) : frozenWidth
height: toastContent.height + Theme.spacingL * 2 height: toastContent.height + Theme.spacingL * 2
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
y: Theme.barHeight - 4 + SettingsData.dankBarSpacing + 2 y: Theme.barHeight - 4 + (SettingsData.barConfigs[0]?.spacing ?? 4) + 2
color: { color: {
switch (ToastService.currentLevel) { switch (ToastService.currentLevel) {
case ToastService.levelError: case ToastService.levelError:

View File

@@ -463,7 +463,7 @@ Variants {
MultiEffect { MultiEffect {
anchors.fill: parent anchors.fill: parent
source: effectLoader.active ? effectLoader.item : (root.actualTransitionType === "none" ? currentWallpaper : null) source: effectLoader.active ? effectLoader.item : (root.actualTransitionType === "none" ? currentWallpaper : null)
visible: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview visible: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && source !== null
blurEnabled: true blurEnabled: true
blur: 0.8 blur: 0.8
blurMax: 75 blurMax: 75

View File

@@ -26,38 +26,42 @@ Singleton {
property var sortedToplevels: [] property var sortedToplevels: []
property bool _sortScheduled: false property bool _sortScheduled: false
signal toplevelsChanged() signal toplevelsChanged
function getScreenScale(screen) { function getScreenScale(screen) {
if (!screen) return 1 if (!screen)
return 1;
if (Quickshell.env("QT_WAYLAND_FORCE_DPI") || Quickshell.env("QT_SCALE_FACTOR")) { if (Quickshell.env("QT_WAYLAND_FORCE_DPI") || Quickshell.env("QT_SCALE_FACTOR")) {
return screen.devicePixelRatio || 1 return screen.devicePixelRatio || 1;
} }
if (WlrOutputService.wlrOutputAvailable && screen) { if (WlrOutputService.wlrOutputAvailable && screen) {
const wlrOutput = WlrOutputService.getOutput(screen.name) const wlrOutput = WlrOutputService.getOutput(screen.name);
if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) { if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) {
return Math.round(wlrOutput.scale * 20) / 20 return Math.round(wlrOutput.scale * 20) / 20;
} }
} }
if (isNiri && screen) { if (isNiri && screen) {
const niriScale = NiriService.displayScales[screen.name] const niriScale = NiriService.displayScales[screen.name];
if (niriScale !== undefined) return niriScale if (niriScale !== undefined)
return niriScale;
} }
if (isHyprland && screen) { if (isHyprland && screen) {
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === screen.name) const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === screen.name);
if (hyprlandMonitor?.scale !== undefined) return hyprlandMonitor.scale if (hyprlandMonitor?.scale !== undefined)
return hyprlandMonitor.scale;
} }
if (isDwl && screen) { if (isDwl && screen) {
const dwlScale = DwlService.getOutputScale(screen.name) const dwlScale = DwlService.getOutputScale(screen.name);
if (dwlScale !== undefined && dwlScale > 0) return dwlScale if (dwlScale !== undefined && dwlScale > 0)
return dwlScale;
} }
return screen?.devicePixelRatio || 1 return screen?.devicePixelRatio || 1;
} }
Timer { Timer {
@@ -65,127 +69,129 @@ Singleton {
interval: 100 interval: 100
repeat: false repeat: false
onTriggered: { onTriggered: {
_sortScheduled = false _sortScheduled = false;
sortedToplevels = computeSortedToplevels() sortedToplevels = computeSortedToplevels();
toplevelsChanged() toplevelsChanged();
} }
} }
function scheduleSort() { function scheduleSort() {
if (_sortScheduled) return if (_sortScheduled)
_sortScheduled = true return;
sortDebounceTimer.restart() _sortScheduled = true;
sortDebounceTimer.restart();
} }
Connections { Connections {
target: ToplevelManager.toplevels target: ToplevelManager.toplevels
function onValuesChanged() { root.scheduleSort() } function onValuesChanged() {
root.scheduleSort();
}
} }
Connections { Connections {
target: isHyprland ? Hyprland : null target: isHyprland ? Hyprland : null
enabled: isHyprland enabled: isHyprland
function onRawEvent(event) { function onRawEvent(event) {
if (event.name === "openwindow" || if (event.name === "openwindow" || event.name === "closewindow" || event.name === "movewindow" || event.name === "movewindowv2" || event.name === "workspace" || event.name === "workspacev2" || event.name === "focusedmon" || event.name === "focusedmonv2" || event.name === "activewindow" || event.name === "activewindowv2" || event.name === "changefloatingmode" || event.name === "fullscreen" || event.name === "moveintogroup" || event.name === "moveoutofgroup") {
event.name === "closewindow" ||
event.name === "movewindow" ||
event.name === "movewindowv2" ||
event.name === "workspace" ||
event.name === "workspacev2" ||
event.name === "focusedmon" ||
event.name === "focusedmonv2" ||
event.name === "activewindow" ||
event.name === "activewindowv2" ||
event.name === "changefloatingmode" ||
event.name === "fullscreen" ||
event.name === "moveintogroup" ||
event.name === "moveoutofgroup") {
try { try {
Hyprland.refreshToplevels() Hyprland.refreshToplevels();
} catch(e) {} } catch (e) {}
root.scheduleSort() root.scheduleSort();
} }
} }
} }
Connections { Connections {
target: NiriService target: NiriService
function onWindowsChanged() { root.scheduleSort() } function onWindowsChanged() {
root.scheduleSort();
}
} }
Component.onCompleted: { Component.onCompleted: {
detectCompositor() detectCompositor();
scheduleSort() scheduleSort();
Qt.callLater(() => NiriService.generateNiriLayoutConfig()) Qt.callLater(() => NiriService.generateNiriLayoutConfig());
} }
Connections { Connections {
target: DwlService target: DwlService
function onStateChanged() { function onStateChanged() {
if (isDwl && !isHyprland && !isNiri) { if (isDwl && !isHyprland && !isNiri) {
scheduleSort() scheduleSort();
} }
} }
} }
function computeSortedToplevels() { function computeSortedToplevels() {
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values) if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values)
return [] return [];
if (useNiriSorting) if (useNiriSorting)
return NiriService.sortToplevels(ToplevelManager.toplevels.values) return NiriService.sortToplevels(ToplevelManager.toplevels.values);
if (isHyprland) if (isHyprland)
return sortHyprlandToplevelsSafe() return sortHyprlandToplevelsSafe();
return Array.from(ToplevelManager.toplevels.values) return Array.from(ToplevelManager.toplevels.values);
} }
function _get(o, path, fallback) { function _get(o, path, fallback) {
try { try {
let v = o let v = o;
for (let i = 0; i < path.length; i++) { for (let i = 0; i < path.length; i++) {
if (v === null || v === undefined) return fallback if (v === null || v === undefined)
v = v[path[i]] return fallback;
v = v[path[i]];
} }
return (v === undefined || v === null) ? fallback : v return (v === undefined || v === null) ? fallback : v;
} catch (e) { return fallback } } catch (e) {
return fallback;
}
} }
function sortHyprlandToplevelsSafe() { function sortHyprlandToplevelsSafe() {
if (!Hyprland.toplevels || !Hyprland.toplevels.values) return [] if (!Hyprland.toplevels || !Hyprland.toplevels.values)
return [];
const items = Array.from(Hyprland.toplevels.values) const items = Array.from(Hyprland.toplevels.values);
function _get(o, path, fb) { function _get(o, path, fb) {
try { try {
let v = o let v = o;
for (let k of path) { if (v == null) return fb; v = v[k] } for (let k of path) {
return (v == null) ? fb : v if (v == null)
} catch(e) { return fb } return fb;
v = v[k];
}
return (v == null) ? fb : v;
} catch (e) {
return fb;
}
} }
let snap = [] let snap = [];
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const t = items[i] const t = items[i];
if (!t) continue if (!t)
continue;
const addr = t.address || "";
if (!addr)
continue;
const li = t.lastIpcObject || null;
const addr = t.address || "" const monName = _get(li, ["monitor"], null) ?? _get(t, ["monitor", "name"], "");
if (!addr) continue const monX = _get(t, ["monitor", "x"], Number.MAX_SAFE_INTEGER);
const monY = _get(t, ["monitor", "y"], Number.MAX_SAFE_INTEGER);
const li = t.lastIpcObject || null const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER);
const monName = _get(li, ["monitor"], null) ?? _get(t, ["monitor", "name"], "") const at = _get(li, ["at"], null);
const monX = _get(t, ["monitor", "x"], Number.MAX_SAFE_INTEGER) let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : 1e9;
const monY = _get(t, ["monitor", "y"], Number.MAX_SAFE_INTEGER) let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : 1e9;
const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER) const relX = Number.isFinite(monX) ? (atX - monX) : atX;
const relY = Number.isFinite(monY) ? (atY - monY) : atY;
const at = _get(li, ["at"], null)
let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : 1e9
let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : 1e9
const relX = Number.isFinite(monX) ? (atX - monX) : atX
const relY = Number.isFinite(monY) ? (atY - monY) : atY
snap.push({ snap.push({
monKey: String(monName), monKey: String(monName),
@@ -197,19 +203,20 @@ Singleton {
title: t.title || "", title: t.title || "",
address: addr, address: addr,
wayland: t.wayland wayland: t.wayland
}) });
} }
const groups = new Map() const groups = new Map();
for (const it of snap) { for (const it of snap) {
const key = it.monKey + "::" + it.wsId const key = it.monKey + "::" + it.wsId;
if (!groups.has(key)) groups.set(key, []) if (!groups.has(key))
groups.get(key).push(it) groups.set(key, []);
groups.get(key).push(it);
} }
let groupList = [] let groupList = [];
for (const [key, arr] of groups) { for (const [key, arr] of groups) {
const repr = arr[0] const repr = arr[0];
groupList.push({ groupList.push({
key, key,
monKey: repr.monKey, monKey: repr.monKey,
@@ -217,122 +224,143 @@ Singleton {
monOrderY: repr.monOrderY, monOrderY: repr.monOrderY,
wsId: repr.wsId, wsId: repr.wsId,
items: arr items: arr
}) });
} }
groupList.sort((a, b) => { groupList.sort((a, b) => {
if (a.monOrderX !== b.monOrderX) return a.monOrderX - b.monOrderX if (a.monOrderX !== b.monOrderX)
if (a.monOrderY !== b.monOrderY) return a.monOrderY - b.monOrderY return a.monOrderX - b.monOrderX;
if (a.monKey !== b.monKey) return a.monKey.localeCompare(b.monKey) if (a.monOrderY !== b.monOrderY)
if (a.wsId !== b.wsId) return a.wsId - b.wsId return a.monOrderY - b.monOrderY;
return 0 if (a.monKey !== b.monKey)
}) return a.monKey.localeCompare(b.monKey);
if (a.wsId !== b.wsId)
return a.wsId - b.wsId;
return 0;
});
const COLUMN_THRESHOLD = 48 const COLUMN_THRESHOLD = 48;
const JITTER_Y = 6 const JITTER_Y = 6;
let ordered = [] let ordered = [];
for (const g of groupList) { for (const g of groupList) {
const arr = g.items const arr = g.items;
const xs = arr.map(it => it.x).filter(x => Number.isFinite(x)).sort((a, b) => a - b) const xs = arr.map(it => it.x).filter(x => Number.isFinite(x)).sort((a, b) => a - b);
let colCenters = [] let colCenters = [];
if (xs.length > 0) { if (xs.length > 0) {
for (const x of xs) { for (const x of xs) {
if (colCenters.length === 0) { if (colCenters.length === 0) {
colCenters.push(x) colCenters.push(x);
} else { } else {
const last = colCenters[colCenters.length - 1] const last = colCenters[colCenters.length - 1];
if (x - last >= COLUMN_THRESHOLD) { if (x - last >= COLUMN_THRESHOLD) {
colCenters.push(x) colCenters.push(x);
} }
} }
} }
} else { } else {
colCenters = [0] colCenters = [0];
} }
for (const it of arr) { for (const it of arr) {
let bestCol = 0 let bestCol = 0;
let bestDist = Number.POSITIVE_INFINITY let bestDist = Number.POSITIVE_INFINITY;
for (let ci = 0; ci < colCenters.length; ci++) { for (let ci = 0; ci < colCenters.length; ci++) {
const d = Math.abs(it.x - colCenters[ci]) const d = Math.abs(it.x - colCenters[ci]);
if (d < bestDist) { if (d < bestDist) {
bestDist = d bestDist = d;
bestCol = ci bestCol = ci;
} }
} }
it._col = bestCol it._col = bestCol;
} }
arr.sort((a, b) => { arr.sort((a, b) => {
if (a._col !== b._col) return a._col - b._col if (a._col !== b._col)
return a._col - b._col;
const dy = a.y - b.y const dy = a.y - b.y;
if (Math.abs(dy) > JITTER_Y) return dy if (Math.abs(dy) > JITTER_Y)
return dy;
if (a.title !== b.title) return a.title.localeCompare(b.title) if (a.title !== b.title)
if (a.address !== b.address) return a.address.localeCompare(b.address) return a.title.localeCompare(b.title);
return 0 if (a.address !== b.address)
}) return a.address.localeCompare(b.address);
return 0;
});
ordered.push.apply(ordered, arr) ordered.push.apply(ordered, arr);
} }
return ordered.map(x => x.wayland).filter(w => w !== null && w !== undefined) return ordered.map(x => x.wayland).filter(w => w !== null && w !== undefined);
} }
function filterCurrentWorkspace(toplevels, screen) { function filterCurrentWorkspace(toplevels, screen) {
if (useNiriSorting) return NiriService.filterCurrentWorkspace(toplevels, screen) if (useNiriSorting)
if (isHyprland) return filterHyprlandCurrentWorkspaceSafe(toplevels, screen) return NiriService.filterCurrentWorkspace(toplevels, screen);
return toplevels if (isHyprland)
return filterHyprlandCurrentWorkspaceSafe(toplevels, screen);
return toplevels;
} }
function filterHyprlandCurrentWorkspaceSafe(toplevels, screenName) { function filterHyprlandCurrentWorkspaceSafe(toplevels, screenName) {
if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels) return toplevels if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels)
return toplevels;
let currentWorkspaceId = null let currentWorkspaceId = null;
try { try {
const hy = Array.from(Hyprland.toplevels.values) const hy = Array.from(Hyprland.toplevels.values);
for (const t of hy) { for (const t of hy) {
const mon = _get(t, ["monitor", "name"], "") const mon = _get(t, ["monitor", "name"], "");
const wsId = _get(t, ["workspace", "id"], null) const wsId = _get(t, ["workspace", "id"], null);
const active = !!_get(t, ["activated"], false) const active = !!_get(t, ["activated"], false);
if (mon === screenName && wsId !== null) { if (mon === screenName && wsId !== null) {
if (active) { currentWorkspaceId = wsId; break } if (active) {
if (currentWorkspaceId === null) currentWorkspaceId = wsId currentWorkspaceId = wsId;
break;
}
if (currentWorkspaceId === null)
currentWorkspaceId = wsId;
} }
} }
if (currentWorkspaceId === null && Hyprland.workspaces) { if (currentWorkspaceId === null && Hyprland.workspaces) {
const wss = Array.from(Hyprland.workspaces.values) const wss = Array.from(Hyprland.workspaces.values);
const focusedId = _get(Hyprland, ["focusedWorkspace", "id"], null) const focusedId = _get(Hyprland, ["focusedWorkspace", "id"], null);
for (const ws of wss) { for (const ws of wss) {
const monName = _get(ws, ["monitor"], "") const monName = _get(ws, ["monitor"], "");
const wsId = _get(ws, ["id"], null) const wsId = _get(ws, ["id"], null);
if (monName === screenName && wsId !== null) { if (monName === screenName && wsId !== null) {
if (focusedId !== null && wsId === focusedId) { currentWorkspaceId = wsId; break } if (focusedId !== null && wsId === focusedId) {
if (currentWorkspaceId === null) currentWorkspaceId = wsId currentWorkspaceId = wsId;
break;
}
if (currentWorkspaceId === null)
currentWorkspaceId = wsId;
} }
} }
} }
} catch (e) { } catch (e) {
console.warn("CompositorService: workspace snapshot failed:", e) console.warn("CompositorService: workspace snapshot failed:", e);
} }
if (currentWorkspaceId === null) return toplevels if (currentWorkspaceId === null)
return toplevels;
// Map wayland → wsId snapshot // Map wayland → wsId snapshot
let map = new Map() let map = new Map();
try { try {
const hy = Array.from(Hyprland.toplevels.values) const hy = Array.from(Hyprland.toplevels.values);
for (const t of hy) { for (const t of hy) {
const wsId = _get(t, ["workspace", "id"], null) const wsId = _get(t, ["workspace", "id"], null);
if (t && t.wayland && wsId !== null) map.set(t.wayland, wsId) if (t && t.wayland && wsId !== null)
map.set(t.wayland, wsId);
} }
} catch (e) {} } catch (e) {}
return toplevels.filter(w => map.get(w) === currentWorkspaceId) return toplevels.filter(w => map.get(w) === currentWorkspaceId);
} }
Timer { Timer {
@@ -341,77 +369,76 @@ Singleton {
running: true running: true
repeat: false repeat: false
onTriggered: { onTriggered: {
detectCompositor() detectCompositor();
Qt.callLater(() => NiriService.generateNiriLayoutConfig()) Qt.callLater(() => NiriService.generateNiriLayoutConfig());
} }
} }
function detectCompositor() { function detectCompositor() {
if (hyprlandSignature && hyprlandSignature.length > 0 && if (hyprlandSignature && hyprlandSignature.length > 0 && !niriSocket && !swaySocket && !labwcPid) {
!niriSocket && !swaySocket && !labwcPid) { isHyprland = true;
isHyprland = true isNiri = false;
isNiri = false isDwl = false;
isDwl = false isSway = false;
isSway = false isLabwc = false;
isLabwc = false compositor = "hyprland";
compositor = "hyprland" console.info("CompositorService: Detected Hyprland");
console.info("CompositorService: Detected Hyprland") return;
return
} }
if (niriSocket && niriSocket.length > 0) { if (niriSocket && niriSocket.length > 0) {
Proc.runCommand("niriSocketCheck", ["test", "-S", niriSocket], (output, exitCode) => { Proc.runCommand("niriSocketCheck", ["test", "-S", niriSocket], (output, exitCode) => {
if (exitCode === 0) { if (exitCode === 0) {
isNiri = true isNiri = true;
isHyprland = false isHyprland = false;
isDwl = false isDwl = false;
isSway = false isSway = false;
isLabwc = false isLabwc = false;
compositor = "niri" compositor = "niri";
console.info("CompositorService: Detected Niri with socket:", niriSocket) console.info("CompositorService: Detected Niri with socket:", niriSocket);
NiriService.generateNiriBinds() NiriService.generateNiriBinds();
NiriService.generateNiriBlurrule() NiriService.generateNiriBlurrule();
} }
}, 0) }, 0);
return return;
} }
if (swaySocket && swaySocket.length > 0) { if (swaySocket && swaySocket.length > 0) {
Proc.runCommand("swaySocketCheck", ["test", "-S", swaySocket], (output, exitCode) => { Proc.runCommand("swaySocketCheck", ["test", "-S", swaySocket], (output, exitCode) => {
if (exitCode === 0) { if (exitCode === 0) {
isNiri = false isNiri = false;
isHyprland = false isHyprland = false;
isDwl = false isDwl = false;
isSway = true isSway = true;
isLabwc = false isLabwc = false;
compositor = "sway" compositor = "sway";
console.info("CompositorService: Detected Sway with socket:", swaySocket) console.info("CompositorService: Detected Sway with socket:", swaySocket);
} }
}, 0) }, 0);
return return;
} }
if (labwcPid && labwcPid.length > 0) { if (labwcPid && labwcPid.length > 0) {
isHyprland = false isHyprland = false;
isNiri = false isNiri = false;
isDwl = false isDwl = false;
isSway = false isSway = false;
isLabwc = true isLabwc = true;
compositor = "labwc" compositor = "labwc";
console.info("CompositorService: Detected LabWC with PID:", labwcPid) console.info("CompositorService: Detected LabWC with PID:", labwcPid);
return return;
} }
if (DMSService.dmsAvailable) { if (DMSService.dmsAvailable) {
Qt.callLater(checkForDwl) Qt.callLater(checkForDwl);
} else { } else {
isHyprland = false isHyprland = false;
isNiri = false isNiri = false;
isDwl = false isDwl = false;
isSway = false isSway = false;
isLabwc = false isLabwc = false;
compositor = "unknown" compositor = "unknown";
console.warn("CompositorService: No compositor detected") console.warn("CompositorService: No compositor detected");
} }
} }
@@ -419,65 +446,85 @@ Singleton {
target: DMSService target: DMSService
function onCapabilitiesReceived() { function onCapabilitiesReceived() {
if (!isHyprland && !isNiri && !isDwl && !isLabwc) { if (!isHyprland && !isNiri && !isDwl && !isLabwc) {
checkForDwl() checkForDwl();
} }
} }
} }
function checkForDwl() { function checkForDwl() {
if (DMSService.apiVersion >= 12 && DMSService.capabilities.includes("dwl")) { if (DMSService.apiVersion >= 12 && DMSService.capabilities.includes("dwl")) {
isHyprland = false isHyprland = false;
isNiri = false isNiri = false;
isDwl = true isDwl = true;
isSway = false isSway = false;
isLabwc = false isLabwc = false;
compositor = "dwl" compositor = "dwl";
console.info("CompositorService: Detected DWL via DMS capability") console.info("CompositorService: Detected DWL via DMS capability");
} }
} }
function powerOffMonitors() { function powerOffMonitors() {
if (isNiri) return NiriService.powerOffMonitors() if (isNiri)
if (isHyprland) return Hyprland.dispatch("dpms off") return NiriService.powerOffMonitors();
if (isDwl) return _dwlPowerOffMonitors() if (isHyprland)
if (isSway) { try { I3.dispatch("output * dpms off") } catch(_){} return } return Hyprland.dispatch("dpms off");
if (isLabwc) { Quickshell.execDetached(["dms", "dpms", "off"]) } if (isDwl)
console.warn("CompositorService: Cannot power off monitors, unknown compositor") return _dwlPowerOffMonitors();
if (isSway) {
try {
I3.dispatch("output * dpms off");
} catch (_) {}
return;
}
if (isLabwc) {
Quickshell.execDetached(["dms", "dpms", "off"]);
}
console.warn("CompositorService: Cannot power off monitors, unknown compositor");
} }
function powerOnMonitors() { function powerOnMonitors() {
if (isNiri) return NiriService.powerOnMonitors() if (isNiri)
if (isHyprland) return Hyprland.dispatch("dpms on") return NiriService.powerOnMonitors();
if (isDwl) return _dwlPowerOnMonitors() if (isHyprland)
if (isSway) { try { I3.dispatch("output * dpms on") } catch(_){} return } return Hyprland.dispatch("dpms on");
if (isLabwc) { Quickshell.execDetached(["dms", "dpms", "on"]) } if (isDwl)
console.warn("CompositorService: Cannot power on monitors, unknown compositor") return _dwlPowerOnMonitors();
if (isSway) {
try {
I3.dispatch("output * dpms on");
} catch (_) {}
return;
}
if (isLabwc) {
Quickshell.execDetached(["dms", "dpms", "on"]);
}
console.warn("CompositorService: Cannot power on monitors, unknown compositor");
} }
function _dwlPowerOffMonitors() { function _dwlPowerOffMonitors() {
if (!Quickshell.screens || Quickshell.screens.length === 0) { if (!Quickshell.screens || Quickshell.screens.length === 0) {
console.warn("CompositorService: No screens available for DWL power off") console.warn("CompositorService: No screens available for DWL power off");
return return;
} }
for (let i = 0; i < Quickshell.screens.length; i++) { for (let i = 0; i < Quickshell.screens.length; i++) {
const screen = Quickshell.screens[i] const screen = Quickshell.screens[i];
if (screen && screen.name) { if (screen && screen.name) {
Quickshell.execDetached(["mmsg", "-d", "disable_monitor," + screen.name]) Quickshell.execDetached(["mmsg", "-d", "disable_monitor," + screen.name]);
} }
} }
} }
function _dwlPowerOnMonitors() { function _dwlPowerOnMonitors() {
if (!Quickshell.screens || Quickshell.screens.length === 0) { if (!Quickshell.screens || Quickshell.screens.length === 0) {
console.warn("CompositorService: No screens available for DWL power on") console.warn("CompositorService: No screens available for DWL power on");
return return;
} }
for (let i = 0; i < Quickshell.screens.length; i++) { for (let i = 0; i < Quickshell.screens.length; i++) {
const screen = Quickshell.screens[i] const screen = Quickshell.screens[i];
if (screen && screen.name) { if (screen && screen.name) {
Quickshell.execDetached(["mmsg", "-d", "enable_monitor," + screen.name]) Quickshell.execDetached(["mmsg", "-d", "enable_monitor," + screen.name]);
} }
} }
} }

View File

@@ -962,7 +962,7 @@ Singleton {
console.log("NiriService: Generating layout config...") console.log("NiriService: Generating layout config...")
const cornerRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12 const cornerRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12
const gaps = typeof SettingsData !== "undefined" ? Math.max(4, SettingsData.dankBarSpacing) : 4 const gaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4
const configContent = `layout { const configContent = `layout {
gaps ${gaps} gaps ${gaps}

View File

@@ -411,6 +411,16 @@ Singleton {
NotifWrapper {} NotifWrapper {}
} }
function clearAllPopups() {
for (const w of visibleNotifications) {
if (w) {
w.popup = false
}
}
visibleNotifications = []
notificationQueue = []
}
function clearAllNotifications() { function clearAllNotifications() {
bulkDismissing = true bulkDismissing = true
popupsDisabled = true popupsDisabled = true

View File

@@ -428,9 +428,12 @@ Singleton {
return id !== widgetId return id !== widgetId
} }
const leftWidgets = SettingsData.dankBarLeftWidgets const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const centerWidgets = SettingsData.dankBarCenterWidgets if (!defaultBar) return
const rightWidgets = SettingsData.dankBarRightWidgets
const leftWidgets = defaultBar.leftWidgets || []
const centerWidgets = defaultBar.centerWidgets || []
const rightWidgets = defaultBar.rightWidgets || []
const newLeft = leftWidgets.filter(filterWidget) const newLeft = leftWidgets.filter(filterWidget)
const newCenter = centerWidgets.filter(filterWidget) const newCenter = centerWidgets.filter(filterWidget)

View File

@@ -78,14 +78,19 @@ PanelWindow {
readonly property bool isVerticalLayout: SettingsData.osdPosition === SettingsData.Position.LeftCenter || SettingsData.osdPosition === SettingsData.Position.RightCenter readonly property bool isVerticalLayout: SettingsData.osdPosition === SettingsData.Position.LeftCenter || SettingsData.osdPosition === SettingsData.Position.RightCenter
readonly property real barThickness: { readonly property real barThickness: {
if (!SettingsData.dankBarVisible) return 0 const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6) if (!defaultBar || !(defaultBar.visible ?? true)) return 0
return Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) 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: { readonly property real barOffset: {
if (!SettingsData.dankBarVisible) return 0 const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
return barThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap 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: { readonly property real dockThickness: {
@@ -102,23 +107,26 @@ PanelWindow {
const margin = Theme.spacingM const margin = Theme.spacingM
const centerX = (screenWidth - alignedWidth) / 2 const centerX = (screenWidth - alignedWidth) / 2
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
switch (SettingsData.osdPosition) { switch (SettingsData.osdPosition) {
case SettingsData.Position.Left: case SettingsData.Position.Left:
case SettingsData.Position.Bottom: 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 const leftDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
return Theme.snap(margin + Math.max(leftBarOffset, leftDockOffset), dpr) return Theme.snap(margin + Math.max(leftBarOffset, leftDockOffset), dpr)
case SettingsData.Position.Top: case SettingsData.Position.Top:
case SettingsData.Position.Right: 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 const rightDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightBarOffset, rightDockOffset), dpr) return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightBarOffset, rightDockOffset), dpr)
case SettingsData.Position.LeftCenter: 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 const leftCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
return Theme.snap(margin + Math.max(leftCenterBarOffset, leftCenterDockOffset), dpr) return Theme.snap(margin + Math.max(leftCenterBarOffset, leftCenterDockOffset), dpr)
case SettingsData.Position.RightCenter: 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 const rightCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightCenterBarOffset, rightCenterDockOffset), dpr) return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightCenterBarOffset, rightCenterDockOffset), dpr)
case SettingsData.Position.TopCenter: case SettingsData.Position.TopCenter:
@@ -132,17 +140,20 @@ PanelWindow {
const margin = Theme.spacingM const margin = Theme.spacingM
const centerY = (screenHeight - alignedHeight) / 2 const centerY = (screenHeight - alignedHeight) / 2
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
switch (SettingsData.osdPosition) { switch (SettingsData.osdPosition) {
case SettingsData.Position.Top: case SettingsData.Position.Top:
case SettingsData.Position.Left: case SettingsData.Position.Left:
case SettingsData.Position.TopCenter: 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 const topDockOffset = SettingsData.dockPosition === SettingsData.Position.Top ? dockOffset : 0
return Theme.snap(margin + Math.max(topBarOffset, topDockOffset), dpr) return Theme.snap(margin + Math.max(topBarOffset, topDockOffset), dpr)
case SettingsData.Position.Right: case SettingsData.Position.Right:
case SettingsData.Position.Bottom: case SettingsData.Position.Bottom:
case SettingsData.Position.BottomCenter: 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 const bottomDockOffset = SettingsData.dockPosition === SettingsData.Position.Bottom ? dockOffset : 0
return Theme.snap(screenHeight - alignedHeight - margin - Math.max(bottomBarOffset, bottomDockOffset), dpr) return Theme.snap(screenHeight - alignedHeight - margin - Math.max(bottomBarOffset, bottomDockOffset), dpr)
case SettingsData.Position.LeftCenter: case SettingsData.Position.LeftCenter:
@@ -217,14 +228,15 @@ PanelWindow {
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr)) layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect { layer.effect: MultiEffect {
id: shadowFx id: shadowFx
autoPaddingEnabled: true autoPaddingEnabled: true
shadowEnabled: true shadowEnabled: true
blurEnabled: false blurEnabled: false
maskEnabled: false maskEnabled: false
property int blurMax: 64 shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / bgShadowLayer.blurMax))
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: { shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest 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 list<real> animationExitCurve: Theme.expressiveCurves.emphasized
property bool shouldBeVisible: false 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 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: { readonly property var barBounds: {
if (!root.screen) { if (!root.screen) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 } 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 readonly property real barX: barBounds.x
@@ -50,6 +58,31 @@ PanelWindow {
signal popoutClosed signal popoutClosed
signal backgroundClicked 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() { function open() {
closeTimer.stop() closeTimer.stop()
shouldBeVisible = true shouldBeVisible = true
@@ -115,75 +148,71 @@ PanelWindow {
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)
property int effectiveBarPosition: 0
property real effectiveBarBottomGap: 0
readonly property real alignedX: Theme.snap((() => { readonly property real alignedX: Theme.snap((() => {
if (SettingsData.dankBarPosition === SettingsData.Position.Left) { const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
return triggerY + SettingsData.dankBarBottomGap const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
} else if (SettingsData.dankBarPosition === SettingsData.Position.Right) { const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
return screenWidth - triggerY - SettingsData.dankBarBottomGap - popupWidth
let rawX = 0
if (effectiveBarPosition === SettingsData.Position.Left) {
rawX = triggerX
} else if (effectiveBarPosition === SettingsData.Position.Right) {
rawX = triggerX - popupWidth
} else { } else {
const centerX = triggerX + (triggerWidth / 2) - (popupWidth / 2) rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
return Math.max(Theme.popupDistance, Math.min(screenWidth - popupWidth - Theme.popupDistance, centerX)) 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) })(), dpr)
readonly property real alignedY: Theme.snap((() => { readonly property real alignedY: Theme.snap((() => {
if (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right) { const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
const centerY = triggerX + (triggerWidth / 2) - (popupHeight / 2) const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
return Math.max(Theme.popupDistance, Math.min(screenHeight - popupHeight - Theme.popupDistance, centerY)) const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
} else if (SettingsData.dankBarPosition === SettingsData.Position.Bottom) {
return Math.max(Theme.popupDistance, screenHeight - triggerY - popupHeight) let rawY = 0
if (effectiveBarPosition === SettingsData.Position.Bottom) {
rawY = triggerY - popupHeight
} else if (effectiveBarPosition === SettingsData.Position.Top) {
rawY = triggerY
} else { } 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) })(), dpr)
readonly property real maskX: { readonly property real maskX: {
switch (SettingsData.dankBarPosition) { const triggeringBarX = (effectiveBarPosition === SettingsData.Position.Left && root.barWidth > 0) ? root.barWidth : 0
case SettingsData.Position.Left: const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0
return root.barWidth > 0 ? root.barWidth : 0 return Math.max(triggeringBarX, adjacentLeftBar)
case SettingsData.Position.Right:
case SettingsData.Position.Top:
case SettingsData.Position.Bottom:
default:
return 0
}
} }
readonly property real maskY: { readonly property real maskY: {
switch (SettingsData.dankBarPosition) { const triggeringBarY = (effectiveBarPosition === SettingsData.Position.Top && root.barHeight > 0) ? root.barHeight : 0
case SettingsData.Position.Top: const adjacentTopBar = adjacentBarInfo?.topBar ?? 0
return root.barHeight > 0 ? root.barHeight : 0 return Math.max(triggeringBarY, adjacentTopBar)
case SettingsData.Position.Bottom:
case SettingsData.Position.Left:
case SettingsData.Position.Right:
default:
return 0
}
} }
readonly property real maskWidth: { readonly property real maskWidth: {
switch (SettingsData.dankBarPosition) { const triggeringBarRight = (effectiveBarPosition === SettingsData.Position.Right && root.barWidth > 0) ? root.barWidth : 0
case SettingsData.Position.Left: const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0
return root.barWidth > 0 ? root.width - root.barWidth : root.width const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar)
case SettingsData.Position.Right: return Math.max(100, root.width - maskX - rightExclusion)
return root.barWidth > 0 ? root.width - root.barWidth : root.width
case SettingsData.Position.Top:
case SettingsData.Position.Bottom:
default:
return root.width
}
} }
readonly property real maskHeight: { readonly property real maskHeight: {
switch (SettingsData.dankBarPosition) { const triggeringBarBottom = (effectiveBarPosition === SettingsData.Position.Bottom && root.barHeight > 0) ? root.barHeight : 0
case SettingsData.Position.Top: const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0
return root.barHeight > 0 ? root.height - root.barHeight : root.height const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar)
case SettingsData.Position.Bottom: return Math.max(100, root.height - maskY - bottomExclusion)
return root.barHeight > 0 ? root.height - root.barHeight : root.height
case SettingsData.Position.Left:
case SettingsData.Position.Right:
default:
return root.height
}
} }
mask: Region { mask: Region {
@@ -222,10 +251,10 @@ PanelWindow {
width: alignedWidth width: alignedWidth
height: alignedHeight height: alignedHeight
readonly property bool barTop: SettingsData.dankBarPosition === SettingsData.Position.Top readonly property bool barTop: effectiveBarPosition === SettingsData.Position.Top
readonly property bool barBottom: SettingsData.dankBarPosition === SettingsData.Position.Bottom readonly property bool barBottom: effectiveBarPosition === SettingsData.Position.Bottom
readonly property bool barLeft: SettingsData.dankBarPosition === SettingsData.Position.Left readonly property bool barLeft: effectiveBarPosition === SettingsData.Position.Left
readonly property bool barRight: SettingsData.dankBarPosition === SettingsData.Position.Right readonly property bool barRight: effectiveBarPosition === SettingsData.Position.Right
readonly property real offsetX: barLeft ? root.animationOffset : (barRight ? -root.animationOffset : 0) readonly property real offsetX: barLeft ? root.animationOffset : (barRight ? -root.animationOffset : 0)
readonly property real offsetY: barBottom ? -root.animationOffset : (barTop ? 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.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect { layer.effect: MultiEffect {
id: shadowFx id: shadowFx
autoPaddingEnabled: true autoPaddingEnabled: true
shadowEnabled: true shadowEnabled: true
blurEnabled: false blurEnabled: false
maskEnabled: false maskEnabled: false
property int blurMax: 64 shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / bgShadowLayer.blurMax))
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: { shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest

View File

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

View File

@@ -50,13 +50,22 @@ PanelWindow {
margins { margins {
left: { left: {
if (alignLeft) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX))) const screenWidth = targetScreen?.width ?? Screen.width
if (alignRight) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX - implicitWidth))) if (alignLeft) {
return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX - implicitWidth / 2))) 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: { top: {
if (alignLeft || alignRight) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.height ?? Screen.height) - implicitHeight - Theme.spacingS, targetY - implicitHeight / 2))) const screenHeight = targetScreen?.height ?? Screen.height
return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.height ?? Screen.height) - implicitHeight - Theme.spacingS, targetY))) 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: { Component.onCompleted: {
Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $ID"], (output, exitCode) => { 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() 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"] const supportedDistroNFs = ["debian", "arch", "archcraft", "fedora", "nixos", "ubuntu", "guix", "gentoo", "endeavouros", "manjaro", "opensuse"]
if (supportedDistroNFs.includes(distroId)) { if (supportedDistroNFs.includes(distroId)) {
if (!root) return
root.useNerdFont = true root.useNerdFont = true
root.nerdFontIcon = distroId root.nerdFontIcon = distroId
return return
} }
Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $LOGO"], (logoOutput, logoExitCode) => { 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() const logo = logoOutput.trim()
if (!logo) return
if (logo === "cachyos") { if (logo === "cachyos") {
iconImage.source = "file:///usr/share/icons/cachyos.svg" iconImage.source = "file:///usr/share/icons/cachyos.svg"
return 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" iconImage.source = "file:///run/current-system/profile/share/icons/hicolor/scalable/apps/guix-icon.svg"
return return
} }