185 lines
6 KiB
QML
185 lines
6 KiB
QML
import QtQuick
|
|
import QtQuick.Effects
|
|
import QtQuick.Layouts
|
|
import QtQuick.Controls
|
|
import Quickshell
|
|
import Quickshell.Services.SystemTray
|
|
import Quickshell.Widgets
|
|
import qs.Commons
|
|
import qs.Modules.Bar.Extras
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
property ShellScreen screen
|
|
property real scaling: 1.0
|
|
|
|
readonly property string barPosition: Settings.data.bar.position
|
|
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
|
readonly property bool compact: (Settings.data.bar.density === "compact")
|
|
readonly property real itemSize: isVertical ? width * 0.75 : height * 0.85
|
|
|
|
function onLoaded() {
|
|
// When the widget is fully initialized with its props set the screen for the trayMenu
|
|
if (trayMenu.item) {
|
|
trayMenu.item.screen = screen
|
|
}
|
|
}
|
|
|
|
visible: SystemTray.items.values.length > 0
|
|
implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : (trayFlow.implicitWidth + Style.marginS * scaling * 2)
|
|
implicitHeight: isVertical ? (trayFlow.implicitHeight + Style.marginS * scaling * 2) : Math.round(Style.capsuleHeight * scaling)
|
|
radius: Math.round(Style.radiusM * scaling)
|
|
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
|
|
|
|
Layout.alignment: Qt.AlignVCenter
|
|
|
|
Flow {
|
|
id: trayFlow
|
|
anchors.centerIn: parent
|
|
spacing: Style.marginS * scaling
|
|
flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
|
|
|
Repeater {
|
|
id: repeater
|
|
model: SystemTray.items
|
|
|
|
delegate: Item {
|
|
width: itemSize
|
|
height: itemSize
|
|
visible: modelData
|
|
|
|
IconImage {
|
|
id: trayIcon
|
|
anchors.centerIn: parent
|
|
width: Style.marginL * scaling
|
|
height: Style.marginL * scaling
|
|
smooth: false
|
|
asynchronous: true
|
|
backer.fillMode: Image.PreserveAspectFit
|
|
source: {
|
|
let icon = modelData?.icon || ""
|
|
if (!icon) {
|
|
return ""
|
|
}
|
|
|
|
// Process icon path
|
|
if (icon.includes("?path=")) {
|
|
// Seems qmlfmt does not support the following ES6 syntax: const[name, path] = icon.split
|
|
const chunks = icon.split("?path=")
|
|
const name = chunks[0]
|
|
const path = chunks[1]
|
|
const fileName = name.substring(name.lastIndexOf("/") + 1)
|
|
return `file://${path}/${fileName}`
|
|
}
|
|
return icon
|
|
}
|
|
opacity: status === Image.Ready ? 1 : 0
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
|
onClicked: mouse => {
|
|
if (!modelData) {
|
|
return
|
|
}
|
|
|
|
if (mouse.button === Qt.LeftButton) {
|
|
// Close any open menu first
|
|
trayPanel.close()
|
|
|
|
if (!modelData.onlyMenu) {
|
|
modelData.activate()
|
|
}
|
|
} else if (mouse.button === Qt.MiddleButton) {
|
|
// Close any open menu first
|
|
trayPanel.close()
|
|
|
|
modelData.secondaryActivate && modelData.secondaryActivate()
|
|
} else if (mouse.button === Qt.RightButton) {
|
|
trayTooltip.hide()
|
|
|
|
// Close the menu if it was visible
|
|
if (trayPanel && trayPanel.visible) {
|
|
trayPanel.close()
|
|
return
|
|
}
|
|
|
|
if (modelData.hasMenu && modelData.menu && trayMenu.item) {
|
|
trayPanel.open()
|
|
|
|
// Position menu based on bar position
|
|
let menuX, menuY
|
|
if (barPosition === "left") {
|
|
// For left bar: position menu to the right of the bar
|
|
menuX = width + Style.marginM * scaling
|
|
menuY = 0
|
|
} else if (barPosition === "right") {
|
|
// For right bar: position menu to the left of the bar
|
|
menuX = -trayMenu.item.width - Style.marginM * scaling
|
|
menuY = 0
|
|
} else {
|
|
// For horizontal bars: center horizontally and position below
|
|
menuX = (width / 2) - (trayMenu.item.width / 2)
|
|
menuY = Math.round(Style.barHeight * scaling)
|
|
}
|
|
trayMenu.item.menu = modelData.menu
|
|
trayMenu.item.showAt(parent, menuX, menuY)
|
|
} else {
|
|
Logger.log("Tray", "No menu available for", modelData.id, "or trayMenu not set")
|
|
}
|
|
}
|
|
}
|
|
onEntered: trayTooltip.show()
|
|
onExited: trayTooltip.hide()
|
|
}
|
|
|
|
NTooltip {
|
|
id: trayTooltip
|
|
target: trayIcon
|
|
text: modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item"
|
|
positionAbove: Settings.data.bar.position === "bottom"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PanelWindow {
|
|
id: trayPanel
|
|
anchors.top: true
|
|
anchors.left: true
|
|
anchors.right: true
|
|
anchors.bottom: true
|
|
visible: false
|
|
color: Color.transparent
|
|
screen: screen
|
|
|
|
function open() {
|
|
visible = true
|
|
PanelService.willOpenPanel(trayPanel)
|
|
}
|
|
|
|
function close() {
|
|
visible = false
|
|
if (trayMenu.item) {
|
|
trayMenu.item.hideMenu()
|
|
}
|
|
}
|
|
|
|
// Clicking outside of the rectangle to close
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: trayPanel.close()
|
|
}
|
|
|
|
Loader {
|
|
id: trayMenu
|
|
source: "../Extras/TrayMenu.qml"
|
|
}
|
|
}
|
|
}
|