summaryrefslogtreecommitdiff
path: root/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml')
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml291
1 files changed, 291 insertions, 0 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml
new file mode 100644
index 0000000..1933035
--- /dev/null
+++ b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml
@@ -0,0 +1,291 @@
+import QtQuick
+import QtQuick.Controls
+import Quickshell
+import Quickshell.Wayland
+import Quickshell.Hyprland
+import qs.Common
+import qs.Services
+
+Scope {
+ id: overviewScope
+
+ property bool overviewOpen: false
+
+ Loader {
+ id: hyprlandLoader
+ active: overviewScope.overviewOpen
+ asynchronous: false
+
+ sourceComponent: Variants {
+ id: overviewVariants
+ model: Quickshell.screens
+
+ PanelWindow {
+ id: root
+ required property var modelData
+ readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
+ property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor?.id)
+
+ screen: modelData
+ visible: overviewScope.overviewOpen
+ color: "transparent"
+
+ WlrLayershell.namespace: "dms:workspace-overview"
+ WlrLayershell.layer: WlrLayer.Overlay
+ WlrLayershell.exclusiveZone: -1
+ WlrLayershell.keyboardFocus: {
+ if (!overviewScope.overviewOpen)
+ return WlrKeyboardFocus.None;
+ if (CompositorService.useHyprlandFocusGrab)
+ return WlrKeyboardFocus.OnDemand;
+ return WlrKeyboardFocus.Exclusive;
+ }
+
+ anchors {
+ top: true
+ left: true
+ right: true
+ bottom: true
+ }
+
+ HyprlandFocusGrab {
+ id: grab
+ windows: [root]
+ active: false
+ property bool hasBeenActivated: false
+ onActiveChanged: {
+ if (active) {
+ hasBeenActivated = true
+ }
+ }
+ onCleared: () => {
+ if (hasBeenActivated && overviewScope.overviewOpen) {
+ overviewScope.overviewOpen = false
+ }
+ }
+ }
+
+ Connections {
+ target: overviewScope
+ function onOverviewOpenChanged() {
+ if (overviewScope.overviewOpen) {
+ grab.hasBeenActivated = false
+ if (CompositorService.useHyprlandFocusGrab)
+ delayedGrabTimer.start()
+ } else {
+ delayedGrabTimer.stop()
+ grab.active = false
+ grab.hasBeenActivated = false
+ }
+ }
+ }
+
+ Connections {
+ target: root
+ function onMonitorIsFocusedChanged() {
+ if (!CompositorService.useHyprlandFocusGrab)
+ return;
+ if (overviewScope.overviewOpen && root.monitorIsFocused && !grab.active) {
+ grab.hasBeenActivated = false
+ grab.active = true
+ } else if (overviewScope.overviewOpen && !root.monitorIsFocused && grab.active) {
+ grab.active = false
+ }
+ }
+ }
+
+ Timer {
+ id: delayedGrabTimer
+ interval: 150
+ repeat: false
+ onTriggered: {
+ if (CompositorService.useHyprlandFocusGrab && overviewScope.overviewOpen && root.monitorIsFocused) {
+ grab.active = true
+ }
+ }
+ }
+
+ Timer {
+ id: closeTimer
+ interval: Theme.expressiveDurations.expressiveDefaultSpatial + 120
+ onTriggered: {
+ root.visible = false
+ }
+ }
+
+ Rectangle {
+ id: background
+ anchors.fill: parent
+ color: "black"
+ opacity: overviewScope.overviewOpen ? 0.5 : 0
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: Theme.expressiveDurations.expressiveDefaultSpatial
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: mouse => {
+ const localPos = mapToItem(contentContainer, mouse.x, mouse.y)
+ if (localPos.x < 0 || localPos.x > contentContainer.width || localPos.y < 0 || localPos.y > contentContainer.height) {
+ overviewScope.overviewOpen = false
+ closeTimer.restart()
+ }
+ }
+ }
+ }
+
+ Item {
+ id: contentContainer
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.topMargin: 100
+ width: childrenRect.width
+ height: childrenRect.height
+
+ opacity: overviewScope.overviewOpen ? 1 : 0
+ transform: [scaleTransform, motionTransform]
+
+ Scale {
+ id: scaleTransform
+ origin.x: contentContainer.width / 2
+ origin.y: contentContainer.height / 2
+ xScale: overviewScope.overviewOpen ? 1 : 0.96
+ yScale: overviewScope.overviewOpen ? 1 : 0.96
+
+ Behavior on xScale {
+ NumberAnimation {
+ duration: Theme.expressiveDurations.expressiveDefaultSpatial
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
+ }
+ }
+
+ Behavior on yScale {
+ NumberAnimation {
+ duration: Theme.expressiveDurations.expressiveDefaultSpatial
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
+ }
+ }
+ }
+
+ Translate {
+ id: motionTransform
+ x: 0
+ y: overviewScope.overviewOpen ? 0 : Theme.spacingL
+
+ Behavior on y {
+ NumberAnimation {
+ duration: Theme.expressiveDurations.expressiveDefaultSpatial
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
+ }
+ }
+ }
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: Theme.expressiveDurations.expressiveDefaultSpatial
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
+ }
+ }
+
+ Loader {
+ id: overviewLoader
+ active: overviewScope.overviewOpen
+ asynchronous: false
+
+ sourceComponent: OverviewWidget {
+ panelWindow: root
+ overviewOpen: overviewScope.overviewOpen
+ }
+ }
+ }
+
+ FocusScope {
+ id: focusScope
+ anchors.fill: parent
+ visible: overviewScope.overviewOpen
+ focus: overviewScope.overviewOpen && root.monitorIsFocused
+
+ Keys.onEscapePressed: event => {
+ if (!root.monitorIsFocused) return
+ overviewScope.overviewOpen = false
+ closeTimer.restart()
+ event.accepted = true
+ }
+
+ Keys.onPressed: event => {
+ if (!root.monitorIsFocused) return
+
+ if (event.key === Qt.Key_Left || event.key === Qt.Key_Right) {
+ if (!overviewLoader.item) return
+
+ const thisMonitorWorkspaceIds = overviewLoader.item.thisMonitorWorkspaceIds
+ if (thisMonitorWorkspaceIds.length === 0) return
+
+ const currentId = root.monitor.activeWorkspace?.id ?? thisMonitorWorkspaceIds[0]
+ const currentIndex = thisMonitorWorkspaceIds.indexOf(currentId)
+
+ let targetIndex
+ if (event.key === Qt.Key_Left) {
+ targetIndex = currentIndex - 1
+ if (targetIndex < 0) targetIndex = thisMonitorWorkspaceIds.length - 1
+ } else {
+ targetIndex = currentIndex + 1
+ if (targetIndex >= thisMonitorWorkspaceIds.length) targetIndex = 0
+ }
+
+ const targetId = thisMonitorWorkspaceIds[targetIndex]
+ Hyprland.dispatch("workspace " + targetId)
+ event.accepted = true
+ }
+ }
+
+ onVisibleChanged: {
+ if (visible && overviewScope.overviewOpen && root.monitorIsFocused) {
+ Qt.callLater(() => focusScope.forceActiveFocus())
+ }
+ }
+
+ Connections {
+ target: root
+ function onMonitorIsFocusedChanged() {
+ if (root.monitorIsFocused && overviewScope.overviewOpen) {
+ Qt.callLater(() => focusScope.forceActiveFocus())
+ }
+ }
+ }
+ }
+
+ onVisibleChanged: {
+ if (visible && overviewScope.overviewOpen) {
+ Qt.callLater(() => focusScope.forceActiveFocus())
+ } else if (!visible) {
+ grab.active = false
+ }
+ }
+
+ Connections {
+ target: overviewScope
+ function onOverviewOpenChanged() {
+ if (overviewScope.overviewOpen) {
+ closeTimer.stop()
+ root.visible = true
+ Qt.callLater(() => focusScope.forceActiveFocus())
+ } else {
+ closeTimer.restart()
+ grab.active = false
+ }
+ }
+ }
+ }
+ }
+ }
+}