From 1d150292d3dfd296308a8ab24d051ca0f9506060 Mon Sep 17 00:00:00 2001 From: zach Date: Wed, 12 Aug 2026 20:15:55 +0200 Subject: [PATCH 1/7] initial commit for repositioning bar, currently broken --- Config/BarConfig.qml | 1 + Drawers/Drawers.qml | 39 +++++++++++++++++++++++++-- Drawers/EdgeGeometry.qml | 57 +++++++++++++++++++++++++++++++++++++++ Drawers/Exclusions.qml | 9 +++++-- Drawers/Interactions.qml | 33 ++++++++++++++--------- Drawers/Windows.qml | 50 +++++++++++++++++++++------------- Modules/Bar/Bar.qml | 55 +++++++++++++++++++++++++------------ Modules/Bar/BarLoader.qml | 35 ++++++++++++++++-------- 8 files changed, 217 insertions(+), 62 deletions(-) create mode 100644 Drawers/EdgeGeometry.qml diff --git a/Config/BarConfig.qml b/Config/BarConfig.qml index 4f3697f..6f5997d 100644 --- a/Config/BarConfig.qml +++ b/Config/BarConfig.qml @@ -61,6 +61,7 @@ JsonObject { property bool hideWhenNotif: false property Popouts popouts: Popouts { } + property string position: "top" property int rounding: 8 property int smoothing: 32 property Tray tray: Tray { diff --git a/Drawers/Drawers.qml b/Drawers/Drawers.qml index b026775..490bc0e 100644 --- a/Drawers/Drawers.qml +++ b/Drawers/Drawers.qml @@ -11,15 +11,50 @@ 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 onConfigDashboardPositionChanged(): void { + Qt.callLater(scope.rebuild); + } + + 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 - screen: scope.modelData + geometry: content.geometry + screen: drawer.screen } Windows { id: content - screen: scope.modelData + screen: drawer.screen } } } diff --git a/Drawers/EdgeGeometry.qml b/Drawers/EdgeGeometry.qml new file mode 100644 index 0000000..47bc341 --- /dev/null +++ b/Drawers/EdgeGeometry.qml @@ -0,0 +1,57 @@ +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 configDashboardPosition + required property string configPosition + readonly property bool dashboardOnLeft: configDashboardPosition === "left" ? !barOnLeft : barOnTop + 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`); + } +} diff --git a/Drawers/Exclusions.qml b/Drawers/Exclusions.qml index 3373e34..259b616 100644 --- a/Drawers/Exclusions.qml +++ b/Drawers/Exclusions.qml @@ -9,19 +9,21 @@ Scope { id: root required property Item bar + required property EdgeGeometry geometry required property ShellScreen screen ExclusionZone { id: top anchors.top: true - exclusiveZone: root.bar.exclusiveZone + hasBar: root.geometry.barOnTop } ExclusionZone { id: left anchors.left: true + hasBar: root.geometry.barOnLeft } ExclusionZone { @@ -34,6 +36,7 @@ Scope { id: bottom anchors.bottom: true + hasBar: root.geometry.barOnBottom } Timer { @@ -44,7 +47,9 @@ Scope { } component ExclusionZone: CustomWindow { - exclusiveZone: Config.bar.border + property bool hasBar + + exclusiveZone: hasBar ? root.bar.exclusiveZone : Config.bar.border implicitHeight: 1 implicitWidth: 1 name: "Bar-Exclusion" diff --git a/Drawers/Interactions.qml b/Drawers/Interactions.qml index c72f55f..73570cf 100644 --- a/Drawers/Interactions.qml +++ b/Drawers/Interactions.qml @@ -12,6 +12,7 @@ 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 BarPopouts.Wrapper popouts @@ -21,19 +22,26 @@ Item { required property PersistentProperties visibilities function inBottomPanel(panel: Item, x: real, y: real): bool { - return y > root.height - panel.height - Config.bar.border && withinPanelWidth(panel, x, y); + return y > root.height - panel.height - geometry.insetBottom(borderThickness) && withinPanelWidth(panel, x, y); } function inLeftPanel(panel: Item, x: real, y: real): bool { - return x < panel.x + panel.width + Config.bar.border && withinPanelHeight(panel, x, y); + 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); } function inRightPanel(panel: Item, x: real, y: real): bool { - return x > panel.x - Config.bar.border && withinPanelHeight(panel, x, y); + return x > panel.x - geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y); } function inTopPanel(panel: Item, x: real, y: real): bool { - return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y); + return y < geometry.insetTop(borderThickness) + panel.height && withinPanelWidth(panel, x, y); } function onWheel(event: WheelEvent): void { @@ -43,12 +51,12 @@ Item { } function withinPanelHeight(panel: Item, x: real, y: real): bool { - const panelY = panel.y + bar.implicitHeight; + const panelY = panel.y + geometry.insetTop(borderThickness); return y >= panelY && y <= panelY + panel.height; } function withinPanelWidth(panel: Item, x: real, y: real): bool { - const panelX = panel.x + root.borderThickness; + const panelX = panel.x + geometry.insetLeft(borderThickness); return x >= panelX && x <= panelX + panel.width; } @@ -81,20 +89,21 @@ Item { if (root.singleGestureTriggered) return; - if (centroid.pressPosition.y < root.bar.implicitHeight) { - if (dragY > 20) { + if (root.geometry.barContains(centroid.pressPosition.x, centroid.pressPosition.y, true)) { + const barDrag = root.geometry.inwardDrag(dragX, dragY); + if (barDrag > 20) { root.visibilities.settings = true; root.singleGestureTriggered = true; - } else if (dragY < -20) { + } else if (barDrag < -20) { root.visibilities.settings = false; root.singleGestureTriggered = true; } } - if (centroid.pressPosition.y > root.screen.height - Config.bar.border && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50) + if (centroid.pressPosition.y > root.screen.height - root.geometry.insetBottom(root.borderThickness) && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50) root.visibilities.clipboard = true; - if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.bar.implicitHeight && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher) + 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 (dragY < -10) { root.visibilities.dock = true; root.singleGestureTriggered = true; @@ -193,7 +202,7 @@ Item { return; } - if (!root.visibilities.bar && Config.bar.autoHide && y < root.bar.implicitHeight) + if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true)) root.bar.isHovered = true; if (root.panels.sidebar.offsetScale === 1) { diff --git a/Drawers/Windows.qml b/Drawers/Windows.qml index 23f9028..e3874e2 100644 --- a/Drawers/Windows.qml +++ b/Drawers/Windows.qml @@ -32,6 +32,7 @@ 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; @@ -94,13 +95,21 @@ 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 + root.borderThickness - y: panels.notifications.y + bar.implicitHeight + x: panels.notifications.x + geometry.insetLeft(root.borderThickness) + y: panels.notifications.y + geometry.insetTop(root.borderThickness) Region { height: panels.osd.height @@ -113,7 +122,7 @@ CustomWindow { Regions { id: regions - bar: bar + geometry: geometry panels: panels win: root } @@ -192,10 +201,10 @@ CustomWindow { BlobInvertedRect { anchors.fill: parent anchors.margins: -50 - borderBottom: root.borderThickness - anchors.margins - root.sdfBorderOffset - borderLeft: root.borderThickness - anchors.margins - root.sdfBorderOffset + borderBottom: geometry.insetBottom(root.borderThickness) - anchors.margins - root.sdfBorderOffset + borderLeft: geometry.insetLeft(root.borderThickness) - anchors.margins - root.sdfBorderOffset borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset - borderTop: bar.implicitHeight - anchors.margins - root.sdfBorderOffset + borderTop: geometry.insetTop(root.borderThickness) - anchors.margins - root.sdfBorderOffset group: blobGroup radius: root.borderRounding } @@ -211,7 +220,7 @@ CustomWindow { panel: panels.dashboardWrapper radius: Appearance.rounding.normal x: panels.dashboardWrapper.x + panels.dashboard.x + root.borderThickness - y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight - panels.dashboard.height * extraHeight + y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - panels.dashboard.height * extraHeight } PanelBg { @@ -244,8 +253,7 @@ CustomWindow { implicitWidth: panels.osd.width panel: panels.osdWrapper radius: 20 - x: panels.osdWrapper.x + panels.osd.x + root.borderThickness - y: panels.osdWrapper.y + panels.osd.y + bar.implicitHeight + x: panels.osdWrapper.x + panels.osd.x + geometry.insetLeft(root.borderThickness) } PanelBg { @@ -267,17 +275,17 @@ CustomWindow { PanelBg { id: popoutBg - property real extraHeight: 0.2 + property real extraExtent: 0.2 deformAmount: panels.popouts.currentName.startsWith("traymenu") ? 0.15 : 0.08 - implicitHeight: panels.popouts.height * (1 + extraHeight) - implicitWidth: panels.popouts.width + implicitHeight: panels.popouts.height * (geometry.horizontal ? 1 + extraExtent : 1) + implicitWidth: panels.popouts.width * (geometry.horizontal ? 1 : 1 + extraExtent) panel: panels.popoutsWrapper radius: panels.popouts.current?.panelRadius ?? Appearance.rounding.normal - x: panels.popoutsWrapper.x + panels.popouts.x + root.borderThickness - y: panels.popoutsWrapper.y + panels.popouts.y + bar.implicitHeight - panels.popouts.height * extraHeight + 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) - Behavior on extraHeight { + Behavior on extraExtent { Anim { } } @@ -370,6 +378,7 @@ CustomWindow { borderThickness: root.borderLayoutThickness drawing: drawing enabled: true + geometry: geometry panels: panels popouts: panels.popouts screen: root.screen @@ -381,6 +390,7 @@ CustomWindow { bar: bar borderThickness: root.borderThickness drawingItem: drawing + geometry: geometry screen: root.screen visibilities: visibilities @@ -422,14 +432,18 @@ CustomWindow { BarLoader { id: bar + anchors.bottom: geometry.barOnBottom ? parent.bottom : undefined anchors.left: parent.left - anchors.right: parent.right + anchors.top: geometry.barOnBottom ? undefined : parent.top 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 } } @@ -442,7 +456,7 @@ CustomWindow { implicitHeight: panel.height implicitWidth: panel.width radius: Appearance.rounding.smallest - x: panel.x + root.borderThickness - y: panel.y + bar.implicitHeight + x: panel.x + geometry.insetLeft(root.borderThickness) + y: panel.y + geometry.insetTop(root.borderThickness) } } diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index b2a1842..14471ef 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -9,18 +9,24 @@ import qs.Modules.SysTray import qs.Modules.Network import qs.Modules.Updates -RowLayout { +GridLayout { 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 checkPopout(x: real): void { - const ch = childAt(x, height / 2) as EntryWrapper; + 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; const id = ch?.entryId; if (!ch || id === undefined) { @@ -34,26 +40,21 @@ RowLayout { if (id === "statusIcons" && Config.bar.popouts.statusIcons) { const items = (ch.item as StatusIcons).items; - const localX = mapToItem(items, x, 0).x; - const icon = items.childAt(localX, items.height / 2); + const icon = horizontal ? items.childAt(mapToItem(items, pos, 0).x, items.height / 2) : items.childAt(items.width / 2, mapToItem(items, 0, pos).y); if (icon) { popouts.currentName = icon.name; - popouts.currentCenter = Qt.binding(() => icon.mapToItem(root, icon.implicitWidth / 2, 0).x); + popouts.currentCenter = Qt.binding(() => axisCenterOf(icon)); 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 localX = mapToItem(layout, x, 0).x; - const trayItem = layout.childAt(localX, layout.height / 2); + const trayItem = horizontal ? layout.childAt(mapToItem(layout, pos, 0).x, layout.height / 2) : layout.childAt(items.width / 2, mapToItem(layout, 0, pos).y); if (trayItem) { const idx = trayItem.index; popouts.currentName = `traymenu${idx}`; - popouts.currentCenter = Qt.binding(() => { - const it = tray.items.itemAt(idx); - return it ? it.mapToItem(root, it.implicitWidth / 2, 0).x : popouts.currentCenter; - }); + popouts.currentCenter = Qt.binding(() => axisCenterOf(trayItem)); popouts.hasCurrent = true; } @@ -63,12 +64,19 @@ RowLayout { if (id === "updates") { popouts.currentName = "updates"; - popouts.currentCenter = Qt.binding(() => ch.item.mapToItem(root, (ch.item as Item).implicitWidth / 2, 0).x); + popouts.currentCenter = Qt.binding(() => axisCenterOf(ch.item as Item)); popouts.hasCurrent = true; } } - spacing: Appearance.spacing.small + function entryAt(pos: real): string { + const ch = (horizontal ? childAt(pos, height / 2) : childAt(width / 2, pos)) as EntryWrapper; + return ch?.entryId ?? ""; + } + + columnSpacing: Appearance.spacing.small + columns: horizontal ? -1 : 1 + rowSpacing: Appearance.spacing.small Repeater { id: repeater @@ -94,7 +102,8 @@ RowLayout { roleValue: "spacer" delegate: EntryWrapper { - Layout.fillWidth: true + Layout.fillHeight: !root.horizontal + Layout.fillWidth: root.horizontal } } @@ -103,6 +112,7 @@ RowLayout { delegate: EntryWrapper { Workspaces { + horizontal: root.horizontal screen: root.screen visible: !root.fullscreen } @@ -114,6 +124,7 @@ RowLayout { delegate: EntryWrapper { TrayIcons { + horizontal: root.horizontal loader: root popouts: root.popouts visible: !root.fullscreen @@ -126,6 +137,7 @@ RowLayout { delegate: EntryWrapper { StatusIcons { + horizontal: root.horizontal } } } @@ -135,6 +147,7 @@ RowLayout { delegate: EntryWrapper { Resources { + horizontal: root.horizontal visibilities: root.visibilities visible: !root.fullscreen } @@ -146,6 +159,7 @@ RowLayout { delegate: EntryWrapper { UpdatesWidget { + horizontal: root.horizontal visible: !root.fullscreen } } @@ -156,6 +170,7 @@ RowLayout { delegate: EntryWrapper { NotifBell { + horizontal: root.horizontal popouts: root.popouts visibilities: root.visibilities visible: !root.fullscreen @@ -168,6 +183,7 @@ RowLayout { delegate: EntryWrapper { Clock { + horizontal: root.horizontal loader: root popouts: root.popouts visibilities: root.visibilities @@ -182,6 +198,7 @@ RowLayout { delegate: EntryWrapper { WindowTitle { bar: root + horizontal: root.horizontal visible: !root.fullscreen } } @@ -192,6 +209,7 @@ RowLayout { delegate: EntryWrapper { NetworkWidget { + horizontal: root.horizontal } } } @@ -201,6 +219,7 @@ RowLayout { delegate: EntryWrapper { MediaWidget { + horizontal: root.horizontal visible: !root.fullscreen } } @@ -215,8 +234,10 @@ RowLayout { required property var modelData Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: index === 0 ? root.vPadding : (entryId === "statusIcons") ? -root.spacing + Appearance.spacing.extraSmall : 0 - Layout.rightMargin: index === repeater.count - 1 ? root.vPadding : 0 + Layout.bottomMargin: !root.horizontal && index === repeater.count - 1 ? root.vPadding : 0 + Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons") ? -root.rowSpacing + Appearance.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.columnSpacing + Appearance.spacing.extraSmall : 0 children: item implicitHeight: item?.implicitHeight ?? 0 implicitWidth: item?.implicitWidth ?? 0 diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index f5baba8..240417c 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -15,31 +15,40 @@ import qs.Modules.Network Item { id: root - readonly property int contentHeight: Config.bar.height + padding * 2 - readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentHeight + readonly property int clampedExtent: Math.max(Config.bar.border, extent) + readonly property int contentThickness: Config.bar.height + padding * 2 + readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness + property real extent: fullscreen ? 0 : Config.bar.border required property bool fullscreen + readonly property bool horizontal: position !== "left" property bool isHovered readonly property int padding: Math.max(Appearance.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(x: real): void { - content.item?.checkPopout(x); + function checkPopout(pos: real): void { + (content.item as Bar)?.checkPopout(pos); } - implicitHeight: fullscreen ? 0 : Config.bar.border - visible: height > Config.bar.border + function entryAt(pos: real): string { + return (content.item as Bar)?.entryAt(pos) ?? ""; + } + + implicitHeight: extent + implicitWidth: extent + visible: extent > Config.bar.border states: State { name: "visible" when: root.shouldBeVisible PropertyChanges { - root.implicitHeight: root.contentHeight + root.extent: root.contentThickness } } transitions: [ @@ -50,7 +59,7 @@ Item { Anim { duration: MaterialEasing.expressiveEffectsTime easing.bezierCurve: MaterialEasing.expressiveEffects - property: "implicitHeight" + property: "extent" target: root } }, @@ -61,7 +70,7 @@ Item { Anim { duration: MaterialEasing.expressiveEffectsTime easing.bezierCurve: MaterialEasing.expressiveEffects - property: "implicitHeight" + property: "extent" target: root } } @@ -71,13 +80,17 @@ Item { id: content active: root.shouldBeVisible || root.visible - anchors.bottom: parent.bottom - anchors.left: parent.left + anchors.bottom: root.position !== "bottom" ? parent.bottom : undefined + anchors.left: root.horizontal ? parent.left : undefined anchors.right: parent.right + anchors.top: root.position !== "top" ? parent.top : undefined + height: root.contentThickness + width: root.contentThickness sourceComponent: Bar { fullscreen: root.fullscreen height: root.contentHeight + horizontal: root.horizontal popouts: root.popouts popoutsWrapper: root.popoutsWrapper screen: root.screen -- 2.47.3 From 4517e5ecd0be5cbb2bb3049b1cdad47e26cda9f5 Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 14 Aug 2026 16:31:52 +0200 Subject: [PATCH 2/7] left-bar working, bottom bar semi-broken --- Components/MarqueeText.qml | 4 +- Drawers/EdgeGeometry.qml | 2 - Drawers/Interactions.qml | 25 ++++------ Drawers/Panels.qml | 25 ++++++---- Drawers/Regions.qml | 21 ++++---- Drawers/Windows.qml | 16 +++---- Modules/Bar/Bar.qml | 30 +++++++++--- Modules/Bar/BarLoader.qml | 11 +---- Modules/ClipWrapper.qml | 43 ++++++++++++++--- Modules/Clock.qml | 24 ++++++++-- Modules/Dashboard/Wrapper.qml | 5 ++ Modules/HyprsunsetWidget.qml | 7 ++- Modules/MediaWidget.qml | 24 ++++++++-- Modules/NotifBell.qml | 9 ++-- Modules/Resource.qml | 16 ++++--- Modules/Resources.qml | 33 ++++++++----- Modules/Resources/Wrapper.qml | 4 +- Modules/Settings/Pages/Panels/BarPanel.qml | 33 ++++++++++++- Modules/SysTray/StatusIcons.qml | 46 ++++++++++++++---- Modules/SysTray/TrayIcons.qml | 22 +++++---- Modules/SysTray/TrayItem.qml | 4 +- Modules/SysTray/TrayWidget.qml | 33 +++++++++---- Modules/SysTray/Widgets/AudioWidget.qml | 4 +- Modules/SysTray/Widgets/MicWidget.qml | 4 +- Modules/SysTray/Widgets/UPowerWidget.qml | 3 ++ Modules/Updates/UpdatesWidget.qml | 19 +++++--- Modules/WindowTitle.qml | 56 +++++++++++++++------- Modules/Workspaces.qml | 49 +++++++++++++------ 28 files changed, 404 insertions(+), 168 deletions(-) diff --git a/Components/MarqueeText.qml b/Components/MarqueeText.qml index 427d381..3db5490 100644 --- a/Components/MarqueeText.qml +++ b/Components/MarqueeText.qml @@ -40,7 +40,7 @@ Item { } } - clip: true + clip: false implicitHeight: elideText.implicitHeight Behavior on leftFadeStrength { @@ -80,7 +80,7 @@ Item { id: marqueeViewport anchors.fill: parent - clip: true + clip: false layer.enabled: true visible: root.overflowing diff --git a/Drawers/EdgeGeometry.qml b/Drawers/EdgeGeometry.qml index 47bc341..e10b45b 100644 --- a/Drawers/EdgeGeometry.qml +++ b/Drawers/EdgeGeometry.qml @@ -10,9 +10,7 @@ QtObject { readonly property bool barOnBottom: position === "bottom" readonly property bool barOnLeft: position === "left" readonly property bool barOnTop: position === "top" - required property string configDashboardPosition required property string configPosition - readonly property bool dashboardOnLeft: configDashboardPosition === "left" ? !barOnLeft : barOnTop readonly property bool horizontal: position !== "left" readonly property string position: configPosition === "top" || configPosition === "bottom" ? configPosition : "left" required property var win diff --git a/Drawers/Interactions.qml b/Drawers/Interactions.qml index 73570cf..2c29d99 100644 --- a/Drawers/Interactions.qml +++ b/Drawers/Interactions.qml @@ -22,7 +22,8 @@ Item { required property PersistentProperties visibilities function inBottomPanel(panel: Item, x: real, y: real): bool { - return y > root.height - panel.height - geometry.insetBottom(borderThickness) && withinPanelWidth(panel, x, y); + const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); + return y > root.height - (panelHeight + geometry.insetBottom(borderThickness)) && withinPanelWidth(panel, x, y); } function inLeftPanel(panel: Item, x: real, y: real): bool { @@ -37,17 +38,12 @@ Item { } function inRightPanel(panel: Item, x: real, y: real): bool { - return x > panel.x - geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y); + return x > panel.x + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y); } function inTopPanel(panel: Item, x: real, y: real): bool { - return y < geometry.insetTop(borderThickness) + panel.height && withinPanelWidth(panel, x, y); - } - - function onWheel(event: WheelEvent): void { - if (event.x < bar.implicitWidth) { - bar.handleWheel(event.y, event.angleDelta); - } + const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); + return y < geometry.insetTop(borderThickness) + panelHeight && withinPanelWidth(panel, x, y); } function withinPanelHeight(panel: Item, x: real, y: real): bool { @@ -89,12 +85,11 @@ Item { if (root.singleGestureTriggered) return; - if (root.geometry.barContains(centroid.pressPosition.x, centroid.pressPosition.y, true)) { - const barDrag = root.geometry.inwardDrag(dragX, dragY); - if (barDrag > 20) { + if (root.geometry.insetTop(root.borderThickness) > centroid.pressPosition.y) { + if (dragY > 20) { root.visibilities.settings = true; root.singleGestureTriggered = true; - } else if (barDrag < -20) { + } else if (dragY < -20) { root.visibilities.settings = false; root.singleGestureTriggered = true; } @@ -228,8 +223,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 (y < root.bar.implicitHeight) - root.bar.checkPopout(x); + if (root.geometry.barContains(x, y)) + root.bar.checkPopout(root.geometry.axisPos(x, y)); } } diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index 8a587be..a3b1bd6 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -27,6 +27,7 @@ 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 @@ -43,9 +44,11 @@ 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: bar.implicitHeight + anchors.topMargin: geometry.insetTop(borderThickness) Item { id: resourcesWrapper @@ -53,14 +56,15 @@ Item { anchors.left: parent.left anchors.top: parent.top clip: true - implicitHeight: resources.implicitHeight * (1 - resources.offsetScale) - implicitWidth: resources.implicitWidth + implicitHeight: root.geometry.horizontal ? resources.implicitHeight * (1 - resources.offsetScale) : resources.implicitHeight + implicitWidth: root.geometry.horizontal ? resources.implicitWidth : resources.implicitWidth * (1 - resources.offsetScale) Resources.Wrapper { id: resources anchors.left: parent.left anchors.top: parent.top + horizontal: root.geometry.horizontal visibilities: root.visibilities } } @@ -99,8 +103,8 @@ Item { Modules.ClipWrapper { id: popouts - anchors.top: parent.top borderThickness: root.borderThickness + position: root.geometry.position screen: root.screen } @@ -147,11 +151,13 @@ Item { property real offsetScale: dashboard.shouldBeActive ? 0 : 1 - anchors.right: parent.right - anchors.top: parent.top + 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 clip: true - implicitHeight: dashboard.implicitHeight * (1 - offsetScale) - implicitWidth: dashboard.implicitWidth + implicitHeight: root.geometry.horizontal ? dashboard.implicitHeight * (1 - offsetScale) : dashboard.implicitHeight + implicitWidth: root.geometry.horizontal ? dashboard.implicitWidth : dashboard.implicitWidth * (1 - offsetScale) Behavior on offsetScale { Anim { @@ -164,8 +170,7 @@ Item { id: dashboard anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: (-implicitHeight - 5) * offsetScale + horizontal: root.geometry.horizontal offsetScale: dashboardWrapper.offsetScale visibilities: root.visibilities } diff --git a/Drawers/Regions.qml b/Drawers/Regions.qml index e5c3757..590f92f 100644 --- a/Drawers/Regions.qml +++ b/Drawers/Regions.qml @@ -7,17 +7,18 @@ 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 - bar.implicitHeight - win.borderThickness - win.dragMaskPadding * 2 + height: win.height - geometry.insetTop(borderThickness, true) - geometry.insetBottom(borderThickness, true) - win.dragMaskPadding * 2 intersection: Intersection.Xor - width: win.width - win.borderThickness * 2 - win.dragMaskPadding * 2 - x: win.borderThickness + win.dragMaskPadding - y: bar.implicitHeight + win.dragMaskPadding + 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 R { panel: root.panels.dashboardWrapper @@ -41,17 +42,21 @@ 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.borderThickness + height: panel.height * (1 - root.panels.utilities.offsetScale) + root.geometry.insetBottom(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 { @@ -82,7 +87,7 @@ Region { height: panel.height intersection: Intersection.Subtract width: panel.width - x: panel.x + root.borderThickness - y: panel.y + root.bar.implicitHeight + x: panel.x + root.geometry.insetLeft(root.borderThickness) + y: panel.y + root.geometry.insetTop(root.borderThickness) } } diff --git a/Drawers/Windows.qml b/Drawers/Windows.qml index e3874e2..b3fb795 100644 --- a/Drawers/Windows.qml +++ b/Drawers/Windows.qml @@ -212,15 +212,15 @@ CustomWindow { PanelBg { id: dashBg - property real extraHeight: 0.2 + property real extraExtent: 0.2 deformAmount: 0.06 - implicitHeight: panels.dashboard.height * (1 + extraHeight) - implicitWidth: panels.dashboard.width + implicitHeight: panels.dashboard.height * (geometry.horizontal ? 1 + extraExtent : 1) + implicitWidth: panels.dashboard.width * (geometry.horizontal ? 1 : 1 + extraExtent) panel: panels.dashboardWrapper radius: Appearance.rounding.normal - x: panels.dashboardWrapper.x + panels.dashboard.x + root.borderThickness - y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - panels.dashboard.height * extraHeight + 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) } PanelBg { @@ -232,7 +232,7 @@ CustomWindow { implicitHeight: panels.launcher.height * (1 + extraHeight) panel: panels.launcher radius: Appearance.rounding.smallest + 5 - y: panels.launcher.y + bar.implicitHeight + y: panels.launcher.y + geometry.insetTop(root.borderThickness) } PanelBg { @@ -299,8 +299,8 @@ CustomWindow { implicitWidth: panels.resources.width panel: panels.resourcesWrapper radius: Appearance.rounding.large - x: panels.resourcesWrapper.x + panels.resources.x + root.borderThickness - y: panels.resourcesWrapper.y + panels.resources.y + bar.implicitHeight + x: panels.resourcesWrapper.x + panels.resources.x + geometry.insetLeft(root.borderThickness) + y: panels.resourcesWrapper.y + panels.resources.y + geometry.insetTop(root.borderThickness) } PanelBg { diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 14471ef..74a79ad 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -49,7 +49,7 @@ GridLayout { } 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(items.width / 2, mapToItem(layout, 0, pos).y); + const trayItem = horizontal ? layout.childAt(mapToItem(layout, pos, 0).x, layout.height / 2) : layout.childAt(tray.width / 2, mapToItem(layout, 0, pos).y); if (trayItem) { const idx = trayItem.index; @@ -92,7 +92,10 @@ GridLayout { roleValue: "hyprsunset" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + HyprsunsetWidget { + horizontal: root.horizontal visible: !root.fullscreen } } @@ -123,6 +126,8 @@ GridLayout { roleValue: "tray" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + TrayIcons { horizontal: root.horizontal loader: root @@ -136,6 +141,8 @@ GridLayout { roleValue: "statusIcons" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + StatusIcons { horizontal: root.horizontal } @@ -146,6 +153,8 @@ GridLayout { roleValue: "resources" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + Resources { horizontal: root.horizontal visibilities: root.visibilities @@ -158,6 +167,8 @@ GridLayout { roleValue: "updates" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + UpdatesWidget { horizontal: root.horizontal visible: !root.fullscreen @@ -169,6 +180,8 @@ GridLayout { roleValue: "notifBell" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + NotifBell { horizontal: root.horizontal popouts: root.popouts @@ -182,6 +195,8 @@ GridLayout { roleValue: "clock" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + Clock { horizontal: root.horizontal loader: root @@ -196,6 +211,8 @@ GridLayout { roleValue: "activeWindow" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + WindowTitle { bar: root horizontal: root.horizontal @@ -209,7 +226,6 @@ GridLayout { delegate: EntryWrapper { NetworkWidget { - horizontal: root.horizontal } } } @@ -218,6 +234,8 @@ GridLayout { roleValue: "media" delegate: EntryWrapper { + Layout.fillWidth: !root.horizontal + MediaWidget { horizontal: root.horizontal visible: !root.fullscreen @@ -233,11 +251,11 @@ GridLayout { default property Item item required property var modelData - Layout.alignment: Qt.AlignVCenter + 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.rowSpacing + Appearance.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.columnSpacing + Appearance.spacing.extraSmall : 0 + Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.rowSpacing + Appearance.spacing.extraSmall : root.horizontal ? 0 : Appearance.padding.smaller + Layout.rightMargin: root.horizontal && index === repeater.count - 1 ? root.vPadding : root.horizontal ? 0 : Appearance.padding.smaller + Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.columnSpacing + Appearance.spacing.extraSmall : 0 children: item implicitHeight: item?.implicitHeight ?? 0 implicitWidth: item?.implicitWidth ?? 0 diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index 240417c..fafd193 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -1,28 +1,22 @@ pragma ComponentBehavior: Bound import Quickshell -import Quickshell.Hyprland import QtQuick -import QtQuick.Layouts import qs.Components import qs.Modules import qs.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: Config.bar.height + padding * 2 + readonly property int contentThickness: Math.max(Config.bar.height, (horizontal ? 24 : 30)) + padding * 2 readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness property real extent: fullscreen ? 0 : Config.bar.border required property bool fullscreen readonly property bool horizontal: position !== "left" property bool isHovered - readonly property int padding: Math.max(Appearance.padding.smaller, Config.bar.border) + readonly property int padding: horizontal ? Math.max(Appearance.padding.smaller, Config.bar.border) : Math.max(Appearance.padding.larger, Config.bar.border) required property Wrapper popouts required property ClipWrapper popoutsWrapper required property string position @@ -89,7 +83,6 @@ Item { sourceComponent: Bar { fullscreen: root.fullscreen - height: root.contentHeight horizontal: root.horizontal popouts: root.popouts popoutsWrapper: root.popoutsWrapper diff --git a/Modules/ClipWrapper.qml b/Modules/ClipWrapper.qml index 10fbd82..cb7cc5e 100644 --- a/Modules/ClipWrapper.qml +++ b/Modules/ClipWrapper.qml @@ -10,27 +10,51 @@ Item { required property real borderThickness readonly property alias content: content - property real offsetScale: y > 0 || content.hasCurrent ? 0 : 1 + 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: content.implicitHeight * (1 - offsetScale) - implicitWidth: content.implicitWidth + 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.offsetScale < 1 + enabled: !root.horizontal || root.offsetScale < 1 Anim { duration: content.animLength @@ -38,6 +62,8 @@ Item { } } Behavior on y { + enabled: root.horizontal || root.offsetScale < 1 + Anim { duration: content.animLength easing.bezierCurve: content.animCurve @@ -47,9 +73,14 @@ Item { Wrapper { id: content - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top + 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 } diff --git a/Modules/Clock.qml b/Modules/Clock.qml index fb668c0..15f95de 100644 --- a/Modules/Clock.qml +++ b/Modules/Clock.qml @@ -9,27 +9,45 @@ import qs.Components CustomRect { id: root - required property RowLayout loader + required property bool horizontal + required property GridLayout loader required property Wrapper popouts + readonly property real shortSize: Config.bar.height + Appearance.padding.smallest * 2 + readonly property real size: timeText.contentWidth + (horizontal ? Appearance.padding.normal : Appearance.padding.larger) * 2 required property PersistentProperties visibilities + anchors.fill: parent color: visibilities.dashboard ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: timeText.contentWidth + Appearance.padding.normal * 2 + implicitHeight: horizontal ? shortSize : size + implicitWidth: horizontal ? size : shortSize radius: Appearance.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 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface font: 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 { diff --git a/Modules/Dashboard/Wrapper.qml b/Modules/Dashboard/Wrapper.qml index 26da1e5..747d0e4 100644 --- a/Modules/Dashboard/Wrapper.qml +++ b/Modules/Dashboard/Wrapper.qml @@ -14,11 +14,16 @@ 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 diff --git a/Modules/HyprsunsetWidget.qml b/Modules/HyprsunsetWidget.qml index 4a2ad27..c5bd375 100644 --- a/Modules/HyprsunsetWidget.qml +++ b/Modules/HyprsunsetWidget.qml @@ -6,11 +6,13 @@ import qs.Config CustomRect { id: root + required property bool horizontal property bool tempEnabled: Hyprsunset.enabled + anchors.fill: parent color: root.tempEnabled ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: implicitHeight + implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : width + implicitWidth: horizontal ? height : Config.bar.height + Appearance.padding.smallest * 2 radius: Appearance.rounding.full StateLayer { @@ -25,6 +27,7 @@ CustomRect { animate: true color: root.tempEnabled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface fill: root.tempEnabled ? 1 : 0 + font.pointSize: root.horizontal ? Appearance.font.size.larger : Appearance.font.size.large text: root.tempEnabled ? "lightbulb" : "light_off" Behavior on fill { diff --git a/Modules/MediaWidget.qml b/Modules/MediaWidget.qml index 644446a..9208622 100644 --- a/Modules/MediaWidget.qml +++ b/Modules/MediaWidget.qml @@ -9,11 +9,13 @@ 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) + anchors.fill: parent color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: layout.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : layout.implicitHeight + Appearance.padding.normal * 2 + implicitWidth: horizontal ? layout.implicitWidth + Appearance.padding.normal * 2 : Config.bar.height + Appearance.padding.smallest radius: Appearance.rounding.full Behavior on implicitWidth { @@ -28,10 +30,11 @@ CustomRect { text: mediatext.text } - RowLayout { + GridLayout { id: layout anchors.centerIn: parent + columns: root.horizontal ? -1 : 1 Behavior on implicitWidth { Anim { @@ -39,6 +42,7 @@ CustomRect { } MaterialIcon { + Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter animate: true color: Players.active?.isPlaying ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface font.pointSize: Appearance.font.size.larger @@ -48,7 +52,8 @@ CustomRect { MarqueeText { id: mediatext - Layout.preferredWidth: root.textWidth + Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter + Layout.preferredHeight: root.horizontal ? root.height : root.textWidth animate: true color: Players.active?.isPlaying ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface font.pointSize: Appearance.font.size.normal @@ -58,6 +63,17 @@ CustomRect { text: root.currentMedia width: root.textWidth + 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 + } + ] + CustomMouseArea { anchors.fill: parent hoverEnabled: true diff --git a/Modules/NotifBell.qml b/Modules/NotifBell.qml index ba15f26..dabacab 100644 --- a/Modules/NotifBell.qml +++ b/Modules/NotifBell.qml @@ -7,12 +7,14 @@ import qs.Components CustomRect { id: root + required property bool horizontal required property Wrapper popouts required property PersistentProperties visibilities + anchors.fill: parent color: visibilities.sidebar ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: implicitHeight + implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : width + implicitWidth: horizontal ? height : Config.bar.height + Appearance.padding.smallest * 2 radius: Appearance.rounding.full MaterialIcon { @@ -21,8 +23,7 @@ CustomRect { anchors.centerIn: parent color: root.visibilities.sidebar ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface fill: root.visibilities.sidebar ? 1 : 0 - font.family: "Material Symbols Rounded" - font.pointSize: Appearance.font.size.larger + font.pointSize: root.horizontal ? Appearance.font.size.larger : Appearance.font.size.large text: NotifServer.list.length ? "\uf4fe" : "\ue7f4" Behavior on color { diff --git a/Modules/Resource.qml b/Modules/Resource.qml index 32a6b46..2cdb28d 100644 --- a/Modules/Resource.qml +++ b/Modules/Resource.qml @@ -4,13 +4,14 @@ import QtQuick.Shapes import qs.Components import qs.Config -RowLayout { +GridLayout { id: root property color accentColor: warning ? DynamicColors.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 @@ -20,8 +21,9 @@ RowLayout { property bool warning: percentage * 100 >= warningThreshold property int warningThreshold: 80 + columnSpacing: Appearance.spacing.smaller + columns: horizontal ? -1 : 1 percentage: 0 - spacing: Appearance.spacing.smaller Behavior on animatedPercentage { Anim { @@ -46,8 +48,8 @@ RowLayout { } CustomClippingRect { - Layout.preferredHeight: root.height - Appearance.padding.small - Layout.preferredWidth: 4 + Layout.preferredHeight: root.horizontal ? icon.implicitHeight : 4 + Layout.preferredWidth: root.horizontal ? 4 : icon.implicitWidth color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) radius: Appearance.rounding.full @@ -56,9 +58,11 @@ RowLayout { anchors.bottom: parent.bottom anchors.left: parent.left - anchors.right: parent.right + anchors.right: root.horizontal ? parent.right : undefined + anchors.top: root.horizontal ? undefined : parent.top color: root.mainColor - implicitHeight: Math.ceil(root.percentage * parent.height) + implicitHeight: root.horizontal ? Math.ceil(root.percentage * parent.height) : 0 + implicitWidth: root.horizontal ? 0 : Math.ceil(root.percentage * parent.height) // Behavior on implicitHeight { // Anim { diff --git a/Modules/Resources.qml b/Modules/Resources.qml index cf3ef24..f33c442 100644 --- a/Modules/Resources.qml +++ b/Modules/Resources.qml @@ -12,12 +12,14 @@ import qs.Components CustomRect { id: root + required property bool horizontal required property PersistentProperties visibilities + anchors.fill: parent clip: true color: visibilities.resources ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: rowLayout.implicitWidth + Appearance.padding.larger * 2 + implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : gridLayout.implicitHeight + Appearance.padding.normal * 2 + implicitWidth: horizontal ? gridLayout.implicitWidth + Appearance.padding.larger * 2 : Config.bar.height radius: Appearance.rounding.full StateLayer { @@ -26,13 +28,14 @@ CustomRect { onClicked: root.visibilities.resources = !root.visibilities.resources } - RowLayout { - id: rowLayout + GridLayout { + id: gridLayout anchors.centerIn: parent - anchors.horizontalCenterOffset: -2 - implicitHeight: root.implicitHeight - spacing: Appearance.spacing.smaller + anchors.horizontalCenterOffset: root.horizontal ? 0 : 1 + anchors.verticalCenterOffset: root.horizontal ? 0 : -3 + columnSpacing: Appearance.spacing.smaller + columns: root.horizontal ? -1 : 1 ServiceRef { service: Gpu @@ -48,7 +51,9 @@ CustomRect { Resource { Layout.alignment: Qt.AlignVCenter - Layout.fillHeight: true + Layout.fillHeight: root.horizontal + Layout.fillWidth: !root.horizontal + horizontal: root.horizontal icon: "memory" iconColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface mainColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary @@ -57,7 +62,9 @@ CustomRect { } Resource { - Layout.fillHeight: true + Layout.fillHeight: root.horizontal + Layout.fillWidth: !root.horizontal + horizontal: root.horizontal icon: "memory_alt" iconColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface mainColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3secondary @@ -66,7 +73,9 @@ CustomRect { } Resource { - Layout.fillHeight: true + Layout.fillHeight: root.horizontal + Layout.fillWidth: !root.horizontal + horizontal: root.horizontal icon: "gamepad" iconColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface mainColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3tertiary @@ -74,7 +83,9 @@ CustomRect { } Resource { - Layout.fillHeight: true + Layout.fillHeight: root.horizontal + Layout.fillWidth: !root.horizontal + horizontal: root.horizontal icon: "developer_board" iconColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface mainColor: root.visibilities.resources ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary diff --git a/Modules/Resources/Wrapper.qml b/Modules/Resources/Wrapper.qml index 7c196e6..77ad0cb 100644 --- a/Modules/Resources/Wrapper.qml +++ b/Modules/Resources/Wrapper.qml @@ -8,12 +8,14 @@ import qs.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.topMargin: (-implicitHeight - 5) * offsetScale + anchors.leftMargin: horizontal ? 0 : (-implicitWidth - 5) * offsetScale + anchors.topMargin: horizontal ? (-implicitHeight - 5) * offsetScale : 0 clip: true implicitHeight: content.implicitHeight implicitWidth: content.implicitWidth || 854 // Hard coded fallback for first open diff --git a/Modules/Settings/Pages/Panels/BarPanel.qml b/Modules/Settings/Pages/Panels/BarPanel.qml index 9b344eb..450063e 100644 --- a/Modules/Settings/Pages/Panels/BarPanel.qml +++ b/Modules/Settings/Pages/Panels/BarPanel.qml @@ -1,6 +1,7 @@ pragma ComponentBehavior: Bound import QtQuick.Layouts +import qs.Components import qs.Config import qs.Modules.Settings.Common @@ -25,7 +26,6 @@ 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,6 +33,37 @@ 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("Automatic or manual effect values") + text: qsTr("Effects mode") + + 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; + Config.save(); + } + } + // Components SectionHeader { text: qsTr("Components") diff --git a/Modules/SysTray/StatusIcons.qml b/Modules/SysTray/StatusIcons.qml index 5e40cdb..1376fb9 100644 --- a/Modules/SysTray/StatusIcons.qml +++ b/Modules/SysTray/StatusIcons.qml @@ -18,9 +18,10 @@ 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: row + readonly property alias items: grid readonly property int lastPresent: { const values = model.values; for (let i = values.length - 1; i >= 0; i--) @@ -28,6 +29,8 @@ CustomClippingRect { return i; return -1; } + readonly property real shortSize: Config.bar.height + Appearance.padding.smallest * 2 + readonly property real size: horizontal ? grid.implicitWidth + Appearance.padding.small * 2 : grid.implicitHeight + Appearance.padding.small * 2 readonly property int spacing: Appearance.spacing.normal / 2 // Entries that can shrink to nothing, spacing included @@ -37,19 +40,37 @@ CustomClippingRect { return false; } - bottomLeftRadius: Appearance.rounding.smallest / 2 + anchors.fill: parent + bottomLeftRadius: horizontal ? Appearance.rounding.smallest / 2 : Appearance.rounding.full color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: row.implicitWidth + Appearance.padding.small * 2 + implicitHeight: horizontal ? shortSize : size + implicitWidth: horizontal ? size : shortSize radius: Appearance.rounding.full topLeftRadius: Appearance.rounding.smallest / 2 + topRightRadius: horizontal ? Appearance.rounding.full : Appearance.rounding.smallest / 2 - RowLayout { - id: row + Behavior on implicitHeight { + enabled: !root.horizontal + Anim { + } + } + Behavior on implicitWidth { + enabled: root.horizontal + + Anim { + } + } + + GridLayout { + id: grid + + anchors.bottomMargin: root.horizontal ? 0 : Appearance.padding.small anchors.fill: parent - anchors.leftMargin: Appearance.padding.small - anchors.rightMargin: Appearance.padding.small + anchors.leftMargin: root.horizontal ? Appearance.padding.small : 0 + anchors.rightMargin: root.horizontal ? Appearance.padding.small : 0 + anchors.topMargin: root.horizontal ? 0 : Appearance.padding.small + columns: root.horizontal ? -1 : 1 Repeater { model: ScriptModel { @@ -68,6 +89,7 @@ CustomClippingRect { name: "audio" AudioWidget { + horizontal: root.horizontal } } } @@ -79,6 +101,7 @@ CustomClippingRect { name: "audio" MicWidget { + horizontal: root.horizontal } } } @@ -90,6 +113,7 @@ CustomClippingRect { name: "upower" UPowerWidget { + horizontal: root.horizontal } } } @@ -108,8 +132,10 @@ CustomClippingRect { property real rightGap: present && index !== root.firstPresent ? margin : 0 Layout.alignment: Qt.AlignHCenter - Layout.leftMargin: Math.round(leftGap) - Layout.rightMargin: Math.round(rightGap) + 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) children: item implicitHeight: item?.implicitHeight ?? 0 implicitWidth: item?.implicitWidth ?? 0 diff --git a/Modules/SysTray/TrayIcons.qml b/Modules/SysTray/TrayIcons.qml index 7d47919..74cb001 100644 --- a/Modules/SysTray/TrayIcons.qml +++ b/Modules/SysTray/TrayIcons.qml @@ -11,24 +11,30 @@ import qs.Modules CustomClippingRect { id: root + required property bool horizontal readonly property alias items: repeater - readonly property alias layout: sysRow - required property RowLayout loader + readonly property alias layout: sysGrid + required property GridLayout loader readonly property int padding: Appearance.padding.small required property Wrapper popouts + readonly property real shortSize: Config.bar.height + Appearance.padding.smallest * 2 + readonly property real size: horizontal ? sysGrid.implicitWidth + Appearance.padding.small : sysGrid.implicitHeight + Appearance.padding.small + anchors.fill: parent + bottomLeftRadius: horizontal ? Appearance.rounding.full : Appearance.rounding.smallest / 2 bottomRightRadius: Appearance.rounding.smallest / 2 color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: sysRow.implicitWidth + Appearance.padding.small * 2 + implicitHeight: horizontal ? shortSize : size + implicitWidth: horizontal ? size : shortSize radius: Appearance.rounding.full - topRightRadius: Appearance.rounding.smallest / 2 + topRightRadius: horizontal ? Appearance.rounding.smallest / 2 : Appearance.rounding.full - RowLayout { - id: sysRow + GridLayout { + id: sysGrid anchors.centerIn: parent - spacing: 0 + columns: root.horizontal ? -1 : 1 + rowSpacing: -2 Repeater { id: repeater diff --git a/Modules/SysTray/TrayItem.qml b/Modules/SysTray/TrayItem.qml index dc017c4..87f9762 100644 --- a/Modules/SysTray/TrayItem.qml +++ b/Modules/SysTray/TrayItem.qml @@ -12,10 +12,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 RowLayout loader + required property GridLayout loader required property Wrapper popouts function resolveIcon(app: string, icon: string): string { diff --git a/Modules/SysTray/TrayWidget.qml b/Modules/SysTray/TrayWidget.qml index 3797200..f63a24a 100644 --- a/Modules/SysTray/TrayWidget.qml +++ b/Modules/SysTray/TrayWidget.qml @@ -8,12 +8,15 @@ import qs.Config import qs.Modules.SysTray.Widgets import qs.Modules -RowLayout { +GridLayout { id: root + required property bool horizontal readonly property alias items: repeater - required property RowLayout loader + required property GridLayout loader required property Wrapper popouts + readonly property real shortSize: Config.bar.height + Appearance.padding.smallest * 2 + readonly property real size: horizontal ? sysTray.implicitWidth + sysTrayMod.implicitWidth + Appearance.padding.small : sysTray.implicitHeight + sysTrayMod.implicitHeight + Appearance.padding.small function closestRowChild(row, x) { let child = row.childAt(x, row.height / 2); @@ -80,9 +83,11 @@ RowLayout { return null; } - height: Config.bar.height + Appearance.padding.smallest * 2 - spacing: Appearance.padding.small - width: sysTray.implicitWidth + sysTrayMod.implicitWidth + Appearance.padding.small + columnSpacing: Appearance.padding.small + columns: horizontal ? -1 : 1 + height: horizontal ? shortSize : size + rowSpacing: Appearance.padding.small + width: horizontal ? size : shortSize CustomClippingRect { id: sysTray @@ -94,11 +99,18 @@ RowLayout { radius: Appearance.rounding.full topRightRadius: Appearance.rounding.smallest / 2 - Row { + GridLayout { id: sysRow + anchors.bottom: root.horizontal ? undefined : parent.bottom anchors.centerIn: parent - spacing: 0 + anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined + anchors.left: root.horizontal ? undefined : parent.left + anchors.right: root.horizontal ? undefined : parent.right + anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined + columnSpacing: Appearance.spacing.small / 2 + columns: root.horizontal ? -1 : 1 + rowSpacing: Appearance.spacing.small / 2 Repeater { id: repeater @@ -125,10 +137,12 @@ RowLayout { CustomClippingRect { id: sysTrayMod - Layout.fillHeight: true + Layout.fillHeight: root.horizontal + Layout.fillWidth: !root.horizontal bottomLeftRadius: Appearance.rounding.smallest / 2 color: DynamicColors.tPalette.m3surfaceContainer - implicitWidth: sysIcons.implicitWidth + Appearance.padding.smaller + Appearance.padding.normal + implicitHeight: root.horizontal ? sysIcons.implicitHeight : sysIcons.implicitHeight + Appearance.padding.smaller + Appearance.padding.normal + implicitWidth: root.horizontal ? sysIcons.implicitWidth + Appearance.padding.smaller + Appearance.padding.normal : sysIcons.implicitWidth radius: Appearance.rounding.full topLeftRadius: Appearance.rounding.smallest / 2 @@ -138,6 +152,7 @@ RowLayout { anchors.fill: parent anchors.leftMargin: Appearance.padding.smaller anchors.rightMargin: Appearance.padding.normal + horizontal: root.horizontal } } } diff --git a/Modules/SysTray/Widgets/AudioWidget.qml b/Modules/SysTray/Widgets/AudioWidget.qml index 4555d11..5190656 100644 --- a/Modules/SysTray/Widgets/AudioWidget.qml +++ b/Modules/SysTray/Widgets/AudioWidget.qml @@ -10,10 +10,12 @@ import qs.Components MaterialIcon { id: speaker + required property bool horizontal + animate: true color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurface fill: 1 - font.pointSize: Appearance.font.size.larger + font.pointSize: horizontal ? Appearance.font.size.larger : Appearance.font.size.large text: Audio.muted ? "volume_off" : "volume_up" Behavior on Layout.maximumWidth { diff --git a/Modules/SysTray/Widgets/MicWidget.qml b/Modules/SysTray/Widgets/MicWidget.qml index 2aa51ce..77681df 100644 --- a/Modules/SysTray/Widgets/MicWidget.qml +++ b/Modules/SysTray/Widgets/MicWidget.qml @@ -10,10 +10,12 @@ import qs.Components MaterialIcon { id: mic + required property bool horizontal + animate: true color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurface fill: 1 - font.pointSize: Appearance.font.size.larger + font.pointSize: horizontal ? Appearance.font.size.larger : Appearance.font.size.large text: Audio.sourceMuted ? "mic_off" : "mic" Behavior on Layout.maximumWidth { diff --git a/Modules/SysTray/Widgets/UPowerWidget.qml b/Modules/SysTray/Widgets/UPowerWidget.qml index 6968b4f..cd789d3 100644 --- a/Modules/SysTray/Widgets/UPowerWidget.qml +++ b/Modules/SysTray/Widgets/UPowerWidget.qml @@ -8,6 +8,8 @@ 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 @@ -123,6 +125,7 @@ Item { Layout.alignment: Qt.AlignVCenter animate: true fill: 1 + font.pointSize: root.horizontal ? Appearance.font.size.larger : Appearance.font.size.large text: { if (PowerProfiles.profile === PowerProfile.PowerSaver) return "energy_savings_leaf"; diff --git a/Modules/Updates/UpdatesWidget.qml b/Modules/Updates/UpdatesWidget.qml index 14be0cb..c1cbe32 100644 --- a/Modules/Updates/UpdatesWidget.qml +++ b/Modules/Updates/UpdatesWidget.qml @@ -9,27 +9,32 @@ CustomRect { id: root property int countUpdates: Updates.availableUpdates + required property bool horizontal property color textColor: DynamicColors.palette.m3onSurface + anchors.fill: parent color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: Config.bar.height + Appearance.padding.smallest * 2 - implicitWidth: contentRow.implicitWidth + Appearance.spacing.small * 2 + implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : content.implicitHeight + Appearance.spacing.small * 2 + implicitWidth: horizontal ? content.implicitWidth + Appearance.spacing.small * 2 : Config.bar.height radius: Appearance.rounding.full - RowLayout { - id: contentRow + GridLayout { + id: content anchors.centerIn: parent - spacing: Appearance.spacing.small + columnSpacing: Appearance.spacing.small + columns: root.horizontal ? -1 : 1 MaterialIcon { - font.pointSize: Appearance.font.size.larger + Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter + font.pointSize: root.horizontal ? Appearance.font.size.larger : Appearance.font.size.large text: "package_2" } CustomText { + Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter color: root.textColor - font.pointSize: Appearance.font.size.normal + font.pointSize: root.horizontal ? Appearance.font.size.normal : Appearance.font.size.larger text: root.countUpdates } } diff --git a/Modules/WindowTitle.qml b/Modules/WindowTitle.qml index 88c4cc0..62deadd 100644 --- a/Modules/WindowTitle.qml +++ b/Modules/WindowTitle.qml @@ -9,22 +9,32 @@ Item { id: root required property var bar - property color colour: DynamicColors.palette.m3primary + property color color: DynamicColors.palette.m3primary property Title current: text1 + required property bool horizontal // 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; + 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: true - implicitHeight: current.implicitHeight - implicitWidth: Math.min(current.implicitWidth, root.maxWidth) + implicitHeight: horizontal ? current.implicitHeight : current.implicitWidth + current.anchors.topMargin + implicitWidth: horizontal ? Math.min(current.implicitWidth, root.maxSize) : current.implicitHeight + current.anchors.topMargin + Behavior on implicitHeight { + enabled: !root.horizontal + + Anim { + duration: MaterialEasing.expressiveEffectsTime + easing.bezierCurve: MaterialEasing.expressiveEffects + } + } Behavior on implicitWidth { + enabled: root.horizontal + Anim { duration: MaterialEasing.expressiveEffectsTime easing.bezierCurve: MaterialEasing.expressiveEffects @@ -33,19 +43,17 @@ Item { Title { id: text1 - } Title { id: text2 - } TextMetrics { id: metrics elide: Qt.ElideRight - elideWidth: root.maxWidth + elideWidth: root.maxSize - (root.horizontal ? root.current.anchors.leftMargin : 0) font.family: "Rubik" font.pointSize: Appearance.font.size.normal text: Hypr.activeToplevel?.title ?? qsTr("Desktop") @@ -61,18 +69,32 @@ Item { component Title: CustomText { id: text - anchors.leftMargin: 7 - anchors.verticalCenter: parent.verticalCenter - color: root.colour + anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter + anchors.left: root.horizontal ? parent.left : undefined + anchors.leftMargin: root.horizontal ? Appearance.spacing.small : 0 + anchors.top: root.horizontal ? undefined : parent.top + anchors.topMargin: root.horizontal ? 0 : Appearance.spacing.small + anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined + color: root.color font.family: metrics.font.family font.pointSize: metrics.font.pointSize - height: implicitHeight + height: root.horizontal ? implicitHeight : implicitWidth opacity: root.current === this ? 1 : 0 - width: implicitWidth + 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 + } + ] } } diff --git a/Modules/Workspaces.qml b/Modules/Workspaces.qml index 91420db..f9c610d 100644 --- a/Modules/Workspaces.qml +++ b/Modules/Workspaces.qml @@ -13,41 +13,57 @@ Item { property real activeWorkspaceMargin: Math.ceil(Appearance.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 - property int workspaceButtonWidth: bgRect.implicitHeight - root.activeWorkspaceMargin * 2 + readonly property real shortSize: Config.bar.height + Appearance.padding.smaller * 2 + readonly property real size: (workspaceButtonWidth * workspacesShown) + activeWorkspaceMargin * 2 + property int workspaceButtonWidth: (horizontal ? bgRect.implicitHeight : bgRect.implicitWidth) - root.activeWorkspaceMargin * 2 property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown readonly property list workspaces: Hyprland.workspaces.values.filter(w => w.monitor === root.monitor) readonly property int workspacesShown: workspaces.length - height: implicitHeight - implicitHeight: Config.bar.height + Appearance.padding.smaller * 2 - implicitWidth: (root.workspaceButtonWidth * root.workspacesShown) + root.activeWorkspaceMargin * 2 + implicitHeight: horizontal ? shortSize : size + implicitWidth: horizontal ? size : shortSize + Behavior on implicitHeight { + enabled: !root.horizontal + + Anim { + } + } Behavior on implicitWidth { + enabled: root.horizontal + Anim { } } CustomRect { + // qmllint disable Quick.anchor-combinations id: bgRect - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter + 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 color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: root.implicitHeight - ((Appearance.padding.small - 1) * 2) + implicitHeight: root.horizontal ? root.implicitHeight - ((Appearance.padding.small - 1) * 2) : 0 + implicitWidth: root.horizontal ? 0 : root.implicitWidth - ((Appearance.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.workspacesShown + columns: root.horizontal ? root.workspacesShown : 1 rowSpacing: 0 - rows: 1 + rows: root.horizontal ? 1 : root.workspacesShown Repeater { model: root.workspaces @@ -93,13 +109,15 @@ Item { property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceMargin property real indicatorThickness: root.workspaceButtonWidth - anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter + anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined clip: true color: DynamicColors.palette.m3primary - implicitHeight: indicatorThickness - implicitWidth: indicatorLength + implicitHeight: root.horizontal ? indicatorThickness : indicatorLength + implicitWidth: root.horizontal ? indicatorLength : indicatorThickness radius: Appearance.rounding.full - x: indicatorPosition + x: root.horizontal ? indicatorPosition : 0 + y: root.horizontal ? 0 : indicatorPosition AnimatedTabIndexPair { id: idxPair @@ -113,7 +131,8 @@ Item { implicitWidth: grid.width source: grid sourceColor: DynamicColors.palette.m3onSurface - x: -indicator.x + 3 + x: root.horizontal ? -indicator.x + 3 : 0 + y: root.horizontal ? 0 : -indicator.y + 3 } } } -- 2.47.3 From ef8811724f38074a04f13bce5787770b485d002f Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 14 Aug 2026 18:03:56 +0200 Subject: [PATCH 3/7] better height/width for bar --- Drawers/Panels.qml | 1 - Modules/Bar/Bar.qml | 22 ++-------------------- Modules/Bar/BarLoader.qml | 4 ++-- Modules/Clock.qml | 3 +-- Modules/Dashboard/Wrapper.qml | 6 ++++-- Modules/HyprsunsetWidget.qml | 5 ++--- Modules/MediaWidget.qml | 5 ++--- Modules/NotifBell.qml | 5 ++--- Modules/Resources.qml | 3 +-- Modules/SysTray/StatusIcons.qml | 3 +-- Modules/SysTray/TrayIcons.qml | 3 +-- Modules/Updates/UpdatesWidget.qml | 3 +-- Modules/Workspaces.qml | 6 +++--- 13 files changed, 22 insertions(+), 47 deletions(-) diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index a3b1bd6..6dfd863 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -169,7 +169,6 @@ Item { Dashboard.Wrapper { id: dashboard - anchors.right: parent.right horizontal: root.geometry.horizontal offsetScale: dashboardWrapper.offsetScale visibilities: root.visibilities diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 74a79ad..be47506 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -92,8 +92,6 @@ GridLayout { roleValue: "hyprsunset" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - HyprsunsetWidget { horizontal: root.horizontal visible: !root.fullscreen @@ -126,8 +124,6 @@ GridLayout { roleValue: "tray" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - TrayIcons { horizontal: root.horizontal loader: root @@ -141,8 +137,6 @@ GridLayout { roleValue: "statusIcons" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - StatusIcons { horizontal: root.horizontal } @@ -153,8 +147,6 @@ GridLayout { roleValue: "resources" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - Resources { horizontal: root.horizontal visibilities: root.visibilities @@ -167,8 +159,6 @@ GridLayout { roleValue: "updates" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - UpdatesWidget { horizontal: root.horizontal visible: !root.fullscreen @@ -180,8 +170,6 @@ GridLayout { roleValue: "notifBell" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - NotifBell { horizontal: root.horizontal popouts: root.popouts @@ -195,8 +183,6 @@ GridLayout { roleValue: "clock" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - Clock { horizontal: root.horizontal loader: root @@ -211,8 +197,6 @@ GridLayout { roleValue: "activeWindow" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - WindowTitle { bar: root horizontal: root.horizontal @@ -234,8 +218,6 @@ GridLayout { roleValue: "media" delegate: EntryWrapper { - Layout.fillWidth: !root.horizontal - MediaWidget { horizontal: root.horizontal visible: !root.fullscreen @@ -253,8 +235,8 @@ GridLayout { 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 + Appearance.spacing.extraSmall : root.horizontal ? 0 : Appearance.padding.smaller - Layout.rightMargin: root.horizontal && index === repeater.count - 1 ? root.vPadding : root.horizontal ? 0 : Appearance.padding.smaller + Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.rowSpacing + Appearance.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 + Appearance.spacing.extraSmall : 0 children: item implicitHeight: item?.implicitHeight ?? 0 diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index fafd193..55e286e 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -10,13 +10,13 @@ Item { id: root readonly property int clampedExtent: Math.max(Config.bar.border, extent) - readonly property int contentThickness: Math.max(Config.bar.height, (horizontal ? 24 : 30)) + padding * 2 + readonly property int contentThickness: Math.max(Config.bar.height, 30) + padding * 2 readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness property real extent: fullscreen ? 0 : Config.bar.border required property bool fullscreen readonly property bool horizontal: position !== "left" property bool isHovered - readonly property int padding: horizontal ? Math.max(Appearance.padding.smaller, Config.bar.border) : Math.max(Appearance.padding.larger, Config.bar.border) + readonly property int padding: Appearance.padding.smaller required property Wrapper popouts required property ClipWrapper popoutsWrapper required property string position diff --git a/Modules/Clock.qml b/Modules/Clock.qml index 15f95de..0ec2816 100644 --- a/Modules/Clock.qml +++ b/Modules/Clock.qml @@ -12,11 +12,10 @@ CustomRect { required property bool horizontal required property GridLayout loader required property Wrapper popouts - readonly property real shortSize: Config.bar.height + Appearance.padding.smallest * 2 + readonly property real shortSize: Config.bar.height readonly property real size: timeText.contentWidth + (horizontal ? Appearance.padding.normal : Appearance.padding.larger) * 2 required property PersistentProperties visibilities - anchors.fill: parent color: visibilities.dashboard ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer implicitHeight: horizontal ? shortSize : size implicitWidth: horizontal ? size : shortSize diff --git a/Modules/Dashboard/Wrapper.qml b/Modules/Dashboard/Wrapper.qml index 747d0e4..946fc6e 100644 --- a/Modules/Dashboard/Wrapper.qml +++ b/Modules/Dashboard/Wrapper.qml @@ -33,8 +33,10 @@ Item { id: content active: root.shouldBeActive || root.visible - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter + 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 sourceComponent: Content { dashState: root.dashState diff --git a/Modules/HyprsunsetWidget.qml b/Modules/HyprsunsetWidget.qml index c5bd375..5dd364a 100644 --- a/Modules/HyprsunsetWidget.qml +++ b/Modules/HyprsunsetWidget.qml @@ -9,10 +9,9 @@ CustomRect { required property bool horizontal property bool tempEnabled: Hyprsunset.enabled - anchors.fill: parent color: root.tempEnabled ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : width - implicitWidth: horizontal ? height : Config.bar.height + Appearance.padding.smallest * 2 + implicitHeight: horizontal ? Config.bar.height : width + implicitWidth: horizontal ? height : Config.bar.height radius: Appearance.rounding.full StateLayer { diff --git a/Modules/MediaWidget.qml b/Modules/MediaWidget.qml index 9208622..ad52b3e 100644 --- a/Modules/MediaWidget.qml +++ b/Modules/MediaWidget.qml @@ -12,10 +12,9 @@ CustomRect { required property bool horizontal readonly property int textWidth: Math.min(metrics.width, 200) - anchors.fill: parent color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : layout.implicitHeight + Appearance.padding.normal * 2 - implicitWidth: horizontal ? layout.implicitWidth + Appearance.padding.normal * 2 : Config.bar.height + Appearance.padding.smallest + implicitHeight: horizontal ? Config.bar.height : layout.implicitHeight + Appearance.padding.normal * 2 + implicitWidth: horizontal ? layout.implicitWidth + Appearance.padding.normal * 2 : Config.bar.height radius: Appearance.rounding.full Behavior on implicitWidth { diff --git a/Modules/NotifBell.qml b/Modules/NotifBell.qml index dabacab..05cfacc 100644 --- a/Modules/NotifBell.qml +++ b/Modules/NotifBell.qml @@ -11,10 +11,9 @@ CustomRect { required property Wrapper popouts required property PersistentProperties visibilities - anchors.fill: parent color: visibilities.sidebar ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : width - implicitWidth: horizontal ? height : Config.bar.height + Appearance.padding.smallest * 2 + implicitHeight: horizontal ? Config.bar.height : width + implicitWidth: horizontal ? height : Config.bar.height radius: Appearance.rounding.full MaterialIcon { diff --git a/Modules/Resources.qml b/Modules/Resources.qml index f33c442..706560b 100644 --- a/Modules/Resources.qml +++ b/Modules/Resources.qml @@ -15,10 +15,9 @@ CustomRect { required property bool horizontal required property PersistentProperties visibilities - anchors.fill: parent clip: true color: visibilities.resources ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : gridLayout.implicitHeight + Appearance.padding.normal * 2 + implicitHeight: horizontal ? Math.max(Config.bar.height, 24) : gridLayout.implicitHeight + Appearance.padding.normal * 2 implicitWidth: horizontal ? gridLayout.implicitWidth + Appearance.padding.larger * 2 : Config.bar.height radius: Appearance.rounding.full diff --git a/Modules/SysTray/StatusIcons.qml b/Modules/SysTray/StatusIcons.qml index 1376fb9..f9e5b3b 100644 --- a/Modules/SysTray/StatusIcons.qml +++ b/Modules/SysTray/StatusIcons.qml @@ -29,7 +29,7 @@ CustomClippingRect { return i; return -1; } - readonly property real shortSize: Config.bar.height + Appearance.padding.smallest * 2 + readonly property real shortSize: Config.bar.height readonly property real size: horizontal ? grid.implicitWidth + Appearance.padding.small * 2 : grid.implicitHeight + Appearance.padding.small * 2 readonly property int spacing: Appearance.spacing.normal / 2 @@ -40,7 +40,6 @@ CustomClippingRect { return false; } - anchors.fill: parent bottomLeftRadius: horizontal ? Appearance.rounding.smallest / 2 : Appearance.rounding.full color: DynamicColors.tPalette.m3surfaceContainer implicitHeight: horizontal ? shortSize : size diff --git a/Modules/SysTray/TrayIcons.qml b/Modules/SysTray/TrayIcons.qml index 74cb001..b2e6f95 100644 --- a/Modules/SysTray/TrayIcons.qml +++ b/Modules/SysTray/TrayIcons.qml @@ -17,10 +17,9 @@ CustomClippingRect { required property GridLayout loader readonly property int padding: Appearance.padding.small required property Wrapper popouts - readonly property real shortSize: Config.bar.height + Appearance.padding.smallest * 2 + readonly property real shortSize: Config.bar.height readonly property real size: horizontal ? sysGrid.implicitWidth + Appearance.padding.small : sysGrid.implicitHeight + Appearance.padding.small - anchors.fill: parent bottomLeftRadius: horizontal ? Appearance.rounding.full : Appearance.rounding.smallest / 2 bottomRightRadius: Appearance.rounding.smallest / 2 color: DynamicColors.tPalette.m3surfaceContainer diff --git a/Modules/Updates/UpdatesWidget.qml b/Modules/Updates/UpdatesWidget.qml index c1cbe32..47480a4 100644 --- a/Modules/Updates/UpdatesWidget.qml +++ b/Modules/Updates/UpdatesWidget.qml @@ -12,9 +12,8 @@ CustomRect { required property bool horizontal property color textColor: DynamicColors.palette.m3onSurface - anchors.fill: parent color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height + Appearance.padding.smallest * 2 : content.implicitHeight + Appearance.spacing.small * 2 + implicitHeight: horizontal ? Config.bar.height : content.implicitHeight + Appearance.spacing.small * 2 implicitWidth: horizontal ? content.implicitWidth + Appearance.spacing.small * 2 : Config.bar.height radius: Appearance.rounding.full diff --git a/Modules/Workspaces.qml b/Modules/Workspaces.qml index f9c610d..aa6d71b 100644 --- a/Modules/Workspaces.qml +++ b/Modules/Workspaces.qml @@ -16,7 +16,7 @@ Item { required property bool horizontal readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen) required property ShellScreen screen - readonly property real shortSize: Config.bar.height + Appearance.padding.smaller * 2 + readonly property real shortSize: Math.max(Config.bar.height, 24) readonly property real size: (workspaceButtonWidth * workspacesShown) + activeWorkspaceMargin * 2 property int workspaceButtonWidth: (horizontal ? bgRect.implicitHeight : bgRect.implicitWidth) - root.activeWorkspaceMargin * 2 property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown @@ -50,8 +50,8 @@ Item { anchors.top: root.horizontal ? undefined : parent.top anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined color: DynamicColors.tPalette.m3surfaceContainer - implicitHeight: root.horizontal ? root.implicitHeight - ((Appearance.padding.small - 1) * 2) : 0 - implicitWidth: root.horizontal ? 0 : root.implicitWidth - ((Appearance.padding.small - 1) * 2) + implicitHeight: root.horizontal ? root.implicitHeight : 0 + implicitWidth: root.horizontal ? 0 : root.implicitWidth radius: height / 2 // qmllint enable Quick.anchor-combinations -- 2.47.3 From 0092b41a058ae47f8d1caaa66ba84d618efa136d Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 14 Aug 2026 22:15:11 +0200 Subject: [PATCH 4/7] fix config file writing + positioning issues --- Modules/Bar/BarLoader.qml | 2 +- Modules/Clock.qml | 2 +- Modules/HyprsunsetWidget.qml | 6 +++--- Modules/MediaWidget.qml | 21 ++++++++++++++++----- Modules/NotifBell.qml | 6 +++--- Modules/Resource.qml | 4 ++-- Modules/Resources.qml | 4 ++-- Modules/Settings/Pages/Panels/BarPanel.qml | 9 +++------ Modules/SysTray/StatusIcons.qml | 2 +- Modules/SysTray/TrayIcons.qml | 2 +- Modules/SysTray/Widgets/AudioWidget.qml | 2 +- Modules/SysTray/Widgets/MicWidget.qml | 2 +- Modules/SysTray/Widgets/UPowerWidget.qml | 2 +- Modules/Updates/UpdatesWidget.qml | 7 ++++--- Modules/Workspaces.qml | 2 +- Plugins/ZShell/Config/bar.hpp | 3 ++- Plugins/ZShell/Config/config.cpp | 11 +++++++++++ Plugins/ZShell/Config/config.hpp | 1 + Plugins/ZShell/Config/tokens.hpp | 16 +++++++++++++++- 19 files changed, 70 insertions(+), 34 deletions(-) diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index a19ea4a..ff7f0a2 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -14,7 +14,7 @@ Item { id: root readonly property int clampedExtent: Math.max(Config.bar.border, extent) - readonly property int contentThickness: Math.max(Config.bar.height, 30) + padding * 2 + 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 required property bool fullscreen diff --git a/Modules/Clock.qml b/Modules/Clock.qml index 6c63af5..0626ed9 100644 --- a/Modules/Clock.qml +++ b/Modules/Clock.qml @@ -13,7 +13,7 @@ CustomRect { required property bool horizontal required property GridLayout loader required property Wrapper popouts - readonly property real shortSize: Config.bar.height + 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 diff --git a/Modules/HyprsunsetWidget.qml b/Modules/HyprsunsetWidget.qml index 19b89ba..34d1426 100644 --- a/Modules/HyprsunsetWidget.qml +++ b/Modules/HyprsunsetWidget.qml @@ -11,8 +11,8 @@ CustomRect { property bool tempEnabled: Hyprsunset.enabled color: root.tempEnabled ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height : width - implicitWidth: horizontal ? height : Config.bar.height + implicitHeight: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : width + implicitWidth: horizontal ? height : Math.max(Config.bar.height, Tokens.bar.innerSize) radius: Tokens.rounding.full StateLayer { @@ -27,7 +27,7 @@ CustomRect { animate: true color: root.tempEnabled ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface fill: root.tempEnabled ? 1 : 0 - font.pointSize: root.horizontal ? Tokens.font.size.larger : Tokens.font.size.large + font.pointSize: Tokens.font.size.larger text: root.tempEnabled ? "lightbulb" : "light_off" Behavior on fill { diff --git a/Modules/MediaWidget.qml b/Modules/MediaWidget.qml index 87d26e4..15e9679 100644 --- a/Modules/MediaWidget.qml +++ b/Modules/MediaWidget.qml @@ -14,11 +14,19 @@ CustomRect { readonly property int textWidth: Math.min(metrics.width, 200) color: Colors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height : layout.implicitHeight + Tokens.padding.normal * 2 - implicitWidth: horizontal ? layout.implicitWidth + Tokens.padding.normal * 2 : Config.bar.height + 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) radius: Tokens.rounding.full + Behavior on implicitHeight { + enabled: !root.horizontal + + Anim { + } + } Behavior on implicitWidth { + enabled: root.horizontal + Anim { } } @@ -33,7 +41,11 @@ CustomRect { GridLayout { id: layout - anchors.centerIn: parent + 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 Behavior on implicitWidth { @@ -53,15 +65,14 @@ CustomRect { id: mediatext Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter - Layout.preferredHeight: root.horizontal ? root.height : 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 - width: root.textWidth transform: [ Translate { diff --git a/Modules/NotifBell.qml b/Modules/NotifBell.qml index f1a1315..0567d89 100644 --- a/Modules/NotifBell.qml +++ b/Modules/NotifBell.qml @@ -13,8 +13,8 @@ CustomRect { required property PersistentProperties visibilities color: visibilities.sidebar ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height : width - implicitWidth: horizontal ? height : Config.bar.height + implicitHeight: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : width + implicitWidth: horizontal ? height : Math.max(Config.bar.height, Tokens.bar.innerSize) radius: Tokens.rounding.full MaterialIcon { @@ -23,7 +23,7 @@ CustomRect { anchors.centerIn: parent color: root.visibilities.sidebar ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface fill: root.visibilities.sidebar ? 1 : 0 - font.pointSize: root.horizontal ? Tokens.font.size.larger : Tokens.font.size.large + font.pointSize: Tokens.font.size.larger text: NotifServer.list.length ? "\uf4fe" : "\ue7f4" Behavior on color { diff --git a/Modules/Resource.qml b/Modules/Resource.qml index 9b15b8c..0608268 100644 --- a/Modules/Resource.qml +++ b/Modules/Resource.qml @@ -49,7 +49,7 @@ GridLayout { } CustomClippingRect { - Layout.preferredHeight: root.horizontal ? icon.implicitHeight : 4 + Layout.preferredHeight: root.horizontal ? icon.implicitHeight - Tokens.padding.small : 4 Layout.preferredWidth: root.horizontal ? 4 : icon.implicitWidth color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2) radius: Tokens.rounding.full @@ -63,7 +63,7 @@ GridLayout { anchors.top: root.horizontal ? undefined : parent.top color: root.mainColor implicitHeight: root.horizontal ? Math.ceil(root.percentage * parent.height) : 0 - implicitWidth: root.horizontal ? 0 : Math.ceil(root.percentage * parent.height) + implicitWidth: root.horizontal ? 0 : Math.ceil(root.percentage * parent.width) // Behavior on implicitHeight { // Anim { diff --git a/Modules/Resources.qml b/Modules/Resources.qml index 65f881a..123636e 100644 --- a/Modules/Resources.qml +++ b/Modules/Resources.qml @@ -17,8 +17,8 @@ CustomRect { clip: true color: visibilities.resources ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Math.max(Config.bar.height, 24) : gridLayout.implicitHeight + Tokens.padding.normal * 2 - implicitWidth: horizontal ? gridLayout.implicitWidth + Tokens.padding.larger * 2 : Config.bar.height + 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) radius: Tokens.rounding.full StateLayer { diff --git a/Modules/Settings/Pages/Panels/BarPanel.qml b/Modules/Settings/Pages/Panels/BarPanel.qml index 090c79c..31e613a 100644 --- a/Modules/Settings/Pages/Panels/BarPanel.qml +++ b/Modules/Settings/Pages/Panels/BarPanel.qml @@ -37,8 +37,8 @@ PageBase { active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2] last: true settingAnchor: "bar-position" - subtext: qsTr("Automatic or manual effect values") - text: qsTr("Effects mode") + subtext: qsTr("Change which edge the bar appears on") + text: qsTr("Position") menuItems: [ MenuItem { @@ -58,10 +58,7 @@ PageBase { } ] - onSelected: item => { - Config.bar.position = item.value; - Config.save(); - } + onSelected: item => Config.bar.position = item.value } // Components diff --git a/Modules/SysTray/StatusIcons.qml b/Modules/SysTray/StatusIcons.qml index ab41b6b..2fa363a 100644 --- a/Modules/SysTray/StatusIcons.qml +++ b/Modules/SysTray/StatusIcons.qml @@ -30,7 +30,7 @@ CustomClippingRect { return i; return -1; } - readonly property real shortSize: Config.bar.height + 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 diff --git a/Modules/SysTray/TrayIcons.qml b/Modules/SysTray/TrayIcons.qml index bb1ffaf..c9eb96f 100644 --- a/Modules/SysTray/TrayIcons.qml +++ b/Modules/SysTray/TrayIcons.qml @@ -17,7 +17,7 @@ CustomClippingRect { required property GridLayout loader readonly property int padding: Tokens.padding.small required property Wrapper popouts - readonly property real shortSize: Config.bar.height + 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 diff --git a/Modules/SysTray/Widgets/AudioWidget.qml b/Modules/SysTray/Widgets/AudioWidget.qml index 8e5f8f2..93c4752 100644 --- a/Modules/SysTray/Widgets/AudioWidget.qml +++ b/Modules/SysTray/Widgets/AudioWidget.qml @@ -13,7 +13,7 @@ MaterialIcon { animate: true color: Audio.muted ? Colors.palette.m3error : Colors.palette.m3onSurface fill: 1 - font.pointSize: horizontal ? Tokens.font.size.larger : Tokens.font.size.large + font.pointSize: Tokens.font.size.larger text: Audio.muted ? "volume_off" : "volume_up" Behavior on Layout.maximumWidth { diff --git a/Modules/SysTray/Widgets/MicWidget.qml b/Modules/SysTray/Widgets/MicWidget.qml index 59725b1..8f58616 100644 --- a/Modules/SysTray/Widgets/MicWidget.qml +++ b/Modules/SysTray/Widgets/MicWidget.qml @@ -13,7 +13,7 @@ MaterialIcon { animate: true color: (Audio.sourceMuted ?? false) ? Colors.palette.m3error : Colors.palette.m3onSurface fill: 1 - font.pointSize: horizontal ? Tokens.font.size.larger : Tokens.font.size.large + font.pointSize: Tokens.font.size.larger text: Audio.sourceMuted ? "mic_off" : "mic" Behavior on Layout.maximumWidth { diff --git a/Modules/SysTray/Widgets/UPowerWidget.qml b/Modules/SysTray/Widgets/UPowerWidget.qml index ca38488..380b912 100644 --- a/Modules/SysTray/Widgets/UPowerWidget.qml +++ b/Modules/SysTray/Widgets/UPowerWidget.qml @@ -125,7 +125,7 @@ Item { Layout.alignment: Qt.AlignVCenter animate: true fill: 1 - font.pointSize: root.horizontal ? Tokens.font.size.larger : Tokens.font.size.large + font.pointSize: Tokens.font.size.larger text: { if (PowerProfiles.profile === PowerProfile.PowerSaver) return "energy_savings_leaf"; diff --git a/Modules/Updates/UpdatesWidget.qml b/Modules/Updates/UpdatesWidget.qml index 385b755..3babcae 100644 --- a/Modules/Updates/UpdatesWidget.qml +++ b/Modules/Updates/UpdatesWidget.qml @@ -14,8 +14,8 @@ CustomRect { property color textColor: Colors.palette.m3onSurface color: Colors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? Config.bar.height : content.implicitHeight + Tokens.spacing.small * 2 - implicitWidth: horizontal ? content.implicitWidth + Tokens.spacing.small * 2 : Config.bar.height + 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 { @@ -24,6 +24,7 @@ CustomRect { 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 @@ -34,7 +35,7 @@ CustomRect { CustomText { Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter color: root.textColor - font.pointSize: root.horizontal ? Tokens.font.size.normal : Tokens.font.size.larger + font.pointSize: Tokens.font.size.normal text: root.countUpdates } } diff --git a/Modules/Workspaces.qml b/Modules/Workspaces.qml index 01ebeb5..fa7e297 100644 --- a/Modules/Workspaces.qml +++ b/Modules/Workspaces.qml @@ -17,7 +17,7 @@ Item { 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, 24) + 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 workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown diff --git a/Plugins/ZShell/Config/bar.hpp b/Plugins/ZShell/Config/bar.hpp index 9edd18c..4a0c8ae 100644 --- a/Plugins/ZShell/Config/bar.hpp +++ b/Plugins/ZShell/Config/bar.hpp @@ -3,6 +3,7 @@ #include "configlist.hpp" #include "configobject.hpp" #include +#include #include namespace ZShell::config { @@ -62,7 +63,7 @@ class Bar : public ConfigObject { CFG_PROPERTY(int, revealDelay, 100) CFG_PROPERTY(int, rounding, 14) CFG_PROPERTY(int, smoothing, 32) - CFG_PROPERTY(QString, position, "top") + CFG_PROPERTY(QString, position, QStringLiteral("top")) CONFIG_SUBOBJECT(Tray, tray) CONFIG_LIST( EntryList, diff --git a/Plugins/ZShell/Config/config.cpp b/Plugins/ZShell/Config/config.cpp index c0fcc9d..ea2c307 100644 --- a/Plugins/ZShell/Config/config.cpp +++ b/Plugins/ZShell/Config/config.cpp @@ -61,6 +61,8 @@ Config::Config(QObject* parent) m_reloadTimer.setInterval(50); connect(&m_reloadTimer, &QTimer::timeout, this, &Config::reloadAsync); + connectAutoSave(this); + connect( &m_watcher, &QFileSystemWatcher::directoryChanged, @@ -232,6 +234,15 @@ 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()); diff --git a/Plugins/ZShell/Config/config.hpp b/Plugins/ZShell/Config/config.hpp index 1a201f3..e1881c5 100644 --- a/Plugins/ZShell/Config/config.hpp +++ b/Plugins/ZShell/Config/config.hpp @@ -90,6 +90,7 @@ class Config : public ConfigObject { void updateWatch(); void loadSync(); void loadAsync(); + void connectAutoSave(ConfigNode* node); QTimer m_saveTimer; QTimer m_reloadTimer; diff --git a/Plugins/ZShell/Config/tokens.hpp b/Plugins/ZShell/Config/tokens.hpp index 79056c1..7c83e47 100644 --- a/Plugins/ZShell/Config/tokens.hpp +++ b/Plugins/ZShell/Config/tokens.hpp @@ -3,7 +3,9 @@ #include "configobject.hpp" #include +#include #include +#include #include namespace ZShell::config { @@ -195,6 +197,16 @@ 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 @@ -205,6 +217,7 @@ 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) @@ -213,7 +226,8 @@ 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_anim(new AnimTokens(this)) + , m_bar(new BarTokens(this)) {} static Tokens* create(QQmlEngine*, QJSEngine*) { return new Tokens(); } }; -- 2.47.3 From 9823c6629900a8a3513a98b18aef7695248381c6 Mon Sep 17 00:00:00 2001 From: zach Date: Sat, 15 Aug 2026 14:18:00 +0200 Subject: [PATCH 5/7] restructure bar components layout --- Drawers/Drawers.qml | 4 - Drawers/Interactions.qml | 4 +- Drawers/Panels.qml | 4 +- Helpers/Icons.qml | 53 +++++- Modules/Bar/Bar.qml | 6 +- Modules/Bar/BarLoader.qml | 6 +- Modules/{ => Bar/Components}/Clock.qml | 2 +- .../{ => Bar/Components}/HyprsunsetWidget.qml | 0 Modules/{ => Bar/Components}/MediaWidget.qml | 0 .../Components}/NetworkWidget.qml | 0 Modules/{ => Bar/Components}/NotifBell.qml | 1 + Modules/{ => Bar/Components}/Resource.qml | 0 Modules/{ => Bar/Components}/Resources.qml | 0 .../Components}/StatusIcons.qml | 4 +- .../Components/StatusIcons}/AudioWidget.qml | 0 .../Components/StatusIcons}/MicWidget.qml | 0 .../Components/StatusIcons}/UPowerWidget.qml | 0 .../Components/Tray}/TrayItem.qml | 3 +- .../{SysTray => Bar/Components}/TrayIcons.qml | 3 +- .../Components}/UpdatesWidget.qml | 0 Modules/{ => Bar/Components}/WindowTitle.qml | 4 +- Modules/{ => Bar/Components}/Workspaces.qml | 4 +- .../Workspaces}/AnimatedTabIndexPair.qml | 0 .../{SysTray => Bar}/Popouts/AudioPopout.qml | 0 Modules/{ => Bar/Popouts}/ClipWrapper.qml | 0 Modules/{ => Bar/Popouts}/Content.qml | 4 - .../Popouts}/NetworkPopout.qml | 0 Modules/{ => Bar/Popouts}/PopoutState.qml | 0 .../Popouts/TrayMenuPopout.qml | 0 .../{SysTray => Bar}/Popouts/UPowerPopout.qml | 0 .../Popouts}/UpdatesPopout.qml | 0 Modules/{ => Bar/Popouts}/Wrapper.qml | 0 Modules/SysTray/TrayWidget.qml | 159 ------------------ Modules/WSOverview/OverviewPopout.qml | 86 ---------- 34 files changed, 69 insertions(+), 278 deletions(-) rename Modules/{ => Bar/Components}/Clock.qml (98%) rename Modules/{ => Bar/Components}/HyprsunsetWidget.qml (100%) rename Modules/{ => Bar/Components}/MediaWidget.qml (100%) rename Modules/{Network => Bar/Components}/NetworkWidget.qml (100%) rename Modules/{ => Bar/Components}/NotifBell.qml (97%) rename Modules/{ => Bar/Components}/Resource.qml (100%) rename Modules/{ => Bar/Components}/Resources.qml (100%) rename Modules/{SysTray => Bar/Components}/StatusIcons.qml (98%) rename Modules/{SysTray/Widgets => Bar/Components/StatusIcons}/AudioWidget.qml (100%) rename Modules/{SysTray/Widgets => Bar/Components/StatusIcons}/MicWidget.qml (100%) rename Modules/{SysTray/Widgets => Bar/Components/StatusIcons}/UPowerWidget.qml (100%) rename Modules/{SysTray => Bar/Components/Tray}/TrayItem.qml (98%) rename Modules/{SysTray => Bar/Components}/TrayIcons.qml (95%) rename Modules/{Updates => Bar/Components}/UpdatesWidget.qml (100%) rename Modules/{ => Bar/Components}/WindowTitle.qml (94%) rename Modules/{ => Bar/Components}/Workspaces.qml (98%) rename {Components => Modules/Bar/Components/Workspaces}/AnimatedTabIndexPair.qml (100%) rename Modules/{SysTray => Bar}/Popouts/AudioPopout.qml (100%) rename Modules/{ => Bar/Popouts}/ClipWrapper.qml (100%) rename Modules/{ => Bar/Popouts}/Content.qml (95%) rename Modules/{Network => Bar/Popouts}/NetworkPopout.qml (100%) rename Modules/{ => Bar/Popouts}/PopoutState.qml (100%) rename Modules/{SysTray => Bar}/Popouts/TrayMenuPopout.qml (100%) rename Modules/{SysTray => Bar}/Popouts/UPowerPopout.qml (100%) rename Modules/{Updates => Bar/Popouts}/UpdatesPopout.qml (100%) rename Modules/{ => Bar/Popouts}/Wrapper.qml (100%) delete mode 100644 Modules/SysTray/TrayWidget.qml delete mode 100644 Modules/WSOverview/OverviewPopout.qml diff --git a/Drawers/Drawers.qml b/Drawers/Drawers.qml index 490bc0e..7a38a43 100644 --- a/Drawers/Drawers.qml +++ b/Drawers/Drawers.qml @@ -27,10 +27,6 @@ Variants { } Connections { - function onConfigDashboardPositionChanged(): void { - Qt.callLater(scope.rebuild); - } - function onConfigPositionChanged(): void { Qt.callLater(scope.rebuild); } diff --git a/Drawers/Interactions.qml b/Drawers/Interactions.qml index 581201e..12d02ba 100644 --- a/Drawers/Interactions.qml +++ b/Drawers/Interactions.qml @@ -3,7 +3,7 @@ import QtQuick import qs.Components import ZShell.Config import qs.Helpers -import qs.Modules as BarPopouts +import qs.Modules.Bar.Popouts Item { id: root @@ -15,7 +15,7 @@ Item { required property EdgeGeometry geometry property bool osdShortcutActive required property Panels panels - required property BarPopouts.Wrapper popouts + required property Wrapper popouts required property ShellScreen screen property bool singleGestureTriggered: false property bool utilitiesShortcutActive diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index b24a048..630582e 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -1,7 +1,7 @@ import Quickshell import QtQuick import qs.Components -import qs.Modules as Modules +import qs.Modules.Bar.Popouts as Popouts import qs.Modules.Notifications as Notifications import qs.Modules.Notifications.Sidebar as Sidebar import qs.Modules.Notifications.Sidebar.Utils as Utils @@ -100,7 +100,7 @@ Item { visibilities: root.visibilities } - Modules.ClipWrapper { + Popouts.ClipWrapper { id: popouts borderThickness: root.borderThickness diff --git a/Helpers/Icons.qml b/Helpers/Icons.qml index 2599449..03be431 100644 --- a/Helpers/Icons.qml +++ b/Helpers/Icons.qml @@ -1,9 +1,8 @@ pragma Singleton -import ZShell.Config +import QtQuick import Quickshell import Quickshell.Services.Notifications -import QtQuick Singleton { id: root @@ -95,6 +94,15 @@ 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"; @@ -168,6 +176,32 @@ 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"; @@ -183,4 +217,19 @@ 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; + } } diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 3ff2e1b..d396f8f 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -3,11 +3,9 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts -import qs.Modules import ZShell.Config -import qs.Modules.SysTray -import qs.Modules.Network -import qs.Modules.Updates +import qs.Modules.Bar.Components +import qs.Modules.Bar.Popouts GridLayout { id: root diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index ff7f0a2..6429b13 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -3,12 +3,8 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import ZShell.Config +import qs.Modules.Bar.Popouts import qs.Components -import qs.Modules -import qs.Helpers -import qs.Modules.SysTray -import qs.Modules.SysTray.Widgets -import qs.Modules.Network Item { id: root diff --git a/Modules/Clock.qml b/Modules/Bar/Components/Clock.qml similarity index 98% rename from Modules/Clock.qml rename to Modules/Bar/Components/Clock.qml index 0626ed9..3c86067 100644 --- a/Modules/Clock.qml +++ b/Modules/Bar/Components/Clock.qml @@ -2,7 +2,7 @@ import Quickshell import QtQuick import QtQuick.Layouts import ZShell.Config -import qs.Modules +import qs.Modules.Bar.Popouts import qs.Helpers import qs.Components import qs.Services diff --git a/Modules/HyprsunsetWidget.qml b/Modules/Bar/Components/HyprsunsetWidget.qml similarity index 100% rename from Modules/HyprsunsetWidget.qml rename to Modules/Bar/Components/HyprsunsetWidget.qml diff --git a/Modules/MediaWidget.qml b/Modules/Bar/Components/MediaWidget.qml similarity index 100% rename from Modules/MediaWidget.qml rename to Modules/Bar/Components/MediaWidget.qml diff --git a/Modules/Network/NetworkWidget.qml b/Modules/Bar/Components/NetworkWidget.qml similarity index 100% rename from Modules/Network/NetworkWidget.qml rename to Modules/Bar/Components/NetworkWidget.qml diff --git a/Modules/NotifBell.qml b/Modules/Bar/Components/NotifBell.qml similarity index 97% rename from Modules/NotifBell.qml rename to Modules/Bar/Components/NotifBell.qml index 0567d89..c1db86f 100644 --- a/Modules/NotifBell.qml +++ b/Modules/Bar/Components/NotifBell.qml @@ -1,6 +1,7 @@ import Quickshell import QtQuick import ZShell.Config +import qs.Modules.Bar.Popouts import qs.Daemons import qs.Components import qs.Services diff --git a/Modules/Resource.qml b/Modules/Bar/Components/Resource.qml similarity index 100% rename from Modules/Resource.qml rename to Modules/Bar/Components/Resource.qml diff --git a/Modules/Resources.qml b/Modules/Bar/Components/Resources.qml similarity index 100% rename from Modules/Resources.qml rename to Modules/Bar/Components/Resources.qml diff --git a/Modules/SysTray/StatusIcons.qml b/Modules/Bar/Components/StatusIcons.qml similarity index 98% rename from Modules/SysTray/StatusIcons.qml rename to Modules/Bar/Components/StatusIcons.qml index 2fa363a..e0d6655 100644 --- a/Modules/SysTray/StatusIcons.qml +++ b/Modules/Bar/Components/StatusIcons.qml @@ -3,9 +3,9 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts -import qs.Helpers -import qs.Modules.SysTray.Widgets import ZShell.Config +import qs.Helpers +import qs.Modules.Bar.Components.StatusIcons import qs.Components import qs.Services diff --git a/Modules/SysTray/Widgets/AudioWidget.qml b/Modules/Bar/Components/StatusIcons/AudioWidget.qml similarity index 100% rename from Modules/SysTray/Widgets/AudioWidget.qml rename to Modules/Bar/Components/StatusIcons/AudioWidget.qml diff --git a/Modules/SysTray/Widgets/MicWidget.qml b/Modules/Bar/Components/StatusIcons/MicWidget.qml similarity index 100% rename from Modules/SysTray/Widgets/MicWidget.qml rename to Modules/Bar/Components/StatusIcons/MicWidget.qml diff --git a/Modules/SysTray/Widgets/UPowerWidget.qml b/Modules/Bar/Components/StatusIcons/UPowerWidget.qml similarity index 100% rename from Modules/SysTray/Widgets/UPowerWidget.qml rename to Modules/Bar/Components/StatusIcons/UPowerWidget.qml diff --git a/Modules/SysTray/TrayItem.qml b/Modules/Bar/Components/Tray/TrayItem.qml similarity index 98% rename from Modules/SysTray/TrayItem.qml rename to Modules/Bar/Components/Tray/TrayItem.qml index ce054aa..d7b8fc1 100644 --- a/Modules/SysTray/TrayItem.qml +++ b/Modules/Bar/Components/Tray/TrayItem.qml @@ -1,10 +1,9 @@ import QtQuick.Layouts import QtQuick -import QtQuick.VectorImage import Quickshell import Quickshell.Services.SystemTray import qs.Helpers -import qs.Modules +import qs.Modules.Bar.Popouts import qs.Components import ZShell.Config import qs.Services diff --git a/Modules/SysTray/TrayIcons.qml b/Modules/Bar/Components/TrayIcons.qml similarity index 95% rename from Modules/SysTray/TrayIcons.qml rename to Modules/Bar/Components/TrayIcons.qml index c9eb96f..a7175b4 100644 --- a/Modules/SysTray/TrayIcons.qml +++ b/Modules/Bar/Components/TrayIcons.qml @@ -5,7 +5,8 @@ import QtQuick.Layouts import Quickshell.Services.SystemTray import qs.Components import ZShell.Config -import qs.Modules +import qs.Modules.Bar.Components.Tray +import qs.Modules.Bar.Popouts import qs.Services CustomClippingRect { diff --git a/Modules/Updates/UpdatesWidget.qml b/Modules/Bar/Components/UpdatesWidget.qml similarity index 100% rename from Modules/Updates/UpdatesWidget.qml rename to Modules/Bar/Components/UpdatesWidget.qml diff --git a/Modules/WindowTitle.qml b/Modules/Bar/Components/WindowTitle.qml similarity index 94% rename from Modules/WindowTitle.qml rename to Modules/Bar/Components/WindowTitle.qml index 72d145f..a9c7a4e 100644 --- a/Modules/WindowTitle.qml +++ b/Modules/Bar/Components/WindowTitle.qml @@ -21,9 +21,9 @@ Item { } anchors.centerIn: parent - clip: true + clip: false implicitHeight: horizontal ? current.implicitHeight : current.implicitWidth + current.anchors.topMargin - implicitWidth: horizontal ? Math.min(current.implicitWidth, root.maxSize) : current.implicitHeight + current.anchors.topMargin + implicitWidth: horizontal ? current.implicitWidth + current.anchors.leftMargin : current.implicitHeight + current.anchors.topMargin Behavior on implicitHeight { enabled: !root.horizontal diff --git a/Modules/Workspaces.qml b/Modules/Bar/Components/Workspaces.qml similarity index 98% rename from Modules/Workspaces.qml rename to Modules/Bar/Components/Workspaces.qml index fa7e297..091ff2f 100644 --- a/Modules/Workspaces.qml +++ b/Modules/Bar/Components/Workspaces.qml @@ -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 @@ -90,7 +90,7 @@ Item { color: Colors.palette.m3onSecondaryContainer elide: Text.ElideRight horizontalAlignment: Text.AlignHCenter - text: button.modelData.name + text: button.modelData?.name ?? "" verticalAlignment: Text.AlignVCenter } } diff --git a/Components/AnimatedTabIndexPair.qml b/Modules/Bar/Components/Workspaces/AnimatedTabIndexPair.qml similarity index 100% rename from Components/AnimatedTabIndexPair.qml rename to Modules/Bar/Components/Workspaces/AnimatedTabIndexPair.qml diff --git a/Modules/SysTray/Popouts/AudioPopout.qml b/Modules/Bar/Popouts/AudioPopout.qml similarity index 100% rename from Modules/SysTray/Popouts/AudioPopout.qml rename to Modules/Bar/Popouts/AudioPopout.qml diff --git a/Modules/ClipWrapper.qml b/Modules/Bar/Popouts/ClipWrapper.qml similarity index 100% rename from Modules/ClipWrapper.qml rename to Modules/Bar/Popouts/ClipWrapper.qml diff --git a/Modules/Content.qml b/Modules/Bar/Popouts/Content.qml similarity index 95% rename from Modules/Content.qml rename to Modules/Bar/Popouts/Content.qml index a2ec2d1..555b9d9 100644 --- a/Modules/Content.qml +++ b/Modules/Bar/Popouts/Content.qml @@ -5,10 +5,6 @@ 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 diff --git a/Modules/Network/NetworkPopout.qml b/Modules/Bar/Popouts/NetworkPopout.qml similarity index 100% rename from Modules/Network/NetworkPopout.qml rename to Modules/Bar/Popouts/NetworkPopout.qml diff --git a/Modules/PopoutState.qml b/Modules/Bar/Popouts/PopoutState.qml similarity index 100% rename from Modules/PopoutState.qml rename to Modules/Bar/Popouts/PopoutState.qml diff --git a/Modules/SysTray/Popouts/TrayMenuPopout.qml b/Modules/Bar/Popouts/TrayMenuPopout.qml similarity index 100% rename from Modules/SysTray/Popouts/TrayMenuPopout.qml rename to Modules/Bar/Popouts/TrayMenuPopout.qml diff --git a/Modules/SysTray/Popouts/UPowerPopout.qml b/Modules/Bar/Popouts/UPowerPopout.qml similarity index 100% rename from Modules/SysTray/Popouts/UPowerPopout.qml rename to Modules/Bar/Popouts/UPowerPopout.qml diff --git a/Modules/Updates/UpdatesPopout.qml b/Modules/Bar/Popouts/UpdatesPopout.qml similarity index 100% rename from Modules/Updates/UpdatesPopout.qml rename to Modules/Bar/Popouts/UpdatesPopout.qml diff --git a/Modules/Wrapper.qml b/Modules/Bar/Popouts/Wrapper.qml similarity index 100% rename from Modules/Wrapper.qml rename to Modules/Bar/Popouts/Wrapper.qml diff --git a/Modules/SysTray/TrayWidget.qml b/Modules/SysTray/TrayWidget.qml deleted file mode 100644 index cd9b8d3..0000000 --- a/Modules/SysTray/TrayWidget.qml +++ /dev/null @@ -1,159 +0,0 @@ -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 - -GridLayout { - id: root - - required property bool horizontal - readonly property alias items: repeater - required property GridLayout loader - required property Wrapper popouts - readonly property real shortSize: Config.bar.height + Tokens.padding.smallest * 2 - readonly property real size: horizontal ? sysTray.implicitWidth + sysTrayMod.implicitWidth + Tokens.padding.small : sysTray.implicitHeight + sysTrayMod.implicitHeight + Tokens.padding.small - - 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; - } - - columnSpacing: Tokens.padding.small - columns: horizontal ? -1 : 1 - height: horizontal ? shortSize : size - rowSpacing: Tokens.padding.small - width: horizontal ? size : shortSize - - 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 - - GridLayout { - id: sysRow - - anchors.bottom: root.horizontal ? undefined : parent.bottom - anchors.centerIn: parent - anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined - anchors.left: root.horizontal ? undefined : parent.left - anchors.right: root.horizontal ? undefined : parent.right - anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined - columnSpacing: Tokens.spacing.small / 2 - columns: root.horizontal ? -1 : 1 - rowSpacing: Tokens.spacing.small / 2 - - 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: root.horizontal - Layout.fillWidth: !root.horizontal - bottomLeftRadius: Tokens.rounding.smallest / 2 - color: Colors.tPalette.m3surfaceContainer - implicitHeight: root.horizontal ? sysIcons.implicitHeight : sysIcons.implicitHeight + Tokens.padding.smaller + Tokens.padding.normal - implicitWidth: root.horizontal ? sysIcons.implicitWidth + Tokens.padding.smaller + Tokens.padding.normal : sysIcons.implicitWidth - 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 - horizontal: root.horizontal - } - } -} diff --git a/Modules/WSOverview/OverviewPopout.qml b/Modules/WSOverview/OverviewPopout.qml deleted file mode 100644 index 9f42165..0000000 --- a/Modules/WSOverview/OverviewPopout.qml +++ /dev/null @@ -1,86 +0,0 @@ -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 - } - } - } - } - } - } - } -} -- 2.47.3 From 5efa0de3a517c3999669cfc00aed97def663cca2 Mon Sep 17 00:00:00 2001 From: zach Date: Sat, 15 Aug 2026 19:37:44 +0200 Subject: [PATCH 6/7] WidgetBase for bar widget + fixed resources and dashboard popouts in left- and bottom-edge bar --- Components/MarqueeText.qml | 276 ++++++++++--------- Drawers/Panels.qml | 9 +- Drawers/Windows.qml | 2 +- Modules/Bar/BarLoader.qml | 2 +- Modules/Bar/Components/Clock.qml | 138 ++++++++-- Modules/Bar/Components/Common/WidgetBase.qml | 16 ++ Modules/Bar/Components/HyprsunsetWidget.qml | 6 +- Modules/Bar/Components/MediaWidget.qml | 50 ++-- Modules/Bar/Components/NotifBell.qml | 6 +- Modules/Bar/Components/Resources.qml | 9 +- Modules/Bar/Components/StatusIcons.qml | 9 +- Modules/Bar/Components/TrayIcons.qml | 11 +- Modules/Bar/Components/UpdatesWidget.qml | 13 +- Modules/Bar/Components/WindowTitle.qml | 8 +- Modules/Dashboard/Wrapper.qml | 21 +- Modules/Resources/Wrapper.qml | 16 +- 16 files changed, 357 insertions(+), 235 deletions(-) create mode 100644 Modules/Bar/Components/Common/WidgetBase.qml diff --git a/Components/MarqueeText.qml b/Components/MarqueeText.qml index b17c1c6..7d3d12d 100644 --- a/Components/MarqueeText.qml +++ b/Components/MarqueeText.qml @@ -18,13 +18,14 @@ Item { property real leftFadeStrength: overflowing && leftFadeEnabled ? fadeStrengthMoving : fadeStrengthIdle property int leftFadeWidth: 28 property bool marqueeEnabled: true - readonly property bool overflowing: metrics.width > root.width + readonly property bool overflowing: metrics.width > content.width property int pauseMs: 1200 property real pixelsPerSecond: 40 property real rightFadeStrength: overflowing ? fadeStrengthMoving : fadeStrengthIdle property int rightFadeWidth: 28 property bool sliding: false property alias text: elideText.text + property bool vertical: false function durationForDistance(px): int { return Math.max(1, Math.round(Math.abs(px) / root.pixelsPerSecond * 1000)); @@ -42,7 +43,8 @@ Item { } clip: false - implicitHeight: elideText.implicitHeight + implicitHeight: vertical ? elideText.implicitWidth : elideText.implicitHeight + implicitWidth: vertical ? elideText.implicitHeight : elideText.implicitWidth Behavior on leftFadeStrength { Anim { @@ -53,171 +55,187 @@ Item { } } + onHeightChanged: resetMarquee() onTextChanged: resetMarquee() + onVerticalChanged: resetMarquee() onVisibleChanged: if (!visible) resetMarquee() onWidthChanged: resetMarquee() - TextMetrics { - id: metrics - - font: elideText.font - text: elideText.text - } - - CustomText { - id: elideText - - anchors.verticalCenter: parent.verticalCenter - animate: root.animate - animateProp: "scale,opacity" - color: root.color - elide: Text.ElideNone - visible: !root.overflowing - width: root.width - } - Item { - id: marqueeViewport + id: content - anchors.fill: parent - clip: false - layer.enabled: true - visible: root.overflowing + anchors.centerIn: parent + height: root.vertical ? root.width : root.height + width: root.vertical ? root.height : root.width - layer.effect: OpacityMask { - maskSource: rightFadeMask + transform: Rotation { + angle: root.vertical ? -90 : 0 + origin.x: content.width / 2 + origin.y: content.height / 2 + } + + TextMetrics { + id: metrics + + font: elideText.font + text: elideText.text + } + + CustomText { + id: elideText + + anchors.verticalCenter: parent.verticalCenter + animate: root.animate + animateProp: "scale,opacity" + color: root.color + elide: Text.ElideNone + visible: !root.overflowing + width: content.width } Item { - id: strip + id: marqueeViewport - anchors.verticalCenter: parent.verticalCenter - height: t1.implicitHeight - width: t1.width + root.gap + t2.width - x: 0 + anchors.fill: parent + clip: false + layer.enabled: true + visible: root.overflowing - CustomText { - id: t1 - - animate: root.animate - animateProp: "opacity" - color: root.color - font.pointSize: elideText.font.pointSize - text: elideText.text + layer.effect: OpacityMask { + maskSource: rightFadeMask } - CustomText { - id: t2 + Item { + id: strip - animate: root.animate - animateProp: "opacity" - color: root.color - font.pointSize: elideText.font.pointSize - text: t1.text - x: t1.width + root.gap - } - } + anchors.verticalCenter: parent.verticalCenter + height: t1.implicitHeight + width: t1.width + root.gap + t2.width + x: 0 - SequentialAnimation { - id: marqueeAnim + CustomText { + id: t1 - running: false + animate: root.animate + animateProp: "opacity" + color: root.color + font.pointSize: elideText.font.pointSize + text: elideText.text + } - onFinished: pauseTimer.restart() + CustomText { + id: t2 - ScriptAction { - script: { - root.sliding = true; - root.leftFadeEnabled = true; + animate: root.animate + animateProp: "opacity" + color: root.color + font.pointSize: elideText.font.pointSize + text: t1.text + x: t1.width + root.gap } } - Anim { - duration: root.durationForDistance(t1.width) - easing.bezierCurve: Easing.Linear - easing.type: Easing.Linear - from: 0 - property: "x" - target: strip - to: -t1.width - } + SequentialAnimation { + id: marqueeAnim - ScriptAction { - script: { - root.leftFadeEnabled = false; + running: false + + onFinished: pauseTimer.restart() + + ScriptAction { + script: { + root.sliding = true; + root.leftFadeEnabled = true; + } + } + + Anim { + duration: root.durationForDistance(t1.width) + easing.bezierCurve: Easing.Linear + easing.type: Easing.Linear + from: 0 + property: "x" + target: strip + to: -t1.width + } + + ScriptAction { + script: { + root.leftFadeEnabled = false; + } + } + + Anim { + duration: root.durationForDistance(root.gap) + easing.bezierCurve: Easing.Linear + easing.type: Easing.Linear + from: -t1.width + property: "x" + target: strip + to: -(t1.width + root.gap) + } + + ScriptAction { + script: { + root.sliding = false; + strip.x = 0; + } } } - Anim { - duration: root.durationForDistance(root.gap) - easing.bezierCurve: Easing.Linear - easing.type: Easing.Linear - from: -t1.width - property: "x" - target: strip - to: -(t1.width + root.gap) - } + Timer { + id: pauseTimer - ScriptAction { - script: { - root.sliding = false; - strip.x = 0; + interval: root.pauseMs + repeat: false + running: true + + onTriggered: { + if (root.marqueeEnabled) + marqueeAnim.start(); } } } - Timer { - id: pauseTimer + Rectangle { + id: rightFadeMask - interval: root.pauseMs - repeat: false - running: true - - onTriggered: { - if (root.marqueeEnabled) - marqueeAnim.start(); + readonly property real fadeStartPos: { + const w = Math.max(1, width); + return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w)); } - } - } - - Rectangle { - id: rightFadeMask - - readonly property real fadeStartPos: { - const w = Math.max(1, width); - return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w)); - } - readonly property real leftFadeEndPos: { - const w = Math.max(1, width); - return Math.max(0, Math.min(1, root.leftFadeWidth / w)); - } - - anchors.fill: marqueeViewport - layer.enabled: true - visible: false - - gradient: Gradient { - orientation: Gradient.Horizontal - - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength) - position: 0.0 + readonly property real leftFadeEndPos: { + const w = Math.max(1, width); + return Math.max(0, Math.min(1, root.leftFadeWidth / w)); } - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0) - position: rightFadeMask.leftFadeEndPos - } + anchors.fill: marqueeViewport + layer.enabled: true + visible: false - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0) - position: rightFadeMask.fadeStartPos - } + gradient: Gradient { + orientation: Gradient.Horizontal - GradientStop { - color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength) - position: 1.0 + GradientStop { + color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength) + position: 0.0 + } + + GradientStop { + color: Qt.rgba(1, 1, 1, 1.0) + position: rightFadeMask.leftFadeEndPos + } + + GradientStop { + color: Qt.rgba(1, 1, 1, 1.0) + position: rightFadeMask.fadeStartPos + } + + GradientStop { + color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength) + position: 1.0 + } } } } diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index 630582e..66827ad 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -53,8 +53,9 @@ Item { Item { id: resourcesWrapper + anchors.bottom: root.geometry.position === "bottom" ? parent.bottom : undefined anchors.left: parent.left - anchors.top: parent.top + anchors.top: root.geometry.position !== "bottom" ? parent.top : undefined clip: true implicitHeight: root.geometry.horizontal ? resources.implicitHeight * (1 - resources.offsetScale) : resources.implicitHeight implicitWidth: root.geometry.horizontal ? resources.implicitWidth : resources.implicitWidth * (1 - resources.offsetScale) @@ -62,9 +63,7 @@ Item { Resources.Wrapper { id: resources - anchors.left: parent.left - anchors.top: parent.top - horizontal: root.geometry.horizontal + position: root.geometry.position visibilities: root.visibilities } } @@ -169,8 +168,8 @@ Item { Dashboard.Wrapper { id: dashboard - horizontal: root.geometry.horizontal offsetScale: dashboardWrapper.offsetScale + position: root.geometry.position visibilities: root.visibilities } } diff --git a/Drawers/Windows.qml b/Drawers/Windows.qml index 4eab93f..dc118cc 100644 --- a/Drawers/Windows.qml +++ b/Drawers/Windows.qml @@ -221,7 +221,7 @@ CustomWindow { 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) + y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - (geometry.horizontal && geometry.position !== "bottom" ? panels.dashboard.height * extraExtent : 0) } PanelBg { diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index 6429b13..2243ad7 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -10,7 +10,7 @@ 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 contentThickness: Math.floor(Math.max(Config.bar.height, Tokens.bar.innerSize * (horizontal ? 1 : 1.5))) + padding * 2 readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness property real extent: fullscreen ? 0 : Config.bar.border required property bool fullscreen diff --git a/Modules/Bar/Components/Clock.qml b/Modules/Bar/Components/Clock.qml index 3c86067..0125670 100644 --- a/Modules/Bar/Components/Clock.qml +++ b/Modules/Bar/Components/Clock.qml @@ -1,58 +1,154 @@ +pragma ComponentBehavior: Bound + import Quickshell import QtQuick import QtQuick.Layouts import ZShell.Config import qs.Modules.Bar.Popouts +import qs.Modules.Bar.Components.Common import qs.Helpers import qs.Components import qs.Services -CustomRect { +WidgetBase { id: root - required property bool horizontal + readonly property color contentColor: visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface + readonly property string effectiveFormat: { + let fmt = Config.general.dateFormat; + if (!root.horizontal) + fmt = fmt.replace("dddd", "ddd"); + return fmt; + } + readonly property var formatParts: { + const segments = root.effectiveFormat.split(" - "); + let datePart = ""; + let timePart = ""; + + if (segments.length > 1) { + datePart = segments[0]; + timePart = segments[1]; + } else if (/[hms]/.test(segments[0])) { + timePart = segments[0]; + } else { + datePart = segments[0]; + } + + const dateTokens = datePart.trim().length ? datePart.trim().split(/\s+/) : []; + const timeTokens = timePart.trim().length ? timePart.trim().split(":") : []; + + return { + dateTokens: dateTokens, + timeTokens: timeTokens + }; + } 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 + readonly property real size: horizontal ? timeText.contentWidth + Tokens.padding.normal * 2 : verticalColumn.implicitHeight + 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 + implicitHeight: horizontal ? baseSize : size + implicitWidth: horizontal ? size : baseSize 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 + color: root.contentColor font: Config.appearance.font.family.mono // qmllint disable incompatible-type - height: root.horizontal ? implicitHeight : implicitWidth + height: implicitHeight text: Time.dateStr - width: root.horizontal ? implicitWidth : implicitHeight + visible: root.horizontal 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 + } + + ColumnLayout { + id: verticalColumn + + anchors.centerIn: parent + spacing: Tokens.padding.small ?? 2 + visible: !root.horizontal + width: root.baseSize + + Repeater { + model: root.formatParts.dateTokens + + CustomText { + required property string modelData + + Layout.alignment: Qt.AlignHCenter + color: root.contentColor + font: Config.appearance.font.family.mono // qmllint disable incompatible-type + text: Qt.formatDateTime(Time.date, modelData) + + Behavior on color { + CAnim { + } + } } - ] + } + + Rectangle { + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: Tokens.padding.small ?? 2 + Layout.topMargin: Tokens.padding.small ?? 2 + color: root.contentColor + height: 1 + implicitWidth: root.baseSize * 0.5 + opacity: 0.4 + radius: 1 + visible: root.formatParts.dateTokens.length > 0 && root.formatParts.timeTokens.length > 0 + } + + Repeater { + model: root.formatParts.timeTokens + + CustomText { + required property string modelData + + Layout.alignment: Qt.AlignHCenter + color: root.contentColor + font: Config.appearance.font.family.mono // qmllint disable incompatible-type + text: { + if (modelData.includes("h")) + return Time.hourStr; + if (modelData.includes("m")) + return Time.minuteStr; + if (modelData.includes("s")) + return Time.secondStr; + return ""; + } + + Behavior on color { + CAnim { + } + } + } + } + + CustomText { + Layout.alignment: Qt.AlignHCenter + color: root.contentColor + font: Config.appearance.font.family.mono // qmllint disable incompatible-type + text: Qt.formatDateTime(Time.date, "AP") + visible: Config.services.useTwelveHourClock && root.formatParts.timeTokens.length > 0 + + Behavior on color { + CAnim { + } + } + } } StateLayer { acceptedButtons: Qt.LeftButton - color: root.visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface + color: root.contentColor onClicked: { root.visibilities.dashboard = !root.visibilities.dashboard; diff --git a/Modules/Bar/Components/Common/WidgetBase.qml b/Modules/Bar/Components/Common/WidgetBase.qml new file mode 100644 index 0000000..2a0fb95 --- /dev/null +++ b/Modules/Bar/Components/Common/WidgetBase.qml @@ -0,0 +1,16 @@ +import QtQuick +import ZShell.Config +import qs.Components +import qs.Services + +CustomRect { + id: root + + readonly property int baseSize: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : Math.max(Config.bar.height, Math.floor(Tokens.bar.innerSize * 1.5)) + required property bool horizontal + + color: Colors.tPalette.m3surfaceContainer + implicitHeight: horizontal ? baseSize : width + implicitWidth: horizontal ? height : baseSize + radius: Tokens.rounding.full +} diff --git a/Modules/Bar/Components/HyprsunsetWidget.qml b/Modules/Bar/Components/HyprsunsetWidget.qml index 34d1426..8afd545 100644 --- a/Modules/Bar/Components/HyprsunsetWidget.qml +++ b/Modules/Bar/Components/HyprsunsetWidget.qml @@ -1,18 +1,16 @@ import QtQuick import ZShell.Config import qs.Components +import qs.Modules.Bar.Components.Common import qs.Helpers import qs.Services -CustomRect { +WidgetBase { 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) radius: Tokens.rounding.full StateLayer { diff --git a/Modules/Bar/Components/MediaWidget.qml b/Modules/Bar/Components/MediaWidget.qml index 15e9679..99e4e1e 100644 --- a/Modules/Bar/Components/MediaWidget.qml +++ b/Modules/Bar/Components/MediaWidget.qml @@ -1,21 +1,19 @@ import QtQuick import QtQuick.Layouts -import qs.Components -import qs.Daemons import ZShell.Config +import qs.Components +import qs.Modules.Bar.Components.Common import qs.Helpers import qs.Services -CustomRect { +WidgetBase { 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: horizontal ? baseSize : layout.implicitHeight + Tokens.padding.normal * 2 + implicitWidth: horizontal ? layout.implicitWidth + Tokens.padding.normal * 2 : baseSize radius: Tokens.rounding.full Behavior on implicitHeight { @@ -69,34 +67,26 @@ CustomRect { color: Players.active?.isPlaying ? Colors.palette.m3primary : Colors.palette.m3onSurface font.pointSize: Tokens.font.size.normal horizontalAlignment: Text.AlignHCenter - implicitWidth: root.textWidth + implicitHeight: root.horizontal ? root.implicitHeight : root.textWidth + implicitWidth: root.horizontal ? root.textWidth : root.implicitWidth marqueeEnabled: false pauseMs: 4000 text: root.currentMedia + vertical: !root.horizontal + } + } - 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 - } - ] + CustomMouseArea { + anchors.fill: parent + hoverEnabled: true - CustomMouseArea { - anchors.fill: parent - hoverEnabled: true - - onContainsMouseChanged: { - if (!containsMouse) { - mediatext.marqueeEnabled = false; - } else { - mediatext.marqueeEnabled = true; - mediatext.anim.start(); - } - } + onContainsMouseChanged: { + console.log(root.textWidth, mediatext.implicitWidth, mediatext.implicitHeight); + if (!containsMouse) { + mediatext.marqueeEnabled = false; + } else { + mediatext.marqueeEnabled = true; + mediatext.anim.start(); } } } diff --git a/Modules/Bar/Components/NotifBell.qml b/Modules/Bar/Components/NotifBell.qml index c1db86f..c255deb 100644 --- a/Modules/Bar/Components/NotifBell.qml +++ b/Modules/Bar/Components/NotifBell.qml @@ -1,21 +1,19 @@ import Quickshell import QtQuick import ZShell.Config +import qs.Modules.Bar.Components.Common import qs.Modules.Bar.Popouts import qs.Daemons import qs.Components import qs.Services -CustomRect { +WidgetBase { 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) radius: Tokens.rounding.full MaterialIcon { diff --git a/Modules/Bar/Components/Resources.qml b/Modules/Bar/Components/Resources.qml index 123636e..5759d54 100644 --- a/Modules/Bar/Components/Resources.qml +++ b/Modules/Bar/Components/Resources.qml @@ -6,19 +6,18 @@ import QtQuick.Layouts import ZShell.Config import ZShell.Services import qs.Services -import qs.Modules +import qs.Modules.Bar.Components.Common import qs.Components -CustomRect { +WidgetBase { 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: horizontal ? baseSize : gridLayout.implicitHeight + Tokens.padding.normal * 2 + implicitWidth: horizontal ? gridLayout.implicitWidth + Tokens.padding.larger * 2 : baseSize radius: Tokens.rounding.full StateLayer { diff --git a/Modules/Bar/Components/StatusIcons.qml b/Modules/Bar/Components/StatusIcons.qml index e0d6655..66f6158 100644 --- a/Modules/Bar/Components/StatusIcons.qml +++ b/Modules/Bar/Components/StatusIcons.qml @@ -6,10 +6,11 @@ import QtQuick.Layouts import ZShell.Config import qs.Helpers import qs.Modules.Bar.Components.StatusIcons +import qs.Modules.Bar.Components.Common import qs.Components import qs.Services -CustomClippingRect { +WidgetBase { id: root readonly property int firstPresent: { @@ -19,7 +20,6 @@ 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 @@ -30,7 +30,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 @@ -43,8 +42,8 @@ CustomClippingRect { bottomLeftRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full color: Colors.tPalette.m3surfaceContainer - implicitHeight: horizontal ? shortSize : size - implicitWidth: horizontal ? size : shortSize + implicitHeight: horizontal ? baseSize : size + implicitWidth: horizontal ? size : baseSize radius: Tokens.rounding.full topLeftRadius: Tokens.rounding.smallest / 2 topRightRadius: horizontal ? Tokens.rounding.full : Tokens.rounding.smallest / 2 diff --git a/Modules/Bar/Components/TrayIcons.qml b/Modules/Bar/Components/TrayIcons.qml index a7175b4..568ee28 100644 --- a/Modules/Bar/Components/TrayIcons.qml +++ b/Modules/Bar/Components/TrayIcons.qml @@ -3,29 +3,28 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import Quickshell.Services.SystemTray -import qs.Components import ZShell.Config +import qs.Components +import qs.Modules.Bar.Components.Common import qs.Modules.Bar.Components.Tray import qs.Modules.Bar.Popouts import qs.Services -CustomClippingRect { +WidgetBase { id: root - required property bool horizontal readonly property alias items: repeater readonly property alias layout: sysGrid required property GridLayout 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: horizontal ? baseSize : size + implicitWidth: horizontal ? size : baseSize radius: Tokens.rounding.full topRightRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full diff --git a/Modules/Bar/Components/UpdatesWidget.qml b/Modules/Bar/Components/UpdatesWidget.qml index 3babcae..a525040 100644 --- a/Modules/Bar/Components/UpdatesWidget.qml +++ b/Modules/Bar/Components/UpdatesWidget.qml @@ -1,21 +1,20 @@ import QtQuick import QtQuick.Layouts -import qs.Components -import qs.Modules -import qs.Helpers import ZShell.Config +import qs.Components +import qs.Modules.Bar.Components.Common +import qs.Helpers import qs.Services -CustomRect { +WidgetBase { 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) + implicitHeight: horizontal ? baseSize : content.implicitHeight + Tokens.spacing.small + implicitWidth: horizontal ? content.implicitWidth + Tokens.spacing.small * 2 : baseSize radius: Tokens.rounding.full GridLayout { diff --git a/Modules/Bar/Components/WindowTitle.qml b/Modules/Bar/Components/WindowTitle.qml index a9c7a4e..c213072 100644 --- a/Modules/Bar/Components/WindowTitle.qml +++ b/Modules/Bar/Components/WindowTitle.qml @@ -1,8 +1,8 @@ pragma ComponentBehavior: Bound import QtQuick -import qs.Components import ZShell.Config +import qs.Components import qs.Helpers import qs.Services @@ -17,11 +17,10 @@ Item { 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; + return horizontal ? (bar.width - otherSize - bar.columnSpacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.rowSpacing * (bar.children.length - 1) - bar.vPadding * 4); } - anchors.centerIn: parent - clip: false + clip: true implicitHeight: horizontal ? current.implicitHeight : current.implicitWidth + current.anchors.topMargin implicitWidth: horizontal ? current.implicitWidth + current.anchors.leftMargin : current.implicitHeight + current.anchors.topMargin @@ -36,6 +35,7 @@ Item { enabled: root.horizontal Anim { + type: Anim.DefaultEffects } } diff --git a/Modules/Dashboard/Wrapper.qml b/Modules/Dashboard/Wrapper.qml index de1856b..c78a97f 100644 --- a/Modules/Dashboard/Wrapper.qml +++ b/Modules/Dashboard/Wrapper.qml @@ -14,16 +14,18 @@ Item { reloadableId: "dashboardState" } - required property bool horizontal readonly property real nonAnimHeight: state === "visible" ? (content.item?.nonAnimHeight ?? 0) : 0 required property real offsetScale + required property string position 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 + anchors.bottom: position === "bottom" ? parent.bottom : undefined + anchors.bottomMargin: position === "bottom" ? (-implicitHeight - 5) * offsetScale : 0 + anchors.left: position === "left" ? parent.left : undefined + anchors.leftMargin: position === "left" ? (-implicitWidth - 5) * offsetScale : 0 + anchors.top: position === "top" ? parent.top : undefined + anchors.topMargin: position === "top" ? (-implicitHeight - 5) * offsetScale : 0 implicitHeight: content.implicitHeight implicitWidth: content.implicitWidth || 854 opacity: 1 - offsetScale @@ -33,10 +35,11 @@ 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: root.position === "top" ? parent.bottom : undefined + anchors.horizontalCenter: root.position !== "left" ? parent.horizontalCenter : undefined + anchors.right: root.position !== "left" ? undefined : parent.right + anchors.top: root.position === "bottom" ? parent.top : undefined + anchors.verticalCenter: root.position === "left" ? undefined : parent.verticalCenter sourceComponent: Content { dashState: root.dashState diff --git a/Modules/Resources/Wrapper.qml b/Modules/Resources/Wrapper.qml index 25629a8..52f4c1b 100644 --- a/Modules/Resources/Wrapper.qml +++ b/Modules/Resources/Wrapper.qml @@ -8,14 +8,18 @@ import ZShell.Config Item { id: root - required property bool horizontal readonly property real nonAnimHeight: content.item?.nonAnimHeight ?? 0 property real offsetScale: shouldBeActive ? 0 : 1 + required property string position 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.bottom: position === "bottom" ? parent.bottom : undefined + anchors.bottomMargin: position === "bottom" ? (-implicitHeight - 5) * offsetScale : 0 + anchors.left: parent.left + anchors.leftMargin: position === "left" ? (-implicitWidth - 5) * offsetScale : 0 + anchors.top: position !== "bottom" ? parent.top : undefined + anchors.topMargin: position === "top" ? (-implicitHeight - 5) * offsetScale : 0 clip: true implicitHeight: content.implicitHeight implicitWidth: content.implicitWidth || 854 // Hard coded fallback for first open @@ -33,7 +37,11 @@ Item { id: content active: root.shouldBeActive || root.visible - anchors.centerIn: parent + anchors.bottom: root.position === "top" ? parent.bottom : undefined + anchors.horizontalCenter: root.position !== "left" ? parent.horizontalCenter : undefined + anchors.right: root.position !== "left" ? undefined : parent.right + anchors.top: root.position === "bottom" ? parent.top : undefined + anchors.verticalCenter: root.position === "left" ? undefined : parent.verticalCenter sourceComponent: Content { wrapper: root -- 2.47.3 From fb0c75a2ba9bcff09d5e9866c08654a980c98e3d Mon Sep 17 00:00:00 2001 From: zach Date: Sat, 15 Aug 2026 19:38:33 +0200 Subject: [PATCH 7/7] remove debug logging --- Modules/Bar/Components/MediaWidget.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/Bar/Components/MediaWidget.qml b/Modules/Bar/Components/MediaWidget.qml index 99e4e1e..0342550 100644 --- a/Modules/Bar/Components/MediaWidget.qml +++ b/Modules/Bar/Components/MediaWidget.qml @@ -81,7 +81,6 @@ WidgetBase { hoverEnabled: true onContainsMouseChanged: { - console.log(root.textWidth, mediatext.implicitWidth, mediatext.implicitHeight); if (!containsMouse) { mediatext.marqueeEnabled = false; } else { -- 2.47.3