From e1e1b316cfffdc9e60046b8bc4036a9077e81eac Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 13 Nov 2025 19:27:11 -0600 Subject: [PATCH] bar --- .../dotfiles/quickshell/modules/Bar.qml | 168 +++++++++++++----- .../dotfiles/quickshell/modules/Battery.qml | 51 ++++++ .../dotfiles/quickshell/modules/Bluetooth.qml | 57 +++++- .../dotfiles/quickshell/modules/Clock.qml | 9 +- .../dotfiles/quickshell/modules/Media.qml | 41 +---- .../quickshell/modules/Notifications.qml | 142 ++++++++++++++- .../dotfiles/quickshell/modules/Power.qml | 34 +++- .../dotfiles/quickshell/modules/Tray.qml | 7 +- .../dotfiles/quickshell/modules/Volume.qml | 52 ++++++ .../dotfiles/quickshell/modules/Wifi.qml | 54 +++++- .../quickshell/modules/Workspaces.qml | 6 +- 11 files changed, 513 insertions(+), 108 deletions(-) diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Bar.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Bar.qml index d7e674e..3c199a4 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Bar.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Bar.qml @@ -26,56 +26,136 @@ PanelWindow { implicitHeight: 40 implicitWidth: 1900 - Flow { - x: 0 - padding: 5 - spacing: 10 - - Launcher { id: l } - - Workspaces { id: ws } - - } - + /*RowLayout { + width: bar.width + }*/ RowLayout { - x: (parent.width - cl.width) / 2 + parent.x - cl.x + //Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + id: left + x: 0 y: parent.y + (parent.height - height) / 2 - spacing: 10 + //width: center.x + spacing: 0 - Volume { id: v } + Launcher { + id: l + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.preferredWidth: width + Layout.margins: 5 + } - Battery { id: bat } - - Hyprsunset { id: hs } - - Clock { id: cl } - - IdleInhibitor { id: ii } - - Wifi { id: wifi } - - Bluetooth { id: bt } - - } - - Flow { - x: parent.width + parent.x - width - padding: 5 - spacing: 10 - - Layout.alignment: Qt.AlignRight - - Media { id: media } - - Tray { id: tray; window: bar } - - Notifications { id: notif } - - Power { - id: power - window: bar + Workspaces { + id: ws + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.margins: 5 } } + RowLayout { + //Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + id: center + x: (parent.width - cl.width) / 2 + parent.x - centerLeft.width + //y: parent.y + (parent.height - height) / 2 + y: parent.y + (parent.height - height) / 2 + spacing: 0 + + RowLayout { + id: centerLeft + spacing: 0 + + Volume { + id: v + window: bar + popupOffset: center.x + Layout.margins: 5 + } + + Battery { + id: bat + window: bar + popupOffset: center.x + Layout.margins: 5 + } + + Hyprsunset { + id: hs + Layout.margins: 5 + } + } + + + Clock { + id: cl + Layout.margins: 5 + } + + IdleInhibitor { + id: ii + Layout.margins: 5 + } + + Wifi { + id: wifi + window: bar + Layout.margins: 5 + } + + Bluetooth { + id: bt + window: bar + Layout.margins: 5 + } + + } + + + RowLayout { + //Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + id: right + //implicitWidth: bar.width - (spacer.x + spacer.width) + x: bar.width - implicitWidth + y: parent.y + (parent.height - height) / 2 + //Layout.maximumWidth: bar.width - (center.x + center.width) + //Layout.preferredWidth: 10 + spacing: 0 + + Media { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + id: media + + implicitWidth: Math.min(textWidth, bar.width - (righter.width) - (center.x + center.width) - 10) + + Layout.margins: 5 + } + + RowLayout { + id: righter + spacing: 0 + Tray { + id: tray + window: bar + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + popupOffset: right.x + righter.x + x + } + + Notifications { + id: notif + window: bar + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + } + + Power { + id: power + window: bar + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + } + } + } + + + } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Battery.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Battery.qml index a8df954..2cf1f30 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Battery.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Battery.qml @@ -1,8 +1,10 @@ import Quickshell // for PanelWindow import QtQuick // for Text import QtQuick.Controls +import QtQuick.Layouts import Quickshell.Io import Quickshell.Widgets +import Quickshell.Hyprland import Quickshell.Services.UPower ClippingWrapperRectangle { @@ -16,5 +18,54 @@ ClippingWrapperRectangle { implicitHeight: parent.height //icon.color: "red" //icon.source: "/nix/store/c4dcn4vl0v5njv4d587sazrad1xgyd9h-rose-pine-icon-theme-unstable-2022-09-01/share/icons/rose-pine/symbolic/devices/battery-symbolic.svg" + onClicked: { + menu.visible = true + grab.active = true + } + } + + required property var window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Bluetooth.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Bluetooth.qml index 1de461a..6eb3217 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Bluetooth.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Bluetooth.qml @@ -1,22 +1,69 @@ import Quickshell // for PanelWindow import QtQuick // for Text import QtQuick.Controls +import QtQuick.Layouts import Quickshell.Io import Quickshell.Widgets +import Quickshell.Hyprland ClippingWrapperRectangle { + + radius: 5 implicitWidth: 30; implicitHeight: 30 Button { id: button text: "" font.pointSize: 16 - Process { - id: launcher - running: false - command: ["rofi", "-show", "drun"] + + onClicked: { + menu.visible = true + grab.active = true } - onClicked: launcher.running = true implicitHeight: parent.height } + + property var window: null + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: root.parent.x + root.parent.width - width + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Clock.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Clock.qml index 6af9428..eeec3d7 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Clock.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Clock.qml @@ -5,13 +5,16 @@ import Quickshell.Widgets import Quickshell Item { - width: 250 - height: 30 + implicitWidth: t.contentWidth + 10 + implicitHeight: 30 ClippingWrapperRectangle { radius: 5 anchors.fill: parent - Button { + Text { + id: t + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter text: Qt.formatDateTime(clock.date, "dddd HH:mm:ss MM/dd/yyyy") font.pointSize: 11 diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Media.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Media.qml index 69fc02d..5548b00 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Media.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Media.qml @@ -6,17 +6,20 @@ import Quickshell.Widgets Item { id: media - width: 250 > 9 * button.text.length ? 250 : 9 * button.text.length height: 30 + readonly property real textWidth: info.contentWidth + 10 + ClippingWrapperRectangle { radius: 5 anchors.fill: parent - Button { + Text { - id: button + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + id: info - property real offset: 0 text: { let s = '' let players = [] @@ -35,37 +38,11 @@ Item { s += ' - ' + players[0].trackArtist } - let a = offset % s.length - let b = (offset + s.length - 1) % s.length + media.visible = players.length > 0 - if(s == '') - media.visible = false - else - media.visible = true - if(b < a) { - return s.substring(a, s.length) + ' ' + s.substring(0, b) - } else { - return s.substring(a, b) + ' ' - } - //return s + return s } font.pointSize: 11 - - onClicked: { - timer.running = !timer.running - } - - Timer { - id: timer - - interval: 225 - - running: true - - repeat: true - - onTriggered: button.offset = (button.offset + 1) % (2 * button.text.length) - } } } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Notifications.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Notifications.qml index c0b0cb3..94d0e34 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Notifications.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Notifications.qml @@ -1,29 +1,32 @@ +import Quickshell import QtQuick // for Text import QtQuick.Controls import QtQuick.Layouts import Quickshell.Services.Notifications import Quickshell.Io import Quickshell.Widgets +import Quickshell.Hyprland Item { width: 50 height: 30 ClippingWrapperRectangle { + id: barbutton radius: 5 anchors.fill: parent Button { id: button text: "󰂚" + //text: server.trackedNotifications.values.length == 0 ? "󰂚" : '󱅫 ' + server.trackedNotifications.values.length //icon.source: '' font.pointSize: 16 onClicked: { - while(server.trackedNotifications.values.length > 0) { - server.trackedNotifications.values[0].dismiss() - } + - text = "󰂚" + menu.visible = true + grab.active = true } implicitHeight: parent.height } @@ -45,5 +48,136 @@ Item { console.log(n?.body) button.text = '󱅫 ' + (server.trackedNotifications.values.length + 1) } + + } + + required property PanelWindow window + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: window.width - width + anchor.rect.y: 50 + implicitWidth: 400 + implicitHeight: 1080 - anchor.rect.y + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + color: "#ff706050" + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + id: lay + + spacing: 10 + + ClippingWrapperRectangle { + radius: 5 + Layout.margins: 5 + Layout.alignment: Qt.AlignVCenter | Qt.AlignTop + implicitWidth: menu.width - 2 * Layout.margins + + RowLayout { + width: parent.width + Text { + Layout.margins: 5 + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + text: 'Notifications' + } + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 5 + implicitWidth: 20 + implicitHeight: 20 + + text: 'x' + + onClicked: { + while(server.trackedNotifications.values.length > 0) { + server.trackedNotifications.values[0].dismiss() + } + } + } + } + } + + + Repeater { + id: rep + + model: server.trackedNotifications.values + ClippingWrapperRectangle { + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.margins: 5 + radius: 10 + implicitWidth: parent.width - 2 * Layout.margins + implicitHeight: 100 + MouseArea { + anchors.fill: parent + + RowLayout { + Image { + //anchors.fill: parent + source: { + let icon = rep.model[index].image + if (icon.includes("?path=")) { + const [name, path] = icon.split("?path="); + icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`); + } + return icon + } + + Layout.maximumWidth: 100 + Layout.maximumHeight: 100 + } + + ColumnLayout { + Layout.topMargin: 10 + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Text { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + text: rep.model[index].summary + Layout.leftMargin: 10 + font.pointSize: 14 + } + Text { + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + text: rep.model[index].body + Layout.leftMargin: 10 + font.pointSize: 12 + } + } + } + + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: mouse => { + if(mouse.button == Qt.LeftButton) { + button.text = rep.count - 1 <= 0 ? "󰂚" : '󱅫 ' + (rep.count - 1) + rep.model[index].dismiss() + //button.text = server.trackedNotifications.values.length == 0 ? "󰂚" : '󱅫 ' + server.trackedNotifications.values.length + } else if(mouse.button == Qt.RightButton) { + } + } + } + } + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Power.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Power.qml index fadc36a..ac1cf6c 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Power.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Power.qml @@ -22,7 +22,10 @@ Item { text: " " font.pointSize: 16 - onClicked: menu.visible = !menu.visible + onClicked: { + menu.visible = true + grab.active = true + } implicitHeight: parent.height } } @@ -34,9 +37,9 @@ Item { anchor.window: window anchor.rect.x: root.parent.x + root.parent.width - width anchor.rect.y: 50 - implicitWidth: 250 - implicitHeight: 150 - visible: true + implicitWidth: 150 + implicitHeight: 250 + visible: false color: "transparent" @@ -48,32 +51,45 @@ Item { ColumnLayout { - spacing: 2 + spacing: 0 Button { + Layout.topMargin: 5 x: (parent.width - width) / 2 implicitWidth: parent.width - 10 - implicitHeight: parent.height / 4 - parent.spacing + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' } Button { x: (parent.width - width) / 2 implicitWidth: parent.width - 10 - implicitHeight: parent.height / 4 - parent.spacing + implicitHeight: parent.height / 5 - parent.spacing + text: 'reboot' } Button { x: (parent.width - width) / 2 implicitWidth: parent.width - 10 - implicitHeight: parent.height / 4 - parent.spacing + implicitHeight: parent.height / 5 - parent.spacing + text: 'logout' } Button { + Layout.bottomMargin: 10 x: (parent.width - width) / 2 implicitWidth: parent.width - 10 - implicitHeight: parent.height / 4 - parent.spacing + implicitHeight: parent.height / 5 - parent.spacing + text: 'sleep' } } } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Tray.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Tray.qml index ad06a17..f4c7e47 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Tray.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Tray.qml @@ -5,12 +5,13 @@ import Quickshell.Services.SystemTray import Quickshell.Widgets Item { - width: 10 + rep.count * (2 * lay.spacing + 20) + implicitWidth: 10 + rep.count * (2 * lay.spacing + 20) height: 30 visible: SystemTray.items.values.length != 0 id: root - property var window: null + required property var window + required property real popupOffset ClippingWrapperRectangle { radius: 5 @@ -48,7 +49,7 @@ Item { if(mouse.button == Qt.LeftButton) { SystemTray.items.values[index].activate() } else if(mouse.button == Qt.RightButton) { - SystemTray.items.values[index].display(root.window, root.x + root.parent.x, 40) + SystemTray.items.values[index].display(root.window, popupOffset, 40) } } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Volume.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Volume.qml index 31b6bd4..6b63819 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Volume.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Volume.qml @@ -1,8 +1,10 @@ import Quickshell // for PanelWindow import QtQuick // for Text import QtQuick.Controls +import QtQuick.Layouts import Quickshell.Io import Quickshell.Widgets +import Quickshell.Hyprland import Quickshell.Services.Pipewire ClippingWrapperRectangle { @@ -18,5 +20,55 @@ ClippingWrapperRectangle { objects: [ Pipewire.defaultAudioSink ] } + onClicked: { + menu.visible = true + grab.active = true + } + + } + + required property var window + required property real popupOffset + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: popupOffset + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Wifi.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Wifi.qml index 3260890..99a66af 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Wifi.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Wifi.qml @@ -1,3 +1,4 @@ +import Quickshell import QtQuick // for Text import QtQuick.Controls import QtQuick.Layouts @@ -16,13 +17,56 @@ Item { id: button text: "󰤨 " font.pointSize: 16 - Process { - id: launcher - running: false - command: ["rofi", "-show", "drun"] + + onClicked: { + menu.visible = true + grab.active = true } - onClicked: launcher.running = true implicitHeight: parent.height } } + + property var window: null + id: root + + PopupWindow { + + id: menu + + anchor.window: window + anchor.rect.x: root.parent.x + root.parent.width - width + anchor.rect.y: 50 + implicitWidth: 250 + implicitHeight: 150 + visible: false + + color: "transparent" + + ClippingWrapperRectangle { + radius: 5 + + implicitHeight: parent.height - 20 + implicitWidth: parent.width + + ColumnLayout { + + spacing: 0 + + Button { + Layout.topMargin: 5 + x: (parent.width - width) / 2 + implicitWidth: parent.width - 10 + implicitHeight: parent.height / 5 - parent.spacing + + text: 'shutdown' + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [ menu ] + onCleared: menu.visible = false + } + } } diff --git a/home-manager/users/nathan/dotfiles/quickshell/modules/Workspaces.qml b/home-manager/users/nathan/dotfiles/quickshell/modules/Workspaces.qml index 0bd2a5f..eb6b00e 100644 --- a/home-manager/users/nathan/dotfiles/quickshell/modules/Workspaces.qml +++ b/home-manager/users/nathan/dotfiles/quickshell/modules/Workspaces.qml @@ -5,8 +5,8 @@ import Quickshell.Hyprland import Quickshell.Widgets Item { - width: 10 + rep.count * (2 * lay.spacing + 25) - height: 30 + implicitWidth: 10 + rep.count * (2 * lay.spacing + 25) + implicitHeight: 30 ClippingWrapperRectangle { radius: 5 @@ -29,7 +29,7 @@ Item { implicitWidth: 25 Button { background: Rectangle { - color: Hyprland.focusedWorkspace.id == rep.test[index].id ? "#ffff00ff" : "#ff251555" + color: Hyprland.focusedWorkspace.id == rep.test[index].id ? "#ffff00ff" : "#ff7744dd" anchors.fill: parent } text: rep.test[index].id