forked from Shinonome/dots-hyprland
hefty: bar: special ws indication
This commit is contained in:
@@ -282,6 +282,20 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property QtObject elementMoveSmall: QtObject {
|
||||||
|
property int duration: animationCurves.expressiveFastSpatialDuration
|
||||||
|
property int type: Easing.BezierSpline
|
||||||
|
property list<real> bezierCurve: animationCurves.expressiveFastSpatial
|
||||||
|
property int velocity: 650
|
||||||
|
property Component numberAnimation: Component {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: root.animation.elementMoveSmall.duration
|
||||||
|
easing.type: root.animation.elementMoveSmall.type
|
||||||
|
easing.bezierCurve: root.animation.elementMoveSmall.bezierCurve
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property QtObject elementMoveEnter: QtObject {
|
property QtObject elementMoveEnter: QtObject {
|
||||||
property int duration: 400
|
property int duration: 400
|
||||||
property int type: Easing.BezierSpline
|
property int type: Easing.BezierSpline
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ NestableObject {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property HyprlandMonitor monitor
|
required property HyprlandMonitor monitor
|
||||||
|
readonly property var liveMonitorData: HyprlandData.monitors.find(m => m.id === monitor.id)
|
||||||
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
||||||
readonly property int activeWorkspace: monitor?.activeWorkspace?.id
|
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 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 fakeWorkspace: currentWorkspaceNotFake ? -9999 : activeWorkspace
|
||||||
readonly property int shownCount: C.Config.options.bar.workspaces.shown
|
readonly property int shownCount: C.Config.options.bar.workspaces.shown
|
||||||
readonly property int group: Math.floor((activeWorkspace - 1) / shownCount)
|
readonly property int group: Math.floor((activeWorkspace - 1) / shownCount)
|
||||||
|
readonly property var specialWorkspace: liveMonitorData?.specialWorkspace
|
||||||
|
readonly property string specialWorkspaceName: specialWorkspace.name.replace("special:", "")
|
||||||
|
readonly property bool specialWorkspaceActive: specialWorkspaceName !== ""
|
||||||
|
|
||||||
property list<bool> occupied: []
|
property list<bool> occupied: []
|
||||||
property list<var> biggestWindow: occupied.map((_, index) => {
|
property list<var> biggestWindow: occupied.map((_, index) => {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
radius: Math.min(width, height) / 2
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ Item {
|
|||||||
property real workspaceIconOpacityShrinked: 1
|
property real workspaceIconOpacityShrinked: 1
|
||||||
property real workspaceIconMarginShrinked: -4
|
property real workspaceIconMarginShrinked: -4
|
||||||
property int workspaceIndexInGroup: (monitor?.activeWorkspace?.id - 1) % wsModel.shownCount
|
property int workspaceIndexInGroup: (monitor?.activeWorkspace?.id - 1) % wsModel.shownCount
|
||||||
|
property real specialTextSize: workspaceButtonWidth * 0.5
|
||||||
|
|
||||||
Layout.alignment: vertical ? Qt.AlignHCenter : Qt.AlignVCenter
|
Layout.alignment: vertical ? Qt.AlignHCenter : Qt.AlignVCenter
|
||||||
Layout.fillWidth: vertical
|
Layout.fillWidth: vertical
|
||||||
@@ -38,243 +39,264 @@ Item {
|
|||||||
implicitWidth: vertical ? Appearance.sizes.verticalBarWidth : occupiedIndicators.implicitWidth
|
implicitWidth: vertical ? Appearance.sizes.verticalBarWidth : occupiedIndicators.implicitWidth
|
||||||
implicitHeight: vertical ? occupiedIndicators.implicitHeight : Appearance.sizes.barHeight
|
implicitHeight: vertical ? occupiedIndicators.implicitHeight : Appearance.sizes.barHeight
|
||||||
|
|
||||||
/////////////////// Occupied indicators ///////////////////
|
property real specialBlur: wsModel.specialWorkspaceActive ? 1 : 0
|
||||||
StyledRectangle {
|
Behavior on specialBlur {
|
||||||
id: occupiedIndicatorsBg
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: regularWorkspaces
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
contentLayer: StyledRectangle.ContentLayer.Group
|
|
||||||
color: ColorUtils.transparentize(Appearance.m3colors.m3secondaryContainer, 0.4)
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
WorkspaceLayout {
|
scale: 1 - 0.08 * root.specialBlur
|
||||||
id: occupiedIndicators
|
layer.smooth: true
|
||||||
anchors.centerIn: parent
|
layer.enabled: root.specialBlur > 0
|
||||||
|
layer.effect: MultiEffect {
|
||||||
// rowSpacing: 0
|
brightness: -0.1 * root.specialBlur
|
||||||
// columnSpacing: 0
|
blurEnabled: true
|
||||||
// columns: root.vertical ? 1 : -1
|
blur: root.specialBlur
|
||||||
// rows: root.vertical ? -1 : 1
|
blurMax: 32
|
||||||
|
|
||||||
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
|
|
||||||
Circle {
|
|
||||||
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
|
|
||||||
radius: undirectionalWidth / 2
|
|
||||||
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.elementMoveFast.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
Behavior on undirectionalLength {
|
|
||||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
Behavior on undirectionalOffset {
|
|
||||||
animation: Appearance.animation.elementMoveFast.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
|
|
||||||
layer.enabled: true // For the masking
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////// Hover ///////////////////
|
|
||||||
MouseArea {
|
|
||||||
id: interactionMouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
hoverEnabled: true
|
|
||||||
property int hoverIndex: {
|
|
||||||
const position = root.vertical ? mouseY : mouseX;
|
|
||||||
return Math.floor(position / root.workspaceButtonWidth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressed: Hyprland.dispatch(`workspace ${wsModel.getWorkspaceIdAt(hoverIndex)}`)
|
/////////////////// Occupied indicators ///////////////////
|
||||||
|
StyledRectangle {
|
||||||
TrailingIndicator {
|
id: occupiedIndicatorsBg
|
||||||
id: interactionIndicator
|
anchors.fill: parent
|
||||||
index: interactionMouseArea.containsMouse ? interactionMouseArea.hoverIndex : root.workspaceIndexInGroup
|
contentLayer: StyledRectangle.ContentLayer.Group
|
||||||
color: "transparent"
|
color: ColorUtils.transparentize(Appearance.m3colors.m3secondaryContainer, 0.4)
|
||||||
StateOverlay {
|
visible: false
|
||||||
id: hoverOverlay
|
|
||||||
anchors.fill: interactionIndicator.indicatorRectangle
|
|
||||||
radius: root.activeWorkspaceSize / 2
|
|
||||||
hover: interactionMouseArea.containsMouse
|
|
||||||
press: interactionMouseArea.containsPress
|
|
||||||
contentColor: Appearance.colors.colPrimary
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////// Numbers ///////////////////
|
WorkspaceLayout {
|
||||||
WorkspaceLayout {
|
id: occupiedIndicators
|
||||||
id: numbersGrid
|
anchors.centerIn: parent
|
||||||
z: 4
|
|
||||||
layer.enabled: true // For the masking
|
|
||||||
|
|
||||||
Repeater {
|
layer.enabled: true
|
||||||
model: wsModel.shownCount
|
visible: false
|
||||||
delegate: WorkspaceItem {
|
|
||||||
id: wsNum
|
|
||||||
property bool hasBiggestWindow: !!wsModel.biggestWindow[index]
|
|
||||||
property color contentColor: wsModel.occupied[wsNum.index] ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnLayer1Inactive
|
|
||||||
|
|
||||||
FadeLoader {
|
Repeater {
|
||||||
shown: !(Config.options?.bar.workspaces.alwaysShowNumbers
|
model: wsModel.shownCount
|
||||||
|| root.superPressAndHeld
|
delegate: Item {
|
||||||
|| (Config.options?.bar.workspaces.showAppIcons && wsNum.hasBiggestWindow)
|
id: wsBg
|
||||||
)
|
required property int index
|
||||||
anchors.centerIn: parent
|
readonly property int wsId: wsModel.getWorkspaceIdAt(index)
|
||||||
Circle {
|
property bool currentOccupied: wsModel.occupied[index] && wsId != wsModel.fakeWorkspace
|
||||||
anchors.centerIn: parent
|
property bool previousOccupied: index > 0 && wsModel.occupied[index - 1] && (wsId - 1) != wsModel.fakeWorkspace
|
||||||
diameter: root.workspaceButtonWidth * 0.18
|
property bool nextOccupied: index < wsModel.shownCount - 1 && wsModel.occupied[index + 1] && (wsId + 1) != wsModel.fakeWorkspace
|
||||||
color: wsNum.contentColor
|
implicitWidth: root.workspaceButtonWidth
|
||||||
}
|
implicitHeight: root.workspaceButtonWidth
|
||||||
}
|
|
||||||
FadeLoader {
|
// The idea: over-stretch to occupied sides, animate this for a smooth transition.
|
||||||
shown: root.superPressAndHeld
|
// masking already prevents weird overlaps
|
||||||
|| ((Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !wsNum.hasBiggestWindow || root.showNumbers))
|
Pill {
|
||||||
|| (root.superPressAndHeld && !Config.options?.bar.workspaces.showAppIcons)
|
property real undirectionalWidth: root.workspaceButtonWidth * wsBg.currentOccupied
|
||||||
)
|
property real undirectionalLength: root.workspaceButtonWidth * (1 + 0.5 * wsBg.previousOccupied + 0.5 * wsBg.nextOccupied) * currentOccupied
|
||||||
anchors.centerIn: parent
|
property real undirectionalOffset: (!wsBg.currentOccupied ? 0.5 : -0.5 * wsBg.previousOccupied) * root.workspaceButtonWidth
|
||||||
StyledText {
|
anchors.verticalCenter: root.vertical ? undefined : parent.verticalCenter
|
||||||
anchors.centerIn: parent
|
anchors.horizontalCenter: root.vertical ? parent.horizontalCenter : undefined
|
||||||
font {
|
x: root.vertical ? 0 : undirectionalOffset
|
||||||
pixelSize: Appearance.font.pixelSize.small - ((text.length - 1) * (text !== "10") * 2)
|
y: root.vertical ? undirectionalOffset : 0
|
||||||
family: Config.options?.bar.workspaces.useNerdFont ? Appearance.font.family.iconNerd : defaultFont
|
implicitWidth: root.vertical ? undirectionalWidth : undirectionalLength
|
||||||
|
implicitHeight: root.vertical ? undirectionalLength : undirectionalWidth
|
||||||
|
|
||||||
|
Behavior on undirectionalWidth {
|
||||||
|
animation: Appearance.animation.elementMoveSmall.numberAnimation.createObject(this)
|
||||||
}
|
}
|
||||||
color: wsNum.contentColor
|
Behavior on undirectionalLength {
|
||||||
text: wsNum.wsId
|
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 ///////////////////
|
||||||
|
MouseArea {
|
||||||
|
id: interactionMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
property int hoverIndex: {
|
||||||
|
const position = root.vertical ? mouseY : mouseX;
|
||||||
|
return Math.floor(position / root.workspaceButtonWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed: Hyprland.dispatch(`workspace ${wsModel.getWorkspaceIdAt(hoverIndex)}`)
|
||||||
|
onWheel: (event) => {
|
||||||
|
if (event.angleDelta.y < 0)
|
||||||
|
Hyprland.dispatch(`workspace r+1`);
|
||||||
|
else if (event.angleDelta.y > 0)
|
||||||
|
Hyprland.dispatch(`workspace r-1`);
|
||||||
|
}
|
||||||
|
|
||||||
|
TrailingIndicator {
|
||||||
|
id: interactionIndicator
|
||||||
|
index: interactionMouseArea.containsMouse ? interactionMouseArea.hoverIndex : root.workspaceIndexInGroup
|
||||||
|
color: "transparent"
|
||||||
|
StateOverlay {
|
||||||
|
id: hoverOverlay
|
||||||
|
anchors.fill: interactionIndicator.indicatorRectangle
|
||||||
|
radius: root.activeWorkspaceSize / 2
|
||||||
|
hover: interactionMouseArea.containsMouse
|
||||||
|
press: interactionMouseArea.containsPress
|
||||||
|
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) ?
|
||||||
|
(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.superPressAndHeld && Config.options?.bar.workspaces.showAppIcons) ? root.workspaceIconSize : root.workspaceIconSizeShrinked)
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on cornerMargin {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on implicitSize {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Circle {
|
||||||
|
id: iconMask
|
||||||
|
visible: false
|
||||||
|
layer.enabled: true
|
||||||
|
diameter: appIcon.implicitSize
|
||||||
|
}
|
||||||
|
|
||||||
|
Colorizer {
|
||||||
|
anchors.fill: appIcon
|
||||||
|
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
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: iconMask
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
maskSpreadAtMin: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Colorizer {
|
|
||||||
z: 5
|
|
||||||
anchors.fill: numbersGrid
|
|
||||||
colorizationColor: Appearance.colors.colOnPrimary
|
|
||||||
sourceColor: Appearance.colors.colOnSecondaryContainer
|
|
||||||
|
|
||||||
source: activeIndicator
|
FadeLoader {
|
||||||
maskEnabled: true
|
anchors.centerIn: parent
|
||||||
maskSource: numbersGrid
|
shown: wsModel.specialWorkspaceActive
|
||||||
|
|
||||||
maskThresholdMin: 0.5
|
scale: 0.8 + 0.2 * root.specialBlur
|
||||||
maskSpreadAtMin: 1
|
// layer.enabled: true
|
||||||
}
|
// layer.smooth: true
|
||||||
|
|
||||||
/////////////////// App icons ///////////////////
|
Pill {
|
||||||
WorkspaceLayout {
|
anchors.centerIn: parent
|
||||||
id: appsGrid
|
property real undirectionalWidth: root.activeWorkspaceSize
|
||||||
z: 6
|
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
|
||||||
|
|
||||||
Repeater {
|
implicitWidth: root.vertical ? undirectionalWidth : undirectionalLength
|
||||||
model: wsModel.shownCount
|
implicitHeight: root.vertical ? undirectionalLength : undirectionalWidth
|
||||||
delegate: WorkspaceItem {
|
|
||||||
id: wsApp
|
|
||||||
property var biggestWindow: wsModel.biggestWindow[index]
|
|
||||||
property var mainAppIconSource: Quickshell.iconPath(AppSearch.guessIcon(biggestWindow?.class), "image-missing")
|
|
||||||
|
|
||||||
AppIcon {
|
StyledText {
|
||||||
id: appIcon
|
id: specialWsText
|
||||||
property real cornerMargin: (!root.superPressAndHeld && Config.options?.bar.workspaces.showAppIcons) ?
|
anchors.centerIn: parent
|
||||||
(root.workspaceButtonWidth - root.workspaceIconSize) / 2 : root.workspaceIconMarginShrinked
|
text: (!root.vertical ? wsModel.specialWorkspaceName : "S")
|
||||||
anchors {
|
color: Appearance.colors.colOnPrimary
|
||||||
bottom: parent.bottom
|
font.pixelSize: root.specialTextSize
|
||||||
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
|
Behavior on undirectionalLength {
|
||||||
visible: false // Prevent dupe: the colorizer already copies the icon
|
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
|
||||||
|
|
||||||
source: wsApp.mainAppIconSource
|
|
||||||
implicitSize: NumberUtils.roundToEven((!root.superPressAndHeld && Config.options?.bar.workspaces.showAppIcons) ? root.workspaceIconSize : root.workspaceIconSizeShrinked)
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
Behavior on cornerMargin {
|
|
||||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
Behavior on implicitSize {
|
|
||||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Circle {
|
|
||||||
id: iconMask
|
|
||||||
visible: false
|
|
||||||
layer.enabled: true
|
|
||||||
diameter: appIcon.implicitSize
|
|
||||||
}
|
|
||||||
|
|
||||||
Colorizer {
|
|
||||||
anchors.fill: appIcon
|
|
||||||
implicitWidth: appIcon.implicitWidth
|
|
||||||
implicitHeight: appIcon.implicitHeight
|
|
||||||
colorizationColor: Appearance.colors.colOnSecondaryContainer
|
|
||||||
colorization: Config.options.bar.workspaces.monochromeIcons * 0.7
|
|
||||||
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
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
maskEnabled: true
|
|
||||||
maskSource: iconMask
|
|
||||||
maskThresholdMin: 0.5
|
|
||||||
maskSpreadAtMin: 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,6 +323,41 @@ Item {
|
|||||||
implicitHeight: root.vertical ? root.workspaceButtonWidth : Appearance.sizes.barHeight
|
implicitHeight: root.vertical ? root.workspaceButtonWidth : Appearance.sizes.barHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component NumberWorkspaceItem: WorkspaceItem {
|
||||||
|
id: wsNum
|
||||||
|
property bool hasBiggestWindow: !!wsModel.biggestWindow[index]
|
||||||
|
property color contentColor: wsModel.occupied[wsNum.index] ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnLayer1Inactive
|
||||||
|
|
||||||
|
FadeLoader {
|
||||||
|
shown: !(Config.options?.bar.workspaces.alwaysShowNumbers
|
||||||
|
|| root.superPressAndHeld
|
||||||
|
|| (Config.options?.bar.workspaces.showAppIcons && wsNum.hasBiggestWindow)
|
||||||
|
)
|
||||||
|
anchors.centerIn: parent
|
||||||
|
Circle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
diameter: root.workspaceButtonWidth * 0.18
|
||||||
|
color: wsNum.contentColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FadeLoader {
|
||||||
|
shown: root.superPressAndHeld
|
||||||
|
|| ((Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !wsNum.hasBiggestWindow || root.showNumbers))
|
||||||
|
|| (root.superPressAndHeld && !Config.options?.bar.workspaces.showAppIcons)
|
||||||
|
)
|
||||||
|
anchors.centerIn: parent
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font {
|
||||||
|
pixelSize: Appearance.font.pixelSize.small - ((text.length - 1) * (text !== "10") * 2)
|
||||||
|
family: Config.options?.bar.workspaces.useNerdFont ? Appearance.font.family.iconNerd : defaultFont
|
||||||
|
}
|
||||||
|
color: wsNum.contentColor
|
||||||
|
text: wsNum.wsId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
component TrailingIndicator: Item {
|
component TrailingIndicator: Item {
|
||||||
id: trailingIndicator
|
id: trailingIndicator
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -308,6 +365,11 @@ Item {
|
|||||||
property alias indicatorRectangle: indicatorRect
|
property alias indicatorRectangle: indicatorRect
|
||||||
property alias color: indicatorRect.color
|
property alias color: indicatorRect.color
|
||||||
|
|
||||||
|
property var indexPair: AnimatedTabIndexPair {
|
||||||
|
id: idxPair
|
||||||
|
index: trailingIndicator.index
|
||||||
|
}
|
||||||
|
|
||||||
StyledRectangle {
|
StyledRectangle {
|
||||||
id: indicatorRect
|
id: indicatorRect
|
||||||
anchors {
|
anchors {
|
||||||
@@ -315,11 +377,6 @@ Item {
|
|||||||
horizontalCenter: vertical ? parent.horizontalCenter : undefined
|
horizontalCenter: vertical ? parent.horizontalCenter : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedTabIndexPair {
|
|
||||||
id: idxPair
|
|
||||||
index: trailingIndicator.index
|
|
||||||
}
|
|
||||||
|
|
||||||
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceMargin
|
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 indicatorLength: Math.abs(idxPair.idx1 - idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceSize
|
||||||
property real indicatorThickness: root.activeWorkspaceSize
|
property real indicatorThickness: root.activeWorkspaceSize
|
||||||
|
|||||||
Reference in New Issue
Block a user