hefty: bar: workspace widget

This commit is contained in:
end-4
2026-02-05 12:49:36 +01:00
parent 24392e3791
commit 6f633122ed
14 changed files with 581 additions and 73 deletions
@@ -109,7 +109,8 @@ Singleton {
*/
function transparentize(color, percentage = 1) {
var c = Qt.color(color);
return Qt.rgba(c.r, c.g, c.b, c.a * (1 - percentage));
var a = c.a * (1 - clamp01(percentage));
return Qt.rgba(c.r, c.g, c.b, a);
}
/**
@@ -121,7 +122,7 @@ Singleton {
*/
function applyAlpha(color, alpha) {
var c = Qt.color(color);
var a = Math.max(0, Math.min(1, alpha));
var a = clamp01(alpha);
return Qt.rgba(c.r, c.g, c.b, a);
}
@@ -0,0 +1,16 @@
pragma Singleton
import Quickshell
Singleton {
id: root
/**
* Rounds the given number to the nearest even integer.
*
* @param {number} num - The number to round.
* @returns {number} The nearest even integer.
*/
function roundToEven(num) {
return Math.round(num / 2) * 2;
}
}
@@ -0,0 +1,59 @@
import QtQuick
import Quickshell.Wayland
import Quickshell.Hyprland
import qs.services
import qs.modules.common as C
NestableObject {
id: root
required property HyprlandMonitor monitor
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
readonly property int activeWorkspace: monitor?.activeWorkspace?.id
readonly property bool currentWorkspaceNotFake: activeWindow?.activated ?? false // Active empty workspace = fake. At least, that's how I like to call it.
readonly property int fakeWorkspace: currentWorkspaceNotFake ? -9999 : activeWorkspace
readonly property int shownCount: C.Config.options.bar.workspaces.shown
readonly property int group: Math.floor((activeWorkspace - 1) / shownCount)
property list<bool> occupied: []
property list<var> biggestWindow: occupied.map((_, index) => {
const wsId = getWorkspaceIdAt(index);
var biggestWindow = HyprlandData.biggestWindowForWorkspace(wsId);
return biggestWindow;
})
function getWorkspaceId(group, index) {
return group * root.shownCount + index + 1;
}
function getWorkspaceIdAt(index) {
return root.getWorkspaceId(root.group, index);
}
// Function to update workspaceOccupied
function updateWorkspaceOccupied() {
root.occupied = Array.from({
length: root.shownCount
}, (_, i) => {
const thisWorkspaceId = getWorkspaceId(root.group, i);
return Hyprland.workspaces.values.some(ws => ws.id === thisWorkspaceId);
});
}
// Occupied workspace updates
Component.onCompleted: updateWorkspaceOccupied()
Connections {
target: Hyprland.workspaces
function onValuesChanged() {
root.updateWorkspaceOccupied();
}
}
Connections {
target: Hyprland
function onFocusedWorkspaceChanged() {
root.updateWorkspaceOccupied();
}
}
onGroupChanged: {
updateWorkspaceOccupied();
}
}
@@ -0,0 +1,15 @@
import QtQuick
import org.kde.kirigami as Kirigami
import qs.services
import qs.modules.common
Kirigami.Icon {
id: root
property real implicitSize: 26
implicitWidth: implicitSize
implicitHeight: implicitSize
roundToIconSize: false
animated: true // It's just fading from one icon to another
}
@@ -1,7 +1,7 @@
import QtQuick
Rectangle {
property double diameter
property real diameter
implicitWidth: diameter
implicitHeight: diameter
@@ -0,0 +1,9 @@
import QtQuick
import QtQuick.Effects
// Note: You still have to set sizes yourself
MultiEffect {
maskEnabled: true
maskThresholdMin: 0.5
maskSpreadAtMin: 1
}
@@ -0,0 +1,19 @@
import QtQuick
Rectangle {
id: root
// https://m3.material.io/foundations/interaction/states/state-layers
enum State {
Hover, Focus, Press, Drag
}
property var state: StateLayer.State.Hover
opacity: switch(state) {
case StateLayer.State.Hover: return 0.08;
case StateLayer.State.Focus: return 0.1;
case StateLayer.State.Press: return 0.1;
case StateLayer.State.Drag: return 0.16;
default: return 0;
}
}
@@ -0,0 +1,53 @@
pragma ComponentBehavior: Bound
import QtQuick
Rectangle {
id: root
property bool hover: false
property bool press: false
property bool drag: false
property color contentColor: Appearance.m3colors.m3onBackground
color: "transparent"
FadeLoader {
id: hoverLoader
anchors.fill: parent
shown: root.hover
sourceComponent: StateLayer {
radius: root.radius
state: StateLayer.State.Hover
color: root.contentColor
}
}
FadeLoader {
id: focusLoader
anchors.fill: parent
shown: root.focus
sourceComponent: StateLayer {
radius: root.radius
state: StateLayer.State.Focus
color: root.contentColor
}
}
FadeLoader {
id: pressLoader
anchors.fill: parent
shown: root.press
sourceComponent: StateLayer {
radius: root.radius
state: StateLayer.State.Press
color: root.contentColor
}
}
FadeLoader {
id: dragLoader
anchors.fill: parent
shown: root.drag
sourceComponent: StateLayer {
radius: root.radius
state: StateLayer.State.Drag
color: root.contentColor
}
}
}