mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-30 00:12:50 -05:00
meta: Vertical Bar, Notification Popup Position Options, ++
- CC Color picker widget - Tooltips in more places - Attempt to improve niri screen transitiosn
This commit is contained in:
@@ -140,7 +140,8 @@ Singleton {
|
|||||||
property bool dankBarSquareCorners: false
|
property bool dankBarSquareCorners: false
|
||||||
property bool dankBarNoBackground: false
|
property bool dankBarNoBackground: false
|
||||||
property bool dankBarGothCornersEnabled: false
|
property bool dankBarGothCornersEnabled: false
|
||||||
property bool dankBarAtBottom: false
|
property int dankBarPosition: SettingsData.Position.Top
|
||||||
|
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
|
||||||
property bool lockScreenShowPowerActions: true
|
property bool lockScreenShowPowerActions: true
|
||||||
property bool hideBrightnessSlider: false
|
property bool hideBrightnessSlider: false
|
||||||
property string widgetBackgroundColor: "sch"
|
property string widgetBackgroundColor: "sch"
|
||||||
@@ -148,6 +149,7 @@ Singleton {
|
|||||||
property int notificationTimeoutLow: 5000
|
property int notificationTimeoutLow: 5000
|
||||||
property int notificationTimeoutNormal: 5000
|
property int notificationTimeoutNormal: 5000
|
||||||
property int notificationTimeoutCritical: 0
|
property int notificationTimeoutCritical: 0
|
||||||
|
property int notificationPopupPosition: SettingsData.Position.Top
|
||||||
property var screenPreferences: ({})
|
property var screenPreferences: ({})
|
||||||
readonly property string defaultFontFamily: "Inter Variable"
|
readonly property string defaultFontFamily: "Inter Variable"
|
||||||
readonly property string defaultMonoFontFamily: "Fira Code"
|
readonly property string defaultMonoFontFamily: "Fira Code"
|
||||||
@@ -335,13 +337,14 @@ Singleton {
|
|||||||
notificationTimeoutLow = settings.notificationTimeoutLow !== undefined ? settings.notificationTimeoutLow : 5000
|
notificationTimeoutLow = settings.notificationTimeoutLow !== undefined ? settings.notificationTimeoutLow : 5000
|
||||||
notificationTimeoutNormal = settings.notificationTimeoutNormal !== undefined ? settings.notificationTimeoutNormal : 5000
|
notificationTimeoutNormal = settings.notificationTimeoutNormal !== undefined ? settings.notificationTimeoutNormal : 5000
|
||||||
notificationTimeoutCritical = settings.notificationTimeoutCritical !== undefined ? settings.notificationTimeoutCritical : 0
|
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)
|
dankBarSpacing = settings.dankBarSpacing !== undefined ? settings.dankBarSpacing : (settings.topBarSpacing !== undefined ? settings.topBarSpacing : 4)
|
||||||
dankBarBottomGap = settings.dankBarBottomGap !== undefined ? settings.dankBarBottomGap : (settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0)
|
dankBarBottomGap = settings.dankBarBottomGap !== undefined ? settings.dankBarBottomGap : (settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0)
|
||||||
dankBarInnerPadding = settings.dankBarInnerPadding !== undefined ? settings.dankBarInnerPadding : (settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 4)
|
dankBarInnerPadding = settings.dankBarInnerPadding !== undefined ? settings.dankBarInnerPadding : (settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 4)
|
||||||
dankBarSquareCorners = settings.dankBarSquareCorners !== undefined ? settings.dankBarSquareCorners : (settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false)
|
dankBarSquareCorners = settings.dankBarSquareCorners !== undefined ? settings.dankBarSquareCorners : (settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false)
|
||||||
dankBarNoBackground = settings.dankBarNoBackground !== undefined ? settings.dankBarNoBackground : (settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : 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)
|
dankBarGothCornersEnabled = settings.dankBarGothCornersEnabled !== undefined ? settings.dankBarGothCornersEnabled : (settings.topBarGothCornersEnabled !== undefined ? settings.topBarGothCornersEnabled : false)
|
||||||
dankBarAtBottom = settings.dankBarAtBottom !== undefined ? settings.dankBarAtBottom : (settings.topBarAtBottom !== undefined ? settings.topBarAtBottom : 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))
|
||||||
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
||||||
hideBrightnessSlider = settings.hideBrightnessSlider !== undefined ? settings.hideBrightnessSlider : false
|
hideBrightnessSlider = settings.hideBrightnessSlider !== undefined ? settings.hideBrightnessSlider : false
|
||||||
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
||||||
@@ -456,7 +459,7 @@ Singleton {
|
|||||||
"dankBarSquareCorners": dankBarSquareCorners,
|
"dankBarSquareCorners": dankBarSquareCorners,
|
||||||
"dankBarNoBackground": dankBarNoBackground,
|
"dankBarNoBackground": dankBarNoBackground,
|
||||||
"dankBarGothCornersEnabled": dankBarGothCornersEnabled,
|
"dankBarGothCornersEnabled": dankBarGothCornersEnabled,
|
||||||
"dankBarAtBottom": dankBarAtBottom,
|
"dankBarPosition": dankBarPosition,
|
||||||
"lockScreenShowPowerActions": lockScreenShowPowerActions,
|
"lockScreenShowPowerActions": lockScreenShowPowerActions,
|
||||||
"hideBrightnessSlider": hideBrightnessSlider,
|
"hideBrightnessSlider": hideBrightnessSlider,
|
||||||
"widgetBackgroundColor": widgetBackgroundColor,
|
"widgetBackgroundColor": widgetBackgroundColor,
|
||||||
@@ -464,6 +467,7 @@ Singleton {
|
|||||||
"notificationTimeoutLow": notificationTimeoutLow,
|
"notificationTimeoutLow": notificationTimeoutLow,
|
||||||
"notificationTimeoutNormal": notificationTimeoutNormal,
|
"notificationTimeoutNormal": notificationTimeoutNormal,
|
||||||
"notificationTimeoutCritical": notificationTimeoutCritical,
|
"notificationTimeoutCritical": notificationTimeoutCritical,
|
||||||
|
"notificationPopupPosition": notificationPopupPosition,
|
||||||
"screenPreferences": screenPreferences
|
"screenPreferences": screenPreferences
|
||||||
}, null, 2))
|
}, null, 2))
|
||||||
}
|
}
|
||||||
@@ -580,11 +584,11 @@ Singleton {
|
|||||||
|
|
||||||
function applyStoredTheme() {
|
function applyStoredTheme() {
|
||||||
if (typeof Theme !== "undefined")
|
if (typeof Theme !== "undefined")
|
||||||
Theme.switchTheme(currentThemeName, false)
|
Theme.switchTheme(currentThemeName, false, false)
|
||||||
else
|
else
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
if (typeof Theme !== "undefined")
|
if (typeof Theme !== "undefined")
|
||||||
Theme.switchTheme(currentThemeName, false)
|
Theme.switchTheme(currentThemeName, false, false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -976,8 +980,13 @@ Singleton {
|
|||||||
|
|
||||||
function setShowDock(enabled) {
|
function setShowDock(enabled) {
|
||||||
showDock = enabled
|
showDock = enabled
|
||||||
if (enabled && dankBarAtBottom && dockPosition === SettingsData.Position.Bottom) {
|
if (enabled && dankBarPosition === SettingsData.Position.Top) {
|
||||||
setDankBarAtBottom(false)
|
setDockPosition(SettingsData.Position.Bottom)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (enabled && dankBarPosition === SettingsData.Position.Top) {
|
||||||
|
setDockPosition(SettingsData.Position.Bottom)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
@@ -1042,6 +1051,56 @@ Singleton {
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setNotificationPopupPosition(position) {
|
||||||
|
notificationPopupPosition = position
|
||||||
|
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) {
|
function setDankBarSpacing(spacing) {
|
||||||
dankBarSpacing = spacing
|
dankBarSpacing = spacing
|
||||||
saveSettings()
|
saveSettings()
|
||||||
@@ -1072,24 +1131,26 @@ Singleton {
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDankBarAtBottom(enabled) {
|
function setDankBarPosition(position) {
|
||||||
dankBarAtBottom = enabled
|
dankBarPosition = position
|
||||||
if (enabled && showDock && dockPosition === SettingsData.Position.Bottom) {
|
if (position === SettingsData.Position.Bottom && showDock) {
|
||||||
setDockPosition(SettingsData.Position.Top)
|
setDockPosition(SettingsData.Position.Top)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (!enabled && showDock && dockPosition === SettingsData.Position.Top) {
|
if (position === SettingsData.Position.Top && showDock) {
|
||||||
setDockPosition(SettingsData.Position.Bottom)
|
setDockPosition(SettingsData.Position.Bottom)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDockPosition(position) {
|
function setDockPosition(position) {
|
||||||
dockPosition = position
|
dockPosition = position
|
||||||
if (position === SettingsData.Position.Bottom && dankBarAtBottom && showDock) {
|
if (position === SettingsData.Position.Bottom && dankBarPosition === SettingsData.Position.Bottom && showDock) {
|
||||||
setDankBarAtBottom(false)
|
setDankBarPosition(SettingsData.Position.Top)
|
||||||
}
|
}
|
||||||
if (position === SettingsData.Position.Top && !dankBarAtBottom && showDock) {
|
if (position === SettingsData.Position.Top && dankBarPosition === SettingsData.Position.Top && showDock) {
|
||||||
setDankBarAtBottom(true)
|
setDankBarPosition(SettingsData.Position.Bottom)
|
||||||
}
|
}
|
||||||
saveSettings()
|
saveSettings()
|
||||||
Qt.callLater(() => forceDockLayoutRefresh())
|
Qt.callLater(() => forceDockLayoutRefresh())
|
||||||
@@ -1108,7 +1169,28 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getPopupYPosition(barHeight) {
|
function getPopupYPosition(barHeight) {
|
||||||
return barHeight + dankBarSpacing + dankBarBottomGap - 2 + Theme.popupDistance
|
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) {
|
function setLockScreenShowPowerActions(enabled) {
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ Singleton {
|
|||||||
|
|
||||||
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
|
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
|
||||||
|
|
||||||
readonly property real popupDistance: 4
|
// ! TODO - Synchronize with niri/hyprland gaps?
|
||||||
|
readonly property real popupDistance: 2
|
||||||
|
|
||||||
property string currentTheme: "blue"
|
property string currentTheme: "blue"
|
||||||
property string currentThemeCategory: "generic"
|
property string currentThemeCategory: "generic"
|
||||||
@@ -88,7 +89,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof SettingsData !== "undefined" && SettingsData.currentThemeName) {
|
if (typeof SettingsData !== "undefined" && SettingsData.currentThemeName) {
|
||||||
switchTheme(SettingsData.currentThemeName, false)
|
switchTheme(SettingsData.currentThemeName, false, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +269,12 @@ Singleton {
|
|||||||
function switchTheme(themeName, savePrefs = true, enableTransition = true) {
|
function switchTheme(themeName, savePrefs = true, enableTransition = true) {
|
||||||
if (enableTransition) {
|
if (enableTransition) {
|
||||||
screenTransition()
|
screenTransition()
|
||||||
|
themeTransitionTimer.themeName = themeName
|
||||||
|
themeTransitionTimer.savePrefs = savePrefs
|
||||||
|
themeTransitionTimer.restart()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (themeName === dynamic) {
|
if (themeName === dynamic) {
|
||||||
currentTheme = dynamic
|
currentTheme = dynamic
|
||||||
currentThemeCategory = dynamic
|
currentThemeCategory = dynamic
|
||||||
@@ -280,7 +286,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
currentTheme = themeName
|
currentTheme = themeName
|
||||||
// Determine category based on theme name
|
|
||||||
if (StockThemes.isCatppuccinVariant(themeName)) {
|
if (StockThemes.isCatppuccinVariant(themeName)) {
|
||||||
currentThemeCategory = "catppuccin"
|
currentThemeCategory = "catppuccin"
|
||||||
} else {
|
} else {
|
||||||
@@ -293,8 +298,15 @@ Singleton {
|
|||||||
generateSystemThemesFromCurrentTheme()
|
generateSystemThemesFromCurrentTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLightMode(light, savePrefs = true) {
|
function setLightMode(light, savePrefs = true, enableTransition = false) {
|
||||||
screenTransition()
|
if (enableTransition) {
|
||||||
|
screenTransition()
|
||||||
|
lightModeTransitionTimer.lightMode = light
|
||||||
|
lightModeTransitionTimer.savePrefs = savePrefs
|
||||||
|
lightModeTransitionTimer.restart()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
isLightMode = light
|
isLightMode = light
|
||||||
if (savePrefs && typeof SessionData !== "undefined")
|
if (savePrefs && typeof SessionData !== "undefined")
|
||||||
SessionData.setLightMode(isLightMode)
|
SessionData.setLightMode(isLightMode)
|
||||||
@@ -303,11 +315,10 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleLightMode(savePrefs = true) {
|
function toggleLightMode(savePrefs = true) {
|
||||||
setLightMode(!isLightMode, savePrefs)
|
setLightMode(!isLightMode, savePrefs, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function forceGenerateSystemThemes() {
|
function forceGenerateSystemThemes() {
|
||||||
screenTransition()
|
|
||||||
if (!matugenAvailable) {
|
if (!matugenAvailable) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -331,8 +342,10 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function switchThemeCategory(category, defaultTheme) {
|
function switchThemeCategory(category, defaultTheme) {
|
||||||
currentThemeCategory = category
|
screenTransition()
|
||||||
switchTheme(defaultTheme, true, false)
|
themeCategoryTransitionTimer.category = category
|
||||||
|
themeCategoryTransitionTimer.defaultTheme = defaultTheme
|
||||||
|
themeCategoryTransitionTimer.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCatppuccinColor(variantName) {
|
function getCatppuccinColor(variantName) {
|
||||||
@@ -356,7 +369,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadCustomTheme(themeData) {
|
function loadCustomTheme(themeData) {
|
||||||
screenTransition()
|
|
||||||
if (themeData.dark || themeData.light) {
|
if (themeData.dark || themeData.light) {
|
||||||
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"
|
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"
|
||||||
const selectedTheme = themeData[colorMode] || themeData.dark || themeData.light
|
const selectedTheme = themeData[colorMode] || themeData.dark || themeData.light
|
||||||
@@ -640,6 +652,7 @@ Singleton {
|
|||||||
qtApplier.running = true
|
qtApplier.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withAlpha(c, a) { return Qt.rgba(c.r, c.g, c.b, a); }
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: matugenCheck
|
id: matugenCheck
|
||||||
@@ -839,12 +852,12 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function light(): string {
|
function light(): string {
|
||||||
root.setLightMode(true)
|
root.setLightMode(true, true, true)
|
||||||
return "light"
|
return "light"
|
||||||
}
|
}
|
||||||
|
|
||||||
function dark(): string {
|
function dark(): string {
|
||||||
root.setLightMode(false)
|
root.setLightMode(false, true, true)
|
||||||
return "dark"
|
return "dark"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -852,4 +865,35 @@ Singleton {
|
|||||||
return root.isLightMode ? "light" : "dark"
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ Rectangle {
|
|||||||
width: parent.width - Theme.spacingS * 2
|
width: parent.width - Theme.spacingS * 2
|
||||||
height: 44
|
height: 44
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
|
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.primaryContainer, 0)
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import qs.Widgets
|
|||||||
DankPopout {
|
DankPopout {
|
||||||
id: appDrawerPopout
|
id: appDrawerPopout
|
||||||
|
|
||||||
property string triggerSection: "left"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
|
|
||||||
// Setting to Exclusive, so virtual keyboards can send input to app drawer
|
// Setting to Exclusive, so virtual keyboards can send input to app drawer
|
||||||
@@ -33,9 +32,9 @@ DankPopout {
|
|||||||
popupWidth: 520
|
popupWidth: 520
|
||||||
popupHeight: 600
|
popupHeight: 600
|
||||||
triggerX: Theme.spacingL
|
triggerX: Theme.spacingL
|
||||||
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2 + Theme.popupDistance
|
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
|
||||||
triggerWidth: 40
|
triggerWidth: 40
|
||||||
positioning: "center"
|
positioning: ""
|
||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
|
|
||||||
onShouldBeVisibleChanged: {
|
onShouldBeVisibleChanged: {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Column {
|
|||||||
property var model: null
|
property var model: null
|
||||||
property var expandedWidgetData: null
|
property var expandedWidgetData: null
|
||||||
property var bluetoothCodecSelector: null
|
property var bluetoothCodecSelector: null
|
||||||
|
property bool darkModeTransitionPending: false
|
||||||
|
|
||||||
signal expandClicked(var widgetData, int globalIndex)
|
signal expandClicked(var widgetData, int globalIndex)
|
||||||
signal removeWidget(int index)
|
signal removeWidget(int index)
|
||||||
@@ -25,6 +26,7 @@ Column {
|
|||||||
property var currentRowWidgets: []
|
property var currentRowWidgets: []
|
||||||
property real currentRowWidth: 0
|
property real currentRowWidth: 0
|
||||||
property int expandedRowIndex: -1
|
property int expandedRowIndex: -1
|
||||||
|
property var colorPickerModal: null
|
||||||
|
|
||||||
function calculateRowsAndWidgets() {
|
function calculateRowsAndWidgets() {
|
||||||
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex)
|
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex)
|
||||||
@@ -131,6 +133,8 @@ Column {
|
|||||||
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
|
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
|
||||||
} else if (id === "diskUsage") {
|
} else if (id === "diskUsage") {
|
||||||
return diskUsagePillComponent
|
return diskUsagePillComponent
|
||||||
|
} else if (id === "colorPicker") {
|
||||||
|
return colorPickerPillComponent
|
||||||
} else {
|
} else {
|
||||||
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
|
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
|
||||||
}
|
}
|
||||||
@@ -532,7 +536,13 @@ Column {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
|
iconRotation: {
|
||||||
|
if (widgetData.id !== "darkMode") return 0
|
||||||
|
if (darkModeTransitionPending) {
|
||||||
|
return SessionData.isLightMode ? 0 : 180
|
||||||
|
}
|
||||||
|
return SessionData.isLightMode ? 180 : 0
|
||||||
|
}
|
||||||
|
|
||||||
isActive: {
|
isActive: {
|
||||||
switch (widgetData.id || "") {
|
switch (widgetData.id || "") {
|
||||||
@@ -551,6 +561,14 @@ Column {
|
|||||||
|
|
||||||
enabled: !root.editMode
|
enabled: !root.editMode
|
||||||
|
|
||||||
|
onIconRotationCompleted: {
|
||||||
|
if (root.darkModeTransitionPending && widgetData.id === "darkMode") {
|
||||||
|
root.darkModeTransitionPending = false
|
||||||
|
Theme.screenTransition()
|
||||||
|
Theme.toggleLightMode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.editMode)
|
if (root.editMode)
|
||||||
return
|
return
|
||||||
@@ -563,7 +581,7 @@ enabled: !root.editMode
|
|||||||
}
|
}
|
||||||
case "darkMode":
|
case "darkMode":
|
||||||
{
|
{
|
||||||
Theme.toggleLightMode()
|
root.darkModeTransitionPending = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "doNotDisturb":
|
case "doNotDisturb":
|
||||||
@@ -604,7 +622,13 @@ enabled: !root.editMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
|
iconRotation: {
|
||||||
|
if (widgetData.id !== "darkMode") return 0
|
||||||
|
if (darkModeTransitionPending) {
|
||||||
|
return SessionData.isLightMode ? 0 : 180
|
||||||
|
}
|
||||||
|
return SessionData.isLightMode ? 180 : 0
|
||||||
|
}
|
||||||
|
|
||||||
isActive: {
|
isActive: {
|
||||||
switch (widgetData.id || "") {
|
switch (widgetData.id || "") {
|
||||||
@@ -623,6 +647,14 @@ enabled: !root.editMode
|
|||||||
|
|
||||||
enabled: !root.editMode
|
enabled: !root.editMode
|
||||||
|
|
||||||
|
onIconRotationCompleted: {
|
||||||
|
if (root.darkModeTransitionPending && widgetData.id === "darkMode") {
|
||||||
|
root.darkModeTransitionPending = false
|
||||||
|
Theme.screenTransition()
|
||||||
|
Theme.toggleLightMode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.editMode)
|
if (root.editMode)
|
||||||
return
|
return
|
||||||
@@ -635,7 +667,7 @@ enabled: !root.editMode
|
|||||||
}
|
}
|
||||||
case "darkMode":
|
case "darkMode":
|
||||||
{
|
{
|
||||||
Theme.toggleLightMode()
|
root.darkModeTransitionPending = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "doNotDisturb":
|
case "doNotDisturb":
|
||||||
@@ -671,4 +703,16 @@ 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ DankPopout {
|
|||||||
|
|
||||||
property string expandedSection: ""
|
property string expandedSection: ""
|
||||||
property bool powerOptionsExpanded: false
|
property bool powerOptionsExpanded: false
|
||||||
property string triggerSection: "right"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
property bool editMode: false
|
property bool editMode: false
|
||||||
property int expandedWidgetIndex: -1
|
property int expandedWidgetIndex: -1
|
||||||
@@ -66,9 +65,9 @@ DankPopout {
|
|||||||
popupWidth: 550
|
popupWidth: 550
|
||||||
popupHeight: Math.min((triggerScreen?.height ?? 1080) - 100, contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400)
|
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
|
triggerX: (triggerScreen?.width ?? 1920) - 600 - Theme.spacingL
|
||||||
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing + Theme.popupDistance
|
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
|
||||||
triggerWidth: 80
|
triggerWidth: 80
|
||||||
positioning: "center"
|
positioning: ""
|
||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
visible: shouldBeVisible
|
visible: shouldBeVisible
|
||||||
@@ -102,7 +101,7 @@ DankPopout {
|
|||||||
property alias bluetoothCodecSelector: bluetoothCodecSelector
|
property alias bluetoothCodecSelector: bluetoothCodecSelector
|
||||||
|
|
||||||
color: {
|
color: {
|
||||||
const transparency = Theme.popupTransparency || 0.92
|
const transparency = Theme.popupTransparency
|
||||||
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
|
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
|
||||||
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
|
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
|
||||||
}
|
}
|
||||||
@@ -154,6 +153,7 @@ DankPopout {
|
|||||||
expandedWidgetData: root.expandedWidgetData
|
expandedWidgetData: root.expandedWidgetData
|
||||||
model: widgetModel
|
model: widgetModel
|
||||||
bluetoothCodecSelector: bluetoothCodecSelector
|
bluetoothCodecSelector: bluetoothCodecSelector
|
||||||
|
colorPickerModal: root.colorPickerModal
|
||||||
onExpandClicked: (widgetData, globalIndex) => {
|
onExpandClicked: (widgetData, globalIndex) => {
|
||||||
root.expandedWidgetIndex = globalIndex
|
root.expandedWidgetIndex = globalIndex
|
||||||
root.expandedWidgetData = widgetData
|
root.expandedWidgetData = widgetData
|
||||||
@@ -223,4 +223,6 @@ DankPopout {
|
|||||||
id: batteryDetailComponent
|
id: batteryDetailComponent
|
||||||
BatteryDetail {}
|
BatteryDetail {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property var colorPickerModal: null
|
||||||
}
|
}
|
||||||
@@ -116,6 +116,14 @@ QtObject {
|
|||||||
"enabled": DgopService.dgopAvailable,
|
"enabled": DgopService.dgopAvailable,
|
||||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined,
|
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined,
|
||||||
"allowMultiple": true
|
"allowMultiple": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "colorPicker",
|
||||||
|
"text": "Color Picker",
|
||||||
|
"description": "Choose colors from palette",
|
||||||
|
"icon": "palette",
|
||||||
|
"type": "action",
|
||||||
|
"enabled": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ Row {
|
|||||||
height: Theme.iconSize + Theme.spacingS * 2
|
height: Theme.iconSize + Theme.spacingS * 2
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation { duration: Theme.shortDuration }
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: iconArea
|
id: iconArea
|
||||||
|
|||||||
@@ -18,17 +18,13 @@ Row {
|
|||||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||||
color: iconArea.containsMouse
|
color: iconArea.containsMouse
|
||||||
? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||||
: "transparent"
|
: Theme.withAlpha(Theme.primary, 0)
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation { duration: Theme.shortDuration }
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: iconArea
|
id: iconArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: DisplayService.devices.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
onClicked: function(event) {
|
onClicked: function(event) {
|
||||||
if (DisplayService.devices.length > 1) {
|
if (DisplayService.devices.length > 1) {
|
||||||
@@ -41,6 +37,22 @@ 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 {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
name: {
|
name: {
|
||||||
@@ -141,4 +153,10 @@ Row {
|
|||||||
onObjectRemoved: (index, object) => deviceMenu.removeItem(object)
|
onObjectRemoved: (index, object) => deviceMenu.removeItem(object)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: tooltipLoader
|
||||||
|
active: false
|
||||||
|
sourceComponent: DankTooltip {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
33
Modules/ControlCenter/Widgets/ColorPickerPill.qml
Normal file
33
Modules/ControlCenter/Widgets/ColorPickerPill.qml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ Rectangle {
|
|||||||
readonly property color _labelSecondary: Theme.surfaceVariantText
|
readonly property color _labelSecondary: Theme.surfaceVariantText
|
||||||
readonly property color _tileBgActive: Theme.primary
|
readonly property color _tileBgActive: Theme.primary
|
||||||
readonly property color _tileBgInactive: {
|
readonly property color _tileBgInactive: {
|
||||||
const transparency = Theme.popupTransparency || 0.92
|
const transparency = Theme.popupTransparency
|
||||||
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
|
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
|
||||||
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
|
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ Row {
|
|||||||
height: Theme.iconSize + Theme.spacingS * 2
|
height: Theme.iconSize + Theme.spacingS * 2
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation { duration: Theme.shortDuration }
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: iconArea
|
id: iconArea
|
||||||
|
|||||||
@@ -91,13 +91,6 @@ Rectangle {
|
|||||||
onClicked: root.clicked()
|
onClicked: root.clicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on radius {
|
Behavior on radius {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Rectangle {
|
|||||||
property real iconRotation: 0
|
property real iconRotation: 0
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
signal iconRotationCompleted()
|
||||||
|
|
||||||
width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48
|
width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48
|
||||||
height: 48
|
height: 48
|
||||||
@@ -58,6 +59,7 @@ Rectangle {
|
|||||||
size: Theme.iconSize
|
size: Theme.iconSize
|
||||||
color: isActive ? _tileIconActive : _tileIconInactive
|
color: isActive ? _tileIconActive : _tileIconInactive
|
||||||
rotation: iconRotation
|
rotation: iconRotation
|
||||||
|
onRotationCompleted: root.iconRotationCompleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -69,13 +71,6 @@ Rectangle {
|
|||||||
onClicked: root.clicked()
|
onClicked: root.clicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on radius {
|
Behavior on radius {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Rectangle {
|
|||||||
property real iconRotation: 0
|
property real iconRotation: 0
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
signal iconRotationCompleted()
|
||||||
|
|
||||||
width: parent ? parent.width : 200
|
width: parent ? parent.width : 200
|
||||||
height: 60
|
height: 60
|
||||||
@@ -46,7 +47,7 @@ Rectangle {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: mouseArea.containsMouse ? hoverTint(_containerBg) : "transparent"
|
color: mouseArea.containsMouse ? hoverTint(_containerBg) : Theme.withAlpha(_containerBg, 0)
|
||||||
opacity: mouseArea.containsMouse ? 0.08 : 0.0
|
opacity: mouseArea.containsMouse ? 0.08 : 0.0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
@@ -66,6 +67,7 @@ Rectangle {
|
|||||||
color: isActive ? Theme.primaryContainer : Theme.primary
|
color: isActive ? Theme.primaryContainer : Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
rotation: root.iconRotation
|
rotation: root.iconRotation
|
||||||
|
onRotationCompleted: root.iconRotationCompleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -110,13 +112,6 @@ Rectangle {
|
|||||||
onClicked: root.clicked()
|
onClicked: root.clicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on radius {
|
Behavior on radius {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
|
|||||||
179
Modules/DankBar/AutoHideManager.qml
Normal file
179
Modules/DankBar/AutoHideManager.qml
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
57
Modules/DankBar/AxisContext.qml
Normal file
57
Modules/DankBar/AxisContext.qml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
214
Modules/DankBar/BarCanvas.qml
Normal file
214
Modules/DankBar/BarCanvas.qml
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var barWindow
|
||||||
|
required property var axis
|
||||||
|
|
||||||
|
readonly property real correctWidth: barWindow.isVertical ? barWindow.implicitWidth : parent.width
|
||||||
|
readonly property real correctHeight: barWindow.isVertical ? parent.height : barWindow.implicitHeight
|
||||||
|
|
||||||
|
width: correctWidth
|
||||||
|
height: correctHeight
|
||||||
|
|
||||||
|
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: barWindow.isVertical ? barWindow.implicitWidth : parent.width
|
||||||
|
readonly property real correctHeight: barWindow.isVertical ? parent.height : barWindow.implicitHeight
|
||||||
|
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: barWindow.isVertical ? barWindow.implicitWidth : parent.width
|
||||||
|
readonly property real correctHeight: barWindow.isVertical ? parent.height : barWindow.implicitHeight
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
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.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
|
||||||
|
|
||||||
signal toggleBatteryPopup()
|
|
||||||
|
|
||||||
width: batteryContent.implicitWidth + horizontalPadding * 2
|
|
||||||
height: widgetHeight
|
|
||||||
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
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: batteryContent
|
|
||||||
|
|
||||||
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 screenX = currentScreen.x || 0;
|
|
||||||
const relativeX = globalPos.x - screenX;
|
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), 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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
382
Modules/DankBar/CenterSection.qml
Normal file
382
Modules/DankBar/CenterSection.qml
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
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.dankBarNoBackground ? 2 : Theme.spacingS
|
|
||||||
|
|
||||||
signal clockClicked
|
|
||||||
|
|
||||||
width: clockRow.implicitWidth + horizontalPadding * 2
|
|
||||||
height: widgetHeight
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen)
|
|
||||||
}
|
|
||||||
root.clockClicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
71
Modules/DankBar/LeftSection.qml
Normal file
71
Modules/DankBar/LeftSection.qml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
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.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
|
||||||
|
|
||||||
signal clicked()
|
|
||||||
|
|
||||||
width: notificationIcon.width + horizontalPadding * 2
|
|
||||||
height: widgetHeight
|
|
||||||
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 {
|
|
||||||
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.dankBarNoBackground ? 0 : 6
|
|
||||||
anchors.topMargin: SettingsData.dankBarNoBackground ? 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, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
|
||||||
root.clicked();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,6 @@ import qs.Widgets
|
|||||||
DankPopout {
|
DankPopout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string triggerSection: "right"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
|
|
||||||
function setTriggerPosition(x, y, width, section, screen) {
|
function setTriggerPosition(x, y, width, section, screen) {
|
||||||
@@ -45,9 +44,9 @@ DankPopout {
|
|||||||
popupWidth: 400
|
popupWidth: 400
|
||||||
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
|
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
|
||||||
triggerX: Screen.width - 380 - Theme.spacingL
|
triggerX: Screen.width - 380 - Theme.spacingL
|
||||||
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing + Theme.popupDistance
|
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
|
||||||
triggerWidth: 70
|
triggerWidth: 70
|
||||||
positioning: "center"
|
positioning: ""
|
||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
visible: shouldBeVisible
|
visible: shouldBeVisible
|
||||||
@@ -13,7 +13,6 @@ import qs.Widgets
|
|||||||
DankPopout {
|
DankPopout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string triggerSection: "right"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
|
|
||||||
function setTriggerPosition(x, y, width, section, screen) {
|
function setTriggerPosition(x, y, width, section, screen) {
|
||||||
@@ -27,9 +26,9 @@ DankPopout {
|
|||||||
popupWidth: 360
|
popupWidth: 360
|
||||||
popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 260)
|
popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 260)
|
||||||
triggerX: Screen.width - 380 - Theme.spacingL
|
triggerX: Screen.width - 380 - Theme.spacingL
|
||||||
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing + Theme.popupDistance
|
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
|
||||||
triggerWidth: 70
|
triggerWidth: 70
|
||||||
positioning: "center"
|
positioning: ""
|
||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
visible: shouldBeVisible
|
visible: shouldBeVisible
|
||||||
73
Modules/DankBar/RightSection.qml
Normal file
73
Modules/DankBar/RightSection.qml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
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.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
|
||||||
|
|
||||||
signal toggleVpnPopup()
|
|
||||||
|
|
||||||
width: Theme.iconSize + horizontalPadding * 2
|
|
||||||
height: widgetHeight
|
|
||||||
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
|
|
||||||
|
|
||||||
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, SettingsData.getPopupYPosition(barHeight), 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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
88
Modules/DankBar/WidgetHost.qml
Normal file
88
Modules/DankBar/WidgetHost.qml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
126
Modules/DankBar/Widgets/Battery.qml
Normal file
126
Modules/DankBar/Widgets/Battery.qml
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
Modules/DankBar/Widgets/ClipboardButton.qml
Normal file
57
Modules/DankBar/Widgets/ClipboardButton.qml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
267
Modules/DankBar/Widgets/Clock.qml
Normal file
267
Modules/DankBar/Widgets/Clock.qml
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,18 +5,20 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property bool isActive: false
|
property bool isActive: false
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
width: colorPickerIcon.width + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (colorPickerIcon.width + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (colorPickerIcon.height + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -43,12 +45,10 @@ Rectangle {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
console.log("Color picker button clicked!")
|
|
||||||
root.colorPickerRequested();
|
root.colorPickerRequested();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal to notify TopBar to open color picker
|
|
||||||
signal colorPickerRequested()
|
signal colorPickerRequested()
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,8 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property bool isActive: false
|
property bool isActive: false
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
@@ -14,14 +16,14 @@ Rectangle {
|
|||||||
property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon
|
property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon
|
||||||
property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon
|
property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon
|
||||||
property bool showAudioIcon: SettingsData.controlCenterShowAudioIcon
|
property bool showAudioIcon: SettingsData.controlCenterShowAudioIcon
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
width: controlIndicators.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (controlIndicators.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (controlColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -32,9 +34,106 @@ Rectangle {
|
|||||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
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 {
|
Row {
|
||||||
id: controlIndicators
|
id: controlIndicators
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
@@ -156,11 +255,10 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
root.clicked();
|
root.clicked();
|
||||||
}
|
}
|
||||||
@@ -7,18 +7,20 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property bool showPercentage: true
|
property bool showPercentage: true
|
||||||
property bool showIcon: true
|
property bool showIcon: true
|
||||||
property var toggleProcessList
|
property var toggleProcessList
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
width: cpuContent.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (cpuContent.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (cpuColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -43,11 +45,10 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
DgopService.setSortBy("cpu");
|
DgopService.setSortBy("cpu");
|
||||||
if (root.toggleProcessList) {
|
if (root.toggleProcessList) {
|
||||||
@@ -57,9 +58,47 @@ 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 {
|
Row {
|
||||||
id: cpuContent
|
id: cpuContent
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
@@ -7,18 +7,20 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property bool showPercentage: true
|
property bool showPercentage: true
|
||||||
property bool showIcon: true
|
property bool showIcon: true
|
||||||
property var toggleProcessList
|
property var toggleProcessList
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
width: cpuTempContent.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (cpuTempContent.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (cpuTempColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -43,11 +45,10 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
DgopService.setSortBy("cpu");
|
DgopService.setSortBy("cpu");
|
||||||
if (root.toggleProcessList) {
|
if (root.toggleProcessList) {
|
||||||
@@ -57,9 +58,47 @@ 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 {
|
Row {
|
||||||
id: cpuTempContent
|
id: cpuTempContent
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
@@ -7,10 +7,13 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property var widgetData: null
|
property var widgetData: null
|
||||||
property real widgetHeight: 30
|
property var parentScreen: null
|
||||||
|
property real widgetThickness: 30
|
||||||
property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/"
|
property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/"
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
property var selectedMount: {
|
property var selectedMount: {
|
||||||
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
|
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
|
||||||
@@ -46,8 +49,8 @@ Rectangle {
|
|||||||
return parseFloat(percentStr) || 0
|
return parseFloat(percentStr) || 0
|
||||||
}
|
}
|
||||||
|
|
||||||
width: diskContent.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (diskContent.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (diskColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -100,10 +103,77 @@ Rectangle {
|
|||||||
target: SettingsData
|
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 {
|
Row {
|
||||||
id: diskContent
|
id: diskContent
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Widgets
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -9,14 +10,45 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
|
property var parentScreen
|
||||||
property bool compactMode: SettingsData.focusedWindowCompactMode
|
property bool compactMode: SettingsData.focusedWindowCompactMode
|
||||||
property int availableWidth: 400
|
property int availableWidth: 400
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||||
readonly property int baseWidth: contentRow.implicitWidth + horizontalPadding * 2
|
readonly property int baseWidth: contentRow.implicitWidth + horizontalPadding * 2
|
||||||
readonly property int maxNormalWidth: 456
|
readonly property int maxNormalWidth: 456
|
||||||
readonly property int maxCompactWidth: 288
|
readonly property int maxCompactWidth: 288
|
||||||
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
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: {
|
readonly property bool hasWindowsOnCurrentWorkspace: {
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
let currentWorkspaceId = null
|
let currentWorkspaceId = null
|
||||||
@@ -54,8 +86,8 @@ Rectangle {
|
|||||||
return activeWindow && activeWindow.title
|
return activeWindow && activeWindow.title
|
||||||
}
|
}
|
||||||
|
|
||||||
width: !hasWindowsOnCurrentWorkspace ? 0 : (compactMode ? Math.min(baseWidth, maxCompactWidth) : Math.min(baseWidth, maxNormalWidth))
|
width: !hasWindowsOnCurrentWorkspace ? 0 : (isVertical ? widgetThickness : (compactMode ? Math.min(baseWidth, maxCompactWidth) : Math.min(baseWidth, maxNormalWidth)))
|
||||||
height: widgetHeight
|
height: !hasWindowsOnCurrentWorkspace ? 0 : (isVertical ? widgetThickness : widgetThickness)
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (!activeWindow || !activeWindow.title) {
|
if (!activeWindow || !activeWindow.title) {
|
||||||
@@ -72,11 +104,61 @@ Rectangle {
|
|||||||
clip: true
|
clip: true
|
||||||
visible: hasWindowsOnCurrentWorkspace
|
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 {
|
Row {
|
||||||
id: contentRow
|
id: contentRow
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
visible: !root.isVertical
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: appText
|
id: appText
|
||||||
@@ -117,7 +199,6 @@ Rectangle {
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove app name from end of title if it exists there
|
|
||||||
if (title.endsWith(" - " + appName)) {
|
if (title.endsWith(" - " + appName)) {
|
||||||
return title.substring(0, title.length - (" - " + appName).length);
|
return title.substring(0, title.length - (" - " + appName).length);
|
||||||
}
|
}
|
||||||
@@ -144,7 +225,39 @@ Rectangle {
|
|||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
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 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -7,6 +7,8 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property bool showPercentage: true
|
property bool showPercentage: true
|
||||||
property bool showIcon: true
|
property bool showIcon: true
|
||||||
property var toggleProcessList
|
property var toggleProcessList
|
||||||
@@ -14,10 +16,10 @@ Rectangle {
|
|||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property var widgetData: null
|
property var widgetData: null
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
|
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
property real displayTemp: {
|
property real displayTemp: {
|
||||||
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -65,8 +67,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width: gpuTempContent.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (gpuTempContent.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (gpuTempColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -78,20 +80,14 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
DgopService.addRef(["gpu"]);
|
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) {
|
if (widgetData && widgetData.pciId) {
|
||||||
console.log("Adding GPU PCI ID to service:", widgetData.pciId);
|
|
||||||
DgopService.addGpuPciId(widgetData.pciId);
|
DgopService.addGpuPciId(widgetData.pciId);
|
||||||
} else {
|
} 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;
|
autoSaveTimer.running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
DgopService.removeRef(["gpu"]);
|
DgopService.removeRef(["gpu"]);
|
||||||
// Remove this widget's PCI ID from the service
|
|
||||||
if (widgetData && widgetData.pciId) {
|
if (widgetData && widgetData.pciId) {
|
||||||
DgopService.removeGpuPciId(widgetData.pciId);
|
DgopService.removeGpuPciId(widgetData.pciId);
|
||||||
}
|
}
|
||||||
@@ -117,11 +113,10 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
DgopService.setSortBy("cpu");
|
DgopService.setSortBy("cpu");
|
||||||
if (root.toggleProcessList) {
|
if (root.toggleProcessList) {
|
||||||
@@ -131,9 +126,47 @@ 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 {
|
Row {
|
||||||
id: gpuTempContent
|
id: gpuTempContent
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
@@ -8,14 +8,16 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
width: idleIcon.width + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (idleIcon.width + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (idleIcon.height + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -10,12 +10,15 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
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))
|
||||||
property string currentLayout: ""
|
property string currentLayout: ""
|
||||||
property string hyprlandKeyboard: ""
|
property string hyprlandKeyboard: ""
|
||||||
|
|
||||||
width: contentRow.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (contentRow.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (contentColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -47,11 +50,42 @@ 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 {
|
Row {
|
||||||
id: contentRow
|
id: contentRow
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
visible: !root.isVertical
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: currentLayout
|
text: currentLayout
|
||||||
@@ -7,17 +7,19 @@ Item {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool isActive: false
|
property bool isActive: false
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property string section: "left"
|
property string section: "left"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
width: Theme.iconSize + horizontalPadding * 2
|
width: widgetThickness
|
||||||
height: widgetHeight
|
height: widgetThickness
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: launcherArea
|
id: launcherArea
|
||||||
@@ -27,14 +29,13 @@ Item {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
onPressed: {
|
onPressed: {
|
||||||
|
root.clicked();
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0);
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen;
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen);
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
root.clicked();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +56,8 @@ Item {
|
|||||||
SystemLogo {
|
SystemLogo {
|
||||||
visible: SettingsData.useOSLogo
|
visible: SettingsData.useOSLogo
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: Theme.iconSize - 3
|
width: widgetThickness - 8
|
||||||
height: Theme.iconSize - 3
|
height: widgetThickness - 8
|
||||||
colorOverride: SettingsData.osLogoColorOverride
|
colorOverride: SettingsData.osLogoColorOverride
|
||||||
brightnessOverride: SettingsData.osLogoBrightness
|
brightnessOverride: SettingsData.osLogoBrightness
|
||||||
contrastOverride: SettingsData.osLogoContrast
|
contrastOverride: SettingsData.osLogoContrast
|
||||||
@@ -64,9 +65,11 @@ Item {
|
|||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
visible: !SettingsData.useOSLogo
|
visible: !SettingsData.useOSLogo
|
||||||
anchors.centerIn: parent
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.verticalCenterOffset: 1
|
||||||
name: "apps"
|
name: "apps"
|
||||||
size: Theme.iconSize - 6
|
size: widgetThickness - 8
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,8 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
readonly property MprisPlayer activePlayer: MprisController.activePlayer
|
readonly property MprisPlayer activePlayer: MprisController.activePlayer
|
||||||
readonly property bool playerAvailable: activePlayer !== null
|
readonly property bool playerAvailable: activePlayer !== null
|
||||||
property bool compactMode: false
|
property bool compactMode: false
|
||||||
@@ -21,24 +23,33 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
readonly property int currentContentWidth: {
|
readonly property int currentContentWidth: {
|
||||||
// Calculate actual content width:
|
if (isVertical) {
|
||||||
// AudioViz (20) + spacing + [text + spacing] + controls (prev:20 + spacing + play:24 + spacing + next:20) + padding
|
return widgetThickness;
|
||||||
|
}
|
||||||
const controlsWidth = 20 + Theme.spacingXS + 24 + Theme.spacingXS + 20;
|
const controlsWidth = 20 + Theme.spacingXS + 24 + Theme.spacingXS + 20;
|
||||||
// ~72px total
|
|
||||||
const audioVizWidth = 20;
|
const audioVizWidth = 20;
|
||||||
const contentWidth = audioVizWidth + Theme.spacingXS + controlsWidth;
|
const contentWidth = audioVizWidth + Theme.spacingXS + controlsWidth;
|
||||||
return contentWidth + (textWidth > 0 ? textWidth + Theme.spacingXS : 0) + horizontalPadding * 2;
|
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 string section: "center"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
height: widgetHeight
|
width: currentContentWidth
|
||||||
|
height: currentContentHeight
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -57,6 +68,7 @@ Rectangle {
|
|||||||
target: root
|
target: root
|
||||||
opacity: 1
|
opacity: 1
|
||||||
width: currentContentWidth
|
width: currentContentWidth
|
||||||
|
height: currentContentHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -67,7 +79,8 @@ Rectangle {
|
|||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: root
|
target: root
|
||||||
opacity: 0
|
opacity: 0
|
||||||
width: 0
|
width: isVertical ? widgetThickness : 0
|
||||||
|
height: isVertical ? 0 : widgetThickness
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -83,7 +96,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
properties: "opacity,width"
|
properties: isVertical ? "opacity,height" : "opacity,width"
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
easing.type: Theme.standardEasing
|
easing.type: Theme.standardEasing
|
||||||
}
|
}
|
||||||
@@ -96,7 +109,7 @@ Rectangle {
|
|||||||
to: "shown"
|
to: "shown"
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
properties: "opacity,width"
|
properties: isVertical ? "opacity,height" : "opacity,width"
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
easing.type: Theme.standardEasing
|
easing.type: Theme.standardEasing
|
||||||
}
|
}
|
||||||
@@ -104,9 +117,107 @@ 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 {
|
Row {
|
||||||
id: mediaRow
|
id: mediaRow
|
||||||
|
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
@@ -208,13 +319,12 @@ Rectangle {
|
|||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (root.popupTarget && root.popupTarget.setTriggerPosition) {
|
if (root.popupTarget && root.popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = root.parentScreen || Screen;
|
const currentScreen = root.parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.width)
|
||||||
const relativeX = globalPos.x - screenX;
|
root.popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen)
|
||||||
root.popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), root.width, root.section, currentScreen);
|
|
||||||
}
|
}
|
||||||
root.clicked();
|
root.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +440,13 @@ Rectangle {
|
|||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
easing.type: Theme.standardEasing
|
easing.type: Theme.standardEasing
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,10 +8,13 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property int availableWidth: 400
|
property int availableWidth: 400
|
||||||
readonly property int baseWidth: contentRow.implicitWidth + Theme.spacingS * 2
|
readonly property int baseWidth: contentRow.implicitWidth + Theme.spacingS * 2
|
||||||
readonly property int maxNormalWidth: 456
|
readonly property int maxNormalWidth: 456
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
property real widgetThickness: 30
|
||||||
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
function formatNetworkSpeed(bytesPerSec) {
|
function formatNetworkSpeed(bytesPerSec) {
|
||||||
if (bytesPerSec < 1024) {
|
if (bytesPerSec < 1024) {
|
||||||
@@ -25,8 +28,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width: contentRow.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (contentRow.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (contentColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -51,11 +54,53 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
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 {
|
Row {
|
||||||
id: contentRow
|
id: contentRow
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
visible: !root.isVertical
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: "network_check"
|
name: "network_check"
|
||||||
@@ -7,11 +7,13 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
@@ -25,7 +27,6 @@ Rectangle {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try focused screen first
|
|
||||||
const targetScreen = focusedScreenName
|
const targetScreen = focusedScreenName
|
||||||
if (targetScreen) {
|
if (targetScreen) {
|
||||||
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
|
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
|
||||||
@@ -36,15 +37,14 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to first available
|
|
||||||
return notepadSlideoutVariants.instances.length > 0 ? notepadSlideoutVariants.instances[0] : null
|
return notepadSlideoutVariants.instances.length > 0 ? notepadSlideoutVariants.instances[0] : null
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var notepadInstance: resolveNotepadInstance()
|
readonly property var notepadInstance: resolveNotepadInstance()
|
||||||
readonly property bool isActive: notepadInstance?.isVisible ?? false
|
readonly property bool isActive: notepadInstance?.isVisible ?? false
|
||||||
|
|
||||||
width: notepadIcon.width + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (notepadIcon.width + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (notepadIcon.height + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
76
Modules/DankBar/Widgets/NotificationCenterButton.qml
Normal file
76
Modules/DankBar/Widgets/NotificationCenterButton.qml
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,17 +7,20 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||||
readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive
|
readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive
|
||||||
readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive + PrivacyService.screensharingActive
|
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 contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
|
||||||
|
readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
|
||||||
|
|
||||||
width: hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0
|
width: isVertical ? widgetThickness : (hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0)
|
||||||
height: hasActivePrivacy ? widgetHeight : 0
|
height: isVertical ? (hasActivePrivacy ? (contentHeight + horizontalPadding * 2) : 0) : (hasActivePrivacy ? widgetThickness : 0)
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
visible: hasActivePrivacy
|
visible: hasActivePrivacy
|
||||||
opacity: hasActivePrivacy ? 1 : 0
|
opacity: hasActivePrivacy ? 1 : 0
|
||||||
@@ -43,10 +46,76 @@ 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 {
|
Row {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
visible: hasActivePrivacy
|
visible: !root.isVertical && hasActivePrivacy
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: 18
|
width: 18
|
||||||
@@ -158,7 +227,17 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Behavior on width {
|
Behavior on width {
|
||||||
enabled: hasActivePrivacy && visible
|
enabled: hasActivePrivacy && visible && !isVertical
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
enabled: hasActivePrivacy && visible && isVertical
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: Theme.mediumDuration
|
duration: Theme.mediumDuration
|
||||||
@@ -7,18 +7,20 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property bool showPercentage: true
|
property bool showPercentage: true
|
||||||
property bool showIcon: true
|
property bool showIcon: true
|
||||||
property var toggleProcessList
|
property var toggleProcessList
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||||
|
|
||||||
width: ramContent.implicitWidth + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (ramContent.implicitWidth + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (ramColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -43,11 +45,10 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
DgopService.setSortBy("memory");
|
DgopService.setSortBy("memory");
|
||||||
if (root.toggleProcessList) {
|
if (root.toggleProcessList) {
|
||||||
@@ -57,9 +58,47 @@ 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 {
|
Row {
|
||||||
id: ramContent
|
id: ramContent
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
@@ -10,13 +10,14 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property string section: "left"
|
property string section: "left"
|
||||||
property var parentScreen
|
property var parentScreen
|
||||||
property var hoveredItem: null
|
property var hoveredItem: null
|
||||||
property var topBar: null
|
property var topBar: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||||
// The visual root for this window
|
|
||||||
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
|
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
|
||||||
readonly property var sortedToplevels: {
|
readonly property var sortedToplevels: {
|
||||||
if (SettingsData.runningAppsCurrentWorkspace) {
|
if (SettingsData.runningAppsCurrentWorkspace) {
|
||||||
@@ -25,7 +26,7 @@ Rectangle {
|
|||||||
return CompositorService.sortedToplevels;
|
return CompositorService.sortedToplevels;
|
||||||
}
|
}
|
||||||
readonly property int windowCount: sortedToplevels.length
|
readonly property int windowCount: sortedToplevels.length
|
||||||
readonly property int calculatedWidth: {
|
readonly property int calculatedSize: {
|
||||||
if (windowCount === 0) {
|
if (windowCount === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -37,8 +38,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width: calculatedWidth
|
width: isVertical ? widgetThickness : calculatedSize
|
||||||
height: widgetHeight
|
height: isVertical ? calculatedSize : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
visible: windowCount > 0
|
visible: windowCount > 0
|
||||||
clip: false
|
clip: false
|
||||||
@@ -143,18 +144,22 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Loader {
|
||||||
id: windowRow
|
id: layoutLoader
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
sourceComponent: root.isVertical ? columnLayout : rowLayout
|
||||||
|
}
|
||||||
|
|
||||||
Repeater {
|
Component {
|
||||||
id: windowRepeater
|
id: rowLayout
|
||||||
|
Row {
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
model: sortedToplevels
|
Repeater {
|
||||||
|
id: windowRepeater
|
||||||
|
model: sortedToplevels
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
id: delegateItem
|
id: delegateItem
|
||||||
|
|
||||||
property bool isFocused: modelData.activated
|
property bool isFocused: modelData.activated
|
||||||
@@ -288,7 +293,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
} else if (mouse.button === Qt.RightButton) {
|
} else if (mouse.button === Qt.RightButton) {
|
||||||
if (tooltipLoader.item) {
|
if (tooltipLoader.item) {
|
||||||
tooltipLoader.item.hideTooltip();
|
tooltipLoader.item.hide();
|
||||||
}
|
}
|
||||||
tooltipLoader.active = false;
|
tooltipLoader.active = false;
|
||||||
|
|
||||||
@@ -299,29 +304,35 @@ Rectangle {
|
|||||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||||
const relativeX = globalPos.x - screenX;
|
const relativeX = globalPos.x - screenX;
|
||||||
const yPos = Theme.barHeight + SettingsData.dankBarSpacing - 7;
|
const yPos = root.isVertical ? delegateItem.height / 2 : (Theme.barHeight + SettingsData.dankBarSpacing - 7);
|
||||||
windowContextMenuLoader.item.showAt(relativeX, yPos);
|
windowContextMenuLoader.item.showAt(relativeX, yPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEntered: {
|
onEntered: {
|
||||||
root.hoveredItem = delegateItem;
|
root.hoveredItem = delegateItem;
|
||||||
const globalPos = delegateItem.mapToGlobal(
|
|
||||||
delegateItem.width / 2, delegateItem.height);
|
|
||||||
tooltipLoader.active = true;
|
tooltipLoader.active = true;
|
||||||
if (tooltipLoader.item) {
|
if (tooltipLoader.item) {
|
||||||
const tooltipY = Theme.barHeight
|
if (root.isVertical) {
|
||||||
+ SettingsData.dankBarSpacing + Theme.spacingXS;
|
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||||
tooltipLoader.item.showTooltip(
|
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||||
delegateItem.tooltipText, globalPos.x,
|
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||||
tooltipY, root.parentScreen);
|
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: {
|
onExited: {
|
||||||
if (root.hoveredItem === delegateItem) {
|
if (root.hoveredItem === delegateItem) {
|
||||||
root.hoveredItem = null;
|
root.hoveredItem = null;
|
||||||
if (tooltipLoader.item) {
|
if (tooltipLoader.item) {
|
||||||
tooltipLoader.item.hideTooltip();
|
tooltipLoader.item.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
tooltipLoader.active = false;
|
tooltipLoader.active = false;
|
||||||
@@ -330,6 +341,198 @@ 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 {
|
Loader {
|
||||||
@@ -337,7 +540,7 @@ Rectangle {
|
|||||||
|
|
||||||
active: false
|
active: false
|
||||||
|
|
||||||
sourceComponent: RunningAppsTooltip {}
|
sourceComponent: DankTooltip {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -10,15 +10,17 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property var parentWindow: null
|
property var parentWindow: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
property bool isAtBottom: false
|
property bool isAtBottom: false
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||||
readonly property int calculatedWidth: SystemTray.items.values.length > 0 ? SystemTray.items.values.length * 24 + horizontalPadding * 2 : 0
|
readonly property int calculatedSize: SystemTray.items.values.length > 0 ? SystemTray.items.values.length * 24 + horizontalPadding * 2 : 0
|
||||||
|
|
||||||
width: calculatedWidth
|
width: isVertical ? widgetThickness : calculatedSize
|
||||||
height: widgetHeight
|
height: isVertical ? calculatedSize : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SystemTray.items.values.length === 0) {
|
if (SystemTray.items.values.length === 0) {
|
||||||
@@ -34,16 +36,21 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
visible: SystemTray.items.values.length > 0
|
visible: SystemTray.items.values.length > 0
|
||||||
|
|
||||||
Row {
|
Loader {
|
||||||
id: systemTrayRow
|
id: layoutLoader
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 0
|
sourceComponent: root.isVertical ? columnComp : rowComp
|
||||||
|
}
|
||||||
|
|
||||||
Repeater {
|
Component {
|
||||||
model: SystemTray.items.values
|
id: rowComp
|
||||||
|
Row {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
delegate: Item {
|
Repeater {
|
||||||
|
model: SystemTray.items.values
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
property var trayItem: modelData
|
property var trayItem: modelData
|
||||||
property string iconSource: {
|
property string iconSource: {
|
||||||
let icon = trayItem && trayItem.icon;
|
let icon = trayItem && trayItem.icon;
|
||||||
@@ -108,7 +115,7 @@ Rectangle {
|
|||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
if (trayItem.hasMenu) {
|
if (trayItem.hasMenu) {
|
||||||
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom);
|
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +123,89 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
Component {
|
||||||
@@ -129,6 +218,8 @@ Rectangle {
|
|||||||
property var anchorItem: null
|
property var anchorItem: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property bool isAtBottom: false
|
property bool isAtBottom: false
|
||||||
|
property bool isVertical: false
|
||||||
|
property var axis: null
|
||||||
property bool showMenu: false
|
property bool showMenu: false
|
||||||
property var menuHandle: null
|
property var menuHandle: null
|
||||||
|
|
||||||
@@ -137,11 +228,13 @@ Rectangle {
|
|||||||
return entryStack.count ? entryStack.get(entryStack.count - 1).handle : null
|
return entryStack.count ? entryStack.get(entryStack.count - 1).handle : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function showForTrayItem(item, anchor, screen, atBottom) {
|
function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) {
|
||||||
trayItem = item
|
trayItem = item
|
||||||
anchorItem = anchor
|
anchorItem = anchor
|
||||||
parentScreen = screen
|
parentScreen = screen
|
||||||
isAtBottom = atBottom
|
isAtBottom = atBottom
|
||||||
|
isVertical = vertical
|
||||||
|
axis = axisObj
|
||||||
menuHandle = item?.menu
|
menuHandle = item?.menu
|
||||||
|
|
||||||
if (parentScreen) {
|
if (parentScreen) {
|
||||||
@@ -185,7 +278,7 @@ Rectangle {
|
|||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: menuWindow
|
id: menuWindow
|
||||||
visible: menuRoot.showMenu && menuRoot.trayItem?.hasMenu
|
visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false)
|
||||||
WlrLayershell.layer: WlrLayershell.Overlay
|
WlrLayershell.layer: WlrLayershell.Overlay
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
@@ -218,18 +311,29 @@ Rectangle {
|
|||||||
const relativeX = globalPos.x - screenX
|
const relativeX = globalPos.x - screenX
|
||||||
const relativeY = globalPos.y - screenY
|
const relativeY = globalPos.y - screenY
|
||||||
|
|
||||||
const widgetHeight = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||||
const effectiveBarHeight = Math.max(widgetHeight + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
const effectiveBarThickness = Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||||
|
|
||||||
let targetY
|
if (menuRoot.isVertical) {
|
||||||
if (menuRoot.isAtBottom) {
|
const edge = menuRoot.axis?.edge
|
||||||
const popupY = effectiveBarHeight + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2 + Theme.popupDistance
|
let targetX
|
||||||
targetY = screen.height - popupY
|
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 {
|
} else {
|
||||||
targetY = effectiveBarHeight + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2 + Theme.popupDistance
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
anchorPos = Qt.point(relativeX + menuRoot.anchorItem.width / 2, targetY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -239,19 +343,37 @@ Rectangle {
|
|||||||
height: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2)
|
height: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2)
|
||||||
|
|
||||||
x: {
|
x: {
|
||||||
const left = 10
|
if (menuRoot.isVertical) {
|
||||||
const right = menuWindow.width - width - 10
|
const edge = menuRoot.axis?.edge
|
||||||
const want = menuWindow.anchorPos.x - width / 2
|
if (edge === "left") {
|
||||||
return Math.max(left, Math.min(right, want))
|
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: {
|
y: {
|
||||||
if (menuRoot.isAtBottom) {
|
if (menuRoot.isVertical) {
|
||||||
const targetY = menuWindow.anchorPos.y - height
|
const top = 10
|
||||||
return Math.max(10, targetY)
|
const bottom = menuWindow.height - height - 10
|
||||||
|
const want = menuWindow.anchorPos.y - height / 2
|
||||||
|
return Math.max(top, Math.min(bottom, want))
|
||||||
} else {
|
} else {
|
||||||
const targetY = menuWindow.anchorPos.y
|
if (menuRoot.isAtBottom) {
|
||||||
return Math.min(menuWindow.screen.height - height - 10, targetY)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,15 +498,13 @@ Rectangle {
|
|||||||
if (!menuEntry || menuEntry.isSeparator) return;
|
if (!menuEntry || menuEntry.isSeparator) return;
|
||||||
|
|
||||||
if (menuEntry.hasChildren) {
|
if (menuEntry.hasChildren) {
|
||||||
console.log("Opening submenu for:", menuEntry.text);
|
|
||||||
menuRoot.showSubMenu(menuEntry);
|
menuRoot.showSubMenu(menuEntry);
|
||||||
} else {
|
} else {
|
||||||
if (typeof menuEntry.activate === "function") {
|
if (typeof menuEntry.activate === "function") {
|
||||||
menuEntry.activate(); // preferred
|
menuEntry.activate();
|
||||||
} else if (typeof menuEntry.triggered === "function") {
|
} else if (typeof menuEntry.triggered === "function") {
|
||||||
menuEntry.triggered();
|
menuEntry.triggered();
|
||||||
}
|
}
|
||||||
// optional: small delay to let provider flip state before closing
|
|
||||||
Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.close() }', menuRoot);
|
Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.close() }', menuRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,13 +617,13 @@ Rectangle {
|
|||||||
|
|
||||||
property var currentTrayMenu: null
|
property var currentTrayMenu: null
|
||||||
|
|
||||||
function showForTrayItem(item, anchor, screen, atBottom) {
|
function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) {
|
||||||
if (currentTrayMenu) {
|
if (currentTrayMenu) {
|
||||||
currentTrayMenu.destroy()
|
currentTrayMenu.destroy()
|
||||||
}
|
}
|
||||||
currentTrayMenu = trayMenuComponent.createObject(null)
|
currentTrayMenu = trayMenuComponent.createObject(null)
|
||||||
if (currentTrayMenu) {
|
if (currentTrayMenu) {
|
||||||
currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom)
|
currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6,20 +6,22 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property bool isActive: false
|
property bool isActive: false
|
||||||
property string section: "right"
|
property string section: "right"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
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 hasUpdates: SystemUpdateService.updateCount > 0
|
||||||
readonly property bool isChecking: SystemUpdateService.isChecking
|
readonly property bool isChecking: SystemUpdateService.isChecking
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
width: updaterIcon.width + horizontalPadding * 2
|
width: isVertical ? widgetThickness : (updaterIcon.width + horizontalPadding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? widgetThickness : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -30,14 +32,63 @@ Rectangle {
|
|||||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
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 {
|
Row {
|
||||||
id: updaterIcon
|
id: updaterIcon
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
visible: !root.isVertical
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
id: statusIcon
|
id: statusIconHorizontal
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
name: {
|
name: {
|
||||||
@@ -54,8 +105,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RotationAnimation {
|
RotationAnimation {
|
||||||
id: rotationAnimation
|
id: rotationAnimationHorizontal
|
||||||
target: statusIcon
|
target: statusIconHorizontal
|
||||||
property: "rotation"
|
property: "rotation"
|
||||||
from: 0
|
from: 0
|
||||||
to: 360
|
to: 360
|
||||||
@@ -65,7 +116,7 @@ Rectangle {
|
|||||||
|
|
||||||
onRunningChanged: {
|
onRunningChanged: {
|
||||||
if (!running) {
|
if (!running) {
|
||||||
statusIcon.rotation = 0
|
statusIconHorizontal.rotation = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,11 +142,10 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
root.clicked();
|
root.clicked();
|
||||||
}
|
}
|
||||||
111
Modules/DankBar/Widgets/Vpn.qml
Normal file
111
Modules/DankBar/Widgets/Vpn.qml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
RotationAnimation on rotation {
|
||||||
|
running: VpnService.isBusy
|
||||||
|
loops: Animation.Infinite
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
duration: 900
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
const globalPos = mapToGlobal(0, 0)
|
||||||
|
const currentScreen = parentScreen || Screen
|
||||||
|
const screenY = currentScreen ? currentScreen.y : 0
|
||||||
|
const relativeY = globalPos.y - screenY
|
||||||
|
|
||||||
|
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 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(tooltipText, screenX + tooltipX, relativeY, currentScreen, isLeft, !isLeft)
|
||||||
|
} else {
|
||||||
|
tooltipLoader.item.show(tooltipText, relativeX, screenY + root.barThickness + SettingsData.dankBarSpacing + Theme.spacingXS, currentScreen, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onExited: {
|
||||||
|
if (tooltipLoader.item) {
|
||||||
|
tooltipLoader.item.hide()
|
||||||
|
}
|
||||||
|
tooltipLoader.active = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,18 +6,20 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property string section: "center"
|
property string section: "center"
|
||||||
property var popupTarget: null
|
property var popupTarget: null
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
property real barHeight: 48
|
property real barThickness: 48
|
||||||
property real widgetHeight: 30
|
property real widgetThickness: 30
|
||||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
visible: SettingsData.weatherEnabled
|
visible: SettingsData.weatherEnabled
|
||||||
width: visible ? Math.min(100, weatherRow.implicitWidth + horizontalPadding * 2) : 0
|
width: isVertical ? widgetThickness : (visible ? Math.min(100, weatherRow.implicitWidth + horizontalPadding * 2) : 0)
|
||||||
height: widgetHeight
|
height: isVertical ? (weatherColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground) {
|
if (SettingsData.dankBarNoBackground) {
|
||||||
@@ -32,9 +34,37 @@ Rectangle {
|
|||||||
service: WeatherService
|
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 {
|
Row {
|
||||||
id: weatherRow
|
id: weatherRow
|
||||||
|
|
||||||
|
visible: !root.isVertical
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
@@ -69,11 +99,10 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||||
const globalPos = mapToGlobal(0, 0);
|
const globalPos = mapToGlobal(0, 0)
|
||||||
const currentScreen = parentScreen || Screen;
|
const currentScreen = parentScreen || Screen
|
||||||
const screenX = currentScreen.x || 0;
|
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||||
const relativeX = globalPos.x - screenX;
|
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||||
popupTarget.setTriggerPosition(relativeX, SettingsData.getPopupYPosition(barHeight), width, section, currentScreen);
|
|
||||||
}
|
}
|
||||||
root.clicked();
|
root.clicked();
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,8 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool isVertical: axis?.isVertical ?? false
|
||||||
|
property var axis: null
|
||||||
property string screenName: ""
|
property string screenName: ""
|
||||||
property real widgetHeight: 30
|
property real widgetHeight: 30
|
||||||
property int currentWorkspace: {
|
property int currentWorkspace: {
|
||||||
@@ -192,7 +194,9 @@ Rectangle {
|
|||||||
return currentMonitor.activeWorkspace?.id ?? 1
|
return currentMonitor.activeWorkspace?.id ?? 1
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real padding: (widgetHeight - workspaceRow.implicitHeight) / 2
|
readonly property real padding: isVertical
|
||||||
|
? Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
||||||
|
: (widgetHeight - workspaceRow.implicitHeight) / 2
|
||||||
|
|
||||||
function getRealWorkspaces() {
|
function getRealWorkspaces() {
|
||||||
return root.workspaceList.filter(ws => {
|
return root.workspaceList.filter(ws => {
|
||||||
@@ -221,8 +225,8 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width: workspaceRow.implicitWidth + padding * 2
|
width: isVertical ? widgetHeight : (workspaceRow.implicitWidth + padding * 2)
|
||||||
height: widgetHeight
|
height: isVertical ? (workspaceRow.implicitHeight + padding * 2) : widgetHeight
|
||||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (SettingsData.dankBarNoBackground)
|
if (SettingsData.dankBarNoBackground)
|
||||||
@@ -261,11 +265,12 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Flow {
|
||||||
id: workspaceRow
|
id: workspaceRow
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.workspaceList
|
model: root.workspaceList
|
||||||
@@ -332,16 +337,36 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
width: {
|
width: {
|
||||||
if (SettingsData.showWorkspaceApps && loadedIcons.length > 0) {
|
if (root.isVertical) {
|
||||||
const numIcons = Math.min(loadedIcons.length, SettingsData.maxWorkspaceIcons);
|
// Vertical mode: width is like horizontal height (small and fixed)
|
||||||
const iconsWidth = numIcons * 18 + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0);
|
return SettingsData.showWorkspaceApps ? widgetHeight * 0.8 : widgetHeight * 0.6;
|
||||||
const baseWidth = isActive ? root.widgetHeight * 1.0 + Theme.spacingXS : root.widgetHeight * 0.8;
|
} else {
|
||||||
return baseWidth + iconsWidth;
|
// Horizontal mode - original logic
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
return isActive ? root.widgetHeight * 1.2 : root.widgetHeight * 0.8;
|
|
||||||
}
|
}
|
||||||
height: SettingsData.showWorkspaceApps ? widgetHeight * 0.8 : widgetHeight * 0.6
|
height: {
|
||||||
radius: height / 2
|
if (root.isVertical) {
|
||||||
|
// Vertical mode: height is like horizontal width (dynamic)
|
||||||
|
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 * 1.0 + Theme.spacingXS : root.widgetHeight * 0.8;
|
||||||
|
return baseHeight + iconsHeight;
|
||||||
|
}
|
||||||
|
return isActive ? root.widgetHeight * 1.2 : root.widgetHeight * 0.8;
|
||||||
|
} else {
|
||||||
|
// Horizontal mode - original logic
|
||||||
|
return SettingsData.showWorkspaceApps ? widgetHeight * 0.8 : widgetHeight * 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
radius: Math.min(width, height) / 2
|
||||||
color: isActive ? Theme.primary : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha
|
color: isActive ? Theme.primary : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha
|
||||||
|
|
||||||
Behavior on width {
|
Behavior on width {
|
||||||
@@ -352,6 +377,14 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
enabled: root.isVertical && (!SettingsData.showWorkspaceApps || SettingsData.maxWorkspaceIcons <= 3)
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
||||||
@@ -372,74 +405,149 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loader for App Icons
|
|
||||||
Loader {
|
Loader {
|
||||||
id: appIconsLoader
|
id: appIconsLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: SettingsData.showWorkspaceApps
|
active: SettingsData.showWorkspaceApps
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
Row {
|
Loader {
|
||||||
id: contentRow
|
id: contentRow
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 4
|
sourceComponent: root.isVertical ? columnLayout : rowLayout
|
||||||
visible: loadedIcons.length > 0
|
}
|
||||||
|
|
||||||
Repeater {
|
Component {
|
||||||
model: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons)
|
id: rowLayout
|
||||||
delegate: Item {
|
Row {
|
||||||
width: 18
|
spacing: 4
|
||||||
height: 18
|
visible: loadedIcons.length > 0
|
||||||
|
|
||||||
IconImage {
|
Repeater {
|
||||||
id: appIcon
|
model: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons)
|
||||||
property var windowId: modelData.windowId
|
delegate: Item {
|
||||||
anchors.fill: parent
|
width: 18
|
||||||
source: modelData.icon
|
height: 18
|
||||||
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
|
|
||||||
visible: !modelData.isSteamApp
|
|
||||||
}
|
|
||||||
|
|
||||||
DankIcon {
|
IconImage {
|
||||||
anchors.centerIn: parent
|
id: appIcon
|
||||||
size: 18
|
property var windowId: modelData.windowId
|
||||||
name: "sports_esports"
|
anchors.fill: parent
|
||||||
color: Theme.surfaceText
|
source: modelData.icon
|
||||||
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
|
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
visible: modelData.isSteamApp
|
visible: !modelData.isSteamApp
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
DankIcon {
|
||||||
id: appMouseArea
|
anchors.centerIn: parent
|
||||||
hoverEnabled: true
|
size: 18
|
||||||
anchors.fill: parent
|
name: "sports_esports"
|
||||||
enabled: isActive
|
color: Theme.surfaceText
|
||||||
cursorShape: Qt.PointingHandCursor
|
opacity: modelData.active ? 1.0 : appMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
onClicked: {
|
visible: modelData.isSteamApp
|
||||||
if (CompositorService.isHyprland) {
|
}
|
||||||
Hyprland.dispatch(`focuswindow address:${appIcon.windowId}`)
|
|
||||||
} else if (CompositorService.isNiri) {
|
MouseArea {
|
||||||
NiriService.focusWindow(appIcon.windowId)
|
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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Component {
|
||||||
visible: modelData.count > 1 && !isActive
|
id: columnLayout
|
||||||
width: 12
|
Column {
|
||||||
height: 12
|
spacing: 4
|
||||||
radius: 6
|
visible: loadedIcons.length > 0
|
||||||
color: "black"
|
|
||||||
border.color: "white"
|
|
||||||
border.width: 1
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
z: 2
|
|
||||||
|
|
||||||
Text {
|
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 {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: modelData.count
|
size: 18
|
||||||
font.pixelSize: 8
|
name: "sports_esports"
|
||||||
color: "white"
|
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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,30 +13,33 @@ DankPopout {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool dashVisible: false
|
property bool dashVisible: false
|
||||||
property string triggerSection: "center"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
property int currentTabIndex: 0
|
property int currentTabIndex: 0
|
||||||
|
|
||||||
function setTriggerPosition(x, y, width, section, screen) {
|
function setTriggerPosition(x, y, width, section, screen) {
|
||||||
if (section === "center") {
|
triggerSection = section
|
||||||
|
triggerScreen = screen
|
||||||
|
triggerY = y
|
||||||
|
|
||||||
|
if (section === "center" && (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)) {
|
||||||
const screenWidth = screen ? screen.width : Screen.width
|
const screenWidth = screen ? screen.width : Screen.width
|
||||||
triggerX = (screenWidth - popupWidth) / 2
|
triggerX = (screenWidth - popupWidth) / 2
|
||||||
triggerWidth = popupWidth
|
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 {
|
} else {
|
||||||
triggerX = x
|
triggerX = x
|
||||||
triggerWidth = width
|
triggerWidth = width
|
||||||
}
|
}
|
||||||
triggerY = y
|
|
||||||
triggerSection = section
|
|
||||||
triggerScreen = screen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
popupWidth: 700
|
popupWidth: 700
|
||||||
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500
|
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500
|
||||||
triggerX: Screen.width - 620 - Theme.spacingL
|
triggerX: Screen.width - 620 - Theme.spacingL
|
||||||
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2 + Theme.popupDistance
|
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
|
||||||
triggerWidth: 80
|
triggerWidth: 80
|
||||||
positioning: "center"
|
|
||||||
shouldBeVisible: dashVisible
|
shouldBeVisible: dashVisible
|
||||||
visible: shouldBeVisible
|
visible: shouldBeVisible
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -32,13 +32,16 @@ Variants {
|
|||||||
property real backgroundTransparency: SettingsData.dockTransparency
|
property real backgroundTransparency: SettingsData.dockTransparency
|
||||||
property bool groupByApp: SettingsData.dockGroupByApp
|
property bool groupByApp: SettingsData.dockGroupByApp
|
||||||
|
|
||||||
readonly property bool isDockAtTop: SettingsData.dockPosition === SettingsData.Position.Top
|
|
||||||
readonly property bool isDankBarAtTop: !SettingsData.dankBarAtBottom
|
|
||||||
readonly property bool isDankBarVisible: SettingsData.dankBarVisible
|
|
||||||
readonly property bool needsBarSpacing: isDankBarVisible && (isDockAtTop === isDankBarAtTop)
|
|
||||||
readonly property real widgetHeight: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
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 effectiveBarHeight: Math.max(widgetHeight + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||||
readonly property real barSpacing: needsBarSpacing ? (SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap) : 0
|
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 dockMargin: SettingsData.dockSpacing
|
||||||
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap
|
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap
|
||||||
@@ -92,7 +95,7 @@ Variants {
|
|||||||
|
|
||||||
exclusiveZone: {
|
exclusiveZone: {
|
||||||
if (!SettingsData.showDock || autoHide) return -1
|
if (!SettingsData.showDock || autoHide) return -1
|
||||||
if (needsBarSpacing) return -1
|
if (barSpacing > 0) return -1
|
||||||
return px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap)
|
return px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ Column {
|
|||||||
width: calculatedWidth
|
width: calculatedWidth
|
||||||
height: 32
|
height: 32
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent"
|
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0)
|
||||||
border.width: isActive ? 0 : 1
|
border.width: isActive ? 0 : 1
|
||||||
border.color: Theme.outlineMedium
|
border.color: Theme.outlineMedium
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ Column {
|
|||||||
width: 20
|
width: 20
|
||||||
height: 20
|
height: 20
|
||||||
radius: 10
|
radius: 10
|
||||||
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||||
visible: NotepadStorageService.tabs.length > 1
|
visible: NotepadStorageService.tabs.length > 1
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ DankPopout {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool notificationHistoryVisible: false
|
property bool notificationHistoryVisible: false
|
||||||
property string triggerSection: "right"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
|
|
||||||
NotificationKeyboardController {
|
NotificationKeyboardController {
|
||||||
@@ -35,10 +34,10 @@ DankPopout {
|
|||||||
|
|
||||||
popupWidth: 400
|
popupWidth: 400
|
||||||
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
|
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
|
||||||
triggerX: Screen.width - 400 - Theme.spacingL
|
triggerX: 0
|
||||||
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing + Theme.popupDistance
|
triggerY: 0
|
||||||
triggerWidth: 40
|
triggerWidth: 40
|
||||||
positioning: "center"
|
positioning: ""
|
||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
shouldBeVisible: notificationHistoryVisible
|
shouldBeVisible: notificationHistoryVisible
|
||||||
visible: shouldBeVisible
|
visible: shouldBeVisible
|
||||||
|
|||||||
@@ -76,13 +76,6 @@ PanelWindow {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
implicitWidth: 400
|
implicitWidth: 400
|
||||||
implicitHeight: 122
|
implicitHeight: 122
|
||||||
onScreenYChanged: {
|
|
||||||
if (SettingsData.dankBarAtBottom) {
|
|
||||||
margins.bottom = Theme.barHeight - 4 + SettingsData.dankBarSpacing + 4 + screenY
|
|
||||||
} else {
|
|
||||||
margins.top = Theme.barHeight - 4 + SettingsData.dankBarSpacing + 4 + screenY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onHasValidDataChanged: {
|
onHasValidDataChanged: {
|
||||||
if (!hasValidData && !exiting && !_isDestroying) {
|
if (!hasValidData && !exiting && !_isDestroying) {
|
||||||
forceExit()
|
forceExit()
|
||||||
@@ -114,16 +107,94 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors {
|
property bool isTopCenter: SettingsData.notificationPopupPosition === -1
|
||||||
top: !SettingsData.dankBarAtBottom
|
|
||||||
bottom: SettingsData.dankBarAtBottom
|
anchors.top: isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left
|
||||||
right: true
|
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
|
||||||
|
|
||||||
margins {
|
margins {
|
||||||
top: SettingsData.dankBarAtBottom ? 0 : (Theme.barHeight - 4 + SettingsData.dankBarSpacing + 4)
|
top: getTopMargin()
|
||||||
bottom: SettingsData.dankBarAtBottom ? (Theme.barHeight - 4 + SettingsData.dankBarSpacing + 4) : 0
|
bottom: getBottomMargin()
|
||||||
right: 12
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -131,7 +202,7 @@ PanelWindow {
|
|||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: win.hasValidData
|
visible: win.hasValidData
|
||||||
layer.enabled: (enterX.running || exitAnim.running)
|
layer.enabled: true
|
||||||
layer.smooth: true
|
layer.smooth: true
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -463,7 +534,12 @@ PanelWindow {
|
|||||||
transform: Translate {
|
transform: Translate {
|
||||||
id: tx
|
id: tx
|
||||||
|
|
||||||
x: Anims.slidePx
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,15 +547,23 @@ PanelWindow {
|
|||||||
id: enterX
|
id: enterX
|
||||||
|
|
||||||
target: tx
|
target: tx
|
||||||
property: "x"
|
property: isTopCenter ? "y" : "x"
|
||||||
from: Anims.slidePx
|
from: {
|
||||||
|
if (isTopCenter) return -Anims.slidePx
|
||||||
|
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
||||||
|
return isLeft ? -Anims.slidePx : Anims.slidePx
|
||||||
|
}
|
||||||
to: 0
|
to: 0
|
||||||
duration: Anims.durMed
|
duration: Anims.durMed
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: Anims.emphasizedDecel
|
easing.bezierCurve: isTopCenter ? Anims.standardDecel : Anims.emphasizedDecel
|
||||||
onStopped: {
|
onStopped: {
|
||||||
if (!win.exiting && !win._isDestroying && Math.abs(tx.x) < 0.5) {
|
if (!win.exiting && !win._isDestroying) {
|
||||||
win.entered()
|
if (isTopCenter) {
|
||||||
|
if (Math.abs(tx.y) < 0.5) win.entered()
|
||||||
|
} else {
|
||||||
|
if (Math.abs(tx.x) < 0.5) win.entered()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -491,9 +575,13 @@ PanelWindow {
|
|||||||
|
|
||||||
PropertyAnimation {
|
PropertyAnimation {
|
||||||
target: tx
|
target: tx
|
||||||
property: "x"
|
property: isTopCenter ? "y" : "x"
|
||||||
from: 0
|
from: 0
|
||||||
to: Anims.slidePx
|
to: {
|
||||||
|
if (isTopCenter) return -Anims.slidePx
|
||||||
|
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
||||||
|
return isLeft ? -Anims.slidePx : Anims.slidePx
|
||||||
|
}
|
||||||
duration: Anims.durShort
|
duration: Anims.durShort
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: Anims.emphasizedAccel
|
easing.bezierCurve: Anims.emphasizedAccel
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ Rectangle {
|
|||||||
width: parent ? parent.width : 0
|
width: parent ? parent.width : 0
|
||||||
height: 40
|
height: 40
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
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) : "transparent"
|
border.color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -158,7 +158,7 @@ Rectangle {
|
|||||||
width: 28
|
width: 28
|
||||||
height: 28
|
height: 28
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0)
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ DankPopout {
|
|||||||
id: processListPopout
|
id: processListPopout
|
||||||
|
|
||||||
property var parentWidget: null
|
property var parentWidget: null
|
||||||
property string triggerSection: "right"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
|
|
||||||
function setTriggerPosition(x, y, width, section, screen) {
|
function setTriggerPosition(x, y, width, section, screen) {
|
||||||
@@ -40,9 +39,9 @@ DankPopout {
|
|||||||
popupWidth: 600
|
popupWidth: 600
|
||||||
popupHeight: 600
|
popupHeight: 600
|
||||||
triggerX: Screen.width - 600 - Theme.spacingL
|
triggerX: Screen.width - 600 - Theme.spacingL
|
||||||
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2 + Theme.popupDistance
|
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
|
||||||
triggerWidth: 55
|
triggerWidth: 55
|
||||||
positioning: "center"
|
positioning: ""
|
||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
visible: shouldBeVisible
|
visible: shouldBeVisible
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Column {
|
|||||||
if (DgopService.currentSort === "name") {
|
if (DgopService.currentSort === "name") {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
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) : "transparent";
|
return processHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
|
||||||
}
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -74,7 +74,7 @@ Column {
|
|||||||
if (DgopService.currentSort === "cpu") {
|
if (DgopService.currentSort === "cpu") {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
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) : "transparent";
|
return cpuHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
|
||||||
}
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -118,7 +118,7 @@ Column {
|
|||||||
if (DgopService.currentSort === "memory") {
|
if (DgopService.currentSort === "memory") {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
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) : "transparent";
|
return memoryHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
|
||||||
}
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -162,7 +162,7 @@ Column {
|
|||||||
if (DgopService.currentSort === "pid") {
|
if (DgopService.currentSort === "pid") {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
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) : "transparent";
|
return pidHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0);
|
||||||
}
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -204,7 +204,7 @@ Column {
|
|||||||
width: 28
|
width: 28
|
||||||
height: 28
|
height: 28
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: sortOrderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: sortOrderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : Theme.withAlpha(Theme.surfaceText, 0)
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 8
|
anchors.rightMargin: 8
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|||||||
@@ -623,11 +623,24 @@ Item {
|
|||||||
DankButtonGroup {
|
DankButtonGroup {
|
||||||
id: positionButtonGroup
|
id: positionButtonGroup
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
model: ["Top", "Bottom"]
|
model: ["Top", "Bottom", "Left", "Right"]
|
||||||
currentIndex: SettingsData.dankBarAtBottom ? 1 : 0
|
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) => {
|
onSelectionChanged: (index, selected) => {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
SettingsData.setDankBarAtBottom(index === 1)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -876,7 +889,7 @@ Item {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Height to Edge Gap (Exclusive Zone)"
|
text: "Exclusive Zone Offset"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@@ -1086,7 +1099,7 @@ Item {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingL
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
// Left Section
|
// Left/Top Section
|
||||||
StyledRect {
|
StyledRect {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: leftSection.implicitHeight + Theme.spacingL * 2
|
height: leftSection.implicitHeight + Theme.spacingL * 2
|
||||||
@@ -1100,7 +1113,7 @@ Item {
|
|||||||
id: leftSection
|
id: leftSection
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
title: "Left Section"
|
title: SettingsData.dankBarIsVertical ? "Top Section" : "Left Section"
|
||||||
titleIcon: "format_align_left"
|
titleIcon: "format_align_left"
|
||||||
sectionId: "left"
|
sectionId: "left"
|
||||||
allWidgets: dankBarTab.baseWidgetDefinitions
|
allWidgets: dankBarTab.baseWidgetDefinitions
|
||||||
@@ -1230,7 +1243,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right Section
|
// Right/Bottom Section
|
||||||
StyledRect {
|
StyledRect {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: rightSection.implicitHeight + Theme.spacingL * 2
|
height: rightSection.implicitHeight + Theme.spacingL * 2
|
||||||
@@ -1244,7 +1257,7 @@ Item {
|
|||||||
id: rightSection
|
id: rightSection
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
title: "Right Section"
|
title: SettingsData.dankBarIsVertical ? "Bottom Section" : "Right Section"
|
||||||
titleIcon: "format_align_right"
|
titleIcon: "format_align_right"
|
||||||
sectionId: "right"
|
sectionId: "right"
|
||||||
allWidgets: dankBarTab.baseWidgetDefinitions
|
allWidgets: dankBarTab.baseWidgetDefinitions
|
||||||
|
|||||||
@@ -985,7 +985,8 @@ Item {
|
|||||||
text: "Light Mode"
|
text: "Light Mode"
|
||||||
description: "Use light theme instead of dark theme"
|
description: "Use light theme instead of dark theme"
|
||||||
checked: SessionData.isLightMode
|
checked: SessionData.isLightMode
|
||||||
onToggled: checked => {
|
onToggleCompleted: checked => {
|
||||||
|
Theme.screenTransition()
|
||||||
Theme.setLightMode(checked)
|
Theme.setLightMode(checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1331,17 +1332,17 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock Screen Settings
|
// Notification Popup Settings
|
||||||
StyledRect {
|
StyledRect {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: lockScreenSection.implicitHeight + Theme.spacingL * 2
|
height: notificationPopupSection.implicitHeight + Theme.spacingL * 2
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceContainerHigh
|
color: Theme.surfaceContainerHigh
|
||||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||||
border.width: 0
|
border.width: 0
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: lockScreenSection
|
id: notificationPopupSection
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
@@ -1352,14 +1353,14 @@ Item {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: "lock"
|
name: "notifications"
|
||||||
size: Theme.iconSize
|
size: Theme.iconSize
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Lock Screen"
|
text: "Notification Popups"
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
@@ -1367,14 +1368,48 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankToggle {
|
DankDropdown {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: "Show Power Actions"
|
text: "Popup Position"
|
||||||
description: "Show power, restart, and logout buttons on the lock screen"
|
description: "Choose where notification popups appear on screen"
|
||||||
checked: SettingsData.lockScreenShowPowerActions
|
currentValue: {
|
||||||
onToggled: checked => {
|
if (SettingsData.notificationPopupPosition === -1) {
|
||||||
SettingsData.setLockScreenShowPowerActions(checked)
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1611,6 +1646,54 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ Item {
|
|||||||
if (Theme.currentThemeCategory === "catppuccin") return 1
|
if (Theme.currentThemeCategory === "catppuccin") return 1
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
property int pendingThemeIndex: -1
|
||||||
|
|
||||||
model: ["Generic", "Catppuccin", "Auto", "Custom"]
|
model: ["Generic", "Catppuccin", "Auto", "Custom"]
|
||||||
currentIndex: currentThemeIndex
|
currentIndex: currentThemeIndex
|
||||||
@@ -233,7 +234,11 @@ Item {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
onSelectionChanged: (index, selected) => {
|
onSelectionChanged: (index, selected) => {
|
||||||
if (!selected) return
|
if (!selected) return
|
||||||
switch (index) {
|
pendingThemeIndex = index
|
||||||
|
}
|
||||||
|
onAnimationCompleted: {
|
||||||
|
if (pendingThemeIndex === -1) return
|
||||||
|
switch (pendingThemeIndex) {
|
||||||
case 0: Theme.switchThemeCategory("generic", "blue"); break
|
case 0: Theme.switchThemeCategory("generic", "blue"); break
|
||||||
case 1: Theme.switchThemeCategory("catppuccin", "cat-mauve"); break
|
case 1: Theme.switchThemeCategory("catppuccin", "cat-mauve"); break
|
||||||
case 2:
|
case 2:
|
||||||
@@ -242,14 +247,15 @@ Item {
|
|||||||
else if (ToastService.wallpaperErrorStatus === "error")
|
else if (ToastService.wallpaperErrorStatus === "error")
|
||||||
ToastService.showError("Wallpaper processing failed - check wallpaper path")
|
ToastService.showError("Wallpaper processing failed - check wallpaper path")
|
||||||
else
|
else
|
||||||
Theme.switchTheme(Theme.dynamic, true, false)
|
Theme.switchTheme(Theme.dynamic, true, true)
|
||||||
break
|
break
|
||||||
case 3:
|
case 3:
|
||||||
if (Theme.currentThemeName !== "custom") {
|
if (Theme.currentThemeName !== "custom") {
|
||||||
Theme.switchTheme("custom", true, false)
|
Theme.switchTheme("custom", true, true)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
pendingThemeIndex = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -305,6 +305,19 @@ Column {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
root.compactModeChanged("music", 0)
|
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 {
|
DankActionButton {
|
||||||
@@ -318,6 +331,19 @@ Column {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
root.compactModeChanged("music", 1)
|
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 {
|
DankActionButton {
|
||||||
@@ -331,6 +357,19 @@ Column {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
root.compactModeChanged("music", 2)
|
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 {
|
DankActionButton {
|
||||||
@@ -373,6 +412,27 @@ Column {
|
|||||||
!SettingsData.runningAppsCompactMode)
|
!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 {
|
Rectangle {
|
||||||
@@ -426,6 +486,7 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DankActionButton {
|
DankActionButton {
|
||||||
|
id: visibilityButton
|
||||||
visible: modelData.id !== "spacer"
|
visible: modelData.id !== "spacer"
|
||||||
buttonSize: 32
|
buttonSize: 32
|
||||||
iconName: modelData.enabled ? "visibility" : "visibility_off"
|
iconName: modelData.enabled ? "visibility" : "visibility_off"
|
||||||
@@ -436,6 +497,20 @@ Column {
|
|||||||
modelData.id,
|
modelData.id,
|
||||||
!modelData.enabled)
|
!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 {
|
Row {
|
||||||
@@ -791,4 +866,34 @@ 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 {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ DankPopout {
|
|||||||
id: systemUpdatePopout
|
id: systemUpdatePopout
|
||||||
|
|
||||||
property var parentWidget: null
|
property var parentWidget: null
|
||||||
property string triggerSection: "right"
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
|
|
||||||
function setTriggerPosition(x, y, width, section, screen) {
|
function setTriggerPosition(x, y, width, section, screen) {
|
||||||
@@ -26,9 +25,9 @@ DankPopout {
|
|||||||
popupWidth: 400
|
popupWidth: 400
|
||||||
popupHeight: 500
|
popupHeight: 500
|
||||||
triggerX: Screen.width - 600 - Theme.spacingL
|
triggerX: Screen.width - 600 - Theme.spacingL
|
||||||
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2 + Theme.popupDistance
|
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
|
||||||
triggerWidth: 55
|
triggerWidth: 55
|
||||||
positioning: "center"
|
positioning: ""
|
||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
visible: shouldBeVisible
|
visible: shouldBeVisible
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
|
|||||||
@@ -412,13 +412,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function doScreenTransition() {
|
function doScreenTransition() {
|
||||||
return send({
|
send({
|
||||||
"Action": {
|
"Action": {
|
||||||
"DoScreenTransition": {
|
"DoScreenTransition": {
|
||||||
"delay_ms": 100,
|
"delay_ms": 0,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchToWorkspace(workspaceIndex) {
|
function switchToWorkspace(workspaceIndex) {
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const shouldShowPopup = !root.popupsDisabled && !SessionData.doNotDisturb
|
const shouldShowPopup = !root.popupsDisabled && !SessionData.doNotDisturb
|
||||||
|
const isTransient = notif.transient
|
||||||
const wrapper = notifComponent.createObject(root, {
|
const wrapper = notifComponent.createObject(root, {
|
||||||
"popup": shouldShowPopup,
|
"popup": shouldShowPopup,
|
||||||
"notification": notif
|
"notification": notif
|
||||||
@@ -233,8 +234,10 @@ Singleton {
|
|||||||
|
|
||||||
if (wrapper) {
|
if (wrapper) {
|
||||||
root.allWrappers.push(wrapper)
|
root.allWrappers.push(wrapper)
|
||||||
root.notifications.push(wrapper)
|
if (!isTransient) {
|
||||||
_trimStored()
|
root.notifications.push(wrapper)
|
||||||
|
_trimStored()
|
||||||
|
}
|
||||||
|
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
_initWrapperPersistence(wrapper)
|
_initWrapperPersistence(wrapper)
|
||||||
@@ -407,8 +410,11 @@ Singleton {
|
|||||||
addGateBusy = false
|
addGateBusy = false
|
||||||
notificationQueue = []
|
notificationQueue = []
|
||||||
|
|
||||||
for (const w of allWrappers)
|
for (const w of allWrappers) {
|
||||||
w.popup = false
|
if (w) {
|
||||||
|
w.popup = false
|
||||||
|
}
|
||||||
|
}
|
||||||
visibleNotifications = []
|
visibleNotifications = []
|
||||||
|
|
||||||
_dismissQueue = notifications.slice()
|
_dismissQueue = notifications.slice()
|
||||||
@@ -528,6 +534,7 @@ Singleton {
|
|||||||
const groups = {}
|
const groups = {}
|
||||||
|
|
||||||
for (const notif of notifications) {
|
for (const notif of notifications) {
|
||||||
|
if (!notif) continue
|
||||||
const groupKey = getGroupKey(notif)
|
const groupKey = getGroupKey(notif)
|
||||||
if (!groups[groupKey]) {
|
if (!groups[groupKey]) {
|
||||||
groups[groupKey] = {
|
groups[groupKey] = {
|
||||||
@@ -563,6 +570,7 @@ Singleton {
|
|||||||
const groups = {}
|
const groups = {}
|
||||||
|
|
||||||
for (const notif of popups) {
|
for (const notif of popups) {
|
||||||
|
if (!notif) continue
|
||||||
const groupKey = getGroupKey(notif)
|
const groupKey = getGroupKey(notif)
|
||||||
if (!groups[groupKey]) {
|
if (!groups[groupKey]) {
|
||||||
groups[groupKey] = {
|
groups[groupKey] = {
|
||||||
@@ -630,7 +638,9 @@ Singleton {
|
|||||||
const currentMessageIds = new Set()
|
const currentMessageIds = new Set()
|
||||||
for (const group of groupedNotifications) {
|
for (const group of groupedNotifications) {
|
||||||
for (const notif of group.notifications) {
|
for (const notif of group.notifications) {
|
||||||
currentMessageIds.add(notif.notification.id)
|
if (notif && notif.notification) {
|
||||||
|
currentMessageIds.add(notif.notification.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let newExpandedGroups = {}
|
let newExpandedGroups = {}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ StyledRect {
|
|||||||
property int buttonSize: 32
|
property int buttonSize: 32
|
||||||
|
|
||||||
signal clicked
|
signal clicked
|
||||||
|
signal entered
|
||||||
|
signal exited
|
||||||
|
|
||||||
width: buttonSize
|
width: buttonSize
|
||||||
height: buttonSize
|
height: buttonSize
|
||||||
@@ -30,5 +32,7 @@ StyledRect {
|
|||||||
stateColor: Theme.primary
|
stateColor: Theme.primary
|
||||||
cornerRadius: root.radius
|
cornerRadius: root.radius
|
||||||
onClicked: root.clicked()
|
onClicked: root.clicked()
|
||||||
|
onEntered: root.entered()
|
||||||
|
onExited: root.exited()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,16 @@ Flow {
|
|||||||
property int textSize: Theme.fontSizeMedium
|
property int textSize: Theme.fontSizeMedium
|
||||||
|
|
||||||
signal selectionChanged(int index, bool selected)
|
signal selectionChanged(int index, bool selected)
|
||||||
|
signal animationCompleted()
|
||||||
|
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: animationTimer
|
||||||
|
interval: Theme.shortDuration
|
||||||
|
onTriggered: root.animationCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
function isSelected(index) {
|
function isSelected(index) {
|
||||||
if (multiSelect) {
|
if (multiSelect) {
|
||||||
return repeater.itemAt(index)?.selected || false
|
return repeater.itemAt(index)?.selected || false
|
||||||
@@ -43,6 +50,7 @@ Flow {
|
|||||||
|
|
||||||
currentSelection = newSelection
|
currentSelection = newSelection
|
||||||
selectionChanged(index, !isCurrentlySelected)
|
selectionChanged(index, !isCurrentlySelected)
|
||||||
|
animationTimer.restart()
|
||||||
} else {
|
} else {
|
||||||
const oldIndex = currentIndex
|
const oldIndex = currentIndex
|
||||||
currentIndex = index
|
currentIndex = index
|
||||||
@@ -50,6 +58,7 @@ Flow {
|
|||||||
if (oldIndex !== index && oldIndex >= 0) {
|
if (oldIndex !== index && oldIndex >= 0) {
|
||||||
selectionChanged(oldIndex, false)
|
selectionChanged(oldIndex, false)
|
||||||
}
|
}
|
||||||
|
animationTimer.restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
size: 18
|
size: 18
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: name !== "" && root.width > 60
|
visible: name !== "" && root.width > 60
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +132,7 @@ Rectangle {
|
|||||||
text: root.currentValue
|
text: root.currentValue
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: root.width <= 60 ? dropdown.width - expandIcon.width - Theme.spacingS * 2 : dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS
|
width: root.width <= 60 ? dropdown.width - expandIcon.width - Theme.spacingS * 2 : dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS
|
||||||
elide: root.width <= 60 ? Text.ElideNone : Text.ElideRight
|
elide: root.width <= 60 ? Text.ElideNone : Text.ElideRight
|
||||||
horizontalAlignment: root.width <= 60 ? Text.AlignHCenter : Text.AlignLeft
|
horizontalAlignment: root.width <= 60 ? Text.AlignHCenter : Text.AlignLeft
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ StyledText {
|
|||||||
property int grade: Theme.isLightMode ? 0 : -25
|
property int grade: Theme.isLightMode ? 0 : -25
|
||||||
property int weight: filled ? 500 : 400
|
property int weight: filled ? 500 : 400
|
||||||
|
|
||||||
|
signal rotationCompleted()
|
||||||
|
|
||||||
font.family: "Material Symbols Rounded"
|
font.family: "Material Symbols Rounded"
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
font.weight: weight
|
font.weight: weight
|
||||||
@@ -40,4 +42,15 @@ StyledText {
|
|||||||
easing.type: Theme.standardEasing
|
easing.type: Theme.standardEasing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: rotationTimer
|
||||||
|
interval: 16
|
||||||
|
repeat: false
|
||||||
|
onTriggered: icon.rotationCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
onRotationChanged: {
|
||||||
|
rotationTimer.restart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,8 +244,8 @@ Rectangle {
|
|||||||
width: 36
|
width: 36
|
||||||
height: 36
|
height: 36
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: iconMouseArea.containsMouse ? Theme.primaryHover : "transparent"
|
color: iconMouseArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.primaryHover, 0)
|
||||||
border.color: root.currentIcon === modelData ? Theme.primary : "transparent"
|
border.color: root.currentIcon === modelData ? Theme.primary : Theme.withAlpha(Theme.primary, 0)
|
||||||
border.width: 2
|
border.width: 2
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ PanelWindow {
|
|||||||
property real triggerX: 0
|
property real triggerX: 0
|
||||||
property real triggerY: 0
|
property real triggerY: 0
|
||||||
property real triggerWidth: 40
|
property real triggerWidth: 40
|
||||||
|
property string triggerSection: ""
|
||||||
property string positioning: "center"
|
property string positioning: "center"
|
||||||
property int animationDuration: Theme.mediumDuration
|
property int animationDuration: Theme.mediumDuration
|
||||||
property var animationEasing: Theme.emphasizedEasing
|
property var animationEasing: Theme.emphasizedEasing
|
||||||
@@ -89,25 +90,29 @@ PanelWindow {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: contentContainer
|
id: contentContainer
|
||||||
|
layer.enabled: true
|
||||||
|
|
||||||
readonly property real screenWidth: root.screen ? root.screen.width : 1920
|
readonly property real screenWidth: root.screen ? root.screen.width : 1920
|
||||||
readonly property real screenHeight: root.screen ? root.screen.height : 1080
|
readonly property real screenHeight: root.screen ? root.screen.height : 1080
|
||||||
|
readonly property real gothOffset: SettingsData.dankBarGothCornersEnabled ? Theme.cornerRadius : 0
|
||||||
readonly property real calculatedX: {
|
readonly property real calculatedX: {
|
||||||
if (positioning === "center") {
|
if (SettingsData.dankBarPosition === SettingsData.Position.Left) {
|
||||||
var centerX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
|
return triggerY
|
||||||
return Math.max(Theme.spacingM, Math.min(screenWidth - popupWidth - Theme.spacingM, centerX))
|
} else if (SettingsData.dankBarPosition === SettingsData.Position.Right) {
|
||||||
} else if (positioning === "left") {
|
return screenWidth - triggerY - popupWidth
|
||||||
return Math.max(Theme.spacingM, triggerX)
|
} else {
|
||||||
} else if (positioning === "right") {
|
const centerX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
|
||||||
return Math.min(screenWidth - popupWidth - Theme.spacingM, triggerX + triggerWidth - popupWidth)
|
return Math.max(Theme.popupDistance, Math.min(screenWidth - popupWidth - Theme.popupDistance, centerX))
|
||||||
}
|
}
|
||||||
return triggerX
|
|
||||||
}
|
}
|
||||||
readonly property real calculatedY: {
|
readonly property real calculatedY: {
|
||||||
if (SettingsData.dankBarAtBottom) {
|
if (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right) {
|
||||||
return Math.max(Theme.spacingM, Math.min(screenHeight - popupHeight - Theme.spacingM, screenHeight - triggerY - popupHeight - SettingsData.dankBarSpacing - 10))
|
const centerY = triggerX + (triggerWidth / 2) - (popupHeight / 2)
|
||||||
|
return Math.max(Theme.popupDistance, Math.min(screenHeight - popupHeight - Theme.popupDistance, centerY))
|
||||||
|
} else if (SettingsData.dankBarPosition === SettingsData.Position.Bottom) {
|
||||||
|
return Math.max(Theme.popupDistance, Math.min(screenHeight - popupHeight - Theme.popupDistance, screenHeight - triggerY - popupHeight + Theme.popupDistance))
|
||||||
} else {
|
} else {
|
||||||
return Math.max(0, Math.min(screenHeight - popupHeight - Theme.spacingM, triggerY + SettingsData.dankBarSpacing + 10))
|
return Math.max(Theme.popupDistance, Math.min(screenHeight - popupHeight - Theme.popupDistance, triggerY + Theme.popupDistance))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ PanelWindow {
|
|||||||
|
|
||||||
StyledRect {
|
StyledRect {
|
||||||
id: contentRect
|
id: contentRect
|
||||||
|
layer.enabled: true
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ Item {
|
|||||||
|
|
||||||
property color thumbOutlineColor: Theme.surfaceContainer
|
property color thumbOutlineColor: Theme.surfaceContainer
|
||||||
property color trackColor: enabled ? Theme.outline : Theme.outline
|
property color trackColor: enabled ? Theme.outline : Theme.outline
|
||||||
function withAlpha(c, a) { return Qt.rgba(c.r, c.g, c.b, a) }
|
|
||||||
|
|
||||||
signal sliderValueChanged(int newValue)
|
signal sliderValueChanged(int newValue)
|
||||||
signal sliderDragFinished(int finalValue)
|
signal sliderDragFinished(int finalValue)
|
||||||
@@ -73,7 +72,7 @@ Item {
|
|||||||
const center = (travel * ratio) + sliderHandle.width / 2
|
const center = (travel * ratio) + sliderHandle.width / 2
|
||||||
return Math.max(0, Math.min(sliderTrack.width, center))
|
return Math.max(0, Math.min(sliderTrack.width, center))
|
||||||
}
|
}
|
||||||
color: slider.enabled ? Theme.primary : withAlpha(Theme.onSurface, 0.12)
|
color: slider.enabled ? Theme.primary : Theme.withAlpha(Theme.onSurface, 0.12)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +90,7 @@ Item {
|
|||||||
return Math.max(0, Math.min(travel, travel * ratio))
|
return Math.max(0, Math.min(travel, travel * ratio))
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
color: slider.enabled ? Theme.primary : withAlpha(Theme.onSurface, 0.12)
|
color: slider.enabled ? Theme.primary : Theme.withAlpha(Theme.onSurface, 0.12)
|
||||||
border.width: 3
|
border.width: 3
|
||||||
border.color: slider.thumbOutlineColor
|
border.color: slider.thumbOutlineColor
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Item {
|
|||||||
|
|
||||||
signal clicked
|
signal clicked
|
||||||
signal toggled(bool checked)
|
signal toggled(bool checked)
|
||||||
|
signal toggleCompleted(bool checked)
|
||||||
|
|
||||||
readonly property bool showText: text && !hideText
|
readonly property bool showText: text && !hideText
|
||||||
|
|
||||||
@@ -113,10 +114,17 @@ Item {
|
|||||||
x: (checked && enabled) ? toggleTrack.edgeRight : toggleTrack.edgeLeft
|
x: (checked && enabled) ? toggleTrack.edgeRight : toggleTrack.edgeLeft
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation {
|
SequentialAnimation {
|
||||||
duration: Appearance.anim.durations.normal
|
NumberAnimation {
|
||||||
easing.type: Easing.BezierSpline
|
duration: Appearance.anim.durations.normal
|
||||||
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
||||||
|
}
|
||||||
|
ScriptAction {
|
||||||
|
script: {
|
||||||
|
toggle.toggleCompleted(toggle.checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,21 +6,30 @@ import qs.Common
|
|||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string tooltipText: ""
|
property string text: ""
|
||||||
property real targetX: 0
|
property real targetX: 0
|
||||||
property real targetY: 0
|
property real targetY: 0
|
||||||
property var targetScreen: null
|
property var targetScreen: null
|
||||||
|
property bool alignLeft: false
|
||||||
|
property bool alignRight: false
|
||||||
|
|
||||||
function showTooltip(text, x, y, screen) {
|
function show(text, x, y, screen, leftAlign, rightAlign) {
|
||||||
tooltipText = text;
|
root.text = text;
|
||||||
targetScreen = screen;
|
if (screen) {
|
||||||
const screenX = screen ? screen.x : 0;
|
targetScreen = screen;
|
||||||
targetX = x - screenX;
|
const screenX = screen.x || 0;
|
||||||
|
targetX = x - screenX;
|
||||||
|
} else {
|
||||||
|
targetScreen = null;
|
||||||
|
targetX = x;
|
||||||
|
}
|
||||||
targetY = y;
|
targetY = y;
|
||||||
|
alignLeft = leftAlign ?? false;
|
||||||
|
alignRight = rightAlign ?? false;
|
||||||
visible = true;
|
visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideTooltip() {
|
function hide() {
|
||||||
visible = false;
|
visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,8 +47,15 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
margins {
|
margins {
|
||||||
left: Math.round(targetX - implicitWidth / 2)
|
left: {
|
||||||
top: Math.round(targetY)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -53,15 +69,13 @@ PanelWindow {
|
|||||||
id: textContent
|
id: textContent
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.tooltipText
|
text: root.text
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
wrapMode: Text.NoWrap
|
wrapMode: Text.NoWrap
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
width: parent.width - Theme.spacingM * 2
|
width: Math.min(implicitWidth, 300 - Theme.spacingM * 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,14 +11,6 @@ Rectangle {
|
|||||||
"easing.bezierCurve": Appearance.anim.curves.standard
|
"easing.bezierCurve": Appearance.anim.curves.standard
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: standardAnimation.duration
|
|
||||||
easing.type: standardAnimation["easing.type"]
|
|
||||||
easing.bezierCurve: standardAnimation["easing.bezierCurve"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on radius {
|
Behavior on radius {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: standardAnimation.duration
|
duration: standardAnimation.duration
|
||||||
|
|||||||
@@ -33,14 +33,6 @@ Text {
|
|||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: standardAnimation.duration
|
|
||||||
easing.type: standardAnimation["easing.type"]
|
|
||||||
easing.bezierCurve: standardAnimation["easing.bezierCurve"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: standardAnimation.duration
|
duration: standardAnimation.duration
|
||||||
|
|||||||
12
shell.qml
12
shell.qml
@@ -25,6 +25,7 @@ import qs.Modules.OSD
|
|||||||
import qs.Modules.ProcessList
|
import qs.Modules.ProcessList
|
||||||
import qs.Modules.Settings
|
import qs.Modules.Settings
|
||||||
import qs.Modules.DankBar
|
import qs.Modules.DankBar
|
||||||
|
import qs.Modules.DankBar.Popouts
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
@@ -48,21 +49,19 @@ ShellRoot {
|
|||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: dankBarLoader
|
id: dankBarLoader
|
||||||
active: true
|
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
|
||||||
property var currentPosition: SettingsData.dankBarAtBottom
|
property var currentPosition: SettingsData.dankBarPosition
|
||||||
|
|
||||||
sourceComponent: DankBar {
|
sourceComponent: DankBar {
|
||||||
onColorPickerRequested: colorPickerModal.show()
|
onColorPickerRequested: colorPickerModal.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentPositionChanged: {
|
onCurrentPositionChanged: {
|
||||||
console.log("DEBUG: DankBar position changed to:", currentPosition, "- recreating bar")
|
const component = sourceComponent
|
||||||
const comp = sourceComponent
|
|
||||||
sourceComponent = null
|
sourceComponent = null
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
sourceComponent = comp
|
sourceComponent = component
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,8 +139,11 @@ ShellRoot {
|
|||||||
|
|
||||||
active: false
|
active: false
|
||||||
|
|
||||||
|
property var modalRef: colorPickerModal
|
||||||
|
|
||||||
ControlCenterPopout {
|
ControlCenterPopout {
|
||||||
id: controlCenterPopout
|
id: controlCenterPopout
|
||||||
|
colorPickerModal: controlCenterLoader.modalRef
|
||||||
|
|
||||||
onPowerActionRequested: (action, title, message) => {
|
onPowerActionRequested: (action, title, message) => {
|
||||||
powerConfirmModalLoader.active = true
|
powerConfirmModalLoader.active = true
|
||||||
|
|||||||
Reference in New Issue
Block a user