mirror of
https://github.com/danbulant/dotfiles
synced 2026-05-19 04:18:55 +00:00
270 lines
12 KiB
QML
270 lines
12 KiB
QML
import "root:/"
|
|
import "root:/services/"
|
|
import "root:/modules/common"
|
|
import "root:/modules/common/widgets"
|
|
import "root:/modules/common/functions/color_utils.js" as ColorUtils
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Io
|
|
import Quickshell.Widgets
|
|
import Qt5Compat.GraphicalEffects
|
|
|
|
Item {
|
|
required property var bar
|
|
property bool borderless: ConfigOptions.bar.borderless
|
|
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen)
|
|
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
|
|
|
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / ConfigOptions.bar.workspaces.shown)
|
|
property list<bool> workspaceOccupied: []
|
|
property int widgetPadding: 4
|
|
property int workspaceButtonWidth: 26
|
|
property real workspaceIconSize: workspaceButtonWidth * 0.69
|
|
property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55
|
|
property real workspaceIconOpacityShrinked: 1
|
|
property real workspaceIconMarginShrinked: -4
|
|
property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % ConfigOptions.bar.workspaces.shown
|
|
|
|
// Function to update workspaceOccupied
|
|
function updateWorkspaceOccupied() {
|
|
workspaceOccupied = Array.from({ length: ConfigOptions.bar.workspaces.shown }, (_, i) => {
|
|
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * ConfigOptions.bar.workspaces.shown + i + 1);
|
|
})
|
|
}
|
|
|
|
// Initialize workspaceOccupied when the component is created
|
|
Component.onCompleted: updateWorkspaceOccupied()
|
|
|
|
// Listen for changes in Hyprland.workspaces.values
|
|
Connections {
|
|
target: Hyprland.workspaces
|
|
function onValuesChanged() {
|
|
updateWorkspaceOccupied();
|
|
}
|
|
}
|
|
|
|
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
|
|
implicitHeight: 40
|
|
|
|
// Scroll to switch workspaces
|
|
WheelHandler {
|
|
onWheel: (event) => {
|
|
if (event.angleDelta.y < 0)
|
|
Hyprland.dispatch(`workspace r+1`);
|
|
else if (event.angleDelta.y > 0)
|
|
Hyprland.dispatch(`workspace r-1`);
|
|
}
|
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.BackButton
|
|
onPressed: (event) => {
|
|
if (event.button === Qt.BackButton) {
|
|
Hyprland.dispatch(`togglespecialworkspace`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Workspaces - background
|
|
RowLayout {
|
|
id: rowLayout
|
|
z: 1
|
|
|
|
spacing: 0
|
|
anchors.fill: parent
|
|
implicitHeight: 40
|
|
|
|
Repeater {
|
|
model: ConfigOptions.bar.workspaces.shown
|
|
|
|
Rectangle {
|
|
z: 1
|
|
implicitWidth: workspaceButtonWidth
|
|
implicitHeight: workspaceButtonWidth
|
|
radius: Appearance.rounding.full
|
|
property var leftOccupied: (workspaceOccupied[index-1] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index))
|
|
property var rightOccupied: (workspaceOccupied[index+1] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index+2))
|
|
property var radiusLeft: leftOccupied ? 0 : Appearance.rounding.full
|
|
property var radiusRight: rightOccupied ? 0 : Appearance.rounding.full
|
|
|
|
topLeftRadius: radiusLeft
|
|
bottomLeftRadius: radiusLeft
|
|
topRightRadius: radiusRight
|
|
bottomRightRadius: radiusRight
|
|
|
|
color: ColorUtils.transparentize(Appearance.m3colors.m3secondaryContainer, 0.4)
|
|
opacity: (workspaceOccupied[index] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index+1)) ? 1 : 0
|
|
|
|
Behavior on opacity {
|
|
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
|
}
|
|
Behavior on radiusLeft {
|
|
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
|
}
|
|
|
|
Behavior on radiusRight {
|
|
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Active workspace
|
|
Rectangle {
|
|
z: 2
|
|
// Make active ws indicator, which has a brighter color, smaller to look like it is of the same size as ws occupied highlight
|
|
property real activeWorkspaceMargin: 2
|
|
implicitHeight: workspaceButtonWidth - activeWorkspaceMargin * 2
|
|
radius: Appearance.rounding.full
|
|
color: Appearance.colors.colPrimary
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
property real idx1: workspaceIndexInGroup
|
|
property real idx2: workspaceIndexInGroup
|
|
x: Math.min(idx1, idx2) * workspaceButtonWidth + activeWorkspaceMargin
|
|
implicitWidth: Math.abs(idx1 - idx2) * workspaceButtonWidth + workspaceButtonWidth - activeWorkspaceMargin * 2
|
|
|
|
Behavior on activeWorkspaceMargin {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
Behavior on idx1 { // Leading anim
|
|
NumberAnimation {
|
|
duration: 100
|
|
easing.type: Easing.OutSine
|
|
}
|
|
}
|
|
Behavior on idx2 { // Following anim
|
|
NumberAnimation {
|
|
duration: 300
|
|
easing.type: Easing.OutSine
|
|
}
|
|
}
|
|
}
|
|
|
|
// Workspaces - numbers
|
|
RowLayout {
|
|
id: rowLayoutNumbers
|
|
z: 3
|
|
|
|
spacing: 0
|
|
anchors.fill: parent
|
|
implicitHeight: 40
|
|
|
|
Repeater {
|
|
model: ConfigOptions.bar.workspaces.shown
|
|
|
|
Button {
|
|
id: button
|
|
property int workspaceValue: workspaceGroup * ConfigOptions.bar.workspaces.shown + index + 1
|
|
Layout.fillHeight: true
|
|
onPressed: Hyprland.dispatch(`workspace ${workspaceValue}`)
|
|
width: workspaceButtonWidth
|
|
|
|
background: Item {
|
|
id: workspaceButtonBackground
|
|
implicitWidth: workspaceButtonWidth
|
|
implicitHeight: workspaceButtonWidth
|
|
property var biggestWindow: {
|
|
const windowsInThisWorkspace = HyprlandData.windowList.filter(w => w.workspace.id == button.workspaceValue)
|
|
return windowsInThisWorkspace.reduce((maxWin, win) => {
|
|
const maxArea = (maxWin?.size?.[0] ?? 0) * (maxWin?.size?.[1] ?? 0)
|
|
const winArea = (win?.size?.[0] ?? 0) * (win?.size?.[1] ?? 0)
|
|
return winArea > maxArea ? win : maxWin
|
|
}, null)
|
|
}
|
|
property var mainAppIconSource: Quickshell.iconPath(AppSearch.guessIcon(biggestWindow?.class), "image-missing")
|
|
|
|
StyledText { // Workspace number text
|
|
opacity: GlobalStates.workspaceShowNumbers
|
|
|| ((ConfigOptions?.bar.workspaces.alwaysShowNumbers && (!ConfigOptions?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || GlobalStates.workspaceShowNumbers))
|
|
|| (GlobalStates.workspaceShowNumbers && !ConfigOptions?.bar.workspaces.showAppIcons)
|
|
) ? 1 : 0
|
|
z: 3
|
|
|
|
anchors.centerIn: parent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.pixelSize: Appearance.font.pixelSize.small - ((text.length - 1) * (text !== "10") * 2)
|
|
text: `${button.workspaceValue}`
|
|
elide: Text.ElideRight
|
|
color: (monitor.activeWorkspace?.id == button.workspaceValue) ?
|
|
Appearance.m3colors.m3onPrimary :
|
|
(workspaceOccupied[index] ? Appearance.m3colors.m3onSecondaryContainer :
|
|
Appearance.colors.colOnLayer1Inactive)
|
|
|
|
Behavior on opacity {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
}
|
|
Rectangle { // Dot instead of ws number
|
|
opacity: (ConfigOptions?.bar.workspaces.alwaysShowNumbers
|
|
|| GlobalStates.workspaceShowNumbers
|
|
|| (ConfigOptions?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow)
|
|
) ? 0 : 1
|
|
visible: opacity > 0
|
|
anchors.centerIn: parent
|
|
width: workspaceButtonWidth * 0.18
|
|
height: width
|
|
radius: width / 2
|
|
color: (monitor.activeWorkspace?.id == button.workspaceValue) ?
|
|
Appearance.m3colors.m3onPrimary :
|
|
(workspaceOccupied[index] ? Appearance.m3colors.m3onSecondaryContainer :
|
|
Appearance.colors.colOnLayer1Inactive)
|
|
|
|
Behavior on opacity {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
}
|
|
Item { // Main app icon
|
|
anchors.centerIn: parent
|
|
width: workspaceButtonWidth
|
|
height: workspaceButtonWidth
|
|
opacity: !ConfigOptions?.bar.workspaces.showAppIcons ? 0 :
|
|
(workspaceButtonBackground.biggestWindow && !GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
|
|
1 : workspaceButtonBackground.biggestWindow ? workspaceIconOpacityShrinked : 0
|
|
visible: opacity > 0
|
|
IconImage {
|
|
id: mainAppIcon
|
|
anchors.bottom: parent.bottom
|
|
anchors.right: parent.right
|
|
anchors.bottomMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
|
|
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
|
anchors.rightMargin: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ?
|
|
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
|
|
|
source: workspaceButtonBackground.mainAppIconSource
|
|
implicitSize: (!GlobalStates.workspaceShowNumbers && ConfigOptions?.bar.workspaces.showAppIcons) ? workspaceIconSize : workspaceIconSizeShrinked
|
|
|
|
Behavior on opacity {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
Behavior on anchors.bottomMargin {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
Behavior on anchors.rightMargin {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
Behavior on implicitSize {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|