1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-30 08:22:51 -05:00

systemtray: new tray detail menu

This commit is contained in:
bbedward
2025-11-13 16:30:07 -05:00
parent 1858597fc9
commit d46b7528e7
4 changed files with 382 additions and 228 deletions

View File

@@ -1,10 +1,12 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Effects
import Quickshell import Quickshell
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Services
import qs.Widgets import qs.Widgets
Item { Item {
@@ -45,6 +47,7 @@ Item {
visible: allTrayItems.length > 0 visible: allTrayItems.length > 0
property bool menuOpen: false property bool menuOpen: false
property bool overflowWasOpenBeforeTrayMenu: false
Rectangle { Rectangle {
id: visualBackground id: visualBackground
@@ -157,17 +160,17 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => { onClicked: (mouse) => {
if (!delegateRoot.trayItem) { if (!delegateRoot.trayItem) return
return;
}
if (mouse.button === Qt.LeftButton && !delegateRoot.trayItem.onlyMenu) { if (mouse.button === Qt.LeftButton && !delegateRoot.trayItem.onlyMenu) {
delegateRoot.trayItem.activate(); delegateRoot.trayItem.activate()
return ; return
}
if (delegateRoot.trayItem.hasMenu) {
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
} }
if (!delegateRoot.trayItem.hasMenu) return
root.overflowWasOpenBeforeTrayMenu = root.menuOpen
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
} }
} }
} }
@@ -289,17 +292,17 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => { onClicked: (mouse) => {
if (!delegateRoot.trayItem) { if (!delegateRoot.trayItem) return
return;
}
if (mouse.button === Qt.LeftButton && !delegateRoot.trayItem.onlyMenu) { if (mouse.button === Qt.LeftButton && !delegateRoot.trayItem.onlyMenu) {
delegateRoot.trayItem.activate(); delegateRoot.trayItem.activate()
return ; return
}
if (delegateRoot.trayItem.hasMenu) {
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
} }
if (!delegateRoot.trayItem.hasMenu) return
root.overflowWasOpenBeforeTrayMenu = root.menuOpen
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
} }
} }
} }
@@ -349,7 +352,7 @@ Item {
screen: root.parentScreen screen: root.parentScreen
WlrLayershell.layer: WlrLayershell.Top WlrLayershell.layer: WlrLayershell.Top
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
WlrLayershell.namespace: "dms:tray-overflow-menu" WlrLayershell.namespace: "dms:tray-overflow-menu"
color: "transparent" color: "transparent"
@@ -360,10 +363,26 @@ Item {
bottom: true bottom: true
} }
readonly property real dpr: (typeof CompositorService !== "undefined" && CompositorService.getScreenScale)
? CompositorService.getScreenScale(overflowMenu.screen)
: (screen?.devicePixelRatio || 1)
property point anchorPos: Qt.point(screen.width / 2, screen.height / 2) property point anchorPos: Qt.point(screen.width / 2, screen.height / 2)
onVisibleChanged: { onVisibleChanged: {
if (visible) updatePosition() if (visible) {
updatePosition()
Qt.callLater(() => overflowFocusScope.forceActiveFocus())
}
}
FocusScope {
id: overflowFocusScope
anchors.fill: parent
focus: true
Keys.onEscapePressed: {
root.menuOpen = false
}
} }
function updatePosition() { function updatePosition() {
@@ -395,50 +414,71 @@ Item {
} }
} }
Rectangle { Item {
id: menuContainer id: menuContainer
width: 250
height: Math.min(screen.height - 100, menuColumn.implicitHeight + Theme.spacingS * 2)
x: { readonly property real rawWidth: {
const itemCount = root.allTrayItems.length
const cols = Math.min(5, itemCount)
const itemSize = 28
const spacing = 2
return cols * itemSize + (cols - 1) * spacing + Theme.spacingS * 2
}
readonly property real rawHeight: {
const itemCount = root.allTrayItems.length
const cols = Math.min(5, itemCount)
const rows = Math.ceil(itemCount / cols)
const itemSize = 28
const spacing = 2
return rows * itemSize + (rows - 1) * spacing + Theme.spacingS * 2
}
readonly property real alignedWidth: Theme.px(rawWidth, overflowMenu.dpr)
readonly property real alignedHeight: Theme.px(rawHeight, overflowMenu.dpr)
width: alignedWidth
height: alignedHeight
x: Theme.snap((() => {
if (root.isVertical) { if (root.isVertical) {
const edge = root.axis?.edge const edge = root.axis?.edge
if (edge === "left") { if (edge === "left") {
const targetX = overflowMenu.anchorPos.x const targetX = overflowMenu.anchorPos.x
return Math.min(overflowMenu.screen.width - width - 10, targetX) return Math.min(overflowMenu.screen.width - alignedWidth - 10, targetX)
} else { } else {
const targetX = overflowMenu.anchorPos.x - width const targetX = overflowMenu.anchorPos.x - alignedWidth
return Math.max(10, targetX) return Math.max(10, targetX)
} }
} else { } else {
const left = 10 const left = 10
const right = overflowMenu.width - width - 10 const right = overflowMenu.width - alignedWidth - 10
const want = overflowMenu.anchorPos.x - width / 2 const want = overflowMenu.anchorPos.x - alignedWidth / 2
return Math.max(left, Math.min(right, want)) return Math.max(left, Math.min(right, want))
} }
} })(), overflowMenu.dpr)
y: { y: Theme.snap((() => {
if (root.isVertical) { if (root.isVertical) {
const top = 10 const top = 10
const bottom = overflowMenu.height - height - 10 const bottom = overflowMenu.height - alignedHeight - 10
const want = overflowMenu.anchorPos.y - height / 2 const want = overflowMenu.anchorPos.y - alignedHeight / 2
return Math.max(top, Math.min(bottom, want)) return Math.max(top, Math.min(bottom, want))
} else { } else {
if (root.isAtBottom) { if (root.isAtBottom) {
const targetY = overflowMenu.anchorPos.y - height const targetY = overflowMenu.anchorPos.y - alignedHeight
return Math.max(10, targetY) return Math.max(10, targetY)
} else { } else {
const targetY = overflowMenu.anchorPos.y const targetY = overflowMenu.anchorPos.y
return Math.min(overflowMenu.screen.height - height - 10, targetY) return Math.min(overflowMenu.screen.height - alignedHeight - 10, targetY)
} }
} }
} })(), overflowMenu.dpr)
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) property real shadowBlurPx: 10
radius: Theme.cornerRadius property real shadowSpreadPx: 0
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) property real shadowBaseAlpha: 0.60
border.width: 1 readonly property real popupSurfaceAlpha: Theme.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
opacity: root.menuOpen ? 1 : 0 opacity: root.menuOpen ? 1 : 0
scale: root.menuOpen ? 1 : 0.85 scale: root.menuOpen ? 1 : 0.85
@@ -457,156 +497,122 @@ Item {
} }
} }
Rectangle { Item {
id: bgShadowLayer
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 4 layer.enabled: true
anchors.leftMargin: 2 layer.smooth: true
anchors.rightMargin: -2 layer.textureSize: Qt.size(Math.round(width * overflowMenu.dpr * 2), Math.round(height * overflowMenu.dpr * 2))
anchors.bottomMargin: -4 layer.textureMirroring: ShaderEffectSource.MirrorVertically
radius: parent.radius layer.samples: 4
color: Qt.rgba(0, 0, 0, 0.15)
z: parent.z - 1 layer.effect: MultiEffect {
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, menuContainer.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * menuContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest
return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha)
}
}
Rectangle {
anchors.fill: parent
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
radius: Theme.cornerRadius
antialiasing: true
smooth: true
}
} }
DankFlickable { Grid {
id: scrollView id: menuGrid
anchors.fill: parent anchors.centerIn: parent
anchors.margins: Theme.spacingS columns: Math.min(5, root.allTrayItems.length)
contentWidth: width spacing: 2
contentHeight: menuColumn.implicitHeight rowSpacing: 2
clip: true
Column { Repeater {
id: menuColumn model: root.allTrayItems
width: parent.width
spacing: 2
Repeater { delegate: Rectangle {
model: root.allTrayItems property var trayItem: modelData
property string iconSource: {
delegate: Rectangle { let icon = trayItem?.icon
property var trayItem: modelData if (typeof icon === 'string' || icon instanceof String) {
property string iconSource: { if (icon === "") return ""
let icon = trayItem?.icon if (icon.includes("?path=")) {
if (typeof icon === 'string' || icon instanceof String) { const split = icon.split("?path=")
if (icon === "") return "" if (split.length !== 2) return icon
if (icon.includes("?path=")) { const name = split[0]
const split = icon.split("?path=") const path = split[1]
if (split.length !== 2) return icon let fileName = name.substring(name.lastIndexOf("/") + 1)
const name = split[0] if (fileName.startsWith("dropboxstatus")) {
const path = split[1] fileName = `hicolor/16x16/status/${fileName}`
let fileName = name.substring(name.lastIndexOf("/") + 1)
if (fileName.startsWith("dropboxstatus")) {
fileName = `hicolor/16x16/status/${fileName}`
}
return `file://${path}/${fileName}`
} }
if (icon.startsWith("/") && !icon.startsWith("file://")) { return `file://${path}/${fileName}`
return `file://${icon}`
}
return icon
} }
return "" if (icon.startsWith("/") && !icon.startsWith("file://")) {
return `file://${icon}`
}
return icon
} }
return ""
}
width: menuColumn.width width: 28
height: 32 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: itemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" color: itemArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceContainer, 0)
Row { IconImage {
anchors.left: parent.left id: menuIconImg
anchors.leftMargin: Theme.spacingS anchors.centerIn: parent
anchors.verticalCenter: parent.verticalCenter width: Theme.barIconSize(root.barThickness)
spacing: Theme.spacingS height: Theme.barIconSize(root.barThickness)
source: parent.iconSource
asynchronous: true
smooth: true
mipmap: true
visible: status === Image.Ready
}
IconImage { Text {
id: menuIconImg anchors.centerIn: parent
width: 20 visible: !menuIconImg.visible
height: 20 text: {
anchors.verticalCenter: parent.verticalCenter const itemId = trayItem?.id || ""
source: parent.parent.iconSource if (!itemId) return "?"
asynchronous: true return itemId.charAt(0).toUpperCase()
smooth: true
mipmap: true
visible: status === Image.Ready
}
Text {
anchors.verticalCenter: parent.verticalCenter
visible: !menuIconImg.visible
text: {
const itemId = trayItem?.id || ""
if (!itemId) return "?"
return itemId.charAt(0).toUpperCase()
}
font.pixelSize: 10
color: Theme.surfaceText
}
StyledText {
text: trayItem?.tooltip?.title || trayItem?.id || "Unknown"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
width: Math.min(implicitWidth, menuColumn.width - 80)
}
} }
font.pixelSize: 10
color: Theme.surfaceText
}
Rectangle { MouseArea {
anchors.right: parent.right id: itemArea
anchors.rightMargin: Theme.spacingS anchors.fill: parent
anchors.verticalCenter: parent.verticalCenter hoverEnabled: true
width: 24 acceptedButtons: Qt.LeftButton | Qt.RightButton
height: 24 cursorShape: Qt.PointingHandCursor
radius: Theme.cornerRadius onClicked: (mouse) => {
color: visibilityArea.containsMouse ? Theme.primaryHover : "transparent" if (!trayItem) return
DankIcon { if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
anchors.centerIn: parent trayItem.activate()
name: SessionData.isHiddenTrayId(trayItem?.id || "") ? "visibility_off" : "visibility" root.menuOpen = false
size: 16 return
color: Theme.surfaceText
} }
MouseArea { if (!trayItem.hasMenu) return
id: visibilityArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
const itemId = trayItem?.id || ""
if (!itemId) return
if (SessionData.isHiddenTrayId(itemId)) {
SessionData.showTrayId(itemId)
} else {
SessionData.hideTrayId(itemId)
}
}
}
}
MouseArea { root.overflowWasOpenBeforeTrayMenu = true
id: itemArea root.menuOpen = false
anchors.fill: parent root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
anchors.rightMargin: 32
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (!trayItem) return
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate()
root.menuOpen = false
return
}
if (trayItem.hasMenu) {
root.menuOpen = false
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
}
}
} }
} }
} }
@@ -665,6 +671,20 @@ Item {
function close() { function close() {
showMenu = false showMenu = false
if (root.overflowWasOpenBeforeTrayMenu) {
root.menuOpen = true
Qt.callLater(() => {
if (overflowMenu.visible && overflowFocusScope) {
overflowFocusScope.forceActiveFocus()
}
})
}
root.overflowWasOpenBeforeTrayMenu = false
}
function closeWithAction() {
root.overflowWasOpenBeforeTrayMenu = false
close()
} }
function showSubMenu(entry) { function showSubMenu(entry) {
@@ -697,7 +717,7 @@ Item {
visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false) visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false)
WlrLayershell.layer: WlrLayershell.Top WlrLayershell.layer: WlrLayershell.Top
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
color: "transparent" color: "transparent"
anchors { anchors {
@@ -707,11 +727,29 @@ Item {
bottom: true bottom: true
} }
readonly property real dpr: (typeof CompositorService !== "undefined" && CompositorService.getScreenScale)
? CompositorService.getScreenScale(menuWindow.screen)
: (screen?.devicePixelRatio || 1)
property point anchorPos: Qt.point(screen.width / 2, screen.height / 2) property point anchorPos: Qt.point(screen.width / 2, screen.height / 2)
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
updatePosition() updatePosition()
Qt.callLater(() => menuFocusScope.forceActiveFocus())
}
}
FocusScope {
id: menuFocusScope
anchors.fill: parent
focus: true
Keys.onEscapePressed: {
if (entryStack.count > 0) {
menuRoot.goBack()
} else {
menuRoot.close()
}
} }
} }
@@ -744,64 +782,104 @@ Item {
} }
} }
Rectangle { Item {
id: menuContainer id: menuContainer
width: Math.min(500, Math.max(250, menuColumn.implicitWidth + Theme.spacingS * 2)) readonly property real rawWidth: Math.min(500, Math.max(250, menuColumn.implicitWidth + Theme.spacingS * 2))
height: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2) readonly property real rawHeight: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2)
x: { readonly property real alignedWidth: Theme.px(rawWidth, menuWindow.dpr)
readonly property real alignedHeight: Theme.px(rawHeight, menuWindow.dpr)
width: alignedWidth
height: alignedHeight
x: Theme.snap((() => {
if (menuRoot.isVertical) { if (menuRoot.isVertical) {
const edge = menuRoot.axis?.edge const edge = menuRoot.axis?.edge
if (edge === "left") { if (edge === "left") {
const targetX = menuWindow.anchorPos.x const targetX = menuWindow.anchorPos.x
return Math.min(menuWindow.screen.width - width - 10, targetX) return Math.min(menuWindow.screen.width - alignedWidth - 10, targetX)
} else { } else {
const targetX = menuWindow.anchorPos.x - width const targetX = menuWindow.anchorPos.x - alignedWidth
return Math.max(10, targetX) return Math.max(10, targetX)
} }
} else { } else {
const left = 10 const left = 10
const right = menuWindow.width - width - 10 const right = menuWindow.width - alignedWidth - 10
const want = menuWindow.anchorPos.x - width / 2 const want = menuWindow.anchorPos.x - alignedWidth / 2
return Math.max(left, Math.min(right, want)) return Math.max(left, Math.min(right, want))
} }
} })(), menuWindow.dpr)
y: { y: Theme.snap((() => {
if (menuRoot.isVertical) { if (menuRoot.isVertical) {
const top = 10 const top = 10
const bottom = menuWindow.height - height - 10 const bottom = menuWindow.height - alignedHeight - 10
const want = menuWindow.anchorPos.y - height / 2 const want = menuWindow.anchorPos.y - alignedHeight / 2
return Math.max(top, Math.min(bottom, want)) return Math.max(top, Math.min(bottom, want))
} else { } else {
if (menuRoot.isAtBottom) { if (menuRoot.isAtBottom) {
const targetY = menuWindow.anchorPos.y - height const targetY = menuWindow.anchorPos.y - alignedHeight
return Math.max(10, targetY) return Math.max(10, targetY)
} else { } else {
const targetY = menuWindow.anchorPos.y const targetY = menuWindow.anchorPos.y
return Math.min(menuWindow.screen.height - height - 10, targetY) return Math.min(menuWindow.screen.height - alignedHeight - 10, targetY)
} }
} }
} })(), menuWindow.dpr)
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) property real shadowBlurPx: 10
radius: Theme.cornerRadius property real shadowSpreadPx: 0
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) property real shadowBaseAlpha: 0.60
border.width: 1 readonly property real popupSurfaceAlpha: Theme.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
opacity: menuRoot.showMenu ? 1 : 0 opacity: menuRoot.showMenu ? 1 : 0
scale: menuRoot.showMenu ? 1 : 0.85 scale: menuRoot.showMenu ? 1 : 0.85
Rectangle { Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Item {
id: menuBgShadowLayer
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 4 layer.enabled: true
anchors.leftMargin: 2 layer.smooth: true
anchors.rightMargin: -2 layer.textureSize: Qt.size(Math.round(width * menuWindow.dpr), Math.round(height * menuWindow.dpr))
anchors.bottomMargin: -4 layer.textureMirroring: ShaderEffectSource.MirrorVertically
radius: parent.radius
color: Qt.rgba(0, 0, 0, 0.15) layer.effect: MultiEffect {
z: parent.z - 1 autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, menuContainer.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * menuContainer.shadowSpreadPx) / Math.max(1, Math.min(menuBgShadowLayer.width, menuBgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest
return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha)
}
}
Rectangle {
anchors.fill: parent
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
radius: Theme.cornerRadius
antialiasing: true
}
} }
QsMenuAnchor { QsMenuAnchor {
@@ -832,12 +910,90 @@ Item {
anchors.topMargin: Theme.spacingS anchors.topMargin: Theme.spacingS
spacing: 1 spacing: 1
Rectangle {
visible: entryStack.count === 0
width: parent.width
height: 24
color: "transparent"
StyledText {
anchors.centerIn: parent
text: menuRoot.trayItem?.id || "Unknown"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
elide: Text.ElideMiddle
width: parent.width - Theme.spacingS * 2
horizontalAlignment: Text.AlignHCenter
}
}
Rectangle {
visible: entryStack.count === 0
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
}
Rectangle {
visible: entryStack.count === 0
width: parent.width
height: 28
radius: 0
color: visibilityToggleArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceContainer, 0)
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
DankIcon {
name: SessionData.isHiddenTrayId(menuRoot.trayItem?.id || "") ? "visibility" : "visibility_off"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: SessionData.isHiddenTrayId(menuRoot.trayItem?.id || "") ? "Show in Tray" : "Hide from Tray"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: visibilityToggleArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
const itemId = menuRoot.trayItem?.id || ""
if (!itemId) return
if (SessionData.isHiddenTrayId(itemId)) {
SessionData.showTrayId(itemId)
} else {
SessionData.hideTrayId(itemId)
}
menuRoot.closeWithAction()
}
}
}
Rectangle {
visible: entryStack.count === 0
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
}
Rectangle { Rectangle {
visible: entryStack.count > 0 visible: entryStack.count > 0
width: parent.width width: parent.width
height: 28 height: 28
radius: Theme.cornerRadius radius: 0
color: backArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" color: backArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceContainer, 0)
Row { Row {
anchors.left: parent.left anchors.left: parent.left
@@ -863,6 +1019,7 @@ Item {
MouseArea { MouseArea {
id: backArea id: backArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: menuRoot.goBack() onClicked: menuRoot.goBack()
} }
@@ -886,33 +1043,35 @@ Item {
width: menuColumn.width width: menuColumn.width
height: menuEntry?.isSeparator ? 1 : 28 height: menuEntry?.isSeparator ? 1 : 28
radius: menuEntry?.isSeparator ? 0 : Theme.cornerRadius radius: 0
color: { color: {
if (menuEntry?.isSeparator) { if (menuEntry?.isSeparator) {
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
} }
return itemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" return itemArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceContainer, 0)
} }
MouseArea { MouseArea {
id: itemArea id: itemArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
enabled: !menuEntry?.isSeparator && (menuEntry?.enabled !== false) enabled: !menuEntry?.isSeparator && (menuEntry?.enabled !== false)
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (!menuEntry || menuEntry.isSeparator) return; if (!menuEntry || menuEntry.isSeparator) return
if (menuEntry.hasChildren) { if (menuEntry.hasChildren) {
menuRoot.showSubMenu(menuEntry); menuRoot.showSubMenu(menuEntry)
} else { return
if (typeof menuEntry.activate === "function") {
menuEntry.activate();
} else if (typeof menuEntry.triggered === "function") {
menuEntry.triggered();
}
Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.close() }', menuRoot);
} }
if (typeof menuEntry.activate === "function") {
menuEntry.activate()
} else if (typeof menuEntry.triggered === "function") {
menuEntry.triggered()
}
Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.closeWithAction() }', menuRoot)
} }
} }
@@ -996,20 +1155,6 @@ Item {
} }
} }
} }
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
} }
MouseArea { MouseArea {

View File

@@ -250,7 +250,10 @@ PanelWindow {
property int blurMax: 64 property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / blurMax)) shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: Qt.rgba(0, 0, 0, content.effectiveShadowAlpha) shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest
return Theme.withAlpha(baseColor, content.effectiveShadowAlpha)
}
} }
Shape { Shape {

View File

@@ -143,7 +143,10 @@ PanelWindow {
property int blurMax: 64 property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / blurMax)) shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: Qt.rgba(0, 0, 0, osdContainer.effectiveShadowAlpha) shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest
return Theme.withAlpha(baseColor, osdContainer.effectiveShadowAlpha)
}
} }
DankRectangle { DankRectangle {

View File

@@ -224,7 +224,10 @@ PanelWindow {
property int blurMax: 64 property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / blurMax)) shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: Qt.rgba(0, 0, 0, contentWrapper.effectiveShadowAlpha) shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest
return Theme.withAlpha(baseColor, contentWrapper.effectiveShadowAlpha)
}
} }
DankRectangle { DankRectangle {