import Quickshell import QtQuick import qs.Components import ZShell.Config import qs.Helpers import qs.Modules.Bar.Popouts Item { id: root required property Item bar required property real borderThickness property bool dashboardShortcutActive required property Drawing drawing required property EdgeGeometry geometry property bool osdShortcutActive required property Panels panels required property Wrapper popouts required property ShellScreen screen property bool singleGestureTriggered: false property bool utilitiesShortcutActive required property PersistentProperties visibilities function inBottomPanel(panel: Item, x: real, y: real): bool { const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); return y > root.height - (panelHeight + geometry.insetBottom(borderThickness)) && withinPanelWidth(panel, x, y); } function inLeftPanel(panel: Item, x: real, y: real): bool { return x < panel.x + panel.width + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y); } function inPopoutArea(x: real, y: real): bool { const panel = panels.popoutsWrapper; if (!geometry.horizontal) return inLeftPanel(panel, x, y); return withinPanelWidth(panel, x, y) && withinPanelHeight(panel, x, y); } function inRightPanel(panel: Item, x: real, y: real): bool { return x > panel.x + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y); } function inTopPanel(panel: Item, x: real, y: real): bool { const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); return y < geometry.insetTop(borderThickness) + panelHeight && withinPanelWidth(panel, x, y); } function withinPanelHeight(panel: Item, x: real, y: real): bool { const panelY = panel.y + geometry.insetTop(borderThickness); return y >= panelY && y <= panelY + panel.height; } function withinPanelWidth(panel: Item, x: real, y: real): bool { const panelX = panel.x + geometry.insetLeft(borderThickness); return x >= panelX && x <= panelX + panel.width; } anchors.fill: parent DragHandler { id: singleHandler cursorShape: (active && centroid.pressPosition.y < root.bar.implicitHeight) ? Qt.ClosedHandCursor : undefined dragThreshold: 0 enabled: !root.visibilities.isDrawing grabPermissions: PointerHandler.CanTakeOverFromHandlersOfSameType | PointerHandler.ApprovesTakeOverByAnything maximumPointCount: 1 minimumPointCount: 1 target: null onActiveChanged: { if (!active) root.singleGestureTriggered = false; } onCentroidChanged: { const x = centroid.position.x; const y = centroid.position.y; const dragX = x - centroid.pressPosition.x; const dragY = y - centroid.pressPosition.y; if (centroid.pressPosition.y >= root.screen.height - Config.bar.border && centroid.pressPosition.x > root.screen.width / 5 && dragY < -Config.launcher.dragThreshold) root.visibilities.launcher = true; if (root.singleGestureTriggered) return; if (root.geometry.insetTop(root.borderThickness) > centroid.pressPosition.y) { if (dragY > 20) { root.visibilities.settings = true; root.singleGestureTriggered = true; } else if (dragY < -20) { root.visibilities.settings = false; root.singleGestureTriggered = true; } } if (centroid.pressPosition.y > root.screen.height - root.geometry.insetBottom(root.borderThickness) && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50) root.visibilities.clipboard = true; if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.geometry.insetTop(root.borderThickness) && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher) if (dragY < -10) { root.visibilities.dock = true; root.singleGestureTriggered = true; } if (centroid.pressPosition.x > root.screen.width - Config.bar.border && centroid.pressPosition.y < (root.screen.height / 2) && dragX < -Config.sidebar.dragThreshold) { root.visibilities.sidebar = true; root.singleGestureTriggered = true; } if (centroid.pressPosition.x >= root.screen.width - Config.bar.border && centroid.pressPosition.y > (root.screen.height / 2) && dragX < -20) { Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`); root.singleGestureTriggered = true; } if (centroid.pressPosition.x <= Config.bar.border && dragX > 20) { Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`); root.singleGestureTriggered = true; } } } PointHandler { id: drawingHandler property bool setInitialPoint: false acceptedButtons: Qt.LeftButton | Qt.RightButton enabled: root.visibilities.isDrawing && (!root.inLeftPanel(root.panels.drawing, hoverHandler.point.position.x, hoverHandler.point.position.y) || !root.panels.drawing.expanded) onActiveChanged: { if (!active) { setInitialPoint = false; root.drawing.content.endStroke(); } else { root.panels.drawing.collapse(); } } onPointChanged: { if (!active) return; const x = point.position.x; const y = point.position.y; const origX = point.pressPosition.x; const origY = point.pressPosition.y; if (point.pressedButtons & Qt.RightButton) { root.drawing.content.clear(); return; } if (x === 0 && y === 0 && origX === 0 && origY === 0) return; if (!setInitialPoint) { setInitialPoint = true; root.drawing.content.beginStroke(origX, origY); return; } root.drawing.content.appendPoint(x, y); } } Timer { id: unhideTimer interval: Config.bar.revealDelay repeat: false running: false onTriggered: { if (hoverHandler.hovered) root.bar.isHovered = true; } } HoverHandler { id: hoverHandler cursorShape: root.visibilities.isDrawing && !root.inLeftPanel(root.panels.drawing, point.position.x, point.position.y) ? Qt.BlankCursor : undefined onHoveredChanged: { if (!hovered) { if (!root.osdShortcutActive) { root.visibilities.osd = false; root.panels.osd.hovered = false; } if (!root.popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover) { root.popouts.hasCurrent = false; } if (Config.bar.autoHide || root.bar.fullscreen) root.bar.isHovered = false; } } onPointChanged: { const x = point.position.x; const y = point.position.y; if (root.visibilities.isDrawing) { if (root.inLeftPanel(root.panels.drawing, x, y) && !(drawingHandler.point.pressedButtons & Qt.LeftButton)) { root.panels.drawing.expand(); root.drawing.content.hideHover(); return; } root.drawing.content.showHover(x, y); return; } if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true)) root.bar.isHovered = true; if (root.bar.fullscreen && !root.bar.isHovered) unhideTimer.start(); if (root.panels.sidebar.offsetScale === 1) { const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y); if (showOsd) { root.osdShortcutActive = false; root.panels.osd.hovered = true; } } else { const outOfSidebar = x < root.width - root.panels.sidebar.width * (1 - root.panels.sidebar.offsetScale); const showOsd = outOfSidebar && root.inRightPanel(root.panels.osdWrapper, x, y); if (!root.osdShortcutActive) { root.visibilities.osd = showOsd; root.panels.osd.hovered = showOsd; } else if (showOsd) { root.osdShortcutActive = false; root.panels.osd.hovered = true; } } if (Config.dock.enable && Config.dock.hoverToReveal && !root.visibilities.dock && !root.visibilities.launcher && root.inBottomPanel(root.panels.dock, x, y)) root.visibilities.dock = true; if (root.geometry.barContains(x, y)) root.bar.checkPopout(root.geometry.axisPos(x, y)); } } Connections { function onDashboardChanged() { if (root.visibilities.dashboard) { const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY); if (!inDashboardArea) { root.dashboardShortcutActive = true; } if (root.panels.launcher.x + root.panels.launcher.width > root.panels.dashboardWrapper.x) root.visibilities.launcher = false; root.visibilities.settings = false; root.visibilities.sidebar = false; root.popouts.hasCurrent = false; } else { root.dashboardShortcutActive = false; } } function onIsDrawingChanged() { if (!root.visibilities.isDrawing) root.drawing.clear(); } function onLauncherChanged() { if (!root.visibilities.launcher) { root.dashboardShortcutActive = false; root.osdShortcutActive = false; root.utilitiesShortcutActive = false; const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); if (!inOsdArea) { root.visibilities.osd = false; root.panels.osd.hovered = false; } } if (root.visibilities.launcher) { if (root.panels.dashboardWrapper.x < root.panels.launcher.x + root.panels.launcher.width) { root.visibilities.dashboard = false; } root.visibilities.dock = false; root.visibilities.settings = false; } } function onOsdChanged() { if (root.visibilities.osd) { const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); if (!inOsdArea) { root.osdShortcutActive = true; } } else { root.osdShortcutActive = false; } } function onResourcesChanged() { if (root.visibilities.resources && (root.popouts.currentName.startsWith("audio") || root.popouts.currentName.startsWith("updates"))) { root.popouts.hasCurrent = false; } if (root.visibilities.resources) root.visibilities.settings = false; } function onSettingsChanged() { if (root.visibilities.settings) { root.visibilities.resources = false; root.visibilities.dashboard = false; root.visibilities.sidebar = false; root.panels.popouts.hasCurrent = false; root.visibilities.launcher = false; } } function onSidebarChanged() { if (root.visibilities.sidebar) { root.visibilities.dashboard = false; root.visibilities.settings = false; root.popouts.hasCurrent = false; } } target: root.visibilities } }