mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-08-04 15:03:06 +10:00
bar: workspaces from hefty
This commit is contained in:
@@ -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,63 @@
|
|||||||
|
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 var liveMonitorData: HyprlandData.monitors.find(m => m.id === monitor.id)
|
||||||
|
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
||||||
|
readonly property int activeWorkspace: monitor?.activeWorkspace?.id ?? 1
|
||||||
|
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)
|
||||||
|
readonly property var specialWorkspace: liveMonitorData?.specialWorkspace
|
||||||
|
readonly property string specialWorkspaceName: specialWorkspace?.name.replace("special:", "") ?? "special"
|
||||||
|
readonly property bool specialWorkspaceActive: specialWorkspaceName !== ""
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
// A type that's both capable of being rows and columns
|
||||||
|
// Qt Row is just a locked down Grid smh
|
||||||
|
// Calling it a Box because that's how row-or-column widget is called in Gtk
|
||||||
|
Grid {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool vertical: false
|
||||||
|
columns: vertical ? 1 : -1
|
||||||
|
rows: vertical ? -1 : 1
|
||||||
|
|
||||||
|
property alias spacing: root.rowSpacing
|
||||||
|
columnSpacing: rowSpacing
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
// Box, Layout version
|
||||||
|
// A type that's both capable of being rows and columns
|
||||||
|
// Qt Row is just a locked down Grid smh
|
||||||
|
// Calling it a Box because that's how row-or-column widget is called in Gtk
|
||||||
|
GridLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool vertical: false
|
||||||
|
columns: vertical ? 1 : -1
|
||||||
|
rows: vertical ? -1 : 1
|
||||||
|
|
||||||
|
property alias spacing: root.rowSpacing
|
||||||
|
columnSpacing: rowSpacing
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
// MouseArea that contains good defaults for buttons
|
||||||
|
MouseArea {
|
||||||
|
id: root
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import qs.modules.common
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
property color sourceColor: "black"
|
||||||
|
|
||||||
|
colorization: 1
|
||||||
|
brightness: 1 - sourceColor.hslLightness
|
||||||
|
|
||||||
|
Behavior on colorizationColor {
|
||||||
|
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
radius: Math.min(width, height) / 2
|
||||||
|
}
|
||||||
@@ -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,66 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import qs.modules.common as C
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool hover: false
|
||||||
|
property bool press: false
|
||||||
|
property bool drag: false
|
||||||
|
property color contentColor: C.Appearance.m3colors.m3onBackground
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
FadeLoader {
|
||||||
|
id: hoverLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
shown: root.hover
|
||||||
|
sourceComponent: StateLayer {
|
||||||
|
state: StateLayer.State.Hover
|
||||||
|
color: root.contentColor
|
||||||
|
topLeftRadius: root.topLeftRadius
|
||||||
|
topRightRadius: root.topRightRadius
|
||||||
|
bottomLeftRadius: root.bottomLeftRadius
|
||||||
|
bottomRightRadius: root.bottomRightRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FadeLoader {
|
||||||
|
id: focusLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
shown: root.focus
|
||||||
|
sourceComponent: StateLayer {
|
||||||
|
state: StateLayer.State.Focus
|
||||||
|
color: root.contentColor
|
||||||
|
topLeftRadius: root.topLeftRadius
|
||||||
|
topRightRadius: root.topRightRadius
|
||||||
|
bottomLeftRadius: root.bottomLeftRadius
|
||||||
|
bottomRightRadius: root.bottomRightRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FadeLoader {
|
||||||
|
id: pressLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
shown: root.press
|
||||||
|
sourceComponent: StateLayer {
|
||||||
|
state: StateLayer.State.Press
|
||||||
|
color: root.contentColor
|
||||||
|
topLeftRadius: root.topLeftRadius
|
||||||
|
topRightRadius: root.topRightRadius
|
||||||
|
bottomLeftRadius: root.bottomLeftRadius
|
||||||
|
bottomRightRadius: root.bottomRightRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FadeLoader {
|
||||||
|
id: dragLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
shown: root.drag
|
||||||
|
sourceComponent: StateLayer {
|
||||||
|
state: StateLayer.State.Drag
|
||||||
|
color: root.contentColor
|
||||||
|
topLeftRadius: root.topLeftRadius
|
||||||
|
topRightRadius: root.topRightRadius
|
||||||
|
bottomLeftRadius: root.bottomLeftRadius
|
||||||
|
bottomRightRadius: root.bottomRightRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.modules.common as C
|
||||||
|
|
||||||
|
// This is to enable future fancy styles for rectangles. Some ideas:
|
||||||
|
// - normal rounded rect
|
||||||
|
// - osk.sh
|
||||||
|
// - 3d
|
||||||
|
// i hope i actually get to this and not shrimply forget
|
||||||
|
// aaaaa i realized for this to work i would have to make this for shapes in general not just rects
|
||||||
|
Rectangle {
|
||||||
|
enum ContentLayer { Background, Pane, Group, Subgroup, Control }
|
||||||
|
property var contentLayer: StyledRectangle.ContentLayer.Pane // To appropriately add effects like shadows/3d-ization
|
||||||
|
|
||||||
|
color: switch(contentLayer) {
|
||||||
|
case StyledRectangle.ContentLayer.Background: C.Appearance.colors.colLayer0;
|
||||||
|
case StyledRectangle.ContentLayer.Pane: C.Appearance.colors.colLayer1;
|
||||||
|
case StyledRectangle.ContentLayer.Group: C.Appearance.colors.colLayer2;
|
||||||
|
case StyledRectangle.ContentLayer.Subgroup: C.Appearance.colors.colLayer3;
|
||||||
|
case StyledRectangle.ContentLayer.Control: C.Appearance.colors.colLayer4;
|
||||||
|
default: C.Appearance.colors.colLayer1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
import qs
|
import qs
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
@@ -5,316 +6,429 @@ import qs.modules.common.models
|
|||||||
import qs.modules.common.widgets
|
import qs.modules.common.widgets
|
||||||
import qs.modules.common.functions
|
import qs.modules.common.functions
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import Quickshell.Widgets
|
|
||||||
import Qt5Compat.GraphicalEffects
|
|
||||||
|
|
||||||
Item {
|
ButtonMouseArea {
|
||||||
id: root
|
id: root
|
||||||
property bool vertical: false
|
|
||||||
property bool borderless: Config.options.bar.borderless
|
|
||||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.QsWindow.window?.screen)
|
|
||||||
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
|
||||||
readonly property int effectiveActiveWorkspaceId: monitor?.activeWorkspace?.id ?? 1
|
|
||||||
|
|
||||||
readonly property int workspacesShown: Config.options.bar.workspaces.shown
|
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.QsWindow.window?.screen)
|
||||||
readonly property int workspaceGroup: Math.floor((effectiveActiveWorkspaceId - 1) / root.workspacesShown)
|
WorkspaceModel {
|
||||||
property list<bool> workspaceOccupied: []
|
id: wsModel
|
||||||
property int widgetPadding: 4
|
monitor: root.monitor
|
||||||
property int workspaceButtonWidth: 26
|
}
|
||||||
|
|
||||||
|
property bool vertical: Config.options.bar.vertical
|
||||||
|
property bool superPressAndHeld: false // Relevant modifications at bottom of file
|
||||||
|
|
||||||
|
property real workspaceButtonWidth: 26
|
||||||
property real activeWorkspaceMargin: 2
|
property real activeWorkspaceMargin: 2
|
||||||
|
property real activeWorkspaceSize: workspaceButtonWidth - activeWorkspaceMargin * 2
|
||||||
property real workspaceIconSize: workspaceButtonWidth * 0.69
|
property real workspaceIconSize: workspaceButtonWidth * 0.69
|
||||||
property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55
|
property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55
|
||||||
property real workspaceIconOpacityShrinked: 1
|
property real workspaceIconOpacityShrinked: 1
|
||||||
property real workspaceIconMarginShrinked: -4
|
property real workspaceIconMarginShrinked: -4
|
||||||
property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown
|
property int workspaceIndexInGroup: (monitor?.activeWorkspace?.id - 1) % wsModel.shownCount
|
||||||
|
property real specialTextSize: workspaceButtonWidth * 0.5
|
||||||
|
|
||||||
property bool showNumbers: false
|
Layout.alignment: vertical ? Qt.AlignHCenter : Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: vertical
|
||||||
|
Layout.fillHeight: !vertical
|
||||||
|
readonly property real barThickness: vertical ? Appearance.sizes.verticalBarWidth : Appearance.sizes.barHeight
|
||||||
|
implicitWidth: vertical ? barThickness : occupiedIndicators.implicitWidth
|
||||||
|
implicitHeight: vertical ? occupiedIndicators.implicitHeight : barThickness
|
||||||
|
|
||||||
|
property real specialBlur: (wsModel.specialWorkspaceActive && !containsMouse) ? 1 : 0
|
||||||
|
Behavior on specialBlur {
|
||||||
|
animation: Appearance.animation.elementMoveSmall.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interactions
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
hoverEnabled: true
|
||||||
|
property int hoverIndex: {
|
||||||
|
const position = root.vertical ? mouseY : mouseX;
|
||||||
|
return Math.floor(position / root.workspaceButtonWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchWorkspaceToHovered() {
|
||||||
|
Hyprland.dispatch(`hl.dsp.focus({workspace = ${wsModel.getWorkspaceIdAt(hoverIndex)}})`);
|
||||||
|
}
|
||||||
|
onPressed: mouse => {
|
||||||
|
if (mouse.button == Qt.LeftButton)
|
||||||
|
switchWorkspaceToHovered();
|
||||||
|
else if (mouse.button == Qt.RightButton)
|
||||||
|
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
|
||||||
|
}
|
||||||
|
onWheel: event => {
|
||||||
|
if (event.angleDelta.y < 0)
|
||||||
|
Hyprland.dispatch(`hl.dsp.focus({workspace = "r+1"})`);
|
||||||
|
else if (event.angleDelta.y > 0)
|
||||||
|
Hyprland.dispatch(`hl.dsp.focus({workspace = "r-1"})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indications
|
||||||
|
Item {
|
||||||
|
id: regularWorkspaces
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
scale: 1 - 0.08 * root.specialBlur
|
||||||
|
layer.smooth: true
|
||||||
|
layer.enabled: root.specialBlur > 0
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
brightness: -0.1 * root.specialBlur
|
||||||
|
blurEnabled: true
|
||||||
|
blur: root.specialBlur
|
||||||
|
blurMax: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////// Occupied indicators ///////////////////
|
||||||
|
StyledRectangle {
|
||||||
|
id: occupiedIndicatorsBg
|
||||||
|
anchors.fill: parent
|
||||||
|
contentLayer: StyledRectangle.ContentLayer.Group
|
||||||
|
color: ColorUtils.transparentize(Appearance.m3colors.m3secondaryContainer, 0.4)
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkspaceLayout {
|
||||||
|
id: occupiedIndicators
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: wsModel.shownCount
|
||||||
|
delegate: Item {
|
||||||
|
id: wsBg
|
||||||
|
required property int index
|
||||||
|
readonly property int wsId: wsModel.getWorkspaceIdAt(index)
|
||||||
|
property bool currentOccupied: wsModel.occupied[index] && wsId != wsModel.fakeWorkspace
|
||||||
|
property bool previousOccupied: index > 0 && wsModel.occupied[index - 1] && (wsId - 1) != wsModel.fakeWorkspace
|
||||||
|
property bool nextOccupied: index < wsModel.shownCount - 1 && wsModel.occupied[index + 1] && (wsId + 1) != wsModel.fakeWorkspace
|
||||||
|
implicitWidth: root.workspaceButtonWidth
|
||||||
|
implicitHeight: root.workspaceButtonWidth
|
||||||
|
|
||||||
|
// The idea: over-stretch to occupied sides, animate this for a smooth transition.
|
||||||
|
// masking already prevents weird overlaps
|
||||||
|
Pill {
|
||||||
|
property real undirectionalWidth: root.workspaceButtonWidth * wsBg.currentOccupied
|
||||||
|
property real undirectionalLength: root.workspaceButtonWidth * (1 + 0.5 * wsBg.previousOccupied + 0.5 * wsBg.nextOccupied) * currentOccupied
|
||||||
|
property real undirectionalOffset: (!wsBg.currentOccupied ? 0.5 : -0.5 * wsBg.previousOccupied) * root.workspaceButtonWidth
|
||||||
|
anchors.verticalCenter: root.vertical ? undefined : parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: root.vertical ? parent.horizontalCenter : undefined
|
||||||
|
x: root.vertical ? 0 : undirectionalOffset
|
||||||
|
y: root.vertical ? undirectionalOffset : 0
|
||||||
|
implicitWidth: root.vertical ? undirectionalWidth : undirectionalLength
|
||||||
|
implicitHeight: root.vertical ? undirectionalLength : undirectionalWidth
|
||||||
|
|
||||||
|
Behavior on undirectionalWidth {
|
||||||
|
animation: Appearance.animation.elementMoveSmall.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on undirectionalLength {
|
||||||
|
animation: Appearance.animation.elementMoveSmall.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on undirectionalOffset {
|
||||||
|
animation: Appearance.animation.elementMoveSmall.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaskMultiEffect {
|
||||||
|
id: occupiedIndicatorsMultiEffect
|
||||||
|
z: 1
|
||||||
|
anchors.centerIn: parent
|
||||||
|
implicitWidth: occupiedIndicators.implicitWidth
|
||||||
|
implicitHeight: occupiedIndicators.implicitHeight
|
||||||
|
source: occupiedIndicatorsBg
|
||||||
|
maskSource: occupiedIndicators
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////// Active indicator ///////////////////
|
||||||
|
TrailingIndicator {
|
||||||
|
id: activeIndicator
|
||||||
|
anchors.fill: parent
|
||||||
|
z: 2
|
||||||
|
|
||||||
|
index: root.workspaceIndexInGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////// Hover ///////////////////
|
||||||
|
TrailingIndicator {
|
||||||
|
id: interactionIndicator
|
||||||
|
z: 3
|
||||||
|
index: root.containsMouse ? root.hoverIndex : root.workspaceIndexInGroup
|
||||||
|
color: "transparent"
|
||||||
|
StateOverlay {
|
||||||
|
id: hoverOverlay
|
||||||
|
anchors.fill: interactionIndicator.indicatorRectangle
|
||||||
|
radius: root.activeWorkspaceSize / 2
|
||||||
|
hover: root.containsMouse
|
||||||
|
press: root.containsPress
|
||||||
|
drag: true // There are too many layers so we need to force this to be a lil more opaque
|
||||||
|
contentColor: Appearance.colors.colPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////// Numbers ///////////////////
|
||||||
|
WorkspaceLayout {
|
||||||
|
id: numbersGrid
|
||||||
|
z: 4
|
||||||
|
layer.enabled: true // For the masking
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: wsModel.shownCount
|
||||||
|
delegate: NumberWorkspaceItem {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Colorizer {
|
||||||
|
z: 5
|
||||||
|
anchors.fill: numbersGrid
|
||||||
|
colorizationColor: Appearance.colors.colOnPrimary
|
||||||
|
sourceColor: Appearance.colors.colOnSecondaryContainer
|
||||||
|
|
||||||
|
source: activeIndicator
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: numbersGrid
|
||||||
|
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////// App icons ///////////////////
|
||||||
|
WorkspaceLayout {
|
||||||
|
id: appsGrid
|
||||||
|
z: 6
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: wsModel.shownCount
|
||||||
|
delegate: WorkspaceItem {
|
||||||
|
id: wsApp
|
||||||
|
property var biggestWindow: wsModel.biggestWindow[index]
|
||||||
|
property var mainAppIconSource: Quickshell.iconPath(AppSearch.guessIcon(biggestWindow?.class), "image-missing")
|
||||||
|
|
||||||
|
AppIcon {
|
||||||
|
id: appIcon
|
||||||
|
property real cornerMargin: (!root.superPressAndHeld && Config.options?.bar.workspaces.showAppIcons && wsApp.biggestWindow) ? (root.workspaceButtonWidth - root.workspaceIconSize) / 2 : root.workspaceIconMarginShrinked
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
right: parent.right
|
||||||
|
bottomMargin: (parent.implicitHeight - root.workspaceButtonWidth) / 2 + cornerMargin
|
||||||
|
rightMargin: (parent.implicitWidth - root.workspaceButtonWidth) / 2 + cornerMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
animated: !wsApp.biggestWindow // Prevent the "image-missing" icon
|
||||||
|
visible: false // Prevent dupe: the colorizer already copies the icon
|
||||||
|
|
||||||
|
source: wsApp.mainAppIconSource
|
||||||
|
implicitSize: NumberUtils.roundToEven(root.workspaceIconSize)
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on cornerMargin {
|
||||||
|
animation: Appearance.animation.elementMoveSmall.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Circle {
|
||||||
|
id: iconMask
|
||||||
|
visible: false
|
||||||
|
layer.enabled: true
|
||||||
|
diameter: appIcon.implicitSize
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader { // Somehow putting this multieffect in a loader prevents it from not showing up
|
||||||
|
id: colorizer
|
||||||
|
anchors.fill: appIcon
|
||||||
|
sourceComponent: Colorizer {
|
||||||
|
implicitWidth: appIcon.implicitWidth
|
||||||
|
implicitHeight: appIcon.implicitHeight
|
||||||
|
colorizationColor: Appearance.m3colors.darkmode ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnPrimary
|
||||||
|
colorization: Config.options.bar.workspaces.monochromeIcons ? 0.8 : 0.5
|
||||||
|
brightness: 0
|
||||||
|
source: appIcon
|
||||||
|
|
||||||
|
opacity: !Config.options?.bar.workspaces.showAppIcons ? 0 : (wsApp.biggestWindow && !root.superPressAndHeld && Config.options?.bar.workspaces.showAppIcons) ? 1 : wsApp.biggestWindow ? root.workspaceIconOpacityShrinked : 0
|
||||||
|
visible: opacity > 0
|
||||||
|
scale: ((!root.superPressAndHeld && Config.options?.bar.workspaces.showAppIcons) ? root.workspaceIconSize : root.workspaceIconSizeShrinked) / root.workspaceIconSize
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
animation: Appearance.animation.elementMoveSmall.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: iconMask
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FadeLoader {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
shown: wsModel.specialWorkspaceActive
|
||||||
|
scale: 0.8 + 0.2 * root.specialBlur
|
||||||
|
|
||||||
|
opacity: root.specialBlur
|
||||||
|
Behavior on opacity {} // Don't animate, as specialBlur is already animated
|
||||||
|
|
||||||
|
sourceComponent: Pill {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
property real undirectionalWidth: root.activeWorkspaceSize
|
||||||
|
property real undirectionalLength: {
|
||||||
|
const base = root.workspaceButtonWidth * Math.min(1.35, wsModel.shownCount); // Who tf only configures only 2 workspaces shown anyway?
|
||||||
|
if (root.vertical)
|
||||||
|
return base;
|
||||||
|
return specialWsText.implicitWidth + undirectionalWidth;
|
||||||
|
}
|
||||||
|
color: Appearance.colors.colPrimary
|
||||||
|
|
||||||
|
implicitWidth: root.vertical ? undirectionalWidth : undirectionalLength
|
||||||
|
implicitHeight: root.vertical ? undirectionalLength : undirectionalWidth
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: specialWsText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: (!root.vertical ? wsModel.specialWorkspaceName : "S")
|
||||||
|
color: Appearance.colors.colOnPrimary
|
||||||
|
font.pixelSize: root.specialTextSize
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on undirectionalLength {
|
||||||
|
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////// Super key press handling ///////////////////
|
||||||
Timer {
|
Timer {
|
||||||
id: showNumbersTimer
|
id: superPressAndHeldTimer
|
||||||
interval: (Config?.options.bar.autoHide.showWhenPressingSuper.delay ?? 100)
|
interval: (Config?.options.bar.autoHide.showWhenPressingSuper.delay ?? 100)
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.showNumbers = true
|
root.superPressAndHeld = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalStates
|
target: GlobalStates
|
||||||
function onSuperDownChanged() {
|
function onSuperDownChanged() {
|
||||||
if (!Config?.options.bar.autoHide.showWhenPressingSuper.enable) return;
|
if (!Config?.options.bar.autoHide.showWhenPressingSuper.enable)
|
||||||
if (GlobalStates.superDown) showNumbersTimer.restart();
|
return;
|
||||||
|
if (GlobalStates.superDown)
|
||||||
|
superPressAndHeldTimer.restart();
|
||||||
else {
|
else {
|
||||||
showNumbersTimer.stop();
|
superPressAndHeldTimer.stop();
|
||||||
root.showNumbers = false;
|
root.superPressAndHeld = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function onSuperReleaseMightTriggerChanged() {
|
function onSuperReleaseMightTriggerChanged() {
|
||||||
showNumbersTimer.stop()
|
superPressAndHeldTimer.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to update workspaceOccupied
|
component WorkspaceLayout: Box {
|
||||||
function updateWorkspaceOccupied() {
|
|
||||||
workspaceOccupied = Array.from({ length: root.workspacesShown }, (_, i) => {
|
|
||||||
return Hyprland.workspaces.values.some(ws => ws.id === workspaceGroup * root.workspacesShown + i + 1);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Occupied workspace updates
|
|
||||||
Component.onCompleted: updateWorkspaceOccupied()
|
|
||||||
Connections {
|
|
||||||
target: Hyprland.workspaces
|
|
||||||
function onValuesChanged() {
|
|
||||||
updateWorkspaceOccupied();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Connections {
|
|
||||||
target: Hyprland
|
|
||||||
function onFocusedWorkspaceChanged() {
|
|
||||||
updateWorkspaceOccupied();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onWorkspaceGroupChanged: {
|
|
||||||
updateWorkspaceOccupied();
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitWidth: root.vertical ? Appearance.sizes.verticalBarWidth : (root.workspaceButtonWidth * root.workspacesShown)
|
|
||||||
implicitHeight: root.vertical ? (root.workspaceButtonWidth * root.workspacesShown) : Appearance.sizes.barHeight
|
|
||||||
|
|
||||||
// Scroll to switch workspaces
|
|
||||||
WheelHandler {
|
|
||||||
onWheel: (event) => {
|
|
||||||
if (event.angleDelta.y < 0)
|
|
||||||
Hyprland.dispatch(`hl.dsp.focus({workspace = "r+1"})`);
|
|
||||||
else if (event.angleDelta.y > 0)
|
|
||||||
Hyprland.dispatch(`hl.dsp.focus({workspace = "r-1"})`);
|
|
||||||
}
|
|
||||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.BackButton
|
|
||||||
onPressed: (event) => {
|
|
||||||
if (event.button === Qt.BackButton) {
|
|
||||||
Hyprland.dispatch(`hl.dsp.workspace.toggle_special("special")`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workspaces - background
|
|
||||||
Grid {
|
|
||||||
z: 1
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
rowSpacing: 0
|
|
||||||
columnSpacing: 0
|
|
||||||
columns: root.vertical ? 1 : root.workspacesShown
|
|
||||||
rows: root.vertical ? root.workspacesShown : 1
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: root.workspacesShown
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
z: 1
|
|
||||||
implicitWidth: workspaceButtonWidth
|
|
||||||
implicitHeight: workspaceButtonWidth
|
|
||||||
radius: (width / 2)
|
|
||||||
property var previousOccupied: (workspaceOccupied[index-1] && !(!activeWindow?.activated && root.effectiveActiveWorkspaceId === index))
|
|
||||||
property var rightOccupied: (workspaceOccupied[index+1] && !(!activeWindow?.activated && root.effectiveActiveWorkspaceId === index+2))
|
|
||||||
property var radiusPrev: previousOccupied ? 0 : (width / 2)
|
|
||||||
property var radiusNext: rightOccupied ? 0 : (width / 2)
|
|
||||||
|
|
||||||
topLeftRadius: radiusPrev
|
|
||||||
bottomLeftRadius: root.vertical ? radiusNext : radiusPrev
|
|
||||||
topRightRadius: root.vertical ? radiusPrev : radiusNext
|
|
||||||
bottomRightRadius: radiusNext
|
|
||||||
|
|
||||||
color: ColorUtils.transparentize(Appearance.m3colors.m3secondaryContainer, 0.4)
|
|
||||||
opacity: (workspaceOccupied[index] && !(!activeWindow?.activated && root.effectiveActiveWorkspaceId === index+1)) ? 1 : 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
Behavior on radiusPrev {
|
|
||||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on radiusNext {
|
|
||||||
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
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Appearance.colors.colPrimary
|
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
verticalCenter: vertical ? undefined : parent.verticalCenter
|
top: !root.vertical ? parent.top : undefined
|
||||||
horizontalCenter: vertical ? parent.horizontalCenter : undefined
|
bottom: !root.vertical ? parent.bottom : undefined
|
||||||
|
left: root.vertical ? parent.left : undefined
|
||||||
|
right: root.vertical ? parent.right : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedTabIndexPair {
|
rowSpacing: 0
|
||||||
id: idxPair
|
columnSpacing: 0
|
||||||
index: root.workspaceIndexInGroup
|
vertical: root.vertical
|
||||||
}
|
|
||||||
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * workspaceButtonWidth + root.activeWorkspaceMargin
|
|
||||||
property real indicatorLength: Math.abs(idxPair.idx1 - idxPair.idx2) * workspaceButtonWidth + workspaceButtonWidth - root.activeWorkspaceMargin * 2
|
|
||||||
property real indicatorThickness: workspaceButtonWidth - root.activeWorkspaceMargin * 2
|
|
||||||
|
|
||||||
x: root.vertical ? null : indicatorPosition
|
|
||||||
implicitWidth: root.vertical ? indicatorThickness : indicatorLength
|
|
||||||
y: root.vertical ? indicatorPosition : null
|
|
||||||
implicitHeight: root.vertical ? indicatorLength : indicatorThickness
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workspaces - numbers
|
component WorkspaceItem: Item {
|
||||||
Grid {
|
required property int index
|
||||||
z: 3
|
readonly property int wsId: wsModel.getWorkspaceIdAt(index)
|
||||||
|
implicitWidth: root.vertical ? root.barThickness : root.workspaceButtonWidth
|
||||||
|
implicitHeight: root.vertical ? root.workspaceButtonWidth : root.barThickness
|
||||||
|
}
|
||||||
|
|
||||||
columns: root.vertical ? 1 : root.workspacesShown
|
component NumberWorkspaceItem: WorkspaceItem {
|
||||||
rows: root.vertical ? root.workspacesShown : 1
|
id: wsNum
|
||||||
columnSpacing: 0
|
property bool hasBiggestWindow: !!wsModel.biggestWindow[index]
|
||||||
rowSpacing: 0
|
property int wsId: wsModel.getWorkspaceIdAt(index)
|
||||||
|
property color contentColor: (wsModel.occupied[wsNum.index] && wsId !== wsModel.fakeWorkspace) ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnLayer1Inactive
|
||||||
|
property bool showingNumbers: {
|
||||||
|
if (root.superPressAndHeld)
|
||||||
|
return true;
|
||||||
|
if (GlobalStates.screenLocked)
|
||||||
|
return false;
|
||||||
|
if (Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !wsNum.hasBiggestWindow))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
FadeLoader {
|
||||||
|
shown: !wsNum.showingNumbers
|
||||||
Repeater {
|
anchors.centerIn: parent
|
||||||
model: root.workspacesShown
|
Circle {
|
||||||
|
anchors.centerIn: parent
|
||||||
Button {
|
diameter: root.workspaceButtonWidth * 0.18
|
||||||
id: button
|
color: wsNum.contentColor
|
||||||
property int workspaceValue: workspaceGroup * root.workspacesShown + index + 1
|
}
|
||||||
implicitHeight: vertical ? Appearance.sizes.verticalBarWidth : Appearance.sizes.barHeight
|
}
|
||||||
implicitWidth: vertical ? Appearance.sizes.verticalBarWidth : Appearance.sizes.verticalBarWidth
|
FadeLoader {
|
||||||
onPressed: Hyprland.dispatch(`hl.dsp.focus({ workspace = ${workspaceValue}})`)
|
shown: wsNum.showingNumbers
|
||||||
width: vertical ? undefined : root.workspaceButtonWidth
|
anchors.centerIn: parent
|
||||||
height: vertical ? root.workspaceButtonWidth : undefined
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
background: Item {
|
font {
|
||||||
id: workspaceButtonBackground
|
pixelSize: Appearance.font.pixelSize.small - ((text.length - 1) * (text !== "10") * 2)
|
||||||
implicitWidth: workspaceButtonWidth
|
family: Config.options?.bar.workspaces.useNerdFont ? Appearance.font.family.iconNerd : defaultFont
|
||||||
implicitHeight: workspaceButtonWidth
|
|
||||||
property var biggestWindow: HyprlandData.biggestWindowForWorkspace(button.workspaceValue)
|
|
||||||
property var mainAppIconSource: Quickshell.iconPath(AppSearch.guessIcon(biggestWindow?.class), "image-missing")
|
|
||||||
|
|
||||||
StyledText { // Workspace number text
|
|
||||||
opacity: root.showNumbers
|
|
||||||
|| ((Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || root.showNumbers))
|
|
||||||
|| (root.showNumbers && !Config.options?.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)
|
|
||||||
family: Config.options?.bar.workspaces.useNerdFont ? Appearance.font.family.iconNerd : defaultFont
|
|
||||||
}
|
|
||||||
text: Config.options?.bar.workspaces.numberMap[button.workspaceValue - 1] || button.workspaceValue
|
|
||||||
elide: Text.ElideRight
|
|
||||||
color: (root.effectiveActiveWorkspaceId == 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
|
|
||||||
id: wsDot
|
|
||||||
opacity: (Config.options?.bar.workspaces.alwaysShowNumbers
|
|
||||||
|| root.showNumbers
|
|
||||||
|| (Config.options?.bar.workspaces.showAppIcons && workspaceButtonBackground.biggestWindow)
|
|
||||||
) ? 0 : 1
|
|
||||||
visible: opacity > 0
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: workspaceButtonWidth * 0.18
|
|
||||||
height: width
|
|
||||||
radius: width / 2
|
|
||||||
color: (root.effectiveActiveWorkspaceId == 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: !Config.options?.bar.workspaces.showAppIcons ? 0 :
|
|
||||||
(workspaceButtonBackground.biggestWindow && !root.showNumbers && Config.options?.bar.workspaces.showAppIcons) ?
|
|
||||||
1 : workspaceButtonBackground.biggestWindow ? workspaceIconOpacityShrinked : 0
|
|
||||||
visible: opacity > 0
|
|
||||||
IconImage {
|
|
||||||
id: mainAppIcon
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottomMargin: (!root.showNumbers && Config.options?.bar.workspaces.showAppIcons) ?
|
|
||||||
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
|
||||||
anchors.rightMargin: (!root.showNumbers && Config.options?.bar.workspaces.showAppIcons) ?
|
|
||||||
(workspaceButtonWidth - workspaceIconSize) / 2 : workspaceIconMarginShrinked
|
|
||||||
|
|
||||||
source: workspaceButtonBackground.mainAppIconSource
|
|
||||||
implicitSize: (!root.showNumbers && Config.options?.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
active: Config.options.bar.workspaces.monochromeIcons
|
|
||||||
anchors.fill: mainAppIcon
|
|
||||||
sourceComponent: Item {
|
|
||||||
Desaturate {
|
|
||||||
id: desaturatedIcon
|
|
||||||
visible: false // There's already color overlay
|
|
||||||
anchors.fill: parent
|
|
||||||
source: mainAppIcon
|
|
||||||
desaturation: 0.8
|
|
||||||
}
|
|
||||||
ColorOverlay {
|
|
||||||
anchors.fill: desaturatedIcon
|
|
||||||
source: desaturatedIcon
|
|
||||||
color: ColorUtils.transparentize(wsDot.color, 0.9)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
color: wsNum.contentColor
|
||||||
|
text: Config.options?.bar.workspaces.numberMap[wsNum.wsId - 1] || wsNum.wsId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component TrailingIndicator: Item {
|
||||||
|
id: trailingIndicator
|
||||||
|
anchors.fill: parent
|
||||||
|
required property int index
|
||||||
|
property alias indicatorRectangle: indicatorRect
|
||||||
|
property alias color: indicatorRect.color
|
||||||
|
|
||||||
|
property var indexPair: AnimatedTabIndexPair {
|
||||||
|
id: idxPair
|
||||||
|
index: trailingIndicator.index
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRectangle {
|
||||||
|
id: indicatorRect
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
verticalCenter: root.vertical ? undefined : parent.verticalCenter
|
||||||
|
horizontalCenter: root.vertical ? parent.horizontalCenter : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceMargin
|
||||||
|
property real indicatorLength: Math.abs(idxPair.idx1 - idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceSize
|
||||||
|
property real indicatorThickness: root.activeWorkspaceSize
|
||||||
|
|
||||||
|
contentLayer: StyledRectangle.ContentLayer.Group
|
||||||
|
radius: indicatorThickness / 2
|
||||||
|
color: Appearance.colors.colPrimary
|
||||||
|
|
||||||
|
x: root.vertical ? null : indicatorPosition
|
||||||
|
y: root.vertical ? indicatorPosition : null
|
||||||
|
implicitWidth: root.vertical ? indicatorThickness : indicatorLength
|
||||||
|
implicitHeight: root.vertical ? indicatorLength : indicatorThickness
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user