diff options
Diffstat (limited to 'bar')
| -rw-r--r-- | bar/ActiveWindow.qml | 218 | ||||
| -rw-r--r-- | bar/Bar.qml | 278 | ||||
| -rw-r--r-- | bar/Mpris.qml | 366 | ||||
| -rw-r--r-- | bar/Network.qml | 204 | ||||
| -rw-r--r-- | bar/Power.qml | 226 | ||||
| -rw-r--r-- | bar/Resources.qml | 92 | ||||
| -rw-r--r-- | bar/TimeDate.qml | 232 | ||||
| -rw-r--r-- | bar/Workspace.qml | 474 | ||||
| -rw-r--r-- | bar/components/SimpleResource.qml | 160 |
9 files changed, 1125 insertions, 1125 deletions
diff --git a/bar/ActiveWindow.qml b/bar/ActiveWindow.qml index 17d2322..0a6a547 100644 --- a/bar/ActiveWindow.qml +++ b/bar/ActiveWindow.qml @@ -10,113 +10,113 @@ import qs.config // TODO use a item wrapping loader for opacity Behavior IRect { - id: root - // hyprland toplevel isn't shown immediately... - property var toplevel: ToplevelManager.activeToplevel - property var icon: Quickshell.iconPath(AppSearch.guessIcon(toplevel?.appId), "image-missing") - - property var activated: toplevel?.activated || false - - implicitWidth: activated ? rowLayout.implicitWidth + General.rectMargin * 4 : 0 - implicitHeight: rowLayout.implicitHeight + General.rectMargin * 2 + Bar.topMargin * 2 - anchors.centerIn: parent - - color: Qt.rgba(Colors.background3.r, Colors.background3.g, Colors.background3.b, Bar.bgTransparency) - // according to docs, null could happen but doesn't seem to happen in practice so.. - // hypr toplevel.activated is always true and doesn't change either so.. - opacity: activated ? 1 : 0 - - bottomLeftRadius: Bar.moduleRadius - bottomRightRadius: Bar.moduleRadius - - function strip(s) { - var out = s; - Bar.windowStrip.forEach(function (w) { - out = out?.replace(new RegExp(w, "g"), ""); - }); - return out?.trim() || s; - } - - RowLayout { - id: rowLayout - anchors.centerIn: parent - spacing: Bar.resourceIconTextSpacing - width: Math.min(implicitWidth, root.width) - - IconImage { - id: icon - source: root.icon - implicitSize: General.appIconSize - - // sync animation - opacity: root.activated ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: General.animationDuration / 4 - } - } - } - - Item { - Layout.fillWidth: true - Layout.fillHeight: true - implicitWidth: childrenRect.width - IText { - anchors.verticalCenter: parent.verticalCenter - width: Math.min(implicitWidth, rowLayout.width - icon.implicitWidth) - animate: true - clip: true - elide: Text.ElideRight - font.pixelSize: General.fontSize - text: strip(root?.toplevel?.title) || "" - - // sync animation - opacity: root.activated ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: General.animationDuration / 4 - } - } - } - } - } - - onIconChanged: fadeIcon.start() - - Behavior on opacity { - NumberAnimation { - duration: General.animationDuration / 4 - } - } - - Behavior on width { - ISpringAnimation { - spring: General.springAnimationSpring * 2 - damping: General.springAnimationDamping * 1.3 - } - } - - SequentialAnimation { - id: fadeIcon - running: false - - PropertyAnimation { - target: icon - property: "opacity" - to: 0 - duration: General.animationDuration / 4 - } - ScriptAction { - script: icon.source = root.icon - } - PropertyAnimation { - target: icon - property: "opacity" - to: 1 - duration: General.animationDuration / 4 - } - ScriptAction { - script: icon.source = root.icon - } - } + id: root + // hyprland toplevel isn't shown immediately... + property var toplevel: ToplevelManager.activeToplevel + property var icon: Quickshell.iconPath(AppSearch.guessIcon(toplevel?.appId), "image-missing") + + property var activated: toplevel?.activated || false + + implicitWidth: activated ? rowLayout.implicitWidth + General.rectMargin * 4 : 0 + implicitHeight: rowLayout.implicitHeight + General.rectMargin * 2 + Bar.topMargin * 2 + anchors.centerIn: parent + + color: Qt.rgba(Colors.background3.r, Colors.background3.g, Colors.background3.b, Bar.bgTransparency) + // according to docs, null could happen but doesn't seem to happen in practice so.. + // hypr toplevel.activated is always true and doesn't change either so.. + opacity: activated ? 1 : 0 + + bottomLeftRadius: Bar.moduleRadius + bottomRightRadius: Bar.moduleRadius + + function strip(s) { + var out = s; + Bar.windowStrip.forEach(function (w) { + out = out?.replace(new RegExp(w, "g"), ""); + }); + return out?.trim() || s; + } + + RowLayout { + id: rowLayout + anchors.centerIn: parent + spacing: Bar.resourceIconTextSpacing + width: Math.min(implicitWidth, root.width) + + IconImage { + id: icon + source: root.icon + implicitSize: General.appIconSize + + // sync animation + opacity: root.activated ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + } + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + implicitWidth: childrenRect.width + IText { + anchors.verticalCenter: parent.verticalCenter + width: Math.min(implicitWidth, rowLayout.width - icon.implicitWidth) + animate: true + clip: true + elide: Text.ElideRight + font.pixelSize: General.fontSize + text: strip(root?.toplevel?.title) || "" + + // sync animation + opacity: root.activated ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + } + } + } + } + } + + onIconChanged: fadeIcon.start() + + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + } + } + + Behavior on width { + ISpringAnimation { + spring: General.springAnimationSpring * 2 + damping: General.springAnimationDamping * 1.3 + } + } + + SequentialAnimation { + id: fadeIcon + running: false + + PropertyAnimation { + target: icon + property: "opacity" + to: 0 + duration: General.animationDuration / 4 + } + ScriptAction { + script: icon.source = root.icon + } + PropertyAnimation { + target: icon + property: "opacity" + to: 1 + duration: General.animationDuration / 4 + } + ScriptAction { + script: icon.source = root.icon + } + } } diff --git a/bar/Bar.qml b/bar/Bar.qml index 6b762b1..2ad13d1 100644 --- a/bar/Bar.qml +++ b/bar/Bar.qml @@ -5,143 +5,143 @@ import qs.components import qs.config Scope { - id: root - - Variants { - model: Quickshell.screens - - IWindow { - id: barWindow - name: "quickshell::bar" - - anchors { - top: true - left: true - right: true - } - implicitHeight: child.implicitHeight + Bar.topMargin * 2 - - IRect { - id: child - radius: Bar.borderRadius - implicitHeight: Bar.height - implicitWidth: parent.width - - anchors { - left: parent.left - right: parent.mid - fill: parent - top: parent.top - } - - color: "transparent" - - IRect { - id: leftRow - anchors { - left: parent.left - } - width: leftInnerRow.width + leftInnerRow.anchors.leftMargin - leftSpacer.width + Bar.leftMargin - height: leftInnerRow.height - color: Qt.rgba(Colors.background3.r, Colors.background3.g, Colors.background3.b, Bar.bgTransparency) - bottomRightRadius: Bar.moduleRadius - - Behavior on color { - ColorAnimation { - duration: General.animationDuration - easing.type: Easing.InOutQuad - } - } - RowLayout { - id: leftInnerRow - height: child.height - spacing: Bar.leftModuleSpacing - anchors { - left: parent.left - leftMargin: Bar.moduleLeftMargin + Bar.leftMargin - } - - Workspace { - id: workspace - // screen: barWindow.screen // multi monitor - // Layout.minimumWidth: 400 // FIXME - } - Mpris { - id: mpris - } - Item { - id: leftSpacer - Layout.fillWidth: true - Layout.fillHeight: true - } - } - } - - Item { - id: centerRow - anchors.centerIn: parent - - ActiveWindow { - id: activeWindow - width: Math.min(implicitWidth, child.width - Math.max(leftRow.width, rightRow.width) * 2 - Bar.leftMargin - Bar.rightMargin) // we don't do child.width - leftRow.width - rightRow.width because left and right width isn't symetric, and we're centered meaning we will colide into the larger width side - } - } - - IRect { - id: rightRow - anchors.right: parent.right - width: rightInnerRow.width + rightInnerRow.anchors.rightMargin - rightSpacer.width - height: rightInnerRow.height - color: Qt.rgba(Colors.background3.r, Colors.background3.g, Colors.background3.b, Bar.bgTransparency) - bottomLeftRadius: Bar.moduleRadius - - RowLayout { - id: rightInnerRow - anchors { - right: parent.right - rightMargin: Bar.moduleRightMargin - } - layoutDirection: Qt.RightToLeft - height: child.height - spacing: Bar.rightModuleSpacing - - Power { - id: power - } - // Tray { - // id: tray - // } - TimeDate {} - Network {} - // Temp { - // id: temp - // } - // Gpu { - // id: gpu - // } - // Memory { - // id: memory - // } - // Cpu { - // id: cpu - // } - Resources {} - - Item { - id: rightSpacer - Layout.fillWidth: true - Layout.fillHeight: true - } - } - - Behavior on color { - ColorAnimation { - duration: General.animationDuration - easing.type: Easing.InOutQuad - } - } - } - } - } - } + id: root + + Variants { + model: Quickshell.screens + + IWindow { + id: barWindow + name: "quickshell::bar" + + anchors { + top: true + left: true + right: true + } + implicitHeight: child.implicitHeight + Bar.topMargin * 2 + + IRect { + id: child + radius: Bar.borderRadius + implicitHeight: Bar.height + implicitWidth: parent.width + + anchors { + left: parent.left + right: parent.mid + fill: parent + top: parent.top + } + + color: "transparent" + + IRect { + id: leftRow + anchors { + left: parent.left + } + width: leftInnerRow.width + leftInnerRow.anchors.leftMargin - leftSpacer.width + Bar.leftMargin + height: leftInnerRow.height + color: Qt.rgba(Colors.background3.r, Colors.background3.g, Colors.background3.b, Bar.bgTransparency) + bottomRightRadius: Bar.moduleRadius + + Behavior on color { + ColorAnimation { + duration: General.animationDuration + easing.type: Easing.InOutQuad + } + } + RowLayout { + id: leftInnerRow + height: child.height + spacing: Bar.leftModuleSpacing + anchors { + left: parent.left + leftMargin: Bar.moduleLeftMargin + Bar.leftMargin + } + + Workspace { + id: workspace + // screen: barWindow.screen // multi monitor + // Layout.minimumWidth: 400 // FIXME + } + Mpris { + id: mpris + } + Item { + id: leftSpacer + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } + + Item { + id: centerRow + anchors.centerIn: parent + + ActiveWindow { + id: activeWindow + width: Math.min(implicitWidth, child.width - Math.max(leftRow.width, rightRow.width) * 2 - Bar.leftMargin - Bar.rightMargin) // we don't do child.width - leftRow.width - rightRow.width because left and right width isn't symetric, and we're centered meaning we will colide into the larger width side + } + } + + IRect { + id: rightRow + anchors.right: parent.right + width: rightInnerRow.width + rightInnerRow.anchors.rightMargin - rightSpacer.width + height: rightInnerRow.height + color: Qt.rgba(Colors.background3.r, Colors.background3.g, Colors.background3.b, Bar.bgTransparency) + bottomLeftRadius: Bar.moduleRadius + + RowLayout { + id: rightInnerRow + anchors { + right: parent.right + rightMargin: Bar.moduleRightMargin + } + layoutDirection: Qt.RightToLeft + height: child.height + spacing: Bar.rightModuleSpacing + + Power { + id: power + } + // Tray { + // id: tray + // } + TimeDate {} + Network {} + // Temp { + // id: temp + // } + // Gpu { + // id: gpu + // } + // Memory { + // id: memory + // } + // Cpu { + // id: cpu + // } + Resources {} + + Item { + id: rightSpacer + Layout.fillWidth: true + Layout.fillHeight: true + } + } + + Behavior on color { + ColorAnimation { + duration: General.animationDuration + easing.type: Easing.InOutQuad + } + } + } + } + } + } } diff --git a/bar/Mpris.qml b/bar/Mpris.qml index 75f7e2d..4bed0fe 100644 --- a/bar/Mpris.qml +++ b/bar/Mpris.qml @@ -13,187 +13,187 @@ import qs.components import "../utils/string_utils.js" as StringUtils Item { - id: root - readonly property MprisPlayer activePlayer: Services.Mpris.activePlayer - readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) - - implicitWidth: activePlayer ? rect.width - General.rectMargin / 1.2 : 0 - height: Bar.height + General.rectMargin / 1.5 - opacity: activePlayer ? 1 : 0 - - IRect { - id: rect - anchors.verticalCenter: parent.verticalCenter - implicitWidth: (layout.width + General.rectMargin * 4) * (mouseArea.containsMouse ? Bar.hoverScale : 1.0) - height: parent.height - General.rectMargin - radius: Style.rounding.smaller - color: "transparent" - - // FIXME: at the start, the progress bar's radius will make it go out of bounds. use OpacityMask or something - Slider { - id: pBar - anchors.fill: parent - - handle: Item - from: 0 - to: activePlayer?.length || 0 - value: activePlayer?.position || 0 - background: IRect { - anchors.fill: parent - color: Colors.accent - radius: Style.rounding.smaller - } - contentItem: Item { - IRect { - width: pBar.visualPosition * parent.width - height: parent.height - color: Qt.rgba(Colors.accentAlt.r, Colors.accentAlt.g, Colors.accentAlt.b, General.accentTransparency * 1.5) - radius: Style.rounding.smaller - - Behavior on width { - NumberAnimation { - duration: General.animationDuration / 2 - } - } - } - } - - // onMoved: { - // if (Math.round(root.activePlayer.position) !== Math.round(value)) { - // root.activePlayer.position = value; - // } - // } - - // cannot remove and replace with modern non stealing handlers cuz otherwise slider will steal from us - MouseArea { - id: mouseArea - anchors.fill: parent - acceptedButtons: Qt.MiddleButton | Qt.RightButton | Qt.LeftButton - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onClicked: mouse => { - if (mouse.button === Qt.MiddleButton) - root.activePlayer?.togglePlaying(); - else if (mouse.button === Qt.RightButton) - root.activePlayer?.next(); - } - onWheel: mouse => { - root.activePlayer?.seek(-mouse.angleDelta.y * Bar.mediaScrollScale); - } - } - } - - RowLayout { - id: layout - - x: (parent.width - width) / 2 - y: (parent.height - height) / 2 - spacing: Bar.resourceIconTextSpacing / 1.5 - - Behavior on x { - ISpringAnimation { - spring: General.springAnimationSpring * 2 - damping: General.springAnimationDamping * 1.3 - } - } - - Item { - Layout.preferredWidth: childrenRect.width - Layout.preferredHeight: childrenRect.height - width: General.appIconSize - height: General.appIconSize - - opacity: activePlayer?.playbackState === MprisPlaybackState.Playing ? 1 : Bar.mediaPausedOpacity - - DropShadow { - anchors.fill: image - source: image - opacity: activePlayer?.playbackState === MprisPlaybackState.Playing ? 1 : Bar.mediaPausedOpacity - radius: 6 - color: Colors.background3 - - Behavior on opacity { - NumberAnimation { - duration: General.animationDuration / 4 - easing.type: Easing.InOutQuad - } - } - } - - ClippingWrapperRectangle { - id: image - anchors.fill: parent - radius: 6 - color: "transparent" - child: Image { - id: albumArt - // IconImage makes it less crisp and blurry - anchors.fill: parent - source: activePlayer?.trackArtUrl || Quickshell.iconPath(Services.AppSearch.guessIcon(activePlayer?.desktopEntry), "image-missing") - antialiasing: true - asynchronous: true - ColorOverlay { - property color rawColor: activePlayer?.playbackState === MprisPlaybackState.Playing ? Colors.background1 : Colors.background2 - anchors.fill: albumArt - source: albumArt - color: Qt.rgba(rawColor.r, rawColor.g, rawColor.b, General.accentTransparency) - - Behavior on color { - ColorAnimation { - duration: General.animationDuration / 4 - easing.type: Easing.InOutQuad - } - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: General.animationDuration / 4 - easing.type: Easing.InOutQuad - } - } - } - IText { - animate: true - color: activePlayer?.playbackState === MprisPlaybackState.Playing ? Qt.rgba(Colors.foreground1.r, Colors.foreground1.g, Colors.foreground1.b, Colors.foreground1.a) : Qt.rgba(Colors.foreground2.r, Colors.foreground2.g, Colors.foreground2.b, Bar.mediaPausedOpacity) - text: root.cleanedTitle - - Behavior on opacity { - NumberAnimation { - duration: General.animationDuration / 4 - easing.type: Easing.InOutQuad - } - } - - Behavior on color { - ColorAnimation { - duration: General.animationDuration / 4 - easing.type: Easing.InOutQuad - } - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: General.animationDuration / 4 - } - } - - Behavior on width { - ISpringAnimation { - spring: General.springAnimationSpring * 2 - damping: General.springAnimationDamping * 1.3 - } - } - - Behavior on implicitWidth { - ISpringAnimation { - spring: General.springAnimationSpring * 2 - damping: General.springAnimationDamping * 1.3 - } - } + id: root + readonly property MprisPlayer activePlayer: Services.Mpris.activePlayer + readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) + + implicitWidth: activePlayer ? rect.width - General.rectMargin / 1.2 : 0 + height: Bar.height + General.rectMargin / 1.5 + opacity: activePlayer ? 1 : 0 + + IRect { + id: rect + anchors.verticalCenter: parent.verticalCenter + implicitWidth: (layout.width + General.rectMargin * 4) * (mouseArea.containsMouse ? Bar.hoverScale : 1.0) + height: parent.height - General.rectMargin + radius: Style.rounding.smaller + color: "transparent" + + // FIXME: at the start, the progress bar's radius will make it go out of bounds. use OpacityMask or something + Slider { + id: pBar + anchors.fill: parent + + handle: Item + from: 0 + to: activePlayer?.length || 0 + value: activePlayer?.position || 0 + background: IRect { + anchors.fill: parent + color: Colors.accent + radius: Style.rounding.smaller + } + contentItem: Item { + IRect { + width: pBar.visualPosition * parent.width + height: parent.height + color: Qt.rgba(Colors.accentAlt.r, Colors.accentAlt.g, Colors.accentAlt.b, General.accentTransparency * 1.5) + radius: Style.rounding.smaller + + Behavior on width { + NumberAnimation { + duration: General.animationDuration / 2 + } + } + } + } + + // onMoved: { + // if (Math.round(root.activePlayer.position) !== Math.round(value)) { + // root.activePlayer.position = value; + // } + // } + + // cannot remove and replace with modern non stealing handlers cuz otherwise slider will steal from us + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.MiddleButton | Qt.RightButton | Qt.LeftButton + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onClicked: mouse => { + if (mouse.button === Qt.MiddleButton) + root.activePlayer?.togglePlaying(); + else if (mouse.button === Qt.RightButton) + root.activePlayer?.next(); + } + onWheel: mouse => { + root.activePlayer?.seek(-mouse.angleDelta.y * Bar.mediaScrollScale); + } + } + } + + RowLayout { + id: layout + + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + spacing: Bar.resourceIconTextSpacing / 1.5 + + Behavior on x { + ISpringAnimation { + spring: General.springAnimationSpring * 2 + damping: General.springAnimationDamping * 1.3 + } + } + + Item { + Layout.preferredWidth: childrenRect.width + Layout.preferredHeight: childrenRect.height + width: General.appIconSize + height: General.appIconSize + + opacity: activePlayer?.playbackState === MprisPlaybackState.Playing ? 1 : Bar.mediaPausedOpacity + + DropShadow { + anchors.fill: image + source: image + opacity: activePlayer?.playbackState === MprisPlaybackState.Playing ? 1 : Bar.mediaPausedOpacity + radius: 6 + color: Colors.background3 + + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + easing.type: Easing.InOutQuad + } + } + } + + ClippingWrapperRectangle { + id: image + anchors.fill: parent + radius: 6 + color: "transparent" + child: Image { + id: albumArt + // IconImage makes it less crisp and blurry + anchors.fill: parent + source: activePlayer?.trackArtUrl || Quickshell.iconPath(Services.AppSearch.guessIcon(activePlayer?.desktopEntry), "image-missing") + antialiasing: true + asynchronous: true + ColorOverlay { + property color rawColor: activePlayer?.playbackState === MprisPlaybackState.Playing ? Colors.background1 : Colors.background2 + anchors.fill: albumArt + source: albumArt + color: Qt.rgba(rawColor.r, rawColor.g, rawColor.b, General.accentTransparency) + + Behavior on color { + ColorAnimation { + duration: General.animationDuration / 4 + easing.type: Easing.InOutQuad + } + } + } + } + } + + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + easing.type: Easing.InOutQuad + } + } + } + IText { + animate: true + color: activePlayer?.playbackState === MprisPlaybackState.Playing ? Qt.rgba(Colors.foreground1.r, Colors.foreground1.g, Colors.foreground1.b, Colors.foreground1.a) : Qt.rgba(Colors.foreground2.r, Colors.foreground2.g, Colors.foreground2.b, Bar.mediaPausedOpacity) + text: root.cleanedTitle + + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + easing.type: Easing.InOutQuad + } + } + + Behavior on color { + ColorAnimation { + duration: General.animationDuration / 4 + easing.type: Easing.InOutQuad + } + } + } + } + } + + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + } + } + + Behavior on width { + ISpringAnimation { + spring: General.springAnimationSpring * 2 + damping: General.springAnimationDamping * 1.3 + } + } + + Behavior on implicitWidth { + ISpringAnimation { + spring: General.springAnimationSpring * 2 + damping: General.springAnimationDamping * 1.3 + } + } } diff --git a/bar/Network.qml b/bar/Network.qml index a343977..940f583 100644 --- a/bar/Network.qml +++ b/bar/Network.qml @@ -6,116 +6,116 @@ import qs.components import qs.config Item { - id: root - property int down: Services.NetworkUsage.down - property string downUnit: Services.NetworkUsage.downUnit - property int up: Services.NetworkUsage.up - property string upUnit: Services.NetworkUsage.upUnit + id: root + property int down: Services.NetworkUsage.down + property string downUnit: Services.NetworkUsage.downUnit + property int up: Services.NetworkUsage.up + property string upUnit: Services.NetworkUsage.upUnit - property int significantUsage: 30 - property string usageUnit: "M" + property int significantUsage: 30 + property string usageUnit: "M" - property bool isCollapsed: true + property bool isCollapsed: true - implicitWidth: container.implicitWidth - implicitHeight: container.implicitHeight - General.rectMargin + implicitWidth: container.implicitWidth + implicitHeight: container.implicitHeight - General.rectMargin - IRect { - id: container - anchors { - fill: parent - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } + IRect { + id: container + anchors { + fill: parent + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } - implicitWidth: layout.implicitWidth + General.rectMargin * 2 - implicitHeight: Bar.height - color: Colors.accent - radius: Style.rounding.large + implicitWidth: layout.implicitWidth + General.rectMargin * 2 + implicitHeight: Bar.height + color: Colors.accent + radius: Style.rounding.large - RowLayout { - id: layout - anchors { - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - spacing: Bar.resourceIconTextSpacing + RowLayout { + id: layout + anchors { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + spacing: Bar.resourceIconTextSpacing - Item { - Layout.fillWidth: true - } + Item { + Layout.fillWidth: true + } - Icon { - visible: root.isCollapsed - text: Services.Network.state - } - IText { - visible: !root.isCollapsed - text: Services.Network.networkStrength - renderType: Text.CurveRendering // it's not static and is rapidly updated - } + Icon { + visible: root.isCollapsed + text: Services.Network.state + } + IText { + visible: !root.isCollapsed + text: Services.Network.networkStrength + renderType: Text.CurveRendering // it's not static and is rapidly updated + } - ColumnLayout { - // spacing: Bar.resourceIconTextSpacing / 2 - spacing: 0 - Item { - Layout.fillHeight: true - Layout.fillWidth: true - } - IText { - animate: true - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - text: root.down + root.downUnit - color: root.downUnit == root.usageUnit && root.down > root.significantUsage ? Colors.cyan : Colors.foreground2 - renderType: Text.CurveRendering // it's not static and is rapidly updated - } - Icon { - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - text: Icons.resource.network.download - iconSize: Style.font.size.normal - color: root.downUnit == root.usageUnit && root.down > root.significantUsage ? Colors.cyan : Colors.foreground2 - } - Item { - Layout.fillHeight: true - Layout.fillWidth: true - } - } - ColumnLayout { - // spacing: Bar.resourceIconTextSpacing / 2 - spacing: 0 - Item { - Layout.fillHeight: true - Layout.fillWidth: true - } - Icon { - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - text: Icons.resource.network.upload - iconSize: Style.font.size.normal - color: root.upUnit == root.usageUnit && root.up > root.significantUsage ? Colors.cyan : Colors.foreground2 - } - IText { - animate: true - Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - text: root.up + root.upUnit - color: root.upUnit == root.usageUnit && root.up > root.significantUsage ? Colors.cyan : Colors.foreground2 - renderType: Text.CurveRendering // it's not static and is rapidly updated - } - Item { - Layout.fillHeight: true - Layout.fillWidth: true - } - } + ColumnLayout { + // spacing: Bar.resourceIconTextSpacing / 2 + spacing: 0 + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + IText { + animate: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + text: root.down + root.downUnit + color: root.downUnit == root.usageUnit && root.down > root.significantUsage ? Colors.cyan : Colors.foreground2 + renderType: Text.CurveRendering // it's not static and is rapidly updated + } + Icon { + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + text: Icons.resource.network.download + iconSize: Style.font.size.normal + color: root.downUnit == root.usageUnit && root.down > root.significantUsage ? Colors.cyan : Colors.foreground2 + } + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + } + ColumnLayout { + // spacing: Bar.resourceIconTextSpacing / 2 + spacing: 0 + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + Icon { + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + text: Icons.resource.network.upload + iconSize: Style.font.size.normal + color: root.upUnit == root.usageUnit && root.up > root.significantUsage ? Colors.cyan : Colors.foreground2 + } + IText { + animate: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + text: root.up + root.upUnit + color: root.upUnit == root.usageUnit && root.up > root.significantUsage ? Colors.cyan : Colors.foreground2 + renderType: Text.CurveRendering // it's not static and is rapidly updated + } + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + } - Item { - Layout.fillWidth: true - } - } - } - MouseArea { - anchors.fill: container - cursorShape: Qt.PointingHandCursor - onClicked: { - root.isCollapsed = !root.isCollapsed; - } - } + Item { + Layout.fillWidth: true + } + } + } + MouseArea { + anchors.fill: container + cursorShape: Qt.PointingHandCursor + onClicked: { + root.isCollapsed = !root.isCollapsed; + } + } } diff --git a/bar/Power.qml b/bar/Power.qml index a29bc4a..289f8e8 100644 --- a/bar/Power.qml +++ b/bar/Power.qml @@ -8,117 +8,117 @@ import qs.components // TODO: move to a full screen menu Item { - id: root - - implicitWidth: container.implicitWidth - implicitHeight: container.implicitHeight - - property bool collapsed: true - - IRect { - id: container - - anchors { - fill: parent - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - implicitWidth: layout.implicitWidth + General.rectMargin * 2 - implicitHeight: Bar.height - General.rectMargin - - color: Colors.accent - radius: Style.rounding.large - - RowLayout { - id: layout - - anchors.fill: parent - spacing: Bar.resourceIconTextSpacing - - Item { - Layout.fillWidth: true - } - - Icon { - id: powerIcon - text: Icons.power.shutdown - font.pixelSize: Style.font.size.large - color: Colors.red - } - - Item { - implicitWidth: root.collapsed ? 0 : loader.width - visible: root.collapsed ? false : true - Loader { - id: loader - anchors.verticalCenter: parent.verticalCenter - active: !root.collapsed - sourceComponent: Component { - RowLayout { - spacing: Bar.resourceIconTextSpacing - Icon { - text: Icons.power.dpms - font.pixelSize: Style.font.size.large - } - - Icon { - text: Icons.power.lock - font.pixelSize: Style.font.size.large - } - - Icon { - text: Icons.power.suspend - font.pixelSize: Style.font.size.large - } - - Icon { - text: Icons.power.reboot - font.pixelSize: Style.font.size.large - } - SequentialAnimation { - running: true - NumberAnimation { - target: parent - property: "opacity" - from: 0 - to: 1 - duration: General.animationDuration / 2 - easing.type: Easing.InOutQuad - } - } - } - } - } - Behavior on implicitWidth { - NumberAnimation { - duration: General.animationDuration / 4 - easing.type: Easing.InOutQuad - } - } - - // no idea why when collapsing the width animation won't trigger - Behavior on visible { - NumberAnimation { - duration: General.animationDuration / 4 - easing.type: Easing.InOutQuad - } - } - } - - Item { - Layout.fillWidth: true - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: { - root.collapsed = false; - } - onExited: { - root.collapsed = true; - } - } - } + id: root + + implicitWidth: container.implicitWidth + implicitHeight: container.implicitHeight + + property bool collapsed: true + + IRect { + id: container + + anchors { + fill: parent + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + implicitWidth: layout.implicitWidth + General.rectMargin * 2 + implicitHeight: Bar.height - General.rectMargin + + color: Colors.accent + radius: Style.rounding.large + + RowLayout { + id: layout + + anchors.fill: parent + spacing: Bar.resourceIconTextSpacing + + Item { + Layout.fillWidth: true + } + + Icon { + id: powerIcon + text: Icons.power.shutdown + font.pixelSize: Style.font.size.large + color: Colors.red + } + + Item { + implicitWidth: root.collapsed ? 0 : loader.width + visible: root.collapsed ? false : true + Loader { + id: loader + anchors.verticalCenter: parent.verticalCenter + active: !root.collapsed + sourceComponent: Component { + RowLayout { + spacing: Bar.resourceIconTextSpacing + Icon { + text: Icons.power.dpms + font.pixelSize: Style.font.size.large + } + + Icon { + text: Icons.power.lock + font.pixelSize: Style.font.size.large + } + + Icon { + text: Icons.power.suspend + font.pixelSize: Style.font.size.large + } + + Icon { + text: Icons.power.reboot + font.pixelSize: Style.font.size.large + } + SequentialAnimation { + running: true + NumberAnimation { + target: parent + property: "opacity" + from: 0 + to: 1 + duration: General.animationDuration / 2 + easing.type: Easing.InOutQuad + } + } + } + } + } + Behavior on implicitWidth { + NumberAnimation { + duration: General.animationDuration / 4 + easing.type: Easing.InOutQuad + } + } + + // no idea why when collapsing the width animation won't trigger + Behavior on visible { + NumberAnimation { + duration: General.animationDuration / 4 + easing.type: Easing.InOutQuad + } + } + } + + Item { + Layout.fillWidth: true + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onEntered: { + root.collapsed = false; + } + onExited: { + root.collapsed = true; + } + } + } } diff --git a/bar/Resources.qml b/bar/Resources.qml index a4d2a2f..943bd52 100644 --- a/bar/Resources.qml +++ b/bar/Resources.qml @@ -7,53 +7,53 @@ import qs.config as Config import qs.services as Services Item { - implicitWidth: container.implicitWidth - implicitHeight: container.implicitHeight + implicitWidth: container.implicitWidth + implicitHeight: container.implicitHeight - IRect { - id: container - implicitWidth: layout.implicitWidth + Config.General.rectMargin * 2 - implicitHeight: Config.Bar.height - Config.General.rectMargin + IRect { + id: container + implicitWidth: layout.implicitWidth + Config.General.rectMargin * 2 + implicitHeight: Config.Bar.height - Config.General.rectMargin - color: Config.Colors.accent - radius: Config.Style.rounding.large + color: Config.Colors.accent + radius: Config.Style.rounding.large - Row { - id: layout - anchors.centerIn: parent - SimpleResource { - value: Math.round(Services.Resource.cpuUsage * 100) - altValue: Math.round(Services.Resource.cpuFreq / 10) / 100 - suffix: "%" - altSuffix: "GHz" - icon: Config.Icons.resource.cpu - } - SimpleResource { - icon: Config.Icons.resource.memory - value: Math.round(Services.Resource.memoryUsedPercentage * 100) - altValue: Math.round(Services.Resource.memoryUsed / 1024 / 1024) - suffix: "%" - altSuffix: "GB" - } - SimpleResource { - icon: Config.Icons.resource.gpu - value: Services.Resource.gpuUsage - altValue: Services.Resource.gpuTemp - suffix: "%" - altSuffix: "°C" - altIcon: Config.Icons.resource.temp - thresholdL1: 60 - thresholdL2: 70 - thresholdL3: 80 - } - SimpleResource { - icon: Config.Icons.resource.temp - value: Math.round(Services.Resource.cpuTemp * 100) - suffix: "°C" - thresholdL1: 60 - thresholdL2: 80 - thresholdL3: 90 - } - } - } + Row { + id: layout + anchors.centerIn: parent + SimpleResource { + value: Math.round(Services.Resource.cpuUsage * 100) + altValue: Math.round(Services.Resource.cpuFreq / 10) / 100 + suffix: "%" + altSuffix: "GHz" + icon: Config.Icons.resource.cpu + } + SimpleResource { + icon: Config.Icons.resource.memory + value: Math.round(Services.Resource.memoryUsedPercentage * 100) + altValue: Math.round(Services.Resource.memoryUsed / 1024 / 1024) + suffix: "%" + altSuffix: "GB" + } + SimpleResource { + icon: Config.Icons.resource.gpu + value: Services.Resource.gpuUsage + altValue: Services.Resource.gpuTemp + suffix: "%" + altSuffix: "°C" + altIcon: Config.Icons.resource.temp + thresholdL1: 60 + thresholdL2: 70 + thresholdL3: 80 + } + SimpleResource { + icon: Config.Icons.resource.temp + value: Math.round(Services.Resource.cpuTemp * 100) + suffix: "°C" + thresholdL1: 60 + thresholdL2: 80 + thresholdL3: 90 + } + } + } } diff --git a/bar/TimeDate.qml b/bar/TimeDate.qml index 2716e6d..ddeca47 100644 --- a/bar/TimeDate.qml +++ b/bar/TimeDate.qml @@ -6,128 +6,128 @@ import qs.components import qs.config Item { - id: root + id: root - property bool isAlt: false - property bool isCollapsed: false + property bool isAlt: false + property bool isCollapsed: false - implicitWidth: container.implicitWidth - implicitHeight: container.implicitHeight - General.rectMargin - IRect { - id: container - anchors { - fill: parent - centerIn: parent - } + implicitWidth: container.implicitWidth + implicitHeight: container.implicitHeight - General.rectMargin + IRect { + id: container + anchors { + fill: parent + centerIn: parent + } - // implicitWidth: !isAlt ? nonAlt.implicitWidth + General.rectMargin * 2 : alt.implicitWidth + General.rectMargin * 2 - implicitWidth: layout.width + General.rectMargin * 2 - implicitHeight: Bar.height + // implicitWidth: !isAlt ? nonAlt.implicitWidth + General.rectMargin * 2 : alt.implicitWidth + General.rectMargin * 2 + implicitWidth: layout.width + General.rectMargin * 2 + implicitHeight: Bar.height - color: Colors.accent - radius: Style.rounding.large + color: Colors.accent + radius: Style.rounding.large - RowLayout { - id: layout - anchors.centerIn: parent - spacing: Bar.resourceIconTextSpacing - Loader { - sourceComponent: !root.isAlt ? main : alt - readonly property Component main: Component { - RowLayout { - id: root - property int h: Services.TimeDate.hours - property int m: Services.TimeDate.minutes - property int s: Services.TimeDate.seconds + RowLayout { + id: layout + anchors.centerIn: parent + spacing: Bar.resourceIconTextSpacing + Loader { + sourceComponent: !root.isAlt ? main : alt + readonly property Component main: Component { + RowLayout { + id: root + property int h: Services.TimeDate.hours + property int m: Services.TimeDate.minutes + property int s: Services.TimeDate.seconds - Item { - Layout.fillWidth: true - } - anchors.centerIn: parent - spacing: Bar.resourceIconTextSpacing + Item { + Layout.fillWidth: true + } + anchors.centerIn: parent + spacing: Bar.resourceIconTextSpacing - Icon { - text: Icons.resource.clock[root.h - 1] - font.pixelSize: Style.font.size.larger - } - RowLayout { - spacing: 0 - IText { - animate: true - text: (root.h >= 10 ? "" : "0") + root.h - } - IText { - text: ":" - renderType: Text.CurveRendering - } - IText { - animate: true - text: (root.m >= 10 ? "" : "0") + root.m - } - IText { - text: ":" - renderType: Text.CurveRendering - } - IText { - animate: true - text: (root.s >= 10 ? "" : "0") + root.s - renderType: Text.QtRendering // it's not static and is rapidly updated - } - } - Item { - Layout.fillWidth: true - } - SequentialAnimation { - running: true - NumberAnimation { - target: parent - property: "opacity" - from: 0 - to: 1 - duration: General.animationDuration / 2 - } - } - } - } - readonly property Component alt: Component { - RowLayout { - Item { - Layout.fillWidth: true - } - anchors.centerIn: parent - spacing: Bar.resourceIconTextSpacing + Icon { + text: Icons.resource.clock[root.h - 1] + font.pixelSize: Style.font.size.larger + } + RowLayout { + spacing: 0 + IText { + animate: true + text: (root.h >= 10 ? "" : "0") + root.h + } + IText { + text: ":" + renderType: Text.CurveRendering + } + IText { + animate: true + text: (root.m >= 10 ? "" : "0") + root.m + } + IText { + text: ":" + renderType: Text.CurveRendering + } + IText { + animate: true + text: (root.s >= 10 ? "" : "0") + root.s + renderType: Text.QtRendering // it's not static and is rapidly updated + } + } + Item { + Layout.fillWidth: true + } + SequentialAnimation { + running: true + NumberAnimation { + target: parent + property: "opacity" + from: 0 + to: 1 + duration: General.animationDuration / 2 + } + } + } + } + readonly property Component alt: Component { + RowLayout { + Item { + Layout.fillWidth: true + } + anchors.centerIn: parent + spacing: Bar.resourceIconTextSpacing - Icon { - text: Icons.resource.calendar - font.pixelSize: Style.font.size.larger - } - IText { - animate: true - text: Services.TimeDate.date - } - Item { - Layout.fillWidth: true - } - SequentialAnimation { - running: true - NumberAnimation { - target: parent - property: "opacity" - from: 0 - to: 1 - duration: General.animationDuration / 2 - } - } - } - } - } - } - } - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: { - root.isAlt = !root.isAlt; - } - } + Icon { + text: Icons.resource.calendar + font.pixelSize: Style.font.size.larger + } + IText { + animate: true + text: Services.TimeDate.date + } + Item { + Layout.fillWidth: true + } + SequentialAnimation { + running: true + NumberAnimation { + target: parent + property: "opacity" + from: 0 + to: 1 + duration: General.animationDuration / 2 + } + } + } + } + } + } + } + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onPressed: { + root.isAlt = !root.isAlt; + } + } } diff --git a/bar/Workspace.qml b/bar/Workspace.qml index 52f2d1b..51c4ba4 100644 --- a/bar/Workspace.qml +++ b/bar/Workspace.qml @@ -6,241 +6,241 @@ import qs.config import qs.components Item { - id: root - - implicitWidth: layout.implicitWidth - - property var ws: Hyprland.workspaces - property var toplevels: Hyprland.toplevels.values // update activeOccupied when toplevels changes as getWorkspaceStat's return is non reactive - - property int activeIndex: -1 - property bool activeOccupied: false - property bool toChild: false - - function getWorkspaceStats(index) { - const w = ws.values.find(i => i.id === index + 1); - return { - isOccupied: w?.toplevels?.values?.length, - isActive: w?.active, - isUrgent: w?.urgent - }; - } - - onToplevelsChanged: { - Qt.callLater(() => { - activeOccupied = getWorkspaceStats(activeIndex).isOccupied || false; - }); - } - - DropShadow { - anchors.fill: activeRect - source: activeRect - radius: 8 - cached: true - color: root.activeOccupied ? Colors.accent : Colors.foreground1 - opacity: root.activeOccupied ? Bar.wsActiveOpacity : Bar.wsEmptyOpacity / 3 - - Behavior on color { - ColorAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - Behavior on opacity { - NumberAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - } - IRect { - id: activeRect - x: layout.x + root.activeIndex * Bar.wsIconSize + root.activeIndex * Bar.wsSpacing - anchors.verticalCenter: layout.verticalCenter - implicitWidth: Bar.wsActiveIconSize - implicitHeight: Bar.wsIconSize - Bar.wsHorizontalSpacing - radius: Bar.wsRounding - color: root.activeOccupied ? Colors.accent : Colors.foreground1 - opacity: root.activeOccupied ? Bar.wsActiveOpacity : Bar.wsEmptyOpacity / 3 - Behavior on x { - ISpringAnimation {} - } - Behavior on color { - ColorAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - Behavior on opacity { - NumberAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - Behavior on width { - NumberAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - } - - RowLayout { - id: layout - anchors.verticalCenter: parent.verticalCenter - implicitWidth: repeater.width - spacing: Bar.wsSpacing - - Repeater { - id: repeater - model: Bar.wss - - IRect { - property var st: getWorkspaceStats(index) - property bool active: st?.isActive || false - - implicitWidth: active ? Bar.wsActiveIconSize : Bar.wsIconSize - implicitHeight: Bar.wsIconSize - Bar.wsHorizontalSpacing - radius: Bar.wsRounding - color: st.isOccupied ? Colors.accent : Colors.foreground1 - opacity: active && st.isOccupied ? Bar.wsActiveOpacity : st.isOccupied ? Bar.wsOpacity : Bar.wsEmptyOpacity - - Icon { - anchors.centerIn: parent - text: !st.isUrgent ? Icons.ws[index + 1] : Icons.ws['urgent'] - font.pixelSize: !active ? Bar.wsIconSize / 2 : Bar.wsActiveIconSize / 2.5 - opacity: !st.isOccupied ? 0 : 1 - color: !st.isUrgent ? !st.isActive ? Colors.foreground2 : Colors.foreground1 : Colors.red - Behavior on font.pixelSize { - ISpringAnimation {} - } - Behavior on color { - ColorAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - } - - MouseArea { - anchors { - fill: parent - topMargin: Bar.wsExtraMouseArea * -1 - bottomMargin: Bar.wsExtraMouseArea * -1 - } - - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - hoverEnabled: true - - onPressed: { - if (!parent.active) - Hyprland.dispatch(`hl.dsp.focus({ workspace = '${index + 1}' })`); - } - function moveActive() { - activeRect.x = parent.x; - root.activeOccupied = st.isOccupied || false; - activeRect.implicitWidth = active ? Bar.wsActiveIconSize : Bar.wsIconSize; - } - onEntered: { - root.toChild = true; - moveActive(); - } - // https://github.com/quickshell-mirror/quickshell/issues/118 - // onEntered: { - // moveActive(); - // } - onExited: { - root.toChild = false; - // outer MouseArea will handle this - // if (!active && previousActiveIndex >= 0) { - // // just in case - // activeRect.x = layout.x + previousActiveIndex * Bar.wsIconSize + previousActiveIndex * Bar.wsSpacing; - // activeRect.implicitWidth = Bar.wsActiveIconSize; - // // root.activeOccupied = parent.st.isOccupied || false; - // root.activeOccupied = getWorkspaceStats(previousActiveIndex).isOccupied || false; - // previousActiveIndex = -1; - // } - } - onWheel: event => { - // no idea wats wrong w/ prev so we just unify it to use +/- 1 - if (event.angleDelta.y < 0) { - if (activeIndex + 1 < Bar.wss) - Hyprland.dispatch(`hl.dsp.focus({ workspace = '+1' })`); - else - Hyprland.dispatch(`hl.dsp.focus({ workspace = '1' })`); - } else if (event.angleDelta.y > 0) { - if (activeIndex + 1 > 1) { - Hyprland.dispatch(`hl.dsp.focus({ workspace = '-1' })`); - } else if (Bar.wss > 1) { - Hyprland.dispatch(`hl.dsp.focus({ workspace = '${Bar.wss}' })`); - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - Behavior on implicitWidth { - NumberAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - Behavior on color { - ColorAnimation { - duration: Bar.wsAnimationDuration - easing.type: Easing.InOutQuad - } - } - - onActiveChanged: if (active) { - root.activeIndex = index; - root.activeOccupied = st.isOccupied; - activeRect.implicitWidth = Bar.wsActiveIconSize; - } - } - } - } - MouseArea { - height: Bar.height - width: parent.width - hoverEnabled: true - z: -1000 // to be below the child's MouseArea - acceptedButtons: Qt.MiddleButton - - // sync w the inner MouseArea - // https://github.com/quickshell-mirror/quickshell/issues/118 // but onEnter won't update the mouseX - onEntered: { - const abovedItemIndex = Math.round((mouseX - layout.x) / (Bar.wsIconSize + Bar.wsSpacing)) - 1; // TODO: workspaceActiveIconSize might be before - activeRect.x = mouseX - activeRect.width / 2; - root.activeOccupied = root.getWorkspaceStats(abovedItemIndex).isOccupied || false; - activeRect.implicitWidth = root.activeIndex === abovedItemIndex ? Bar.wsActiveIconSize : Bar.wsIconSize; - } - onExited: { - if (!root.toChild && root.activeIndex >= 0) { - // just in case - activeRect.x = layout.x + root.activeIndex * Bar.wsIconSize + root.activeIndex * Bar.wsSpacing; - activeRect.implicitWidth = Bar.wsActiveIconSize; - root.activeOccupied = root.getWorkspaceStats(root.activeIndex).isOccupied || false; - } - } - onWheel: event => { - // no idea wats wrong w/ prev so we just unify it to use +/- 1 - if (event.angleDelta.y < 0) { - if (root.activeIndex + 1 < Bar.wss) - Hyprland.dispatch(`hl.dsp.focus({ workspace = '+1' })`); - else - Hyprland.dispatch(`hl.dsp.focus({ workspace = '1' })`); - } else if (event.angleDelta.y > 0) { - if (root.activeIndex + 1 > 1) - Hyprland.dispatch(`hl.dsp.focus({ workspace = '1' })`); - else if (Bar.wss > 1) - Hyprland.dispatch(`hl.dsp.focus({ workspace = '${Bar.wss}' })`); - } - } - } + id: root + + implicitWidth: layout.implicitWidth + + property var ws: Hyprland.workspaces + property var toplevels: Hyprland.toplevels.values // update activeOccupied when toplevels changes as getWorkspaceStat's return is non reactive + + property int activeIndex: -1 + property bool activeOccupied: false + property bool toChild: false + + function getWorkspaceStats(index) { + const w = ws.values.find(i => i.id === index + 1); + return { + isOccupied: w?.toplevels?.values?.length, + isActive: w?.active, + isUrgent: w?.urgent + }; + } + + onToplevelsChanged: { + Qt.callLater(() => { + activeOccupied = getWorkspaceStats(activeIndex).isOccupied || false; + }); + } + + DropShadow { + anchors.fill: activeRect + source: activeRect + radius: 8 + cached: true + color: root.activeOccupied ? Colors.accent : Colors.foreground1 + opacity: root.activeOccupied ? Bar.wsActiveOpacity : Bar.wsEmptyOpacity / 3 + + Behavior on color { + ColorAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + Behavior on opacity { + NumberAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + } + IRect { + id: activeRect + x: layout.x + root.activeIndex * Bar.wsIconSize + root.activeIndex * Bar.wsSpacing + anchors.verticalCenter: layout.verticalCenter + implicitWidth: Bar.wsActiveIconSize + implicitHeight: Bar.wsIconSize - Bar.wsHorizontalSpacing + radius: Bar.wsRounding + color: root.activeOccupied ? Colors.accent : Colors.foreground1 + opacity: root.activeOccupied ? Bar.wsActiveOpacity : Bar.wsEmptyOpacity / 3 + Behavior on x { + ISpringAnimation {} + } + Behavior on color { + ColorAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + Behavior on opacity { + NumberAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + Behavior on width { + NumberAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + } + + RowLayout { + id: layout + anchors.verticalCenter: parent.verticalCenter + implicitWidth: repeater.width + spacing: Bar.wsSpacing + + Repeater { + id: repeater + model: Bar.wss + + IRect { + property var st: getWorkspaceStats(index) + property bool active: st?.isActive || false + + implicitWidth: active ? Bar.wsActiveIconSize : Bar.wsIconSize + implicitHeight: Bar.wsIconSize - Bar.wsHorizontalSpacing + radius: Bar.wsRounding + color: st.isOccupied ? Colors.accent : Colors.foreground1 + opacity: active && st.isOccupied ? Bar.wsActiveOpacity : st.isOccupied ? Bar.wsOpacity : Bar.wsEmptyOpacity + + Icon { + anchors.centerIn: parent + text: !st.isUrgent ? Icons.ws[index + 1] : Icons.ws['urgent'] + font.pixelSize: !active ? Bar.wsIconSize / 2 : Bar.wsActiveIconSize / 2.5 + opacity: !st.isOccupied ? 0 : 1 + color: !st.isUrgent ? !st.isActive ? Colors.foreground2 : Colors.foreground1 : Colors.red + Behavior on font.pixelSize { + ISpringAnimation {} + } + Behavior on color { + ColorAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + } + + MouseArea { + anchors { + fill: parent + topMargin: Bar.wsExtraMouseArea * -1 + bottomMargin: Bar.wsExtraMouseArea * -1 + } + + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + hoverEnabled: true + + onPressed: { + if (!parent.active) + Hyprland.dispatch(`hl.dsp.focus({ workspace = '${index + 1}' })`); + } + function moveActive() { + activeRect.x = parent.x; + root.activeOccupied = st.isOccupied || false; + activeRect.implicitWidth = active ? Bar.wsActiveIconSize : Bar.wsIconSize; + } + onEntered: { + root.toChild = true; + moveActive(); + } + // https://github.com/quickshell-mirror/quickshell/issues/118 + // onEntered: { + // moveActive(); + // } + onExited: { + root.toChild = false; + // outer MouseArea will handle this + // if (!active && previousActiveIndex >= 0) { + // // just in case + // activeRect.x = layout.x + previousActiveIndex * Bar.wsIconSize + previousActiveIndex * Bar.wsSpacing; + // activeRect.implicitWidth = Bar.wsActiveIconSize; + // // root.activeOccupied = parent.st.isOccupied || false; + // root.activeOccupied = getWorkspaceStats(previousActiveIndex).isOccupied || false; + // previousActiveIndex = -1; + // } + } + onWheel: event => { + // no idea wats wrong w/ prev so we just unify it to use +/- 1 + if (event.angleDelta.y < 0) { + if (activeIndex + 1 < Bar.wss) + Hyprland.dispatch(`hl.dsp.focus({ workspace = '+1' })`); + else + Hyprland.dispatch(`hl.dsp.focus({ workspace = '1' })`); + } else if (event.angleDelta.y > 0) { + if (activeIndex + 1 > 1) { + Hyprland.dispatch(`hl.dsp.focus({ workspace = '-1' })`); + } else if (Bar.wss > 1) { + Hyprland.dispatch(`hl.dsp.focus({ workspace = '${Bar.wss}' })`); + } + } + } + } + + Behavior on opacity { + NumberAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + Behavior on implicitWidth { + NumberAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + Behavior on color { + ColorAnimation { + duration: Bar.wsAnimationDuration + easing.type: Easing.InOutQuad + } + } + + onActiveChanged: if (active) { + root.activeIndex = index; + root.activeOccupied = st.isOccupied; + activeRect.implicitWidth = Bar.wsActiveIconSize; + } + } + } + } + MouseArea { + height: Bar.height + width: parent.width + hoverEnabled: true + z: -1000 // to be below the child's MouseArea + acceptedButtons: Qt.MiddleButton + + // sync w the inner MouseArea + // https://github.com/quickshell-mirror/quickshell/issues/118 // but onEnter won't update the mouseX + onEntered: { + const abovedItemIndex = Math.round((mouseX - layout.x) / (Bar.wsIconSize + Bar.wsSpacing)) - 1; // TODO: workspaceActiveIconSize might be before + activeRect.x = mouseX - activeRect.width / 2; + root.activeOccupied = root.getWorkspaceStats(abovedItemIndex).isOccupied || false; + activeRect.implicitWidth = root.activeIndex === abovedItemIndex ? Bar.wsActiveIconSize : Bar.wsIconSize; + } + onExited: { + if (!root.toChild && root.activeIndex >= 0) { + // just in case + activeRect.x = layout.x + root.activeIndex * Bar.wsIconSize + root.activeIndex * Bar.wsSpacing; + activeRect.implicitWidth = Bar.wsActiveIconSize; + root.activeOccupied = root.getWorkspaceStats(root.activeIndex).isOccupied || false; + } + } + onWheel: event => { + // no idea wats wrong w/ prev so we just unify it to use +/- 1 + if (event.angleDelta.y < 0) { + if (root.activeIndex + 1 < Bar.wss) + Hyprland.dispatch(`hl.dsp.focus({ workspace = '+1' })`); + else + Hyprland.dispatch(`hl.dsp.focus({ workspace = '1' })`); + } else if (event.angleDelta.y > 0) { + if (root.activeIndex + 1 > 1) + Hyprland.dispatch(`hl.dsp.focus({ workspace = '1' })`); + else if (Bar.wss > 1) + Hyprland.dispatch(`hl.dsp.focus({ workspace = '${Bar.wss}' })`); + } + } + } } diff --git a/bar/components/SimpleResource.qml b/bar/components/SimpleResource.qml index 5e873f9..cb2fef6 100644 --- a/bar/components/SimpleResource.qml +++ b/bar/components/SimpleResource.qml @@ -6,95 +6,95 @@ import qs.components import QtQuick.Controls Item { - id: root + id: root - // TODO: use https://quickshell.org/docs/master/types/Quickshell/PopupWindow/ for tooltip + // TODO: use https://quickshell.org/docs/master/types/Quickshell/PopupWindow/ for tooltip - required property real value - required property string suffix // unit - required property string icon - property string altValue: value - property string altSuffix: suffix - property string altIcon: icon - property string text: root.value + root.suffix - property string altText: root.altValue + root.altSuffix - property real thresholdL1: 40 - property real thresholdL2: thresholdL1 * 1.5 - property real thresholdL3: thresholdL2 * 1.5 - property color thresholdColorL1: Colors.cyan - property color thresholdColorL2: Colors.yellow - property color thresholdColorL3: Colors.red + required property real value + required property string suffix // unit + required property string icon + property string altValue: value + property string altSuffix: suffix + property string altIcon: icon + property string text: root.value + root.suffix + property string altText: root.altValue + root.altSuffix + property real thresholdL1: 40 + property real thresholdL2: thresholdL1 * 1.5 + property real thresholdL3: thresholdL2 * 1.5 + property color thresholdColorL1: Colors.cyan + property color thresholdColorL2: Colors.yellow + property color thresholdColorL3: Colors.red - property bool isAlt: false + property bool isAlt: false - property color color: value < thresholdL1 ? Colors.accentAlt : value >= thresholdL3 ? thresholdColorL3 : value >= thresholdL2 ? thresholdColorL2 : thresholdColorL1 + property color color: value < thresholdL1 ? Colors.accentAlt : value >= thresholdL3 ? thresholdColorL3 : value >= thresholdL2 ? thresholdColorL2 : thresholdColorL1 - implicitWidth: layout.implicitWidth - implicitHeight: layout.implicitHeight + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight - RowLayout { - id: layout + RowLayout { + id: layout - spacing: 0 + spacing: 0 - Item { - Layout.fillWidth: true - } + Item { + Layout.fillWidth: true + } - IRect { - Layout.fillWidth: true - Layout.fillHeight: true - implicitWidth: m_icon.width + General.rectMargin * 2 - implicitHeight: Bar.height - General.rectMargin - color: "transparent" - Slider { - id: pBar - anchors.fill: parent - handle: Item - from: 0 - to: 100 - value: !root.isAlt ? root.value : root.altValue - background: IRect { - anchors.fill: parent - color: "transparent" - // radius: Style.rounding.smaller - } - contentItem: Item { - IRect { - anchors.bottom: parent.bottom - width: parent.width - height: parent.height * pBar.visualPosition - color: Qt.rgba(root.color.r, root.color.g, root.color.b, General.accentTransparency * 1.5) - radius: Style.rounding.smaller + IRect { + Layout.fillWidth: true + Layout.fillHeight: true + implicitWidth: m_icon.width + General.rectMargin * 2 + implicitHeight: Bar.height - General.rectMargin + color: "transparent" + Slider { + id: pBar + anchors.fill: parent + handle: Item + from: 0 + to: 100 + value: !root.isAlt ? root.value : root.altValue + background: IRect { + anchors.fill: parent + color: "transparent" + // radius: Style.rounding.smaller + } + contentItem: Item { + IRect { + anchors.bottom: parent.bottom + width: parent.width + height: parent.height * pBar.visualPosition + color: Qt.rgba(root.color.r, root.color.g, root.color.b, General.accentTransparency * 1.5) + radius: Style.rounding.smaller - Behavior on height { - NumberAnimation { - duration: General.animationDuration / 2 - } - } - } - } - } - Icon { - id: m_icon - anchors { - centerIn: parent - } - iconSize: Style.font.size.small - text: !root.isAlt ? root.icon : root.altIcon - color: root.value < root.thresholdL1 ? Colors.foreground2 : root.value >= root.thresholdL3 ? root.thresholdColorL3 : root.value >= root.thresholdL2 ? root.thresholdColorL2 : root.thresholdColorL1 - } - } + Behavior on height { + NumberAnimation { + duration: General.animationDuration / 2 + } + } + } + } + } + Icon { + id: m_icon + anchors { + centerIn: parent + } + iconSize: Style.font.size.small + text: !root.isAlt ? root.icon : root.altIcon + color: root.value < root.thresholdL1 ? Colors.foreground2 : root.value >= root.thresholdL3 ? root.thresholdColorL3 : root.value >= root.thresholdL2 ? root.thresholdColorL2 : root.thresholdColorL1 + } + } - Item { - Layout.fillWidth: true - } - } - MouseArea { - anchors.fill: parent - cursorShape: altValue != value ? Qt.PointingHandCursor : Qt.ArrowCursor - onPressed: { - root.isAlt = !root.isAlt; - } - } + Item { + Layout.fillWidth: true + } + } + MouseArea { + anchors.fill: parent + cursorShape: altValue != value ? Qt.PointingHandCursor : Qt.ArrowCursor + onPressed: { + root.isAlt = !root.isAlt; + } + } } |
