diff --git a/modules/Bluetooth.qml b/modules/Bluetooth.qml index 884a708..7e74c1f 100644 --- a/modules/Bluetooth.qml +++ b/modules/Bluetooth.qml @@ -67,22 +67,37 @@ M.BarSection { icon: "\uF294" color: root.state === "off" ? M.Theme.base04 : root.accentColor anchors.verticalCenter: parent.verticalCenter + TapHandler { + cursorShape: Qt.PointingHandCursor + onTapped: { + M.FlyoutState.visible = false; + btLoader.active = true; + } + } } M.BarLabel { visible: root.state === "connected" label: root.device + (root.batteryPct >= 0 ? " " + root.batteryPct + "%" : "") anchors.verticalCenter: parent.verticalCenter + TapHandler { + cursorShape: Qt.PointingHandCursor + onTapped: { + M.FlyoutState.visible = false; + btLoader.active = true; + } + } } required property var bar - readonly property bool _anyHover: root._hovered || bluetoothMenu.panelHovered || bluetoothMenu._busy - - M.BluetoothMenu { - id: bluetoothMenu - showPanel: root._anyHover - screen: root.bar.screen - anchorItem: root - accentColor: root.accentColor + LazyLoader { + id: btLoader + active: false + M.BluetoothMenu { + accentColor: root.accentColor + screen: QsWindow.window?.screen ?? null + anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) + onDismissed: btLoader.active = false + } } } diff --git a/modules/BluetoothMenu.qml b/modules/BluetoothMenu.qml index 4d0e415..e80096c 100644 --- a/modules/BluetoothMenu.qml +++ b/modules/BluetoothMenu.qml @@ -8,12 +8,43 @@ M.HoverPanel { contentWidth: 250 panelNamespace: "nova-bluetooth" + popupMode: true + panelTitle: "Bluetooth" + titleActionsComponent: Component { + Item { + width: 20 + height: 20 + + Text { + anchors.centerIn: parent + text: "\uF011" + color: menuWindow._btEnabled ? menuWindow.accentColor : M.Theme.base04 + font.pixelSize: M.Theme.fontSize + font.family: M.Theme.iconFontFamily + + Behavior on color { + ColorAnimation { + duration: 100 + } + } + } + + HoverHandler { + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onTapped: { + powerProc._action = menuWindow._btEnabled ? "off" : "on"; + powerProc.running = true; + } + } + } + } onVisibleChanged: if (visible) scanner.running = true - readonly property bool _busy: powerProc.running || toggleProc.running - property var _devices: [] property bool _btEnabled: true @@ -56,8 +87,10 @@ M.HoverPanel { id: powerProc property string _action: "" command: ["bluetoothctl", "power", _action] - onRunningChanged: if (!running) - scanner.running = true + onRunningChanged: if (!running) { + scanner.running = true; + menuWindow.keepOpen(500); + } } property Process _toggleProc: Process { @@ -65,72 +98,10 @@ M.HoverPanel { property string action: "" property string mac: "" command: ["bluetoothctl", action, mac] - onRunningChanged: if (!running) - scanner.running = true - } - - // Bluetooth radio toggle header - Item { - width: menuWindow.contentWidth - height: 36 - - Rectangle { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - color: btHeaderHover.hovered ? M.Theme.base02 : "transparent" - radius: M.Theme.radius + onRunningChanged: if (!running) { + scanner.running = true; + menuWindow.keepOpen(500); } - - Text { - id: btHeaderIcon - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "\uF294" - color: menuWindow._btEnabled ? menuWindow.accentColor : M.Theme.base04 - font.pixelSize: M.Theme.fontSize + 1 - font.family: M.Theme.iconFontFamily - } - - Text { - anchors.left: btHeaderIcon.right - anchors.leftMargin: 8 - anchors.verticalCenter: parent.verticalCenter - text: "Bluetooth" - color: menuWindow._btEnabled ? M.Theme.base05 : M.Theme.base04 - font.pixelSize: M.Theme.fontSize - font.family: M.Theme.fontFamily - font.bold: true - } - - Text { - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "\uF011" - color: menuWindow._btEnabled ? menuWindow.accentColor : M.Theme.base04 - font.pixelSize: M.Theme.fontSize - font.family: M.Theme.iconFontFamily - } - - HoverHandler { - id: btHeaderHover - cursorShape: Qt.PointingHandCursor - } - TapHandler { - onTapped: { - powerProc._action = menuWindow._btEnabled ? "off" : "on"; - powerProc.running = true; - } - } - } - - Rectangle { - width: menuWindow.contentWidth - 16 - height: 1 - anchors.horizontalCenter: parent.horizontalCenter - color: M.Theme.base03 } Repeater { diff --git a/modules/Cpu.qml b/modules/Cpu.qml index 8159533..338e8cf 100644 --- a/modules/Cpu.qml +++ b/modules/Cpu.qml @@ -96,23 +96,14 @@ M.BarSection { anchorItem: root accentColor: root.accentColor panelNamespace: "nova-cpu" + panelTitle: "CPU" contentWidth: 260 - // Header + // Header — freq + usage (title comes from panelTitle) Item { width: parent.width height: 28 - Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "CPU" - color: M.Theme.base04 - font.pixelSize: M.Theme.fontSize - 1 - font.family: M.Theme.fontFamily - } - Text { id: _headerFreq anchors.right: parent.right diff --git a/modules/Disk.qml b/modules/Disk.qml index 05ffcb6..804346c 100644 --- a/modules/Disk.qml +++ b/modules/Disk.qml @@ -69,23 +69,9 @@ M.BarSection { anchorItem: root accentColor: root.accentColor panelNamespace: "nova-disk" + panelTitle: "Disk" contentWidth: 260 - Item { - width: parent.width - height: 28 - - Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "Disk" - color: M.Theme.base04 - font.pixelSize: M.Theme.fontSize - 1 - font.family: M.Theme.fontFamily - } - } - Repeater { model: root._mounts diff --git a/modules/HoverPanel.qml b/modules/HoverPanel.qml index 47f6dc3..fd459da 100644 --- a/modules/HoverPanel.qml +++ b/modules/HoverPanel.qml @@ -32,6 +32,7 @@ PanelWindow { // Shared required property color accentColor property string panelTitle: "" + property Component titleActionsComponent: null property string panelNamespace: "nova-panel" property real contentWidth: 220 @@ -231,9 +232,10 @@ PanelWindow { id: _panelColumn width: root.contentWidth - // Header row: title (optional) + pin button — hover mode only + // Header row: title + action buttons + pin — shown in hover mode always, + // and in popup mode when a title or actions are provided. Item { - visible: !root.popupMode + visible: !root.popupMode || root.panelTitle !== "" || root.titleActionsComponent !== null width: parent.width height: 24 @@ -249,13 +251,24 @@ PanelWindow { font.family: M.Theme.fontFamily } - Item { - visible: root.panelHovered || root._pinned - anchors.right: parent.right + // Action buttons — anchored left of pin button slot + Loader { + id: _titleActionsLoader + anchors.right: _pinBtn.left anchors.rightMargin: 4 anchors.verticalCenter: parent.verticalCenter - width: 20 + sourceComponent: root.titleActionsComponent + } + + // Pin button — zero-width in popup mode so actions anchor flush to right + Item { + id: _pinBtn + anchors.right: parent.right + anchors.rightMargin: root.popupMode ? 0 : 4 + anchors.verticalCenter: parent.verticalCenter + width: root.popupMode ? 0 : 20 height: 20 + visible: !root.popupMode && (root.panelHovered || root._pinned) opacity: pinHover.hovered || root._pinned ? 1 : 0.35 Behavior on opacity { @@ -291,6 +304,15 @@ PanelWindow { } } } + + // Divider at bottom of header + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: 1 + color: M.Theme.base03 + } } Column { diff --git a/modules/Memory.qml b/modules/Memory.qml index c9df8bc..29a77e8 100644 --- a/modules/Memory.qml +++ b/modules/Memory.qml @@ -65,23 +65,14 @@ M.BarSection { anchorItem: root accentColor: root.accentColor panelNamespace: "nova-memory" + panelTitle: "Memory" contentWidth: 240 - // Header + // Header — used/total (title comes from panelTitle) Item { width: parent.width height: 28 - Text { - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "Memory" - color: M.Theme.base04 - font.pixelSize: M.Theme.fontSize - 1 - font.family: M.Theme.fontFamily - } - Text { anchors.right: parent.right anchors.rightMargin: 12 diff --git a/modules/NetworkMenu.qml b/modules/NetworkMenu.qml index 529458e..613ef1f 100644 --- a/modules/NetworkMenu.qml +++ b/modules/NetworkMenu.qml @@ -8,6 +8,38 @@ M.HoverPanel { contentWidth: 250 panelNamespace: "nova-network" + panelTitle: "Wi-Fi" + titleActionsComponent: Component { + Item { + width: 20 + height: 20 + + Text { + anchors.centerIn: parent + text: "\uF011" + color: menuWindow._wifiEnabled ? menuWindow.accentColor : M.Theme.base04 + font.pixelSize: M.Theme.fontSize + font.family: M.Theme.iconFontFamily + + Behavior on color { + ColorAnimation { + duration: 100 + } + } + } + + HoverHandler { + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onTapped: { + radioProc._state = menuWindow._wifiEnabled ? "off" : "on"; + radioProc.running = true; + } + } + } + } onVisibleChanged: if (visible) scanner.running = true @@ -109,70 +141,6 @@ M.HoverPanel { } } - // Wi-Fi radio toggle header - Item { - width: menuWindow.contentWidth - height: 36 - - Rectangle { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - color: headerHover.hovered ? M.Theme.base02 : "transparent" - radius: M.Theme.radius - } - - Text { - id: wifiHeaderIcon - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "\uF1EB" - color: menuWindow._wifiEnabled ? menuWindow.accentColor : M.Theme.base04 - font.pixelSize: M.Theme.fontSize + 1 - font.family: M.Theme.iconFontFamily - } - - Text { - anchors.left: wifiHeaderIcon.right - anchors.leftMargin: 8 - anchors.verticalCenter: parent.verticalCenter - text: "Wi-Fi" - color: menuWindow._wifiEnabled ? M.Theme.base05 : M.Theme.base04 - font.pixelSize: M.Theme.fontSize - font.family: M.Theme.fontFamily - font.bold: true - } - - Text { - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - text: "\uF011" - color: menuWindow._wifiEnabled ? menuWindow.accentColor : M.Theme.base04 - font.pixelSize: M.Theme.fontSize - font.family: M.Theme.iconFontFamily - } - - HoverHandler { - id: headerHover - cursorShape: Qt.PointingHandCursor - } - TapHandler { - onTapped: { - radioProc._state = menuWindow._wifiEnabled ? "off" : "on"; - radioProc.running = true; - } - } - } - - Rectangle { - width: menuWindow.contentWidth - 16 - height: 1 - anchors.horizontalCenter: parent.horizontalCenter - color: M.Theme.base03 - } - Repeater { model: menuWindow._networks