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 property bool dashboardShortcutActive property point dragStart required property Drawing drawing required property EdgeGeometry geometry property bool osdShortcutActive required property Panels panels required property Wrapper popouts required property ShellScreen screen required property ScreenState screenState property bool setInitialPoint: false property bool singleGestureTriggered: false property bool utilitiesShortcutActive 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; } acceptedButtons: bar.fullscreen ? Qt.NoButton : Qt.AllButtons anchors.fill: parent hoverEnabled: true 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 entryAt = bar.entryAt(geometry.axisPos(x, y)); const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboardWrapper, x, y) && (!entryAt || entryAt === "activeWindow"); 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 && !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)); } 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(); } } } 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 } }