Author SHA1 Message Date
AramJonghu abf7382771 ci: libcava dev headers
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 12s
JS/TS / lint (pull_request) Successful in 16s
Python / lint (pull_request) Successful in 33s
Python / fmt (pull_request) Successful in 36s
Python / test (pull_request) Successful in 1m3s
Python / typecheck (pull_request) Successful in 1m21s
Rust / fmt (pull_request) Successful in 33s
C++ / build (pull_request) Successful in 2m26s
Rust / build (pull_request) Successful in 1m43s
Python / buildcheck (pull_request) Successful in 2m12s
Rust / clippy (pull_request) Successful in 1m41s
C++ / clang-tidy (pull_request) Successful in 4m10s
2026-08-14 20:00:27 +02:00
AramJonghu a1a8a6e695 ci: add relevant dependencies; resolves MissingImport
C++ / fmt (pull_request) Successful in 4s
JS/TS / lint (pull_request) Successful in 15s
JS/TS / fmt (pull_request) Successful in 21s
Python / fmt (pull_request) Successful in 31s
Python / lint (pull_request) Successful in 34s
Python / test (pull_request) Successful in 1m0s
Python / typecheck (pull_request) Successful in 1m20s
Rust / fmt (pull_request) Successful in 34s
C++ / build (pull_request) Successful in 2m29s
Rust / build (pull_request) Successful in 1m45s
Rust / clippy (pull_request) Successful in 1m2s
Python / buildcheck (pull_request) Successful in 2m18s
C++ / clang-tidy (pull_request) Successful in 3m52s
2026-08-14 19:40:28 +02:00
53 changed files with 669 additions and 848 deletions
+1 -1
View File
@@ -97,7 +97,7 @@ jobs:
py3-pip
python3 -m venv .venv
. .venv/bin/activate
pip install --no-cache-dir basedpyright
pip install --no-cache-dir basedpyright typer pillow materialyoucolor jinja2
- name: Type check
run: |
+2 -2
View File
@@ -41,7 +41,7 @@ Item {
}
}
clip: false
clip: true
implicitHeight: elideText.implicitHeight
Behavior on leftFadeStrength {
@@ -81,7 +81,7 @@ Item {
id: marqueeViewport
anchors.fill: parent
clip: false
clip: true
layer.enabled: true
visible: root.overflowing
+2 -33
View File
@@ -11,46 +11,15 @@ Variants {
required property ShellScreen modelData
function rebuild(): void {
loader.active = false;
loader.active = true;
}
LazyLoader {
id: loader
active: true
Drawer {
screen: scope.modelData
}
}
Connections {
function onConfigPositionChanged(): void {
Qt.callLater(scope.rebuild);
}
target: (loader.item as Drawer)?.geometry ?? null
}
}
component Drawer: Scope {
id: drawer
readonly property alias geometry: content.geometry
required property ShellScreen screen
Exclusions {
bar: content.bar
geometry: content.geometry
screen: drawer.screen
screen: scope.modelData
}
Windows {
id: content
screen: drawer.screen
screen: scope.modelData
}
}
}
-55
View File
@@ -1,55 +0,0 @@
import QtQuick
import qs.Modules.Bar as Bar
QtObject {
id: root
required property Bar.BarLoader bar
readonly property real barClamped: bar.clampedExtent
readonly property real barExtent: bar.extent
readonly property bool barOnBottom: position === "bottom"
readonly property bool barOnLeft: position === "left"
readonly property bool barOnTop: position === "top"
required property string configPosition
readonly property bool horizontal: position !== "left"
readonly property string position: configPosition === "top" || configPosition === "bottom" ? configPosition : "left"
required property var win
function axisPos(x: real, y: real): real {
return horizontal ? x : y;
}
function barContains(x: real, y: real, clamped = false): bool {
const extent = clamped ? barClamped : barExtent;
if (barOnTop)
return y < extent;
if (barOnBottom)
return y > win.height - extent;
return x < extent;
}
function insetBottom(border: real, clamped = false): real {
return barOnBottom ? (clamped ? barClamped : barExtent) : border;
}
function insetLeft(border: real, clamped = false): real {
return barOnLeft ? (clamped ? barClamped : barExtent) : border;
}
function insetTop(border: real, clamped = false): real {
return barOnTop ? (clamped ? barClamped : barExtent) : border;
}
function inwardDrag(dragX: real, dragY: real): real {
if (barOnTop)
return dragY;
if (barOnBottom)
return -dragY;
return dragX;
}
onConfigPositionChanged: {
if (!["left", "top", "bottom"].includes(configPosition))
console.warn(`Invalid bar position '${configPosition}', falling back to left`);
}
}
+2 -7
View File
@@ -9,21 +9,19 @@ Scope {
id: root
required property Item bar
required property EdgeGeometry geometry
required property ShellScreen screen
ExclusionZone {
id: top
anchors.top: true
hasBar: root.geometry.barOnTop
exclusiveZone: root.bar.exclusiveZone
}
ExclusionZone {
id: left
anchors.left: true
hasBar: root.geometry.barOnLeft
}
ExclusionZone {
@@ -36,7 +34,6 @@ Scope {
id: bottom
anchors.bottom: true
hasBar: root.geometry.barOnBottom
}
Timer {
@@ -47,9 +44,7 @@ Scope {
}
component ExclusionZone: CustomWindow {
property bool hasBar
exclusiveZone: hasBar ? root.bar.exclusiveZone : Config.bar.border
exclusiveZone: Config.bar.border
implicitHeight: 1
implicitWidth: 1
name: "Bar-Exclusion"
+20 -24
View File
@@ -3,7 +3,7 @@ import QtQuick
import qs.Components
import ZShell.Config
import qs.Helpers
import qs.Modules.Bar.Popouts
import qs.Modules as BarPopouts
Item {
id: root
@@ -12,47 +12,43 @@ Item {
required property real borderThickness
property bool dashboardShortcutActive
required property Drawing drawing
required property EdgeGeometry geometry
property bool osdShortcutActive
required property Panels panels
required property Wrapper popouts
required property BarPopouts.Wrapper popouts
required property ShellScreen screen
property bool singleGestureTriggered: false
property bool utilitiesShortcutActive
required property PersistentProperties visibilities
function inBottomPanel(panel: Item, x: real, y: real): bool {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
return y > root.height - (panelHeight + geometry.insetBottom(borderThickness)) && withinPanelWidth(panel, x, y);
return y > root.height - panel.height - Config.bar.border && withinPanelWidth(panel, x, y);
}
function inLeftPanel(panel: Item, x: real, y: real): bool {
return x < panel.x + panel.width + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
}
function inPopoutArea(x: real, y: real): bool {
const panel = panels.popoutsWrapper;
if (!geometry.horizontal)
return inLeftPanel(panel, x, y);
return withinPanelWidth(panel, x, y) && withinPanelHeight(panel, x, y);
return x < panel.x + panel.width + Config.bar.border && withinPanelHeight(panel, x, y);
}
function inRightPanel(panel: Item, x: real, y: real): bool {
return x > panel.x + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
return x > panel.x - Config.bar.border && withinPanelHeight(panel, x, y);
}
function inTopPanel(panel: Item, x: real, y: real): bool {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
return y < geometry.insetTop(borderThickness) + panelHeight && withinPanelWidth(panel, x, y);
return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y);
}
function onWheel(event: WheelEvent): void {
if (event.x < bar.implicitWidth) {
bar.handleWheel(event.y, event.angleDelta);
}
}
function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = panel.y + geometry.insetTop(borderThickness);
const panelY = panel.y + bar.implicitHeight;
return y >= panelY && y <= panelY + panel.height;
}
function withinPanelWidth(panel: Item, x: real, y: real): bool {
const panelX = panel.x + geometry.insetLeft(borderThickness);
const panelX = panel.x + root.borderThickness;
return x >= panelX && x <= panelX + panel.width;
}
@@ -85,7 +81,7 @@ Item {
if (root.singleGestureTriggered)
return;
if (root.geometry.insetTop(root.borderThickness) > centroid.pressPosition.y) {
if (centroid.pressPosition.y < root.bar.implicitHeight) {
if (dragY > 20) {
root.visibilities.settings = true;
root.singleGestureTriggered = true;
@@ -95,10 +91,10 @@ Item {
}
}
if (centroid.pressPosition.y > root.screen.height - root.geometry.insetBottom(root.borderThickness) && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50)
if (centroid.pressPosition.y > root.screen.height - Config.bar.border && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50)
root.visibilities.clipboard = true;
if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.geometry.insetTop(root.borderThickness) && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher)
if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.bar.implicitHeight && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher)
if (dragY < -10) {
root.visibilities.dock = true;
root.singleGestureTriggered = true;
@@ -197,7 +193,7 @@ Item {
return;
}
if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true))
if (!root.visibilities.bar && Config.bar.autoHide && y < root.bar.implicitHeight)
root.bar.isHovered = true;
if (root.panels.sidebar.offsetScale === 1) {
@@ -223,8 +219,8 @@ Item {
if (Config.dock.enable && Config.dock.hoverToReveal && !root.visibilities.dock && !root.visibilities.launcher && root.inBottomPanel(root.panels.dock, x, y))
root.visibilities.dock = true;
if (root.geometry.barContains(x, y))
root.bar.checkPopout(root.geometry.axisPos(x, y));
if (y < root.bar.implicitHeight)
root.bar.checkPopout(x);
}
}
+13 -17
View File
@@ -1,7 +1,7 @@
import Quickshell
import QtQuick
import qs.Components
import qs.Modules.Bar.Popouts as Popouts
import qs.Modules as Modules
import qs.Modules.Notifications as Notifications
import qs.Modules.Notifications.Sidebar as Sidebar
import qs.Modules.Notifications.Sidebar.Utils as Utils
@@ -27,7 +27,6 @@ Item {
readonly property alias dock: dock
readonly property alias drawing: drawing
required property var drawingItem
required property EdgeGeometry geometry
readonly property alias launcher: launcher
readonly property alias notifications: notifications
readonly property alias osd: osd
@@ -44,11 +43,9 @@ Item {
readonly property alias utilities: utilities
required property PersistentProperties visibilities
anchors.bottomMargin: geometry.insetBottom(borderThickness)
anchors.fill: parent
anchors.leftMargin: geometry.insetLeft(borderThickness)
anchors.margins: borderThickness
anchors.topMargin: geometry.insetTop(borderThickness)
anchors.topMargin: bar.implicitHeight
Item {
id: resourcesWrapper
@@ -56,15 +53,14 @@ Item {
anchors.left: parent.left
anchors.top: parent.top
clip: true
implicitHeight: root.geometry.horizontal ? resources.implicitHeight * (1 - resources.offsetScale) : resources.implicitHeight
implicitWidth: root.geometry.horizontal ? resources.implicitWidth : resources.implicitWidth * (1 - resources.offsetScale)
implicitHeight: resources.implicitHeight * (1 - resources.offsetScale)
implicitWidth: resources.implicitWidth
Resources.Wrapper {
id: resources
anchors.left: parent.left
anchors.top: parent.top
horizontal: root.geometry.horizontal
visibilities: root.visibilities
}
}
@@ -100,11 +96,11 @@ Item {
visibilities: root.visibilities
}
Popouts.ClipWrapper {
Modules.ClipWrapper {
id: popouts
anchors.top: parent.top
borderThickness: root.borderThickness
position: root.geometry.position
screen: root.screen
}
@@ -151,13 +147,11 @@ Item {
property real offsetScale: dashboard.shouldBeActive ? 0 : 1
anchors.bottom: root.geometry.barOnLeft || root.geometry.barOnBottom ? parent.bottom : undefined
anchors.left: root.geometry.barOnLeft ? parent.left : undefined
anchors.right: root.geometry.barOnLeft ? undefined : parent.right
anchors.top: root.geometry.barOnBottom || root.geometry.barOnLeft ? undefined : parent.top
anchors.right: parent.right
anchors.top: parent.top
clip: true
implicitHeight: root.geometry.horizontal ? dashboard.implicitHeight * (1 - offsetScale) : dashboard.implicitHeight
implicitWidth: root.geometry.horizontal ? dashboard.implicitWidth : dashboard.implicitWidth * (1 - offsetScale)
implicitHeight: dashboard.implicitHeight * (1 - offsetScale)
implicitWidth: dashboard.implicitWidth
Behavior on offsetScale {
Anim {
@@ -169,7 +163,9 @@ Item {
Dashboard.Wrapper {
id: dashboard
horizontal: root.geometry.horizontal
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: (-implicitHeight - 5) * offsetScale
offsetScale: dashboardWrapper.offsetScale
visibilities: root.visibilities
}
+8 -13
View File
@@ -7,18 +7,17 @@ import qs.Modules.Bar as Bar
Region {
id: root
// required property Bar.BarLoader bar
required property Bar.BarLoader bar
readonly property real borderThickness: win.borderThickness
required property EdgeGeometry geometry
readonly property alias menuPopoutRegion: menuPopoutRegion
required property Panels panels
required property var win
height: win.height - geometry.insetTop(borderThickness, true) - geometry.insetBottom(borderThickness, true) - win.dragMaskPadding * 2
height: win.height - bar.implicitHeight - win.borderThickness - win.dragMaskPadding * 2
intersection: Intersection.Xor
width: win.width - geometry.insetLeft(borderThickness, true) * 2 - win.dragMaskPadding * 2
x: geometry.insetLeft(borderThickness, true) + win.dragMaskPadding
y: geometry.insetTop(borderThickness, true) + win.dragMaskPadding
width: win.width - win.borderThickness * 2 - win.dragMaskPadding * 2
x: win.borderThickness + win.dragMaskPadding
y: bar.implicitHeight + win.dragMaskPadding
R {
panel: root.panels.dashboardWrapper
@@ -42,21 +41,17 @@ Region {
}
R {
height: panel.height + root.geometry.insetTop(root.borderThickness)
panel: root.panels.notifications
y: 0
}
R {
height: panel.height * (1 - root.panels.utilities.offsetScale) + root.geometry.insetBottom(root.borderThickness)
height: panel.height * (1 - root.panels.utilities.offsetScale) + root.borderThickness
panel: root.panels.utilities
y: root.win.height - height
}
R {
height: root.geometry.horizontal ? panel.height * (1 - root.panels.popoutsWrapper.offsetScale) : panel.height
panel: root.panels.popoutsWrapper
width: root.geometry.horizontal ? panel.width : panel.width * (1 - root.panels.popoutsWrapper.offsetScale)
}
R {
@@ -87,7 +82,7 @@ Region {
height: panel.height
intersection: Intersection.Subtract
width: panel.width
x: panel.x + root.geometry.insetLeft(root.borderThickness)
y: panel.y + root.geometry.insetTop(root.borderThickness)
x: panel.x + root.borderThickness
y: panel.y + root.bar.implicitHeight
}
}
+25 -39
View File
@@ -33,7 +33,6 @@ CustomWindow {
return 100;
}
property real fsTransitionProg: hasFullscreen ? 1 : 0
readonly property alias geometry: geometry
readonly property bool hasFullscreen: {
if (hasSpecialWorkspace) {
const specialName = monitor?.lastIpcObject.specialWorkspace?.name;
@@ -96,21 +95,13 @@ CustomWindow {
panels.popouts.hasCurrent = false;
}
EdgeGeometry {
id: geometry
bar: bar
configPosition: Config.bar.position
win: root
}
Region {
id: emptyRegion
height: panels.notifications.height
width: panels.notifications.width
x: panels.notifications.x + geometry.insetLeft(root.borderThickness)
y: panels.notifications.y + geometry.insetTop(root.borderThickness)
x: panels.notifications.x + root.borderThickness
y: panels.notifications.y + bar.implicitHeight
Region {
height: panels.osd.height
@@ -123,7 +114,7 @@ CustomWindow {
Regions {
id: regions
geometry: geometry
bar: bar
panels: panels
win: root
}
@@ -202,10 +193,10 @@ CustomWindow {
BlobInvertedRect {
anchors.fill: parent
anchors.margins: -50
borderBottom: geometry.insetBottom(root.borderThickness) - anchors.margins - root.sdfBorderOffset
borderLeft: geometry.insetLeft(root.borderThickness) - anchors.margins - root.sdfBorderOffset
borderBottom: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderLeft: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderTop: geometry.insetTop(root.borderThickness) - anchors.margins - root.sdfBorderOffset
borderTop: bar.implicitHeight - anchors.margins - root.sdfBorderOffset
group: blobGroup
radius: root.borderRounding
}
@@ -213,15 +204,15 @@ CustomWindow {
PanelBg {
id: dashBg
property real extraExtent: 0.2
property real extraHeight: 0.2
deformAmount: 0.06
implicitHeight: panels.dashboard.height * (geometry.horizontal ? 1 + extraExtent : 1)
implicitWidth: panels.dashboard.width * (geometry.horizontal ? 1 : 1 + extraExtent)
implicitHeight: panels.dashboard.height * (1 + extraHeight)
implicitWidth: panels.dashboard.width
panel: panels.dashboardWrapper
radius: Tokens.rounding.normal
x: panels.dashboardWrapper.x + panels.dashboard.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.dashboard.width * extraExtent)
y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - (geometry.horizontal ? panels.dashboard.height * extraExtent : 0)
x: panels.dashboardWrapper.x + panels.dashboard.x + root.borderThickness
y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight - panels.dashboard.height * extraHeight
}
PanelBg {
@@ -233,7 +224,7 @@ CustomWindow {
implicitHeight: panels.launcher.height * (1 + extraHeight)
panel: panels.launcher
radius: Tokens.rounding.smallest + 5
y: panels.launcher.y + geometry.insetTop(root.borderThickness)
y: panels.launcher.y + bar.implicitHeight
}
PanelBg {
@@ -254,7 +245,8 @@ CustomWindow {
implicitWidth: panels.osd.width
panel: panels.osdWrapper
radius: 20
x: panels.osdWrapper.x + panels.osd.x + geometry.insetLeft(root.borderThickness)
x: panels.osdWrapper.x + panels.osd.x + root.borderThickness
y: panels.osdWrapper.y + panels.osd.y + bar.implicitHeight
}
PanelBg {
@@ -276,17 +268,17 @@ CustomWindow {
PanelBg {
id: popoutBg
property real extraExtent: 0.2
property real extraHeight: 0.2
deformAmount: panels.popouts.currentName.startsWith("traymenu") ? 0.15 : 0.08
implicitHeight: panels.popouts.height * (geometry.horizontal ? 1 + extraExtent : 1)
implicitWidth: panels.popouts.width * (geometry.horizontal ? 1 : 1 + extraExtent)
implicitHeight: panels.popouts.height * (1 + extraHeight)
implicitWidth: panels.popouts.width
panel: panels.popoutsWrapper
radius: panels.popouts.current?.panelRadius ?? Tokens.rounding.normal
x: panels.popoutsWrapper.x + panels.popouts.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.popouts.width * extraExtent)
y: panels.popoutsWrapper.y + panels.popouts.y + geometry.insetTop(root.borderThickness) - (geometry.barOnTop ? panels.popouts.height * extraExtent : 0)
x: panels.popoutsWrapper.x + panels.popouts.x + root.borderThickness
y: panels.popoutsWrapper.y + panels.popouts.y + bar.implicitHeight - panels.popouts.height * extraHeight
Behavior on extraExtent {
Behavior on extraHeight {
Anim {
}
}
@@ -300,8 +292,8 @@ CustomWindow {
implicitWidth: panels.resources.width
panel: panels.resourcesWrapper
radius: Tokens.rounding.large
x: panels.resourcesWrapper.x + panels.resources.x + geometry.insetLeft(root.borderThickness)
y: panels.resourcesWrapper.y + panels.resources.y + geometry.insetTop(root.borderThickness)
x: panels.resourcesWrapper.x + panels.resources.x + root.borderThickness
y: panels.resourcesWrapper.y + panels.resources.y + bar.implicitHeight
}
PanelBg {
@@ -379,7 +371,6 @@ CustomWindow {
borderThickness: root.borderLayoutThickness
drawing: drawing
enabled: true
geometry: geometry
panels: panels
popouts: panels.popouts
screen: root.screen
@@ -391,7 +382,6 @@ CustomWindow {
bar: bar
borderThickness: root.borderThickness
drawingItem: drawing
geometry: geometry
screen: root.screen
visibilities: visibilities
@@ -433,18 +423,14 @@ CustomWindow {
BarLoader {
id: bar
anchors.bottom: geometry.barOnBottom ? parent.bottom : undefined
anchors.left: parent.left
anchors.top: geometry.barOnBottom ? undefined : parent.top
anchors.right: parent.right
enabled: !visibilities.isDrawing
fullscreen: root.hasFullscreen
height: geometry.horizontal ? implicitHeight : parent.height
popouts: panels.popouts
popoutsWrapper: panels.popoutsWrapper
position: geometry.position
screen: root.screen
visibilities: visibilities
width: geometry.horizontal ? parent.width : implicitWidth
}
}
@@ -457,7 +443,7 @@ CustomWindow {
implicitHeight: panel.height
implicitWidth: panel.width
radius: Tokens.rounding.smallest
x: panel.x + geometry.insetLeft(root.borderThickness)
y: panel.y + geometry.insetTop(root.borderThickness)
x: panel.x + root.borderThickness
y: panel.y + bar.implicitHeight
}
}
+2 -51
View File
@@ -1,8 +1,9 @@
pragma Singleton
import QtQuick
import ZShell.Config
import Quickshell
import Quickshell.Services.Notifications
import QtQuick
Singleton {
id: root
@@ -94,15 +95,6 @@ Singleton {
return Quickshell.iconPath(icon);
}
function getBatteryIcon(percentage: real, charging = false): string {
if (percentage === 1)
return charging ? "battery_charging_full" : "battery_full";
let level = Math.floor(percentage * 7);
if (charging && (level === 4 || level === 1))
level--;
return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`;
}
function getBluetoothIcon(icon: string): string {
if (icon.includes("headset") || icon.includes("headphones"))
return "headphones";
@@ -176,32 +168,6 @@ Singleton {
return "chat";
}
function getSpecialWsIcon(name: string): string {
name = name.toLowerCase().slice("special:".length);
if (name === "special")
return "star";
if (name === "communication")
return "forum";
if (name === "music")
return "music_cast";
if (name === "todo")
return "checklist";
if (name === "sysmon")
return "monitor_heart";
return name[0].toUpperCase();
}
function getTrayIcon(id: string, icon: string): string {
if (icon.includes("?path=")) {
const [name, path] = icon.split("?path=");
const file = name.slice(name.lastIndexOf("/") + 1);
const themed = Quickshell.iconPath(file, true);
icon = themed ? themed : Qt.resolvedUrl(`${path}/${file}`);
}
return icon;
}
function getVolumeIcon(volume: real, isMuted: bool): string {
if (isMuted)
return "no_sound";
@@ -217,19 +183,4 @@ Singleton {
return weatherIcons[code];
return "air";
}
function matchIconConfig(name: string, iconConfig: var): bool {
if (!iconConfig.icon)
return false;
if (iconConfig.regex) {
const re = new RegExp(iconConfig.regex, iconConfig.flags ?? "");
if (re.test(name))
return true;
} else if (iconConfig.name === name) {
return true;
}
return false;
}
}
+22 -41
View File
@@ -3,28 +3,24 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Modules
import ZShell.Config
import qs.Modules.Bar.Components
import qs.Modules.Bar.Popouts
import qs.Modules.SysTray
import qs.Modules.Network
import qs.Modules.Updates
GridLayout {
RowLayout {
id: root
required property bool fullscreen
required property bool horizontal
required property Wrapper popouts
required property ClipWrapper popoutsWrapper
required property ShellScreen screen
readonly property int vPadding: 6
required property PersistentProperties visibilities
function axisCenterOf(item: Item): real {
const c = item.mapToItem(root, item.implicitWidth / 2, item.implicitHeight / 2);
return horizontal ? c.x : c.y;
}
function checkPopout(pos: real): void {
const ch = (horizontal ? childAt(pos, height / 2) : childAt(width / 2, pos)) as EntryWrapper;
function checkPopout(x: real): void {
const ch = childAt(x, height / 2) as EntryWrapper;
const id = ch?.entryId;
if (!ch || id === undefined) {
@@ -38,21 +34,26 @@ GridLayout {
if (id === "statusIcons" && Config.bar.popouts.statusIcons) {
const items = (ch.item as StatusIcons).items;
const icon = horizontal ? items.childAt(mapToItem(items, pos, 0).x, items.height / 2) : items.childAt(items.width / 2, mapToItem(items, 0, pos).y);
const localX = mapToItem(items, x, 0).x;
const icon = items.childAt(localX, items.height / 2);
if (icon) {
popouts.currentName = icon.name;
popouts.currentCenter = Qt.binding(() => axisCenterOf(icon));
popouts.currentCenter = Qt.binding(() => icon.mapToItem(root, icon.implicitWidth / 2, 0).x);
popouts.hasCurrent = true;
}
} else if (id === "tray" && Config.bar.popouts.tray && Config.bar.tray.showOnHover) {
const tray = ch.item as TrayIcons;
const layout = tray.layout;
const trayItem = horizontal ? layout.childAt(mapToItem(layout, pos, 0).x, layout.height / 2) : layout.childAt(tray.width / 2, mapToItem(layout, 0, pos).y);
const localX = mapToItem(layout, x, 0).x;
const trayItem = layout.childAt(localX, layout.height / 2);
if (trayItem) {
const idx = trayItem.index;
popouts.currentName = `traymenu${idx}`;
popouts.currentCenter = Qt.binding(() => axisCenterOf(trayItem));
popouts.currentCenter = Qt.binding(() => {
const it = tray.items.itemAt(idx);
return it ? it.mapToItem(root, it.implicitWidth / 2, 0).x : popouts.currentCenter;
});
popouts.hasCurrent = true;
}
@@ -62,19 +63,12 @@ GridLayout {
if (id === "updates") {
popouts.currentName = "updates";
popouts.currentCenter = Qt.binding(() => axisCenterOf(ch.item as Item));
popouts.currentCenter = Qt.binding(() => ch.item.mapToItem(root, (ch.item as Item).implicitWidth / 2, 0).x);
popouts.hasCurrent = true;
}
}
function entryAt(pos: real): string {
const ch = (horizontal ? childAt(pos, height / 2) : childAt(width / 2, pos)) as EntryWrapper;
return ch?.entryId ?? "";
}
columnSpacing: Tokens.spacing.small
columns: horizontal ? -1 : 1
rowSpacing: Tokens.spacing.small
spacing: Tokens.spacing.small
Repeater {
id: repeater
@@ -91,7 +85,6 @@ GridLayout {
delegate: EntryWrapper {
HyprsunsetWidget {
horizontal: root.horizontal
visible: !root.fullscreen
}
}
@@ -101,8 +94,7 @@ GridLayout {
roleValue: "spacer"
delegate: EntryWrapper {
Layout.fillHeight: !root.horizontal
Layout.fillWidth: root.horizontal
Layout.fillWidth: true
}
}
@@ -111,7 +103,6 @@ GridLayout {
delegate: EntryWrapper {
Workspaces {
horizontal: root.horizontal
screen: root.screen
visible: !root.fullscreen
}
@@ -123,7 +114,6 @@ GridLayout {
delegate: EntryWrapper {
TrayIcons {
horizontal: root.horizontal
loader: root
popouts: root.popouts
visible: !root.fullscreen
@@ -136,7 +126,6 @@ GridLayout {
delegate: EntryWrapper {
StatusIcons {
horizontal: root.horizontal
}
}
}
@@ -146,7 +135,6 @@ GridLayout {
delegate: EntryWrapper {
Resources {
horizontal: root.horizontal
visibilities: root.visibilities
visible: !root.fullscreen
}
@@ -158,7 +146,6 @@ GridLayout {
delegate: EntryWrapper {
UpdatesWidget {
horizontal: root.horizontal
visible: !root.fullscreen
}
}
@@ -169,7 +156,6 @@ GridLayout {
delegate: EntryWrapper {
NotifBell {
horizontal: root.horizontal
popouts: root.popouts
visibilities: root.visibilities
visible: !root.fullscreen
@@ -182,7 +168,6 @@ GridLayout {
delegate: EntryWrapper {
Clock {
horizontal: root.horizontal
loader: root
popouts: root.popouts
visibilities: root.visibilities
@@ -197,7 +182,6 @@ GridLayout {
delegate: EntryWrapper {
WindowTitle {
bar: root
horizontal: root.horizontal
visible: !root.fullscreen
}
}
@@ -217,7 +201,6 @@ GridLayout {
delegate: EntryWrapper {
MediaWidget {
horizontal: root.horizontal
visible: !root.fullscreen
}
}
@@ -231,11 +214,9 @@ GridLayout {
default property Item item
required property var modelData
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
Layout.bottomMargin: !root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.rowSpacing + Tokens.spacing.extraSmall : 0
Layout.rightMargin: root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.columnSpacing + Tokens.spacing.extraSmall : 0
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: index === 0 ? root.vPadding : (entryId === "statusIcons") ? -root.spacing + Tokens.spacing.extraSmall : 0
Layout.rightMargin: index === repeater.count - 1 ? root.vPadding : 0
children: item
implicitHeight: item?.implicitHeight ?? 0
implicitWidth: item?.implicitWidth ?? 0
+20 -26
View File
@@ -1,48 +1,45 @@
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Hyprland
import QtQuick
import ZShell.Config
import qs.Modules.Bar.Popouts
import QtQuick.Layouts
import qs.Components
import qs.Modules
import ZShell.Config
import qs.Helpers
import qs.Modules.SysTray
import qs.Modules.SysTray.Widgets
import qs.Modules.Network
Item {
id: root
readonly property int clampedExtent: Math.max(Config.bar.border, extent)
readonly property int contentThickness: Math.max(Config.bar.height, Tokens.bar.innerSize) + padding * 2
readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness
property real extent: fullscreen ? 0 : Config.bar.border
readonly property int contentHeight: Config.bar.height + padding * 2
readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentHeight
required property bool fullscreen
readonly property bool horizontal: position !== "left"
property bool isHovered
readonly property int padding: Math.max(Tokens.padding.smaller, Config.bar.border)
required property Wrapper popouts
required property ClipWrapper popoutsWrapper
required property string position
required property ShellScreen screen
readonly property bool shouldBeVisible: !fullscreen && (!Config.bar.autoHide || visibilities.bar || isHovered)
readonly property int vPadding: 6
required property PersistentProperties visibilities
function checkPopout(pos: real): void {
(content.item as Bar)?.checkPopout(pos);
function checkPopout(x: real): void {
content.item?.checkPopout(x);
}
function entryAt(pos: real): string {
return (content.item as Bar)?.entryAt(pos) ?? "";
}
implicitHeight: extent
implicitWidth: extent
visible: extent > Config.bar.border
implicitHeight: fullscreen ? 0 : Config.bar.border
visible: height > Config.bar.border
states: State {
name: "visible"
when: root.shouldBeVisible
PropertyChanges {
root.extent: root.contentThickness
root.implicitHeight: root.contentHeight
}
}
transitions: [
@@ -51,7 +48,7 @@ Item {
to: "visible"
Anim {
property: "extent"
property: "implicitHeight"
target: root
}
},
@@ -60,7 +57,7 @@ Item {
to: ""
Anim {
property: "extent"
property: "implicitHeight"
target: root
}
}
@@ -70,16 +67,13 @@ Item {
id: content
active: root.shouldBeVisible || root.visible
anchors.bottom: root.position !== "bottom" ? parent.bottom : undefined
anchors.left: root.horizontal ? parent.left : undefined
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.top: root.position !== "top" ? parent.top : undefined
height: root.contentThickness
width: root.contentThickness
sourceComponent: Bar {
fullscreen: root.fullscreen
horizontal: root.horizontal
height: root.contentHeight
popouts: root.popouts
popoutsWrapper: root.popoutsWrapper
screen: root.screen
-61
View File
@@ -1,61 +0,0 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Modules.Bar.Popouts
import qs.Helpers
import qs.Components
import qs.Services
CustomRect {
id: root
required property bool horizontal
required property GridLayout loader
required property Wrapper popouts
readonly property real shortSize: Math.max(Config.bar.height, Tokens.bar.innerSize)
readonly property real size: timeText.contentWidth + (horizontal ? Tokens.padding.normal : Tokens.padding.larger) * 2
required property PersistentProperties visibilities
color: visibilities.dashboard ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? shortSize : size
implicitWidth: horizontal ? size : shortSize
radius: Tokens.rounding.full
CustomText {
id: timeText
anchors.centerIn: parent
// anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter
// anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined
color: root.visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
font: Config.appearance.font.family.mono // qmllint disable incompatible-type
height: root.horizontal ? implicitHeight : implicitWidth
text: Time.dateStr
width: root.horizontal ? implicitWidth : implicitHeight
Behavior on color {
CAnim {
}
}
transform: [
Translate {
x: !root.horizontal ? -timeText.implicitWidth + timeText.implicitHeight : 0
},
Rotation {
angle: root.horizontal ? 0 : 270
origin.x: timeText.implicitHeight / 2
origin.y: timeText.implicitHeight / 2
}
]
}
StateLayer {
acceptedButtons: Qt.LeftButton
color: root.visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
onClicked: {
root.visibilities.dashboard = !root.visibilities.dashboard;
}
}
}
-42
View File
@@ -1,42 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules
import qs.Helpers
import ZShell.Config
import qs.Services
CustomRect {
id: root
property int countUpdates: Updates.availableUpdates
required property bool horizontal
property color textColor: Colors.palette.m3onSurface
color: Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : content.implicitHeight + Tokens.spacing.small
implicitWidth: horizontal ? content.implicitWidth + Tokens.spacing.small * 2 : Math.max(Config.bar.height, Tokens.bar.innerSize)
radius: Tokens.rounding.full
GridLayout {
id: content
anchors.centerIn: parent
columnSpacing: Tokens.spacing.small
columns: root.horizontal ? -1 : 1
rowSpacing: -Tokens.spacing.extraSmall / 2
MaterialIcon {
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
font.pointSize: root.horizontal ? Tokens.font.size.larger : Tokens.font.size.large
text: "package_2"
}
CustomText {
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
color: root.textColor
font.pointSize: Tokens.font.size.normal
text: root.countUpdates
}
}
}
-98
View File
@@ -1,98 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.Components
import ZShell.Config
import qs.Helpers
import qs.Services
Item {
id: root
required property var bar
property color color: Colors.palette.m3primary
property Title current: text1
required property bool horizontal
// readonly property int maxWidth: 300
readonly property int maxSize: {
const otherModules = bar.children.filter(c => c.enabled && c.entryId && c.item !== this && c.entryId !== "spacer");
const otherSize = otherModules.reduce((acc, curr) => acc + (horizontal ? (curr.item?.nonAnimWidth ?? curr.width ?? 0) : (curr.item.nonAnimHeight ?? curr.height ?? 0)), 0);
return horizontal ? bar.width - otherSize - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2 : bar.height - otherSize - bar.vPadding * (bar.children.length - 1) - bar.vPadding * 4;
}
anchors.centerIn: parent
clip: false
implicitHeight: horizontal ? current.implicitHeight : current.implicitWidth + current.anchors.topMargin
implicitWidth: horizontal ? current.implicitWidth + current.anchors.leftMargin : current.implicitHeight + current.anchors.topMargin
Behavior on implicitHeight {
enabled: !root.horizontal
Anim {
type: Anim.DefaultEffects
}
}
Behavior on implicitWidth {
enabled: root.horizontal
Anim {
}
}
Title {
id: text1
}
Title {
id: text2
}
TextMetrics {
id: metrics
elide: Qt.ElideRight
elideWidth: root.maxSize - (root.horizontal ? root.current.anchors.leftMargin : 0)
font.family: "Rubik"
font.pointSize: Tokens.font.size.normal
text: Hypr.activeToplevel?.title ?? qsTr("Desktop")
onElideWidthChanged: root.current.text = elidedText
onTextChanged: {
const next = root.current === text1 ? text2 : text1;
next.text = elidedText;
root.current = next;
}
}
component Title: CustomText {
id: text
anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter
anchors.left: root.horizontal ? parent.left : undefined
anchors.leftMargin: root.horizontal ? Tokens.spacing.small : 0
anchors.top: root.horizontal ? undefined : parent.top
anchors.topMargin: root.horizontal ? 0 : Tokens.spacing.small
anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined
color: root.color
font.family: metrics.font.family
font.pointSize: metrics.font.pointSize
height: root.horizontal ? implicitHeight : implicitWidth
opacity: root.current === this ? 1 : 0
width: root.horizontal ? implicitWidth : implicitHeight
Behavior on opacity {
Anim {
}
}
transform: [
Translate {
x: !root.horizontal ? -text.implicitWidth + text.implicitHeight : 0
},
Rotation {
angle: root.horizontal ? 0 : 270
origin.x: text.implicitHeight / 2
origin.y: text.implicitHeight / 2
}
]
}
}
-87
View File
@@ -1,87 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.Components
import ZShell.Config
Item {
id: root
required property real borderThickness
readonly property alias content: content
readonly property bool horizontal: position !== "left"
// property real offsetScale: y > 0 || content.hasCurrent ? 0 : 1
property real offsetScale: {
if (content.hasCurrent)
return 0;
if (position === "top")
return y > 0 ? 0 : 1;
if (position === "bottom")
return 1;
return x > 0 ? 0 : 1;
}
required property string position
required property ShellScreen screen
anchors.bottom: position === "bottom" ? parent.bottom : undefined
clip: true
implicitHeight: horizontal ? content.implicitHeight * (1 - offsetScale) : content.implicitHeight
implicitWidth: horizontal ? content.implicitWidth : content.implicitWidth * (1 - offsetScale)
visible: width > 0 && height > 0
x: {
if (!horizontal)
return 0;
const off = content.currentCenter - borderThickness - content.nonAnimWidth / 2;
const diff = parent.width - Math.floor(off + content.nonAnimWidth);
if (diff < 0)
return off + diff;
return Math.floor(Math.max(off, 0));
}
y: {
if (horizontal)
return 0;
const off = content.currentCenter - borderThickness - content.nonAnimHeight / 2;
const diff = parent.height - Math.floor(off + content.nonAnimHeight);
if (diff < 0)
return off + diff;
return Math.max(off, 0);
}
Behavior on offsetScale {
Anim {
}
}
Behavior on x {
enabled: !root.horizontal || root.offsetScale < 1
Anim {
duration: content.animLength
easing.bezierCurve: content.animCurve
}
}
Behavior on y {
enabled: root.horizontal || root.offsetScale < 1
Anim {
duration: content.animLength
easing.bezierCurve: content.animCurve
}
}
Wrapper {
id: content
anchors.bottom: root.position === "bottom" ? parent.bottom : undefined
anchors.bottomMargin: (-implicitHeight - 5) * root.offsetScale
anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined
anchors.left: root.horizontal ? undefined : parent.left
anchors.leftMargin: (-implicitWidth - 5) * root.offsetScale
anchors.top: root.position === "top" ? parent.top : undefined
anchors.topMargin: (-implicitHeight - 5) * root.offsetScale
anchors.verticalCenter: root.horizontal ? undefined : parent.verticalCenter
offsetScale: root.offsetScale
screen: root.screen
}
}
+56
View File
@@ -0,0 +1,56 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.Components
import ZShell.Config
Item {
id: root
required property real borderThickness
readonly property alias content: content
property real offsetScale: y > 0 || content.hasCurrent ? 0 : 1
required property ShellScreen screen
clip: true
implicitHeight: content.implicitHeight * (1 - offsetScale)
implicitWidth: content.implicitWidth
visible: width > 0 && height > 0
x: {
const off = content.currentCenter - borderThickness - content.nonAnimWidth / 2;
const diff = parent.width - Math.floor(off + content.nonAnimWidth);
if (diff < 0)
return off + diff;
return Math.floor(Math.max(off, 0));
}
Behavior on offsetScale {
Anim {
}
}
Behavior on x {
enabled: root.offsetScale < 1
Anim {
duration: content.animLength
easing.bezierCurve: content.animCurve
}
}
Behavior on y {
Anim {
duration: content.animLength
easing.bezierCurve: content.animCurve
}
}
Wrapper {
id: content
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: (-implicitHeight - 5) * root.offsetScale
offsetScale: root.offsetScale
screen: root.screen
}
}
+44
View File
@@ -0,0 +1,44 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Modules
import qs.Helpers
import qs.Components
import qs.Services
CustomRect {
id: root
required property RowLayout loader
required property Wrapper popouts
required property PersistentProperties visibilities
color: visibilities.dashboard ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: timeText.contentWidth + Tokens.padding.normal * 2
radius: Tokens.rounding.full
CustomText {
id: timeText
anchors.centerIn: parent
color: root.visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
font: Config.appearance.font.family.mono
text: Time.dateStr
Behavior on color {
CAnim {
}
}
}
StateLayer {
acceptedButtons: Qt.LeftButton
color: root.visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
onClicked: {
root.visibilities.dashboard = !root.visibilities.dashboard;
}
}
}
@@ -5,6 +5,10 @@ import Quickshell.Services.SystemTray
import QtQuick
import ZShell.Config
import qs.Components
import qs.Modules.WSOverview
import qs.Modules.Network
import qs.Modules.SysTray.Popouts
import qs.Modules.Updates
Item {
id: root
+2 -9
View File
@@ -14,16 +14,11 @@ Item {
reloadableId: "dashboardState"
}
required property bool horizontal
readonly property real nonAnimHeight: state === "visible" ? (content.item?.nonAnimHeight ?? 0) : 0
required property real offsetScale
readonly property bool shouldBeActive: root.visibilities.dashboard && Config.dashboard.enabled
required property PersistentProperties visibilities
anchors.left: horizontal ? undefined : parent.left
anchors.leftMargin: horizontal ? 0 : (-implicitWidth - 5) * offsetScale
anchors.top: horizontal ? parent.top : undefined
anchors.topMargin: horizontal ? (-implicitHeight - 5) * offsetScale : 0
implicitHeight: content.implicitHeight
implicitWidth: content.implicitWidth || 854
opacity: 1 - offsetScale
@@ -33,10 +28,8 @@ Item {
id: content
active: root.shouldBeActive || root.visible
anchors.bottom: root.horizontal ? parent.bottom : undefined
anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined
anchors.right: root.horizontal ? undefined : parent.right
anchors.verticalCenter: root.horizontal ? undefined : parent.verticalCenter
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
sourceComponent: Content {
dashState: root.dashState
@@ -1,18 +1,17 @@
import QtQuick
import ZShell.Config
import qs.Components
import qs.Helpers
import ZShell.Config
import qs.Services
CustomRect {
id: root
required property bool horizontal
property bool tempEnabled: Hyprsunset.enabled
color: root.tempEnabled ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : width
implicitWidth: horizontal ? height : Math.max(Config.bar.height, Tokens.bar.innerSize)
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: implicitHeight
radius: Tokens.rounding.full
StateLayer {
@@ -27,7 +26,6 @@ CustomRect {
animate: true
color: root.tempEnabled ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
fill: root.tempEnabled ? 1 : 0
font.pointSize: Tokens.font.size.larger
text: root.tempEnabled ? "lightbulb" : "light_off"
Behavior on fill {
@@ -10,23 +10,14 @@ CustomRect {
id: root
readonly property string currentMedia: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title")
required property bool horizontal
readonly property int textWidth: Math.min(metrics.width, 200)
color: Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : layout.implicitHeight + Tokens.padding.normal * 2
implicitWidth: horizontal ? layout.implicitWidth + Tokens.padding.normal * 2 : Math.max(Config.bar.height, Tokens.bar.innerSize)
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: layout.implicitWidth + Tokens.padding.normal * 2
radius: Tokens.rounding.full
Behavior on implicitHeight {
enabled: !root.horizontal
Anim {
}
}
Behavior on implicitWidth {
enabled: root.horizontal
Anim {
}
}
@@ -38,15 +29,10 @@ CustomRect {
text: mediatext.text
}
GridLayout {
RowLayout {
id: layout
anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.normal
anchors.fill: parent
anchors.leftMargin: root.horizontal ? Tokens.padding.normal : 0
anchors.rightMargin: root.horizontal ? Tokens.padding.normal : 0
anchors.topMargin: root.horizontal ? 0 : Tokens.padding.normal
columns: root.horizontal ? -1 : 1
anchors.centerIn: parent
Behavior on implicitWidth {
Anim {
@@ -54,7 +40,6 @@ CustomRect {
}
MaterialIcon {
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
animate: true
color: Players.active?.isPlaying ? Colors.palette.m3primary : Colors.palette.m3onSurface
font.pointSize: Tokens.font.size.larger
@@ -64,26 +49,15 @@ CustomRect {
MarqueeText {
id: mediatext
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
Layout.preferredWidth: root.textWidth
animate: true
color: Players.active?.isPlaying ? Colors.palette.m3primary : Colors.palette.m3onSurface
font.pointSize: Tokens.font.size.normal
horizontalAlignment: Text.AlignHCenter
implicitWidth: root.textWidth
marqueeEnabled: false
pauseMs: 4000
text: root.currentMedia
transform: [
Translate {
x: !root.horizontal ? -root.textWidth + mediatext.implicitHeight : 0
},
Rotation {
angle: root.horizontal ? 0 : 270
origin.x: mediatext.implicitHeight / 2
origin.y: mediatext.implicitHeight / 2
}
]
width: root.textWidth
CustomMouseArea {
anchors.fill: parent
@@ -1,7 +1,6 @@
import Quickshell
import QtQuick
import ZShell.Config
import qs.Modules.Bar.Popouts
import qs.Daemons
import qs.Components
import qs.Services
@@ -9,13 +8,12 @@ import qs.Services
CustomRect {
id: root
required property bool horizontal
required property Wrapper popouts
required property PersistentProperties visibilities
color: visibilities.sidebar ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : width
implicitWidth: horizontal ? height : Math.max(Config.bar.height, Tokens.bar.innerSize)
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: implicitHeight
radius: Tokens.rounding.full
MaterialIcon {
@@ -24,6 +22,7 @@ CustomRect {
anchors.centerIn: parent
color: root.visibilities.sidebar ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
fill: root.visibilities.sidebar ? 1 : 0
font.family: "Material Symbols Rounded"
font.pointSize: Tokens.font.size.larger
text: NotifServer.list.length ? "\uf4fe" : "\ue7f4"
@@ -5,14 +5,13 @@ import qs.Components
import ZShell.Config
import qs.Services
GridLayout {
RowLayout {
id: root
property color accentColor: warning ? Colors.palette.m3error : mainColor
property real animatedPercentage: 0
readonly property real arcStartAngle: 0.75 * Math.PI
readonly property real arcSweep: 1.5 * Math.PI
required property bool horizontal
property string icon
required property color iconColor
required property color mainColor
@@ -22,9 +21,8 @@ GridLayout {
property bool warning: percentage * 100 >= warningThreshold
property int warningThreshold: 80
columnSpacing: Tokens.spacing.smaller
columns: horizontal ? -1 : 1
percentage: 0
spacing: Tokens.spacing.smaller
Behavior on animatedPercentage {
Anim {
@@ -49,8 +47,8 @@ GridLayout {
}
CustomClippingRect {
Layout.preferredHeight: root.horizontal ? icon.implicitHeight - Tokens.padding.small : 4
Layout.preferredWidth: root.horizontal ? 4 : icon.implicitWidth
Layout.preferredHeight: root.height - Tokens.padding.small
Layout.preferredWidth: 4
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
radius: Tokens.rounding.full
@@ -59,11 +57,9 @@ GridLayout {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: root.horizontal ? parent.right : undefined
anchors.top: root.horizontal ? undefined : parent.top
anchors.right: parent.right
color: root.mainColor
implicitHeight: root.horizontal ? Math.ceil(root.percentage * parent.height) : 0
implicitWidth: root.horizontal ? 0 : Math.ceil(root.percentage * parent.width)
implicitHeight: Math.ceil(root.percentage * parent.height)
// Behavior on implicitHeight {
// Anim {
@@ -12,13 +12,12 @@ import qs.Components
CustomRect {
id: root
required property bool horizontal
required property PersistentProperties visibilities
clip: true
color: visibilities.resources ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : gridLayout.implicitHeight + Tokens.padding.normal * 2
implicitWidth: horizontal ? gridLayout.implicitWidth + Tokens.padding.larger * 2 : Math.max(Config.bar.height, Tokens.bar.innerSize)
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: rowLayout.implicitWidth + Tokens.padding.larger * 2
radius: Tokens.rounding.full
StateLayer {
@@ -27,14 +26,13 @@ CustomRect {
onClicked: root.visibilities.resources = !root.visibilities.resources
}
GridLayout {
id: gridLayout
RowLayout {
id: rowLayout
anchors.centerIn: parent
anchors.horizontalCenterOffset: root.horizontal ? 0 : 1
anchors.verticalCenterOffset: root.horizontal ? 0 : -3
columnSpacing: Tokens.spacing.smaller
columns: root.horizontal ? -1 : 1
anchors.horizontalCenterOffset: -2
implicitHeight: root.implicitHeight
spacing: Tokens.spacing.smaller
ServiceRef {
service: Gpu
@@ -50,9 +48,7 @@ CustomRect {
Resource {
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: root.horizontal
Layout.fillWidth: !root.horizontal
horizontal: root.horizontal
Layout.fillHeight: true
icon: "memory"
iconColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
mainColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3primary
@@ -61,9 +57,7 @@ CustomRect {
}
Resource {
Layout.fillHeight: root.horizontal
Layout.fillWidth: !root.horizontal
horizontal: root.horizontal
Layout.fillHeight: true
icon: "memory_alt"
iconColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
mainColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3secondary
@@ -72,9 +66,7 @@ CustomRect {
}
Resource {
Layout.fillHeight: root.horizontal
Layout.fillWidth: !root.horizontal
horizontal: root.horizontal
Layout.fillHeight: true
icon: "gamepad"
iconColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
mainColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3tertiary
@@ -82,9 +74,7 @@ CustomRect {
}
Resource {
Layout.fillHeight: root.horizontal
Layout.fillWidth: !root.horizontal
horizontal: root.horizontal
Layout.fillHeight: true
icon: "developer_board"
iconColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
mainColor: root.visibilities.resources ? Colors.palette.m3onPrimary : Colors.palette.m3primary
+1 -3
View File
@@ -8,14 +8,12 @@ import ZShell.Config
Item {
id: root
required property bool horizontal
readonly property real nonAnimHeight: content.item?.nonAnimHeight ?? 0
property real offsetScale: shouldBeActive ? 0 : 1
readonly property bool shouldBeActive: root.visibilities.resources
required property PersistentProperties visibilities
anchors.leftMargin: horizontal ? 0 : (-implicitWidth - 5) * offsetScale
anchors.topMargin: horizontal ? (-implicitHeight - 5) * offsetScale : 0
anchors.topMargin: (-implicitHeight - 5) * offsetScale
clip: true
implicitHeight: content.implicitHeight
implicitWidth: content.implicitWidth || 854 // Hard coded fallback for first open
+1 -29
View File
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick.Layouts
import ZShell.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
@@ -26,6 +25,7 @@ PageBase {
ToggleRow {
checked: Config.bar.autoHide
first: true
last: true
settingAnchor: "bar-autohide"
subtext: qsTr("Hide the bar, reveal on hover")
text: qsTr("Auto hide")
@@ -33,34 +33,6 @@ PageBase {
onToggled: Config.bar.autoHide = checked
}
SelectRow {
active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2]
last: true
settingAnchor: "bar-position"
subtext: qsTr("Change which edge the bar appears on")
text: qsTr("Position")
menuItems: [
MenuItem {
icon: "build"
text: qsTr("Top")
value: "top"
},
MenuItem {
icon: "rotate_auto"
text: qsTr("Left")
value: "left"
},
MenuItem {
icon: "rotate_auto"
text: qsTr("Bottom")
value: "bottom"
}
]
onSelected: item => Config.bar.position = item.value
}
// Components
SectionHeader {
text: qsTr("Components")
@@ -3,9 +3,9 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Helpers
import qs.Modules.Bar.Components.StatusIcons
import qs.Modules.SysTray.Widgets
import ZShell.Config
import qs.Components
import qs.Services
@@ -19,10 +19,9 @@ CustomClippingRect {
return i;
return -1;
}
required property bool horizontal
// Index of the first/last entry that isn't collapsed, for edge margin gating
readonly property alias items: grid
readonly property alias items: row
readonly property int lastPresent: {
const values = model.values;
for (let i = values.length - 1; i >= 0; i--)
@@ -30,8 +29,6 @@ CustomClippingRect {
return i;
return -1;
}
readonly property real shortSize: Math.max(Config.bar.height, Tokens.bar.innerSize)
readonly property real size: horizontal ? grid.implicitWidth + Tokens.padding.small * 2 : grid.implicitHeight + Tokens.padding.small * 2
readonly property int spacing: Tokens.spacing.normal / 2
// Entries that can shrink to nothing, spacing included
@@ -41,36 +38,19 @@ CustomClippingRect {
return false;
}
bottomLeftRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full
bottomLeftRadius: Tokens.rounding.smallest / 2
color: Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? shortSize : size
implicitWidth: horizontal ? size : shortSize
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: row.implicitWidth + Tokens.padding.small * 2
radius: Tokens.rounding.full
topLeftRadius: Tokens.rounding.smallest / 2
topRightRadius: horizontal ? Tokens.rounding.full : Tokens.rounding.smallest / 2
Behavior on implicitHeight {
enabled: !root.horizontal
RowLayout {
id: row
Anim {
}
}
Behavior on implicitWidth {
enabled: root.horizontal
Anim {
}
}
GridLayout {
id: grid
anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: root.horizontal ? Tokens.padding.small : 0
anchors.rightMargin: root.horizontal ? Tokens.padding.small : 0
anchors.topMargin: root.horizontal ? 0 : Tokens.padding.small
columns: root.horizontal ? -1 : 1
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
Repeater {
model: ScriptModel {
@@ -89,7 +69,6 @@ CustomClippingRect {
name: "audio"
AudioWidget {
horizontal: root.horizontal
}
}
}
@@ -101,7 +80,6 @@ CustomClippingRect {
name: "audio"
MicWidget {
horizontal: root.horizontal
}
}
}
@@ -113,7 +91,6 @@ CustomClippingRect {
name: "upower"
UPowerWidget {
horizontal: root.horizontal
}
}
}
@@ -132,10 +109,8 @@ CustomClippingRect {
property real rightGap: present && index !== root.firstPresent ? margin : 0
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: root.horizontal ? 0 : Math.round(rightGap)
Layout.leftMargin: root.horizontal ? Math.round(leftGap) : 0
Layout.rightMargin: root.horizontal ? Math.round(rightGap) : 0
Layout.topMargin: root.horizontal ? 0 : Math.round(leftGap)
Layout.leftMargin: Math.round(leftGap)
Layout.rightMargin: Math.round(rightGap)
children: item
implicitHeight: item?.implicitHeight ?? 0
implicitWidth: item?.implicitWidth ?? 0
@@ -5,36 +5,31 @@ import QtQuick.Layouts
import Quickshell.Services.SystemTray
import qs.Components
import ZShell.Config
import qs.Modules.Bar.Components.Tray
import qs.Modules.Bar.Popouts
import qs.Modules.SysTray.Widgets
import qs.Modules
import qs.Services
CustomClippingRect {
id: root
required property bool horizontal
readonly property alias items: repeater
readonly property alias layout: sysGrid
required property GridLayout loader
readonly property alias layout: sysRow
required property RowLayout loader
readonly property int padding: Tokens.padding.small
required property Wrapper popouts
readonly property real shortSize: Math.max(Config.bar.height, Tokens.bar.innerSize)
readonly property real size: horizontal ? sysGrid.implicitWidth + Tokens.padding.small : sysGrid.implicitHeight + Tokens.padding.small
bottomLeftRadius: horizontal ? Tokens.rounding.full : Tokens.rounding.smallest / 2
bottomRightRadius: Tokens.rounding.smallest / 2
color: Colors.tPalette.m3surfaceContainer
implicitHeight: horizontal ? shortSize : size
implicitWidth: horizontal ? size : shortSize
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: sysRow.implicitWidth + Tokens.padding.small * 2
radius: Tokens.rounding.full
topRightRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full
topRightRadius: Tokens.rounding.smallest / 2
GridLayout {
id: sysGrid
RowLayout {
id: sysRow
anchors.centerIn: parent
columns: root.horizontal ? -1 : 1
rowSpacing: -2
spacing: 0
Repeater {
id: repeater
@@ -1,9 +1,10 @@
import QtQuick.Layouts
import QtQuick
import QtQuick.VectorImage
import Quickshell
import Quickshell.Services.SystemTray
import qs.Helpers
import qs.Modules.Bar.Popouts
import qs.Modules
import qs.Components
import ZShell.Config
import qs.Services
@@ -12,10 +13,10 @@ Item {
id: root
property bool current: popouts.currentName.startsWith(`traymenu${ind}`) && popouts.hasCurrent
readonly property real dpr: Hypr.monitorFor(loader?.screen).scale
readonly property real dpr: Hypr.monitorFor(loader.screen).scale
required property int ind
required property SystemTrayItem item
required property GridLayout loader
required property RowLayout loader
required property Wrapper popouts
function resolveIcon(app: string, icon: string): string {
+144
View File
@@ -0,0 +1,144 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.SystemTray
import qs.Components
import ZShell.Config
import qs.Modules.SysTray.Widgets
import qs.Modules
import qs.Services
RowLayout {
id: root
readonly property alias items: repeater
required property RowLayout loader
required property Wrapper popouts
function closestRowChild(row, x) {
let child = row.childAt(x, row.height / 2);
if (child)
return child;
let closest = null;
let closestDistance = Infinity;
for (let i = 0; i < row.children.length; ++i) {
let c = row.children[i];
if (!c.visible || c.width <= 0)
continue;
let centerX = c.x + c.width / 2;
let dist = Math.abs(x - centerX);
if (dist < closestDistance) {
closestDistance = dist;
closest = c;
}
}
return closest;
}
function getHoveredSubItem(localX, localY) {
let modPos = mapToItem(sysTrayMod, localX, localY);
if (sysTrayMod.contains(Qt.point(modPos.x, modPos.y))) {
let modRowPos = sysTrayMod.mapToItem(sysIcons, modPos.x, modPos.y);
let child = closestRowChild(sysIcons, modRowPos.x);
if (child) {
if (child.objectName === "audio" && Config.bar.popouts.audio)
return {
id: "audio",
item: child
};
if (child.objectName === "microphone" && Config.bar.popouts.audio)
return {
id: "audio",
item: child
};
if (child.objectName === "upower" && Config.bar.popouts.upower)
return {
id: "upower",
item: child
};
}
}
let trayPos = mapToItem(sysTray, localX, localY);
if (Config.bar.tray.showOnHover && sysTray.contains(Qt.point(trayPos.x, trayPos.y))) {
let trayRowPos = sysTray.mapToItem(sysRow, trayPos.x, trayPos.y);
let child = sysRow.childAt(trayRowPos.x, trayRowPos.y);
if (child && child.hasOwnProperty("ind")) {
return {
id: `traymenu${child.ind}`,
item: child
};
}
}
return null;
}
height: Config.bar.height + Tokens.padding.smallest * 2
spacing: Tokens.padding.small
width: sysTray.implicitWidth + sysTrayMod.implicitWidth + Tokens.padding.small
CustomClippingRect {
id: sysTray
Layout.fillHeight: true
bottomRightRadius: Tokens.rounding.smallest / 2
color: Colors.tPalette.m3surfaceContainer
implicitWidth: sysRow.width + Tokens.padding.small * 2
radius: Tokens.rounding.full
topRightRadius: Tokens.rounding.smallest / 2
Row {
id: sysRow
anchors.centerIn: parent
spacing: 0
Repeater {
id: repeater
model: SystemTray.items
TrayItem {
id: trayItem
required property int index
required property SystemTrayItem modelData
implicitHeight: 34
implicitWidth: 34
ind: index
item: modelData
loader: root.loader
popouts: root.popouts
}
}
}
}
CustomClippingRect {
id: sysTrayMod
Layout.fillHeight: true
bottomLeftRadius: Tokens.rounding.smallest / 2
color: Colors.tPalette.m3surfaceContainer
implicitWidth: sysIcons.implicitWidth + Tokens.padding.smaller + Tokens.padding.normal
radius: Tokens.rounding.full
topLeftRadius: Tokens.rounding.smallest / 2
StatusIcons {
id: sysIcons
anchors.fill: parent
anchors.leftMargin: Tokens.padding.smaller
anchors.rightMargin: Tokens.padding.normal
}
}
}
@@ -1,15 +1,16 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import Quickshell.Io
import Quickshell.Services.Pipewire
import qs.Daemons
import qs.Modules
import ZShell.Config
import qs.Components
import qs.Services
MaterialIcon {
id: speaker
required property bool horizontal
animate: true
color: Audio.muted ? Colors.palette.m3error : Colors.palette.m3onSurface
fill: 1
@@ -1,15 +1,16 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import Quickshell.Io
import Quickshell.Services.Pipewire
import qs.Daemons
import qs.Modules
import ZShell.Config
import qs.Components
import qs.Services
MaterialIcon {
id: mic
required property bool horizontal
animate: true
color: (Audio.sourceMuted ?? false) ? Colors.palette.m3error : Colors.palette.m3onSurface
fill: 1
@@ -1,15 +1,13 @@
import Quickshell.Services.UPower
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Components
import ZShell.Config
import qs.Helpers
Item {
id: root
required property bool horizontal
implicitHeight: Battery.isLaptop ? batteryIconLoader.item.implicitHeight : upowerIconLoader.item.implicitHeight
implicitWidth: Battery.isLaptop ? batteryIconLoader.item.implicitWidth : upowerIconLoader.item.implicitWidth
@@ -125,7 +123,6 @@ Item {
Layout.alignment: Qt.AlignVCenter
animate: true
fill: 1
font.pointSize: Tokens.font.size.larger
text: {
if (PowerProfiles.profile === PowerProfile.PowerSaver)
return "energy_savings_leaf";
+37
View File
@@ -0,0 +1,37 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules
import qs.Helpers
import ZShell.Config
import qs.Services
CustomRect {
id: root
property int countUpdates: Updates.availableUpdates
property color textColor: Colors.palette.m3onSurface
color: Colors.tPalette.m3surfaceContainer
implicitHeight: Config.bar.height + Tokens.padding.smallest * 2
implicitWidth: contentRow.implicitWidth + Tokens.spacing.small * 2
radius: Tokens.rounding.full
RowLayout {
id: contentRow
anchors.centerIn: parent
spacing: Tokens.spacing.small
MaterialIcon {
font.pointSize: Tokens.font.size.larger
text: "package_2"
}
CustomText {
color: root.textColor
font.pointSize: Tokens.font.size.normal
text: root.countUpdates
}
}
}
+86
View File
@@ -0,0 +1,86 @@
import Quickshell
import Quickshell.Hyprland
import Quickshell.Wayland
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Components
import qs.Modules
import qs.Helpers
import qs.Services
Item {
id: root
required property ShellScreen screen
required property Item wrapper
implicitHeight: layout.implicitHeight + 16
implicitWidth: layout.implicitWidth + 16
GridLayout {
id: layout
anchors.centerIn: parent
columnSpacing: 8
rowSpacing: 8
Repeater {
model: Hypr.workspaces
CustomRect {
id: workspacePreview
required property HyprlandWorkspace modelData
Layout.preferredHeight: 180 + 10
Layout.preferredWidth: 320 + 10
border.color: "white"
border.width: 1
radius: Tokens.rounding.smallest
Repeater {
model: workspacePreview.modelData.toplevels
Item {
id: preview
property rect appPosition: {
let {
at: [cx, cy],
size: [cw, ch]
} = modelData.lastIpcObject;
cx -= modelData.monitor.x;
cy -= modelData.monitor.y;
return Qt.rect((cx / 8), (cy / 8), (cw / 8), (ch / 8));
}
required property HyprlandToplevel modelData
anchors.fill: parent
anchors.margins: 5
CustomRect {
border.color: Colors.tPalette.m3outline
border.width: 1
implicitHeight: preview.appPosition.height
implicitWidth: preview.appPosition.width
radius: Tokens.rounding.smallest / 2
x: preview.appPosition.x
y: preview.appPosition.y - 3.4
ScreencopyView {
id: previewCopy
anchors.fill: parent
captureSource: preview.modelData.wayland
live: true
}
}
}
}
}
}
}
}
+75
View File
@@ -0,0 +1,75 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.Components
import ZShell.Config
import qs.Helpers
import qs.Services
Item {
id: root
required property var bar
property color colour: Colors.palette.m3primary
property Title current: text1
// readonly property int maxWidth: 300
readonly property int maxWidth: {
const otherModules = bar.children.filter(c => c.enabled && c.id && c.item !== this && c.id !== "spacer");
const otherWidth = otherModules.reduce((acc, curr) => {
return acc + (curr.item?.nonAnimWidth ?? curr.width ?? 0);
}, 0);
return bar.width - otherWidth - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2;
}
clip: true
implicitHeight: current.implicitHeight
implicitWidth: Math.min(current.implicitWidth, root.maxWidth)
Behavior on implicitWidth {
Anim {
}
}
Title {
id: text1
}
Title {
id: text2
}
TextMetrics {
id: metrics
elide: Qt.ElideRight
elideWidth: root.maxWidth
font.family: "Rubik"
font.pointSize: Tokens.font.size.normal
text: Hypr.activeToplevel?.title ?? qsTr("Desktop")
onElideWidthChanged: root.current.text = elidedText
onTextChanged: {
const next = root.current === text1 ? text2 : text1;
next.text = elidedText;
root.current = next;
}
}
component Title: CustomText {
id: text
anchors.leftMargin: 7
anchors.verticalCenter: parent.verticalCenter
color: root.colour
font.family: metrics.font.family
font.pointSize: metrics.font.pointSize
height: implicitHeight
opacity: root.current === this ? 1 : 0
width: implicitWidth
Behavior on opacity {
Anim {
}
}
}
}
@@ -2,10 +2,10 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import Quickshell.Hyprland
import ZShell.Config
import qs.Modules.Bar.Components.Workspaces
import qs.Components
import qs.Services
@@ -14,57 +14,41 @@ Item {
property real activeWorkspaceMargin: Math.ceil(Tokens.padding.small / 2)
readonly property int effectiveActiveWorkspaceId: monitor?.activeWorkspace?.id ?? 1
required property bool horizontal
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
required property ShellScreen screen
readonly property real shortSize: Math.max(Config.bar.height, Tokens.bar.innerSize)
readonly property real size: (workspaceButtonWidth * workspacesShown) + activeWorkspaceMargin * 2
property int workspaceButtonWidth: (horizontal ? bgRect.implicitHeight : bgRect.implicitWidth) - root.activeWorkspaceMargin * 2
property int workspaceButtonWidth: bgRect.implicitHeight - root.activeWorkspaceMargin * 2
property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown
readonly property list<var> workspaces: Hyprland.workspaces.values.filter(w => w.monitor === root.monitor)
readonly property int workspacesShown: workspaces.length
implicitHeight: horizontal ? shortSize : size
implicitWidth: horizontal ? size : shortSize
height: implicitHeight
implicitHeight: Config.bar.height + Tokens.padding.smaller * 2
implicitWidth: (root.workspaceButtonWidth * root.workspacesShown) + root.activeWorkspaceMargin * 2
Behavior on implicitHeight {
enabled: !root.horizontal
Anim {
}
}
Behavior on implicitWidth {
enabled: root.horizontal
Anim {
}
}
CustomRect {
// qmllint disable Quick.anchor-combinations
id: bgRect
anchors.bottom: root.horizontal ? undefined : parent.bottom
anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter
anchors.left: root.horizontal ? parent.left : undefined
anchors.right: root.horizontal ? parent.right : undefined
anchors.top: root.horizontal ? undefined : parent.top
anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
color: Colors.tPalette.m3surfaceContainer
implicitHeight: root.horizontal ? root.implicitHeight : 0
implicitWidth: root.horizontal ? 0 : root.implicitWidth
implicitHeight: root.implicitHeight - ((Tokens.padding.small - 1) * 2)
radius: height / 2
// qmllint enable Quick.anchor-combinations
Grid {
id: grid
anchors.fill: parent
anchors.margins: root.activeWorkspaceMargin
columnSpacing: 0
columns: root.horizontal ? root.workspacesShown : 1
columns: root.workspacesShown
rowSpacing: 0
rows: root.horizontal ? 1 : root.workspacesShown
rows: 1
Repeater {
model: root.workspaces
@@ -90,7 +74,7 @@ Item {
color: Colors.palette.m3onSecondaryContainer
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: button.modelData?.name ?? ""
text: button.modelData.name
verticalAlignment: Text.AlignVCenter
}
}
@@ -110,15 +94,13 @@ Item {
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceMargin
property real indicatorThickness: root.workspaceButtonWidth
anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter
anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined
anchors.verticalCenter: parent.verticalCenter
clip: true
color: Colors.palette.m3primary
implicitHeight: root.horizontal ? indicatorThickness : indicatorLength
implicitWidth: root.horizontal ? indicatorLength : indicatorThickness
implicitHeight: indicatorThickness
implicitWidth: indicatorLength
radius: Tokens.rounding.full
x: root.horizontal ? indicatorPosition : 0
y: root.horizontal ? 0 : indicatorPosition
x: indicatorPosition
AnimatedTabIndexPair {
id: idxPair
@@ -132,8 +114,7 @@ Item {
implicitWidth: grid.width
source: grid
sourceColor: Colors.palette.m3onSurface
x: root.horizontal ? -indicator.x + 3 : 0
y: root.horizontal ? 0 : -indicator.y + 3
x: -indicator.x + 3
}
}
}
-3
View File
@@ -2,8 +2,6 @@
#include "configlist.hpp"
#include "configobject.hpp"
#include <qcontainerfwd.h>
#include <qhashfunctions.h>
#include <qqmlregistration.h>
namespace ZShell::config {
@@ -63,7 +61,6 @@ class Bar : public ConfigObject {
CFG_PROPERTY(int, revealDelay, 100)
CFG_PROPERTY(int, rounding, 14)
CFG_PROPERTY(int, smoothing, 32)
CFG_PROPERTY(QString, position, QStringLiteral("top"))
CONFIG_SUBOBJECT(Tray, tray)
CONFIG_LIST(
EntryList,
-11
View File
@@ -61,8 +61,6 @@ Config::Config(QObject* parent)
m_reloadTimer.setInterval(50);
connect(&m_reloadTimer, &QTimer::timeout, this, &Config::reloadAsync);
connectAutoSave(this);
connect(
&m_watcher,
&QFileSystemWatcher::directoryChanged,
@@ -234,15 +232,6 @@ void Config::saveNow() {
flushAsync();
}
void Config::connectAutoSave(ConfigNode* node) {
connect(node, &ConfigNode::propertiesChanged, this, [this] {
scheduleSave();
});
for (auto* child : node->childNodes())
connectAutoSave(child);
}
bool Config::writeAtomically(const QByteArray& data) {
QSaveFile f(filePath());
-1
View File
@@ -90,7 +90,6 @@ class Config : public ConfigObject {
void updateWatch();
void loadSync();
void loadAsync();
void connectAutoSave(ConfigNode* node);
QTimer m_saveTimer;
QTimer m_reloadTimer;
+1 -15
View File
@@ -3,9 +3,7 @@
#include "configobject.hpp"
#include <QVariantList>
#include <qobject.h>
#include <qqmlengine.h>
#include <qqmlintegration.h>
#include <qqmlregistration.h>
namespace ZShell::config {
@@ -197,16 +195,6 @@ class AnimTokens : public ConfigObject {
, m_durations(new AnimDurations(this)) {}
};
class BarTokens : public ConfigObject {
Q_OBJECT
QML_ANONYMOUS
CFG_PROPERTY(int, innerSize, 28)
public:
explicit BarTokens(QObject* parent = nullptr) : ConfigObject(parent) {}
};
class Tokens : public ConfigObject {
Q_OBJECT
QML_ELEMENT
@@ -217,7 +205,6 @@ class Tokens : public ConfigObject {
CONFIG_SUBOBJECT(AppearanceSpacing, spacing)
CONFIG_SUBOBJECT(FontTokens, font)
CONFIG_SUBOBJECT(AnimTokens, anim)
CONFIG_SUBOBJECT(BarTokens, bar)
public:
explicit Tokens(QObject* parent = nullptr)
@@ -226,8 +213,7 @@ class Tokens : public ConfigObject {
, m_padding(new AppearancePadding(this))
, m_spacing(new AppearanceSpacing(this))
, m_font(new FontTokens(this))
, m_anim(new AnimTokens(this))
, m_bar(new BarTokens(this)) {}
, m_anim(new AnimTokens(this)) {}
static Tokens* create(QQmlEngine*, QJSEngine*) { return new Tokens(); }
};
+17 -7
View File
@@ -30,14 +30,24 @@ RUN pacman -S --noconfirm \
glib2
# AUR: libcava (provides development headers for cava)
RUN pacman -S --needed --noconfirm sudo && \
RUN pacman -Syu --noconfirm && \
pacman -S --needed --noconfirm \
sudo \
meson \
autoconf-archive \
python-tqdm && \
useradd -m builder && \
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
su builder -c " \
git clone https://aur.archlinux.org/libcava.git /tmp/libcava && \
cd /tmp/libcava && \
makepkg -si --noconfirm \
" && \
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
RUN for i in 1 2 3 4 5; do \
rm -rf /tmp/libcava && \
git clone --depth 1 https://aur.archlinux.org/libcava.git /tmp/libcava && \
break || sleep 5; \
done && \
test -d /tmp/libcava/.git && \
chown -R builder /tmp/libcava
RUN su builder -c "cd /tmp/libcava && makepkg -si --noconfirm" && \
rm -rf /tmp/libcava && \
userdel -r builder && \
sed -i '/^builder/d' /etc/sudoers
+3
View File
@@ -13,6 +13,9 @@ dependencies = [
"materialyoucolor"
]
[project.optional-dependencies]
dev = ["pytest"]
[project.scripts]
zshell-cli = "zshell:main"