panel title bar: add title, action buttons slot, divider; bt to popup mode; move wifi/bt toggles to title bar

This commit is contained in:
Damocles 2026-04-16 18:51:06 +02:00
parent 46f14d5d36
commit d4407ee538
7 changed files with 128 additions and 184 deletions

View file

@ -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
}
}
}

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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