mirror of
https://github.com/AquaMorph/dotfiles.git
synced 2026-09-29 20:04:21 +00:00
refactor(quickshell): split bar components
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Block {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var sink
|
||||||
|
required property var source
|
||||||
|
signal detailsRequested(var anchorItem)
|
||||||
|
|
||||||
|
blockColor: sink && sink.audio && sink.audio.muted
|
||||||
|
? Theme.foreground : Theme.primary
|
||||||
|
textColor: sink && sink.audio && sink.audio.muted
|
||||||
|
? Theme.foregroundDark : Theme.foreground
|
||||||
|
interactive: true
|
||||||
|
text: {
|
||||||
|
if (!sink || !sink.audio)
|
||||||
|
return "\uf026";
|
||||||
|
return sink.audio.muted
|
||||||
|
? "\uf026" : "\uf028 " + Math.round(sink.audio.volume * 100) + "%";
|
||||||
|
}
|
||||||
|
secondaryIcon: source && source.audio
|
||||||
|
? (source.audio.muted
|
||||||
|
? "file://" + Quickshell.shellPath("icons/microphone-muted.svg")
|
||||||
|
: "file://" + Quickshell.shellPath("icons/microphone.svg"))
|
||||||
|
: ""
|
||||||
|
secondaryText: source && source.audio
|
||||||
|
? (source.audio.muted ? "OFF"
|
||||||
|
: Math.round(source.audio.volume * 100) + "%")
|
||||||
|
: ""
|
||||||
|
|
||||||
|
onClicked: mouse => {
|
||||||
|
if (mouse.button === Qt.LeftButton)
|
||||||
|
detailsRequested(root);
|
||||||
|
else if (mouse.button === Qt.MiddleButton && sink && sink.audio)
|
||||||
|
sink.audio.muted = !sink.audio.muted;
|
||||||
|
else
|
||||||
|
Quickshell.execDetached(["qjackctl"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
onWheel: wheel => {
|
||||||
|
if (!sink || !sink.audio)
|
||||||
|
return;
|
||||||
|
const change = wheel.angleDelta.y > 0 ? 0.05 : -0.05;
|
||||||
|
sink.audio.volume = Math.max(0, Math.min(1.5,
|
||||||
|
sink.audio.volume + change));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,7 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import Quickshell.Services.Pipewire
|
import Quickshell.Services.Pipewire
|
||||||
import Quickshell.Services.SystemTray
|
|
||||||
import Quickshell.Services.UPower
|
import Quickshell.Services.UPower
|
||||||
import Quickshell.Widgets
|
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: bar
|
id: bar
|
||||||
@@ -14,13 +12,6 @@ PanelWindow {
|
|||||||
property var battery: UPower.displayDevice
|
property var battery: UPower.displayDevice
|
||||||
property var hardware
|
property var hardware
|
||||||
|
|
||||||
function formatClock(date, includeSeconds) {
|
|
||||||
const hour = date.getHours() % 12 || 12;
|
|
||||||
const minute = date.getMinutes().toString().padStart(2, "0");
|
|
||||||
const second = date.getSeconds().toString().padStart(2, "0");
|
|
||||||
return hour + ":" + minute + (includeSeconds ? ":" + second : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
left: true
|
left: true
|
||||||
@@ -56,55 +47,8 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
spacing: Theme.moduleSpacing
|
spacing: Theme.moduleSpacing
|
||||||
|
|
||||||
Row {
|
Workspaces {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Hyprland.workspaces
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: workspaceButton
|
|
||||||
|
|
||||||
required property var modelData
|
|
||||||
property bool active: modelData.active
|
|
||||||
|
|
||||||
visible: modelData.id > 0
|
|
||||||
width: Theme.blockHeight + 2
|
|
||||||
height: parent.height
|
|
||||||
color: modelData.urgent ? Theme.urgent
|
|
||||||
: active ? Theme.primary : "transparent"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: parent.bottom
|
|
||||||
}
|
|
||||||
height: Theme.activeLineWidth
|
|
||||||
color: workspaceButton.active ? Theme.accent : "transparent"
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: modelData.id === 2 ? "\uf120"
|
|
||||||
: modelData.id === 13 ? "\uf001" : modelData.name
|
|
||||||
color: Theme.foreground
|
|
||||||
font.family: Theme.iconFontFamily
|
|
||||||
font.pixelSize: Theme.fontSize
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: Quickshell.execDetached([
|
|
||||||
"hyprctl",
|
|
||||||
"dispatch",
|
|
||||||
"hl.dsp.focus({ workspace = " + workspaceButton.modelData.id + " })"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,43 +74,10 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
spacing: Theme.moduleSpacing
|
spacing: Theme.moduleSpacing
|
||||||
|
|
||||||
Block {
|
AudioBlock {
|
||||||
id: audioBlock
|
sink: bar.sink
|
||||||
blockColor: bar.sink && bar.sink.audio && bar.sink.audio.muted
|
source: bar.source
|
||||||
? Theme.foreground : Theme.primary
|
onDetailsRequested: anchorItem => detailsPopup.toggle("audio", anchorItem)
|
||||||
textColor: bar.sink && bar.sink.audio && bar.sink.audio.muted
|
|
||||||
? Theme.foregroundDark : Theme.foreground
|
|
||||||
interactive: true
|
|
||||||
text: {
|
|
||||||
if (!bar.sink || !bar.sink.audio)
|
|
||||||
return "\uf026";
|
|
||||||
return bar.sink.audio.muted
|
|
||||||
? "\uf026" : "\uf028 " + Math.round(bar.sink.audio.volume * 100) + "%";
|
|
||||||
}
|
|
||||||
secondaryIcon: bar.source && bar.source.audio
|
|
||||||
? (bar.source.audio.muted
|
|
||||||
? "file://" + Quickshell.shellPath("icons/microphone-muted.svg")
|
|
||||||
: "file://" + Quickshell.shellPath("icons/microphone.svg"))
|
|
||||||
: ""
|
|
||||||
secondaryText: bar.source && bar.source.audio
|
|
||||||
? (bar.source.audio.muted ? "OFF"
|
|
||||||
: Math.round(bar.source.audio.volume * 100) + "%")
|
|
||||||
: ""
|
|
||||||
onClicked: mouse => {
|
|
||||||
if (mouse.button === Qt.LeftButton)
|
|
||||||
detailsPopup.toggle("audio", audioBlock);
|
|
||||||
else if (mouse.button === Qt.MiddleButton && bar.sink && bar.sink.audio)
|
|
||||||
bar.sink.audio.muted = !bar.sink.audio.muted;
|
|
||||||
else
|
|
||||||
Quickshell.execDetached(["qjackctl"]);
|
|
||||||
}
|
|
||||||
onWheel: wheel => {
|
|
||||||
if (!bar.sink || !bar.sink.audio)
|
|
||||||
return;
|
|
||||||
const change = wheel.angleDelta.y > 0 ? 0.05 : -0.05;
|
|
||||||
bar.sink.audio.volume = Math.max(0, Math.min(1.5,
|
|
||||||
bar.sink.audio.volume + change));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Network {
|
Network {
|
||||||
@@ -175,95 +86,16 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
Backlight { service: bar.hardware }
|
Backlight { service: bar.hardware }
|
||||||
|
|
||||||
Block {
|
BatteryBlock {
|
||||||
id: batteryBlock
|
battery: bar.battery
|
||||||
property int percentage: Math.round(bar.battery.percentage * 100)
|
onDetailsRequested: anchorItem => detailsPopup.toggle("battery", anchorItem)
|
||||||
|
|
||||||
visible: bar.battery.ready && bar.battery.isLaptopBattery
|
|
||||||
interactive: true
|
|
||||||
blockColor: percentage <= 15 && UPower.onBattery
|
|
||||||
? Theme.urgent : UPower.onBattery ? Theme.foreground : Theme.secondary
|
|
||||||
textColor: UPower.onBattery && percentage > 15
|
|
||||||
? Theme.foregroundDark : Theme.foreground
|
|
||||||
text: {
|
|
||||||
if (!UPower.onBattery)
|
|
||||||
return "\uf1e6 " + percentage + "%";
|
|
||||||
if (percentage <= 10) return "\uf244 " + percentage + "%";
|
|
||||||
if (percentage <= 35) return "\uf243 " + percentage + "%";
|
|
||||||
if (percentage <= 60) return "\uf242 " + percentage + "%";
|
|
||||||
if (percentage <= 85) return "\uf241 " + percentage + "%";
|
|
||||||
return "\uf240 " + percentage + "%";
|
|
||||||
}
|
|
||||||
onClicked: detailsPopup.toggle("battery", batteryBlock)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Tray { barWindow: bar }
|
||||||
visible: trayRepeater.count > 0
|
|
||||||
implicitWidth: trayItems.implicitWidth + Theme.contentPadding * 2
|
|
||||||
implicitHeight: Theme.blockHeight
|
|
||||||
color: Theme.primary
|
|
||||||
|
|
||||||
Row {
|
ClockBlock {
|
||||||
id: trayItems
|
clock: clock
|
||||||
anchors.centerIn: parent
|
onDetailsRequested: anchorItem => detailsPopup.toggle("clock", anchorItem)
|
||||||
spacing: Theme.contentPadding
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: trayRepeater
|
|
||||||
model: SystemTray.items
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: trayItem
|
|
||||||
|
|
||||||
required property var modelData
|
|
||||||
width: 26
|
|
||||||
height: 30
|
|
||||||
|
|
||||||
IconImage {
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
margins: 3
|
|
||||||
}
|
|
||||||
source: trayItem.modelData.icon
|
|
||||||
opacity: trayMouse.containsMouse ? 1 : 0.82
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation { duration: 120 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: trayMouse
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
|
||||||
onClicked: mouse => {
|
|
||||||
if (mouse.button === Qt.MiddleButton)
|
|
||||||
trayItem.modelData.secondaryActivate();
|
|
||||||
else if (mouse.button === Qt.RightButton || trayItem.modelData.onlyMenu) {
|
|
||||||
const point = mapToItem(bar.contentItem, 0, height);
|
|
||||||
trayItem.modelData.display(bar, point.x, point.y);
|
|
||||||
} else {
|
|
||||||
trayItem.modelData.activate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onWheel: wheel => trayItem.modelData.scroll(
|
|
||||||
wheel.angleDelta.y, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Block {
|
|
||||||
id: clockBlock
|
|
||||||
property bool showSeconds: false
|
|
||||||
|
|
||||||
interactive: true
|
|
||||||
text: bar.formatClock(clock.date, showSeconds)
|
|
||||||
onClicked: detailsPopup.toggle("clock", clockBlock)
|
|
||||||
onDoubleClicked: showSeconds = !showSeconds
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import Quickshell.Services.UPower
|
||||||
|
|
||||||
|
Block {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var battery
|
||||||
|
property int percentage: Math.round(battery.percentage * 100)
|
||||||
|
signal detailsRequested(var anchorItem)
|
||||||
|
|
||||||
|
visible: battery.ready && battery.isLaptopBattery
|
||||||
|
interactive: true
|
||||||
|
blockColor: percentage <= 15 && UPower.onBattery
|
||||||
|
? Theme.urgent : UPower.onBattery ? Theme.foreground : Theme.secondary
|
||||||
|
textColor: UPower.onBattery && percentage > 15
|
||||||
|
? Theme.foregroundDark : Theme.foreground
|
||||||
|
text: {
|
||||||
|
if (!UPower.onBattery)
|
||||||
|
return "\uf1e6 " + percentage + "%";
|
||||||
|
if (percentage <= 10) return "\uf244 " + percentage + "%";
|
||||||
|
if (percentage <= 35) return "\uf243 " + percentage + "%";
|
||||||
|
if (percentage <= 60) return "\uf242 " + percentage + "%";
|
||||||
|
if (percentage <= 85) return "\uf241 " + percentage + "%";
|
||||||
|
return "\uf240 " + percentage + "%";
|
||||||
|
}
|
||||||
|
onClicked: detailsRequested(root)
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Block {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var clock
|
||||||
|
property bool showSeconds: false
|
||||||
|
signal detailsRequested(var anchorItem)
|
||||||
|
|
||||||
|
function formattedTime() {
|
||||||
|
const date = clock.date;
|
||||||
|
const hour = date.getHours() % 12 || 12;
|
||||||
|
const minute = date.getMinutes().toString().padStart(2, "0");
|
||||||
|
const second = date.getSeconds().toString().padStart(2, "0");
|
||||||
|
return hour + ":" + minute + (showSeconds ? ":" + second : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
interactive: true
|
||||||
|
text: formattedTime()
|
||||||
|
onClicked: detailsRequested(root)
|
||||||
|
onDoubleClicked: showSeconds = !showSeconds
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var barWindow
|
||||||
|
|
||||||
|
visible: trayRepeater.count > 0
|
||||||
|
implicitWidth: trayItems.implicitWidth + Theme.contentPadding * 2
|
||||||
|
implicitHeight: Theme.blockHeight
|
||||||
|
color: Theme.primary
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: trayItems
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Theme.contentPadding
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: trayRepeater
|
||||||
|
model: SystemTray.items
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: trayItem
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
width: 26
|
||||||
|
height: 30
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
margins: 3
|
||||||
|
}
|
||||||
|
source: trayItem.modelData.icon
|
||||||
|
opacity: trayMouse.containsMouse ? 1 : 0.82
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: 120 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: trayMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||||
|
onClicked: mouse => {
|
||||||
|
if (mouse.button === Qt.MiddleButton) {
|
||||||
|
trayItem.modelData.secondaryActivate();
|
||||||
|
} else if (mouse.button === Qt.RightButton || trayItem.modelData.onlyMenu) {
|
||||||
|
const point = mapToItem(root.barWindow.contentItem, 0, height);
|
||||||
|
trayItem.modelData.display(root.barWindow, point.x, point.y);
|
||||||
|
} else {
|
||||||
|
trayItem.modelData.activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onWheel: wheel => trayItem.modelData.scroll(
|
||||||
|
wheel.angleDelta.y, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Hyprland.workspaces
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: workspaceButton
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
property bool active: modelData.active
|
||||||
|
|
||||||
|
visible: modelData.id > 0
|
||||||
|
width: Theme.blockHeight + 2
|
||||||
|
height: parent.height
|
||||||
|
color: modelData.urgent ? Theme.urgent
|
||||||
|
: active ? Theme.primary : "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
height: Theme.activeLineWidth
|
||||||
|
color: workspaceButton.active ? Theme.accent : "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: modelData.id === 2 ? "\uf120"
|
||||||
|
: modelData.id === 13 ? "\uf001" : modelData.name
|
||||||
|
color: Theme.foreground
|
||||||
|
font.family: Theme.iconFontFamily
|
||||||
|
font.pixelSize: Theme.fontSize
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: Quickshell.execDetached([
|
||||||
|
"hyprctl",
|
||||||
|
"dispatch",
|
||||||
|
"hl.dsp.focus({ workspace = " + workspaceButton.modelData.id + " })"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user