From 3b587f3e15173c24a0cc3346f83136a946561662 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Thu, 21 Mar 2024 06:13:20 -0700 Subject: [PATCH] Start on new bar --- flake.lock | 8 +- modules/user/modules/quickshell/shell/Bar.qml | 62 +++++++++++++ .../quickshell/shell/BarWidgetInner.qml | 8 ++ .../modules/quickshell/shell/ClockWidget.qml | 40 +++++++++ .../quickshell/shell/OverlayWidget.qml | 87 +++++++++++++++++++ .../modules/quickshell/shell/PopupSurface.qml | 74 ++++++++++++++++ .../quickshell/shell/SelectionLayer.qml | 1 + .../modules/quickshell/shell/ShellGlobals.qml | 31 +++++++ .../user/modules/quickshell/shell/shell.qml | 4 + 9 files changed, 311 insertions(+), 4 deletions(-) create mode 100644 modules/user/modules/quickshell/shell/Bar.qml create mode 100644 modules/user/modules/quickshell/shell/BarWidgetInner.qml create mode 100644 modules/user/modules/quickshell/shell/ClockWidget.qml create mode 100644 modules/user/modules/quickshell/shell/OverlayWidget.qml create mode 100644 modules/user/modules/quickshell/shell/PopupSurface.qml create mode 100644 modules/user/modules/quickshell/shell/ShellGlobals.qml diff --git a/flake.lock b/flake.lock index 7b2150f..24b579a 100644 --- a/flake.lock +++ b/flake.lock @@ -400,11 +400,11 @@ ] }, "locked": { - "lastModified": 1710923850, - "narHash": "sha256-RcUYOBX/tv8kYzdkCJi/SrWd7kyca6HVEHEXz/dL2xk=", + "lastModified": 1711024375, + "narHash": "sha256-l10c8cvYlZepcMApXQbOu2f8IaFd47cOgWTGs3Eb+b4=", "ref": "refs/heads/master", - "rev": "31264ac7d14d323eaff627d13b2d11501c3ee8a7", - "revCount": 123, + "rev": "4eb5dc559342677d2e45a98c4e4db9c1c85c6757", + "revCount": 127, "type": "git", "url": "https://git.outfoxxed.me/outfoxxed/quickshell" }, diff --git a/modules/user/modules/quickshell/shell/Bar.qml b/modules/user/modules/quickshell/shell/Bar.qml new file mode 100644 index 0000000..a535243 --- /dev/null +++ b/modules/user/modules/quickshell/shell/Bar.qml @@ -0,0 +1,62 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Wayland + +PanelWindow { + id: root + + PopupSurface { + id: popupSurface + screen: root.screen + bar: barRect + visible: false + } + + onWindowConnected: { + popupSurface.visible = true + } + + anchors { + left: true + top: true + bottom: true + } + + width: 70 + color: "transparent" + WlrLayershell.namespace: "shell:bar" + + Rectangle { + id: barRect + anchors { + fill: parent + margins: 10 + rightMargin: 5 + } + + color: ShellGlobals.colors.bar + radius: 5 + border.color: ShellGlobals.colors.barOutline + border.width: 1 + + Item { + anchors { + fill: parent + margins: 5 + } + + ColumnLayout { + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + ClockWidget { + Layout.fillWidth: true + popupSurface: popupSurface + } + } + } + } +} diff --git a/modules/user/modules/quickshell/shell/BarWidgetInner.qml b/modules/user/modules/quickshell/shell/BarWidgetInner.qml new file mode 100644 index 0000000..bf0fd93 --- /dev/null +++ b/modules/user/modules/quickshell/shell/BarWidgetInner.qml @@ -0,0 +1,8 @@ +import QtQuick + +Rectangle { + color: ShellGlobals.colors.widget + radius: 5 + border.color: ShellGlobals.colors.widgetOutline + border.width: 1 +} diff --git a/modules/user/modules/quickshell/shell/ClockWidget.qml b/modules/user/modules/quickshell/shell/ClockWidget.qml new file mode 100644 index 0000000..527efe0 --- /dev/null +++ b/modules/user/modules/quickshell/shell/ClockWidget.qml @@ -0,0 +1,40 @@ +import QtQuick +import QtQuick.Layouts + +OverlayWidget { + expandedWidth: 100 + expandedHeight: 100 + + BarWidgetInner { + implicitHeight: layout.implicitHeight + + ColumnLayout { + id: layout + spacing: 0 + + anchors { + right: parent.right + left: parent.left + } + + Text { + Layout.alignment: Qt.AlignHCenter + text: ShellGlobals.time.getHours().toString().padStart(2, '0') + font.pointSize: 18 + color: "#a0ffffff" + } + + Text { + Layout.alignment: Qt.AlignHCenter + text: ShellGlobals.time.getMinutes().toString().padStart(2, '0') + font.pointSize: 18 + color: "#a0ffffff" + } + } + + MouseArea { + anchors.fill: parent + onClicked: expanded = !expanded + } + } +} diff --git a/modules/user/modules/quickshell/shell/OverlayWidget.qml b/modules/user/modules/quickshell/shell/OverlayWidget.qml new file mode 100644 index 0000000..580b098 --- /dev/null +++ b/modules/user/modules/quickshell/shell/OverlayWidget.qml @@ -0,0 +1,87 @@ +import QtQuick +import Quickshell + +Item { + required property PopupSurface popupSurface; + required property real expandedWidth; + required property real expandedHeight; + required default property Item widget; + + property bool expanded: false; + + onExpandedChanged: { + animateTo(expanded ? 1.0 : 0.0) + if (expanded) popupSurface.activeOverlay = this + } + + readonly property bool fullyCollapsed: animationProgress == 0.0; + + onFullyCollapsedChanged: { + if (fullyCollapsed && popupSurface.activeOverlay == this) { + popupSurface.activeOverlay = null; + } + } + + readonly property rect collapsedLayerRect: { + //console.log(`schrodinger's coordinate space: ${popupSurface.width} ${popupSurface.height}`); + const w = popupSurface.width; + const h = popupSurface.height; + return this.mapToItem(popupSurface.contentItem, 0, 0, width, height); + } + + readonly property rect expandedLayerRect: popupSurface.expandedPosition(this) + + readonly property rect layerRect: { + return Qt.rect( + ShellGlobals.popoutXCurve.interpolate(animationProgress, collapsedLayerRect.x, expandedLayerRect.x), + ShellGlobals.popoutYCurve.interpolate(animationProgress, collapsedLayerRect.y, expandedLayerRect.y), + ShellGlobals.popoutXCurve.interpolate(animationProgress, collapsedLayerRect.width, expandedLayerRect.width), + ShellGlobals.popoutYCurve.interpolate(animationProgress, collapsedLayerRect.height, expandedLayerRect.height), + ); + } + + implicitWidth: widget.implicitWidth + implicitHeight: widget.implicitHeight + + Component.onCompleted: { + popupSurface.connectOverlay(this) + widget.x = Qt.binding(() => layerRect.x); + widget.y = Qt.binding(() => layerRect.y); + widget.width = Qt.binding(() => layerRect.width); + widget.height = Qt.binding(() => layerRect.height); + } + Component.onDestruction: { + popupSurface.disconnectOverlay(this) + } + + function animateTo(target: real) { + animationProgressInternal = target * 1000 + } + + property real animationProgress: animationProgressInternal * 0.001 + property real animationProgressInternal: 0.0 // animations seem to only have int precision + + Behavior on animationProgressInternal { + SmoothedAnimation { velocity: 3000 } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onPressed: expanded = false + + Rectangle { + anchors.fill: parent + border.color: ShellGlobals.colors.widgetOutline + border.width: 1 + radius: 5 + color: "transparent" + opacity: mouseArea.containsMouse ? 1.0 : 0.0 + + Behavior on opacity { + SmoothedAnimation { velocity: 4 } + } + } + } +} diff --git a/modules/user/modules/quickshell/shell/PopupSurface.qml b/modules/user/modules/quickshell/shell/PopupSurface.qml new file mode 100644 index 0000000..ccb2871 --- /dev/null +++ b/modules/user/modules/quickshell/shell/PopupSurface.qml @@ -0,0 +1,74 @@ +import Quickshell +import Quickshell.Wayland + +WlrLayershell { + id: root + required property var bar; + + property var popup: null; + property list overlays: []; + property variant activeOverlay: null; + property variant lastActiveOverlay: null; + + onActiveOverlayChanged: { + if (lastActiveOverlay != null && lastActiveOverlay != activeOverlay) { + lastActiveOverlay.expanded = false; + } + + lastActiveOverlay = activeOverlay; + } + + readonly property rect barRect: this.contentItem.mapFromItem(bar, 0, 0, bar.width, bar.height) + readonly property real overlayXOffset: barRect.x + barRect.width + 10 + + exclusionMode: ExclusionMode.Ignore + color: "transparent" + namespace: "shell:bar" + + Variants { + id: masks + model: overlays + + Region { + required property var modelData; + item: modelData == undefined ? null : modelData.widget + } + } + + mask: Region { + regions: masks.instances + } + + anchors { + left: true + top: true + bottom: true + } + + width: { + const extents = overlays + .filter(overlay => overlay != undefined && !overlay.fullyCollapsed) + .map(overlay => overlayXOffset + overlay.expandedWidth); + + return Math.max(barRect.x + barRect.width, ...extents); + } + + function connectOverlay(overlay: variant) { + overlay.widget.parent = this.contentItem + overlays.push(overlay); + } + + function disconnectOverlay(overlay: variant) { + const index = overlays.indexOf(overlay); + if (index != -1) overlays.splice(index, 1); + } + + function expandedPosition(overlay: variant): rect { + const rect = overlay.collapsedLayerRect; + + const idealY = rect.y + (rect.height / 2) - (overlay.expandedHeight / 2) + const y = Math.max(barRect.y, Math.min((barRect.y + barRect.height) - overlay.expandedHeight, idealY)); + + return Qt.rect(overlayXOffset, y, overlay.expandedWidth, overlay.expandedHeight); + } +} diff --git a/modules/user/modules/quickshell/shell/SelectionLayer.qml b/modules/user/modules/quickshell/shell/SelectionLayer.qml index 30e0758..a877f51 100644 --- a/modules/user/modules/quickshell/shell/SelectionLayer.qml +++ b/modules/user/modules/quickshell/shell/SelectionLayer.qml @@ -7,6 +7,7 @@ WlrLayershell { color: "transparent" visible: selectionArea.selecting || selectionArea.initializing + exclusionMode: ExclusionMode.Ignore layer: WlrLayer.Overlay namespace: "termspawner" diff --git a/modules/user/modules/quickshell/shell/ShellGlobals.qml b/modules/user/modules/quickshell/shell/ShellGlobals.qml new file mode 100644 index 0000000..135caca --- /dev/null +++ b/modules/user/modules/quickshell/shell/ShellGlobals.qml @@ -0,0 +1,31 @@ +pragma Singleton + +import QtQuick +import Quickshell + +Singleton { + readonly property var colors: QtObject { + readonly property var bar: "#30e0ffff"; + readonly property var barOutline: "#50ffffff"; + readonly property var widget: "#40e0ffff"; + readonly property var widgetOutline: "#60ffffff"; + } + + readonly property var popoutXCurve: EasingCurve { + curve.type: Easing.OutQuint + } + + readonly property var popoutYCurve: EasingCurve { + curve.type: Easing.InQuart + } + + property var time: new Date(); + + Timer { + interval: 1000 + running: true + repeat: true + + onTriggered: time = new Date() + } +} diff --git a/modules/user/modules/quickshell/shell/shell.qml b/modules/user/modules/quickshell/shell/shell.qml index ae1af0a..cd06b93 100644 --- a/modules/user/modules/quickshell/shell/shell.qml +++ b/modules/user/modules/quickshell/shell/shell.qml @@ -12,6 +12,10 @@ ShellRoot { Scope { property var modelData + Bar { + screen: modelData + } + PanelWindow { id: window