import QtQuick import Quickshell import "." as M import "../services" as S // Unified base component for all bar modules. // Provides: tooltip on hover, panel state management, OSD flash support. // // On tap: toggles _panelOpen and emits tapped(). Modules that want custom tap // behavior connect onTapped to their action (the toggle still happens). // // Panel modules set panelComponent + panel config properties. BarModule owns the // HoverPanel internally - modules never interact with it directly. // For content resize grace, call keepPanelOpen(ms). Row { id: root property string tooltip: "" property bool _hovered: false property color accentColor: parent?.accentColor ?? S.Theme.base05 property int cursorShape: Qt.PointingHandCursor // Panel state property bool _panelOpen: false property bool _osdActive: false readonly property bool _showPanel: _panelOpen || _osdActive // Panel configuration - set by modules that have applets property Component panelComponent: null property string panelTitle: "" property string panelNamespace: "nova-panel" property real panelContentWidth: 220 property Component titleActionsComponent: null signal tapped function flashPanel() { _osdActive = true; _osdTimer.restart(); } function dismissPanel() { _panelOpen = false; _osdActive = false; _osdTimer.stop(); } function keepPanelOpen(ms) { if (_panelLoader.item) _panelLoader.item.keepOpen(ms); } Timer { id: _osdTimer interval: 1500 onTriggered: if (!root._panelOpen) root._osdActive = false } on_PanelOpenChanged: { if (_panelOpen) M.TooltipState.visible = false; } HoverHandler { cursorShape: root.cursorShape onHoveredChanged: { root._hovered = hovered; if (hovered && root.tooltip !== "" && !root._panelOpen) { M.TooltipState.text = root.tooltip; M.TooltipState.itemX = root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0); M.TooltipState.screen = QsWindow.window?.screen ?? null; M.TooltipState.accentColor = root.accentColor; M.TooltipState.visible = true; } else if (!hovered && root.tooltip !== "") { M.TooltipState.visible = false; } } } TapHandler { onTapped: { root._panelOpen = !root._panelOpen; root.tapped(); } } onTooltipChanged: if (_hovered && tooltip !== "" && !_panelOpen) M.TooltipState.text = tooltip Behavior on opacity { NumberAnimation { duration: 150 } } // HoverPanel - only created when module provides panelComponent LazyLoader { id: _panelLoader active: root.panelComponent !== null M.HoverPanel { showPanel: root._showPanel screen: QsWindow.window?.screen ?? null anchorItem: root accentColor: root.accentColor panelNamespace: root.panelNamespace panelTitle: root.panelTitle contentWidth: root.panelContentWidth titleActionsComponent: root.titleActionsComponent onDismissed: root.dismissPanel() Loader { width: root.panelContentWidth sourceComponent: root.panelComponent } } } }