335 lines
8.1 KiB
QML
Executable file
335 lines
8.1 KiB
QML
Executable file
//@ pragma UseQApplication
|
|
import Quickshell
|
|
import Quickshell.I3
|
|
import Quickshell.Wayland
|
|
import Quickshell.Io
|
|
import Quickshell.Services.SystemTray
|
|
import Quickshell.Widgets
|
|
import Quickshell.Services.UPower
|
|
import Quickshell.Services.Pipewire
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
// Some credit goes to my friends Lucy and Babsi
|
|
// Work in progress (Audio)
|
|
|
|
PanelWindow {
|
|
id: root
|
|
|
|
property color colBg: "#64320a"
|
|
property color colAppBg: "#2d1405"
|
|
property color colFg: "#d2d2d2"
|
|
property color colDark: "#230f05"
|
|
property string fontFamily: "Noto Sans"
|
|
property int fontSize: 18
|
|
property int appletRadHeight: 25
|
|
property int appletSpacing: 6
|
|
|
|
|
|
property int cpuUsage: 0
|
|
property var lastCpuIdle: 0
|
|
property var lastCpuTotal: 0
|
|
property real ramUsage: 0.00
|
|
property var batTime: 0
|
|
property var batCharMin: (UPower.displayDevice.timeToFull / 60).toFixed(2)
|
|
property var batDisMin: (UPower.displayDevice.timeToEmpty / 60).toFixed(2)
|
|
|
|
anchors {
|
|
right: true
|
|
left: true
|
|
top:true
|
|
}
|
|
|
|
color: "transparent"
|
|
implicitHeight: root.appletRadHeight + 10
|
|
margins {
|
|
right: 5
|
|
left: 5
|
|
top: 5
|
|
bottom: 0
|
|
}
|
|
Rectangle {
|
|
color: root.colBg
|
|
anchors.fill: parent
|
|
radius: root.appletRadHeight
|
|
}
|
|
|
|
RowLayout {
|
|
id: leftRow
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
Item {
|
|
id: rootItem
|
|
implicitWidth: root.appletRadHeight
|
|
height: root.appletRadHeight
|
|
Row {
|
|
id: workspaceRow
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
leftPadding: 10
|
|
|
|
Repeater {
|
|
id: wsRepeater
|
|
model: I3.workspaces
|
|
anchors.centerIn: parent
|
|
property var ws: I3.workspaces
|
|
|
|
Rectangle {
|
|
id: workspaceNumber
|
|
property bool isOnMon: {
|
|
if (!modelData)
|
|
return false
|
|
if (!modelData.monitor)
|
|
return false
|
|
if (!rootItem.screen)
|
|
return false;
|
|
return modelData.monitor.name === rootItem.screen.name;
|
|
}
|
|
|
|
required property var modelData
|
|
height: root.appletRadHeight * 1.1
|
|
width: root.appletRadHeight * 1.1
|
|
radius: root.appletRadHeight
|
|
color: root.colAppBg
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: parent.modelData.number
|
|
color: root.colFg
|
|
opacity: workspaceNumber.modelData.focused ? 1 : 0.5
|
|
font { family: root.fontFamily; pixelSize: root.fontSize; bold: true }
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {parent.modelData.activate();}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
RowLayout {
|
|
id: centerRow
|
|
spacing: root.appletSpacing
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
*/
|
|
RowLayout {
|
|
id: rightRow
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: root.appletSpacing
|
|
|
|
Item {
|
|
|
|
Process {
|
|
id: cpuProc
|
|
command: ["sh", "-c", "head -1 /proc/stat"]
|
|
stdout: SplitParser {
|
|
onRead: data => {
|
|
if (!data) return
|
|
var p = data.trim().split(/\s+/)
|
|
var idle = parseInt(p[4]) + parseInt(p[5])
|
|
var total = p.slice(1, 8).reduce((a, b) => a + parseInt(b), 0)
|
|
if (lastCpuTotal > 0) {
|
|
cpuUsage = Math.round(100 * (1 - (idle - lastCpuIdle) / (total - lastCpuTotal)))
|
|
}
|
|
lastCpuTotal = total
|
|
lastCpuIdle = idle
|
|
}
|
|
}
|
|
Component.onCompleted: running = true
|
|
}
|
|
|
|
Process {
|
|
id: ramProc
|
|
command: ["sh", "-c", "free | grep Mem"]
|
|
stdout: SplitParser {
|
|
onRead: data => {
|
|
if (!data) return
|
|
var parts = data.trim().split(/\s+/)
|
|
var used = parseInt(parts[2]) || 0
|
|
ramUsage = used /1048576
|
|
}
|
|
}
|
|
Component.onCompleted: running = true
|
|
}
|
|
Timer {
|
|
interval: 2000
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
cpuProc.running = true
|
|
ramProc.running = true
|
|
}
|
|
}
|
|
Item {
|
|
id: procItem
|
|
Row {
|
|
id: procRow
|
|
spacing: root.appletSpacing
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
leftPadding: 10
|
|
|
|
Loader {
|
|
id: statLoader
|
|
active: true
|
|
sourceComponent: Rectangle {
|
|
id: batRect
|
|
height: root.appletRadHeight
|
|
width: batText.paintedWidth + root.appletRadHeight
|
|
radius: root.appletRadHeight
|
|
color: root.colAppBg
|
|
|
|
function getBatStat() {
|
|
if (UPower.displayDevice.state == UPowerDeviceState.Discharging) {
|
|
batTime = Math.floor(batDisMin / 60) + "h " + ((batDisMin - (Math.floor(batDisMin / 60) * 60)).toFixed(0)) + "min"
|
|
return batTime;
|
|
}
|
|
if (UPower.displayDevice.state == UPowerDeviceState.Charging) {
|
|
batTime = Math.floor(batCharMin / 60) + "h " + ((batCharMin - (Math.floor(batCharMin / 60) * 60)).toFixed(0)) + "min"
|
|
return batTime;
|
|
}
|
|
if (UPower.displayDevice.state == UPowerDeviceState.FullyCharged) {
|
|
return "Full";
|
|
}
|
|
}
|
|
function batStatProc() {
|
|
return Math.round(UPower.displayDevice.percentage * 100) + "%";
|
|
}
|
|
|
|
Text {
|
|
id: batText
|
|
anchors.centerIn: parent
|
|
color: root.colFg
|
|
text: batStatProc() + " - " + getBatStat()
|
|
font { family: root.fontFamily; pixelSize: root.fontSize; bold: true }
|
|
}
|
|
}
|
|
}
|
|
Rectangle {
|
|
height: root.appletRadHeight
|
|
width: cpuText.paintedWidth + 25
|
|
radius: root.appletRadHeight
|
|
color: root.colAppBg
|
|
|
|
|
|
Text {
|
|
id: cpuText
|
|
anchors.centerIn: parent
|
|
text: "CPU: " + cpuUsage + "%"
|
|
color: root.colFg
|
|
font { family: root.fontFamily; pixelSize: root.fontSize; bold: true }
|
|
}
|
|
}
|
|
Rectangle {
|
|
height: root.appletRadHeight
|
|
width: ramText.paintedWidth + 28
|
|
radius: root.appletRadHeight
|
|
color: root.colAppBg
|
|
|
|
Text {
|
|
id: ramText
|
|
anchors.centerIn: parent
|
|
text: "RAM: " + ramUsage.toFixed(2) + " GiB"
|
|
color: root.colFg
|
|
font { family: root.fontFamily; pixelSize: root.fontSize; bold: true }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Row {
|
|
id: clockRow
|
|
Rectangle {
|
|
height: root.appletRadHeight
|
|
width: clock.paintedWidth + root.appletRadHeight
|
|
radius: root.appletRadHeight
|
|
color: root.colAppBg
|
|
|
|
Text {
|
|
id: clock
|
|
anchors.centerIn: parent
|
|
anchors.right: parent.right
|
|
text: Qt.formatDateTime(new Date(), "yyyy.MM.dd - HH:mm:ss")
|
|
color: root.colFg
|
|
font { family: root.fontFamily; pixelSize: root.fontSize; bold: true }
|
|
|
|
Timer {
|
|
interval: 1000
|
|
running: true
|
|
repeat: true
|
|
onTriggered: clock.text = Qt.formatDateTime(new Date(), "yyyy.MM.dd - HH:mm:ss")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Row {
|
|
id: trayWholeRow
|
|
rightPadding: 10
|
|
Item{
|
|
id: miscItem
|
|
implicitHeight: root.appletRadHeight
|
|
implicitWidth: trayRect.implicitWidth
|
|
visible: trayRepeater.count > 0
|
|
|
|
Rectangle {
|
|
id: trayRect
|
|
implicitHeight: root.appletRadHeight
|
|
implicitWidth: trayRow.implicitWidth + 10
|
|
radius: root.appletRadHeight
|
|
color: root.colAppBg
|
|
anchors.centerIn: parent
|
|
|
|
Row {
|
|
id: trayRow
|
|
spacing: root.appletSpacing
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.centerIn: parent
|
|
|
|
Repeater {
|
|
id: trayRepeater
|
|
model: SystemTray.items
|
|
|
|
MouseArea {
|
|
id: trayMouse
|
|
property var bar: trayMouse.QsWindow.window
|
|
required property SystemTrayItem modelData
|
|
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
implicitWidth: 16
|
|
implicitHeight: 16
|
|
|
|
onClicked: event => {
|
|
if (event.button === Qt.LeftButton) {
|
|
modelData.activate();
|
|
}
|
|
else if (modelData.hasMenu) {
|
|
menu.open();
|
|
}
|
|
}
|
|
|
|
QsMenuAnchor {
|
|
id: menu
|
|
menu: trayMouse.modelData.hasMenu ? trayMouse.modelData.menu : null
|
|
anchor.item: trayMouse
|
|
}
|
|
|
|
IconImage {
|
|
id: trayIcon
|
|
width: parent.implicitWidth
|
|
height: parent.implicitHeight
|
|
source: trayMouse.modelData.icon
|
|
anchors.centerIn: parent
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|