import Quickshell import QtQuick import ZShell.Config import ZShell.Internal import qs.Components import qs.Helpers import qs.Modules.Bar.Popouts CustomMouseArea { id: root required property Item bar required property real borderThickness required property ScreenState screenState required property Drawing drawing required property EdgeGeometry geometry required property Panels panels required property Wrapper popouts required property ShellScreen screen property bool dashboardShortcutActive property bool osdShortcutActive property bool singleGestureTriggered: false property bool utilitiesShortcutActive property bool setInitialPoint: false property point dragStart 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 acceptedButtons: bar.fullscreen ? Qt.NoButton : Qt.AllButtons hoverEnabled: true onPressed: event => { dragStart = Qt.point(event.x, event.y); if (screenState.isDrawing) { if (event.button & Qt.RightButton) { drawing.content.clear(); return; } if (!inLeftPanel(panels.drawing, mouseX, mouseY)) drawing.content.beginStroke(event.x, event.y); } } onPressedChanged: { if (!pressed) { if (screenState.isDrawing) { setInitialPoint = false; drawing.content.endStroke(); if (!inLeftPanel(panels.drawing, mouseX, mouseY)) drawing.content.showHover(mouseX, mouseY); } } else { if (screenState.isDrawing) { panels.drawing.collapse(); } } } onContainsMouseChanged: { if (!containsMouse) { if (!osdShortcutActive) { screenState.osd = false; panels.osd.hovered = false; } if (!popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover) { popouts.hasCurrent = false; } if (Config.bar.autoHide || bar.fullscreen) bar.isHovered = false; if (screenState.dashboard && Config.dashboard.showOnHover) screenState.dashboard = false; } } onPositionChanged: event => { const x = event.x; const y = event.y; const dragX = x - dragStart.x; const dragY = y - dragStart.y; if (screenState.isDrawing) { if (pressed) { drawing.content.appendPoint(x, y); } else { if (inLeftPanel(panels.drawing, x, y)) { if (!(pressedButtons & Qt.LeftButton)) { panels.drawing.expand(); drawing.content.hideHover(); Cursor.clearOverride(); } } else { Cursor.setOverride(Qt.BlankCursor); drawing.content.showHover(x, y); } } if (drawing.content.hoverVisible) drawing.content.showHover(x, y); return; } if (root.bar.fullscreen && !root.bar.isHovered) unhideTimer.start(); if (pressed && dragStart.y >= screen.height - Config.bar.border && dragStart.x > screen.width / 5 && dragY < -Config.launcher.dragThreshold) screenState.launcher = true; const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboardWrapper, x, y); if (!dashboardShortcutActive) { screenState.dashboard = showDashboard; } else if (showDashboard) { dashboardShortcutActive = false; } if (pressed && geometry.insetTop(borderThickness) > dragStart.y && withinPanelWidth(panels.dashboardWrapper, x, y)) { if (dragY > Config.dashboard.dragThreshold) screenState.dashboard = true; else if (dragY < -Config.dashboard.dragThreshold) screenState.dashboard = false; } if (pressed && geometry.insetTop(borderThickness) > dragStart.y && (Config.dashboard.showOnHover || !inTopPanel(panels.dashboardWrapper, dragStart.x, dragStart.y))) { if (dragY > 20) { screenState.settings = true; } else if (dragY < -20) { screenState.settings = false; } } if (pressed && dragStart.y > screen.height - geometry.insetBottom(borderThickness) && dragStart.x < screen.width / 5 && dragY < -50) screenState.clipboard = true; if (pressed && !Config.dock.hoverToReveal && dragStart.y > screen.height - geometry.insetTop(borderThickness) && dragStart.x > screen.width / 5 && !screenState.launcher) if (dragY < -10) screenState.dock = true; if (pressed && dragStart.x > screen.width - Config.bar.border && dragStart.y < (screen.height / 2) && dragX < -Config.sidebar.dragThreshold) screenState.sidebar = true; if (pressed && dragStart.x >= screen.width - Config.bar.border && dragStart.y > (screen.height / 2) && dragX < -20) Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`); if (pressed && dragStart.x <= Config.bar.border && dragX > 20) Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`); if (!screenState.bar && Config.bar.autoHide && geometry.barContains(x, y, true)) bar.isHovered = true; if (panels.sidebar.offsetScale === 1) { const showOsd = inRightPanel(panels.osdWrapper, x, y); if (showOsd) { osdShortcutActive = false; panels.osd.hovered = true; } } else { const outOfSidebar = x < width - panels.sidebar.width * (1 - panels.sidebar.offsetScale); const showOsd = outOfSidebar && inRightPanel(panels.osdWrapper, x, y); if (!osdShortcutActive) { screenState.osd = showOsd; panels.osd.hovered = showOsd; } else if (showOsd) { osdShortcutActive = false; panels.osd.hovered = true; } } if (Config.dock.enable && Config.dock.hoverToReveal && !screenState.dock && !screenState.launcher && inBottomPanel(panels.dock, x, y)) screenState.dock = true; if (geometry.barContains(x, y)) bar.checkPopout(geometry.axisPos(x, y)); } Timer { id: unhideTimer interval: Config.bar.revealDelay repeat: false running: false onTriggered: { if (root.containsMouse) root.bar.isHovered = true; } } Connections { function onDashboardChanged(): void { if (root.screenState.dashboard) { const inDashboardArea = root.inTopPanel(root.panels.dashboardWrapper, root.mouseX, root.mouseY); if (!inDashboardArea) { root.dashboardShortcutActive = true; } root.screenState.launcher = false; root.screenState.settings = false; root.screenState.sidebar = false; root.screenState.resources = false; root.popouts.hasCurrent = false; } else { root.dashboardShortcutActive = false; } } function onIsDrawingChanged(): void { if (root.screenState.isDrawing) { Cursor.setOverride(Qt.BlankCursor); } else { Cursor.clearOverride(); } } function onLauncherChanged(): void { if (!root.screenState.launcher) { root.dashboardShortcutActive = false; root.osdShortcutActive = false; root.utilitiesShortcutActive = false; const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); if (!inOsdArea) { root.screenState.osd = false; root.panels.osd.hovered = false; } } if (root.screenState.launcher) { root.screenState.dashboard = false; root.screenState.dock = false; root.screenState.settings = false; } } function onOsdChanged(): void { if (root.screenState.osd) { const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); if (!inOsdArea) { root.osdShortcutActive = true; } } else { root.osdShortcutActive = false; } } function onResourcesChanged(): void { if (root.screenState.resources) { if (root.popouts.currentName.startsWith("audio") || root.popouts.currentName.startsWith("updates")) root.popouts.hasCurrent = false; root.screenState.settings = false; root.screenState.dashboard = false; } } function onSettingsChanged(): void { if (root.screenState.settings) { root.screenState.resources = false; root.screenState.dashboard = false; root.screenState.sidebar = false; root.panels.popouts.hasCurrent = false; root.screenState.launcher = false; } } function onSidebarChanged(): void { if (root.screenState.sidebar) { if (root.panels.dashboardWrapper.x + root.panels.dashboardWrapper.width > root.panels.sidebar.x) root.screenState.dashboard = false; root.screenState.settings = false; root.popouts.hasCurrent = false; } } target: root.screenState } }