1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

Compare commits

..

1 Commits

Author SHA1 Message Date
bbedward
db28879185 Reparations for drag and drop control center edits 2025-09-25 21:29:14 -04:00
125 changed files with 3697 additions and 10266 deletions

View File

@@ -1,6 +1,6 @@
# Contributing
Contributions are welcome and encouraged.
Contributions are welcome and encourages.
## Formatting
@@ -27,4 +27,4 @@ Sometimes it just breaks code though. Like turning `"_\""` into `"_""`, so you m
## Pull request
Include screenshots/video if applicable in your pull request if applicable, to visualize what your change is affecting.
Include screenshots/video if applicable in your pull request if applicable, to visualize what your change is affecting.

View File

@@ -18,11 +18,6 @@ Singleton {
property string profileLastPath: ""
property bool perMonitorWallpaper: false
property var monitorWallpapers: ({})
property bool perModeWallpaper: false
property string wallpaperPathLight: ""
property string wallpaperPathDark: ""
property var monitorWallpapersLight: ({})
property var monitorWallpapersDark: ({})
property bool doNotDisturb: false
property bool nightModeEnabled: false
property int nightModeTemperature: 4500
@@ -88,11 +83,6 @@ Singleton {
profileLastPath = settings.profileLastPath !== undefined ? settings.profileLastPath : ""
perMonitorWallpaper = settings.perMonitorWallpaper !== undefined ? settings.perMonitorWallpaper : false
monitorWallpapers = settings.monitorWallpapers !== undefined ? settings.monitorWallpapers : {}
perModeWallpaper = settings.perModeWallpaper !== undefined ? settings.perModeWallpaper : false
wallpaperPathLight = settings.wallpaperPathLight !== undefined ? settings.wallpaperPathLight : ""
wallpaperPathDark = settings.wallpaperPathDark !== undefined ? settings.wallpaperPathDark : ""
monitorWallpapersLight = settings.monitorWallpapersLight !== undefined ? settings.monitorWallpapersLight : {}
monitorWallpapersDark = settings.monitorWallpapersDark !== undefined ? settings.monitorWallpapersDark : {}
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
nightModeTemperature = settings.nightModeTemperature !== undefined ? settings.nightModeTemperature : 4500
@@ -161,11 +151,6 @@ Singleton {
"profileLastPath": profileLastPath,
"perMonitorWallpaper": perMonitorWallpaper,
"monitorWallpapers": monitorWallpapers,
"perModeWallpaper": perModeWallpaper,
"wallpaperPathLight": wallpaperPathLight,
"wallpaperPathDark": wallpaperPathDark,
"monitorWallpapersLight": monitorWallpapersLight,
"monitorWallpapersDark": monitorWallpapersDark,
"doNotDisturb": doNotDisturb,
"nightModeEnabled": nightModeEnabled,
"nightModeTemperature": nightModeTemperature,
@@ -206,21 +191,9 @@ Singleton {
function setLightMode(lightMode) {
isLightMode = lightMode
syncWallpaperForCurrentMode()
saveSettings()
}
function syncWallpaperForCurrentMode() {
if (!perModeWallpaper) return
if (perMonitorWallpaper) {
monitorWallpapers = isLightMode ? Object.assign({}, monitorWallpapersLight) : Object.assign({}, monitorWallpapersDark)
return
}
wallpaperPath = isLightMode ? wallpaperPathLight : wallpaperPathDark
}
function setDoNotDisturb(enabled) {
doNotDisturb = enabled
saveSettings()
@@ -291,13 +264,6 @@ Singleton {
function setWallpaper(imagePath) {
wallpaperPath = imagePath
if (perModeWallpaper) {
if (isLightMode) {
wallpaperPathLight = imagePath
} else {
wallpaperPathDark = imagePath
}
}
saveSettings()
if (typeof Theme !== "undefined") {
@@ -307,13 +273,6 @@ Singleton {
function setWallpaperColor(color) {
wallpaperPath = color
if (perModeWallpaper) {
if (isLightMode) {
wallpaperPathLight = color
} else {
wallpaperPathDark = color
}
}
saveSettings()
if (typeof Theme !== "undefined") {
@@ -461,51 +420,9 @@ Singleton {
function setPerMonitorWallpaper(enabled) {
perMonitorWallpaper = enabled
if (enabled && perModeWallpaper) {
syncWallpaperForCurrentMode()
}
saveSettings()
if (typeof Theme !== "undefined") {
Theme.generateSystemThemesFromCurrentTheme()
}
}
function setPerModeWallpaper(enabled) {
if (enabled && wallpaperCyclingEnabled) {
setWallpaperCyclingEnabled(false)
}
if (enabled && perMonitorWallpaper) {
var monitorCyclingAny = false
for (var key in monitorCyclingSettings) {
if (monitorCyclingSettings[key].enabled) {
monitorCyclingAny = true
break
}
}
if (monitorCyclingAny) {
var newSettings = Object.assign({}, monitorCyclingSettings)
for (var screenName in newSettings) {
newSettings[screenName].enabled = false
}
monitorCyclingSettings = newSettings
}
}
perModeWallpaper = enabled
if (enabled) {
if (perMonitorWallpaper) {
monitorWallpapersLight = Object.assign({}, monitorWallpapers)
monitorWallpapersDark = Object.assign({}, monitorWallpapers)
} else {
wallpaperPathLight = wallpaperPath
wallpaperPathDark = wallpaperPath
}
} else {
syncWallpaperForCurrentMode()
}
saveSettings()
// Refresh dynamic theming when per-monitor mode changes
if (typeof Theme !== "undefined") {
Theme.generateSystemThemesFromCurrentTheme()
}
@@ -519,29 +436,9 @@ Singleton {
delete newMonitorWallpapers[screenName]
}
monitorWallpapers = newMonitorWallpapers
if (perModeWallpaper) {
if (isLightMode) {
var newLight = Object.assign({}, monitorWallpapersLight)
if (path && path !== "") {
newLight[screenName] = path
} else {
delete newLight[screenName]
}
monitorWallpapersLight = newLight
} else {
var newDark = Object.assign({}, monitorWallpapersDark)
if (path && path !== "") {
newDark[screenName] = path
} else {
delete newDark[screenName]
}
monitorWallpapersDark = newDark
}
}
saveSettings()
// Trigger dynamic theming if this is the first monitor and dynamic theming is enabled
if (typeof Theme !== "undefined" && typeof Quickshell !== "undefined") {
var screens = Quickshell.screens
if (screens.length > 0 && screenName === screens[0].name) {

View File

@@ -12,27 +12,12 @@ import qs.Services
Singleton {
id: root
enum Position {
Top,
Bottom,
Left,
Right
}
enum AnimationSpeed {
None,
Shortest,
Short,
Medium,
Long
}
// Theme settings
property string currentThemeName: "blue"
property string customThemeFile: ""
property string matugenScheme: "scheme-tonal-spot"
property real dankBarTransparency: 1.0
property real dankBarWidgetTransparency: 1.0
property real topBarTransparency: 0.75
property real topBarWidgetTransparency: 0.85
property real popupTransparency: 1.0
property real dockTransparency: 1
property bool use24HourClock: true
@@ -85,13 +70,12 @@ Singleton {
property string clockDateFormat: ""
property string lockDateFormat: ""
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 alias dankBarLeftWidgetsModel: leftWidgetsModel
property alias dankBarCenterWidgetsModel: centerWidgetsModel
property alias dankBarRightWidgetsModel: rightWidgetsModel
property var topBarLeftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"]
property var topBarCenterWidgets: ["music", "clock", "weather"]
property var topBarRightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
property alias topBarLeftWidgetsModel: leftWidgetsModel
property alias topBarCenterWidgetsModel: centerWidgetsModel
property alias topBarRightWidgetsModel: rightWidgetsModel
property string appLauncherViewMode: "list"
property string spotlightModalViewMode: "list"
property string networkPreference: "auto"
@@ -133,23 +117,17 @@ Singleton {
property bool showDock: false
property bool dockAutoHide: false
property bool dockGroupByApp: false
property bool dockOpenOnOverview: false
property int dockPosition: SettingsData.Position.Bottom
property real dockSpacing: 4
property real dockBottomGap: 0
property real cornerRadius: 12
property bool notificationOverlayEnabled: false
property bool dankBarAutoHide: false
property bool dankBarOpenOnOverview: false
property bool dankBarVisible: true
property real dankBarSpacing: 4
property real dankBarBottomGap: 0
property real dankBarInnerPadding: 4
property bool dankBarSquareCorners: false
property bool dankBarNoBackground: false
property bool dankBarGothCornersEnabled: false
property int dankBarPosition: SettingsData.Position.Top
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
property bool topBarAutoHide: false
property bool topBarOpenOnOverview: false
property bool topBarVisible: true
property real topBarSpacing: 4
property real topBarBottomGap: 0
property real topBarInnerPadding: 8
property bool topBarSquareCorners: false
property bool topBarNoBackground: false
property bool topBarGothCornersEnabled: false
property bool lockScreenShowPowerActions: true
property bool hideBrightnessSlider: false
property string widgetBackgroundColor: "sch"
@@ -157,17 +135,14 @@ Singleton {
property int notificationTimeoutLow: 5000
property int notificationTimeoutNormal: 5000
property int notificationTimeoutCritical: 0
property int notificationPopupPosition: SettingsData.Position.Top
property var screenPreferences: ({})
property int animationSpeed: SettingsData.AnimationSpeed.Short
readonly property string defaultFontFamily: "Inter Variable"
readonly property string defaultMonoFontFamily: "Fira Code"
readonly property string _homeUrl: StandardPaths.writableLocation(StandardPaths.HomeLocation)
readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
readonly property string _configDir: Paths.strip(_configUrl)
signal forceDankBarLayoutRefresh
signal forceDockLayoutRefresh
signal forceTopBarLayoutRefresh
signal widgetDataChanged
signal workspaceIconsUpdated
@@ -204,9 +179,9 @@ Singleton {
centerWidgetsModel.append(dummyItem)
rightWidgetsModel.append(dummyItem)
updateListModel(leftWidgetsModel, dankBarLeftWidgets)
updateListModel(centerWidgetsModel, dankBarCenterWidgets)
updateListModel(rightWidgetsModel, dankBarRightWidgets)
updateListModel(leftWidgetsModel, topBarLeftWidgets)
updateListModel(centerWidgetsModel, topBarCenterWidgets)
updateListModel(rightWidgetsModel, topBarRightWidgets)
}
function loadSettings() {
@@ -234,8 +209,8 @@ Singleton {
}
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""
matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"
dankBarTransparency = settings.dankBarTransparency !== undefined ? (settings.dankBarTransparency > 1 ? settings.dankBarTransparency / 100 : settings.dankBarTransparency) : (settings.topBarTransparency !== undefined ? (settings.topBarTransparency > 1 ? settings.topBarTransparency / 100 : settings.topBarTransparency) : 1.0)
dankBarWidgetTransparency = settings.dankBarWidgetTransparency !== undefined ? (settings.dankBarWidgetTransparency > 1 ? settings.dankBarWidgetTransparency / 100 : settings.dankBarWidgetTransparency) : (settings.topBarWidgetTransparency !== undefined ? (settings.topBarWidgetTransparency > 1 ? settings.topBarWidgetTransparency / 100 : settings.topBarWidgetTransparency) : 1.0)
topBarTransparency = settings.topBarTransparency !== undefined ? (settings.topBarTransparency > 1 ? settings.topBarTransparency / 100 : settings.topBarTransparency) : 0.75
topBarWidgetTransparency = settings.topBarWidgetTransparency !== undefined ? (settings.topBarWidgetTransparency > 1 ? settings.topBarWidgetTransparency / 100 : settings.topBarWidgetTransparency) : 0.85
popupTransparency = settings.popupTransparency !== undefined ? (settings.popupTransparency > 1 ? settings.popupTransparency / 100 : settings.popupTransparency) : 1.0
dockTransparency = settings.dockTransparency !== undefined ? (settings.dockTransparency > 1 ? settings.dockTransparency / 100 : settings.dockTransparency) : 1
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true
@@ -289,24 +264,23 @@ Singleton {
clockDateFormat = settings.clockDateFormat !== undefined ? settings.clockDateFormat : ""
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : ""
mediaSize = settings.mediaSize !== undefined ? settings.mediaSize : (settings.mediaCompactMode !== undefined ? (settings.mediaCompactMode ? 0 : 1) : 1)
if (settings.dankBarWidgetOrder || settings.topBarWidgetOrder) {
var widgetOrder = settings.dankBarWidgetOrder || settings.topBarWidgetOrder
dankBarLeftWidgets = widgetOrder.filter(w => {
if (settings.topBarWidgetOrder) {
topBarLeftWidgets = settings.topBarWidgetOrder.filter(w => {
return ["launcherButton", "workspaceSwitcher", "focusedWindow"].includes(w)
})
dankBarCenterWidgets = widgetOrder.filter(w => {
topBarCenterWidgets = settings.topBarWidgetOrder.filter(w => {
return ["clock", "music", "weather"].includes(w)
})
dankBarRightWidgets = widgetOrder.filter(w => {
topBarRightWidgets = settings.topBarWidgetOrder.filter(w => {
return ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].includes(w)
})
} else {
var leftWidgets = settings.dankBarLeftWidgets !== undefined ? settings.dankBarLeftWidgets : (settings.topBarLeftWidgets !== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"])
var centerWidgets = settings.dankBarCenterWidgets !== undefined ? settings.dankBarCenterWidgets : (settings.topBarCenterWidgets !== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"])
var rightWidgets = settings.dankBarRightWidgets !== undefined ? settings.dankBarRightWidgets : (settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"])
dankBarLeftWidgets = leftWidgets
dankBarCenterWidgets = centerWidgets
dankBarRightWidgets = rightWidgets
var leftWidgets = settings.topBarLeftWidgets !== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"]
var centerWidgets = settings.topBarCenterWidgets !== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"]
var rightWidgets = settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
topBarLeftWidgets = leftWidgets
topBarCenterWidgets = centerWidgets
topBarRightWidgets = rightWidgets
updateListModel(leftWidgetsModel, leftWidgets)
updateListModel(centerWidgetsModel, centerWidgets)
updateListModel(rightWidgetsModel, rightWidgets)
@@ -334,32 +308,25 @@ Singleton {
showDock = settings.showDock !== undefined ? settings.showDock : false
dockAutoHide = settings.dockAutoHide !== undefined ? settings.dockAutoHide : false
dockGroupByApp = settings.dockGroupByApp !== undefined ? settings.dockGroupByApp : false
dockPosition = settings.dockPosition !== undefined ? settings.dockPosition : SettingsData.Position.Bottom
dockSpacing = settings.dockSpacing !== undefined ? settings.dockSpacing : 4
dockBottomGap = settings.dockBottomGap !== undefined ? settings.dockBottomGap : 0
cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12
notificationOverlayEnabled = settings.notificationOverlayEnabled !== undefined ? settings.notificationOverlayEnabled : false
dankBarAutoHide = settings.dankBarAutoHide !== undefined ? settings.dankBarAutoHide : (settings.topBarAutoHide !== undefined ? settings.topBarAutoHide : false)
dankBarOpenOnOverview = settings.dankBarOpenOnOverview !== undefined ? settings.dankBarOpenOnOverview : (settings.topBarOpenOnOverview !== undefined ? settings.topBarOpenOnOverview : false)
dankBarVisible = settings.dankBarVisible !== undefined ? settings.dankBarVisible : (settings.topBarVisible !== undefined ? settings.topBarVisible : true)
dockOpenOnOverview = settings.dockOpenOnOverview !== undefined ? settings.dockOpenOnOverview : false
topBarAutoHide = settings.topBarAutoHide !== undefined ? settings.topBarAutoHide : false
topBarOpenOnOverview = settings.topBarOpenOnOverview !== undefined ? settings.topBarOpenOnOverview : false
topBarVisible = settings.topBarVisible !== undefined ? settings.topBarVisible : true
notificationTimeoutLow = settings.notificationTimeoutLow !== undefined ? settings.notificationTimeoutLow : 5000
notificationTimeoutNormal = settings.notificationTimeoutNormal !== undefined ? settings.notificationTimeoutNormal : 5000
notificationTimeoutCritical = settings.notificationTimeoutCritical !== undefined ? settings.notificationTimeoutCritical : 0
notificationPopupPosition = settings.notificationPopupPosition !== undefined ? settings.notificationPopupPosition : SettingsData.Position.Top
dankBarSpacing = settings.dankBarSpacing !== undefined ? settings.dankBarSpacing : (settings.topBarSpacing !== undefined ? settings.topBarSpacing : 4)
dankBarBottomGap = settings.dankBarBottomGap !== undefined ? settings.dankBarBottomGap : (settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0)
dankBarInnerPadding = settings.dankBarInnerPadding !== undefined ? settings.dankBarInnerPadding : (settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 4)
dankBarSquareCorners = settings.dankBarSquareCorners !== undefined ? settings.dankBarSquareCorners : (settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false)
dankBarNoBackground = settings.dankBarNoBackground !== undefined ? settings.dankBarNoBackground : (settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : false)
dankBarGothCornersEnabled = settings.dankBarGothCornersEnabled !== undefined ? settings.dankBarGothCornersEnabled : (settings.topBarGothCornersEnabled !== undefined ? settings.topBarGothCornersEnabled : false)
dankBarPosition = settings.dankBarPosition !== undefined ? settings.dankBarPosition : (settings.dankBarAtBottom !== undefined ? (settings.dankBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : (settings.topBarAtBottom !== undefined ? (settings.topBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : SettingsData.Position.Top))
topBarSpacing = settings.topBarSpacing !== undefined ? settings.topBarSpacing : 4
topBarBottomGap = settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0
topBarInnerPadding = settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 8
topBarSquareCorners = settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false
topBarNoBackground = settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : false
topBarGothCornersEnabled = settings.topBarGothCornersEnabled !== undefined ? settings.topBarGothCornersEnabled : false
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
hideBrightnessSlider = settings.hideBrightnessSlider !== undefined ? settings.hideBrightnessSlider : false
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : SettingsData.AnimationSpeed.Short
applyStoredTheme()
detectAvailableIconThemes()
detectQtTools()
@@ -382,8 +349,8 @@ Singleton {
"currentThemeName": currentThemeName,
"customThemeFile": customThemeFile,
"matugenScheme": matugenScheme,
"dankBarTransparency": dankBarTransparency,
"dankBarWidgetTransparency": dankBarWidgetTransparency,
"topBarTransparency": topBarTransparency,
"topBarWidgetTransparency": topBarWidgetTransparency,
"popupTransparency": popupTransparency,
"dockTransparency": dockTransparency,
"use24HourClock": use24HourClock,
@@ -428,9 +395,9 @@ Singleton {
"clockDateFormat": clockDateFormat,
"lockDateFormat": lockDateFormat,
"mediaSize": mediaSize,
"dankBarLeftWidgets": dankBarLeftWidgets,
"dankBarCenterWidgets": dankBarCenterWidgets,
"dankBarRightWidgets": dankBarRightWidgets,
"topBarLeftWidgets": topBarLeftWidgets,
"topBarCenterWidgets": topBarCenterWidgets,
"topBarRightWidgets": topBarRightWidgets,
"appLauncherViewMode": appLauncherViewMode,
"spotlightModalViewMode": spotlightModalViewMode,
"networkPreference": networkPreference,
@@ -454,22 +421,17 @@ Singleton {
"showDock": showDock,
"dockAutoHide": dockAutoHide,
"dockGroupByApp": dockGroupByApp,
"dockOpenOnOverview": dockOpenOnOverview,
"dockPosition": dockPosition,
"dockSpacing": dockSpacing,
"dockBottomGap": dockBottomGap,
"cornerRadius": cornerRadius,
"notificationOverlayEnabled": notificationOverlayEnabled,
"dankBarAutoHide": dankBarAutoHide,
"dankBarOpenOnOverview": dankBarOpenOnOverview,
"dankBarVisible": dankBarVisible,
"dankBarSpacing": dankBarSpacing,
"dankBarBottomGap": dankBarBottomGap,
"dankBarInnerPadding": dankBarInnerPadding,
"dankBarSquareCorners": dankBarSquareCorners,
"dankBarNoBackground": dankBarNoBackground,
"dankBarGothCornersEnabled": dankBarGothCornersEnabled,
"dankBarPosition": dankBarPosition,
"topBarAutoHide": topBarAutoHide,
"topBarOpenOnOverview": topBarOpenOnOverview,
"topBarVisible": topBarVisible,
"topBarSpacing": topBarSpacing,
"topBarBottomGap": topBarBottomGap,
"topBarInnerPadding": topBarInnerPadding,
"topBarSquareCorners": topBarSquareCorners,
"topBarNoBackground": topBarNoBackground,
"topBarGothCornersEnabled": topBarGothCornersEnabled,
"lockScreenShowPowerActions": lockScreenShowPowerActions,
"hideBrightnessSlider": hideBrightnessSlider,
"widgetBackgroundColor": widgetBackgroundColor,
@@ -477,9 +439,7 @@ Singleton {
"notificationTimeoutLow": notificationTimeoutLow,
"notificationTimeoutNormal": notificationTimeoutNormal,
"notificationTimeoutCritical": notificationTimeoutCritical,
"notificationPopupPosition": notificationPopupPosition,
"screenPreferences": screenPreferences,
"animationSpeed": animationSpeed
"screenPreferences": screenPreferences
}, null, 2))
}
@@ -595,11 +555,11 @@ Singleton {
function applyStoredTheme() {
if (typeof Theme !== "undefined")
Theme.switchTheme(currentThemeName, false, false)
Theme.switchTheme(currentThemeName, false)
else
Qt.callLater(() => {
if (typeof Theme !== "undefined")
Theme.switchTheme(currentThemeName, false, false)
Theme.switchTheme(currentThemeName, false)
})
}
@@ -626,13 +586,13 @@ Singleton {
}
}
function setDankBarTransparency(transparency) {
dankBarTransparency = transparency
function setTopBarTransparency(transparency) {
topBarTransparency = transparency
saveSettings()
}
function setDankBarWidgetTransparency(transparency) {
dankBarWidgetTransparency = transparency
function setTopBarWidgetTransparency(transparency) {
topBarWidgetTransparency = transparency
saveSettings()
}
@@ -767,25 +727,25 @@ Singleton {
saveSettings()
}
function setDankBarWidgetOrder(order) {
dankBarWidgetOrder = order
function setTopBarWidgetOrder(order) {
topBarWidgetOrder = order
saveSettings()
}
function setDankBarLeftWidgets(order) {
dankBarLeftWidgets = order
function setTopBarLeftWidgets(order) {
topBarLeftWidgets = order
updateListModel(leftWidgetsModel, order)
saveSettings()
}
function setDankBarCenterWidgets(order) {
dankBarCenterWidgets = order
function setTopBarCenterWidgets(order) {
topBarCenterWidgets = order
updateListModel(centerWidgetsModel, order)
saveSettings()
}
function setDankBarRightWidgets(order) {
dankBarRightWidgets = order
function setTopBarRightWidgets(order) {
topBarRightWidgets = order
updateListModel(rightWidgetsModel, order)
saveSettings()
}
@@ -818,13 +778,13 @@ Singleton {
widgetDataChanged()
}
function resetDankBarWidgetsToDefault() {
function resetTopBarWidgetsToDefault() {
var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"]
var defaultCenter = ["music", "clock", "weather"]
var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"]
dankBarLeftWidgets = defaultLeft
dankBarCenterWidgets = defaultCenter
dankBarRightWidgets = defaultRight
topBarLeftWidgets = defaultLeft
topBarCenterWidgets = defaultCenter
topBarRightWidgets = defaultRight
updateListModel(leftWidgetsModel, defaultLeft)
updateListModel(centerWidgetsModel, defaultCenter)
updateListModel(rightWidgetsModel, defaultRight)
@@ -991,14 +951,6 @@ Singleton {
function setShowDock(enabled) {
showDock = enabled
if (enabled && dankBarPosition === SettingsData.Position.Top) {
setDockPosition(SettingsData.Position.Bottom)
return
}
if (enabled && dankBarPosition === SettingsData.Position.Top) {
setDockPosition(SettingsData.Position.Bottom)
return
}
saveSettings()
}
@@ -1012,11 +964,6 @@ Singleton {
saveSettings()
}
function setdockOpenOnOverview(enabled) {
dockOpenOnOverview = enabled
saveSettings()
}
function setCornerRadius(radius) {
cornerRadius = radius
saveSettings()
@@ -1027,23 +974,23 @@ Singleton {
saveSettings()
}
function setDankBarAutoHide(enabled) {
dankBarAutoHide = enabled
function setTopBarAutoHide(enabled) {
topBarAutoHide = enabled
saveSettings()
}
function setDankBarOpenOnOverview(enabled) {
dankBarOpenOnOverview = enabled
function setTopBarOpenOnOverview(enabled) {
topBarOpenOnOverview = enabled
saveSettings()
}
function setDankBarVisible(visible) {
dankBarVisible = visible
function setTopBarVisible(visible) {
topBarVisible = visible
saveSettings()
}
function toggleDankBarVisible() {
dankBarVisible = !dankBarVisible
function toggleTopBarVisible() {
topBarVisible = !topBarVisible
saveSettings()
}
@@ -1062,148 +1009,36 @@ Singleton {
saveSettings()
}
function setNotificationPopupPosition(position) {
notificationPopupPosition = position
function setTopBarSpacing(spacing) {
topBarSpacing = spacing
saveSettings()
}
function sendTestNotifications() {
sendTestNotification(0)
testNotifTimer1.start()
testNotifTimer2.start()
}
function sendTestNotification(index) {
const notifications = [
["Notification Position Test", "DMS test notification 1 of 3 ~ Hi there!", "dialog-information"],
["Second Test", "DMS Notification 2 of 3 ~ Check it out!", "emblem-default"],
["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "emblem-favorite"]
]
if (index < 0 || index >= notifications.length) {
return
}
const notif = notifications[index]
testNotificationProcess.command = ["notify-send", "-h", "int:transient:1", "-a", "DMS", "-i", notif[2], notif[0], notif[1]]
testNotificationProcess.running = true
}
property Process testNotificationProcess
testNotificationProcess: Process {
command: []
running: false
}
property Timer testNotifTimer1
testNotifTimer1: Timer {
interval: 400
repeat: false
onTriggered: sendTestNotification(1)
}
property Timer testNotifTimer2
testNotifTimer2: Timer {
interval: 800
repeat: false
onTriggered: sendTestNotification(2)
}
function setDankBarSpacing(spacing) {
dankBarSpacing = spacing
function setTopBarBottomGap(gap) {
topBarBottomGap = gap
saveSettings()
}
function setDankBarBottomGap(gap) {
dankBarBottomGap = gap
function setTopBarInnerPadding(padding) {
topBarInnerPadding = padding
saveSettings()
}
function setDankBarInnerPadding(padding) {
dankBarInnerPadding = padding
function setTopBarSquareCorners(enabled) {
topBarSquareCorners = enabled
saveSettings()
}
function setDankBarSquareCorners(enabled) {
dankBarSquareCorners = enabled
function setTopBarNoBackground(enabled) {
topBarNoBackground = enabled
saveSettings()
}
function setDankBarNoBackground(enabled) {
dankBarNoBackground = enabled
function setTopBarGothCornersEnabled(enabled) {
topBarGothCornersEnabled = enabled
saveSettings()
}
function setDankBarGothCornersEnabled(enabled) {
dankBarGothCornersEnabled = enabled
saveSettings()
}
function setDankBarPosition(position) {
dankBarPosition = position
if (position === SettingsData.Position.Bottom && showDock) {
setDockPosition(SettingsData.Position.Top)
return
}
if (position === SettingsData.Position.Top && showDock) {
setDockPosition(SettingsData.Position.Bottom)
return
}
saveSettings()
}
function setDockPosition(position) {
dockPosition = position
if (position === SettingsData.Position.Bottom && dankBarPosition === SettingsData.Position.Bottom && showDock) {
setDankBarPosition(SettingsData.Position.Top)
}
if (position === SettingsData.Position.Top && dankBarPosition === SettingsData.Position.Top && showDock) {
setDankBarPosition(SettingsData.Position.Bottom)
}
saveSettings()
Qt.callLater(() => forceDockLayoutRefresh())
}
function setDockSpacing(spacing) {
dockSpacing = spacing
saveSettings()
}
function setDockBottomGap(gap) {
dockBottomGap = gap
saveSettings()
}
function setDockOpenOnOverview(enabled) {
dockOpenOnOverview = enabled
saveSettings()
}
function getPopupYPosition(barHeight) {
const gothOffset = dankBarGothCornersEnabled ? Theme.cornerRadius : 0
return barHeight + dankBarSpacing + dankBarBottomGap - gothOffset + Theme.popupDistance
}
function getPopupTriggerPosition(globalPos, screen, barThickness, widgetWidth) {
const screenX = screen ? screen.x : 0
const screenY = screen ? screen.y : 0
const relativeX = globalPos.x - screenX
const relativeY = globalPos.y - screenY
if (dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right) {
return {
x: relativeY,
y: barThickness + dankBarSpacing + Theme.popupDistance,
width: widgetWidth
}
}
return {
x: relativeX,
y: barThickness + dankBarSpacing + dankBarBottomGap + Theme.popupDistance,
width: widgetWidth
}
}
function setLockScreenShowPowerActions(enabled) {
lockScreenShowPowerActions = enabled
saveSettings()
@@ -1240,11 +1075,6 @@ Singleton {
return Quickshell.screens.filter(screen => prefs.includes(screen.name))
}
function setAnimationSpeed(speed) {
animationSpeed = speed
saveSettings()
}
function _shq(s) {
return "'" + String(s).replace(/'/g, "'\\''") + "'"
}
@@ -1391,22 +1221,22 @@ Singleton {
IpcHandler {
function reveal(): string {
root.setDankBarVisible(true)
root.setTopBarVisible(true)
return "BAR_SHOW_SUCCESS"
}
function hide(): string {
root.setDankBarVisible(false)
root.setTopBarVisible(false)
return "BAR_HIDE_SUCCESS"
}
function toggle(): string {
root.toggleDankBarVisible()
return root.dankBarVisible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"
root.toggleTopBarVisible()
return topBarVisible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"
}
function status(): string {
return root.dankBarVisible ? "visible" : "hidden"
return topBarVisible ? "visible" : "hidden"
}
target: "bar"

View File

@@ -2,101 +2,101 @@
// Separated from Theme.qml to keep that file clean
const CatppuccinMocha = {
surface: "#313244",
surface: "#45475a",
surfaceText: "#cdd6f4",
surfaceVariant: "#313244",
surfaceVariant: "#45475a",
surfaceVariantText: "#a6adc8",
background: "#1e1e2e",
backgroundText: "#cdd6f4",
outline: "#6c7086",
surfaceContainer: "#45475a",
surfaceContainer: "#313244",
surfaceContainerHigh: "#585b70",
surfaceContainerHighest: "#6c7086"
surfaceContainerHighest: "#7f849c"
}
const CatppuccinLatte = {
surface: "#e6e9ef",
surface: "#bcc0cc",
surfaceText: "#4c4f69",
surfaceVariant: "#e6e9ef",
surfaceVariant: "#bcc0cc",
surfaceVariantText: "#6c6f85",
background: "#eff1f5",
backgroundText: "#4c4f69",
outline: "#9ca0b0",
surfaceContainer: "#dce0e8",
surfaceContainerHigh: "#ccd0da",
surfaceContainerHighest: "#bcc0cc"
surfaceContainer: "#ccd0da",
surfaceContainerHigh: "#acb0be",
surfaceContainerHighest: "#8c8fa1"
}
const CatppuccinVariants = {
"cat-rosewater": {
name: "Rosewater",
dark: { primary: "#f5e0dc", secondary: "#f2cdcd", primaryText: "#1e1e2e", primaryContainer: "#7d5d56", surfaceTint: "#f5e0dc" },
light: { primary: "#dc8a78", secondary: "#dd7878", primaryText: "#ffffff", primaryContainer: "#f6e7e3", surfaceTint: "#dc8a78" }
dark: { primary: "#f5e0dc", secondary: "#f2cdcd", primaryText: "#1e1e2e", primaryContainer: "#8b6b5e", surfaceTint: "#f5e0dc" },
light: { primary: "#dc8a78", secondary: "#dd7878", primaryText: "#ffffff", primaryContainer: "#f4d2ca", surfaceTint: "#dc8a78" }
},
"cat-flamingo": {
name: "Flamingo",
dark: { primary: "#f2cdcd", secondary: "#f5e0dc", primaryText: "#1e1e2e", primaryContainer: "#7a555a", surfaceTint: "#f2cdcd" },
light: { primary: "#dd7878", secondary: "#dc8a78", primaryText: "#ffffff", primaryContainer: "#f6e5e5", surfaceTint: "#dd7878" }
dark: { primary: "#f2cdcd", secondary: "#f5e0dc", primaryText: "#1e1e2e", primaryContainer: "#885d62", surfaceTint: "#f2cdcd" },
light: { primary: "#dd7878", secondary: "#dc8a78", primaryText: "#ffffff", primaryContainer: "#f4caca", surfaceTint: "#dd7878" }
},
"cat-pink": {
name: "Pink",
dark: { primary: "#f5c2e7", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#7a3f69", surfaceTint: "#f5c2e7" },
light: { primary: "#ea76cb", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#f7d7ee", surfaceTint: "#ea76cb" }
dark: { primary: "#f5c2e7", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#8b537a", surfaceTint: "#f5c2e7" },
light: { primary: "#ea76cb", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#f7c9e7", surfaceTint: "#ea76cb" }
},
"cat-mauve": {
name: "Mauve",
dark: { primary: "#cba6f7", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#55307f", surfaceTint: "#cba6f7" },
light: { primary: "#8839ef", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#eadcff", surfaceTint: "#8839ef" }
dark: { primary: "#cba6f7", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#61378a", surfaceTint: "#cba6f7" },
light: { primary: "#8839ef", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#e4d3ff", surfaceTint: "#8839ef" }
},
"cat-red": {
name: "Red",
dark: { primary: "#f38ba8", secondary: "#eba0ac", primaryText: "#1e1e2e", primaryContainer: "#6f2438", surfaceTint: "#f38ba8" },
light: { primary: "#d20f39", secondary: "#e64553", primaryText: "#ffffff", primaryContainer: "#f6d0d6", surfaceTint: "#d20f39" }
dark: { primary: "#f38ba8", secondary: "#eba0ac", primaryText: "#1e1e2e", primaryContainer: "#891c3b", surfaceTint: "#f38ba8" },
light: { primary: "#d20f39", secondary: "#e64553", primaryText: "#ffffff", primaryContainer: "#f1b8c4", surfaceTint: "#d20f39" }
},
"cat-maroon": {
name: "Maroon",
dark: { primary: "#eba0ac", secondary: "#f38ba8", primaryText: "#1e1e2e", primaryContainer: "#6d3641", surfaceTint: "#eba0ac" },
light: { primary: "#e64553", secondary: "#d20f39", primaryText: "#ffffff", primaryContainer: "#f7d8dc", surfaceTint: "#e64553" }
dark: { primary: "#eba0ac", secondary: "#f38ba8", primaryText: "#1e1e2e", primaryContainer: "#81313f", surfaceTint: "#eba0ac" },
light: { primary: "#e64553", secondary: "#d20f39", primaryText: "#ffffff", primaryContainer: "#f4c3c8", surfaceTint: "#e64553" }
},
"cat-peach": {
name: "Peach",
dark: { primary: "#fab387", secondary: "#f9e2af", primaryText: "#1e1e2e", primaryContainer: "#734226", surfaceTint: "#fab387" },
light: { primary: "#fe640b", secondary: "#df8e1d", primaryText: "#ffffff", primaryContainer: "#ffe4d5", surfaceTint: "#fe640b" }
dark: { primary: "#fab387", secondary: "#f9e2af", primaryText: "#1e1e2e", primaryContainer: "#90441a", surfaceTint: "#fab387" },
light: { primary: "#fe640b", secondary: "#df8e1d", primaryText: "#ffffff", primaryContainer: "#ffddcc", surfaceTint: "#fe640b" }
},
"cat-yellow": {
name: "Yellow",
dark: { primary: "#f9e2af", secondary: "#a6e3a1", primaryText: "#1e1e2e", primaryContainer: "#6e5a2f", surfaceTint: "#f9e2af" },
light: { primary: "#df8e1d", secondary: "#40a02b", primaryText: "#ffffff", primaryContainer: "#fff6d6", surfaceTint: "#df8e1d" }
dark: { primary: "#f9e2af", secondary: "#a6e3a1", primaryText: "#1e1e2e", primaryContainer: "#8f7342", surfaceTint: "#f9e2af" },
light: { primary: "#df8e1d", secondary: "#40a02b", primaryText: "#ffffff", primaryContainer: "#fff3cc", surfaceTint: "#df8e1d" }
},
"cat-green": {
name: "Green",
dark: { primary: "#a6e3a1", secondary: "#94e2d5", primaryText: "#1e1e2e", primaryContainer: "#2f5f36", surfaceTint: "#a6e3a1" },
light: { primary: "#40a02b", secondary: "#179299", primaryText: "#ffffff", primaryContainer: "#dff4e0", surfaceTint: "#40a02b" }
dark: { primary: "#a6e3a1", secondary: "#94e2d5", primaryText: "#1e1e2e", primaryContainer: "#3c7534", surfaceTint: "#a6e3a1" },
light: { primary: "#40a02b", secondary: "#179299", primaryText: "#ffffff", primaryContainer: "#d4f5d4", surfaceTint: "#40a02b" }
},
"cat-teal": {
name: "Teal",
dark: { primary: "#94e2d5", secondary: "#89dceb", primaryText: "#1e1e2e", primaryContainer: "#2e5e59", surfaceTint: "#94e2d5" },
light: { primary: "#179299", secondary: "#04a5e5", primaryText: "#ffffff", primaryContainer: "#daf3f1", surfaceTint: "#179299" }
dark: { primary: "#94e2d5", secondary: "#89dceb", primaryText: "#1e1e2e", primaryContainer: "#2a7468", surfaceTint: "#94e2d5" },
light: { primary: "#179299", secondary: "#04a5e5", primaryText: "#ffffff", primaryContainer: "#ccf2f2", surfaceTint: "#179299" }
},
"cat-sky": {
name: "Sky",
dark: { primary: "#89dceb", secondary: "#74c7ec", primaryText: "#1e1e2e", primaryContainer: "#24586a", surfaceTint: "#89dceb" },
light: { primary: "#04a5e5", secondary: "#209fb5", primaryText: "#ffffff", primaryContainer: "#dbf1fb", surfaceTint: "#04a5e5" }
dark: { primary: "#89dceb", secondary: "#74c7ec", primaryText: "#1e1e2e", primaryContainer: "#196e7e", surfaceTint: "#89dceb" },
light: { primary: "#04a5e5", secondary: "#209fb5", primaryText: "#ffffff", primaryContainer: "#ccebff", surfaceTint: "#04a5e5" }
},
"cat-sapphire": {
name: "Sapphire",
dark: { primary: "#74c7ec", secondary: "#89b4fa", primaryText: "#1e1e2e", primaryContainer: "#1f4d6f", surfaceTint: "#74c7ec" },
light: { primary: "#209fb5", secondary: "#1e66f5", primaryText: "#ffffff", primaryContainer: "#def3f8", surfaceTint: "#209fb5" }
dark: { primary: "#74c7ec", secondary: "#89b4fa", primaryText: "#1e1e2e", primaryContainer: "#0a597f", surfaceTint: "#74c7ec" },
light: { primary: "#209fb5", secondary: "#1e66f5", primaryText: "#ffffff", primaryContainer: "#d0f0f5", surfaceTint: "#209fb5" }
},
"cat-blue": {
name: "Blue",
dark: { primary: "#89b4fa", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#243f75", surfaceTint: "#89b4fa" },
light: { primary: "#1e66f5", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#e0e9ff", surfaceTint: "#1e66f5" }
dark: { primary: "#89b4fa", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#19468d", surfaceTint: "#89b4fa" },
light: { primary: "#1e66f5", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#ccd9ff", surfaceTint: "#1e66f5" }
},
"cat-lavender": {
name: "Lavender",
dark: { primary: "#b4befe", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#3f4481", surfaceTint: "#b4befe" },
light: { primary: "#7287fd", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#e5e8ff", surfaceTint: "#7287fd" }
dark: { primary: "#b4befe", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#4a5091", surfaceTint: "#b4befe" },
light: { primary: "#7287fd", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#dde1ff", surfaceTint: "#7287fd" }
}
}
@@ -290,9 +290,9 @@ const StockThemes = {
background: "#131315",
backgroundText: "#e4e2e3",
outline: "#929092",
surfaceContainer: "#353535",
surfaceContainerHigh: "#424242",
surfaceContainerHighest: "#505050",
surfaceContainer: "#2a2a2a",
surfaceContainerHigh: "#2a2a2b",
surfaceContainerHighest: "#353535",
error: "#ffb4ab",
warning: "#3f4759",
info: "#595e6c",
@@ -476,9 +476,8 @@ const StockThemes = {
background: "#ffffff",
backgroundText: "#1a1a1a",
outline: "#757577",
surfaceContainer: "#e8e8ea",
surfaceContainerHigh: "#dcdcde",
surfaceContainerHighest: "#d0d0d2",
surfaceContainer: "#f5f5f6",
surfaceContainerHigh: "#eaeaeb",
error: "#ba1a1a",
warning: "#f9e79f",
info: "#5d6475",

View File

@@ -16,12 +16,11 @@ Singleton {
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
// ! TODO - Synchronize with niri/hyprland gaps?
readonly property real popupDistance: 2
readonly property real popupDistance: 4
property string currentTheme: "blue"
property string currentThemeCategory: "generic"
property bool isLightMode: typeof SessionData !== "undefined" ? SessionData.isLightMode : false
property bool isLightMode: false
readonly property string dynamic: "dynamic"
readonly property string custom : "custom"
@@ -83,13 +82,11 @@ Singleton {
Component.onCompleted: {
Quickshell.execDetached(["mkdir", "-p", stateDir])
matugenCheck.running = true
if (typeof SessionData !== "undefined") {
if (typeof SessionData !== "undefined")
SessionData.isLightModeChanged.connect(root.onLightModeChanged)
isLightMode = SessionData.isLightMode
}
if (typeof SettingsData !== "undefined" && SettingsData.currentThemeName) {
switchTheme(SettingsData.currentThemeName, false, false)
switchTheme(SettingsData.currentThemeName, false)
}
}
@@ -235,22 +232,11 @@ Singleton {
property color shadowMedium: Qt.rgba(0, 0, 0, 0.08)
property color shadowStrong: Qt.rgba(0, 0, 0, 0.3)
readonly property var animationDurations: [
{ shorter: 0, short: 0, medium: 0, long: 0, extraLong: 0 },
{ shorter: 50, short: 75, medium: 150, long: 250, extraLong: 500 },
{ shorter: 100, short: 150, medium: 300, long: 500, extraLong: 1000 },
{ shorter: 150, short: 225, medium: 450, long: 750, extraLong: 1500 },
{ shorter: 200, short: 300, medium: 600, long: 1000, extraLong: 2000 }
]
readonly property int currentAnimationSpeed: typeof SettingsData !== "undefined" ? SettingsData.animationSpeed : SettingsData.AnimationSpeed.Short
readonly property var currentDurations: animationDurations[currentAnimationSpeed] || animationDurations[SettingsData.AnimationSpeed.Short]
property int shorterDuration: currentDurations.shorter
property int shortDuration: currentDurations.short
property int mediumDuration: currentDurations.medium
property int longDuration: currentDurations.long
property int extraLongDuration: currentDurations.extraLong
property int shorterDuration: 100
property int shortDuration: 150
property int mediumDuration: 300
property int longDuration: 500
property int extraLongDuration: 1000
property int standardEasing: Easing.OutCubic
property int emphasizedEasing: Easing.OutQuart
@@ -270,8 +256,8 @@ Singleton {
property real iconSizeLarge: 32
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 widgetTransparency: typeof SettingsData !== "undefined" && SettingsData.topBarWidgetTransparency !== undefined ? SettingsData.topBarWidgetTransparency : 0.85
property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 0.92
function screenTransition() {
CompositorService.isNiri && NiriService.doScreenTransition()
@@ -280,12 +266,7 @@ Singleton {
function switchTheme(themeName, savePrefs = true, enableTransition = true) {
if (enableTransition) {
screenTransition()
themeTransitionTimer.themeName = themeName
themeTransitionTimer.savePrefs = savePrefs
themeTransitionTimer.restart()
return
}
if (themeName === dynamic) {
currentTheme = dynamic
currentThemeCategory = dynamic
@@ -297,6 +278,7 @@ Singleton {
}
} else {
currentTheme = themeName
// Determine category based on theme name
if (StockThemes.isCatppuccinVariant(themeName)) {
currentThemeCategory = "catppuccin"
} else {
@@ -309,15 +291,8 @@ Singleton {
generateSystemThemesFromCurrentTheme()
}
function setLightMode(light, savePrefs = true, enableTransition = false) {
if (enableTransition) {
screenTransition()
lightModeTransitionTimer.lightMode = light
lightModeTransitionTimer.savePrefs = savePrefs
lightModeTransitionTimer.restart()
return
}
function setLightMode(light, savePrefs = true) {
screenTransition()
isLightMode = light
if (savePrefs && typeof SessionData !== "undefined")
SessionData.setLightMode(isLightMode)
@@ -326,10 +301,11 @@ Singleton {
}
function toggleLightMode(savePrefs = true) {
setLightMode(!isLightMode, savePrefs, true)
setLightMode(!isLightMode, savePrefs)
}
function forceGenerateSystemThemes() {
screenTransition()
if (!matugenAvailable) {
return
}
@@ -353,10 +329,8 @@ Singleton {
}
function switchThemeCategory(category, defaultTheme) {
screenTransition()
themeCategoryTransitionTimer.category = category
themeCategoryTransitionTimer.defaultTheme = defaultTheme
themeCategoryTransitionTimer.restart()
currentThemeCategory = category
switchTheme(defaultTheme, true, false)
}
function getCatppuccinColor(variantName) {
@@ -380,6 +354,7 @@ Singleton {
}
function loadCustomTheme(themeData) {
screenTransition()
if (themeData.dark || themeData.light) {
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"
const selectedTheme = themeData[colorMode] || themeData.dark || themeData.light
@@ -663,7 +638,6 @@ Singleton {
qtApplier.running = true
}
function withAlpha(c, a) { return Qt.rgba(c.r, c.g, c.b, a); }
Process {
id: matugenCheck
@@ -863,12 +837,12 @@ Singleton {
}
function light(): string {
root.setLightMode(true, true, true)
root.setLightMode(true)
return "light"
}
function dark(): string {
root.setLightMode(false, true, true)
root.setLightMode(false)
return "dark"
}
@@ -876,35 +850,4 @@ Singleton {
return root.isLightMode ? "light" : "dark"
}
}
// These timers are for screen transitions, since sometimes QML still beats the niri call
Timer {
id: themeTransitionTimer
interval: 50
repeat: false
property string themeName: ""
property bool savePrefs: true
onTriggered: root.switchTheme(themeName, savePrefs, false)
}
Timer {
id: lightModeTransitionTimer
interval: 100
repeat: false
property bool lightMode: false
property bool savePrefs: true
onTriggered: root.setLightMode(lightMode, savePrefs, false)
}
Timer {
id: themeCategoryTransitionTimer
interval: 50
repeat: false
property string category: ""
property string defaultTheme: ""
onTriggered: {
root.currentThemeCategory = category
root.switchTheme(defaultTheme, true, false)
}
}
}

View File

@@ -53,7 +53,7 @@ QtObject {
modal.hide()
event.accepted = true
}
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Tab) {
} else if (event.key === Qt.Key_Down) {
if (!modal.keyboardNavigationActive) {
modal.keyboardNavigationActive = true
modal.selectedIndex = 0
@@ -62,7 +62,7 @@ QtObject {
selectNext()
event.accepted = true
}
} else if (event.key === Qt.Key_Up || event.key === Qt.Key_Backtab) {
} else if (event.key === Qt.Key_Up) {
if (!modal.keyboardNavigationActive) {
modal.keyboardNavigationActive = true
modal.selectedIndex = 0
@@ -74,42 +74,6 @@ QtObject {
selectPrevious()
event.accepted = true
}
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
if (!modal.keyboardNavigationActive) {
modal.keyboardNavigationActive = true
modal.selectedIndex = 0
} else {
selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
if (!modal.keyboardNavigationActive) {
modal.keyboardNavigationActive = true
modal.selectedIndex = 0
} else if (modal.selectedIndex === 0) {
modal.keyboardNavigationActive = false
} else {
selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
if (!modal.keyboardNavigationActive) {
modal.keyboardNavigationActive = true
modal.selectedIndex = 0
} else {
selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
if (!modal.keyboardNavigationActive) {
modal.keyboardNavigationActive = true
modal.selectedIndex = 0
} else if (modal.selectedIndex === 0) {
modal.keyboardNavigationActive = false
} else {
selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_Delete && (event.modifiers & Qt.ShiftModifier)) {
modal.clearAll()
modal.hide()

View File

@@ -93,48 +93,6 @@ DankModal {
selectedButton = 1
event.accepted = true
break
case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) {
keyboardNavigation = true
selectedButton = (selectedButton + 1) % 2
event.accepted = true
}
break
case Qt.Key_P:
if (event.modifiers & Qt.ControlModifier) {
keyboardNavigation = true
selectedButton = selectedButton === -1 ? 1 : (selectedButton - 1 + 2) % 2
event.accepted = true
}
break
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
keyboardNavigation = true
selectedButton = 1
event.accepted = true
}
break
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
keyboardNavigation = true
selectedButton = 0
event.accepted = true
}
break
case Qt.Key_H:
if (event.modifiers & Qt.ControlModifier) {
keyboardNavigation = true
selectedButton = 0
event.accepted = true
}
break
case Qt.Key_L:
if (event.modifiers & Qt.ControlModifier) {
keyboardNavigation = true
selectedButton = 1
event.accepted = true
}
break
case Qt.Key_Tab:
keyboardNavigation = true
selectedButton = selectedButton === -1 ? 0 : (selectedButton + 1) % 2

View File

@@ -22,7 +22,7 @@ PanelWindow {
property bool closeOnEscapeKey: true
property bool closeOnBackgroundClick: true
property string animationType: "scale"
property int animationDuration: Theme.shortDuration
property int animationDuration: Theme.shorterDuration
property var animationEasing: Theme.emphasizedEasing
property color backgroundColor: Theme.surfaceContainer
property color borderColor: Theme.outlineMedium
@@ -34,7 +34,6 @@ PanelWindow {
property bool shouldHaveFocus: shouldBeVisible
property bool allowFocusOverride: false
property bool allowStacking: false
property bool keepContentLoaded: false
signal opened
signal dialogClosed
@@ -91,7 +90,7 @@ PanelWindow {
Timer {
id: closeTimer
interval: animationDuration + 100
interval: animationDuration + 50
onTriggered: {
visible = false
}
@@ -159,6 +158,7 @@ PanelWindow {
border.width: root.borderWidth
layer.enabled: root.enableShadow
opacity: root.shouldBeVisible ? 1 : 0
scale: root.animationType === "scale" ? (root.shouldBeVisible ? 1 : 0.9) : 1
transform: root.animationType === "slide" ? slideTransform : null
Translate {
@@ -172,7 +172,7 @@ PanelWindow {
id: contentLoader
anchors.fill: parent
active: root.keepContentLoaded || root.shouldBeVisible || root.visible
active: root.visible
asynchronous: false
}
@@ -183,6 +183,15 @@ PanelWindow {
}
}
Behavior on scale {
enabled: root.animationType === "scale"
NumberAnimation {
duration: root.animationDuration
easing.type: root.animationEasing
}
}
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
@@ -198,8 +207,8 @@ PanelWindow {
objectName: "modalFocusScope"
anchors.fill: parent
visible: root.shouldBeVisible || root.visible
focus: root.shouldBeVisible
visible: root.visible // Only active when the modal is visible
focus: root.visible
Keys.onEscapePressed: event => {
if (root.closeOnEscapeKey && shouldHaveFocus) {
root.close()
@@ -214,7 +223,7 @@ PanelWindow {
Connections {
function onShouldHaveFocusChanged() {
if (shouldHaveFocus && shouldBeVisible) {
if (shouldHaveFocus && visible) {
Qt.callLater(() => focusScope.forceActiveFocus())
}
}

View File

@@ -239,12 +239,7 @@ DankModal {
return
}
if (!keyboardNavigationActive) {
const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === Qt.Key_Right ||
(event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) ||
(event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) ||
(event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier)
if (isInitKey) {
if (event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === Qt.Key_Right) {
keyboardNavigationActive = true
if (currentPath !== homeDir) {
backButtonFocused = true
@@ -286,69 +281,6 @@ DankModal {
}
event.accepted = true
break
case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) {
backButtonFocused = false
selectedIndex = 0
} else if (selectedIndex < totalItems - 1) {
selectedIndex++
}
event.accepted = true
}
break
case Qt.Key_P:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) {
selectedIndex--
} else if (currentPath !== homeDir) {
backButtonFocused = true
selectedIndex = -1
}
event.accepted = true
}
break
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex < totalItems - 1) {
selectedIndex++
}
event.accepted = true
}
break
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) {
selectedIndex--
} else if (currentPath !== homeDir) {
backButtonFocused = true
selectedIndex = -1
}
event.accepted = true
}
break
case Qt.Key_H:
if (event.modifiers & Qt.ControlModifier) {
if (!backButtonFocused && selectedIndex > 0) {
selectedIndex--
} else if (currentPath !== homeDir) {
backButtonFocused = true
selectedIndex = -1
}
event.accepted = true
}
break
case Qt.Key_L:
if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) {
backButtonFocused = false
selectedIndex = 0
} else if (selectedIndex < totalItems - 1) {
selectedIndex++
}
event.accepted = true
}
break
case Qt.Key_Left:
if (backButtonFocused)
return

View File

@@ -57,11 +57,13 @@ DankModal {
modalFocusScope.Keys.onPressed: (event) => {
switch (event.key) {
case Qt.Key_Up:
case Qt.Key_Backtab:
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
event.accepted = true;
break;
case Qt.Key_Down:
selectedIndex = (selectedIndex + 1) % optionCount;
event.accepted = true;
break;
case Qt.Key_Tab:
selectedIndex = (selectedIndex + 1) % optionCount;
event.accepted = true;
@@ -76,30 +78,6 @@ DankModal {
}
event.accepted = true;
break;
case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex + 1) % optionCount;
event.accepted = true;
}
break;
case Qt.Key_P:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
event.accepted = true;
}
break;
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex + 1) % optionCount;
event.accepted = true;
}
break;
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
event.accepted = true;
}
break;
}
}

View File

@@ -34,28 +34,27 @@ Item {
}
Loader {
id: timeWeatherLoader
id: timeLoader
anchors.fill: parent
active: root.currentIndex === 1
visible: active
asynchronous: true
sourceComponent: TimeWeatherTab {
sourceComponent: TimeTab {
}
}
Loader {
id: keybindsLoader
id: weatherLoader
anchors.fill: parent
active: root.currentIndex === 2
visible: active
asynchronous: true
sourceComponent: KeybindsTab {
parentModal: root.parentModal
sourceComponent: WeatherTab {
}
}
@@ -68,7 +67,7 @@ Item {
visible: active
asynchronous: true
sourceComponent: DankBarTab {
sourceComponent: TopBarTab {
}
}

View File

@@ -12,13 +12,13 @@ Rectangle {
"text": "Personalization",
"icon": "person"
}, {
"text": "Time & Weather",
"text": "Time & Date",
"icon": "schedule"
}, {
"text": "Key Bindings",
"icon": "keyboard"
"text": "Weather",
"icon": "cloud"
}, {
"text": "Dank Bar",
"text": "Top Bar",
"icon": "toolbar"
}, {
"text": "Widgets",
@@ -83,7 +83,7 @@ Rectangle {
width: parent.width - Theme.spacingS * 2
height: 44
radius: Theme.cornerRadius
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.primaryContainer, 0)
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
Row {
anchors.left: parent.left

View File

@@ -33,46 +33,6 @@ Item {
} else if (event.key === Qt.Key_Left && appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
event.accepted = true
} else if (event.key == Qt.Key_J && event.modifiers & Qt.ControlModifier) {
appLauncher.selectNext()
event.accepted = true
} else if (event.key == Qt.Key_K && event.modifiers & Qt.ControlModifier) {
appLauncher.selectPrevious()
event.accepted = true
} else if (event.key == Qt.Key_L && event.modifiers & Qt.ControlModifier && appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
event.accepted = true
} else if (event.key == Qt.Key_H && event.modifiers & Qt.ControlModifier && appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
event.accepted = true
} else if (event.key === Qt.Key_Tab) {
if (appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
} else {
appLauncher.selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_Backtab) {
if (appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
} else {
appLauncher.selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
if (appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
} else {
appLauncher.selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
if (appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
} else {
appLauncher.selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
appLauncher.launchSelected()
event.accepted = true
@@ -164,7 +124,7 @@ Item {
else if (appLauncher.model.count > 0)
appLauncher.launchApp(appLauncher.model.get(0))
event.accepted = true
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
event.accepted = false
}
}

View File

@@ -32,7 +32,11 @@ DankModal {
function hide() {
spotlightOpen = false
close()
cleanupTimer.restart()
if (contentLoader.item && contentLoader.item.appLauncher) {
contentLoader.item.appLauncher.searchQuery = ""
contentLoader.item.appLauncher.selectedIndex = 0
contentLoader.item.appLauncher.setCategory("All")
}
}
function toggle() {
@@ -51,7 +55,6 @@ DankModal {
borderColor: Theme.outlineMedium
borderWidth: 1
enableShadow: true
keepContentLoaded: true
onVisibleChanged: () => {
if (visible && !spotlightOpen) {
show()
@@ -69,19 +72,6 @@ DankModal {
}
content: spotlightContent
Timer {
id: cleanupTimer
interval: animationDuration + 50
onTriggered: {
if (contentLoader.item && contentLoader.item.appLauncher) {
contentLoader.item.appLauncher.searchQuery = ""
contentLoader.item.appLauncher.selectedIndex = 0
contentLoader.item.appLauncher.setCategory("All")
}
}
}
Connections {
function onCloseAllModalsExcept(excludedModal) {
if (excludedModal !== spotlightModal && !allowStacking && spotlightOpen) {

View File

@@ -12,6 +12,7 @@ import qs.Widgets
DankPopout {
id: appDrawerPopout
property string triggerSection: "left"
property var triggerScreen: null
// Setting to Exclusive, so virtual keyboards can send input to app drawer
@@ -32,9 +33,9 @@ DankPopout {
popupWidth: 520
popupHeight: 600
triggerX: Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerY: Math.max(26 + SettingsData.topBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.topBarInnerPadding)) + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance
triggerWidth: 40
positioning: ""
positioning: "center"
screen: triggerScreen
onShouldBeVisibleChanged: {
@@ -127,44 +128,6 @@ DankPopout {
return
}
if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
appLauncher.selectNext()
event.accepted = true
return
}
if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
appLauncher.selectPrevious()
event.accepted = true
return
}
if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
appLauncher.selectNext()
event.accepted = true
return
}
if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
appLauncher.selectPrevious()
event.accepted = true
return
}
if (appLauncher.viewMode === "grid") {
if (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier) {
appLauncher.selectNextInRow()
event.accepted = true
return
}
if (event.key === Qt.Key_H && event.modifiers & Qt.ControlModifier) {
appLauncher.selectPreviousInRow()
event.accepted = true
return
}
}
if (!searchField.activeFocus && event.text && /[a-zA-Z0-9\s]/.test(event.text)) {
searchField.forceActiveFocus()
searchField.insertText(event.text)

View File

@@ -7,7 +7,6 @@ Item {
property string expandedSection: ""
property var expandedWidgetData: null
property var bluetoothCodecSelector: null
Loader {
width: parent.width
@@ -43,17 +42,7 @@ Item {
Component {
id: bluetoothDetailComponent
BluetoothDetail {
id: bluetoothDetail
onShowCodecSelector: function(device) {
if (root.bluetoothCodecSelector) {
root.bluetoothCodecSelector.show(device)
root.bluetoothCodecSelector.codecSelected.connect(function(deviceAddress, codecName) {
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName)
})
}
}
}
BluetoothDetail {}
}
Component {

View File

@@ -13,8 +13,6 @@ Column {
property int expandedWidgetIndex: -1
property var model: null
property var expandedWidgetData: null
property var bluetoothCodecSelector: null
property bool darkModeTransitionPending: false
signal expandClicked(var widgetData, int globalIndex)
signal removeWidget(int index)
@@ -26,7 +24,6 @@ Column {
property var currentRowWidgets: []
property real currentRowWidth: 0
property int expandedRowIndex: -1
property var colorPickerModal: null
function calculateRowsAndWidgets() {
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex)
@@ -133,8 +130,6 @@ Column {
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
} else if (id === "diskUsage") {
return diskUsagePillComponent
} else if (id === "colorPicker") {
return colorPickerPillComponent
} else {
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
}
@@ -163,7 +158,6 @@ Column {
visible: active
expandedSection: root.expandedSection
expandedWidgetData: root.expandedWidgetData
bluetoothCodecSelector: root.bluetoothCodecSelector
}
}
}
@@ -536,13 +530,7 @@ Column {
}
}
iconRotation: {
if (widgetData.id !== "darkMode") return 0
if (darkModeTransitionPending) {
return SessionData.isLightMode ? 0 : 180
}
return SessionData.isLightMode ? 180 : 0
}
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
isActive: {
switch (widgetData.id || "") {
@@ -561,14 +549,6 @@ Column {
enabled: !root.editMode
onIconRotationCompleted: {
if (root.darkModeTransitionPending && widgetData.id === "darkMode") {
root.darkModeTransitionPending = false
Theme.screenTransition()
Theme.toggleLightMode()
}
}
onClicked: {
if (root.editMode)
return
@@ -581,7 +561,7 @@ enabled: !root.editMode
}
case "darkMode":
{
root.darkModeTransitionPending = true
Theme.toggleLightMode()
break
}
case "doNotDisturb":
@@ -622,13 +602,7 @@ enabled: !root.editMode
}
}
iconRotation: {
if (widgetData.id !== "darkMode") return 0
if (darkModeTransitionPending) {
return SessionData.isLightMode ? 0 : 180
}
return SessionData.isLightMode ? 180 : 0
}
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
isActive: {
switch (widgetData.id || "") {
@@ -647,14 +621,6 @@ enabled: !root.editMode
enabled: !root.editMode
onIconRotationCompleted: {
if (root.darkModeTransitionPending && widgetData.id === "darkMode") {
root.darkModeTransitionPending = false
Theme.screenTransition()
Theme.toggleLightMode()
}
}
onClicked: {
if (root.editMode)
return
@@ -667,7 +633,7 @@ enabled: !root.editMode
}
case "darkMode":
{
root.darkModeTransitionPending = true
Theme.toggleLightMode()
break
}
case "doNotDisturb":
@@ -703,16 +669,4 @@ enabled: !root.editMode
}
}
}
Component {
id: colorPickerPillComponent
ColorPickerPill {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
width: parent.width
height: 60
colorPickerModal: root.colorPickerModal
}
}
}

View File

@@ -231,7 +231,7 @@ Item {
}
}
SizeControls {
PieChartSizeControl {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: -6

View File

@@ -10,7 +10,7 @@ import qs.Common
import qs.Modules.ControlCenter
import qs.Modules.ControlCenter.Widgets
import qs.Modules.ControlCenter.Details
import qs.Modules.DankBar
import qs.Modules.TopBar
import qs.Services
import qs.Widgets
import qs.Modules.ControlCenter.Components
@@ -22,6 +22,7 @@ DankPopout {
property string expandedSection: ""
property bool powerOptionsExpanded: false
property string triggerSection: "right"
property var triggerScreen: null
property bool editMode: false
property int expandedWidgetIndex: -1
@@ -65,9 +66,9 @@ DankPopout {
popupWidth: 550
popupHeight: Math.min((triggerScreen?.height ?? 1080) - 100, contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400)
triggerX: (triggerScreen?.width ?? 1920) - 600 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.popupDistance
triggerWidth: 80
positioning: ""
positioning: "center"
screen: triggerScreen
shouldBeVisible: false
visible: shouldBeVisible
@@ -101,7 +102,7 @@ DankPopout {
property alias bluetoothCodecSelector: bluetoothCodecSelector
color: {
const transparency = Theme.popupTransparency
const transparency = Theme.popupTransparency || 0.92
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
}
@@ -152,8 +153,6 @@ DankPopout {
expandedWidgetIndex: root.expandedWidgetIndex
expandedWidgetData: root.expandedWidgetData
model: widgetModel
bluetoothCodecSelector: bluetoothCodecSelector
colorPickerModal: root.colorPickerModal
onExpandClicked: (widgetData, globalIndex) => {
root.expandedWidgetIndex = globalIndex
root.expandedWidgetData = widgetData
@@ -223,6 +222,4 @@ DankPopout {
id: batteryDetailComponent
BatteryDetail {}
}
property var colorPickerModal: null
}

View File

@@ -116,14 +116,6 @@ QtObject {
"enabled": DgopService.dgopAvailable,
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined,
"allowMultiple": true
},
{
"id": "colorPicker",
"text": "Color Picker",
"description": "Choose colors from palette",
"icon": "palette",
"type": "action",
"enabled": true
}
]

View File

@@ -20,7 +20,11 @@ Row {
height: Theme.iconSize + Theme.spacingS * 2
anchors.verticalCenter: parent.verticalCenter
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
MouseArea {
id: iconArea
@@ -30,9 +34,7 @@ Row {
cursorShape: Qt.PointingHandCursor
onClicked: {
if (defaultSink) {
AudioService.suppressOSD = true
defaultSink.audio.muted = !defaultSink.audio.muted
AudioService.suppressOSD = false
}
}
}
@@ -69,9 +71,6 @@ Row {
valueOverride: actualVolumePercent
thumbOutlineColor: Theme.surfaceContainer
trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.surfaceContainerHigh
onIsDraggingChanged: {
AudioService.suppressOSD = isDragging
}
onSliderValueChanged: function(newValue) {
if (defaultSink) {
defaultSink.audio.volume = newValue / 100.0

View File

@@ -18,13 +18,17 @@ Row {
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
color: iconArea.containsMouse
? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
: Theme.withAlpha(Theme.primary, 0)
: "transparent"
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
MouseArea {
id: iconArea
anchors.fill: parent
hoverEnabled: true
cursorShape: DisplayService.devices.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
cursorShape: Qt.PointingHandCursor
onClicked: function(event) {
if (DisplayService.devices.length > 1) {
@@ -37,22 +41,6 @@ Row {
}
}
onEntered: {
tooltipLoader.active = true
if (tooltipLoader.item) {
const tooltipText = DisplayService.currentDevice ? "bl device: " + DisplayService.currentDevice : "Backlight Control"
const p = iconArea.mapToItem(null, iconArea.width / 2, 0)
tooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide()
}
tooltipLoader.active = false
}
DankIcon {
anchors.centerIn: parent
name: {
@@ -153,10 +141,4 @@ Row {
onObjectRemoved: (index, object) => deviceMenu.removeItem(object)
}
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
}
}

View File

@@ -1,33 +0,0 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.ControlCenter.Widgets
CompoundPill {
id: root
property var colorPickerModal: null
isActive: true
iconName: "palette"
iconColor: Theme.primary
primaryText: "Color Picker"
secondaryText: "Choose a color"
onToggled: {
console.log("ColorPickerPill toggled, modal:", colorPickerModal)
if (colorPickerModal) {
colorPickerModal.show()
}
}
onExpandClicked: {
console.log("ColorPickerPill expandClicked, modal:", colorPickerModal)
if (colorPickerModal) {
colorPickerModal.show()
}
}
}

View File

@@ -41,7 +41,7 @@ Rectangle {
readonly property color _labelSecondary: Theme.surfaceVariantText
readonly property color _tileBgActive: Theme.primary
readonly property color _tileBgInactive: {
const transparency = Theme.popupTransparency
const transparency = Theme.popupTransparency || 0.92
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
}

View File

@@ -20,7 +20,11 @@ Row {
height: Theme.iconSize + Theme.spacingS * 2
anchors.verticalCenter: parent.verticalCenter
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
MouseArea {
id: iconArea
@@ -30,9 +34,7 @@ Row {
cursorShape: Qt.PointingHandCursor
onClicked: {
if (defaultSource) {
AudioService.suppressOSD = true
defaultSource.audio.muted = !defaultSource.audio.muted
AudioService.suppressOSD = false
}
}
}
@@ -67,9 +69,6 @@ Row {
valueOverride: actualVolumePercent
thumbOutlineColor: Theme.surfaceContainer
trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.surfaceContainerHigh
onIsDraggingChanged: {
AudioService.suppressOSD = isDragging
}
onSliderValueChanged: function(newValue) {
if (defaultSource) {
defaultSource.audio.volume = newValue / 100.0

View File

@@ -91,6 +91,13 @@ Rectangle {
onClicked: root.clicked()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on radius {
NumberAnimation {
duration: Theme.shortDuration

View File

@@ -12,7 +12,6 @@ Rectangle {
property real iconRotation: 0
signal clicked()
signal iconRotationCompleted()
width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48
height: 48
@@ -59,7 +58,6 @@ Rectangle {
size: Theme.iconSize
color: isActive ? _tileIconActive : _tileIconInactive
rotation: iconRotation
onRotationCompleted: root.iconRotationCompleted()
}
MouseArea {
@@ -71,6 +69,13 @@ Rectangle {
onClicked: root.clicked()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on radius {
NumberAnimation {
duration: Theme.shortDuration

View File

@@ -12,9 +12,8 @@ Rectangle {
property bool enabled: true
property string secondaryText: ""
property real iconRotation: 0
signal clicked()
signal iconRotationCompleted()
width: parent ? parent.width : 200
height: 60
@@ -47,7 +46,7 @@ Rectangle {
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: mouseArea.containsMouse ? hoverTint(_containerBg) : Theme.withAlpha(_containerBg, 0)
color: mouseArea.containsMouse ? hoverTint(_containerBg) : "transparent"
opacity: mouseArea.containsMouse ? 0.08 : 0.0
Behavior on opacity {
@@ -67,7 +66,6 @@ Rectangle {
color: isActive ? Theme.primaryContainer : Theme.primary
anchors.verticalCenter: parent.verticalCenter
rotation: root.iconRotation
onRotationCompleted: root.iconRotationCompleted()
}
Item {
@@ -112,6 +110,13 @@ Rectangle {
onClicked: root.clicked()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on radius {
NumberAnimation {
duration: Theme.shortDuration

View File

@@ -1,179 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Services
Item {
id: root
required property var barWindow
required property var axis
required property var appDrawerLoader
required property var dankDashPopoutLoader
required property var processListPopoutLoader
required property var notificationCenterLoader
required property var batteryPopoutLoader
required property var vpnPopoutLoader
required property var controlCenterLoader
required property var clipboardHistoryModalPopup
required property var systemUpdateLoader
required property var notepadInstance
property alias reveal: core.reveal
property alias autoHide: core.autoHide
property alias backgroundTransparency: core.backgroundTransparency
property alias hasActivePopout: core.hasActivePopout
property alias mouseArea: topBarMouseArea
Item {
id: inputMask
readonly property int barThickness: barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing)
readonly property bool showing: SettingsData.dankBarVisible && (core.reveal
|| (CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview)
|| !core.autoHide)
readonly property int maskThickness: showing ? barThickness : 1
x: {
if (!axis.isVertical) {
return 0
} else {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Left: return 0
case SettingsData.Position.Right: return parent.width - maskThickness
default: return 0
}
}
}
y: {
if (axis.isVertical) {
return 0
} else {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Top: return 0
case SettingsData.Position.Bottom: return parent.height - maskThickness
default: return 0
}
}
}
width: axis.isVertical ? maskThickness : parent.width
height: axis.isVertical ? parent.height : maskThickness
}
Region {
id: mask
item: inputMask
}
property alias maskRegion: mask
QtObject {
id: core
property real backgroundTransparency: SettingsData.dankBarTransparency
property bool autoHide: SettingsData.dankBarAutoHide
property bool revealSticky: false
property bool notepadInstanceVisible: notepadInstance?.isVisible ?? false
readonly property bool hasActivePopout: {
const loaders = [{
"loader": appDrawerLoader,
"prop": "shouldBeVisible"
}, {
"loader": dankDashPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": processListPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": notificationCenterLoader,
"prop": "shouldBeVisible"
}, {
"loader": batteryPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": vpnPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": controlCenterLoader,
"prop": "shouldBeVisible"
}, {
"loader": clipboardHistoryModalPopup,
"prop": "visible"
}, {
"loader": systemUpdateLoader,
"prop": "shouldBeVisible"
}]
return notepadInstanceVisible || loaders.some(item => {
if (item.loader) {
return item.loader?.item?.[item.prop]
}
return false
})
}
property bool reveal: {
if (CompositorService.isNiri && NiriService.inOverview) {
return SettingsData.dankBarOpenOnOverview
}
return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky)
}
onHasActivePopoutChanged: {
if (!hasActivePopout && autoHide && !topBarMouseArea.containsMouse) {
revealSticky = true
revealHold.restart()
}
}
}
Timer {
id: revealHold
interval: 250
repeat: false
onTriggered: core.revealSticky = false
}
Connections {
function onDankBarTransparencyChanged() {
core.backgroundTransparency = SettingsData.dankBarTransparency
}
target: SettingsData
}
Connections {
target: topBarMouseArea
function onContainsMouseChanged() {
if (topBarMouseArea.containsMouse) {
core.revealSticky = true
revealHold.stop()
} else {
if (core.autoHide && !core.hasActivePopout) {
revealHold.restart()
}
}
}
}
MouseArea {
id: topBarMouseArea
y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0
height: !barWindow.isVertical ? barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
width: barWindow.isVertical ? barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
anchors {
left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined)
right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined)
top: barWindow.isVertical ? parent.top : undefined
bottom: barWindow.isVertical ? parent.bottom : undefined
}
hoverEnabled: SettingsData.dankBarAutoHide && !core.reveal
acceptedButtons: Qt.NoButton
enabled: SettingsData.dankBarAutoHide && !core.reveal
}
}

View File

@@ -1,57 +0,0 @@
import QtQuick
QtObject {
id: root
property string edge: "top"
readonly property string orientation: isVertical ? "vertical" : "horizontal"
readonly property bool isVertical: edge === "left" || edge === "right"
readonly property bool isHorizontal: !isVertical
function primarySize(item) {
return isVertical ? item.height : item.width
}
function crossSize(item) {
return isVertical ? item.width : item.height
}
function setPrimaryPos(item, value) {
if (isVertical) {
item.y = value
} else {
item.x = value
}
}
function getPrimaryPos(item) {
return isVertical ? item.y : item.x
}
function primaryAnchor(anchors) {
return isVertical ? anchors.verticalCenter : anchors.horizontalCenter
}
function crossAnchor(anchors) {
return isVertical ? anchors.horizontalCenter : anchors.verticalCenter
}
function outerVisualEdge() {
if (edge === "bottom") return "bottom"
if (edge === "left") return "right"
if (edge === "right") return "left"
if (edge === "top") return "top"
return "bottom"
}
signal axisEdgeChanged()
signal axisOrientationChanged()
signal changed() // Single coalesced signal
onEdgeChanged: {
axisEdgeChanged()
axisOrientationChanged()
changed()
}
}

View File

@@ -1,210 +0,0 @@
import QtQuick
import qs.Common
Item {
id: root
required property var barWindow
required property var axis
anchors.fill: parent
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0)
anchors.rightMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0)
anchors.topMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0)
anchors.bottomMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0)
Canvas {
id: barShape
anchors.fill: parent
antialiasing: true
renderTarget: Canvas.FramebufferObject
renderStrategy: Canvas.Cooperative
readonly property real correctWidth: root.width
readonly property real correctHeight: root.height
canvasSize: Qt.size(barWindow.px(correctWidth), barWindow.px(correctHeight))
property real wing: SettingsData.dankBarGothCornersEnabled ? barWindow._wingR : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.cornerRadius
onWingChanged: requestPaint()
onRtChanged: requestPaint()
onCorrectWidthChanged: requestPaint()
onCorrectHeightChanged: requestPaint()
onVisibleChanged: if (visible) requestPaint()
Component.onCompleted: requestPaint()
Connections {
target: barWindow
function on_BgColorChanged() { barShape.requestPaint() }
function on_DprChanged() { barShape.requestPaint() }
}
Connections {
target: Theme
function onIsLightModeChanged() { barShape.requestPaint() }
}
onPaint: {
const ctx = getContext("2d")
const scale = barWindow._dpr
const W = barWindow.px(barWindow.isVertical ? correctHeight : correctWidth)
const H_raw = barWindow.px(barWindow.isVertical ? correctWidth : correctHeight)
const R = barWindow.px(wing)
const RT = barWindow.px(rt)
const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
ctx.scale(scale, scale)
function drawTopPath() {
ctx.beginPath()
ctx.moveTo(RT, 0)
ctx.lineTo(W - RT, 0)
ctx.arcTo(W, 0, W, RT, RT)
ctx.lineTo(W, H)
if (R > 0) {
ctx.lineTo(W, H + R)
ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true)
ctx.lineTo(R, H)
ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true)
ctx.lineTo(0, H + R)
} else {
ctx.lineTo(W, H - RT)
ctx.arcTo(W, H, W - RT, H, RT)
ctx.lineTo(RT, H)
ctx.arcTo(0, H, 0, H - RT, RT)
}
ctx.lineTo(0, RT)
ctx.arcTo(0, 0, RT, 0, RT)
ctx.closePath()
}
ctx.reset()
ctx.clearRect(0, 0, W, H_raw)
ctx.save()
if (isBottom) {
ctx.translate(W, H_raw)
ctx.rotate(Math.PI)
} else if (isLeft) {
ctx.translate(0, W)
ctx.rotate(-Math.PI / 2)
} else if (isRight) {
ctx.translate(H_raw, 0)
ctx.rotate(Math.PI / 2)
}
drawTopPath()
ctx.restore()
ctx.fillStyle = barWindow._bgColor
ctx.fill()
}
}
Canvas {
id: barTint
anchors.fill: parent
antialiasing: true
renderTarget: Canvas.FramebufferObject
renderStrategy: Canvas.Cooperative
readonly property real correctWidth: root.width
readonly property real correctHeight: root.height
canvasSize: Qt.size(barWindow.px(correctWidth), barWindow.px(correctHeight))
property real wing: SettingsData.dankBarGothCornersEnabled ? barWindow._wingR : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.cornerRadius
property real alphaTint: (barWindow._bgColor?.a ?? 1) < 0.99 ? (Theme.stateLayerOpacity ?? 0) : 0
onWingChanged: requestPaint()
onRtChanged: requestPaint()
onAlphaTintChanged: requestPaint()
onCorrectWidthChanged: requestPaint()
onCorrectHeightChanged: requestPaint()
onVisibleChanged: if (visible) requestPaint()
Component.onCompleted: requestPaint()
Connections {
target: barWindow
function on_BgColorChanged() { barTint.requestPaint() }
function on_DprChanged() { barTint.requestPaint() }
}
Connections {
target: Theme
function onIsLightModeChanged() { barTint.requestPaint() }
}
onPaint: {
const ctx = getContext("2d")
const scale = barWindow._dpr
const W = barWindow.px(barWindow.isVertical ? correctHeight : correctWidth)
const H_raw = barWindow.px(barWindow.isVertical ? correctWidth : correctHeight)
const R = barWindow.px(wing)
const RT = barWindow.px(rt)
const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
ctx.scale(scale, scale)
function drawTopPath() {
ctx.beginPath()
ctx.moveTo(RT, 0)
ctx.lineTo(W - RT, 0)
ctx.arcTo(W, 0, W, RT, RT)
ctx.lineTo(W, H)
if (R > 0) {
ctx.lineTo(W, H + R)
ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true)
ctx.lineTo(R, H)
ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true)
ctx.lineTo(0, H + R)
} else {
ctx.lineTo(W, H - RT)
ctx.arcTo(W, H, W - RT, H, RT)
ctx.lineTo(RT, H)
ctx.arcTo(0, H, 0, H - RT, RT)
}
ctx.lineTo(0, RT)
ctx.arcTo(0, 0, RT, 0, RT)
ctx.closePath()
}
ctx.reset()
ctx.clearRect(0, 0, W, H_raw)
ctx.save()
if (isBottom) {
ctx.translate(W, H_raw)
ctx.rotate(Math.PI)
} else if (isLeft) {
ctx.translate(0, W)
ctx.rotate(-Math.PI / 2)
} else if (isRight) {
ctx.translate(H_raw, 0)
ctx.rotate(Math.PI / 2)
}
drawTopPath()
ctx.restore()
ctx.fillStyle = Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, alphaTint)
ctx.fill()
}
}
}

View File

@@ -1,382 +0,0 @@
import QtQuick
import qs.Common
import qs.Services
Item {
id: root
property var widgetsModel: null
property var components: null
property bool noBackground: false
required property var axis
readonly property bool isVertical: axis?.isVertical ?? false
readonly property real spacing: noBackground ? 2 : Theme.spacingXS
property var centerWidgets: []
property int totalWidgets: 0
property real totalSize: 0
function updateLayout() {
const containerSize = isVertical ? height : width
if (containerSize <= 0 || !visible) {
return
}
centerWidgets = []
totalWidgets = 0
totalSize = 0
let configuredWidgets = 0
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
if (item && getWidgetVisible(item.widgetId)) {
configuredWidgets++
if (item.active && item.item) {
centerWidgets.push(item.item)
totalWidgets++
totalSize += isVertical ? item.item.height : item.item.width
}
}
}
if (totalWidgets > 1) {
totalSize += spacing * (totalWidgets - 1)
}
positionWidgets(configuredWidgets)
}
function positionWidgets(configuredWidgets) {
if (totalWidgets === 0 || (isVertical ? height : width) <= 0) {
return
}
const parentCenter = (isVertical ? height : width) / 2
const isOdd = configuredWidgets % 2 === 1
centerWidgets.forEach(widget => {
if (isVertical) {
widget.anchors.verticalCenter = undefined
} else {
widget.anchors.horizontalCenter = undefined
}
})
if (isOdd) {
const middleIndex = Math.floor(configuredWidgets / 2)
let currentActiveIndex = 0
let middleWidget = null
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
if (item && getWidgetVisible(item.widgetId)) {
if (currentActiveIndex === middleIndex && item.active && item.item) {
middleWidget = item.item
break
}
currentActiveIndex++
}
}
if (middleWidget) {
const middleSize = isVertical ? middleWidget.height : middleWidget.width
if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2)
} else {
middleWidget.x = parentCenter - (middleSize / 2)
}
let leftWidgets = []
let rightWidgets = []
let foundMiddle = false
for (var i = 0; i < centerWidgets.length; i++) {
if (centerWidgets[i] === middleWidget) {
foundMiddle = true
continue
}
if (!foundMiddle) {
leftWidgets.push(centerWidgets[i])
} else {
rightWidgets.push(centerWidgets[i])
}
}
let currentPos = isVertical ? middleWidget.y : middleWidget.x
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
}
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
}
}
} else {
let configuredLeftIndex = (configuredWidgets / 2) - 1
let configuredRightIndex = configuredWidgets / 2
const halfSpacing = spacing / 2
let leftWidget = null
let rightWidget = null
let leftWidgets = []
let rightWidgets = []
let currentConfigIndex = 0
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
if (item && getWidgetVisible(item.widgetId)) {
if (item.active && item.item) {
if (currentConfigIndex < configuredLeftIndex) {
leftWidgets.push(item.item)
} else if (currentConfigIndex === configuredLeftIndex) {
leftWidget = item.item
} else if (currentConfigIndex === configuredRightIndex) {
rightWidget = item.item
} else {
rightWidgets.push(item.item)
}
}
currentConfigIndex++
}
}
if (leftWidget && rightWidget) {
const leftSize = isVertical ? leftWidget.height : leftWidget.width
if (isVertical) {
leftWidget.y = parentCenter - halfSpacing - leftSize
rightWidget.y = parentCenter + halfSpacing
} else {
leftWidget.x = parentCenter - halfSpacing - leftSize
rightWidget.x = parentCenter + halfSpacing
}
let currentPos = isVertical ? leftWidget.y : leftWidget.x
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
}
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
}
} else if (leftWidget && !rightWidget) {
const leftSize = isVertical ? leftWidget.height : leftWidget.width
if (isVertical) {
leftWidget.y = parentCenter - halfSpacing - leftSize
} else {
leftWidget.x = parentCenter - halfSpacing - leftSize
}
let currentPos = isVertical ? leftWidget.y : leftWidget.x
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
}
currentPos = (isVertical ? leftWidget.y + leftWidget.height : leftWidget.x + leftWidget.width) + spacing
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
}
} else if (!leftWidget && rightWidget) {
if (isVertical) {
rightWidget.y = parentCenter + halfSpacing
} else {
rightWidget.x = parentCenter + halfSpacing
}
let currentPos = (isVertical ? rightWidget.y : rightWidget.x) - spacing
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= size
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
currentPos -= spacing
}
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
}
} else if (totalWidgets === 1 && centerWidgets[0]) {
const size = isVertical ? centerWidgets[0].height : centerWidgets[0].width
if (isVertical) {
centerWidgets[0].y = parentCenter - (size / 2)
} else {
centerWidgets[0].x = parentCenter - (size / 2)
}
}
}
}
function getWidgetVisible(widgetId) {
const widgetVisibility = {
"cpuUsage": DgopService.dgopAvailable,
"memUsage": DgopService.dgopAvailable,
"cpuTemp": DgopService.dgopAvailable,
"gpuTemp": DgopService.dgopAvailable,
"network_speed_monitor": DgopService.dgopAvailable
}
return widgetVisibility[widgetId] ?? true
}
function getWidgetComponent(widgetId) {
const componentMap = {
"launcherButton": "launcherButtonComponent",
"workspaceSwitcher": "workspaceSwitcherComponent",
"focusedWindow": "focusedWindowComponent",
"runningApps": "runningAppsComponent",
"clock": "clockComponent",
"music": "mediaComponent",
"weather": "weatherComponent",
"systemTray": "systemTrayComponent",
"privacyIndicator": "privacyIndicatorComponent",
"clipboard": "clipboardComponent",
"cpuUsage": "cpuUsageComponent",
"memUsage": "memUsageComponent",
"diskUsage": "diskUsageComponent",
"cpuTemp": "cpuTempComponent",
"gpuTemp": "gpuTempComponent",
"notificationButton": "notificationButtonComponent",
"battery": "batteryComponent",
"controlCenterButton": "controlCenterButtonComponent",
"idleInhibitor": "idleInhibitorComponent",
"spacer": "spacerComponent",
"separator": "separatorComponent",
"network_speed_monitor": "networkComponent",
"keyboard_layout_name": "keyboardLayoutNameComponent",
"vpn": "vpnComponent",
"notepadButton": "notepadButtonComponent",
"colorPicker": "colorPickerComponent",
"systemUpdate": "systemUpdateComponent"
}
const componentKey = componentMap[widgetId]
return componentKey ? root.components[componentKey] : null
}
height: parent.height
width: parent.width
anchors.centerIn: parent
Timer {
id: layoutTimer
interval: 0
repeat: false
onTriggered: root.updateLayout()
}
Component.onCompleted: {
layoutTimer.restart()
}
onWidthChanged: {
if (width > 0) {
layoutTimer.restart()
}
}
onHeightChanged: {
if (height > 0) {
layoutTimer.restart()
}
}
onVisibleChanged: {
if (visible && (isVertical ? height : width) > 0) {
layoutTimer.restart()
}
}
Repeater {
id: centerRepeater
model: root.widgetsModel
Loader {
property string widgetId: model.widgetId
property var widgetData: model
property int spacerSize: model.size || 20
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
active: root.getWidgetVisible(model.widgetId) && (model.widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: root.getWidgetComponent(model.widgetId)
opacity: (model.enabled !== false) ? 1 : 0
asynchronous: false
onLoaded: {
if (!item) {
return
}
item.widthChanged.connect(() => layoutTimer.restart())
item.heightChanged.connect(() => layoutTimer.restart())
if (model.widgetId === "spacer") {
item.spacerSize = Qt.binding(() => model.size || 20)
}
if (root.axis && "axis" in item) {
item.axis = root.axis
}
if (root.axis && "isVertical" in item) {
item.isVertical = root.axis.isVertical
}
layoutTimer.restart()
}
onActiveChanged: {
layoutTimer.restart()
}
}
}
Connections {
target: widgetsModel
function onCountChanged() {
layoutTimer.restart()
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,71 +0,0 @@
import QtQuick
import qs.Common
Item {
id: root
property var widgetsModel: null
property var components: null
property bool noBackground: false
required property var axis
readonly property bool isVertical: axis?.isVertical ?? false
implicitHeight: layoutLoader.item ? (layoutLoader.item.implicitHeight || layoutLoader.item.height) : 0
implicitWidth: layoutLoader.item ? (layoutLoader.item.implicitWidth || layoutLoader.item.width) : 0
Loader {
id: layoutLoader
anchors.fill: parent
sourceComponent: root.isVertical ? columnComp : rowComp
}
Component {
id: rowComp
Row {
spacing: noBackground ? 2 : Theme.spacingXS
Repeater {
model: root.widgetsModel
Item {
width: widgetLoader.item ? widgetLoader.item.width : 0
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.verticalCenter: parent.verticalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
components: root.components
isInColumn: false
axis: root.axis
}
}
}
}
}
Component {
id: columnComp
Column {
width: Math.max(parent.width, 200)
spacing: noBackground ? 2 : Theme.spacingXS
Repeater {
model: root.widgetsModel
Item {
width: parent.width
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.horizontalCenter: parent.horizontalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
components: root.components
isInColumn: true
axis: root.axis
}
}
}
}
}
}

View File

@@ -1,73 +0,0 @@
import QtQuick
import qs.Common
Item {
id: root
property var widgetsModel: null
property var components: null
property bool noBackground: false
required property var axis
readonly property bool isVertical: axis?.isVertical ?? false
implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0
implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0
Loader {
id: layoutLoader
width: parent.width
height: parent.height
sourceComponent: root.isVertical ? columnComp : rowComp
}
Component {
id: rowComp
Row {
spacing: noBackground ? 2 : Theme.spacingXS
anchors.right: parent ? parent.right : undefined
Repeater {
model: root.widgetsModel
Item {
width: widgetLoader.item ? widgetLoader.item.width : 0
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.verticalCenter: parent.verticalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
components: root.components
isInColumn: false
axis: root.axis
}
}
}
}
}
Component {
id: columnComp
Column {
width: parent ? parent.width : 0
spacing: noBackground ? 2 : Theme.spacingXS
Repeater {
model: root.widgetsModel
Item {
width: parent.width
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.horizontalCenter: parent.horizontalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
components: root.components
isInColumn: true
axis: root.axis
}
}
}
}
}
}

View File

@@ -1,88 +0,0 @@
import QtQuick
import Quickshell.Services.Mpris
import qs.Services
Loader {
id: root
property string widgetId: ""
property var widgetData: null
property int spacerSize: 20
property var components: null
property bool isInColumn: false
property var axis: null
asynchronous: false
active: getWidgetVisible(widgetId, DgopService.dgopAvailable) &&
(widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: getWidgetComponent(widgetId, components)
opacity: getWidgetEnabled(widgetData?.enabled) ? 1 : 0
signal contentItemReady(var item)
onLoaded: {
if (item) {
contentItemReady(item)
if (widgetId === "spacer") {
item.spacerSize = Qt.binding(() => spacerSize)
}
if (axis && "axis" in item) {
item.axis = axis
}
if (axis && "isVertical" in item) {
item.isVertical = axis.isVertical
}
}
}
function getWidgetComponent(widgetId, components) {
const componentMap = {
"launcherButton": components.launcherButtonComponent,
"workspaceSwitcher": components.workspaceSwitcherComponent,
"focusedWindow": components.focusedWindowComponent,
"runningApps": components.runningAppsComponent,
"clock": components.clockComponent,
"music": components.mediaComponent,
"weather": components.weatherComponent,
"systemTray": components.systemTrayComponent,
"privacyIndicator": components.privacyIndicatorComponent,
"clipboard": components.clipboardComponent,
"cpuUsage": components.cpuUsageComponent,
"memUsage": components.memUsageComponent,
"diskUsage": components.diskUsageComponent,
"cpuTemp": components.cpuTempComponent,
"gpuTemp": components.gpuTempComponent,
"notificationButton": components.notificationButtonComponent,
"battery": components.batteryComponent,
"controlCenterButton": components.controlCenterButtonComponent,
"idleInhibitor": components.idleInhibitorComponent,
"spacer": components.spacerComponent,
"separator": components.separatorComponent,
"network_speed_monitor": components.networkComponent,
"keyboard_layout_name": components.keyboardLayoutNameComponent,
"vpn": components.vpnComponent,
"notepadButton": components.notepadButtonComponent,
"colorPicker": components.colorPickerComponent,
"systemUpdate": components.systemUpdateComponent
}
return componentMap[widgetId] || null
}
function getWidgetVisible(widgetId, dgopAvailable) {
const widgetVisibility = {
"cpuUsage": dgopAvailable,
"memUsage": dgopAvailable,
"cpuTemp": dgopAvailable,
"gpuTemp": dgopAvailable,
"network_speed_monitor": dgopAvailable
}
return widgetVisibility[widgetId] ?? true
}
function getWidgetEnabled(enabled) {
return enabled !== false
}
}

View File

@@ -1,126 +0,0 @@
import QtQuick
import Quickshell.Services.UPower
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: battery
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool batteryPopupVisible: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
signal toggleBatteryPopup()
width: isVertical ? widgetThickness : (batteryContent.implicitWidth + horizontalPadding * 2)
height: isVertical ? (batteryColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent";
}
const baseColor = batteryArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
visible: true
Column {
id: batteryColumn
visible: battery.isVertical
anchors.centerIn: parent
spacing: 1
DankIcon {
name: BatteryService.getBatteryIcon()
size: Theme.iconSize - 8
color: {
if (!BatteryService.batteryAvailable) {
return Theme.surfaceText
}
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error
}
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
return Theme.primary
}
return Theme.surfaceText
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: BatteryService.batteryLevel.toString()
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: BatteryService.batteryAvailable
}
}
Row {
id: batteryContent
visible: !battery.isVertical
anchors.centerIn: parent
spacing: SettingsData.dankBarNoBackground ? 1 : 2
DankIcon {
name: BatteryService.getBatteryIcon()
size: Theme.iconSize - 6
color: {
if (!BatteryService.batteryAvailable) {
return Theme.surfaceText;
}
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error;
}
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
return Theme.primary;
}
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: `${BatteryService.batteryLevel}%`
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable
}
}
MouseArea {
id: batteryArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
toggleBatteryPopup();
}
}
}

View File

@@ -1,57 +0,0 @@
import QtQuick
import qs.Common
import qs.Widgets
Item {
id: root
property bool isActive: false
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "right"
property var clipboardHistoryModal: null
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
signal clicked()
width: widgetThickness
height: widgetThickness
MouseArea {
id: clipboardArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
root.clicked()
}
}
Rectangle {
id: clipboardContent
anchors.fill: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent"
}
const baseColor = clipboardArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
}
DankIcon {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
name: "content_paste"
size: widgetThickness - 8
color: Theme.surfaceText
}
}
}

View File

@@ -1,267 +0,0 @@
import QtQuick
import Quickshell
import qs.Common
import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool compactMode: false
property string section: "center"
property var popupTarget: null
property var parentScreen: null
property real barThickness: 48
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
signal clockClicked
width: isVertical ? widgetThickness : (clockRow.implicitWidth + horizontalPadding * 2)
height: isVertical ? (clockColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent";
}
const baseColor = clockMouseArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Column {
id: clockColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: -2
Row {
spacing: 0
anchors.horizontalCenter: parent.horizontalCenter
StyledText {
text: {
if (SettingsData.use24HourClock) {
return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(0)
} else {
const hours = systemClock?.date?.getHours()
const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours
return String(display).padStart(2, '0').charAt(0)
}
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Normal
width: 9
horizontalAlignment: Text.AlignHCenter
}
StyledText {
text: {
if (SettingsData.use24HourClock) {
return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(1)
} else {
const hours = systemClock?.date?.getHours()
const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours
return String(display).padStart(2, '0').charAt(1)
}
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Normal
width: 9
horizontalAlignment: Text.AlignHCenter
}
}
Row {
spacing: 0
anchors.horizontalCenter: parent.horizontalCenter
StyledText {
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0)
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Normal
width: 9
horizontalAlignment: Text.AlignHCenter
}
StyledText {
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1)
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Normal
width: 9
horizontalAlignment: Text.AlignHCenter
}
}
Item {
width: 12
height: Theme.spacingM
anchors.horizontalCenter: parent.horizontalCenter
Rectangle {
width: 12
height: 1
color: Theme.outlineButton
anchors.centerIn: parent
}
}
Row {
spacing: 0
anchors.horizontalCenter: parent.horizontalCenter
StyledText {
text: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
return value.charAt(0)
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
return dayFirst ? Font.Normal : Font.Light
}
width: 9
horizontalAlignment: Text.AlignHCenter
}
StyledText {
text: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
return value.charAt(1)
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
return dayFirst ? Font.Normal : Font.Light
}
width: 9
horizontalAlignment: Text.AlignHCenter
}
}
Row {
spacing: 0
anchors.horizontalCenter: parent.horizontalCenter
StyledText {
text: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
return value.charAt(0)
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
return dayFirst ? Font.Light : Font.Normal
}
width: 9
horizontalAlignment: Text.AlignHCenter
}
StyledText {
text: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
return value.charAt(1)
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: {
const locale = Qt.locale()
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
return dayFirst ? Font.Light : Font.Normal
}
width: 9
horizontalAlignment: Text.AlignHCenter
}
}
}
Row {
id: clockRow
visible: !root.isVertical
anchors.centerIn: parent
spacing: Theme.spacingS
StyledText {
text: {
const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"
return systemClock?.date?.toLocaleTimeString(Qt.locale(), format)
}
font.pixelSize: Theme.fontSizeMedium - 1
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.clockCompactMode
}
StyledText {
text: {
if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) {
return systemClock?.date?.toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat)
}
return systemClock?.date?.toLocaleDateString(Qt.locale(), "ddd d")
}
font.pixelSize: Theme.fontSizeMedium - 1
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.clockCompactMode
}
}
SystemClock {
id: systemClock
precision: SystemClock.Seconds
}
MouseArea {
id: clockMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.clockClicked()
}
}
}

View File

@@ -1,96 +0,0 @@
import QtQuick
import Quickshell.Hyprland
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "right"
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
signal clicked()
readonly property string focusedScreenName: (
CompositorService.isHyprland && typeof Hyprland !== "undefined" && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor ? (Hyprland.focusedWorkspace.monitor.name || "") :
CompositorService.isNiri && typeof NiriService !== "undefined" && NiriService.currentOutput ? NiriService.currentOutput : ""
)
function resolveNotepadInstance() {
if (typeof notepadSlideoutVariants === "undefined" || !notepadSlideoutVariants || !notepadSlideoutVariants.instances) {
return null
}
const targetScreen = focusedScreenName
if (targetScreen) {
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
var slideout = notepadSlideoutVariants.instances[i]
if (slideout.modelData && slideout.modelData.name === targetScreen) {
return slideout
}
}
}
return notepadSlideoutVariants.instances.length > 0 ? notepadSlideoutVariants.instances[0] : null
}
readonly property var notepadInstance: resolveNotepadInstance()
readonly property bool isActive: notepadInstance?.isVisible ?? false
width: isVertical ? widgetThickness : (notepadIcon.width + horizontalPadding * 2)
height: isVertical ? (notepadIcon.height + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent";
}
const baseColor = notepadArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
DankIcon {
id: notepadIcon
anchors.centerIn: parent
name: "assignment"
size: Theme.iconSize - 6
color: notepadArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
}
Rectangle {
width: 6
height: 6
radius: 3
color: Theme.primary
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 4
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 4
visible: NotepadStorageService.tabs && NotepadStorageService.tabs.length > 0
opacity: 0.8
}
MouseArea {
id: notepadArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
const inst = root.notepadInstance
if (inst) {
inst.toggle()
}
root.clicked()
}
}
}

View File

@@ -1,76 +0,0 @@
import QtQuick
import qs.Common
import qs.Widgets
Item {
id: root
property bool hasUnread: false
property bool isActive: false
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
signal clicked()
width: widgetThickness
height: widgetThickness
MouseArea {
id: notificationArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.clicked()
}
}
Rectangle {
id: notificationContent
anchors.fill: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent"
}
const baseColor = notificationArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
}
DankIcon {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
size: widgetThickness - 8
color: SessionData.doNotDisturb ? Theme.error : (notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText)
}
Rectangle {
width: 8
height: 8
radius: 4
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 6
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 6
visible: root.hasUnread
}
}
}

View File

@@ -1,630 +0,0 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Services.SystemTray
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property var parentWindow: null
property var parentScreen: null
property real widgetThickness: 30
property bool isAtBottom: false
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
readonly property int calculatedSize: SystemTray.items.values.length > 0 ? SystemTray.items.values.length * 24 + horizontalPadding * 2 : 0
width: isVertical ? widgetThickness : calculatedSize
height: isVertical ? calculatedSize : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SystemTray.items.values.length === 0) {
return "transparent";
}
if (SettingsData.dankBarNoBackground) {
return "transparent";
}
const baseColor = Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
visible: SystemTray.items.values.length > 0
Loader {
id: layoutLoader
anchors.centerIn: parent
sourceComponent: root.isVertical ? columnComp : rowComp
}
Component {
id: rowComp
Row {
spacing: 0
Repeater {
model: SystemTray.items.values
delegate: Item {
property var trayItem: modelData
property string iconSource: {
let icon = trayItem && trayItem.icon;
if (typeof icon === 'string' || icon instanceof String) {
if (icon === "") {
return "";
}
if (icon.includes("?path=")) {
const split = icon.split("?path=");
if (split.length !== 2) {
return icon;
}
const name = split[0];
const path = split[1];
const fileName = name.substring(name.lastIndexOf("/") + 1);
return `file://${path}/${fileName}`;
}
if (icon.startsWith("/") && !icon.startsWith("file://")) {
return `file://${icon}`;
}
return icon;
}
return "";
}
width: 24
height: 24
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: trayItemArea.containsMouse ? Theme.primaryHover : "transparent"
}
IconImage {
anchors.centerIn: parent
width: 16
height: 16
source: parent.iconSource
asynchronous: true
smooth: true
mipmap: true
}
MouseArea {
id: trayItemArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (!trayItem) {
return;
}
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate();
return ;
}
if (trayItem.hasMenu) {
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
}
}
}
}
}
}
}
Component {
id: columnComp
Column {
spacing: 0
Repeater {
model: SystemTray.items.values
delegate: Item {
property var trayItem: modelData
property string iconSource: {
let icon = trayItem && trayItem.icon;
if (typeof icon === 'string' || icon instanceof String) {
if (icon === "") {
return "";
}
if (icon.includes("?path=")) {
const split = icon.split("?path=");
if (split.length !== 2) {
return icon;
}
const name = split[0];
const path = split[1];
const fileName = name.substring(name.lastIndexOf("/") + 1);
return `file://${path}/${fileName}`;
}
if (icon.startsWith("/") && !icon.startsWith("file://")) {
return `file://${icon}`;
}
return icon;
}
return "";
}
width: 24
height: 24
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: trayItemArea.containsMouse ? Theme.primaryHover : "transparent"
}
IconImage {
anchors.centerIn: parent
width: 16
height: 16
source: parent.iconSource
asynchronous: true
smooth: true
mipmap: true
}
MouseArea {
id: trayItemArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (!trayItem) {
return;
}
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate();
return ;
}
if (trayItem.hasMenu) {
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
}
}
}
}
}
}
}
Component {
id: trayMenuComponent
Rectangle {
id: menuRoot
property var trayItem: null
property var anchorItem: null
property var parentScreen: null
property bool isAtBottom: false
property bool isVertical: false
property var axis: null
property bool showMenu: false
property var menuHandle: null
ListModel { id: entryStack }
function topEntry() {
return entryStack.count ? entryStack.get(entryStack.count - 1).handle : null
}
function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) {
trayItem = item
anchorItem = anchor
parentScreen = screen
isAtBottom = atBottom
isVertical = vertical
axis = axisObj
menuHandle = item?.menu
if (parentScreen) {
for (var i = 0; i < Quickshell.screens.length; i++) {
const s = Quickshell.screens[i]
if (s === parentScreen) {
menuWindow.screen = s
break
}
}
}
showMenu = true
}
function close() {
showMenu = false
}
function showSubMenu(entry) {
if (!entry || !entry.hasChildren) return;
entryStack.append({ handle: entry });
const h = entry.menu || entry;
if (h && typeof h.updateLayout === "function") h.updateLayout();
submenuHydrator.menu = h;
submenuHydrator.open();
Qt.callLater(() => submenuHydrator.close());
}
function goBack() {
if (!entryStack.count) return;
entryStack.remove(entryStack.count - 1);
}
width: 0
height: 0
color: "transparent"
PanelWindow {
id: menuWindow
visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false)
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
color: "transparent"
anchors {
top: true
left: true
right: true
bottom: true
}
property point anchorPos: Qt.point(screen.width / 2, screen.height / 2)
onVisibleChanged: {
if (visible) {
updatePosition()
}
}
function updatePosition() {
if (!menuRoot.anchorItem || !menuRoot.trayItem) {
anchorPos = Qt.point(screen.width / 2, screen.height / 2)
return
}
const globalPos = menuRoot.anchorItem.mapToGlobal(0, 0)
const screenX = screen.x || 0
const screenY = screen.y || 0
const relativeX = globalPos.x - screenX
const relativeY = globalPos.y - screenY
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
const effectiveBarThickness = Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
if (menuRoot.isVertical) {
const edge = menuRoot.axis?.edge
let targetX
if (edge === "left") {
targetX = effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance
} else {
const popupX = effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance
targetX = screen.width - popupX
}
anchorPos = Qt.point(targetX, relativeY + menuRoot.anchorItem.height / 2)
} else {
let targetY
if (menuRoot.isAtBottom) {
const popupY = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance
targetY = screen.height - popupY
} else {
targetY = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance
}
anchorPos = Qt.point(relativeX + menuRoot.anchorItem.width / 2, targetY)
}
}
Rectangle {
id: menuContainer
width: Math.min(500, Math.max(250, menuColumn.implicitWidth + Theme.spacingS * 2))
height: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2)
x: {
if (menuRoot.isVertical) {
const edge = menuRoot.axis?.edge
if (edge === "left") {
const targetX = menuWindow.anchorPos.x
return Math.min(menuWindow.screen.width - width - 10, targetX)
} else {
const targetX = menuWindow.anchorPos.x - width
return Math.max(10, targetX)
}
} else {
const left = 10
const right = menuWindow.width - width - 10
const want = menuWindow.anchorPos.x - width / 2
return Math.max(left, Math.min(right, want))
}
}
y: {
if (menuRoot.isVertical) {
const top = 10
const bottom = menuWindow.height - height - 10
const want = menuWindow.anchorPos.y - height / 2
return Math.max(top, Math.min(bottom, want))
} else {
if (menuRoot.isAtBottom) {
const targetY = menuWindow.anchorPos.y - height
return Math.max(10, targetY)
} else {
const targetY = menuWindow.anchorPos.y
return Math.min(menuWindow.screen.height - height - 10, targetY)
}
}
}
color: Theme.popupBackground()
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
opacity: menuRoot.showMenu ? 1 : 0
scale: menuRoot.showMenu ? 1 : 0.85
Rectangle {
anchors.fill: parent
anchors.topMargin: 4
anchors.leftMargin: 2
anchors.rightMargin: -2
anchors.bottomMargin: -4
radius: parent.radius
color: Qt.rgba(0, 0, 0, 0.15)
z: parent.z - 1
}
QsMenuAnchor {
id: submenuHydrator
anchor.window: menuWindow
}
QsMenuOpener {
id: rootOpener
menu: menuRoot.menuHandle
}
QsMenuOpener {
id: subOpener
menu: {
const e = menuRoot.topEntry();
return e ? (e.menu || e) : null;
}
}
Column {
id: menuColumn
width: parent.width - Theme.spacingS * 2
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Theme.spacingS
spacing: 1
Rectangle {
visible: entryStack.count > 0
width: parent.width
height: 28
radius: Theme.cornerRadius
color: backArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
DankIcon {
name: "arrow_back"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Back"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: backArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: menuRoot.goBack()
}
}
Rectangle {
visible: entryStack.count > 0
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
}
Repeater {
model: entryStack.count
? (subOpener.children ? subOpener.children
: (menuRoot.topEntry()?.children || []))
: rootOpener.children
Rectangle {
property var menuEntry: modelData
width: menuColumn.width
height: menuEntry?.isSeparator ? 1 : 28
radius: menuEntry?.isSeparator ? 0 : Theme.cornerRadius
color: {
if (menuEntry?.isSeparator) {
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
}
return itemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
}
MouseArea {
id: itemArea
anchors.fill: parent
enabled: !menuEntry?.isSeparator && (menuEntry?.enabled !== false)
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (!menuEntry || menuEntry.isSeparator) return;
if (menuEntry.hasChildren) {
menuRoot.showSubMenu(menuEntry);
} else {
if (typeof menuEntry.activate === "function") {
menuEntry.activate();
} else if (typeof menuEntry.triggered === "function") {
menuEntry.triggered();
}
Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.close() }', menuRoot);
}
}
}
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
visible: !menuEntry?.isSeparator
Rectangle {
width: 16
height: 16
anchors.verticalCenter: parent.verticalCenter
visible: menuEntry?.buttonType !== undefined && menuEntry.buttonType !== 0
radius: menuEntry?.buttonType === 2 ? 8 : 2
border.width: 1
border.color: Theme.outline
color: "transparent"
Rectangle {
anchors.centerIn: parent
width: parent.width - 6
height: parent.height - 6
radius: parent.radius - 3
color: Theme.primary
visible: menuEntry?.checkState === 2
}
DankIcon {
anchors.centerIn: parent
name: "check"
size: 10
color: Theme.primaryText
visible: menuEntry?.buttonType === 1 && menuEntry?.checkState === 2
}
}
Item {
width: 16
height: 16
anchors.verticalCenter: parent.verticalCenter
visible: menuEntry?.icon && menuEntry.icon !== ""
Image {
anchors.fill: parent
source: menuEntry?.icon || ""
sourceSize.width: 16
sourceSize.height: 16
fillMode: Image.PreserveAspectFit
smooth: true
}
}
StyledText {
text: menuEntry?.text || ""
font.pixelSize: Theme.fontSizeSmall
color: (menuEntry?.enabled !== false) ? Theme.surfaceText : Theme.surfaceTextMedium
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
width: Math.max(150, parent.width - 64)
wrapMode: Text.NoWrap
}
Item {
width: 16
height: 16
anchors.verticalCenter: parent.verticalCenter
DankIcon {
anchors.centerIn: parent
name: "chevron_right"
size: 14
color: Theme.surfaceText
visible: menuEntry?.hasChildren ?? false
}
}
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
MouseArea {
anchors.fill: parent
z: -1
onClicked: menuRoot.close()
}
}
}
}
property var currentTrayMenu: null
function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) {
if (currentTrayMenu) {
currentTrayMenu.destroy()
}
currentTrayMenu = trayMenuComponent.createObject(null)
if (currentTrayMenu) {
currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj)
}
}
}

View File

@@ -1,154 +0,0 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property bool hasUpdates: SystemUpdateService.updateCount > 0
readonly property bool isChecking: SystemUpdateService.isChecking
signal clicked()
width: isVertical ? widgetThickness : (updaterIcon.width + horizontalPadding * 2)
height: isVertical ? widgetThickness : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent";
}
const baseColor = updaterArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
DankIcon {
id: statusIcon
anchors.centerIn: parent
visible: root.isVertical
name: {
if (isChecking) return "refresh";
if (SystemUpdateService.hasError) return "error";
if (hasUpdates) return "system_update_alt";
return "check_circle";
}
size: Theme.iconSize - 6
color: {
if (SystemUpdateService.hasError) return Theme.error;
if (hasUpdates) return Theme.primary;
return (updaterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText);
}
RotationAnimation {
id: rotationAnimation
target: statusIcon
property: "rotation"
from: 0
to: 360
duration: 1000
running: isChecking
loops: Animation.Infinite
onRunningChanged: {
if (!running) {
statusIcon.rotation = 0
}
}
}
}
Rectangle {
width: 8
height: 8
radius: 4
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 6
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 6
visible: root.isVertical && root.hasUpdates && !root.isChecking
}
Row {
id: updaterIcon
anchors.centerIn: parent
spacing: Theme.spacingXS
visible: !root.isVertical
DankIcon {
id: statusIconHorizontal
anchors.verticalCenter: parent.verticalCenter
name: {
if (isChecking) return "refresh";
if (SystemUpdateService.hasError) return "error";
if (hasUpdates) return "system_update_alt";
return "check_circle";
}
size: Theme.iconSize - 6
color: {
if (SystemUpdateService.hasError) return Theme.error;
if (hasUpdates) return Theme.primary;
return (updaterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText);
}
RotationAnimation {
id: rotationAnimationHorizontal
target: statusIconHorizontal
property: "rotation"
from: 0
to: 360
duration: 1000
running: isChecking
loops: Animation.Infinite
onRunningChanged: {
if (!running) {
statusIconHorizontal.rotation = 0
}
}
}
}
StyledText {
id: countText
anchors.verticalCenter: parent.verticalCenter
text: SystemUpdateService.updateCount.toString()
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
visible: hasUpdates && !isChecking
}
}
MouseArea {
id: updaterArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.clicked();
}
}
}

View File

@@ -1,103 +0,0 @@
import QtQuick
import Quickshell
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property int widgetThickness: 28
property int barThickness: 32
property string section: "right"
property var popupTarget: null
property var parentScreen: null
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
signal toggleVpnPopup()
width: isVertical ? widgetThickness : (Theme.iconSize + horizontalPadding * 2)
height: isVertical ? (Theme.iconSize + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent";
}
const baseColor = clickArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
DankIcon {
id: icon
name: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
size: Theme.iconSize - 6
color: VpnService.connected ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
}
MouseArea {
id: clickArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.toggleVpnPopup();
}
onEntered: {
if (root.parentScreen && !(popupTarget && popupTarget.shouldBeVisible)) {
tooltipLoader.active = true
if (tooltipLoader.item) {
let tooltipText = ""
if (!VpnService.connected) {
tooltipText = "VPN Disconnected"
} else {
const names = VpnService.activeNames || []
if (names.length <= 1) {
tooltipText = "VPN Connected • " + (names[0] || "")
} else {
tooltipText = "VPN Connected • " + names[0] + " +" + (names.length - 1)
}
}
if (root.isVertical) {
const globalPos = mapToGlobal(width / 2, height / 2)
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0
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 isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
} else {
const globalPos = mapToGlobal(width / 2, height)
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS
tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
}
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide()
}
tooltipLoader.active = false
}
}
}

View File

@@ -13,33 +13,30 @@ DankPopout {
id: root
property bool dashVisible: false
property string triggerSection: "center"
property var triggerScreen: null
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)) {
if (section === "center") {
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
}
triggerY = y
triggerSection = section
triggerScreen = screen
}
popupWidth: 700
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
triggerY: Math.max(26 + SettingsData.topBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.topBarInnerPadding)) + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance
triggerWidth: 80
positioning: "center"
shouldBeVisible: dashVisible
visible: shouldBeVisible

File diff suppressed because it is too large Load Diff

View File

@@ -7,49 +7,22 @@ import qs.Common
import qs.Services
import qs.Widgets
pragma ComponentBehavior: Bound
PanelWindow {
id: dock
Variants {
id: dockVariants
model: SettingsData.getFilteredScreens("dock")
WlrLayershell.namespace: "quickshell:dock"
WlrLayershell.layer: WlrLayershell.Top
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
property var modelData
property var contextMenu
delegate: PanelWindow {
id: dock
WlrLayershell.namespace: "quickshell:dock"
anchors {
top: SettingsData.dockPosition === SettingsData.Position.Top
bottom: SettingsData.dockPosition === SettingsData.Position.Bottom
left: true
right: true
}
property var modelData: item
property bool autoHide: SettingsData.dockAutoHide
property real backgroundTransparency: SettingsData.dockTransparency
property bool groupByApp: SettingsData.dockGroupByApp
readonly property real widgetHeight: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
readonly property real effectiveBarHeight: Math.max(widgetHeight + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
readonly property real barSpacing: {
// Only add spacing if bar is visible, horizontal (Top/Bottom), and at same position as dock
const barIsHorizontal = (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)
const samePosition = (SettingsData.dockPosition === SettingsData.dankBarPosition)
return (SettingsData.dankBarVisible && barIsHorizontal && samePosition)
? (SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap)
: 0
}
readonly property real dockMargin: SettingsData.dockSpacing
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
function px(v) { return Math.round(v * _dpr) / _dpr }
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
property bool contextMenuOpen: (contextMenu && contextMenu.visible && contextMenu.screen === modelData)
property bool windowIsFullscreen: {
if (!ToplevelManager.activeToplevel) {
return false
@@ -58,28 +31,7 @@ Variants {
const fullscreenApps = ["vlc", "mpv", "kodi", "steam", "lutris", "wine", "dosbox"]
return fullscreenApps.some(app => activeWindow.appId && activeWindow.appId.toLowerCase().includes(app))
}
property bool revealSticky: false
Timer {
id: revealHold
interval: 250
repeat: false
onTriggered: dock.revealSticky = false
}
property bool reveal: {
if (CompositorService.isNiri && NiriService.inOverview) {
return SettingsData.dockOpenOnOverview
}
return (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky) && !windowIsFullscreen
}
onContextMenuOpenChanged: {
if (!contextMenuOpen && autoHide && !dockMouseArea.containsMouse) {
revealSticky = true
revealHold.restart()
}
}
property bool reveal: (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen) && !windowIsFullscreen
Connections {
target: SettingsData
@@ -92,124 +44,102 @@ Variants {
visible: SettingsData.showDock
color: "transparent"
exclusiveZone: {
if (!SettingsData.showDock || autoHide) return -1
if (barSpacing > 0) return -1
return px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap)
anchors {
bottom: true
left: true
right: true
}
margins {
left: 0
right: 0
}
implicitHeight: 100
exclusiveZone: autoHide ? -1 : 65 - 16
mask: Region {
item: dockMouseArea
}
Item {
id: dockCore
anchors.fill: parent
MouseArea {
id: dockMouseArea
property real currentScreen: modelData ? modelData : dock.screen
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
property real maxDockWidth: Math.min(screenWidth * 0.8, 1200)
Connections {
target: dockMouseArea
function onContainsMouseChanged() {
if (dockMouseArea.containsMouse) {
dock.revealSticky = true
revealHold.stop()
} else {
if (dock.autoHide && !dock.contextMenuOpen) {
revealHold.restart()
}
}
height: dock.reveal ? 65 : 20
width: dock.reveal ? Math.min(dockBackground.width + 32, maxDockWidth) : Math.min(Math.max(dockBackground.width + 64, 200), screenWidth * 0.5)
anchors {
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
}
hoverEnabled: true
Behavior on height {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
MouseArea {
id: dockMouseArea
property real currentScreen: modelData ? modelData : dock.screen
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
property real maxDockWidth: Math.min(screenWidth * 0.8, 1200)
Item {
id: dockContainer
anchors.fill: parent
height: dock.reveal ? px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) : 1
width: dock.reveal ? Math.min(dockBackground.implicitWidth + 32, maxDockWidth) : Math.min(Math.max(dockBackground.implicitWidth + 64, 200), screenWidth * 0.5)
anchors {
top: SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top
bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined
horizontalCenter: parent.horizontalCenter
}
hoverEnabled: true
acceptedButtons: Qt.NoButton
transform: Translate {
id: dockSlide
y: dock.reveal ? 0 : 60
Behavior on height {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
Behavior on y {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
Item {
id: dockContainer
anchors.fill: parent
transform: Translate {
id: dockSlide
y: {
if (dock.reveal) return 0
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
return 60
} else {
return -60
}
}
Behavior on y {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
Rectangle {
id: dockBackground
objectName: "dockBackground"
anchors {
top: parent.top
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
}
width: dockApps.implicitWidth + 12
height: parent.height - 8
anchors.topMargin: 4
anchors.bottomMargin: 1
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
radius: Theme.cornerRadius
border.width: 1
border.color: Theme.outlineMedium
layer.enabled: true
Rectangle {
id: dockBackground
objectName: "dockBackground"
anchors {
top: SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top
bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined
horizontalCenter: parent.horizontalCenter
}
anchors.topMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? 0 : barSpacing + 4
anchors.bottomMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + 1 : 0
implicitWidth: dockApps.implicitWidth + SettingsData.dockSpacing * 2
implicitHeight: dockApps.implicitHeight + SettingsData.dockSpacing * 2
width: implicitWidth
height: implicitHeight
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
radius: Theme.cornerRadius
border.width: 1
border.color: Theme.outlineMedium
layer.enabled: true
Rectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
radius: parent.radius
}
DockApps {
id: dockApps
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: SettingsData.dockSpacing
anchors.bottomMargin: SettingsData.dockSpacing
contextMenu: dockVariants.contextMenu
groupByApp: dock.groupByApp
}
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
radius: parent.radius
}
DockApps {
id: dockApps
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 4
anchors.bottomMargin: 4
contextMenu: dock.contextMenu
groupByApp: dock.groupByApp
}
}
Rectangle {
id: appTooltip
@@ -241,15 +171,15 @@ Variants {
property string tooltipText: hoveredButton ? hoveredButton.tooltipText : ""
visible: hoveredButton !== null && tooltipText !== ""
width: px(tooltipLabel.implicitWidth + 24)
height: px(tooltipLabel.implicitHeight + 12)
width: tooltipLabel.implicitWidth + 24
height: tooltipLabel.implicitHeight + 12
color: Theme.surfaceContainer
radius: Theme.cornerRadius
border.width: 1
border.color: Theme.outlineMedium
y: SettingsData.dockPosition === SettingsData.Position.Bottom ? -height - Theme.spacingS : parent.height + Theme.spacingS
y: -height - 8
x: hoveredButton ? hoveredButton.mapToItem(dockContainer, hoveredButton.width / 2, 0).x - width / 2 : 0
StyledText {
@@ -261,7 +191,5 @@ Variants {
}
}
}
}
}
}
}

View File

@@ -25,27 +25,6 @@ Item {
property string windowTitle: ""
property bool isHovered: mouseArea.containsMouse && !dragging
property bool showTooltip: mouseArea.containsMouse && !dragging
property var cachedDesktopEntry: null
function updateDesktopEntry() {
if (!appData || appData.appId === "__SEPARATOR__") {
cachedDesktopEntry = null
return
}
const moddedId = Paths.moddedAppId(appData.appId)
cachedDesktopEntry = DesktopEntries.heuristicLookup(moddedId)
}
Component.onCompleted: updateDesktopEntry()
onAppDataChanged: updateDesktopEntry()
Connections {
target: DesktopEntries
function onApplicationsChanged() {
updateDesktopEntry()
}
}
property bool isWindowFocused: {
if (!appData) {
return false
@@ -76,7 +55,8 @@ Item {
}
if ((appData.type === "window" && showWindowTitle) || (appData.type === "grouped" && appData.windowTitle)) {
const appName = cachedDesktopEntry && cachedDesktopEntry.name ? cachedDesktopEntry.name : appData.appId
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
const appName = desktopEntry && desktopEntry.name ? desktopEntry.name : appData.appId
const title = appData.type === "window" ? windowTitle : appData.windowTitle
return appName + (title ? " • " + title : "")
}
@@ -85,7 +65,8 @@ Item {
return ""
}
return cachedDesktopEntry && cachedDesktopEntry.name ? cachedDesktopEntry.name : appData.appId
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
return desktopEntry && desktopEntry.name ? desktopEntry.name : appData.appId
}
width: 40
@@ -274,7 +255,7 @@ Item {
if (mouse.button === Qt.LeftButton) {
if (appData.type === "pinned") {
if (appData && appData.appId) {
const desktopEntry = cachedDesktopEntry
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
@@ -294,7 +275,7 @@ Item {
} else if (appData.type === "grouped") {
if (appData.windowCount === 0) {
if (appData && appData.appId) {
const desktopEntry = cachedDesktopEntry
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
@@ -324,7 +305,7 @@ Item {
}
} else if (mouse.button === Qt.MiddleButton) {
if (appData && appData.appId) {
const desktopEntry = cachedDesktopEntry
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
@@ -360,7 +341,8 @@ Item {
if (moddedId.toLowerCase().includes("steam_app")) {
return ""
}
return cachedDesktopEntry && cachedDesktopEntry.icon ? Quickshell.iconPath(cachedDesktopEntry.icon, true) : ""
const desktopEntry = DesktopEntries.heuristicLookup(moddedId)
return desktopEntry && desktopEntry.icon ? Quickshell.iconPath(desktopEntry.icon, true) : ""
}
mipmap: true
smooth: true
@@ -399,7 +381,7 @@ Item {
return "?"
}
const desktopEntry = cachedDesktopEntry
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry && desktopEntry.name) {
return desktopEntry.name.charAt(0).toUpperCase()
}

View File

@@ -35,7 +35,7 @@ Item {
Row {
id: row
spacing: 8
spacing: 2
anchors.centerIn: parent
height: 40

View File

@@ -96,15 +96,8 @@ PanelWindow {
actualDockHeight = dockBackground.height
}
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
const dockBottomMargin = 16
let buttonScreenY
if (isDockAtBottom) {
buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20
} else {
buttonScreenY = actualDockHeight + dockBottomMargin + 20
}
const buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20
const dockContentWidth = dockWindow.width
const screenWidth = root.screen.width
@@ -126,14 +119,7 @@ PanelWindow {
const want = root.anchorPos.x - width / 2
return Math.max(left, Math.min(right, want))
}
y: {
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
if (isDockAtBottom) {
return Math.max(10, root.anchorPos.y - height + 30)
} else {
return Math.min(root.height - height - 10, root.anchorPos.y - 30)
}
}
y: Math.max(10, root.anchorPos.y - height + 30)
color: Theme.popupBackground()
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)

View File

@@ -63,7 +63,7 @@ Column {
width: calculatedWidth
height: 32
radius: Theme.cornerRadius
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0)
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent"
border.width: isActive ? 0 : 1
border.color: Theme.outlineMedium
@@ -104,7 +104,7 @@ Column {
width: 20
height: 20
radius: 10
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : "transparent"
visible: NotepadStorageService.tabs.length > 1
anchors.verticalCenter: parent.verticalCenter

View File

@@ -13,6 +13,7 @@ DankPopout {
id: root
property bool notificationHistoryVisible: false
property string triggerSection: "right"
property var triggerScreen: null
NotificationKeyboardController {
@@ -34,10 +35,10 @@ DankPopout {
popupWidth: 400
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
triggerX: 0
triggerY: 0
triggerX: Screen.width - 400 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.popupDistance
triggerWidth: 40
positioning: ""
positioning: "center"
screen: triggerScreen
shouldBeVisible: notificationHistoryVisible
visible: shouldBeVisible

View File

@@ -411,78 +411,6 @@ QtObject {
selectPrevious()
event.accepted = true
}
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
if (!keyboardNavigationActive) {
keyboardNavigationActive = true
rebuildFlatNavigation()
selectedFlatIndex = 0
updateSelectedIdFromIndex()
if (listView) {
listView.keyboardActive = true
}
selectionVersion++
ensureVisible()
} else {
selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
if (!keyboardNavigationActive) {
keyboardNavigationActive = true
rebuildFlatNavigation()
selectedFlatIndex = 0
updateSelectedIdFromIndex()
if (listView) {
listView.keyboardActive = true
}
selectionVersion++
ensureVisible()
} else if (selectedFlatIndex === 0) {
keyboardNavigationActive = false
if (listView) {
listView.keyboardActive = false
}
selectionVersion++
} else {
selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
if (!keyboardNavigationActive) {
keyboardNavigationActive = true
rebuildFlatNavigation()
selectedFlatIndex = 0
updateSelectedIdFromIndex()
if (listView) {
listView.keyboardActive = true
}
selectionVersion++
ensureVisible()
} else {
selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
if (!keyboardNavigationActive) {
keyboardNavigationActive = true
rebuildFlatNavigation()
selectedFlatIndex = 0
updateSelectedIdFromIndex()
if (listView) {
listView.keyboardActive = true
}
selectionVersion++
ensureVisible()
} else if (selectedFlatIndex === 0) {
keyboardNavigationActive = false
if (listView) {
listView.keyboardActive = false
}
selectionVersion++
} else {
selectPrevious()
}
event.accepted = true
} else if (keyboardNavigationActive) {
if (event.key === Qt.Key_Space) {
toggleGroupExpanded()
@@ -497,10 +425,7 @@ QtObject {
clearSelected()
event.accepted = true
} else if (event.key === Qt.Key_Tab) {
selectNext()
event.accepted = true
} else if (event.key === Qt.Key_Backtab) {
selectPrevious()
selectNextWrapping()
event.accepted = true
} else if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) {
const actionIndex = event.key - Qt.Key_1

View File

@@ -76,6 +76,7 @@ PanelWindow {
color: "transparent"
implicitWidth: 400
implicitHeight: 122
onScreenYChanged: margins.top = Theme.barHeight - 4 + SettingsData.topBarSpacing + 4 + screenY
onHasValidDataChanged: {
if (!hasValidData && !exiting && !_isDestroying) {
forceExit()
@@ -107,94 +108,14 @@ PanelWindow {
}
}
property bool isTopCenter: SettingsData.notificationPopupPosition === -1
anchors.top: isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left
anchors.bottom: SettingsData.notificationPopupPosition === SettingsData.Position.Bottom || SettingsData.notificationPopupPosition === SettingsData.Position.Right
anchors.left: SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
anchors.right: SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Right
anchors {
top: true
right: true
}
margins {
top: getTopMargin()
bottom: getBottomMargin()
left: getLeftMargin()
right: getRightMargin()
}
function getTopMargin() {
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left
if (!isTop) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
let base = Theme.popupDistance
if (barPos === SettingsData.Position.Top) {
base = exclusiveZone
}
return base + screenY
}
function getBottomMargin() {
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right
if (!isBottom) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
let base = Theme.popupDistance
if (barPos === SettingsData.Position.Bottom) {
base = exclusiveZone
}
return base + screenY
}
function getLeftMargin() {
if (isTopCenter) {
return (screen.width - implicitWidth) / 2
}
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom
if (!isLeft) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
if (barPos === SettingsData.Position.Left) {
return exclusiveZone
}
return Theme.popupDistance
}
function getRightMargin() {
if (isTopCenter) return 0
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right
if (!isRight) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
if (barPos === SettingsData.Position.Right) {
return exclusiveZone
}
return Theme.popupDistance
top: Theme.barHeight - 4 + SettingsData.topBarSpacing + 4
right: 12
}
Item {
@@ -202,7 +123,7 @@ PanelWindow {
anchors.fill: parent
visible: win.hasValidData
layer.enabled: true
layer.enabled: (enterX.running || exitAnim.running)
layer.smooth: true
Rectangle {
@@ -534,12 +455,7 @@ PanelWindow {
transform: Translate {
id: tx
x: {
if (isTopCenter) return 0
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
return isLeft ? -Anims.slidePx : Anims.slidePx
}
y: isTopCenter ? -Anims.slidePx : 0
x: Anims.slidePx
}
}
@@ -547,23 +463,15 @@ PanelWindow {
id: enterX
target: tx
property: isTopCenter ? "y" : "x"
from: {
if (isTopCenter) return -Anims.slidePx
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
return isLeft ? -Anims.slidePx : Anims.slidePx
}
property: "x"
from: Anims.slidePx
to: 0
duration: Anims.durMed
easing.type: Easing.BezierSpline
easing.bezierCurve: isTopCenter ? Anims.standardDecel : Anims.emphasizedDecel
easing.bezierCurve: Anims.emphasizedDecel
onStopped: {
if (!win.exiting && !win._isDestroying) {
if (isTopCenter) {
if (Math.abs(tx.y) < 0.5) win.entered()
} else {
if (Math.abs(tx.x) < 0.5) win.entered()
}
if (!win.exiting && !win._isDestroying && Math.abs(tx.x) < 0.5) {
win.entered()
}
}
}
@@ -575,13 +483,9 @@ PanelWindow {
PropertyAnimation {
target: tx
property: isTopCenter ? "y" : "x"
property: "x"
from: 0
to: {
if (isTopCenter) return -Anims.slidePx
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
return isLeft ? -Anims.slidePx : Anims.slidePx
}
to: Anims.slidePx
duration: Anims.durShort
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasizedAccel

View File

@@ -12,24 +12,12 @@ DankOSD {
enableMouseInteraction: true
Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
target: AudioService
function onVolumeChanged() {
if (!AudioService.suppressOSD) {
root.show()
}
root.show()
}
function onMutedChanged() {
if (!AudioService.suppressOSD) {
root.show()
}
}
}
Connections {
target: AudioService
function onSinkChanged() {
if (root.shouldBeVisible) {
root.show()

View File

@@ -12,8 +12,8 @@ Rectangle {
width: parent ? parent.width : 0
height: 40
radius: Theme.cornerRadius
color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.withAlpha(Theme.primary, 0)
border.color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
border.color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
border.width: 1
MouseArea {
@@ -158,7 +158,7 @@ Rectangle {
width: 28
height: 28
radius: Theme.cornerRadius
color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0)
color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter

View File

@@ -15,6 +15,7 @@ DankPopout {
id: processListPopout
property var parentWidget: null
property string triggerSection: "right"
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
@@ -39,9 +40,9 @@ DankPopout {
popupWidth: 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
triggerY: Math.max(26 + SettingsData.topBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.topBarInnerPadding)) + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance
triggerWidth: 55
positioning: ""
positioning: "center"
screen: triggerScreen
visible: shouldBeVisible
shouldBeVisible: false

View File

@@ -30,7 +30,7 @@ Column {
if (DgopService.currentSort === "name") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
}
return processHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
return processHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
}
radius: Theme.cornerRadius
anchors.left: parent.left
@@ -74,7 +74,7 @@ Column {
if (DgopService.currentSort === "cpu") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
}
return cpuHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
return cpuHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
}
radius: Theme.cornerRadius
anchors.right: parent.right
@@ -118,7 +118,7 @@ Column {
if (DgopService.currentSort === "memory") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
}
return memoryHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
return memoryHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
}
radius: Theme.cornerRadius
anchors.right: parent.right
@@ -162,7 +162,7 @@ Column {
if (DgopService.currentSort === "pid") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
}
return pidHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
return pidHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
}
radius: Theme.cornerRadius
anchors.right: parent.right
@@ -204,7 +204,7 @@ Column {
width: 28
height: 28
radius: Theme.cornerRadius
color: sortOrderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0)
color: sortOrderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
anchors.right: parent.right
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter

View File

@@ -10,8 +10,8 @@ Item {
id: displaysTab
property var variantComponents: [{
"id": "dankBar",
"name": "Dank Bar",
"id": "topBar",
"name": "Top Bar",
"description": "System bar with widgets and system information",
"icon": "toolbar"
}, {

View File

@@ -2,7 +2,6 @@ import QtQuick
import QtQuick.Controls
import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Widgets
Item {
@@ -20,10 +19,10 @@ Item {
width: parent.width
spacing: Theme.spacingXL
// Dock Position
// Enable Dock
StyledRect {
width: parent.width
height: dockPositionSection.implicitHeight + Theme.spacingL * 2
height: enableDockSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
@@ -31,7 +30,7 @@ Item {
border.width: 0
Column {
id: dockPositionSection
id: enableDockSection
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -42,53 +41,61 @@ Item {
spacing: Theme.spacingM
DankIcon {
name: "swap_vert"
name: "dock_to_bottom"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
id: positionText
text: "Dock Position"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
Column {
width: parent.width - Theme.iconSize - Theme.spacingM
- enableToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - Theme.iconSize - Theme.spacingM - positionText.width - positionButtonGroup.width - Theme.spacingM * 2
anchors.verticalCenter: parent.verticalCenter
}
DankButtonGroup {
id: positionButtonGroup
anchors.verticalCenter: parent.verticalCenter
model: ["Top", "Bottom"]
currentIndex: SettingsData.dockPosition === SettingsData.Position.Bottom ? 1 : 0
onSelectionChanged: (index, selected) => {
if (selected) {
SettingsData.setDockPosition(index === 1 ? SettingsData.Position.Bottom : SettingsData.Position.Top)
}
StyledText {
text: "Show Dock"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display a dock at the bottom of the screen with pinned and running applications"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: enableToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.showDock
onToggled: checked => {
SettingsData.setShowDock(checked)
}
}
}
}
}
// Dock Visibility Section
// Auto-hide Dock
StyledRect {
width: parent.width
height: dockVisibilitySection.implicitHeight + Theme.spacingL * 2
height: autoHideSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 0
visible: SettingsData.showDock
opacity: visible ? 1 : 0
Column {
id: dockVisibilitySection
id: autoHideSection
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -119,7 +126,7 @@ Item {
}
StyledText {
text: "Hide the dock when not in use and reveal it when hovering near the dock area"
text: "Hide the dock when not in use and reveal it when hovering near the bottom of the screen"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
@@ -137,109 +144,12 @@ Item {
}
}
}
}
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.2
}
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "dock_to_bottom"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM
- enableToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Show Dock"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display a dock with pinned and running applications that can be positioned at the top or bottom of the screen"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: enableToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.showDock
onToggled: checked => {
SettingsData.setShowDock(checked)
}
}
}
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.2
visible: CompositorService.isNiri
}
Row {
width: parent.width
spacing: Theme.spacingM
visible: CompositorService.isNiri
DankIcon {
name: "fullscreen"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM
- overviewToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Show on Overview"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Always show the dock when niri's overview is open"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: overviewToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.dockOpenOnOverview
onToggled: checked => {
SettingsData.setDockOpenOnOverview(checked)
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
@@ -316,110 +226,6 @@ Item {
}
}
// Dock Spacing Section
StyledRect {
width: parent.width
height: dockSpacingSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 0
visible: SettingsData.showDock
opacity: visible ? 1 : 0
Column {
id: dockSpacingSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "space_bar"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Spacing"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Padding"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: SettingsData.dockSpacing
minimum: 0
maximum: 32
unit: ""
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.surfaceContainerHigh
onSliderValueChanged: newValue => {
SettingsData.setDockSpacing(
newValue)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Height to Edge Gap (Exclusive Zone)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: SettingsData.dockBottomGap
minimum: -100
maximum: 100
unit: ""
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.surfaceContainerHigh
onSliderValueChanged: newValue => {
SettingsData.setDockBottomGap(
newValue)
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
// Dock Transparency Section
StyledRect {
width: parent.width

View File

@@ -1,181 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Item {
id: keybindsTab
property var parentModal: null
ListModel {
id: bindingsModel
}
function addBinding() {
console.log("Adding binding, current count:", bindingsModel.count)
bindingsModel.append({
token: "",
configType: "dms",
actionName: "",
args: [],
shellCmd: "",
repeatEnabled: true,
cooldownMs: 0,
allowWhenLocked: false,
overlayTitle: ""
})
console.log("After append, count:", bindingsModel.count)
}
function removeBinding(index) {
bindingsModel.remove(index)
}
function exportBindings() {
const lines = []
for (let i = 0; i < bindingsRepeater.count; i++) {
const item = bindingsRepeater.itemAt(i)
if (item) {
const line = item.toConfigLine()
if (line) {
const existingToken = line.split(" {")[0].trim()
const duplicate = lines.some(l => l.split(" {")[0].trim() === existingToken)
if (duplicate) {
console.warn("Duplicate binding found:", existingToken)
}
lines.push(line)
}
}
}
const block = "binds {\n " + lines.join("\n ") + "\n}\n"
console.log("Exported bindings block:")
console.log(block)
return block
}
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingL
StyledRect {
width: parent.width
height: headerSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.width: 0
Row {
id: headerSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
DankIcon {
name: "keyboard"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - addButton.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Key Bindings Editor"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Configure keyboard shortcuts, mouse bindings, and scroll gestures"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankActionButton {
id: addButton
width: 40
height: 40
circular: false
iconName: "add"
iconSize: Theme.iconSize
iconColor: Theme.primary
anchors.verticalCenter: parent.verticalCenter
onClicked: keybindsTab.addBinding()
}
}
}
Column {
width: parent.width
spacing: Theme.spacingM
StyledText {
text: "Bindings count: " + bindingsModel.count
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: bindingsModel.count === 0
}
Repeater {
id: bindingsRepeater
model: bindingsModel
delegate: KeybindRow {
width: parent.width
token: model.token || ""
configType: model.configType || "dms"
actionName: model.actionName || ""
args: model.args || []
shellCmd: model.shellCmd || ""
repeatEnabled: model.repeatEnabled ?? true
cooldownMs: model.cooldownMs || 0
allowWhenLocked: model.allowWhenLocked ?? false
overlayTitle: model.overlayTitle || ""
panelWindow: keybindsTab.parentModal
onRemoveRequested: keybindsTab.removeBinding(index)
onChanged: {
bindingsModel.set(index, {
token: token,
configType: configType,
actionName: actionName,
args: args,
shellCmd: shellCmd,
repeatEnabled: repeatEnabled,
cooldownMs: cooldownMs,
allowWhenLocked: allowWhenLocked,
overlayTitle: overlayTitle
})
}
}
}
}
Item {
width: parent.width
height: Theme.spacingXL
}
}
}
Component.onCompleted: {
addBinding()
}
}

View File

@@ -15,6 +15,7 @@ Item {
property alias wallpaperBrowser: wallpaperBrowser
property var parentModal: null
property var cachedFontFamilies: []
property var cachedMonoFamilies: []
property bool fontsEnumerated: false
property string selectedMonitorName: {
var screens = Quickshell.screens
@@ -44,6 +45,28 @@ Item {
}
}
cachedFontFamilies = fonts.concat(rootFamilies.sort())
var monoFonts = ["Default"]
var monoFamilies = []
var seenMonoFamilies = new Set()
for (var j = 0; j < availableFonts.length; j++) {
var fontName2 = availableFonts[j]
if (fontName2.startsWith("."))
continue
if (fontName2 === SettingsData.defaultMonoFontFamily)
continue
var lowerName = fontName2.toLowerCase()
if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes(
"jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) {
var rootName2 = fontName2.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim()
if (!seenMonoFamilies.has(rootName2) && rootName2 !== "") {
seenMonoFamilies.add(rootName2)
monoFamilies.push(rootName2)
}
}
}
cachedMonoFamilies = monoFonts.concat(monoFamilies.sort())
}
Component.onCompleted: {
@@ -391,63 +414,6 @@ Item {
}
}
// Per-Mode Wallpaper Section - Full Width
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.2
visible: SessionData.wallpaperPath !== ""
}
Column {
width: parent.width
spacing: Theme.spacingM
visible: SessionData.wallpaperPath !== ""
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "brightness_6"
size: Theme.iconSize
color: SessionData.perModeWallpaper ? Theme.primary : Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - perModeToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Per-Mode Wallpapers"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Set different wallpapers for light and dark mode"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
}
}
DankToggle {
id: perModeToggle
anchors.verticalCenter: parent.verticalCenter
checked: SessionData.perModeWallpaper
onToggled: toggled => {
return SessionData.setPerModeWallpaper(toggled)
}
}
}
}
// Per-Monitor Wallpaper Section - Full Width
Rectangle {
width: parent.width
@@ -539,18 +505,19 @@ Item {
}
}
// Wallpaper Cycling Section - Full Width
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.2
visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper
visible: SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper
}
Column {
width: parent.width
spacing: Theme.spacingM
visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper
visible: SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper
Row {
width: parent.width
@@ -607,6 +574,7 @@ Item {
}
}
// Cycling mode and settings
Column {
width: parent.width
spacing: Theme.spacingS
@@ -1040,8 +1008,7 @@ Item {
text: "Light Mode"
description: "Use light theme instead of dark theme"
checked: SessionData.isLightMode
onToggleCompleted: checked => {
Theme.screenTransition()
onToggled: checked => {
Theme.setLightMode(checked)
}
}
@@ -1387,17 +1354,17 @@ Item {
}
}
// Notification Popup Settings
// Lock Screen Settings
StyledRect {
width: parent.width
height: notificationPopupSection.implicitHeight + Theme.spacingL * 2
height: lockScreenSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 0
Column {
id: notificationPopupSection
id: lockScreenSection
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -1408,14 +1375,14 @@ Item {
spacing: Theme.spacingM
DankIcon {
name: "notifications"
name: "lock"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Notification Popups"
text: "Lock Screen"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
@@ -1423,48 +1390,14 @@ Item {
}
}
DankDropdown {
DankToggle {
width: parent.width
text: "Popup Position"
description: "Choose where notification popups appear on screen"
currentValue: {
if (SettingsData.notificationPopupPosition === -1) {
return "Top Center"
}
switch (SettingsData.notificationPopupPosition) {
case SettingsData.Position.Top:
return "Top Right"
case SettingsData.Position.Bottom:
return "Bottom Left"
case SettingsData.Position.Left:
return "Top Left"
case SettingsData.Position.Right:
return "Bottom Right"
default:
return "Top Right"
}
}
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left"]
onValueChanged: value => {
switch (value) {
case "Top Right":
SettingsData.setNotificationPopupPosition(SettingsData.Position.Top)
break
case "Top Left":
SettingsData.setNotificationPopupPosition(SettingsData.Position.Left)
break
case "Top Center":
SettingsData.setNotificationPopupPosition(-1)
break
case "Bottom Right":
SettingsData.setNotificationPopupPosition(SettingsData.Position.Right)
break
case "Bottom Left":
SettingsData.setNotificationPopupPosition(SettingsData.Position.Bottom)
break
}
SettingsData.sendTestNotifications()
}
text: "Show Power Actions"
description: "Show power, restart, and logout buttons on the lock screen"
checked: SettingsData.lockScreenShowPowerActions
onToggled: checked => {
SettingsData.setLockScreenShowPowerActions(checked)
}
}
}
}
@@ -1607,7 +1540,7 @@ Item {
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 400
options: cachedFontFamilies
options: cachedMonoFamilies
onValueChanged: value => {
if (value === "Default")
SettingsData.setMonoFontFamily(SettingsData.defaultMonoFontFamily)
@@ -1701,125 +1634,6 @@ Item {
}
}
}
// Animation Settings
StyledRect {
width: parent.width
height: animationSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 0
Column {
id: animationSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "animation"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Animations"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Animation Speed"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: "Control the speed of animations throughout the interface"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
DankButtonGroup {
id: animationSpeedGroup
width: parent.width
model: ["None", "Shortest", "Short", "Medium", "Long"]
selectionMode: "single"
currentIndex: SettingsData.animationSpeed
onSelectionChanged: (index, selected) => {
if (selected) {
SettingsData.setAnimationSpeed(index)
}
}
}
}
}
}
// Lock Screen Settings
StyledRect {
width: parent.width
height: lockScreenSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 0
Column {
id: lockScreenSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "lock"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Lock Screen"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Show Power Actions"
description: "Show power, restart, and logout buttons on the lock screen"
checked: SettingsData.lockScreenShowPowerActions
onToggled: checked => {
SettingsData.setLockScreenShowPowerActions(checked)
}
}
}
}
}
}

View File

@@ -226,7 +226,6 @@ Item {
if (Theme.currentThemeCategory === "catppuccin") return 1
return 0
}
property int pendingThemeIndex: -1
model: ["Generic", "Catppuccin", "Auto", "Custom"]
currentIndex: currentThemeIndex
@@ -234,11 +233,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
onSelectionChanged: (index, selected) => {
if (!selected) return
pendingThemeIndex = index
}
onAnimationCompleted: {
if (pendingThemeIndex === -1) return
switch (pendingThemeIndex) {
switch (index) {
case 0: Theme.switchThemeCategory("generic", "blue"); break
case 1: Theme.switchThemeCategory("catppuccin", "cat-mauve"); break
case 2:
@@ -247,15 +242,14 @@ Item {
else if (ToastService.wallpaperErrorStatus === "error")
ToastService.showError("Wallpaper processing failed - check wallpaper path")
else
Theme.switchTheme(Theme.dynamic, true, true)
Theme.switchTheme(Theme.dynamic, true, false)
break
case 3:
if (Theme.currentThemeName !== "custom") {
Theme.switchTheme("custom", true, true)
Theme.switchTheme("custom", true, false)
}
break
}
pendingThemeIndex = -1
}
}
@@ -770,7 +764,7 @@ Item {
spacing: Theme.spacingS
StyledText {
text: "Dank Bar Transparency"
text: "Top Bar Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
@@ -780,7 +774,7 @@ Item {
width: parent.width
height: 24
value: Math.round(
SettingsData.dankBarTransparency * 100)
SettingsData.topBarTransparency * 100)
minimum: 0
maximum: 100
unit: ""
@@ -788,7 +782,7 @@ Item {
wheelEnabled: false
thumbOutlineColor: Theme.surfaceContainerHigh
onSliderValueChanged: newValue => {
SettingsData.setDankBarTransparency(
SettingsData.setTopBarTransparency(
newValue / 100)
}
}
@@ -804,7 +798,7 @@ Item {
StyledText {
id: transparencyLabel
text: "Dank Bar Widget Transparency"
text: "Top Bar Widget Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
@@ -849,7 +843,7 @@ Item {
width: parent.width
height: 24
value: Math.round(
SettingsData.dankBarWidgetTransparency * 100)
SettingsData.topBarWidgetTransparency * 100)
minimum: 0
maximum: 100
unit: ""
@@ -857,7 +851,7 @@ Item {
wheelEnabled: false
thumbOutlineColor: Theme.surfaceContainerHigh
onSliderValueChanged: newValue => {
SettingsData.setDankBarWidgetTransparency(
SettingsData.setTopBarWidgetTransparency(
newValue / 100)
}
}

View File

@@ -1,717 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Item {
id: timeWeatherTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
StyledRect {
width: parent.width
height: timeSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.width: 0
Column {
id: timeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "schedule"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - toggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "24-Hour Format"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Use 24-hour time format instead of 12-hour AM/PM"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: toggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.use24HourClock
onToggled: checked => {
return SettingsData.setClockFormat(checked)
}
}
}
}
}
StyledRect {
width: parent.width
height: dateSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.width: 0
Column {
id: dateSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "calendar_today"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Date Format"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankDropdown {
width: parent.width
height: 50
text: "Top Bar Format"
description: "Preview: " + (SettingsData.clockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat) : new Date().toLocaleDateString(Qt.locale(), "ddd d"))
currentValue: {
if (!SettingsData.clockDateFormat || SettingsData.clockDateFormat.length === 0) {
return "System Default"
}
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}]
const match = presets.find(p => {
return p.format === SettingsData.clockDateFormat
})
return match ? match.label : "Custom: " + SettingsData.clockDateFormat
}
options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: value => {
const formatMap = {
"System Default": "",
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
}
if (value === "Custom...") {
customFormatInput.visible = true
} else {
customFormatInput.visible = false
SettingsData.setClockDateFormat(formatMap[value])
}
}
}
DankDropdown {
width: parent.width
height: 50
text: "Lock Screen Format"
description: "Preview: " + (SettingsData.lockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat) : new Date().toLocaleDateString(Qt.locale(), Locale.LongFormat))
currentValue: {
if (!SettingsData.lockDateFormat || SettingsData.lockDateFormat.length === 0) {
return "System Default"
}
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}]
const match = presets.find(p => {
return p.format === SettingsData.lockDateFormat
})
return match ? match.label : "Custom: " + SettingsData.lockDateFormat
}
options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: value => {
const formatMap = {
"System Default": "",
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
}
if (value === "Custom...") {
customLockFormatInput.visible = true
} else {
customLockFormatInput.visible = false
SettingsData.setLockDateFormat(formatMap[value])
}
}
}
DankTextField {
id: customFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom top bar format (e.g., ddd MMM d)"
text: SettingsData.clockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setClockDateFormat(text)
}
}
DankTextField {
id: customLockFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom lock screen format (e.g., dddd, MMMM d)"
text: SettingsData.lockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setLockDateFormat(text)
}
}
Rectangle {
width: parent.width
height: formatHelp.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
border.width: 0
Column {
id: formatHelp
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: "Format Legend"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Medium
}
Row {
width: parent.width
spacing: Theme.spacingL
Column {
width: (parent.width - Theme.spacingL) / 2
spacing: 2
StyledText {
text: "• d - Day (1-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dd - Day (01-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• ddd - Day name (Mon)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dddd - Day name (Monday)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• M - Month (1-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
width: (parent.width - Theme.spacingL) / 2
spacing: 2
StyledText {
text: "• MM - Month (01-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMM - Month (Jan)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMMM - Month (January)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• yy - Year (24)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• yyyy - Year (2024)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
}
}
}
}
StyledRect {
width: parent.width
height: enableWeatherSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.width: 0
Column {
id: enableWeatherSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "cloud"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - enableToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Enable Weather"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Show weather information in top bar and control center"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: enableToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.weatherEnabled
onToggled: checked => {
return SettingsData.setWeatherEnabled(checked)
}
}
}
}
}
StyledRect {
width: parent.width
height: temperatureSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.width: 0
visible: SettingsData.weatherEnabled
opacity: visible ? 1 : 0
Column {
id: temperatureSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "thermostat"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - temperatureToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Use Fahrenheit"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Use Fahrenheit instead of Celsius for temperature"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: temperatureToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.useFahrenheit
onToggled: checked => {
return SettingsData.setTemperatureUnit(checked)
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
StyledRect {
width: parent.width
height: locationSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.width: 0
visible: SettingsData.weatherEnabled
opacity: visible ? 1 : 0
Column {
id: locationSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "location_on"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - autoLocationToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Auto Location"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Automatically determine your location using your IP address"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: autoLocationToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.useAutoLocation
onToggled: checked => {
return SettingsData.setAutoLocation(checked)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
visible: !SettingsData.useAutoLocation
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.2
}
StyledText {
text: "Custom Location"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
Row {
width: parent.width
spacing: Theme.spacingM
Column {
width: (parent.width - Theme.spacingM) / 2
spacing: Theme.spacingXS
StyledText {
text: "Latitude"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: latitudeInput
width: parent.width
height: 48
placeholderText: "40.7128"
backgroundColor: Theme.surfaceVariant
normalBorderColor: Theme.primarySelected
focusedBorderColor: Theme.primary
keyNavigationTab: longitudeInput
Component.onCompleted: {
if (SettingsData.weatherCoordinates) {
const coords = SettingsData.weatherCoordinates.split(',')
if (coords.length > 0) {
text = coords[0].trim()
}
}
}
Connections {
target: SettingsData
function onWeatherCoordinatesChanged() {
if (SettingsData.weatherCoordinates) {
const coords = SettingsData.weatherCoordinates.split(',')
if (coords.length > 0) {
latitudeInput.text = coords[0].trim()
}
}
}
}
onTextEdited: {
if (text && longitudeInput.text) {
const coords = text + "," + longitudeInput.text
SettingsData.weatherCoordinates = coords
SettingsData.saveSettings()
}
}
}
}
Column {
width: (parent.width - Theme.spacingM) / 2
spacing: Theme.spacingXS
StyledText {
text: "Longitude"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: longitudeInput
width: parent.width
height: 48
placeholderText: "-74.0060"
backgroundColor: Theme.surfaceVariant
normalBorderColor: Theme.primarySelected
focusedBorderColor: Theme.primary
keyNavigationTab: locationSearchInput
keyNavigationBacktab: latitudeInput
Component.onCompleted: {
if (SettingsData.weatherCoordinates) {
const coords = SettingsData.weatherCoordinates.split(',')
if (coords.length > 1) {
text = coords[1].trim()
}
}
}
Connections {
target: SettingsData
function onWeatherCoordinatesChanged() {
if (SettingsData.weatherCoordinates) {
const coords = SettingsData.weatherCoordinates.split(',')
if (coords.length > 1) {
longitudeInput.text = coords[1].trim()
}
}
}
}
onTextEdited: {
if (text && latitudeInput.text) {
const coords = latitudeInput.text + "," + text
SettingsData.weatherCoordinates = coords
SettingsData.saveSettings()
}
}
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Location Search"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
font.weight: Font.Medium
}
DankLocationSearch {
id: locationSearchInput
width: parent.width
currentLocation: ""
placeholderText: "New York, NY"
keyNavigationBacktab: longitudeInput
onLocationSelected: (displayName, coordinates) => {
SettingsData.setWeatherLocation(displayName, coordinates)
const coords = coordinates.split(',')
if (coords.length >= 2) {
latitudeInput.text = coords[0].trim()
longitudeInput.text = coords[1].trim()
}
}
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}

View File

@@ -6,7 +6,7 @@ import qs.Services
import qs.Widgets
Item {
id: dankBarTab
id: topBarTab
property var baseWidgetDefinitions: [{
"id": "launcherButton",
@@ -236,51 +236,51 @@ Item {
var widgets = []
if (targetSection === "left") {
widgets = SettingsData.dankBarLeftWidgets.slice()
widgets = SettingsData.topBarLeftWidgets.slice()
widgets.push(widgetObj)
SettingsData.setDankBarLeftWidgets(widgets)
SettingsData.setTopBarLeftWidgets(widgets)
} else if (targetSection === "center") {
widgets = SettingsData.dankBarCenterWidgets.slice()
widgets = SettingsData.topBarCenterWidgets.slice()
widgets.push(widgetObj)
SettingsData.setDankBarCenterWidgets(widgets)
SettingsData.setTopBarCenterWidgets(widgets)
} else if (targetSection === "right") {
widgets = SettingsData.dankBarRightWidgets.slice()
widgets = SettingsData.topBarRightWidgets.slice()
widgets.push(widgetObj)
SettingsData.setDankBarRightWidgets(widgets)
SettingsData.setTopBarRightWidgets(widgets)
}
}
function removeWidgetFromSection(sectionId, widgetIndex) {
var widgets = []
if (sectionId === "left") {
widgets = SettingsData.dankBarLeftWidgets.slice()
widgets = SettingsData.topBarLeftWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1)
}
SettingsData.setDankBarLeftWidgets(widgets)
SettingsData.setTopBarLeftWidgets(widgets)
} else if (sectionId === "center") {
widgets = SettingsData.dankBarCenterWidgets.slice()
widgets = SettingsData.topBarCenterWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1)
}
SettingsData.setDankBarCenterWidgets(widgets)
SettingsData.setTopBarCenterWidgets(widgets)
} else if (sectionId === "right") {
widgets = SettingsData.dankBarRightWidgets.slice()
widgets = SettingsData.topBarRightWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1)
}
SettingsData.setDankBarRightWidgets(widgets)
SettingsData.setTopBarRightWidgets(widgets)
}
}
function handleItemEnabledChanged(sectionId, itemId, enabled) {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.dankBarLeftWidgets.slice()
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.dankBarCenterWidgets.slice()
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.dankBarRightWidgets.slice()
widgets = SettingsData.topBarRightWidgets.slice()
for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i]
var widgetId = typeof widget === "string" ? widget : widget.id
@@ -316,30 +316,30 @@ Item {
}
}
if (sectionId === "left")
SettingsData.setDankBarLeftWidgets(widgets)
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setDankBarCenterWidgets(widgets)
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setDankBarRightWidgets(widgets)
SettingsData.setTopBarRightWidgets(widgets)
}
function handleItemOrderChanged(sectionId, newOrder) {
if (sectionId === "left")
SettingsData.setDankBarLeftWidgets(newOrder)
SettingsData.setTopBarLeftWidgets(newOrder)
else if (sectionId === "center")
SettingsData.setDankBarCenterWidgets(newOrder)
SettingsData.setTopBarCenterWidgets(newOrder)
else if (sectionId === "right")
SettingsData.setDankBarRightWidgets(newOrder)
SettingsData.setTopBarRightWidgets(newOrder)
}
function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.dankBarLeftWidgets.slice()
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.dankBarCenterWidgets.slice()
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.dankBarRightWidgets.slice()
widgets = SettingsData.topBarRightWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex]
@@ -372,21 +372,21 @@ Item {
}
if (sectionId === "left")
SettingsData.setDankBarLeftWidgets(widgets)
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setDankBarCenterWidgets(widgets)
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setDankBarRightWidgets(widgets)
SettingsData.setTopBarRightWidgets(widgets)
}
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.dankBarLeftWidgets.slice()
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.dankBarCenterWidgets.slice()
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.dankBarRightWidgets.slice()
widgets = SettingsData.topBarRightWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex]
@@ -415,21 +415,21 @@ Item {
}
if (sectionId === "left")
SettingsData.setDankBarLeftWidgets(widgets)
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setDankBarCenterWidgets(widgets)
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setDankBarRightWidgets(widgets)
SettingsData.setTopBarRightWidgets(widgets)
}
function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.dankBarLeftWidgets.slice()
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.dankBarCenterWidgets.slice()
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.dankBarRightWidgets.slice()
widgets = SettingsData.topBarRightWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex]
@@ -461,11 +461,11 @@ Item {
}
if (sectionId === "left")
SettingsData.setDankBarLeftWidgets(widgets)
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setDankBarCenterWidgets(widgets)
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setDankBarRightWidgets(widgets)
SettingsData.setTopBarRightWidgets(widgets)
}
function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) {
@@ -483,11 +483,11 @@ Item {
var widgets = []
var widgetData = []
if (sectionId === "left")
widgetData = SettingsData.dankBarLeftWidgets || []
widgetData = SettingsData.topBarLeftWidgets || []
else if (sectionId === "center")
widgetData = SettingsData.dankBarCenterWidgets || []
widgetData = SettingsData.topBarCenterWidgets || []
else if (sectionId === "right")
widgetData = SettingsData.dankBarRightWidgets || []
widgetData = SettingsData.topBarRightWidgets || []
widgetData.forEach(widget => {
var widgetId = typeof widget === "string" ? widget : widget.id
var widgetEnabled = typeof widget
@@ -531,23 +531,23 @@ Item {
Component.onCompleted: {
// Only set defaults if widgets have never been configured (null/undefined, not empty array)
if (!SettingsData.dankBarLeftWidgets)
SettingsData.setDankBarLeftWidgets(defaultLeftWidgets)
if (!SettingsData.topBarLeftWidgets)
SettingsData.setTopBarLeftWidgets(defaultLeftWidgets)
if (!SettingsData.dankBarCenterWidgets)
SettingsData.setDankBarCenterWidgets(defaultCenterWidgets)
if (!SettingsData.topBarCenterWidgets)
SettingsData.setTopBarCenterWidgets(defaultCenterWidgets)
if (!SettingsData.dankBarRightWidgets)
SettingsData.setDankBarRightWidgets(defaultRightWidgets)
if (!SettingsData.topBarRightWidgets)
SettingsData.setTopBarRightWidgets(defaultRightWidgets)
const sections = ["left", "center", "right"]
sections.forEach(sectionId => {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.dankBarLeftWidgets.slice()
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.dankBarCenterWidgets.slice()
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.dankBarRightWidgets.slice()
widgets = SettingsData.topBarRightWidgets.slice()
var updated = false
for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i]
@@ -562,11 +562,11 @@ Item {
}
if (updated) {
if (sectionId === "left")
SettingsData.setDankBarLeftWidgets(widgets)
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setDankBarCenterWidgets(widgets)
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setDankBarRightWidgets(widgets)
SettingsData.setTopBarRightWidgets(widgets)
}
})
}
@@ -584,10 +584,10 @@ Item {
width: parent.width
spacing: Theme.spacingXL
// Position Section
// TopBar Auto-hide Section
StyledRect {
width: parent.width
height: positionSection.implicitHeight + Theme.spacingL * 2
height: topBarAutoHideSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
@@ -595,71 +595,7 @@ Item {
border.width: 0
Column {
id: positionSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "vertical_align_center"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Position"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
DankButtonGroup {
id: positionButtonGroup
anchors.verticalCenter: parent.verticalCenter
model: ["Top", "Bottom", "Left", "Right"]
currentIndex: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Top: return 0
case SettingsData.Position.Bottom: return 1
case SettingsData.Position.Left: return 2
case SettingsData.Position.Right: return 3
default: return 0
}
}
onSelectionChanged: (index, selected) => {
if (selected) {
switch (index) {
case 0: SettingsData.setDankBarPosition(SettingsData.Position.Top); break
case 1: SettingsData.setDankBarPosition(SettingsData.Position.Bottom); break
case 2: SettingsData.setDankBarPosition(SettingsData.Position.Left); break
case 3: SettingsData.setDankBarPosition(SettingsData.Position.Right); break
}
}
}
}
}
}
}
// DankBar Auto-hide Section
StyledRect {
width: parent.width
height: dankBarAutoHideSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 0
Column {
id: dankBarAutoHideSection
id: topBarAutoHideSection
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -702,9 +638,9 @@ Item {
id: autoHideToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.dankBarAutoHide
checked: SettingsData.topBarAutoHide
onToggled: toggled => {
return SettingsData.setDankBarAutoHide(
return SettingsData.setTopBarAutoHide(
toggled)
}
}
@@ -754,9 +690,9 @@ Item {
id: visibilityToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.dankBarVisible
checked: SettingsData.topBarVisible
onToggled: toggled => {
return SettingsData.setDankBarVisible(
return SettingsData.setTopBarVisible(
toggled)
}
}
@@ -808,9 +744,9 @@ Item {
id: overviewToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.dankBarOpenOnOverview
checked: SettingsData.topBarOpenOnOverview
onToggled: toggled => {
return SettingsData.setDankBarOpenOnOverview(
return SettingsData.setTopBarOpenOnOverview(
toggled)
}
}
@@ -822,7 +758,7 @@ Item {
// Spacing
StyledRect {
width: parent.width
height: dankBarSpacingSection.implicitHeight + Theme.spacingL * 2
height: topBarSpacingSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
@@ -830,7 +766,7 @@ Item {
border.width: 0
Column {
id: dankBarSpacingSection
id: topBarSpacingSection
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -861,7 +797,7 @@ Item {
spacing: Theme.spacingS
StyledText {
text: "Edge Spacing (0 = edge-to-edge)"
text: "Top/Left/Right Gaps (0 = edge-to-edge)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
@@ -870,7 +806,7 @@ Item {
DankSlider {
width: parent.width
height: 24
value: SettingsData.dankBarSpacing
value: SettingsData.topBarSpacing
minimum: 0
maximum: 32
unit: ""
@@ -878,7 +814,7 @@ Item {
wheelEnabled: false
thumbOutlineColor: Theme.surfaceContainerHigh
onSliderValueChanged: newValue => {
SettingsData.setDankBarSpacing(
SettingsData.setTopBarSpacing(
newValue)
}
}
@@ -889,7 +825,7 @@ Item {
spacing: Theme.spacingS
StyledText {
text: "Exclusive Zone Offset"
text: "Bottom Gap (Exclusive Zone)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
@@ -898,7 +834,7 @@ Item {
DankSlider {
width: parent.width
height: 24
value: SettingsData.dankBarBottomGap
value: SettingsData.topBarBottomGap
minimum: -100
maximum: 100
unit: ""
@@ -906,7 +842,7 @@ Item {
wheelEnabled: false
thumbOutlineColor: Theme.surfaceContainerHigh
onSliderValueChanged: newValue => {
SettingsData.setDankBarBottomGap(
SettingsData.setTopBarBottomGap(
newValue)
}
}
@@ -926,7 +862,7 @@ Item {
DankSlider {
width: parent.width
height: 24
value: SettingsData.dankBarInnerPadding
value: SettingsData.topBarInnerPadding
minimum: 0
maximum: 24
unit: ""
@@ -934,7 +870,7 @@ Item {
wheelEnabled: false
thumbOutlineColor: Theme.surfaceContainerHigh
onSliderValueChanged: newValue => {
SettingsData.setDankBarInnerPadding(
SettingsData.setTopBarInnerPadding(
newValue)
}
}
@@ -945,9 +881,9 @@ Item {
width: parent.width
text: "Square Corners"
description: "Removes rounded corners from bar container."
checked: SettingsData.dankBarSquareCorners
checked: SettingsData.topBarSquareCorners
onToggled: checked => {
SettingsData.setDankBarSquareCorners(
SettingsData.setTopBarSquareCorners(
checked)
}
}
@@ -956,9 +892,9 @@ Item {
width: parent.width
text: "No Background"
description: "Remove widget backgrounds for a minimal look with tighter spacing."
checked: SettingsData.dankBarNoBackground
checked: SettingsData.topBarNoBackground
onToggled: checked => {
SettingsData.setDankBarNoBackground(
SettingsData.setTopBarNoBackground(
checked)
}
}
@@ -967,9 +903,9 @@ Item {
width: parent.width
text: "Goth Corners"
description: "Add curved swooping tips at the bottom of the bar."
checked: SettingsData.dankBarGothCornersEnabled
checked: SettingsData.topBarGothCornersEnabled
onToggled: checked => {
SettingsData.setDankBarGothCornersEnabled(
SettingsData.setTopBarGothCornersEnabled(
checked)
}
}
@@ -1060,11 +996,11 @@ Item {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
SettingsData.setDankBarLeftWidgets(
SettingsData.setTopBarLeftWidgets(
defaultLeftWidgets)
SettingsData.setDankBarCenterWidgets(
SettingsData.setTopBarCenterWidgets(
defaultCenterWidgets)
SettingsData.setDankBarRightWidgets(
SettingsData.setTopBarRightWidgets(
defaultRightWidgets)
}
}
@@ -1099,7 +1035,7 @@ Item {
width: parent.width
spacing: Theme.spacingL
// Left/Top Section
// Left Section
StyledRect {
width: parent.width
height: leftSection.implicitHeight + Theme.spacingL * 2
@@ -1113,32 +1049,32 @@ Item {
id: leftSection
anchors.fill: parent
anchors.margins: Theme.spacingL
title: SettingsData.dankBarIsVertical ? "Top Section" : "Left Section"
title: "Left Section"
titleIcon: "format_align_left"
sectionId: "left"
allWidgets: dankBarTab.baseWidgetDefinitions
items: dankBarTab.getItemsForSection("left")
allWidgets: topBarTab.baseWidgetDefinitions
items: topBarTab.getItemsForSection("left")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
dankBarTab.handleItemEnabledChanged(
topBarTab.handleItemEnabledChanged(
sectionId,
itemId, enabled)
}
onItemOrderChanged: newOrder => {
dankBarTab.handleItemOrderChanged(
topBarTab.handleItemOrderChanged(
"left", newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets
= dankBarTab.baseWidgetDefinitions
= topBarTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
dankBarTab.removeWidgetFromSection(
topBarTab.removeWidgetFromSection(
sectionId, widgetIndex)
}
onSpacerSizeChanged: (sectionId, widgetIndex, newSize) => {
dankBarTab.handleSpacerSizeChanged(
topBarTab.handleSpacerSizeChanged(
sectionId, widgetIndex, newSize)
}
onCompactModeChanged: (widgetId, value) => {
@@ -1160,12 +1096,12 @@ Item {
handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value)
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
dankBarTab.handleGpuSelectionChanged(
topBarTab.handleGpuSelectionChanged(
sectionId, widgetIndex,
selectedIndex)
}
onDiskMountSelectionChanged: (sectionId, widgetIndex, mountPath) => {
dankBarTab.handleDiskMountSelectionChanged(
topBarTab.handleDiskMountSelectionChanged(
sectionId, widgetIndex, mountPath)
}
}
@@ -1188,29 +1124,29 @@ Item {
title: "Center Section"
titleIcon: "format_align_center"
sectionId: "center"
allWidgets: dankBarTab.baseWidgetDefinitions
items: dankBarTab.getItemsForSection("center")
allWidgets: topBarTab.baseWidgetDefinitions
items: topBarTab.getItemsForSection("center")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
dankBarTab.handleItemEnabledChanged(
topBarTab.handleItemEnabledChanged(
sectionId,
itemId, enabled)
}
onItemOrderChanged: newOrder => {
dankBarTab.handleItemOrderChanged(
topBarTab.handleItemOrderChanged(
"center", newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets
= dankBarTab.baseWidgetDefinitions
= topBarTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
dankBarTab.removeWidgetFromSection(
topBarTab.removeWidgetFromSection(
sectionId, widgetIndex)
}
onSpacerSizeChanged: (sectionId, widgetIndex, newSize) => {
dankBarTab.handleSpacerSizeChanged(
topBarTab.handleSpacerSizeChanged(
sectionId, widgetIndex, newSize)
}
onCompactModeChanged: (widgetId, value) => {
@@ -1232,18 +1168,18 @@ Item {
handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value)
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
dankBarTab.handleGpuSelectionChanged(
topBarTab.handleGpuSelectionChanged(
sectionId, widgetIndex,
selectedIndex)
}
onDiskMountSelectionChanged: (sectionId, widgetIndex, mountPath) => {
dankBarTab.handleDiskMountSelectionChanged(
topBarTab.handleDiskMountSelectionChanged(
sectionId, widgetIndex, mountPath)
}
}
}
// Right/Bottom Section
// Right Section
StyledRect {
width: parent.width
height: rightSection.implicitHeight + Theme.spacingL * 2
@@ -1257,32 +1193,32 @@ Item {
id: rightSection
anchors.fill: parent
anchors.margins: Theme.spacingL
title: SettingsData.dankBarIsVertical ? "Bottom Section" : "Right Section"
title: "Right Section"
titleIcon: "format_align_right"
sectionId: "right"
allWidgets: dankBarTab.baseWidgetDefinitions
items: dankBarTab.getItemsForSection("right")
allWidgets: topBarTab.baseWidgetDefinitions
items: topBarTab.getItemsForSection("right")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
dankBarTab.handleItemEnabledChanged(
topBarTab.handleItemEnabledChanged(
sectionId,
itemId, enabled)
}
onItemOrderChanged: newOrder => {
dankBarTab.handleItemOrderChanged(
topBarTab.handleItemOrderChanged(
"right", newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets
= dankBarTab.baseWidgetDefinitions
= topBarTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
dankBarTab.removeWidgetFromSection(
topBarTab.removeWidgetFromSection(
sectionId, widgetIndex)
}
onSpacerSizeChanged: (sectionId, widgetIndex, newSize) => {
dankBarTab.handleSpacerSizeChanged(
topBarTab.handleSpacerSizeChanged(
sectionId, widgetIndex, newSize)
}
onCompactModeChanged: (widgetId, value) => {
@@ -1304,12 +1240,12 @@ Item {
handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value)
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
dankBarTab.handleGpuSelectionChanged(
topBarTab.handleGpuSelectionChanged(
sectionId, widgetIndex,
selectedIndex)
}
onDiskMountSelectionChanged: (sectionId, widgetIndex, mountPath) => {
dankBarTab.handleDiskMountSelectionChanged(
topBarTab.handleDiskMountSelectionChanged(
sectionId, widgetIndex, mountPath)
}
}
@@ -1323,7 +1259,7 @@ Item {
anchors.centerIn: parent
onWidgetSelected: (widgetId, targetSection) => {
dankBarTab.addWidgetToSection(widgetId,
topBarTab.addWidgetToSection(widgetId,
targetSection)
}
}

View File

@@ -85,6 +85,7 @@ Popup {
onOpened: {
isOpening = false
Qt.callLater(() => {
contentItem.forceActiveFocus()
searchField.forceActiveFocus()
})
}
@@ -120,18 +121,6 @@ Popup {
} else if (event.key === Qt.Key_Up) {
root.selectPrevious()
event.accepted = true
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
root.selectNext()
event.accepted = true
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
root.selectPrevious()
event.accepted = true
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
root.selectNext()
event.accepted = true
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
root.selectPrevious()
event.accepted = true
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (root.keyboardNavigationActive) {
root.selectWidget()

View File

@@ -305,19 +305,6 @@ Column {
onClicked: {
root.compactModeChanged("music", 0)
}
onEntered: {
smallTooltipLoader.active = true
if (smallTooltipLoader.item) {
const p = smallSizeButton.mapToItem(null, smallSizeButton.width / 2, 0)
smallTooltipLoader.item.show("Small", p.x, p.y - 40, null)
}
}
onExited: {
if (smallTooltipLoader.item) {
smallTooltipLoader.item.hide()
}
smallTooltipLoader.active = false
}
}
DankActionButton {
@@ -331,19 +318,6 @@ Column {
onClicked: {
root.compactModeChanged("music", 1)
}
onEntered: {
mediumTooltipLoader.active = true
if (mediumTooltipLoader.item) {
const p = mediumSizeButton.mapToItem(null, mediumSizeButton.width / 2, 0)
mediumTooltipLoader.item.show("Medium", p.x, p.y - 40, null)
}
}
onExited: {
if (mediumTooltipLoader.item) {
mediumTooltipLoader.item.hide()
}
mediumTooltipLoader.active = false
}
}
DankActionButton {
@@ -357,19 +331,6 @@ Column {
onClicked: {
root.compactModeChanged("music", 2)
}
onEntered: {
largeTooltipLoader.active = true
if (largeTooltipLoader.item) {
const p = largeSizeButton.mapToItem(null, largeSizeButton.width / 2, 0)
largeTooltipLoader.item.show("Large", p.x, p.y - 40, null)
}
}
onExited: {
if (largeTooltipLoader.item) {
largeTooltipLoader.item.hide()
}
largeTooltipLoader.active = false
}
}
DankActionButton {
@@ -412,27 +373,6 @@ Column {
!SettingsData.runningAppsCompactMode)
}
}
onEntered: {
compactTooltipLoader.active = true
if (compactTooltipLoader.item) {
let tooltipText = "Toggle Compact Mode"
if (modelData.id === "clock") {
tooltipText = SettingsData.clockCompactMode ? "Full Size" : "Compact"
} else if (modelData.id === "focusedWindow") {
tooltipText = SettingsData.focusedWindowCompactMode ? "Full Size" : "Compact"
} else if (modelData.id === "runningApps") {
tooltipText = SettingsData.runningAppsCompactMode ? "Full Size" : "Compact"
}
const p = compactModeButton.mapToItem(null, compactModeButton.width / 2, 0)
compactTooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
}
}
onExited: {
if (compactTooltipLoader.item) {
compactTooltipLoader.item.hide()
}
compactTooltipLoader.active = false
}
}
Rectangle {
@@ -486,7 +426,6 @@ Column {
}
DankActionButton {
id: visibilityButton
visible: modelData.id !== "spacer"
buttonSize: 32
iconName: modelData.enabled ? "visibility" : "visibility_off"
@@ -497,20 +436,6 @@ Column {
modelData.id,
!modelData.enabled)
}
onEntered: {
visibilityTooltipLoader.active = true
if (visibilityTooltipLoader.item) {
const tooltipText = modelData.enabled ? "Hide" : "Show"
const p = visibilityButton.mapToItem(null, visibilityButton.width / 2, 0)
visibilityTooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
}
}
onExited: {
if (visibilityTooltipLoader.item) {
visibilityTooltipLoader.item.hide()
}
visibilityTooltipLoader.active = false
}
}
Row {
@@ -866,34 +791,4 @@ Column {
}
}
Loader {
id: smallTooltipLoader
active: false
sourceComponent: DankTooltip {}
}
Loader {
id: mediumTooltipLoader
active: false
sourceComponent: DankTooltip {}
}
Loader {
id: largeTooltipLoader
active: false
sourceComponent: DankTooltip {}
}
Loader {
id: compactTooltipLoader
active: false
sourceComponent: DankTooltip {}
}
Loader {
id: visibilityTooltipLoader
active: false
sourceComponent: DankTooltip {}
}
}

View File

@@ -12,6 +12,7 @@ DankPopout {
id: systemUpdatePopout
property var parentWidget: null
property string triggerSection: "right"
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
@@ -25,9 +26,9 @@ DankPopout {
popupWidth: 400
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
triggerY: Math.max(26 + SettingsData.topBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.topBarInnerPadding)) + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance
triggerWidth: 55
positioning: ""
positioning: "center"
screen: triggerScreen
visible: shouldBeVisible
shouldBeVisible: false

View File

@@ -69,7 +69,7 @@ PanelWindow {
width: shouldBeVisible ? (ToastService.hasDetails ? 380 : 350) : frozenWidth
height: toastContent.height + Theme.spacingL * 2
anchors.horizontalCenter: parent.horizontalCenter
y: Theme.barHeight - 4 + SettingsData.dankBarSpacing + 2
y: Theme.barHeight - 4 + SettingsData.topBarSpacing + 2
color: {
switch (ToastService.currentLevel) {
case ToastService.levelError:

153
Modules/TopBar/Battery.qml Normal file
View File

@@ -0,0 +1,153 @@
import QtQuick
import Quickshell.Services.UPower
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: battery
property bool batteryPopupVisible: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetHeight: 30
property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal toggleBatteryPopup()
width: batteryContent.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = batteryArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
visible: true
Row {
id: batteryContent
anchors.centerIn: parent
spacing: SettingsData.topBarNoBackground ? 1 : 2
DankIcon {
name: BatteryService.getBatteryIcon()
size: Theme.iconSize - 6
color: {
if (!BatteryService.batteryAvailable) {
return Theme.surfaceText;
}
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error;
}
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
return Theme.primary;
}
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: `${BatteryService.batteryLevel}%`
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable
}
}
MouseArea {
id: batteryArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
toggleBatteryPopup();
}
}
Rectangle {
id: batteryTooltip
width: Math.max(120, tooltipText.contentWidth + Theme.spacingM * 2)
height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.widgetBaseBackgroundColor
border.color: Theme.surfaceVariantAlpha
border.width: 1
visible: batteryArea.containsMouse && !batteryPopupVisible
anchors.bottom: parent.top
anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter
opacity: batteryArea.containsMouse ? 1 : 0
Column {
anchors.centerIn: parent
spacing: 2
StyledText {
id: tooltipText
text: {
if (!BatteryService.batteryAvailable) {
if (typeof PowerProfiles === "undefined") {
return "Power Management";
}
switch (PowerProfiles.profile) {
case PowerProfile.PowerSaver:
return "Power Profile: Power Saver";
case PowerProfile.Performance:
return "Power Profile: Performance";
default:
return "Power Profile: Balanced";
}
}
const status = BatteryService.batteryStatus;
const level = `${BatteryService.batteryLevel}%`;
const time = BatteryService.formatTimeRemaining();
if (time !== "Unknown") {
return `${status} ${level} ${time}`;
} else {
return `${status} ${level}`;
}
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
horizontalAlignment: Text.AlignHCenter
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -11,6 +11,7 @@ import qs.Widgets
DankPopout {
id: root
property string triggerSection: "right"
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
@@ -44,9 +45,9 @@ DankPopout {
popupWidth: 400
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.popupDistance
triggerWidth: 70
positioning: ""
positioning: "center"
screen: triggerScreen
shouldBeVisible: false
visible: shouldBeVisible

93
Modules/TopBar/Clock.qml Normal file
View File

@@ -0,0 +1,93 @@
import QtQuick
import Quickshell
import qs.Common
import qs.Widgets
Rectangle {
id: root
property bool compactMode: false
property string section: "center"
property var popupTarget: null
property var parentScreen: null
property real barHeight: 48
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
signal clockClicked
width: clockRow.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = clockMouseArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Row {
id: clockRow
anchors.centerIn: parent
spacing: Theme.spacingS
StyledText {
text: {
const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"
return systemClock?.date?.toLocaleTimeString(Qt.locale(), format)
}
font.pixelSize: Theme.fontSizeMedium - 1
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.clockCompactMode
}
StyledText {
text: {
if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) {
return systemClock?.date?.toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat)
}
return systemClock?.date?.toLocaleDateString(Qt.locale(), "ddd d")
}
font.pixelSize: Theme.fontSizeMedium - 1
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.clockCompactMode
}
}
SystemClock {
id: systemClock
precision: SystemClock.Seconds
}
MouseArea {
id: clockMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const screenX = currentScreen.x || 0
const relativeX = globalPos.x - screenX
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen)
}
root.clockClicked()
}
}
}

View File

@@ -5,23 +5,21 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real widgetHeight: 30
property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked()
width: isVertical ? widgetThickness : (colorPickerIcon.width + horizontalPadding * 2)
height: isVertical ? (colorPickerIcon.height + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: colorPickerIcon.width + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -45,10 +43,12 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
console.log("Color picker button clicked!")
root.colorPickerRequested();
}
}
// Signal to notify TopBar to open color picker
signal colorPickerRequested()
}

View File

@@ -6,8 +6,6 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool isActive: false
property string section: "right"
property var popupTarget: null
@@ -16,17 +14,17 @@ Rectangle {
property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon
property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon
property bool showAudioIcon: SettingsData.controlCenterShowAudioIcon
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real widgetHeight: 30
property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked()
width: isVertical ? widgetThickness : (controlIndicators.implicitWidth + horizontalPadding * 2)
height: isVertical ? (controlColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: controlIndicators.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -34,106 +32,9 @@ Rectangle {
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Column {
id: controlColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
name: {
if (NetworkService.wifiToggling) {
return "sync"
}
if (NetworkService.networkStatus === "ethernet") {
return "lan"
}
return NetworkService.wifiSignalIcon
}
size: Theme.iconSize - 8
color: {
if (NetworkService.wifiToggling) {
return Theme.primary
}
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton
}
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showNetworkIcon
}
DankIcon {
name: "bluetooth"
size: Theme.iconSize - 8
color: BluetoothService.enabled ? Theme.primary : Theme.outlineButton
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled
}
Rectangle {
width: audioIconV.implicitWidth + 4
height: audioIconV.implicitHeight + 4
color: "transparent"
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showAudioIcon
DankIcon {
id: audioIconV
name: {
if (AudioService.sink && AudioService.sink.audio) {
if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0) {
return "volume_off"
} else if (AudioService.sink.audio.volume * 100 < 33) {
return "volume_down"
} else {
return "volume_up"
}
}
return "volume_up"
}
size: Theme.iconSize - 8
color: Theme.surfaceText
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onWheel: function(wheelEvent) {
let delta = wheelEvent.angleDelta.y
let currentVolume = (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0
let newVolume
if (delta > 0) {
newVolume = Math.min(100, currentVolume + 5)
} else {
newVolume = Math.max(0, currentVolume - 5)
}
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false
AudioService.sink.audio.volume = newVolume / 100
AudioService.volumeChanged()
}
wheelEvent.accepted = true
}
}
}
DankIcon {
name: "settings"
size: Theme.iconSize - 8
color: controlCenterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon
}
}
Row {
id: controlIndicators
visible: !root.isVertical
anchors.centerIn: parent
spacing: Theme.spacingXS
@@ -255,10 +156,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
root.clicked();
}

View File

@@ -7,23 +7,21 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real barThickness: 48
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real barHeight: 48
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
width: isVertical ? widgetThickness : (cpuContent.implicitWidth + horizontalPadding * 2)
height: isVertical ? (cpuColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: cpuContent.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -45,10 +43,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
DgopService.setSortBy("cpu");
if (root.toggleProcessList) {
@@ -58,47 +57,9 @@ Rectangle {
}
}
Column {
id: cpuColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: 1
DankIcon {
name: "memory"
size: Theme.iconSize - 8
color: {
if (DgopService.cpuUsage > 80) {
return Theme.tempDanger;
}
if (DgopService.cpuUsage > 60) {
return Theme.tempWarning;
}
return Theme.surfaceText;
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
if (DgopService.cpuUsage === undefined || DgopService.cpuUsage === null || DgopService.cpuUsage === 0) {
return "--";
}
return DgopService.cpuUsage.toFixed(0);
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: cpuContent
visible: !root.isVertical
anchors.centerIn: parent
spacing: 3

View File

@@ -7,23 +7,21 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real barThickness: 48
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real barHeight: 48
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
width: isVertical ? widgetThickness : (cpuTempContent.implicitWidth + horizontalPadding * 2)
height: isVertical ? (cpuTempColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: cpuTempContent.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -45,10 +43,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
DgopService.setSortBy("cpu");
if (root.toggleProcessList) {
@@ -58,47 +57,9 @@ Rectangle {
}
}
Column {
id: cpuTempColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: 1
DankIcon {
name: "memory"
size: Theme.iconSize - 8
color: {
if (DgopService.cpuTemperature > 85) {
return Theme.tempDanger;
}
if (DgopService.cpuTemperature > 69) {
return Theme.tempWarning;
}
return Theme.surfaceText;
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) {
return "--";
}
return Math.round(DgopService.cpuTemperature).toString();
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: cpuTempContent
visible: !root.isVertical
anchors.centerIn: parent
spacing: 3

View File

@@ -7,13 +7,10 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property var widgetData: null
property var parentScreen: null
property real widgetThickness: 30
property real widgetHeight: 30
property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/"
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
property var selectedMount: {
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
@@ -49,11 +46,11 @@ Rectangle {
return parseFloat(percentStr) || 0
}
width: isVertical ? widgetThickness : (diskContent.implicitWidth + horizontalPadding * 2)
height: isVertical ? (diskColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: diskContent.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent"
}
@@ -103,77 +100,10 @@ Rectangle {
target: SettingsData
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
}
MouseArea {
id: diskArea
anchors.fill: parent
hoverEnabled: root.isVertical
onEntered: {
if (root.isVertical && root.selectedMount) {
tooltipLoader.active = true
if (tooltipLoader.item) {
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 tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(root.selectedMount.mount, screenX + tooltipX, relativeY, currentScreen, isLeft, !isLeft)
}
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide()
}
tooltipLoader.active = false
}
}
Column {
id: diskColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: 1
DankIcon {
name: "storage"
size: Theme.iconSize - 8
color: {
if (root.diskUsagePercent > 90) {
return Theme.tempDanger
}
if (root.diskUsagePercent > 75) {
return Theme.tempWarning
}
return Theme.surfaceText
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
return "--"
}
return root.diskUsagePercent.toFixed(0)
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: diskContent
visible: !root.isVertical
anchors.centerIn: parent
spacing: 3

View File

@@ -1,7 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import Quickshell.Hyprland
import qs.Common
import qs.Services
@@ -10,45 +9,14 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property var parentScreen
property bool compactMode: SettingsData.focusedWindowCompactMode
property int availableWidth: 400
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
readonly property int baseWidth: contentRow.implicitWidth + horizontalPadding * 2
readonly property int maxNormalWidth: 456
readonly property int maxCompactWidth: 288
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
property var activeDesktopEntry: null
Component.onCompleted: {
updateDesktopEntry()
}
Connections {
target: DesktopEntries
function onApplicationsChanged() {
root.updateDesktopEntry()
}
}
Connections {
target: root
function onActiveWindowChanged() {
root.updateDesktopEntry()
}
}
function updateDesktopEntry() {
if (activeWindow && activeWindow.appId) {
const moddedId = Paths.moddedAppId(activeWindow.appId)
activeDesktopEntry = DesktopEntries.heuristicLookup(moddedId)
} else {
activeDesktopEntry = null
}
}
readonly property bool hasWindowsOnCurrentWorkspace: {
if (CompositorService.isNiri) {
let currentWorkspaceId = null
@@ -86,15 +54,15 @@ Rectangle {
return activeWindow && activeWindow.title
}
width: !hasWindowsOnCurrentWorkspace ? 0 : (isVertical ? widgetThickness : (compactMode ? Math.min(baseWidth, maxCompactWidth) : Math.min(baseWidth, maxNormalWidth)))
height: !hasWindowsOnCurrentWorkspace ? 0 : (isVertical ? widgetThickness : widgetThickness)
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: !hasWindowsOnCurrentWorkspace ? 0 : (compactMode ? Math.min(baseWidth, maxCompactWidth) : Math.min(baseWidth, maxNormalWidth))
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (!activeWindow || !activeWindow.title) {
return "transparent";
}
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -104,61 +72,11 @@ Rectangle {
clip: true
visible: hasWindowsOnCurrentWorkspace
IconImage {
id: appIcon
anchors.centerIn: parent
width: 18
height: 18
visible: root.isVertical && activeWindow && status === Image.Ready
source: {
if (!activeWindow || !activeWindow.appId) return ""
const moddedId = Paths.moddedAppId(activeWindow.appId)
if (moddedId.toLowerCase().includes("steam_app")) return ""
return Quickshell.iconPath(activeDesktopEntry?.icon, true)
}
smooth: true
mipmap: true
asynchronous: true
}
DankIcon {
anchors.centerIn: parent
size: 18
name: "sports_esports"
color: Theme.surfaceText
visible: {
if (!root.isVertical || !activeWindow || !activeWindow.appId) return false
const moddedId = Paths.moddedAppId(activeWindow.appId)
return moddedId.toLowerCase().includes("steam_app")
}
}
Text {
anchors.centerIn: parent
visible: {
if (!root.isVertical || !activeWindow || !activeWindow.appId) return false
if (appIcon.status === Image.Ready) return false
const moddedId = Paths.moddedAppId(activeWindow.appId)
return !moddedId.toLowerCase().includes("steam_app")
}
text: {
if (!activeWindow || !activeWindow.appId) return "?"
if (activeDesktopEntry && activeDesktopEntry.name) {
return activeDesktopEntry.name.charAt(0).toUpperCase()
}
return activeWindow.appId.charAt(0).toUpperCase()
}
font.pixelSize: 10
color: Theme.surfaceText
font.weight: Font.Medium
}
Row {
id: contentRow
anchors.centerIn: parent
spacing: Theme.spacingS
visible: !root.isVertical
StyledText {
id: appText
@@ -199,6 +117,7 @@ Rectangle {
return title;
}
// Remove app name from end of title if it exists there
if (title.endsWith(" - " + appName)) {
return title.substring(0, title.length - (" - " + appName).length);
}
@@ -225,39 +144,7 @@ Rectangle {
id: mouseArea
anchors.fill: parent
hoverEnabled: root.isVertical
onEntered: {
if (root.isVertical && activeWindow && activeWindow.appId && root.parentScreen) {
tooltipLoader.active = true
if (tooltipLoader.item) {
const globalPos = mapToGlobal(width / 2, height / 2)
const currentScreen = root.parentScreen
const screenX = currentScreen ? currentScreen.x : 0
const screenY = currentScreen ? currentScreen.y : 0
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 appName = activeDesktopEntry && activeDesktopEntry.name ? activeDesktopEntry.name : activeWindow.appId
const title = activeWindow.title || ""
const tooltipText = appName + (title ? " • " + title : "")
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, currentScreen, isLeft, !isLeft)
}
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide()
}
tooltipLoader.active = false
}
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
hoverEnabled: true
}

View File

@@ -7,8 +7,6 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
@@ -16,10 +14,10 @@ Rectangle {
property var popupTarget: null
property var parentScreen: null
property var widgetData: null
property real barThickness: 48
property real widgetThickness: 30
property real barHeight: 48
property real widgetHeight: 30
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
property real displayTemp: {
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
return 0;
@@ -39,11 +37,11 @@ Rectangle {
const sectionId = sections[s];
let widgets = [];
if (sectionId === "left") {
widgets = SettingsData.dankBarLeftWidgets.slice();
widgets = SettingsData.topBarLeftWidgets.slice();
} else if (sectionId === "center") {
widgets = SettingsData.dankBarCenterWidgets.slice();
widgets = SettingsData.topBarCenterWidgets.slice();
} else if (sectionId === "right") {
widgets = SettingsData.dankBarRightWidgets.slice();
widgets = SettingsData.topBarRightWidgets.slice();
}
for (let i = 0; i < widgets.length; i++) {
const widget = widgets[i];
@@ -55,11 +53,11 @@ Rectangle {
"pciId": pciId
};
if (sectionId === "left") {
SettingsData.setDankBarLeftWidgets(widgets);
SettingsData.setTopBarLeftWidgets(widgets);
} else if (sectionId === "center") {
SettingsData.setDankBarCenterWidgets(widgets);
SettingsData.setTopBarCenterWidgets(widgets);
} else if (sectionId === "right") {
SettingsData.setDankBarRightWidgets(widgets);
SettingsData.setTopBarRightWidgets(widgets);
}
return ;
}
@@ -67,11 +65,11 @@ Rectangle {
}
}
width: isVertical ? widgetThickness : (gpuTempContent.implicitWidth + horizontalPadding * 2)
height: isVertical ? (gpuTempColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: gpuTempContent.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -80,14 +78,20 @@ Rectangle {
}
Component.onCompleted: {
DgopService.addRef(["gpu"]);
console.log("GpuTemperature widget - pciId:", widgetData ? widgetData.pciId : "no widgetData", "selectedGpuIndex:", widgetData ? widgetData.selectedGpuIndex : "no widgetData");
// Add this widget's PCI ID to the service
if (widgetData && widgetData.pciId) {
console.log("Adding GPU PCI ID to service:", widgetData.pciId);
DgopService.addGpuPciId(widgetData.pciId);
} else {
console.log("No PCI ID in widget data, starting auto-detection");
// No PCI ID saved, auto-detect and save the first GPU
autoSaveTimer.running = true;
}
}
Component.onDestruction: {
DgopService.removeRef(["gpu"]);
// Remove this widget's PCI ID from the service
if (widgetData && widgetData.pciId) {
DgopService.removeGpuPciId(widgetData.pciId);
}
@@ -113,10 +117,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
DgopService.setSortBy("cpu");
if (root.toggleProcessList) {
@@ -126,47 +131,9 @@ Rectangle {
}
}
Column {
id: gpuTempColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: 1
DankIcon {
name: "auto_awesome_mosaic"
size: Theme.iconSize - 8
color: {
if (root.displayTemp > 80) {
return Theme.tempDanger;
}
if (root.displayTemp > 65) {
return Theme.tempWarning;
}
return Theme.surfaceText;
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
return "--";
}
return Math.round(root.displayTemp).toString();
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: gpuTempContent
visible: !root.isVertical
anchors.centerIn: parent
spacing: 3

View File

@@ -8,19 +8,17 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
width: isVertical ? widgetThickness : (idleIcon.width + horizontalPadding * 2)
height: isVertical ? (idleIcon.height + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: idleIcon.width + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}

View File

@@ -10,18 +10,15 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
property string currentLayout: ""
property string hyprlandKeyboard: ""
width: isVertical ? widgetThickness : (contentRow.implicitWidth + horizontalPadding * 2)
height: isVertical ? (contentColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: contentRow.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -50,42 +47,11 @@ Rectangle {
}
}
Column {
id: contentColumn
anchors.centerIn: parent
spacing: 1
visible: root.isVertical
DankIcon {
name: "keyboard"
size: Theme.iconSize - 8
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
if (!currentLayout) return ""
const parts = currentLayout.split(" ")
if (parts.length > 0) {
return parts[0].substring(0, 2).toUpperCase()
}
return currentLayout.substring(0, 2).toUpperCase()
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: contentRow
anchors.centerIn: parent
spacing: Theme.spacingS
visible: !root.isVertical
StyledText {
text: currentLayout

View File

@@ -7,19 +7,17 @@ Item {
id: root
property bool isActive: false
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "left"
property var popupTarget: null
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real widgetHeight: 30
property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked()
width: widgetThickness
height: widgetThickness
width: Theme.iconSize + horizontalPadding * 2
height: widgetHeight
MouseArea {
id: launcherArea
@@ -29,13 +27,14 @@ Item {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
root.clicked();
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen);
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
root.clicked();
}
}
@@ -43,9 +42,9 @@ Item {
id: launcherContent
anchors.fill: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -56,8 +55,8 @@ Item {
SystemLogo {
visible: SettingsData.useOSLogo
anchors.centerIn: parent
width: widgetThickness - 8
height: widgetThickness - 8
width: Theme.iconSize - 3
height: Theme.iconSize - 3
colorOverride: SettingsData.osLogoColorOverride
brightnessOverride: SettingsData.osLogoBrightness
contrastOverride: SettingsData.osLogoContrast
@@ -65,11 +64,9 @@ Item {
DankIcon {
visible: !SettingsData.useOSLogo
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
anchors.centerIn: parent
name: "apps"
size: widgetThickness - 8
size: Theme.iconSize - 6
color: Theme.surfaceText
}
}

View File

@@ -7,8 +7,6 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool playerAvailable: activePlayer !== null
property bool compactMode: false
@@ -23,36 +21,27 @@ Rectangle {
}
}
readonly property int currentContentWidth: {
if (isVertical) {
return widgetThickness;
}
// Calculate actual content width:
// AudioViz (20) + spacing + [text + spacing] + controls (prev:20 + spacing + play:24 + spacing + next:20) + padding
const controlsWidth = 20 + Theme.spacingXS + 24 + Theme.spacingXS + 20;
// ~72px total
const audioVizWidth = 20;
const contentWidth = audioVizWidth + Theme.spacingXS + controlsWidth;
return contentWidth + (textWidth > 0 ? textWidth + Theme.spacingXS : 0) + horizontalPadding * 2;
}
readonly property int currentContentHeight: {
if (!isVertical) {
return widgetThickness;
}
const audioVizHeight = 20;
const playButtonHeight = 24;
return audioVizHeight + Theme.spacingXS + playButtonHeight + horizontalPadding * 2;
}
property string section: "center"
property var popupTarget: null
property var parentScreen: null
property real barThickness: 48
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real barHeight: 48
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked()
width: currentContentWidth
height: currentContentHeight
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -68,7 +57,6 @@ Rectangle {
target: root
opacity: 1
width: currentContentWidth
height: currentContentHeight
}
},
@@ -79,8 +67,7 @@ Rectangle {
PropertyChanges {
target: root
opacity: 0
width: isVertical ? widgetThickness : 0
height: isVertical ? 0 : widgetThickness
width: 0
}
}
@@ -96,7 +83,7 @@ Rectangle {
}
NumberAnimation {
properties: isVertical ? "opacity,height" : "opacity,width"
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
@@ -109,7 +96,7 @@ Rectangle {
to: "shown"
NumberAnimation {
properties: isVertical ? "opacity,height" : "opacity,width"
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
@@ -117,107 +104,9 @@ Rectangle {
}
]
Column {
id: verticalLayout
visible: root.isVertical
anchors.centerIn: parent
spacing: Theme.spacingXS
AudioVisualization {
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (root.popupTarget && root.popupTarget.setTriggerPosition) {
const globalPos = parent.mapToGlobal(0, 0)
const currentScreen = root.parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, parent.width)
root.popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen)
}
root.clicked()
}
onEntered: {
tooltipLoader.active = true
if (tooltipLoader.item && activePlayer) {
const globalPos = parent.mapToGlobal(parent.width / 2, parent.height / 2)
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0
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)
let identity = activePlayer.identity || ""
let isWebMedia = identity.toLowerCase().includes("firefox") || identity.toLowerCase().includes("chrome") || identity.toLowerCase().includes("chromium")
let title = activePlayer.trackTitle || "Unknown Track"
let subtitle = ""
if (isWebMedia && activePlayer.trackTitle) {
subtitle = activePlayer.trackArtist || identity
} else {
subtitle = activePlayer.trackArtist || ""
}
let tooltipText = subtitle.length > 0 ? title + " • " + subtitle : title
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide()
}
tooltipLoader.active = false
}
}
}
Rectangle {
width: 24
height: 24
radius: 12
anchors.horizontalCenter: parent.horizontalCenter
color: activePlayer && activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover
visible: root.playerAvailable
opacity: activePlayer ? 1 : 0.3
DankIcon {
anchors.centerIn: parent
name: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow"
size: 14
color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary
}
MouseArea {
anchors.fill: parent
enabled: root.playerAvailable
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
onClicked: (mouse) => {
if (!activePlayer) return
if (mouse.button === Qt.LeftButton) {
activePlayer.togglePlaying()
} else if (mouse.button === Qt.MiddleButton) {
activePlayer.previous()
} else if (mouse.button === Qt.RightButton) {
activePlayer.next()
}
}
}
}
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
}
Row {
id: mediaRow
visible: !root.isVertical
anchors.centerIn: parent
spacing: Theme.spacingXS
@@ -319,12 +208,13 @@ Rectangle {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onPressed: {
if (root.popupTarget && root.popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = root.parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.width)
root.popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = root.parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
root.popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, root.width, root.section, currentScreen);
}
root.clicked()
root.clicked();
}
}
@@ -440,13 +330,7 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on height {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -8,13 +8,10 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property int availableWidth: 400
readonly property int baseWidth: contentRow.implicitWidth + Theme.spacingS * 2
readonly property int maxNormalWidth: 456
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
function formatNetworkSpeed(bytesPerSec) {
if (bytesPerSec < 1024) {
@@ -28,11 +25,11 @@ Rectangle {
}
}
width: isVertical ? widgetThickness : (contentRow.implicitWidth + horizontalPadding * 2)
height: isVertical ? (contentColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: contentRow.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -54,53 +51,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
}
Column {
id: contentColumn
anchors.centerIn: parent
spacing: 2
visible: root.isVertical
DankIcon {
name: "network_check"
size: Theme.iconSize - 8
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
const rate = DgopService.networkRxRate
if (rate < 1024) return rate.toFixed(0)
if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K"
return (rate / (1024 * 1024)).toFixed(0) + "M"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.info
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
const rate = DgopService.networkTxRate
if (rate < 1024) return rate.toFixed(0)
if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K"
return (rate / (1024 * 1024)).toFixed(0) + "M"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.error
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: contentRow
anchors.centerIn: parent
spacing: Theme.spacingS
visible: !root.isVertical
DankIcon {
name: "network_check"

View File

@@ -0,0 +1,65 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetHeight: 30
property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked()
width: notepadIcon.width + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = notepadArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
DankIcon {
id: notepadIcon
anchors.centerIn: parent
name: "assignment"
size: Theme.iconSize - 6
color: notepadArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
}
Rectangle {
width: 6
height: 6
radius: 3
color: Theme.primary
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: SettingsData.topBarNoBackground ? 0 : 4
anchors.topMargin: SettingsData.topBarNoBackground ? 0 : 4
visible: NotepadStorageService.tabs && NotepadStorageService.tabs.length > 0
opacity: 0.8
}
MouseArea {
id: notepadArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
root.clicked();
}
}
}

View File

@@ -0,0 +1,71 @@
import QtQuick
import qs.Common
import qs.Widgets
Rectangle {
id: root
property bool hasUnread: false
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetHeight: 30
property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked()
width: notificationIcon.width + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = notificationArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
DankIcon {
id: notificationIcon
anchors.centerIn: parent
name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
size: Theme.iconSize - 6
color: SessionData.doNotDisturb ? Theme.error : (notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText)
}
Rectangle {
width: 8
height: 8
radius: 4
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: SettingsData.topBarNoBackground ? 0 : 6
anchors.topMargin: SettingsData.topBarNoBackground ? 0 : 6
visible: root.hasUnread
}
MouseArea {
id: notificationArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
root.clicked();
}
}
}

View File

@@ -7,26 +7,23 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive
readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive + PrivacyService.screensharingActive
readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
width: isVertical ? widgetThickness : (hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0)
height: isVertical ? (hasActivePrivacy ? (contentHeight + horizontalPadding * 2) : 0) : (hasActivePrivacy ? widgetThickness : 0)
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0
height: hasActivePrivacy ? widgetHeight : 0
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
visible: hasActivePrivacy
opacity: hasActivePrivacy ? 1 : 0
enabled: hasActivePrivacy
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -46,76 +43,10 @@ Rectangle {
}
}
Column {
anchors.centerIn: parent
spacing: Theme.spacingXS
visible: root.isVertical && hasActivePrivacy
Item {
width: 18
height: 18
visible: PrivacyService.microphoneActive
anchors.horizontalCenter: parent.horizontalCenter
DankIcon {
name: "mic"
size: Theme.iconSizeSmall
color: Theme.error
filled: true
anchors.centerIn: parent
}
}
Item {
width: 18
height: 18
visible: PrivacyService.cameraActive
anchors.horizontalCenter: parent.horizontalCenter
DankIcon {
name: "camera_video"
size: Theme.iconSizeSmall
color: Theme.surfaceText
filled: true
anchors.centerIn: parent
}
Rectangle {
width: 6
height: 6
radius: 3
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: -2
anchors.topMargin: -1
}
}
Item {
width: 18
height: 18
visible: PrivacyService.screensharingActive
anchors.horizontalCenter: parent.horizontalCenter
DankIcon {
name: "screen_share"
size: Theme.iconSizeSmall
color: Theme.warning
filled: true
anchors.centerIn: parent
}
}
}
Row {
anchors.centerIn: parent
spacing: Theme.spacingXS
visible: !root.isVertical && hasActivePrivacy
visible: hasActivePrivacy
Item {
width: 18
@@ -227,17 +158,7 @@ Rectangle {
}
Behavior on width {
enabled: hasActivePrivacy && visible && !isVertical
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on height {
enabled: hasActivePrivacy && visible && isVertical
enabled: hasActivePrivacy && visible
NumberAnimation {
duration: Theme.mediumDuration

View File

@@ -7,23 +7,21 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real barThickness: 48
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
property real barHeight: 48
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
width: isVertical ? widgetThickness : (ramContent.implicitWidth + horizontalPadding * 2)
height: isVertical ? (ramColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: ramContent.implicitWidth + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -45,10 +43,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
DgopService.setSortBy("memory");
if (root.toggleProcessList) {
@@ -58,47 +57,9 @@ Rectangle {
}
}
Column {
id: ramColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: 1
DankIcon {
name: "developer_board"
size: Theme.iconSize - 8
color: {
if (DgopService.memoryUsage > 90) {
return Theme.tempDanger;
}
if (DgopService.memoryUsage > 75) {
return Theme.tempWarning;
}
return Theme.surfaceText;
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
return "--";
}
return DgopService.memoryUsage.toFixed(0);
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: ramContent
visible: !root.isVertical
anchors.centerIn: parent
spacing: 3

View File

@@ -10,14 +10,13 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "left"
property var parentScreen
property var hoveredItem: null
property var topBar: null
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
// The visual root for this window
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
readonly property var sortedToplevels: {
if (SettingsData.runningAppsCurrentWorkspace) {
@@ -26,7 +25,7 @@ Rectangle {
return CompositorService.sortedToplevels;
}
readonly property int windowCount: sortedToplevels.length
readonly property int calculatedSize: {
readonly property int calculatedWidth: {
if (windowCount === 0) {
return 0;
}
@@ -38,9 +37,9 @@ Rectangle {
}
}
width: isVertical ? widgetThickness : calculatedSize
height: isVertical ? calculatedSize : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: calculatedWidth
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
visible: windowCount > 0
clip: false
color: {
@@ -48,7 +47,7 @@ Rectangle {
return "transparent";
}
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -144,22 +143,18 @@ Rectangle {
}
}
Loader {
id: layoutLoader
Row {
id: windowRow
anchors.centerIn: parent
sourceComponent: root.isVertical ? columnLayout : rowLayout
}
spacing: Theme.spacingXS
Component {
id: rowLayout
Row {
spacing: Theme.spacingXS
Repeater {
id: windowRepeater
Repeater {
id: windowRepeater
model: sortedToplevels
model: sortedToplevels
delegate: Item {
delegate: Item {
id: delegateItem
property bool isFocused: modelData.activated
@@ -293,10 +288,10 @@ Rectangle {
}
} else if (mouse.button === Qt.RightButton) {
if (tooltipLoader.item) {
tooltipLoader.item.hide();
tooltipLoader.item.hideTooltip();
}
tooltipLoader.active = false;
windowContextMenuLoader.active = true;
if (windowContextMenuLoader.item) {
windowContextMenuLoader.item.currentWindow = toplevelObject;
@@ -304,35 +299,29 @@ Rectangle {
const screenX = root.parentScreen ? root.parentScreen.x : 0;
const screenY = root.parentScreen ? root.parentScreen.y : 0;
const relativeX = globalPos.x - screenX;
const yPos = root.isVertical ? delegateItem.height / 2 : (Theme.barHeight + SettingsData.dankBarSpacing - 7);
const yPos = Theme.barHeight + SettingsData.topBarSpacing - 7;
windowContextMenuLoader.item.showAt(relativeX, yPos);
}
}
}
onEntered: {
root.hoveredItem = delegateItem;
const globalPos = delegateItem.mapToGlobal(
delegateItem.width / 2, delegateItem.height);
tooltipLoader.active = true;
if (tooltipLoader.item) {
if (root.isVertical) {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
const screenX = root.parentScreen ? root.parentScreen.x : 0;
const screenY = root.parentScreen ? root.parentScreen.y : 0;
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 isLeft = root.axis?.edge === "left";
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft);
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height);
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS;
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false);
}
const tooltipY = Theme.barHeight
+ SettingsData.topBarSpacing + Theme.spacingXS;
tooltipLoader.item.showTooltip(
delegateItem.tooltipText, globalPos.x,
tooltipY, root.parentScreen);
}
}
onExited: {
if (root.hoveredItem === delegateItem) {
root.hoveredItem = null;
if (tooltipLoader.item) {
tooltipLoader.item.hide();
tooltipLoader.item.hideTooltip();
}
tooltipLoader.active = false;
@@ -341,198 +330,6 @@ Rectangle {
}
}
}
}
}
Component {
id: columnLayout
Column {
spacing: Theme.spacingXS
Repeater {
id: windowRepeater
model: sortedToplevels
delegate: Item {
id: delegateItem
property bool isFocused: modelData.activated
property string appId: modelData.appId || ""
property string windowTitle: modelData.title || "(Unnamed)"
property var toplevelObject: modelData
property string tooltipText: {
let appName = "Unknown";
if (appId) {
const desktopEntry = DesktopEntries.heuristicLookup(appId);
appName = desktopEntry
&& desktopEntry.name ? desktopEntry.name : appId;
}
return appName + (windowTitle ? " • " + windowTitle : "")
}
width: SettingsData.runningAppsCompactMode ? 24 : (24 + Theme.spacingXS + 120)
height: 24
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: {
if (isFocused) {
return mouseArea.containsMouse ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.3) : Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.2);
} else {
return mouseArea.containsMouse ? Qt.rgba(
Theme.primaryHover.r,
Theme.primaryHover.g,
Theme.primaryHover.b,
0.1) : "transparent";
}
}
}
IconImage {
id: iconImg
anchors.left: parent.left
anchors.leftMargin: SettingsData.runningAppsCompactMode ? (parent.width - 18) / 2 : Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
width: 18
height: 18
source: {
const moddedId = Paths.moddedAppId(appId)
if (moddedId.toLowerCase().includes("steam_app")) {
return ""
}
return Quickshell.iconPath(DesktopEntries.heuristicLookup(moddedId)?.icon, true)
}
smooth: true
mipmap: true
asynchronous: true
visible: status === Image.Ready
}
DankIcon {
anchors.left: parent.left
anchors.leftMargin: SettingsData.runningAppsCompactMode ? (parent.width - 18) / 2 : Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
size: 18
name: "sports_esports"
color: Theme.surfaceText
visible: {
const moddedId = Paths.moddedAppId(appId)
return moddedId.toLowerCase().includes("steam_app")
}
}
Text {
anchors.centerIn: parent
visible: {
const moddedId = Paths.moddedAppId(appId)
const isSteamApp = moddedId.toLowerCase().includes("steam_app")
return !iconImg.visible && !isSteamApp
}
text: {
if (!appId) {
return "?";
}
const desktopEntry = DesktopEntries.heuristicLookup(appId);
if (desktopEntry && desktopEntry.name) {
return desktopEntry.name.charAt(0).toUpperCase();
}
return appId.charAt(0).toUpperCase();
}
font.pixelSize: 10
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
anchors.left: iconImg.right
anchors.leftMargin: Theme.spacingXS
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.runningAppsCompactMode
text: windowTitle
font.pixelSize: Theme.fontSizeMedium - 1
color: Theme.surfaceText
font.weight: Font.Medium
elide: Text.ElideRight
maximumLineCount: 1
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: (mouse) => {
if (mouse.button === Qt.LeftButton) {
if (toplevelObject) {
toplevelObject.activate();
}
} else if (mouse.button === Qt.RightButton) {
if (tooltipLoader.item) {
tooltipLoader.item.hide();
}
tooltipLoader.active = false;
windowContextMenuLoader.active = true;
if (windowContextMenuLoader.item) {
windowContextMenuLoader.item.currentWindow = toplevelObject;
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
const screenX = root.parentScreen ? root.parentScreen.x : 0;
const screenY = root.parentScreen ? root.parentScreen.y : 0;
const relativeX = globalPos.x - screenX;
const yPos = root.isVertical ? delegateItem.height / 2 : (Theme.barHeight + SettingsData.dankBarSpacing - 7);
windowContextMenuLoader.item.showAt(relativeX, yPos);
}
}
}
onEntered: {
root.hoveredItem = delegateItem;
tooltipLoader.active = true;
if (tooltipLoader.item) {
if (root.isVertical) {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
const screenX = root.parentScreen ? root.parentScreen.x : 0;
const screenY = root.parentScreen ? root.parentScreen.y : 0;
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 isLeft = root.axis?.edge === "left";
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft);
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height);
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS;
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false);
}
}
}
onExited: {
if (root.hoveredItem === delegateItem) {
root.hoveredItem = null;
if (tooltipLoader.item) {
tooltipLoader.item.hide();
}
tooltipLoader.active = false;
}
}
}
}
}
}
}
Loader {
@@ -540,7 +337,7 @@ Rectangle {
active: false
sourceComponent: DankTooltip {}
sourceComponent: RunningAppsTooltip {}
}
Loader {

View File

@@ -6,30 +6,21 @@ import qs.Common
PanelWindow {
id: root
property string text: ""
property string tooltipText: ""
property real targetX: 0
property real targetY: 0
property var targetScreen: null
property bool alignLeft: false
property bool alignRight: false
function show(text, x, y, screen, leftAlign, rightAlign) {
root.text = text;
if (screen) {
targetScreen = screen;
const screenX = screen.x || 0;
targetX = x - screenX;
} else {
targetScreen = null;
targetX = x;
}
function showTooltip(text, x, y, screen) {
tooltipText = text;
targetScreen = screen;
const screenX = screen ? screen.x : 0;
targetX = x - screenX;
targetY = y;
alignLeft = leftAlign ?? false;
alignRight = rightAlign ?? false;
visible = true;
}
function hide() {
function hideTooltip() {
visible = false;
}
@@ -47,15 +38,8 @@ PanelWindow {
}
margins {
left: {
if (alignLeft) return Math.round(targetX)
if (alignRight) return Math.round(targetX - implicitWidth)
return Math.round(targetX - implicitWidth / 2)
}
top: {
if (alignLeft || alignRight) return Math.round(targetY - implicitHeight / 2)
return Math.round(targetY)
}
left: Math.round(targetX - implicitWidth / 2)
top: Math.round(targetY)
}
Rectangle {
@@ -69,13 +53,15 @@ PanelWindow {
id: textContent
anchors.centerIn: parent
text: root.text
text: root.tooltipText
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
wrapMode: Text.NoWrap
maximumLineCount: 1
elide: Text.ElideRight
width: Math.min(implicitWidth, 300 - Theme.spacingM * 2)
width: parent.width - Theme.spacingM * 2
}
}
}
}

View File

@@ -0,0 +1,123 @@
import QtQuick
import Quickshell
import Quickshell.Services.SystemTray
import Quickshell.Widgets
import qs.Common
Rectangle {
id: root
property var parentWindow: null
property var parentScreen: null
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
readonly property int calculatedWidth: SystemTray.items.values.length > 0 ? SystemTray.items.values.length * 24 + horizontalPadding * 2 : 0
width: calculatedWidth
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SystemTray.items.values.length === 0) {
return "transparent";
}
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
visible: SystemTray.items.values.length > 0
Row {
id: systemTrayRow
anchors.centerIn: parent
spacing: 0
Repeater {
model: SystemTray.items.values
delegate: Item {
property var trayItem: modelData
property string iconSource: {
let icon = trayItem && trayItem.icon;
if (typeof icon === 'string' || icon instanceof String) {
if (icon.includes("?path=")) {
const split = icon.split("?path=");
if (split.length !== 2) {
return icon;
}
const name = split[0];
const path = split[1];
const fileName = name.substring(name.lastIndexOf("/") + 1);
return `file://${path}/${fileName}`;
}
return icon;
}
return "";
}
width: 24
height: 24
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: trayItemArea.containsMouse ? Theme.primaryHover : "transparent"
}
IconImage {
anchors.centerIn: parent
width: 16
height: 16
source: parent.iconSource
asynchronous: true
smooth: true
mipmap: true
}
MouseArea {
id: trayItemArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (!trayItem) {
return;
}
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate();
return ;
}
if (trayItem.hasMenu) {
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
menuAnchor.menu = trayItem.menu;
menuAnchor.anchor.window = parentWindow;
menuAnchor.anchor.rect = Qt.rect(relativeX, parentWindow.effectiveBarHeight + SettingsData.topBarSpacing, parent.width, 1);
menuAnchor.open();
}
}
}
}
}
}
QsMenuAnchor {
id: menuAnchor
}
}

View File

@@ -0,0 +1,104 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property real widgetHeight: 30
property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
readonly property bool hasUpdates: SystemUpdateService.updateCount > 0
readonly property bool isChecking: SystemUpdateService.isChecking
signal clicked()
width: updaterIcon.width + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = updaterArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Row {
id: updaterIcon
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
id: statusIcon
anchors.verticalCenter: parent.verticalCenter
name: {
if (isChecking) return "refresh";
if (SystemUpdateService.hasError) return "error";
if (hasUpdates) return "system_update_alt";
return "check_circle";
}
size: Theme.iconSize - 6
color: {
if (SystemUpdateService.hasError) return Theme.error;
if (hasUpdates) return Theme.primary;
return (updaterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText);
}
RotationAnimation {
id: rotationAnimation
target: statusIcon
property: "rotation"
from: 0
to: 360
duration: 1000
running: isChecking
loops: Animation.Infinite
onRunningChanged: {
if (!running) {
statusIcon.rotation = 0
}
}
}
}
StyledText {
id: countText
anchors.verticalCenter: parent.verticalCenter
text: SystemUpdateService.updateCount.toString()
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
visible: hasUpdates && !isChecking
}
}
MouseArea {
id: updaterArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
root.clicked();
}
}
}

1259
Modules/TopBar/TopBar.qml Normal file

File diff suppressed because it is too large Load Diff

113
Modules/TopBar/Vpn.qml Normal file
View File

@@ -0,0 +1,113 @@
import QtQuick
import Quickshell
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
// Passed in by TopBar
property int widgetHeight: 28
property int barHeight: 32
property string section: "right"
property var popupTarget: null
property var parentScreen: null
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal toggleVpnPopup()
width: Theme.iconSize + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = clickArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
DankIcon {
id: icon
name: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
size: Theme.iconSize - 6
color: VpnService.connected ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
RotationAnimation on rotation {
running: VpnService.isBusy
loops: Animation.Infinite
from: 0
to: 360
duration: 900
}
}
MouseArea {
id: clickArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
root.toggleVpnPopup();
}
}
Rectangle {
id: tooltip
width: Math.max(120, tooltipText.contentWidth + Theme.spacingM * 2)
height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.widgetBaseBackgroundColor
border.color: Theme.surfaceVariantAlpha
border.width: 1
visible: clickArea.containsMouse && !(popupTarget && popupTarget.shouldBeVisible)
anchors.bottom: parent.top
anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter
opacity: clickArea.containsMouse ? 1 : 0
Text {
id: tooltipText
anchors.centerIn: parent
text: {
if (!VpnService.connected) {
return "VPN Disconnected";
}
const names = VpnService.activeNames || [];
if (names.length <= 1) {
return "VPN Connected • " + (names[0] || "");
}
return "VPN Connected • " + names[0] + " +" + (names.length - 1);
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
}
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -13,6 +13,7 @@ import qs.Widgets
DankPopout {
id: root
property string triggerSection: "right"
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
@@ -26,9 +27,9 @@ DankPopout {
popupWidth: 360
popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 260)
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.popupDistance
triggerWidth: 70
positioning: ""
positioning: "center"
screen: triggerScreen
shouldBeVisible: false
visible: shouldBeVisible

View File

@@ -6,23 +6,21 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "center"
property var popupTarget: null
property var parentScreen: null
property real barThickness: 48
property real widgetThickness: 30
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
property real barHeight: 48
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
signal clicked()
visible: SettingsData.weatherEnabled
width: isVertical ? widgetThickness : (visible ? Math.min(100, weatherRow.implicitWidth + horizontalPadding * 2) : 0)
height: isVertical ? (weatherColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: visible ? Math.min(100, weatherRow.implicitWidth + horizontalPadding * 2) : 0
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
if (SettingsData.topBarNoBackground) {
return "transparent";
}
@@ -34,37 +32,9 @@ Rectangle {
service: WeatherService
}
Column {
id: weatherColumn
visible: root.isVertical
anchors.centerIn: parent
spacing: 1
DankIcon {
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
size: Theme.iconSize - 4
color: Theme.primary
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: {
const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
if (temp === undefined || temp === null || temp === 0) {
return "--";
}
return temp;
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Row {
id: weatherRow
visible: !root.isVertical
anchors.centerIn: parent
spacing: Theme.spacingXS
@@ -99,10 +69,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + SettingsData.topBarSpacing + SettingsData.topBarBottomGap - 2 + Theme.popupDistance, width, section, currentScreen);
}
root.clicked();
}

View File

@@ -10,8 +10,6 @@ import qs.Widgets
Rectangle {
id: root
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string screenName: ""
property real widgetHeight: 30
property int currentWorkspace: {
@@ -194,9 +192,7 @@ Rectangle {
return currentMonitor.activeWorkspace?.id ?? 1
}
readonly property real padding: isVertical
? Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
: (widgetHeight - workspaceRow.implicitHeight) / 2
readonly property real padding: (widgetHeight - workspaceRow.implicitHeight) / 2
function getRealWorkspaces() {
return root.workspaceList.filter(ws => {
@@ -225,11 +221,11 @@ Rectangle {
}
}
width: isVertical ? widgetHeight : (workspaceRow.implicitWidth + padding * 2)
height: isVertical ? (workspaceRow.implicitHeight + padding * 2) : widgetHeight
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
width: workspaceRow.implicitWidth + padding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground)
if (SettingsData.topBarNoBackground)
return "transparent"
const baseColor = Theme.widgetBaseBackgroundColor
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
@@ -265,12 +261,11 @@ Rectangle {
}
}
Flow {
Row {
id: workspaceRow
anchors.centerIn: parent
spacing: Theme.spacingS
flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight
Repeater {
model: root.workspaceList
@@ -337,32 +332,16 @@ Rectangle {
}
width: {
if (root.isVertical) {
return SettingsData.showWorkspaceApps ? widgetHeight * 0.7 : widgetHeight * 0.5;
} else {
if (SettingsData.showWorkspaceApps && loadedIcons.length > 0) {
const numIcons = Math.min(loadedIcons.length, SettingsData.maxWorkspaceIcons);
const iconsWidth = numIcons * 18 + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0);
const baseWidth = isActive ? root.widgetHeight * 0.9 + Theme.spacingXS : root.widgetHeight * 0.7;
return baseWidth + iconsWidth;
}
return isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7;
if (SettingsData.showWorkspaceApps && loadedIcons.length > 0) {
const numIcons = Math.min(loadedIcons.length, SettingsData.maxWorkspaceIcons);
const iconsWidth = numIcons * 18 + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0);
const baseWidth = isActive ? root.widgetHeight * 1.0 + Theme.spacingXS : root.widgetHeight * 0.8;
return baseWidth + iconsWidth;
}
return isActive ? root.widgetHeight * 1.2 : root.widgetHeight * 0.8;
}
height: {
if (root.isVertical) {
if (SettingsData.showWorkspaceApps && loadedIcons.length > 0) {
const numIcons = Math.min(loadedIcons.length, SettingsData.maxWorkspaceIcons);
const iconsHeight = numIcons * 18 + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0);
const baseHeight = isActive ? root.widgetHeight * 0.9 + Theme.spacingXS : root.widgetHeight * 0.7;
return baseHeight + iconsHeight;
}
return isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7;
} else {
return SettingsData.showWorkspaceApps ? widgetHeight * 0.7 : widgetHeight * 0.5;
}
}
radius: Math.min(width, height) / 2
height: SettingsData.showWorkspaceApps ? widgetHeight * 0.8 : widgetHeight * 0.6
radius: height / 2
color: isActive ? Theme.primary : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha
Behavior on width {
@@ -373,20 +352,10 @@ Rectangle {
}
}
Behavior on height {
enabled: root.isVertical && (!SettingsData.showWorkspaceApps || SettingsData.maxWorkspaceIcons <= 3)
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
MouseArea {
id: mouseArea
anchors.centerIn: parent
width: root.isVertical ? parent.width + Theme.spacingXL : parent.width
height: root.isVerical ? parent.height : parent.height + Theme.spacingXL
anchors.fill: parent
hoverEnabled: !isPlaceholder
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
enabled: !isPlaceholder
@@ -403,149 +372,74 @@ Rectangle {
}
}
// Loader for App Icons
Loader {
id: appIconsLoader
anchors.fill: parent
active: SettingsData.showWorkspaceApps
sourceComponent: Item {
Loader {
Row {
id: contentRow
anchors.centerIn: parent
sourceComponent: root.isVertical ? columnLayout : rowLayout
}
spacing: 4
visible: loadedIcons.length > 0
Component {
id: rowLayout
Row {
spacing: 4
visible: loadedIcons.length > 0
Repeater {
model: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons)
delegate: Item {
width: 18
height: 18
Repeater {
model: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons)
delegate: Item {
width: 18
height: 18
IconImage {
id: appIcon
property var windowId: modelData.windowId
anchors.fill: parent
source: modelData.icon
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
visible: !modelData.isSteamApp
}
IconImage {
id: appIcon
property var windowId: modelData.windowId
anchors.fill: parent
source: modelData.icon
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
visible: !modelData.isSteamApp
}
DankIcon {
anchors.centerIn: parent
size: 18
name: "sports_esports"
color: Theme.surfaceText
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
visible: modelData.isSteamApp
}
DankIcon {
anchors.centerIn: parent
size: 18
name: "sports_esports"
color: Theme.surfaceText
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
visible: modelData.isSteamApp
}
MouseArea {
id: appMouseArea
hoverEnabled: true
anchors.fill: parent
enabled: isActive
cursorShape: Qt.PointingHandCursor
onClicked: {
if (CompositorService.isHyprland) {
Hyprland.dispatch(`focuswindow address:${appIcon.windowId}`)
} else if (CompositorService.isNiri) {
NiriService.focusWindow(appIcon.windowId)
}
}
}
Rectangle {
visible: modelData.count > 1 && !isActive
width: 12
height: 12
radius: 6
color: "black"
border.color: "white"
border.width: 1
anchors.right: parent.right
anchors.bottom: parent.bottom
z: 2
Text {
anchors.centerIn: parent
text: modelData.count
font.pixelSize: 8
color: "white"
MouseArea {
id: appMouseArea
hoverEnabled: true
anchors.fill: parent
enabled: isActive
cursorShape: Qt.PointingHandCursor
onClicked: {
if (CompositorService.isHyprland) {
Hyprland.dispatch(`focuswindow address:${appIcon.windowId}`)
} else if (CompositorService.isNiri) {
NiriService.focusWindow(appIcon.windowId)
}
}
}
}
}
}
Component {
id: columnLayout
Column {
spacing: 4
visible: loadedIcons.length > 0
Rectangle {
visible: modelData.count > 1 && !isActive
width: 12
height: 12
radius: 6
color: "black"
border.color: "white"
border.width: 1
anchors.right: parent.right
anchors.bottom: parent.bottom
z: 2
Repeater {
model: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons)
delegate: Item {
width: 18
height: 18
IconImage {
id: appIcon
property var windowId: modelData.windowId
anchors.fill: parent
source: modelData.icon
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
visible: !modelData.isSteamApp
}
DankIcon {
Text {
anchors.centerIn: parent
size: 18
name: "sports_esports"
color: Theme.surfaceText
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
visible: modelData.isSteamApp
}
MouseArea {
id: appMouseArea
hoverEnabled: true
anchors.fill: parent
enabled: isActive
cursorShape: Qt.PointingHandCursor
onClicked: {
if (CompositorService.isHyprland) {
Hyprland.dispatch(`focuswindow address:${appIcon.windowId}`)
} else if (CompositorService.isNiri) {
NiriService.focusWindow(appIcon.windowId)
}
}
}
Rectangle {
visible: modelData.count > 1 && !isActive
width: 12
height: 12
radius: 6
color: "black"
border.color: "white"
border.width: 1
anchors.right: parent.right
anchors.bottom: parent.bottom
z: 2
Text {
anchors.centerIn: parent
text: modelData.count
font.pixelSize: 8
color: "white"
}
text: modelData.count
font.pixelSize: 8
color: "white"
}
}
}

View File

@@ -38,18 +38,6 @@ LazyLoader {
property bool isColorSource: source.startsWith("#")
property string transitionType: SessionData.wallpaperTransition
property string actualTransitionType: transitionType
Connections {
target: SessionData
function onIsLightModeChanged() {
if (SessionData.perModeWallpaper) {
var newSource = SessionData.getMonitorWallpaper(modelData.name) || ""
if (newSource !== root.source) {
root.source = newSource
}
}
}
}
onTransitionTypeChanged: {
if (transitionType === "random") {
if (SessionData.includedTransitions.length === 0) {
@@ -89,6 +77,7 @@ LazyLoader {
monitor: modelData.name
}
Component.onDestruction: {
weProc.stop()
}
@@ -127,10 +116,8 @@ LazyLoader {
}
function changeWallpaper(newPath, force) {
if (!force && newPath === currentWallpaper.source)
return
if (!newPath || newPath.startsWith("#"))
return
if (!force && newPath === currentWallpaper.source) return
if (!newPath || newPath.startsWith("#")) return
if (root.transitioning) {
transitionAnimation.stop()
@@ -176,6 +163,7 @@ LazyLoader {
}
}
Loader {
anchors.fill: parent
active: !root.source || root.isColorSource
@@ -224,14 +212,15 @@ LazyLoader {
fillMode: Image.PreserveAspectCrop
onStatusChanged: {
if (status !== Image.Ready)
return
if (status !== Image.Ready) return
if (root.actualTransitionType === "none") {
currentWallpaper.source = source
nextWallpaper.source = ""
root.transitionProgress = 0.0
} else {
currentWallpaper.layer.enabled = true
layer.enabled = true
visible = true
if (!root.transitioning) {
transitionAnimation.start()
@@ -240,185 +229,166 @@ LazyLoader {
}
}
Loader {
id: effectLoader
ShaderEffect {
id: fadeShader
anchors.fill: parent
active: root.actualTransitionType !== "none" && (root.hasCurrent || root.booting)
sourceComponent: {
switch (root.actualTransitionType) {
case "fade":
return fadeComp
case "wipe":
return wipeComp
case "disc":
return discComp
case "stripes":
return stripesComp
case "iris bloom":
return irisComp
case "pixelate":
return pixelateComp
case "portal":
return portalComp
default:
return null
}
}
visible: root.actualTransitionType === "fade" && (root.hasCurrent || root.booting)
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_fade.frag.qsb")
}
Component {
id: fadeComp
ShaderEffect {
anchors.fill: parent
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_fade.frag.qsb")
}
ShaderEffect {
id: wipeShader
anchors.fill: parent
visible: root.actualTransitionType === "wipe" && (root.hasCurrent || root.booting)
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real direction: root.wipeDirection
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_wipe.frag.qsb")
}
Component {
id: wipeComp
ShaderEffect {
anchors.fill: parent
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real direction: root.wipeDirection
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_wipe.frag.qsb")
}
ShaderEffect {
id: discShader
anchors.fill: parent
visible: root.actualTransitionType === "disc" && (root.hasCurrent || root.booting)
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_disc.frag.qsb")
}
Component {
id: discComp
ShaderEffect {
anchors.fill: parent
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_disc.frag.qsb")
}
ShaderEffect {
id: stripesShader
anchors.fill: parent
visible: root.actualTransitionType === "stripes" && (root.hasCurrent || root.booting)
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real stripeCount: root.stripesCount
property real angle: root.stripesAngle
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_stripes.frag.qsb")
}
Component {
id: stripesComp
ShaderEffect {
anchors.fill: parent
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real stripeCount: root.stripesCount
property real angle: root.stripesAngle
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_stripes.frag.qsb")
}
ShaderEffect {
id: irisBloomShader
anchors.fill: parent
visible: root.actualTransitionType === "iris bloom" && (root.hasCurrent || root.booting)
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real centerX: 0.5
property real centerY: 0.5
property real aspectRatio: root.width / root.height
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_iris_bloom.frag.qsb")
}
Component {
id: irisComp
ShaderEffect {
anchors.fill: parent
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real centerX: 0.5
property real centerY: 0.5
property real aspectRatio: root.width / root.height
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_iris_bloom.frag.qsb")
}
ShaderEffect {
id: pixelateShader
anchors.fill: parent
visible: root.actualTransitionType === "pixelate" && (root.hasCurrent || root.booting)
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness // controls starting block size
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
property real aspectRatio: root.width / root.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_pixelate.frag.qsb")
}
Component {
id: pixelateComp
ShaderEffect {
anchors.fill: parent
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
property real aspectRatio: root.width / root.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_pixelate.frag.qsb")
}
}
ShaderEffect {
id: portalShader
anchors.fill: parent
visible: root.actualTransitionType === "portal" && (root.hasCurrent || root.booting)
Component {
id: portalComp
ShaderEffect {
anchors.fill: parent
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_portal.frag.qsb")
}
property variant source1: root.hasCurrent ? currentWallpaper : transparentSource
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: Math.max(1, root.hasCurrent ? source1.sourceSize.width : modelData.width)
property real imageHeight1: Math.max(1, root.hasCurrent ? source1.sourceSize.height : modelData.height)
property real imageWidth2: Math.max(1, source2.sourceSize.width)
property real imageHeight2: Math.max(1, source2.sourceSize.height)
property real screenWidth: modelData.width
property real screenHeight: modelData.height
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_portal.frag.qsb")
}
NumberAnimation {
@@ -431,14 +401,16 @@ LazyLoader {
easing.type: Easing.InOutCubic
onFinished: {
Qt.callLater(() => {
if (nextWallpaper.source && nextWallpaper.status === Image.Ready && !nextWallpaper.source.toString().startsWith("#")) {
currentWallpaper.source = nextWallpaper.source
}
nextWallpaper.source = ""
nextWallpaper.visible = false
currentWallpaper.visible = root.actualTransitionType === "none"
root.transitionProgress = 0.0
})
if (nextWallpaper.source && nextWallpaper.status === Image.Ready && !nextWallpaper.source.toString().startsWith("#")) {
currentWallpaper.source = nextWallpaper.source
}
nextWallpaper.source = ""
nextWallpaper.visible = false
currentWallpaper.visible = root.actualTransitionType === "none"
currentWallpaper.layer.enabled = false
nextWallpaper.layer.enabled = false
root.transitionProgress = 0.0
})
}
}
}

View File

@@ -175,60 +175,6 @@ paru -S dms-shell-git
nix profile install github:AvengeMedia/DankMaterialShell
```
#### nixOS - via home-manager
To install using home-manager, you need to add this repo into your flake inputs:
``` nix
dankMaterialShell = {
url = "github:AvengeMedia/DankMaterialShell";
inputs.nixpkgs.follows = "nixpkgs";
};
```
Then somewhere in your home-manager config, add this to the imports:
``` nix
imports = [
inputs.dankMaterialShell.homeModules.dankMaterialShell.default
];
```
If you use Niri, the `niri` homeModule provides additional options for Niri integration, such as key bindings and spawn:
``` nix
imports = [
inputs.dankMaterialShell.homeModules.dankMaterialShell.default
inputs.dankMaterialShell.homeModules.dankMaterialShell.niri
];
```
> [!IMPORTANT]
> To use the `niri` homeModule, you must have `sobidoo/niri-flake` in your inputs:
``` nix
niri = {
url = "github:sodiboo/niri-flake";
inputs.nixpkgs.follows = "nixpkgs";
};
```
And import it in home-manager:
``` nix
imports = [
inputs.niri.homeModules.niri
];
```
Now you can enable it with:
``` nix
programs.dankMaterialShell.enable = true;
```
There are a lot of possible configurations that you can enable/disable in the flake, check [nix/default.nix](nix/default.nix) and [nix/niri.nix](nix/niri.nix) to see them all.
#### Other Distributions - via manual installation
**1. Install Quickshell (Varies by Distribution)**
@@ -727,6 +673,5 @@ DankMaterialShell welcomes contributions! Whether it's bug fixes, new widgets, t
- [quickshell](https://quickshell.org/) the core of what makes a shell like this possible.
- [niri](https://github.com/YaLTeR/niri) for the awesome scrolling compositor.
- [Ly-sec](http://github.com/ly-sec) for awesome wallpaper effects among other things from [Noctalia](https://github.com/noctalia-dev/noctalia-shell)
- [soramanew](https://github.com/soramanew) who built [caelestia](https://github.com/caelestia-dots/shell) which served as inspiration and guidance for many dank widgets.
- [end-4](https://github.com/end-4) for [dots-hyprland](https://github.com/end-4/dots-hyprland) which also served as inspiration and guidance for many dank widgets.

Some files were not shown because too many files have changed in this diff Show More