resource widget is broken lol

This commit is contained in:
Zacharias-Brohn
2026-03-02 17:09:39 +01:00
parent 9065d693ef
commit 7451c52684
8 changed files with 263 additions and 224 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ Item {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.tPalette.m3surfaceContainer
height: 22
implicitHeight: root.parent.height - ((Appearance.padding.small - 1) * 2)
radius: height / 2
}
+1 -1
View File
@@ -25,7 +25,7 @@ Item {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: 22
implicitHeight: root.parent.height - ((Appearance.padding.small - 1) * 2)
radius: Appearance.rounding.full
}
+116
View File
@@ -0,0 +1,116 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes
import qs.Components
import qs.Config
Item {
id: root
property color borderColor: warning ? DynamicColors.palette.m3onError : mainColor
required property color mainColor
required property double percentage
property bool shown: true
property color usageColor: warning ? DynamicColors.palette.m3error : mainColor
property bool warning: percentage * 100 >= warningThreshold
property int warningThreshold: 100
clip: true
implicitHeight: 22
implicitWidth: resourceRowLayout.x < 0 ? 0 : resourceRowLayout.implicitWidth
visible: width > 0 && height > 0
Behavior on percentage {
NumberAnimation {
duration: 300
easing.type: Easing.InOutQuad
}
}
RowLayout {
id: resourceRowLayout
spacing: 2
x: shown ? 0 : -resourceRowLayout.width
anchors {
verticalCenter: parent.verticalCenter
}
Item {
Layout.alignment: Qt.AlignVCenter
implicitHeight: root.implicitHeight
implicitWidth: 14
Rectangle {
id: backgroundCircle
anchors.centerIn: parent
border.color: "#404040"
border.width: 1
color: "#40000000"
height: 14
radius: height / 2
width: 14
}
Shape {
anchors.fill: backgroundCircle
preferredRendererType: Shape.CurveRenderer
smooth: true
ShapePath {
fillColor: root.usageColor
startX: backgroundCircle.width / 2
startY: backgroundCircle.height / 2
strokeWidth: 0
Behavior on fillColor {
CAnim {
}
}
PathLine {
x: backgroundCircle.width / 2
y: 0 + (1 / 2)
}
PathAngleArc {
centerX: backgroundCircle.width / 2
centerY: backgroundCircle.height / 2
radiusX: backgroundCircle.width / 2 - (1 / 2)
radiusY: backgroundCircle.height / 2 - (1 / 2)
startAngle: -90
sweepAngle: 360 * root.percentage
}
PathLine {
x: backgroundCircle.width / 2
y: backgroundCircle.height / 2
}
}
ShapePath {
capStyle: ShapePath.FlatCap
fillColor: "transparent"
strokeColor: root.borderColor
strokeWidth: 1
Behavior on strokeColor {
CAnim {
}
}
PathAngleArc {
centerX: backgroundCircle.width / 2
centerY: backgroundCircle.height / 2
radiusX: backgroundCircle.width / 2 - (1 / 2)
radiusY: backgroundCircle.height / 2 - (1 / 2)
startAngle: -90
sweepAngle: 360 * root.percentage
}
}
}
}
}
}
+47 -85
View File
@@ -7,110 +7,72 @@ import qs.Config
Item {
id: root
property color accentColor: DynamicColors.palette.m3primary
property real animatedPercentage: 0
readonly property real arcStartAngle: 0.75 * Math.PI
readonly property real arcSweep: 1.5 * Math.PI
property color borderColor: warning ? DynamicColors.palette.m3onError : mainColor
property string icon
required property color mainColor
required property double percentage
property bool shown: true
property string subtitle
property string title
property color usageColor: warning ? DynamicColors.palette.m3error : mainColor
property bool warning: percentage * 100 >= warningThreshold
property int warningThreshold: 100
clip: true
implicitHeight: 22
implicitWidth: resourceRowLayout.x < 0 ? 0 : resourceRowLayout.implicitWidth
implicitHeight: root.parent.height
implicitWidth: root.parent.width
percentage: 0
visible: width > 0 && height > 0
Behavior on percentage {
NumberAnimation {
duration: 300
easing.type: Easing.InOutQuad
}
}
Canvas {
id: gaugeCanvas
RowLayout {
id: resourceRowLayout
anchors.centerIn: parent
height: width
width: Math.min(parent.width, parent.height)
spacing: 2
x: shown ? 0 : -resourceRowLayout.width
anchors {
verticalCenter: parent.verticalCenter
Component.onCompleted: requestPaint()
onPaint: {
const ctx = getContext("2d");
ctx.reset();
const cx = width / 2;
const cy = height / 2;
const radius = (Math.min(width, height) - 12) / 2;
const lineWidth = 3;
ctx.beginPath();
ctx.arc(cx, cy, radius, root.arcStartAngle, root.arcStartAngle + root.arcSweep);
ctx.lineWidth = lineWidth;
ctx.lineCap = "round";
ctx.strokeStyle = DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2);
ctx.stroke();
if (root.animatedPercentage > 0) {
ctx.beginPath();
ctx.arc(cx, cy, radius, root.arcStartAngle, root.arcStartAngle + root.arcSweep * root.animatedPercentage);
ctx.lineWidth = lineWidth;
ctx.lineCap = "round";
ctx.strokeStyle = root.accentColor;
ctx.stroke();
}
}
Item {
Layout.alignment: Qt.AlignVCenter
implicitHeight: root.implicitHeight
implicitWidth: 14
Rectangle {
id: backgroundCircle
anchors.centerIn: parent
border.color: "#404040"
border.width: 1
color: "#40000000"
height: 14
radius: height / 2
width: 14
Connections {
function onAnimatedPercentageChanged() {
gaugeCanvas.requestPaint();
}
Shape {
anchors.fill: backgroundCircle
preferredRendererType: Shape.CurveRenderer
smooth: true
target: root
}
ShapePath {
fillColor: root.usageColor
startX: backgroundCircle.width / 2
startY: backgroundCircle.height / 2
strokeWidth: 0
Behavior on fillColor {
CAnim {
}
}
PathLine {
x: backgroundCircle.width / 2
y: 0 + (1 / 2)
}
PathAngleArc {
centerX: backgroundCircle.width / 2
centerY: backgroundCircle.height / 2
radiusX: backgroundCircle.width / 2 - (1 / 2)
radiusY: backgroundCircle.height / 2 - (1 / 2)
startAngle: -90
sweepAngle: 360 * root.percentage
}
PathLine {
x: backgroundCircle.width / 2
y: backgroundCircle.height / 2
}
}
ShapePath {
capStyle: ShapePath.FlatCap
fillColor: "transparent"
strokeColor: root.borderColor
strokeWidth: 1
Behavior on strokeColor {
CAnim {
}
}
PathAngleArc {
centerX: backgroundCircle.width / 2
centerY: backgroundCircle.height / 2
radiusX: backgroundCircle.width / 2 - (1 / 2)
radiusY: backgroundCircle.height / 2 - (1 / 2)
startAngle: -90
sweepAngle: 360 * root.percentage
}
}
Connections {
function onPaletteChanged() {
gaugeCanvas.requestPaint();
}
target: DynamicColors
}
}
}
+3 -2
View File
@@ -14,15 +14,16 @@ Item {
required property PersistentProperties visibilities
anchors.bottom: parent.bottom
anchors.top: parent.top
clip: true
implicitHeight: 34
implicitWidth: rowLayout.implicitWidth + Appearance.padding.small * 2
CustomRect {
id: backgroundRect
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: 22
implicitHeight: root.parent.height - ((Appearance.padding.small - 1) * 2)
radius: height / 2
anchors {
+1 -1
View File
@@ -19,7 +19,7 @@ Item {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: 22
implicitHeight: root.parent.height - ((Appearance.padding.small - 1) * 2)
radius: height / 2
}
-128
View File
@@ -1,128 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Effects
import Quickshell
import Quickshell.Hyprland
import qs.Config
import qs.Components
Item {
id: itemRoot
required property PanelWindow bar
anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: workspacesRow.implicitWidth + 10
Behavior on implicitWidth {
NumberAnimation {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
Rectangle {
id: root
property HyprlandMonitor monitor: Hyprland.monitorFor(itemRoot.bar?.screen)
function shouldShow(monitor) {
Hyprland.refreshWorkspaces();
Hyprland.refreshMonitors();
if (monitor === root.monitor) {
return true;
} else {
return false;
}
}
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: 22
radius: height / 2
Behavior on color {
CAnim {
}
}
RowLayout {
id: workspacesRow
anchors.left: parent.left
anchors.leftMargin: 6
anchors.verticalCenter: parent.verticalCenter
spacing: 8
Repeater {
model: Hyprland.workspaces
RowLayout {
id: workspaceIndicator
required property var modelData
visible: root.shouldShow(workspaceIndicator.modelData.monitor)
CustomText {
color: workspaceIndicator.modelData.id === Hyprland.focusedWorkspace.id ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant
font.pointSize: 12
text: workspaceIndicator.modelData.name
visible: true
}
Rectangle {
border.color: workspaceIndicator.modelData.id === Hyprland.focusedWorkspace.id ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant
border.width: 1
color: "transparent"
implicitHeight: 14
implicitWidth: 14
opacity: 1.0
radius: height / 2
scale: 1.0
Behavior on border.color {
ColorAnimation {
duration: 150
easing.type: Easing.InOutQuad
}
}
NumberAnimation on opacity {
duration: 200
from: 0.0
to: 1.0
}
NumberAnimation on scale {
duration: 300
easing.type: Easing.OutBack
from: 0.0
to: 1.0
}
CustomRect {
anchors.centerIn: parent
color: workspaceIndicator.modelData.id === Hyprland.focusedWorkspace.id ? DynamicColors.palette.m3primary : "transparent"
implicitHeight: 8
implicitWidth: 8
radius: implicitHeight / 2
}
MouseArea {
anchors.fill: parent
onClicked: {
workspaceIndicator.modelData.activate();
}
}
}
}
}
}
}
}
+94 -6
View File
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import Quickshell.Hyprland
import qs.Config
@@ -14,7 +15,7 @@ Item {
required property PanelWindow bar
readonly property int effectiveActiveWorkspaceId: monitor?.activeWorkspace?.id ?? 1
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.bar.screen)
property int workspaceButtonWidth: rect.implicitHeight - root.activeWorkspaceMargin * 2
property int workspaceButtonWidth: bgRect.implicitHeight - root.activeWorkspaceMargin * 2
property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown
readonly property list<var> workspaces: Hyprland.workspaces.values.filter(w => w.monitor === root.monitor)
readonly property int workspacesShown: workspaces.length
@@ -29,7 +30,7 @@ Item {
}
CustomRect {
id: rect
id: bgRect
anchors.left: parent.left
anchors.right: parent.right
@@ -80,17 +81,17 @@ Item {
implicitHeight: indicator.indicatorThickness
implicitWidth: indicator.indicatorThickness
width: workspaceButtonWidth
width: root.workspaceButtonWidth
background: Item {
id: workspaceButtonBackground
implicitHeight: workspaceButtonWidth
implicitWidth: workspaceButtonWidth
implicitHeight: root.workspaceButtonWidth
implicitWidth: root.workspaceButtonWidth
CustomText {
anchors.centerIn: parent
color: (root.effectiveActiveWorkspaceId === button.modelData.id) ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondaryContainer
color: DynamicColors.palette.m3onSecondaryContainer
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: button.modelData.name
@@ -105,5 +106,92 @@ Item {
}
}
}
Item {
id: activeTextSource
anchors.fill: parent
anchors.margins: root.activeWorkspaceMargin
layer.enabled: true
visible: false
z: 4
Grid {
anchors.fill: parent
columnSpacing: 0
columns: root.workspacesShown
rowSpacing: 0
rows: 1
Repeater {
model: root.workspaces
Item {
id: activeWorkspace
required property int index
required property HyprlandWorkspace modelData
implicitHeight: indicator.indicatorThickness
implicitWidth: indicator.indicatorThickness
width: root.workspaceButtonWidth
CustomText {
anchors.centerIn: parent
color: DynamicColors.palette.m3onPrimary
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: activeWorkspace.modelData.name
verticalAlignment: Text.AlignVCenter
}
}
}
}
}
ShaderEffectSource {
id: activeTextTex
anchors.fill: bgRect
anchors.margins: root.activeWorkspaceMargin
hideSource: true
live: true
recursive: true
sourceItem: activeTextSource
}
Item {
id: indicatorMask
anchors.fill: bgRect
visible: false
CustomRect {
color: "white"
height: indicator.height
radius: indicator.radius
width: indicator.width
x: indicator.x
y: indicator.y
}
}
ShaderEffectSource {
id: indicatorMaskEffect
anchors.fill: activeTextSource
live: true
sourceItem: indicatorMask
visible: false
}
MultiEffect {
anchors.fill: activeTextSource
maskEnabled: true
maskInverted: false
maskSource: indicatorMaskEffect
source: activeTextTex
z: 5
}
}
}