diff --git a/shell/bar/Bar.qml b/shell/bar/Bar.qml index bc727d9..31ecb65 100644 --- a/shell/bar/Bar.qml +++ b/shell/bar/Bar.qml @@ -24,8 +24,7 @@ Variants { right: true } - PopupHandler { - id: popupHandler + readonly property Popup popup: Popup { bar: root } @@ -43,6 +42,7 @@ Variants { spacing: 15 Layout.fillWidth: true Layout.fillHeight: true + Layout.alignment: Qt.AlignLeft Workspaces { screen: root.screen @@ -64,40 +64,10 @@ Variants { SysTray { id: sysTray - popup: popupHandler + bar: root Layout.fillHeight: true } - PopupItem { - id: test - Layout.preferredWidth: 20 - Layout.fillHeight: true - - onClicked: { - popupHandler.set(test); - } - - menu: Rectangle { - implicitWidth: 100 - implicitHeight: 100 - } - } - - PopupItem { - id: test2 - Layout.preferredWidth: 20 - Layout.fillHeight: true - - onClicked: { - popupHandler.set(test2); - } - - menu: Rectangle { - implicitWidth: 200 - implicitHeight: 200 - } - } - // VolumeIndicator { // id: volumeIndicator // popup: root.popup diff --git a/shell/bar/PopupHandler.qml b/shell/bar/PopupHandler.qml deleted file mode 100644 index 0f4565e..0000000 --- a/shell/bar/PopupHandler.qml +++ /dev/null @@ -1,151 +0,0 @@ -pragma ComponentBehavior: Bound - -import Quickshell -import Quickshell.Widgets -import Quickshell.Hyprland -import QtQuick -import qs - -PopupWindow { - id: root - visible: false - color: "transparent" - implicitWidth: bar.width - implicitHeight: Math.max(1000, bar.height) - mask: Region { - item: surface - } - - anchor { - window: bar - rect: Qt.rect(0, 0, bar.width, bar.height) - edges: Edges.Bottom | Edges.Left - gravity: Edges.Bottom | Edges.Right - adjustment: PopupAdjustment.None - } - - required property var bar - property var currentMenu - property real padding: 5 - - function set(item) { - - // Clear surface - if (content.children.includes(item.menu)) { - console.log("Clearing popup surface."); - root.currentMenu = undefined; - content.children = []; - // surface.implicitHeight = 0; - surface.opacity = 0; - contentOpacity.restart(); - grab.active = false; - return; - } - - // Set surface - console.log("Setting popup surface."); - root.visible = true; - root.currentMenu = item.menu - content.children = [item.menu]; - // content.implicitWidth = item.menu.implicitWidth; - // content.implicitHeight = item.menu.implicitHeight; - - let itemPos = item.mapToItem(root.bar.contentItem, 0, root.bar.height, item.width, 0).x; - - // Check right edge - let rightEdge = itemPos + surface.implicitWidth; - let maxRightEdge = root.width - padding; - let isTouchingRightEdge = rightEdge > maxRightEdge; - - if (isTouchingRightEdge) { - // touching right edge, reposition - surface.x = maxRightEdge - surface.implicitWidth; - surface.y = padding; - } else { - // not touching right edge - surface.x = itemPos; - surface.y = padding; - } - - surface.opacity = 1; - contentOpacity.restart(); - grab.active = true; - } - - HyprlandFocusGrab { - id: grab - windows: [root, root.bar] - onCleared: { - surface.opacity = 0; - contentOpacity.restart(); - root.currentMenu = undefined; - content.children = []; - } - } - - WrapperRectangle { - id: surface - opacity: 0 - visible: opacity > 0 - color: ShellSettings.colors.surface_translucent - clip: true - margin: 5 - radius: 12 - - border { - width: 1 - color: ShellSettings.colors.active_translucent - } - - // Animating implicit widht/height causes issues, this works but - // is kind of cursed, but fuck it. Better solutions welcome. - width: implicitWidth - height: implicitHeight - - Item { - id: content - implicitWidth: Math.max(root.currentMenu?.width, 60) - implicitHeight: root.currentMenu?.height ?? 0 - - NumberAnimation { - id: contentOpacity - target: content - property: "opacity" - from: 0 - to: 1 - duration: 300 - easing.type: Easing.InOutQuad - } - } - - Behavior on opacity { - NumberAnimation { - duration: 250 - easing.type: Easing.InOutQuad - } - } - - Behavior on width { - enabled: root.visible - SmoothedAnimation { - duration: 250 - easing.type: Easing.InOutQuad - } - } - - Behavior on height { - SmoothedAnimation { - duration: 250 - easing.type: Easing.InOutQuad - } - } - - Behavior on x { - enabled: root.visible - SmoothedAnimation { - duration: 250 - easing.type: Easing.InOutQuad - } - } - } -} diff --git a/shell/bar/PopupItem.qml b/shell/bar/PopupItem.qml index 26b4b6d..84f83bb 100644 --- a/shell/bar/PopupItem.qml +++ b/shell/bar/PopupItem.qml @@ -1,8 +1,70 @@ import QtQuick -import qs.widgets -StyledMouseArea { +Item { id: root + visible: false + opacity: root.targetOpacity - property QtObject menu + onShowChanged: { + if (show) { + popup.setItem(this); + } else { + popup.removeItem(this); + } + } + + onTargetVisibleChanged: { + if (targetVisible) { + visible = true; + targetOpacity = 1; + } else { + console.log("closed"); + closed(); + targetOpacity = 0; + } + } + + onTargetOpacityChanged: { + if (!targetVisible && targetOpacity == 0) { + visible = false; + this.parent = null; + if (popup) + popup.onHidden(this); + } + } + + readonly property alias contentItem: contentItem + default property alias data: contentItem.data + readonly property Item item: contentItem + + Item { + id: contentItem + anchors.fill: parent + // anchors.margins: 5 + + implicitHeight: children[0].implicitHeight + implicitWidth: children[0].implicitWidth + } + + required property var popup + required property var owner + property bool show: false + + signal closed + + property bool targetVisible: false + property real targetOpacity: 0 + + Behavior on targetOpacity { + id: opacityAnimation + SmoothedAnimation { + velocity: 5 + } + } + + function snapOpacity(opacity: real) { + opacityAnimation.enabled = false; + targetOpacity = opacity; + opacityAnimation.enabled = true; + } } diff --git a/shell/bar/systray/SysTray.qml b/shell/bar/systray/SysTray.qml index c6b8818..ccc8359 100644 --- a/shell/bar/systray/SysTray.qml +++ b/shell/bar/systray/SysTray.qml @@ -2,7 +2,10 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets import Quickshell.Services.SystemTray +import "../../widgets" import ".." RowLayout { @@ -10,19 +13,80 @@ RowLayout { spacing: 5 visible: SystemTray.items.values.length > 0 - required property PopupHandler popup + required property var bar Repeater { id: repeater model: SystemTray.items - delegate: TrayMenuLauncher { - id: trayItem - required property SystemTrayItem modelData - trayItem: modelData - popup: root.popup + delegate: StyledMouseArea { + id: button Layout.preferredWidth: parent.height Layout.fillHeight: true + + required property SystemTrayItem modelData + property bool showMenu: false + + onClicked: { + menuOpener.menu = modelData.menu; + showMenu = !showMenu; + } + + IconImage { + id: trayIcon + anchors.fill: parent + source: { + // console.log(trayField.modelData.id); + switch (button.modelData.id) { + case "obs": + return "image://icon/obs-tray"; + default: + return button.modelData.icon; + } + } + } + + QsMenuOpener { + id: menuOpener + } + + property PopupItem menu: PopupItem { + id: menu + owner: button + popup: root.bar.popup + show: button.showMenu + onClosed: button.showMenu = false + + implicitWidth: content.implicitWidth + (2 * 8) + implicitHeight: content.implicitHeight + (2 * 8) + + // TODO: come up with a better way instead of having to do this + property var leftItem: false + property var rightItem: false + + ColumnLayout { + id: content + spacing: 2 + anchors.centerIn: parent + + Repeater { + model: menuOpener.children + + delegate: TrayMenuItem { + id: sysTrayContent + Layout.fillWidth: true + Layout.fillHeight: true + + rootMenu: menu + + onInteracted: { + menuOpener.menu = null; + button.showMenu = false; + } + } + } + } + } } } } diff --git a/shell/bar/systray/TrayMenuLauncher.qml b/shell/bar/systray/TrayMenuLauncher.qml deleted file mode 100644 index 44976cd..0000000 --- a/shell/bar/systray/TrayMenuLauncher.qml +++ /dev/null @@ -1,62 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Widgets -import Quickshell.Services.SystemTray -import ".." - -PopupItem { - id: root - onClicked: { - menuOpener.menu = trayItem.menu; - popup.set(menu); - } - - required property PopupHandler popup - required property SystemTrayItem trayItem - - menu: ColumnLayout { - id: trayMenu - spacing: 2 - // visible: false - - property var leftItem: false - property var rightItem: false - - Repeater { - model: menuOpener.children - - delegate: TrayMenuItem { - id: sysTrayContent - Layout.fillWidth: true - Layout.fillHeight: true - - rootMenu: trayMenu - - onInteracted: { - menuOpener.menu = null; - } - } - } - } - - QsMenuOpener { - id: menuOpener - } - - IconImage { - id: trayIcon - anchors.fill: parent - source: { - // console.log(trayField.modelData.id); - switch (root.trayItem.id) { - case "obs": - return "image://icon/obs-tray"; - default: - return root.trayItem.icon; - } - } - } -}