From 9cbb90f9e13683c92c753d164e2c54457b6aa66a Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 29 Oct 2026 17:34:57 +0100 Subject: [PATCH] feat: initial commit for pixel-snapping components and helpers --- Components/CustomProgressBar.qml | 7 +- Components/CustomSlider.qml | 12 +- Components/IconButton.qml | 5 +- Components/IconTextButton.qml | 4 +- Components/LineGraph.qml | 155 ++++--- Components/Menu.qml | 8 +- Components/SplitButton.qml | 3 +- Components/Toast/ToastItem.qml | 7 +- Drawers/Panels.qml | 14 +- Greeter/Center.qml | 9 +- Greeter/Content.qml | 5 +- Greeter/InputField.qml | 1 + Greeter/SessionDock.qml | 14 +- Greeter/UserDock.qml | 14 +- Helpers/Picker/AnnotationToolbar.qml | 2 +- Modules/Bar/Bar.qml | 63 ++- Modules/Bar/BarLoader.qml | 1 + Modules/Bar/Components/Clock.qml | 6 +- Modules/Bar/Components/MediaWidget.qml | 1 + Modules/Bar/Components/NetworkWidget.qml | 3 +- Modules/Bar/Components/Resource.qml | 1 + Modules/Bar/Components/Resources.qml | 1 + Modules/Bar/Components/StatusIcons.qml | 15 +- .../Components/StatusIcons/AudioWidget.qml | 1 + .../Bar/Components/StatusIcons/MicWidget.qml | 1 + .../Components/StatusIcons/UPowerWidget.qml | 1 + Modules/Bar/Components/Tray/TrayItem.qml | 5 +- Modules/Bar/Components/TrayIcons.qml | 9 +- Modules/Bar/Components/UpdatesWidget.qml | 1 + Modules/Bar/Components/WindowTitle.qml | 2 +- Modules/Bar/Popouts/AudioPopout.qml | 25 +- Modules/Bar/Popouts/NetworkPopout.qml | 4 +- Modules/Bar/Popouts/TrayMenuPopout.qml | 4 +- Modules/Bar/Popouts/UPowerPopout.qml | 3 +- Modules/Bar/Popouts/UpdatesPopout.qml | 8 +- Modules/Clipboard/Content.qml | 5 +- Modules/Dashboard/Content.qml | 9 +- Modules/Dashboard/Dash.qml | 132 +++--- Modules/Dashboard/Dash/Calendar.qml | 6 +- Modules/Dashboard/Dash/Resources.qml | 20 +- Modules/Dashboard/Media.qml | 14 +- Modules/Dashboard/Media/Details.qml | 332 +++++++------- Modules/Dashboard/Media/LyricList.qml | 7 +- Modules/Dashboard/Media/LyricsAndSelector.qml | 6 +- Modules/Dashboard/Media/LyricsInfo.qml | 4 +- .../Dashboard/Processes/ProcessesHeader.qml | 1 + Modules/Dashboard/Processes/ProcessesList.qml | 3 +- Modules/Dashboard/Processes/SystemInfo.qml | 10 +- Modules/Dashboard/Tabs.qml | 89 ++-- Modules/Dashboard/Weather/Graphs.qml | 18 +- Modules/Dashboard/WeatherTab.qml | 21 +- .../DesktopIcons/BackgroundContextMenu.qml | 12 +- .../DesktopIcons/DesktopIconContextMenu.qml | 20 +- Modules/Dock/Parts/DockAppButton.qml | 9 +- Modules/Dock/Parts/DockSeparator.qml | 1 + Modules/Launcher/AppList.qml | 4 +- Modules/Launcher/CarouselView.qml | 5 +- Modules/Launcher/Content.qml | 5 +- Modules/Launcher/ContentList.qml | 9 +- Modules/Launcher/Items/ActionItem.qml | 2 +- Modules/Launcher/Items/AppItem.qml | 60 ++- Modules/Launcher/Items/CalcItem.qml | 3 +- Modules/Lock/Center.qml | 13 +- Modules/Lock/Content.qml | 14 +- Modules/Lock/InputField.qml | 1 + Modules/Lock/Media.qml | 4 +- Modules/Lock/NotifDock.qml | 10 +- Modules/Lock/NotifGroup.qml | 23 +- Modules/Lock/Resources.qml | 4 +- Modules/Lock/Weather/BriefInfo.qml | 6 +- Modules/Lock/Weather/Forecast.qml | 6 +- Modules/Osd/Content.qml | 30 +- Modules/Osd/Wrapper.qml | 10 +- Modules/Polkit/Polkit.qml | 19 +- Modules/Resources/Cards/BatteryTank.qml | 6 +- Modules/Resources/Cards/HeroCard.qml | 32 +- Modules/Resources/Cards/MemoryCard.qml | 41 +- Modules/Resources/Cards/NetworkCard.qml | 23 +- Modules/Resources/Cards/StorageCard.qml | 19 +- Modules/Resources/Cards/VramCard.qml | 89 ---- Modules/Resources/Content.qml | 52 ++- Modules/Settings/Common/AudioDeviceList.qml | 3 +- Modules/Settings/Common/DialogRowButton.qml | 6 +- Modules/Settings/Common/InfoRow.qml | 6 +- Modules/Settings/Common/ItemList.qml | 4 +- Modules/Settings/Common/ListEditor.qml | 3 +- Modules/Settings/Common/PageBase.qml | 6 +- Modules/Settings/Common/PopupRow.qml | 6 +- Modules/Settings/Common/RowButton.qml | 3 +- Modules/Settings/Common/SearchPopup.qml | 4 +- Modules/Settings/Common/SectionHeader.qml | 2 +- Modules/Settings/Common/SelectRow.qml | 6 +- Modules/Settings/Common/SliderRow.qml | 8 +- Modules/Settings/Common/SpinRow.qml | 6 +- Modules/Settings/Common/TextFieldRow.qml | 6 +- Modules/Settings/Common/TimeDialogRow.qml | 6 +- Modules/Settings/Common/TimeDialogToggle.qml | 1 + Modules/Settings/Common/TimeInput.qml | 7 +- Modules/Settings/Common/ToggleRow.qml | 1 + Modules/Settings/Common/WallItem.qml | 4 +- Modules/Settings/Common/WallpaperCropper.qml | 2 +- Modules/Settings/NavPane.qml | 4 +- Modules/Settings/NavPane/NavLocations.qml | 17 +- Modules/Settings/PageCompRegistry.qml | 4 +- Modules/Settings/Pages/AboutPage.qml | 7 +- Modules/Settings/Pages/Apps/AllApps.qml | 9 +- Modules/Settings/Pages/Apps/AppInfo.qml | 11 +- Modules/Settings/Pages/AppsPage.qml | 9 +- Modules/Settings/Pages/Audio/AppVolumes.qml | 4 +- Modules/Settings/Pages/AudioPage.qml | 9 +- .../Settings/Pages/Panels/Bar/BarClock.qml | 4 +- .../Pages/Panels/Bar/BarStatusIcons.qml | 4 +- Modules/Settings/Pages/Panels/Bar/BarTray.qml | 4 +- Modules/Settings/Pages/Panels/BarPanel.qml | 4 +- .../Settings/Pages/Panels/DashboardPanel.qml | 4 +- .../Settings/Pages/Panels/LauncherPanel.qml | 4 +- .../Settings/Pages/Panels/ResourcesPanel.qml | 4 +- .../Pages/Panels/Sidebar/SidebarLlm.qml | 4 +- .../Settings/Pages/Panels/SidebarPanel.qml | 4 +- Modules/Settings/Pages/PanelsPage.qml | 4 +- Modules/Settings/Pages/ScreenshotPage.qml | 3 +- .../Pages/Services/NotificationsPage.qml | 4 +- Modules/Settings/Pages/ServicesPage.qml | 4 +- .../Settings/Pages/Wallpaper/ColorsFonts.qml | 4 +- .../Pages/Wallpaper/WallpaperSelect.qml | 7 +- Modules/Settings/Pages/WallpaperPage.qml | 3 +- Modules/Sidebar/Chat/ChatContent.qml | 2 +- Modules/Sidebar/Chat/ChatList.qml | 8 +- .../Sidebar/Chat/Content/ApprovalPrompt.qml | 15 +- .../Sidebar/Chat/Content/CodeBlockView.qml | 5 +- .../Sidebar/Chat/Content/ContentBubble.qml | 1 + .../Sidebar/Chat/Content/EmptyBackground.qml | 4 +- Modules/Sidebar/Chat/Content/ErrorBubble.qml | 4 +- .../Sidebar/Chat/Content/ModelsContainer.qml | 11 +- Modules/Sidebar/Chat/Content/ProcessBlock.qml | 4 +- Modules/Sidebar/Chat/SidebarView.qml | 1 + Modules/Sidebar/Content.qml | 15 +- Modules/Sidebar/Notif.qml | 10 +- Modules/Sidebar/NotifActionList.qml | 173 ++++--- Modules/Sidebar/NotifDock.qml | 12 +- Modules/Sidebar/NotifGroup.qml | 38 +- Modules/Sidebar/NotifGroupList.qml | 11 +- Modules/Sidebar/Tabs.qml | 5 +- Modules/Sidebar/Utils/Cards/Record.qml | 16 +- Modules/Sidebar/Utils/Cards/RecordingList.qml | 13 +- Modules/Sidebar/Utils/Cards/Toggles.qml | 3 +- Modules/Sidebar/Utils/Content.qml | 12 +- Modules/Sidebar/Utils/IdleInhibit.qml | 19 +- Plugins/CMakeLists.txt | 3 + Plugins/ZShell/CMakeLists.txt | 20 +- Plugins/ZShell/Components/CMakeLists.txt | 5 + Plugins/ZShell/Components/snaplayout.cpp | 419 +++++++++++++++++ Plugins/ZShell/Components/snaplayout.hpp | 129 ++++++ Plugins/ZShell/Config/font.hpp | 12 +- Plugins/ZShell/Config/launcher.hpp | 10 - Plugins/ZShell/Config/tokens.hpp | 10 + Plugins/ZShell/alignaudit.cpp | 206 +++++++++ Plugins/ZShell/alignaudit.hpp | 19 + Plugins/ZShell/alignauditor.cpp | 26 ++ Plugins/ZShell/alignauditor.hpp | 52 +++ Plugins/ZShell/zutils.cpp | 424 ++++++++++++++++++ Plugins/ZShell/zutils.hpp | 38 ++ shell.qml | 14 + 163 files changed, 2671 insertions(+), 951 deletions(-) delete mode 100644 Modules/Resources/Cards/VramCard.qml create mode 100644 Plugins/ZShell/Components/snaplayout.cpp create mode 100644 Plugins/ZShell/Components/snaplayout.hpp create mode 100644 Plugins/ZShell/alignaudit.cpp create mode 100644 Plugins/ZShell/alignaudit.hpp create mode 100644 Plugins/ZShell/alignauditor.cpp create mode 100644 Plugins/ZShell/alignauditor.hpp diff --git a/Components/CustomProgressBar.qml b/Components/CustomProgressBar.qml index c9666f5..1fddd73 100644 --- a/Components/CustomProgressBar.qml +++ b/Components/CustomProgressBar.qml @@ -99,6 +99,7 @@ ProgressBar { } Line { + id: dot property real implicitSize anchors.right: parent.right @@ -124,8 +125,7 @@ ProgressBar { anchors.left: parent.left Behavior on implicitWidth { - Anim { - } + Anim {} } Component.onCompleted: implicitWidth = Qt.binding(() => parent.width * root.visualPosition) @@ -222,8 +222,7 @@ ProgressBar { } } Behavior on color { - CAnim { - } + CAnim {} } Anim on waveProgress { duration: root.waveDuration diff --git a/Components/CustomSlider.qml b/Components/CustomSlider.qml index 5acd92b..dd3db9b 100644 --- a/Components/CustomSlider.qml +++ b/Components/CustomSlider.qml @@ -2,10 +2,10 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Templates -import ZShell.Components import ZShell -import qs.Components +import ZShell.Components import ZShell.Config +import qs.Components import qs.Services Slider { @@ -28,7 +28,7 @@ Slider { signal interaction(v: real) - implicitHeight: 12 + implicitHeight: ZUtils.snap(12, root) implicitWidth: 200 contentItem: Item { @@ -123,7 +123,7 @@ Slider { bottomRightRadius: Tokens.rounding.extraSmall / 2 color: root.fgColor implicitHeight: root.height - implicitWidth: root.filledWidth + implicitWidth: ZUtils.snap(root.filledWidth, root) radius: root.radius topRightRadius: Tokens.rounding.extraSmall / 2 } @@ -137,8 +137,8 @@ Slider { frequency: root.waveFrequency fullLength: root.width - handle.implicitWidth - handle.anchors.leftMargin implicitHeight: lineWidth * amplitudeMultiplier * 2 + lineWidth - implicitWidth: root.filledWidth - lineWidth: root.height * 0.7 + implicitWidth: ZUtils.snap(root.filledWidth, root) + lineWidth: ZUtils.snap(root.height * 0.7, root) startX: x Behavior on color { diff --git a/Components/IconButton.qml b/Components/IconButton.qml index 3bdfc48..bf46b3d 100644 --- a/Components/IconButton.qml +++ b/Components/IconButton.qml @@ -1,4 +1,5 @@ import QtQuick +import ZShell import ZShell.Config import qs.Services @@ -15,9 +16,9 @@ ButtonBase { const h = label.implicitHeight + padding * 2; if (h % 2 !== 0) return h + 1; - return h; + return ZUtils.snap(h, root); } - implicitWidth: implicitHeight + implicitWidth: ZUtils.snap(implicitHeight, root) inactiveColor: { if (!isToggle && type === IconButton.Filled) return Colors.palette.m3primary; diff --git a/Components/IconTextButton.qml b/Components/IconTextButton.qml index fb568f6..ed2b5d2 100644 --- a/Components/IconTextButton.qml +++ b/Components/IconTextButton.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Services @@ -34,10 +35,11 @@ ButtonBase { } verticalPadding: Tokens.padding.extraSmall - RowLayout { + SnapLayout { id: row anchors.centerIn: parent + spacing: Tokens.spacing.small MaterialIcon { diff --git a/Components/LineGraph.qml b/Components/LineGraph.qml index c16a1a6..b8f32fa 100644 --- a/Components/LineGraph.qml +++ b/Components/LineGraph.qml @@ -1,6 +1,8 @@ pragma ComponentBehavior: Bound import QtQuick +import QtCanvas2D +import ZShell Item { id: root @@ -36,54 +38,62 @@ Item { property real fillAlpha: 0.15 property real lineWidth: 2 property real markerDotRadius: 4 - property real labelFontSize: 10 + property real labelFontSize: 8 - Canvas { + Canvas2D { id: canvas anchors.fill: parent - renderStrategy: Canvas.Immediate + + alphaBlending: true + fillColor: "transparent" onWidthChanged: requestPaint() onHeightChanged: requestPaint() + function snapV(v) { + return ZUtils.snap(v, canvas); + } + function strokeCurve(ctx, pts) { ctx.beginPath(); ctx.moveTo(pts[0].x, pts[0].y); - if (root.curveSmoothing && pts.length > 2) { - const k = 1 / 6; - const n = pts.length; + const dpr = ZUtils.dprFor(canvas); + for (let i = 0; i < pts.length - 1; i++) { + const p1 = pts[i]; + const p2 = pts[i + 1]; + const [c1x, c1y, c2x, c2y] = segmentControls(pts, i); - for (let i = 0; i < n - 1; i++) { - const p0 = pts[Math.max(i - 1, 0)]; - const p1 = pts[i]; - const p2 = pts[i + 1]; - const p3 = pts[Math.min(i + 2, n - 1)]; - - let c1x = p1.x + (p2.x - p0.x) * k; - let c1y = p1.y + (p2.y - p0.y) * k; - let c2x = p2.x - (p3.x - p1.x) * k; - let c2y = p2.y - (p3.y - p1.y) * k; - - const minY = Math.min(p1.y, p2.y); - const maxY = Math.max(p1.y, p2.y); - c1y = Math.max(minY, Math.min(maxY, c1y)); - c2y = Math.max(minY, Math.min(maxY, c2y)); - - ctx.bezierCurveTo(c1x, c1y, c2x, c2y, p2.x, p2.y); - } - } else { - for (let i = 0; i < pts.length - 1; i++) { - const p0 = pts[i]; - const p1 = pts[i + 1]; - const cx = (p0.x + p1.x) * 0.5; - ctx.bezierCurveTo(cx, p0.y, cx, p1.y, p1.x, p1.y); + const firstCol = Math.ceil(p1.x * dpr) + 1; + const lastCol = Math.floor(p2.x * dpr) - 1; + for (let col = firstCol; col <= lastCol; ++col) { + const x = col / dpr; + ctx.lineTo(x, bezierY(p1, c1x, c1y, c2x, c2y, p2, x)); } + + ctx.lineTo(p2.x, p2.y); } } - // Control points for segment i (pts[i] -> pts[i+1]), matching strokeCurve + function bezierY(p1, c1x, c1y, c2x, c2y, p2, targetX) { + let tlo = 0; + let thi = 1; + for (let it = 0; it < 16; it++) { + const tm = (tlo + thi) / 2; + const u = 1 - tm; + const x = u * u * u * p1.x + 3 * u * u * tm * c1x + 3 * u * tm * tm * c2x + tm * tm * tm * p2.x; + if (x < targetX) + tlo = tm; + else + thi = tm; + } + + const t = (tlo + thi) / 2; + const u = 1 - t; + return u * u * u * p1.y + 3 * u * u * t * c1y + 3 * u * t * t * c2y + t * t * t * p2.y; + } + function segmentControls(pts, i) { const p0 = pts[Math.max(i - 1, 0)]; const p1 = pts[i]; @@ -109,7 +119,6 @@ Item { return [cx, p1.y, cx, p2.y]; } - // Point on the curve at a given x (x is monotonic per segment) function pointAtX(pts, targetX) { let j = pts.length - 2; for (let i = 0; i < pts.length - 1; i++) { @@ -138,10 +147,16 @@ Item { const t = (tlo + thi) / 2; const u = 1 - t; const y = u * u * u * p1.y + 3 * u * u * t * c1y + 3 * u * t * t * c2y + t * t * t * p2.y; - return { x: targetX, y }; + return { + x: targetX, + y + }; + } + + function cutPoint(pts, targetX) { + return pointAtX(pts, targetX); } - // Part of the curve left/right of a cut x, including the cut point function cutLeft(pts, targetX) { if (targetX <= pts[0].x) return []; @@ -158,7 +173,7 @@ Item { const left = pts.slice(0, j + 1); if (targetX > pts[j].x) - left.push(pointAtX(pts, targetX)); + left.push(cutPoint(pts, targetX)); return left; } @@ -184,17 +199,20 @@ Item { onPaint: { const ctx = getContext("2d"); + if (!ctx) + return; ctx.reset(); + ctx.clearRect(0, 0, width, height); const W = width; const H = height; if (W < 2 || H < 2) return; - const padLeft = root.labelFontSize * 3.4; - const padRight = 2; - const padTop = 2; - const padBottom = root.labelFontSize + 8; + const padLeft = root.labelFontSize * 5; + const padRight = 0; + const padTop = 0; + const padBottom = root.labelFontSize + 14; const plot = { x: padLeft, y: padTop, @@ -204,8 +222,6 @@ Item { if (plot.w < 2 || plot.h < 2) return; - // Auto-fit: NaN yMin/yMax derive from the data, snapped to the - // horizontal step grid, honoring minHorizontalLines let lo = root.yMin; let hi = root.yMax; const loAuto = Number.isNaN(lo); @@ -279,11 +295,17 @@ Item { const xAt = i => plot.x + (i / root.xSteps) * plot.w; const yAt = v => plot.y + (1 - (v - scaleBottom) / range) * plot.h; - const crisp = v => Math.floor(v) + 0.5; - // 1. Grid lines + const dpr = ZUtils.dprFor(canvas); + const devW = w => Math.max(1, Math.round(w * dpr)); + const snapLine = (v, w) => { + const dw = devW(w); + return (Math.round(v * dpr - dw / 2) + dw / 2) / dpr; + }; + const gridW = devW(1) / dpr; + ctx.strokeStyle = Qt.alpha(root.gridColor, root.gridAlpha); - ctx.lineWidth = 1; + ctx.lineWidth = gridW; if (root.verticalLineStep > 0) { for (let i = 0; i <= root.xSteps; i += root.verticalLineStep) { @@ -292,7 +314,7 @@ Item { if (i === root.xSteps && !root.lastXLine) continue; - const x = crisp(xAt(i)); + const x = snapLine(xAt(i), 1); ctx.beginPath(); ctx.moveTo(x, plot.y); ctx.lineTo(x, H); @@ -300,12 +322,11 @@ Item { } } - // Lines extend down into yPaddingBottom, snapped to the grid const vStart = lo - (root.yPaddingBottom > 0 ? Math.floor(root.yPaddingBottom / root.horizontalLineStep) * root.horizontalLineStep : 0); if (root.horizontalLineStep > 0) { for (let v = vStart; v <= hi + 0.001; v += root.horizontalLineStep) { - const y = crisp(yAt(v)); + const y = snapLine(yAt(v), 1); ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(plot.x + plot.w, y); @@ -313,9 +334,8 @@ Item { } } - // 2. Labels ctx.fillStyle = Qt.alpha(root.labelColor, root.labelAlpha); - ctx.font = root.labelFontSize + "px sans-serif"; + ctx.font = root.labelFontSize + "pt 'sans-serif'"; ctx.textAlign = "left"; ctx.textBaseline = "top"; @@ -328,7 +348,7 @@ Item { const text = root.xLabel(i); if (text) - ctx.fillText(text, xAt(i) + 4, plot.y + plot.h + 4); + ctx.fillText(text, xAt(i) + 4, plot.y + plot.h + 8); } } @@ -341,7 +361,6 @@ Item { } } - // 3. Curve, split into segments at null gaps const segments = []; let current = null; for (let i = 0; i < series.length; i++) { @@ -352,7 +371,7 @@ Item { continue; } const pt = { - x: xAt(i), + x: snapV(xAt(i)), y: yAt(series[i]) }; if (!current) @@ -369,8 +388,6 @@ Item { const markerPx = hasMarker ? xAt(root.markerX) : 0; let gapPx = 0; if (hasMarker) { - // markerGap is measured from the dot edge, perpendicular to the - // curve; project onto x via the local curve slope let slope = 0; const seg = segments.find(s => s[0].x <= markerPx && markerPx <= s[s.length - 1].x); if (seg && seg.length > 2 && markerPx - 1 >= seg[0].x && markerPx + 1 <= seg[seg.length - 1].x) @@ -382,7 +399,6 @@ Item { if (seg.length < 2) continue; - // Fill stays continuous under the marker ctx.fillStyle = Qt.alpha(root.lineColor, root.fillAlpha); strokeCurve(ctx, seg); ctx.lineTo(seg[seg.length - 1].x, plot.y + plot.h); @@ -390,7 +406,6 @@ Item { ctx.closePath(); ctx.fill(); - // Stroke has a gap around the marker const pieces = hasMarker ? [cutLeft(seg, markerPx - gapPx), cutRight(seg, markerPx + gapPx)] : [seg]; for (const pts of pieces) { @@ -398,24 +413,32 @@ Item { continue; ctx.strokeStyle = root.lineColor; - ctx.lineWidth = root.lineWidth; + ctx.lineWidth = ZUtils.snap(root.lineWidth, root); strokeCurve(ctx, pts); ctx.stroke(); } } - // 4. Marker: dashed vertical + dot if (root.markerX >= 0 && root.markerX <= root.xSteps) { const x = markerPx; - ctx.setLineDash([4, 4]); ctx.strokeStyle = Qt.alpha(root.markerColor, 0.6); - ctx.lineWidth = 1; - ctx.beginPath(); - ctx.moveTo(crisp(x), plot.y); - ctx.lineTo(crisp(x), H); - ctx.stroke(); - ctx.setLineDash([]); + ctx.lineWidth = gridW; + const lineX = snapLine(x, 1); + let dashY = plot.y; + let dashOn = true; + + while (dashY < H) { + const dashEnd = Math.min(dashY + 4, H); + if (dashOn) { + ctx.beginPath(); + ctx.moveTo(lineX, snapV(dashY)); + ctx.lineTo(lineX, snapV(dashEnd)); + ctx.stroke(); + } + dashY = dashEnd; + dashOn = !dashOn; + } const i0 = Math.floor(root.markerX); const v0 = series[i0]; @@ -430,7 +453,7 @@ Item { if (y != null) { ctx.fillStyle = root.markerColor; ctx.beginPath(); - ctx.arc(x, y, root.markerDotRadius, 0, Math.PI * 2); + ctx.circle(snapV(x), y, root.markerDotRadius); ctx.fill(); } } diff --git a/Components/Menu.qml b/Components/Menu.qml index 6a3db28..1cdb710 100644 --- a/Components/Menu.qml +++ b/Components/Menu.qml @@ -4,6 +4,7 @@ import QtQuick import QtQuick.Layouts import Quickshell import ZShell.Config +import ZShell.Components import qs.Drawers import qs.Services @@ -111,12 +112,14 @@ MouseArea { color: Colors.palette.m3surfaceContainerLow radius: parent.radius - ColumnLayout { + SnapLayout { id: column anchors.fill: parent anchors.margins: Tokens.padding.extraSmall + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical Repeater { id: repeater @@ -153,11 +156,12 @@ MouseArea { } } - RowLayout { + SnapLayout { id: menuOptionRow anchors.fill: parent anchors.margins: Tokens.padding.medium + spacing: Tokens.spacing.small MaterialIcon { diff --git a/Components/SplitButton.qml b/Components/SplitButton.qml index 9f54950..5b0c0f8 100644 --- a/Components/SplitButton.qml +++ b/Components/SplitButton.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Services @@ -53,7 +54,7 @@ Row { onClicked: root.active?.clicked() } - RowLayout { + SnapLayout { id: textRow anchors.centerIn: parent diff --git a/Components/Toast/ToastItem.qml b/Components/Toast/ToastItem.qml index 254e20c..4c2feb0 100644 --- a/Components/Toast/ToastItem.qml +++ b/Components/Toast/ToastItem.qml @@ -1,4 +1,5 @@ import ZShell +import ZShell.Components import QtQuick import QtQuick.Layouts import qs.Components @@ -47,7 +48,7 @@ CustomRect { z: -1 } - RowLayout { + SnapLayout { id: layout anchors.fill: parent @@ -88,9 +89,11 @@ CustomRect { } } - ColumnLayout { + SnapLayout { Layout.fillWidth: true + spacing: 0 + orientation: Qt.Vertical CustomText { id: title diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index 46fcda3..0807b23 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -1,5 +1,7 @@ import Quickshell import QtQuick +import ZShell.Config +import ZShell import qs.Components import qs.Modules.Bar.Popouts as Popouts import qs.Modules.Notifications as Notifications @@ -14,7 +16,6 @@ import qs.Modules.Settings as Settings import qs.Modules.Drawing as Drawing import qs.Modules.Dock as Dock import qs.Modules.Clipboard as Clipboard -import ZShell.Config Item { id: root @@ -74,7 +75,10 @@ Item { anchors.right: parent.right anchors.rightMargin: sidebar.width * (1 - sidebar.offsetScale) - anchors.verticalCenter: parent.verticalCenter + + y: ZUtils.snap((parent.height - implicitHeight) / 2, root) + + // anchors.verticalCenter: parent.verticalCenter clip: sidebar.visible implicitHeight: osd.implicitHeight implicitWidth: osd.implicitWidth * (1 - osd.offsetScale) @@ -82,8 +86,7 @@ Item { Osd.Wrapper { id: osd - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter + anchors.fill: parent screen: root.screen screenState: root.screenState sidebarOrSessionVisible: sidebar.visible @@ -129,8 +132,9 @@ Item { Launcher.Wrapper { id: launcher + x: ZUtils.snap((parent.width - implicitWidth) / 2, root) + anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter panels: root screen: root.screen screenState: root.screenState diff --git a/Greeter/Center.qml b/Greeter/Center.qml index 845b2fc..d7bb578 100644 --- a/Greeter/Center.qml +++ b/Greeter/Center.qml @@ -3,11 +3,12 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell.Components import qs.Components import qs.Helpers import qs.Services -ColumnLayout { +SnapLayout { id: root readonly property real centerScale: Math.min(1, screenHeight / 1440) @@ -18,9 +19,11 @@ ColumnLayout { Layout.fillHeight: true Layout.fillWidth: false Layout.preferredWidth: centerWidth + + orientation: Qt.Vertical spacing: Tokens.spacing.largeIncreased * 2 - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignHCenter spacing: Tokens.spacing.small @@ -116,7 +119,7 @@ ColumnLayout { } } - RowLayout { + SnapLayout { id: input anchors.fill: parent diff --git a/Greeter/Content.qml b/Greeter/Content.qml index 78104b1..094008b 100644 --- a/Greeter/Content.qml +++ b/Greeter/Content.qml @@ -1,11 +1,12 @@ import QtQuick import QtQuick.Layouts +import ZShell.Config +import ZShell.Components import qs.Components import qs.Helpers -import ZShell.Config import qs.Services -RowLayout { +SnapLayout { id: root required property var greeter diff --git a/Greeter/InputField.qml b/Greeter/InputField.qml index 89b46ab..9bb5744 100644 --- a/Greeter/InputField.qml +++ b/Greeter/InputField.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Services diff --git a/Greeter/SessionDock.qml b/Greeter/SessionDock.qml index a1b2b72..d1b33e2 100644 --- a/Greeter/SessionDock.qml +++ b/Greeter/SessionDock.qml @@ -3,17 +3,20 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell.Components import qs.Components import qs.Services -ColumnLayout { +SnapLayout { id: root required property var greeter anchors.fill: parent anchors.margins: Tokens.padding.large + spacing: Tokens.spacing.large + orientation: Qt.Vertical CustomText { Layout.fillWidth: true @@ -37,8 +40,9 @@ ColumnLayout { duration: Tokens.anim.durations.extraLarge } } - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { spacing: Tokens.spacing.largeIncreased + orientation: Qt.Vertical MaterialIcon { Layout.alignment: Qt.AlignHCenter @@ -84,7 +88,7 @@ ColumnLayout { } } - RowLayout { + SnapLayout { id: row anchors.fill: parent @@ -97,9 +101,11 @@ ColumnLayout { text: modelData.kind === "x11" ? "tv" : "desktop_windows" } - ColumnLayout { + SnapLayout { Layout.fillWidth: true + spacing: Tokens.spacing.small / 2 + orientation: Qt.Vertical CustomText { Layout.fillWidth: true diff --git a/Greeter/UserDock.qml b/Greeter/UserDock.qml index d8d3085..db7a6e9 100644 --- a/Greeter/UserDock.qml +++ b/Greeter/UserDock.qml @@ -3,18 +3,21 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell.Components import qs.Components import qs.Helpers import qs.Services -ColumnLayout { +SnapLayout { id: root required property var greeter anchors.fill: parent anchors.margins: Tokens.padding.large + spacing: Tokens.spacing.large + orientation: Qt.Vertical CustomText { Layout.fillWidth: true @@ -38,8 +41,9 @@ ColumnLayout { duration: Tokens.anim.durations.extraLarge } } - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { spacing: Tokens.spacing.largeIncreased + orientation: Qt.Vertical MaterialIcon { Layout.alignment: Qt.AlignHCenter @@ -86,7 +90,7 @@ ColumnLayout { } } - RowLayout { + SnapLayout { id: row anchors.fill: parent @@ -112,9 +116,11 @@ ColumnLayout { } } - ColumnLayout { + SnapLayout { Layout.fillWidth: true + spacing: Tokens.spacing.small / 2 + orientation: Qt.Vertical CustomText { Layout.fillWidth: true diff --git a/Helpers/Picker/AnnotationToolbar.qml b/Helpers/Picker/AnnotationToolbar.qml index fb6b673..e9219de 100755 --- a/Helpers/Picker/AnnotationToolbar.qml +++ b/Helpers/Picker/AnnotationToolbar.qml @@ -53,7 +53,7 @@ CustomRect { radius: Tokens.rounding.full width: row.implicitWidth + Tokens.padding.small * 2 - RowLayout { + SnapLayout { id: row anchors.centerIn: parent diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 856b391..e19aba4 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -4,11 +4,12 @@ import Quickshell import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell.Components import qs.Components import qs.Modules.Bar.Components import qs.Modules.Bar.Popouts -GridLayout { +SnapLayout { id: root required property bool fullscreen @@ -74,9 +75,47 @@ GridLayout { return ch?.entryId ?? ""; } - columnSpacing: Tokens.spacing.small - columns: horizontal ? -1 : 1 - rowSpacing: Tokens.spacing.small + readonly property var sectionRects: { + const count = repeater.count; // dependency: re-run when items are added/removed + const names = ["start", "middle", "end"]; // constant ids by position + const bounds = [null]; + let spacers = 0; + + for (let i = 0; i < count; i++) { + const it = repeater.itemAt(i) as EntryWrapper; + if (!it) + continue; + + if (it.entryId === "spacer") { + bounds.push(null); + spacers++; + continue; + } + + const l = it.x, t = it.y, r = it.x + it.width, b = it.y + it.height; + const cur = bounds[spacers]; + + bounds[spacers] = cur ? { + l: Math.min(cur.l, l), + t: Math.min(cur.t, t), + r: Math.max(cur.r, r), + b: Math.max(cur.b, b) + } : { + l, + t, + r, + b + }; + } + + return bounds.map((c, n) => ({ + id: names[n] ?? `section${n}`, + rect: c ? Qt.rect(c.l, c.t, c.r - c.l, c.b - c.t) : Qt.rect(0, 0, 0, 0) + })); + } + + spacing: Tokens.spacing.small + orientation: horizontal ? Qt.Horizontal : Qt.Vertical Repeater { id: repeater @@ -229,16 +268,26 @@ GridLayout { } component EntryWrapper: Item { + readonly property int section: { + let n = 0; + for (let i = 0; i < index; i++) { + if (repeater.model.values[i].id === "spacer") + n++; + } + return n; + } + readonly property string entryId: modelData.id required property int index - default property Item item required property var modelData + default property Item item + Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter Layout.bottomMargin: !root.horizontal && index === repeater.count - 1 ? root.vPadding : 0 - Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.rowSpacing + Tokens.spacing.extraSmall : 0 + Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.spacing + Tokens.spacing.extraSmall : 0 Layout.rightMargin: root.horizontal && index === repeater.count - 1 ? root.vPadding : 0 - Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.columnSpacing + Tokens.spacing.extraSmall : 0 + Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.spacing + Tokens.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 82ff8e8..248a555 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -9,6 +9,7 @@ import qs.Components Item { id: root + readonly property var sections: (content.item as Bar)?.sectionRects ?? [] readonly property int clampedExtent: Math.max(Config.bar.border, extent) readonly property int contentThickness: Math.floor(Math.max(Config.bar.height, Tokens.sizes.bar.innerSize * (horizontal ? 1 : 1.5))) + padding * 2 readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness diff --git a/Modules/Bar/Components/Clock.qml b/Modules/Bar/Components/Clock.qml index e47f198..c5557ed 100644 --- a/Modules/Bar/Components/Clock.qml +++ b/Modules/Bar/Components/Clock.qml @@ -4,6 +4,7 @@ import Quickshell import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell.Components import qs.Modules.Bar.Popouts import qs.Modules.Bar.Components.Common import qs.Helpers @@ -43,7 +44,7 @@ WidgetBase { timeTokens: timeTokens }; } - required property GridLayout loader + required property SnapLayout loader required property Wrapper popouts readonly property real size: horizontal ? timeText.contentWidth + Tokens.padding.medium * 2 : verticalColumn.implicitHeight + Tokens.padding.medium * 2 required property ScreenState screenState @@ -67,7 +68,8 @@ WidgetBase { } } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: verticalColumn anchors.centerIn: parent diff --git a/Modules/Bar/Components/MediaWidget.qml b/Modules/Bar/Components/MediaWidget.qml index 7d2297f..47c6d24 100644 --- a/Modules/Bar/Components/MediaWidget.qml +++ b/Modules/Bar/Components/MediaWidget.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Bar.Components.Common diff --git a/Modules/Bar/Components/NetworkWidget.qml b/Modules/Bar/Components/NetworkWidget.qml index 53463ee..e69c888 100644 --- a/Modules/Bar/Components/NetworkWidget.qml +++ b/Modules/Bar/Components/NetworkWidget.qml @@ -1,6 +1,7 @@ import Quickshell import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import qs.Modules @@ -11,7 +12,7 @@ Item { anchors.top: parent.top implicitWidth: layout.implicitWidth - RowLayout { + SnapLayout { id: layout anchors.bottom: parent.bottom diff --git a/Modules/Bar/Components/Resource.qml b/Modules/Bar/Components/Resource.qml index b22d9e7..f39a03d 100644 --- a/Modules/Bar/Components/Resource.qml +++ b/Modules/Bar/Components/Resource.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import qs.Components import ZShell.Config diff --git a/Modules/Bar/Components/Resources.qml b/Modules/Bar/Components/Resources.qml index 32bd1f2..f8979e8 100644 --- a/Modules/Bar/Components/Resources.qml +++ b/Modules/Bar/Components/Resources.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import QtQuick import Quickshell import QtQuick.Layouts +import ZShell.Components import ZShell.Config import ZShell.Services import qs.Services diff --git a/Modules/Bar/Components/StatusIcons.qml b/Modules/Bar/Components/StatusIcons.qml index b0c58af..ac131ba 100644 --- a/Modules/Bar/Components/StatusIcons.qml +++ b/Modules/Bar/Components/StatusIcons.qml @@ -4,6 +4,7 @@ import Quickshell import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell.Components import qs.Helpers import qs.Modules.Bar.Components.StatusIcons import qs.Modules.Bar.Components.Common @@ -51,17 +52,15 @@ WidgetBase { Behavior on implicitHeight { enabled: !root.horizontal - Anim { - } + Anim {} } Behavior on implicitWidth { enabled: root.horizontal - Anim { - } + Anim {} } - GridLayout { + SnapLayout { id: grid anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.medium @@ -69,7 +68,8 @@ WidgetBase { anchors.leftMargin: root.horizontal ? Tokens.padding.extraSmall : 0 anchors.rightMargin: root.horizontal ? Tokens.padding.extraSmall : 0 anchors.topMargin: root.horizontal ? 0 : Tokens.padding.extraSmall - columns: root.horizontal ? -1 : 1 + orientation: root.horizontal ? Qt.Horizontal : Qt.Vertical + spacing: root.horizontal ? Tokens.spacing.extraSmall : -2 Repeater { model: ScriptModel { @@ -111,8 +111,7 @@ WidgetBase { delegate: EntryWrapper { name: "upower" - UPowerWidget { - } + UPowerWidget {} } } } diff --git a/Modules/Bar/Components/StatusIcons/AudioWidget.qml b/Modules/Bar/Components/StatusIcons/AudioWidget.qml index a6fab2a..8235a14 100644 --- a/Modules/Bar/Components/StatusIcons/AudioWidget.qml +++ b/Modules/Bar/Components/StatusIcons/AudioWidget.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Daemons import qs.Components diff --git a/Modules/Bar/Components/StatusIcons/MicWidget.qml b/Modules/Bar/Components/StatusIcons/MicWidget.qml index cb61bee..093f45e 100644 --- a/Modules/Bar/Components/StatusIcons/MicWidget.qml +++ b/Modules/Bar/Components/StatusIcons/MicWidget.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Daemons import qs.Components diff --git a/Modules/Bar/Components/StatusIcons/UPowerWidget.qml b/Modules/Bar/Components/StatusIcons/UPowerWidget.qml index 48c1b71..d94d1ca 100644 --- a/Modules/Bar/Components/StatusIcons/UPowerWidget.qml +++ b/Modules/Bar/Components/StatusIcons/UPowerWidget.qml @@ -1,6 +1,7 @@ import Quickshell.Services.UPower import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Modules.Bar.Components.Common import qs.Components diff --git a/Modules/Bar/Components/Tray/TrayItem.qml b/Modules/Bar/Components/Tray/TrayItem.qml index 453bef4..6913e7b 100644 --- a/Modules/Bar/Components/Tray/TrayItem.qml +++ b/Modules/Bar/Components/Tray/TrayItem.qml @@ -2,10 +2,11 @@ import QtQuick.Layouts import QtQuick import Quickshell import Quickshell.Services.SystemTray +import ZShell.Config +import ZShell.Components import qs.Helpers import qs.Modules.Bar.Popouts import qs.Components -import ZShell.Config import qs.Services Item { @@ -15,7 +16,7 @@ Item { readonly property real dpr: Hypr.monitorFor(loader?.screen).scale required property int ind required property SystemTrayItem item - required property GridLayout loader + required property SnapLayout loader required property Wrapper popouts function resolveIcon(app: string, icon: string): string { diff --git a/Modules/Bar/Components/TrayIcons.qml b/Modules/Bar/Components/TrayIcons.qml index fae91a7..0ab11f9 100644 --- a/Modules/Bar/Components/TrayIcons.qml +++ b/Modules/Bar/Components/TrayIcons.qml @@ -4,6 +4,7 @@ import QtQuick import QtQuick.Layouts import Quickshell.Services.SystemTray import ZShell.Config +import ZShell.Components import qs.Components import qs.Modules.Bar.Components.Common import qs.Modules.Bar.Components.Tray @@ -15,7 +16,7 @@ WidgetBase { readonly property alias items: repeater readonly property alias layout: sysGrid - required property GridLayout loader + required property SnapLayout loader readonly property int padding: Tokens.padding.extraSmall required property Wrapper popouts readonly property real size: horizontal ? sysGrid.implicitWidth + sysGrid.anchors.leftMargin + sysGrid.anchors.rightMargin : sysGrid.implicitHeight + sysGrid.anchors.topMargin + sysGrid.anchors.bottomMargin @@ -28,7 +29,7 @@ WidgetBase { radius: Tokens.rounding.full topRightRadius: horizontal ? Tokens.rounding.small / 2 : Tokens.rounding.full - GridLayout { + SnapLayout { id: sysGrid anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.extraSmall @@ -36,8 +37,8 @@ WidgetBase { anchors.leftMargin: root.horizontal ? Tokens.padding.extraSmall : 0 anchors.rightMargin: root.horizontal ? Tokens.padding.extraSmall : 0 anchors.topMargin: root.horizontal ? 0 : Tokens.padding.extraSmall - columns: root.horizontal ? -1 : 1 - rowSpacing: -2 + orientation: root.horizontal ? Qt.Horizontal : Qt.Vertical + spacing: root.horizontal ? Tokens.spacing.extraSmall : -2 Repeater { id: repeater diff --git a/Modules/Bar/Components/UpdatesWidget.qml b/Modules/Bar/Components/UpdatesWidget.qml index a44c0de..101e87e 100644 --- a/Modules/Bar/Components/UpdatesWidget.qml +++ b/Modules/Bar/Components/UpdatesWidget.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Bar.Components.Common diff --git a/Modules/Bar/Components/WindowTitle.qml b/Modules/Bar/Components/WindowTitle.qml index 7515093..3c3a0a8 100644 --- a/Modules/Bar/Components/WindowTitle.qml +++ b/Modules/Bar/Components/WindowTitle.qml @@ -17,7 +17,7 @@ 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.columnSpacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.rowSpacing * (bar.children.length - 1) - bar.vPadding * 4); + return horizontal ? (bar.width - otherSize - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.spacing * (bar.children.length - 1) - bar.vPadding * 4); } clip: true diff --git a/Modules/Bar/Popouts/AudioPopout.qml b/Modules/Bar/Popouts/AudioPopout.qml index 023bd68..5ec5f66 100644 --- a/Modules/Bar/Popouts/AudioPopout.qml +++ b/Modules/Bar/Popouts/AudioPopout.qml @@ -5,6 +5,7 @@ import Quickshell.Services.Pipewire import Quickshell.Widgets import QtQuick import QtQuick.Layouts +import ZShell.Components import QtQuick.Controls import ZShell.Config import qs.Components @@ -46,7 +47,8 @@ Item { anchors.verticalCenter: parent.verticalCenter } - component VolumesTab: ColumnLayout { + component VolumesTab: SnapLayout { +orientation: Qt.Vertical spacing: 12 CustomRect { @@ -56,14 +58,15 @@ Item { color: Colors.tPalette.m3surfaceContainer radius: root.rounding - vol.anchors.margins - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.bottomMargin: Tokens.padding.small anchors.fill: parent anchors.leftMargin: Tokens.padding.small anchors.rightMargin: Tokens.padding.small anchors.topMargin: Tokens.padding.small - RowLayout { + SnapLayout { Layout.fillHeight: true Layout.fillWidth: true @@ -81,7 +84,7 @@ Item { } } - RowLayout { + SnapLayout { spacing: Tokens.spacing.largeIncreased CustomMouseArea { @@ -153,14 +156,15 @@ Item { } } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.bottomMargin: Tokens.padding.small anchors.fill: parent anchors.leftMargin: Tokens.padding.small anchors.rightMargin: Tokens.padding.small anchors.topMargin: Tokens.padding.small - RowLayout { + SnapLayout { Layout.fillHeight: true Layout.fillWidth: true @@ -178,7 +182,7 @@ Item { } } - RowLayout { + SnapLayout { spacing: Tokens.spacing.largeIncreased CustomMouseArea { @@ -276,14 +280,15 @@ Item { text: Audio.getStreamName(appBox.modelData) } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.bottomMargin: Tokens.padding.small anchors.fill: parent anchors.leftMargin: Tokens.padding.small anchors.rightMargin: Tokens.padding.small anchors.topMargin: Tokens.padding.small - RowLayout { + SnapLayout { Layout.fillHeight: true Layout.fillWidth: true @@ -302,7 +307,7 @@ Item { } } - RowLayout { + SnapLayout { spacing: Tokens.spacing.largeIncreased CustomMouseArea { diff --git a/Modules/Bar/Popouts/NetworkPopout.qml b/Modules/Bar/Popouts/NetworkPopout.qml index f955d0f..79e2ab1 100644 --- a/Modules/Bar/Popouts/NetworkPopout.qml +++ b/Modules/Bar/Popouts/NetworkPopout.qml @@ -4,6 +4,7 @@ import Quickshell import Quickshell.Networking import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Modules @@ -14,7 +15,8 @@ Item { required property var wrapper - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout spacing: 8 diff --git a/Modules/Bar/Popouts/TrayMenuPopout.qml b/Modules/Bar/Popouts/TrayMenuPopout.qml index 4410c6f..058970c 100644 --- a/Modules/Bar/Popouts/TrayMenuPopout.qml +++ b/Modules/Bar/Popouts/TrayMenuPopout.qml @@ -4,6 +4,7 @@ import Quickshell import Quickshell.Widgets import QtQuick import QtQuick.Layouts +import ZShell.Components import QtQuick.Controls import QtQuick.Effects import qs.Components @@ -47,7 +48,8 @@ StackView { duration: 0 } } - component SubMenu: ColumnLayout { + component SubMenu: SnapLayout { +orientation: Qt.Vertical id: menu required property QsMenuHandle handle diff --git a/Modules/Bar/Popouts/UPowerPopout.qml b/Modules/Bar/Popouts/UPowerPopout.qml index 09c94e1..6fcbcbc 100644 --- a/Modules/Bar/Popouts/UPowerPopout.qml +++ b/Modules/Bar/Popouts/UPowerPopout.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell.Services.UPower import ZShell.Config import qs.Modules.Bar.Components.Common @@ -35,7 +36,7 @@ Column { Repeater { model: Battery.allPeripherals - RowLayout { + SnapLayout { id: layout required property var modelData diff --git a/Modules/Bar/Popouts/UpdatesPopout.qml b/Modules/Bar/Popouts/UpdatesPopout.qml index 3217de7..54b6d3c 100644 --- a/Modules/Bar/Popouts/UpdatesPopout.qml +++ b/Modules/Bar/Popouts/UpdatesPopout.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import ZShell.Config import qs.Components @@ -86,7 +87,7 @@ CustomRect { implicitWidth: 600 radius: root.radius - Tokens.padding.extraSmall - RowLayout { + SnapLayout { anchors.fill: parent anchors.leftMargin: Tokens.padding.small anchors.rightMargin: Tokens.padding.small @@ -96,7 +97,8 @@ CustomRect { text: "package_2" } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true CustomText { @@ -114,7 +116,7 @@ CustomRect { } } - RowLayout { + SnapLayout { Layout.fillHeight: true Layout.preferredWidth: 300 diff --git a/Modules/Clipboard/Content.qml b/Modules/Clipboard/Content.qml index 8fd5c62..be9d497 100644 --- a/Modules/Clipboard/Content.qml +++ b/Modules/Clipboard/Content.qml @@ -4,6 +4,7 @@ import Quickshell import QtQuick import QtQuick.Controls import QtQuick.Layouts +import ZShell.Components import qs.Components import qs.Helpers import ZShell.Config @@ -110,7 +111,7 @@ Item { Repeater { model: lineRow.modelData.text.split("\t").slice(1) - RowLayout { + SnapLayout { height: lineText.height width: lineText.height + Tokens.spacing.extraSmall @@ -224,7 +225,7 @@ Item { } } - RowLayout { + SnapLayout { anchors.fill: parent spacing: Tokens.spacing.small diff --git a/Modules/Dashboard/Content.qml b/Modules/Dashboard/Content.qml index 69b0c2f..8e89eb7 100644 --- a/Modules/Dashboard/Content.qml +++ b/Modules/Dashboard/Content.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import ZShell import qs.Components @@ -39,8 +40,8 @@ Item { ]; return allTabs.filter(tab => tab.enabled); } - readonly property real nonAnimHeight: tabs.implicitHeight + tabs.anchors.topMargin + view.implicitHeight + viewWrapper.anchors.margins + viewWrapper.anchors.topMargin - readonly property real nonAnimWidth: view.implicitWidth + viewWrapper.anchors.margins * 2 + readonly property real nonAnimHeight: ZUtils.snap(tabs.implicitHeight + tabs.anchors.topMargin + view.implicitHeight + viewWrapper.anchors.margins + viewWrapper.anchors.topMargin, root) + readonly property real nonAnimWidth: ZUtils.snap(view.implicitWidth + viewWrapper.anchors.margins * 2, root) required property ScreenState screenState implicitHeight: nonAnimHeight @@ -93,8 +94,8 @@ Item { } anchors.fill: parent - implicitHeight: currentItem?.implicitHeight ?? 0 - implicitWidth: currentItem?.implicitWidth ?? 0 + implicitHeight: currentItem?.height ?? currentItem?.implicitHeight ?? 0 + implicitWidth: currentItem?.width ?? currentItem?.implicitWidth ?? 0 Repeater { id: repeater diff --git a/Modules/Dashboard/Dash.qml b/Modules/Dashboard/Dash.qml index 4f61d07..a63f4a9 100644 --- a/Modules/Dashboard/Dash.qml +++ b/Modules/Dashboard/Dash.qml @@ -1,104 +1,82 @@ import Quickshell import QtQuick import QtQuick.Layouts +import ZShell +import ZShell.Config +import ZShell.Components import qs.Helpers import qs.Components import qs.Modules -import ZShell.Config import qs.Modules.Dashboard.Dash import qs.Services -GridLayout { +SnapLayout { +orientation: Qt.Vertical id: root readonly property bool dashboardVisible: screenState.dashboard required property int radius required property ScreenState screenState - columnSpacing: Tokens.spacing.small - rowSpacing: Tokens.spacing.small + spacing: ZUtils.snap(Tokens.spacing.small, root) - ParallelAnimation { - id: openAnim + height: ZUtils.snap(implicitHeight, root) + width: ZUtils.snap(implicitWidth, root) - Anim { - property: "opacity" - target: root - to: 1 - } - - Anim { - property: "scale" - target: root - to: 1 - } - } - - ParallelAnimation { - id: closeAnim - - Anim { - property: "opacity" - target: root - to: 0 - } - - Anim { - property: "scale" - target: root - to: 0.9 - } - } - - Rect { - Layout.column: 2 - Layout.columnSpan: 3 - Layout.preferredHeight: user.implicitHeight - Layout.preferredWidth: user.implicitWidth - radius: root.radius - - User { - id: user - - screenState: root.screenState - } - } - - Rect { - Layout.columnSpan: 2 - Layout.fillHeight: true - Layout.preferredWidth: Tokens.sizes.dashboard.weatherWidth - Layout.row: 0 - radius: root.radius - - Weather {} - } - - Rect { - Layout.column: 0 - Layout.columnSpan: 3 + SnapLayout { Layout.fillWidth: true - Layout.preferredHeight: calendar.implicitHeight - Layout.row: 1 - radius: root.radius + spacing: parent.spacing - Calendar { - id: calendar + Rect { + id: weatherRect + Layout.fillHeight: true + Layout.preferredWidth: ZUtils.snap(Tokens.sizes.dashboard.weatherWidth, root) + radius: root.radius - screenState: root.screenState + Weather {} + } + + Rect { + id: userRect + Layout.preferredHeight: ZUtils.snap(user.implicitHeight, root) + Layout.preferredWidth: ZUtils.snap(user.implicitWidth, root) + radius: root.radius + + User { + id: user + + screenState: root.screenState + } } } - Rect { - Layout.column: 3 - Layout.columnSpan: 2 - Layout.fillHeight: true - Layout.preferredWidth: resources.implicitWidth - Layout.row: 1 - radius: root.radius + SnapLayout { + Layout.fillWidth: true + spacing: parent.spacing - Resources { - id: resources + Rect { + id: calendarRect + Layout.fillWidth: true + Layout.fillHeight: true + implicitHeight: ZUtils.snap(calendar.implicitHeight, root) + radius: root.radius + + Calendar { + id: calendar + + screenState: root.screenState + } + } + + Rect { + id: resourcesRect + Layout.fillHeight: true + implicitWidth: ZUtils.snap(resources.implicitWidth, root) + radius: root.radius + + Resources { + id: resources + } } } diff --git a/Modules/Dashboard/Dash/Calendar.qml b/Modules/Dashboard/Dash/Calendar.qml index 9d198ef..c1e2ea8 100644 --- a/Modules/Dashboard/Dash/Calendar.qml +++ b/Modules/Dashboard/Dash/Calendar.qml @@ -4,6 +4,7 @@ import Quickshell import QtQuick import QtQuick.Controls import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services @@ -117,14 +118,15 @@ CustomMouseArea { } } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: inner anchors.fill: parent anchors.margins: Tokens.padding.large spacing: Tokens.spacing.extraSmall - RowLayout { + SnapLayout { id: monthNavigationRow Layout.fillWidth: true diff --git a/Modules/Dashboard/Dash/Resources.qml b/Modules/Dashboard/Dash/Resources.qml index 9b4a716..96e7a8f 100644 --- a/Modules/Dashboard/Dash/Resources.qml +++ b/Modules/Dashboard/Dash/Resources.qml @@ -1,5 +1,7 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components +import ZShell import ZShell.Services import ZShell.Config import qs.Components @@ -8,9 +10,8 @@ import qs.Services Item { id: root - anchors.bottom: parent.bottom - anchors.top: parent.top - implicitWidth: layout.implicitWidth + layout.anchors.margins * 4 + anchors.fill: parent + implicitWidth: ZUtils.snap(layout.implicitWidth + layout.anchors.margins * 2, root) ServiceRef { service: Storage @@ -28,13 +29,16 @@ Item { service: Gpu } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter anchors.margins: Tokens.padding.large anchors.top: parent.top + + x: ZUtils.snap((root.width - implicitWidth) / 2, root) + spacing: Tokens.spacing.medium Resource { @@ -73,12 +77,10 @@ Item { required property string icon - Layout.fillHeight: true - implicitSize: height + implicitSize: ZUtils.snap((root.height - layout.anchors.margins * 2 - layout.spacing * 4) / 5, root) Behavior on clampedVal { - Anim { - } + Anim {} } MaterialIcon { diff --git a/Modules/Dashboard/Media.qml b/Modules/Dashboard/Media.qml index 311114d..b37054c 100644 --- a/Modules/Dashboard/Media.qml +++ b/Modules/Dashboard/Media.qml @@ -1,6 +1,8 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import M3Shapes +import ZShell import ZShell.Config import qs.Modules.Dashboard.Media import qs.Components @@ -13,8 +15,8 @@ Item { property ScreenState screenState required property int radius - implicitWidth: 1000 - implicitHeight: 320 + implicitWidth: ZUtils.snap(1000, root) + implicitHeight: ZUtils.snap(320, root) ClipRect { anchors.fill: parent @@ -25,7 +27,7 @@ Item { } } - RowLayout { + SnapLayout { anchors.fill: parent anchors.margins: Tokens.padding.large spacing: Tokens.spacing.extraLarge @@ -94,7 +96,8 @@ Item { active: opacity > 0 opacity: 0 - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { +orientation: Qt.Vertical spacing: Tokens.spacing.small MaterialShape { @@ -140,11 +143,12 @@ Item { asynchronous: true active: opacity > 0 - sourceComponent: RowLayout { + sourceComponent: SnapLayout { spacing: Tokens.spacing.extraLarge Details { Layout.fillWidth: true + Layout.fillHeight: true } LyricsAndSelector { diff --git a/Modules/Dashboard/Media/Details.qml b/Modules/Dashboard/Media/Details.qml index 2d6c6c9..8b4490f 100644 --- a/Modules/Dashboard/Media/Details.qml +++ b/Modules/Dashboard/Media/Details.qml @@ -1,13 +1,14 @@ import QtQuick import QtQuick.Layouts import Quickshell.Services.Mpris +import ZShell import ZShell.Components import ZShell.Config import qs.Components import qs.Services import qs.Helpers -ColumnLayout { +Item { id: root readonly property bool hasUnknownLength: (Players.active?.length ?? 0) > 2147483647 @@ -25,46 +26,187 @@ ColumnLayout { return `${mins}:${secs}`; } - spacing: Tokens.spacing.extraSmall + implicitHeight: ZUtils.snap(layout.implicitHeight, root) + implicitWidth: layout.implicitWidth - Timer { - running: Players.active?.isPlaying ?? false - interval: Config.dashboard.mediaUpdateInterval - triggeredOnStart: true - repeat: true - onTriggered: Players.active?.positionChanged() - } + SnapLayout { +orientation: Qt.Vertical + id: layout + anchors.left: parent.left + anchors.right: parent.right + y: ZUtils.snap((parent.height - implicitHeight) / 2, root) - CustomText { - Layout.fillWidth: true - text: Players.active?.trackTitle ?? "" - font: Tokens.font.title.large - elide: Text.ElideRight - animate: true - } + spacing: ZUtils.snap(Tokens.spacing.extraSmall, root) - CustomText { - Layout.fillWidth: true - text: Players.active?.trackArtist || qsTr("Unknown artist") - color: Colors.palette.m3onSurfaceVariant - font: Tokens.font.title.medium - elide: Text.ElideRight - animate: true - } + Timer { + running: Players.active?.isPlaying ?? false + interval: Config.dashboard.mediaUpdateInterval + triggeredOnStart: true + repeat: true + onTriggered: Players.active?.positionChanged() + } - CustomText { - Layout.fillWidth: true - text: Players.active?.trackAlbum || qsTr("Unknown album") - color: Colors.palette.m3secondary - font: Tokens.font.title.medium - elide: Text.ElideRight - animate: true - } + CustomText { + id: title + Layout.fillWidth: true + Layout.preferredHeight: ZUtils.snapCeil(implicitHeight, root) + text: Players.active?.trackTitle ?? "" + font: Tokens.font.title.large + elide: Text.ElideRight + animate: true + } - RowLayout { - Layout.topMargin: Tokens.spacing.extraLargeIncreased - Layout.fillWidth: true - spacing: Tokens.spacing.small + CustomText { + id: artist + Layout.fillWidth: true + Layout.preferredHeight: ZUtils.snapCeil(implicitHeight, root) + text: Players.active?.trackArtist || qsTr("Unknown artist") + color: Colors.palette.m3onSurfaceVariant + font: Tokens.font.title.medium + elide: Text.ElideRight + animate: true + } + + CustomText { + id: album + Layout.fillWidth: true + Layout.preferredHeight: ZUtils.snapCeil(implicitHeight, root) + text: Players.active?.trackAlbum || qsTr("Unknown album") + color: Colors.palette.m3secondary + font: Tokens.font.title.medium + elide: Text.ElideRight + animate: true + } + + SnapLayout { + id: sliderLayout + Layout.topMargin: Tokens.spacing.extraLargeIncreased + Layout.fillWidth: true + spacing: ZUtils.snap(Tokens.spacing.small, root) + + CustomText { + id: positionLabel + + Layout.preferredWidth: ZUtils.snapCeil(timeMetrics.width, root) + Layout.preferredHeight: positionSlider.implicitHeight + text: root.lengthStr(Players.active?.position ?? -1) + color: Colors.palette.m3onSurfaceVariant + font: timeMetrics.font + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + CustomSlider { + id: positionSlider + + Layout.fillWidth: true + Layout.preferredHeight: ZUtils.snap(implicitHeight, root) + value: Players.active ? Players.active.position / (Players.active.length || 1) : 0 + enabled: (Players.active?.canSeek ?? false) && !root.hasUnknownLength + wavy: true + animateWave: Players.active?.isPlaying ?? false + waveFrequency: 5 + waveDuration: 2000 + interactionOnMove: false + onInteraction: value => { + const active = Players.active; + if (active?.canSeek && active?.positionSupported) + active.position = value * active.length; + } + + Binding { + target: positionLabel + property: "text" + value: root.lengthStr(positionSlider.pos * (Players.active?.length ?? 0)) + when: positionSlider.dragging + } + } + + CustomText { + Layout.preferredWidth: ZUtils.snapCeil(timeMetrics.width, root) + Layout.preferredHeight: positionSlider.implicitHeight + text: root.hasUnknownLength ? "--:--" : root.lengthStr(Players.active?.length ?? -1) + color: Colors.palette.m3onSurfaceVariant + font: timeMetrics.font + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + ButtonRow { + Layout.topMargin: Tokens.spacing.largeIncreased + Layout.fillWidth: true + spacing: Tokens.spacing.extraSmall + + IconButton { + type: IconButton.Tonal + icon: "shuffle" + isRound: true + shapeMorph: true + checked: Players.active?.shuffle ?? false + font: Tokens.font.icon.builders.medium.weight(Font.Medium).build() + enabled: Players.active?.shuffleSupported + onClicked: Players.active.shuffle = !Players.active?.shuffle + implicitWidth: Math.round(implicitHeight * 0.9) + } + + IconButton { + id: previousBtn + + type: IconButton.Tonal + icon: "skip_previous" + isRound: true + shapeMorph: true + font: Tokens.font.icon.large + enabled: Players.active?.canGoPrevious + onClicked: Players.active?.previous() + } + + IconButton { + id: playPauseBtn + + icon: Players.active?.isPlaying ? "pause" : "play_arrow" + isRound: true + shapeMorph: true + fillWidth: true + checked: Players.active?.isPlaying ?? false + font: Tokens.font.icon.large + enabled: Players.active?.canTogglePlaying + onClicked: Players.active?.togglePlaying() + } + + IconButton { + id: nextBtn + + type: IconButton.Tonal + icon: "skip_next" + isRound: true + shapeMorph: true + font: Tokens.font.icon.large + enabled: Players.active?.canGoNext + onClicked: Players.active?.next() + } + + IconButton { + type: IconButton.Tonal + icon: Players.active?.loopState === MprisLoopState.Track ? "repeat_one" : "repeat" + isRound: true + shapeMorph: true + checked: Players.active?.loopState === MprisLoopState.Track || Players.active?.loopState === MprisLoopState.Playlist + font: Tokens.font.icon.builders.medium.weight(Font.Medium).build() + enabled: Players.active?.loopSupported + onClicked: { + const state = Players.active.loopState; + if (state === MprisLoopState.None) + Players.active.loopState = MprisLoopState.Track; + else if (state === MprisLoopState.Track) + Players.active.loopState = MprisLoopState.Playlist; + else + Players.active.loopState = MprisLoopState.None; + } + implicitWidth: Math.round(implicitHeight * 0.9) + } + } TextMetrics { id: timeMetrics @@ -72,123 +214,5 @@ ColumnLayout { text: Players.active ? root.lengthStr(Math.max(Players.active.position, root.hasUnknownLength ? 0 : Players.active.length)).replace(/[1-9]/g, "0") : "00:00" font: Tokens.font.label.medium } - - CustomText { - id: positionLabel - - Layout.preferredWidth: timeMetrics.width - text: root.lengthStr(Players.active?.position ?? -1) - color: Colors.palette.m3onSurfaceVariant - font: timeMetrics.font - horizontalAlignment: Text.AlignHCenter - } - - CustomSlider { - id: positionSlider - - Layout.fillWidth: true - value: Players.active ? Players.active.position / (Players.active.length || 1) : 0 - enabled: (Players.active?.canSeek ?? false) && !root.hasUnknownLength - wavy: true - animateWave: Players.active?.isPlaying ?? false - waveFrequency: 5 - waveDuration: 2000 - interactionOnMove: false - onInteraction: value => { - const active = Players.active; - if (active?.canSeek && active?.positionSupported) - active.position = value * active.length; - } - - Binding { - target: positionLabel - property: "text" - value: root.lengthStr(positionSlider.pos * (Players.active?.length ?? 0)) - when: positionSlider.dragging - } - } - - CustomText { - Layout.preferredWidth: timeMetrics.width - text: root.hasUnknownLength ? "--:--" : root.lengthStr(Players.active?.length ?? -1) - color: Colors.palette.m3onSurfaceVariant - font: timeMetrics.font - horizontalAlignment: Text.AlignHCenter - } - } - - ButtonRow { - Layout.topMargin: Tokens.spacing.largeIncreased - Layout.fillWidth: true - spacing: Tokens.spacing.extraSmall - - IconButton { - type: IconButton.Tonal - icon: "shuffle" - isRound: true - shapeMorph: true - checked: Players.active?.shuffle ?? false - font: Tokens.font.icon.builders.medium.weight(Font.Medium).build() - enabled: Players.active?.shuffleSupported - onClicked: Players.active.shuffle = !Players.active?.shuffle - implicitWidth: Math.round(implicitHeight * 0.9) - } - - IconButton { - id: previousBtn - - type: IconButton.Tonal - icon: "skip_previous" - isRound: true - shapeMorph: true - font: Tokens.font.icon.large - enabled: Players.active?.canGoPrevious - onClicked: Players.active?.previous() - } - - IconButton { - id: playPauseBtn - - icon: Players.active?.isPlaying ? "pause" : "play_arrow" - isRound: true - shapeMorph: true - fillWidth: true - checked: Players.active?.isPlaying ?? false - font: Tokens.font.icon.large - enabled: Players.active?.canTogglePlaying - onClicked: Players.active?.togglePlaying() - } - - IconButton { - id: nextBtn - - type: IconButton.Tonal - icon: "skip_next" - isRound: true - shapeMorph: true - font: Tokens.font.icon.large - enabled: Players.active?.canGoNext - onClicked: Players.active?.next() - } - - IconButton { - type: IconButton.Tonal - icon: Players.active?.loopState === MprisLoopState.Track ? "repeat_one" : "repeat" - isRound: true - shapeMorph: true - checked: Players.active?.loopState === MprisLoopState.Track || Players.active?.loopState === MprisLoopState.Playlist - font: Tokens.font.icon.builders.medium.weight(Font.Medium).build() - enabled: Players.active?.loopSupported - onClicked: { - const state = Players.active.loopState; - if (state === MprisLoopState.None) - Players.active.loopState = MprisLoopState.Track; - else if (state === MprisLoopState.Track) - Players.active.loopState = MprisLoopState.Playlist; - else - Players.active.loopState = MprisLoopState.None; - } - implicitWidth: Math.round(implicitHeight * 0.9) - } } } diff --git a/Modules/Dashboard/Media/LyricList.qml b/Modules/Dashboard/Media/LyricList.qml index cdec3dc..56b612b 100644 --- a/Modules/Dashboard/Media/LyricList.qml +++ b/Modules/Dashboard/Media/LyricList.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Effects import QtQuick.Layouts +import ZShell.Components import ZShell.Config import ZShell.Services import qs.Components @@ -157,7 +158,8 @@ Item { active: opacity > 0 opacity: 0 - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { +orientation: Qt.Vertical spacing: Tokens.spacing.large CustomRect { @@ -198,7 +200,8 @@ Item { active: opacity > 0 opacity: 0 - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { +orientation: Qt.Vertical spacing: Tokens.spacing.small MaterialIcon { diff --git a/Modules/Dashboard/Media/LyricsAndSelector.qml b/Modules/Dashboard/Media/LyricsAndSelector.qml index 328cc5b..8abf990 100644 --- a/Modules/Dashboard/Media/LyricsAndSelector.qml +++ b/Modules/Dashboard/Media/LyricsAndSelector.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Services.Mpris import ZShell.Config @@ -8,14 +9,15 @@ import qs.Helpers import qs.Services Item { - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout anchors.fill: parent anchors.leftMargin: Tokens.padding.medium spacing: Tokens.spacing.medium - RowLayout { + SnapLayout { Layout.bottomMargin: -Tokens.spacing.medium spacing: Tokens.spacing.medium z: 1 diff --git a/Modules/Dashboard/Media/LyricsInfo.qml b/Modules/Dashboard/Media/LyricsInfo.qml index cc15f41..c82939f 100644 --- a/Modules/Dashboard/Media/LyricsInfo.qml +++ b/Modules/Dashboard/Media/LyricsInfo.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell import ZShell.Blobs import ZShell.Config @@ -141,7 +142,8 @@ Item { } ] - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout anchors.centerIn: parent diff --git a/Modules/Dashboard/Processes/ProcessesHeader.qml b/Modules/Dashboard/Processes/ProcessesHeader.qml index 307d4da..8182528 100644 --- a/Modules/Dashboard/Processes/ProcessesHeader.qml +++ b/Modules/Dashboard/Processes/ProcessesHeader.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import ZShell.Config import ZShell.Internal diff --git a/Modules/Dashboard/Processes/ProcessesList.qml b/Modules/Dashboard/Processes/ProcessesList.qml index d64b047..48b441f 100644 --- a/Modules/Dashboard/Processes/ProcessesList.qml +++ b/Modules/Dashboard/Processes/ProcessesList.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Widgets import ZShell.Config @@ -38,7 +39,7 @@ CustomListView { id: rowHover } - RowLayout { + SnapLayout { id: rowLayout anchors.left: parent.left diff --git a/Modules/Dashboard/Processes/SystemInfo.qml b/Modules/Dashboard/Processes/SystemInfo.qml index afaedce..5c311e8 100644 --- a/Modules/Dashboard/Processes/SystemInfo.qml +++ b/Modules/Dashboard/Processes/SystemInfo.qml @@ -23,7 +23,7 @@ Item { service: Memory } - RowLayout { + SnapLayout { id: layout anchors.fill: parent spacing: Tokens.spacing.medium @@ -60,13 +60,14 @@ Item { Layout.fillHeight: true implicitHeight: mainLayout.implicitHeight + mainLayout.anchors.margins * 2 - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: mainLayout anchors.fill: parent anchors.margins: Tokens.padding.large spacing: 0 - RowLayout { + SnapLayout { spacing: Tokens.spacing.small MaterialIcon { @@ -131,7 +132,8 @@ Item { } } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: infoColumn anchors.right: parent.right anchors.bottom: parent.bottom diff --git a/Modules/Dashboard/Tabs.qml b/Modules/Dashboard/Tabs.qml index 56234fa..c2a1aef 100644 --- a/Modules/Dashboard/Tabs.qml +++ b/Modules/Dashboard/Tabs.qml @@ -4,6 +4,8 @@ import QtQuick import QtQuick.Layouts import QtQuick.Templates import Quickshell +import ZShell +import ZShell.Components import ZShell.Config import qs.Components import qs.Services @@ -16,9 +18,17 @@ Item { required property var tabs readonly property alias count: bar.count - readonly property int tabIndicatorSpacing: Tokens.spacing.small + readonly property int tabIndicatorSpacing: ZUtils.snap(Tokens.spacing.small, root) - implicitHeight: bar.implicitHeight + bar.anchors.topMargin + indicator.implicitHeight + indicator.anchors.topMargin + separator.implicitHeight + function snapLayoutHeight(v) { + const dpr = ZUtils.dprFor(root); + let h = Math.ceil(v); + while (Math.abs(h * dpr - Math.round(h * dpr)) > 1e-6) + ++h; + return h; + } + + implicitHeight: ZUtils.snap(bar.implicitHeight + bar.anchors.topMargin + indicator.implicitHeight + indicator.anchors.topMargin + separator.implicitHeight, root) TabBar { id: bar @@ -31,9 +41,11 @@ Item { currentIndex: root.screenState.dashboardTab onCurrentIndexChanged: root.screenState.dashboardTab = currentIndex - implicitHeight: contentHeight + topPadding: 0 + bottomPadding: 0 + implicitHeight: implicitContentHeight background: null - contentItem: RowLayout { + contentItem: SnapLayout { spacing: 0 Repeater { @@ -116,10 +128,13 @@ Item { readonly property bool current: TabBar.tabBar.currentItem === this Layout.fillWidth: true - Layout.preferredWidth: 1 // Uniform width across all tabs + Layout.fillHeight: true + Layout.preferredWidth: 1 implicitWidth: implicitContentWidth implicitHeight: implicitContentHeight background: null + topPadding: 0 + bottomPadding: 0 contentItem: CustomMouseArea { id: mouse @@ -131,8 +146,8 @@ Item { root.screenState.dashboardTab = Math.max(root.screenState.dashboardTab - 1, 0); } - implicitWidth: Math.max(icon.width, label.width) - implicitHeight: icon.height + label.height + implicitWidth: Math.max(icon.implicitWidth, label.implicitWidth) + implicitHeight: snapLayout.implicitHeight hoverEnabled: true cursorShape: Qt.PointingHandCursor @@ -146,39 +161,49 @@ Item { anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - implicitHeight: parent.height + root.tabIndicatorSpacing * 2 + anchors.alignWhenCentered: false + implicitHeight: ZUtils.snap(parent.height + Tokens.sizes.dashboard.tabIndicatorSpacing * 2, stateLayer) radius: Tokens.rounding.medium color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurface - onClicked: root.screenState.dashboardTab = tab.TabBar.index - } - - MaterialIcon { - id: icon - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: label.top - - text: tab.iconName - color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant - fill: tab.current ? 1 : 0 - fontStyle: Tokens.font.icon.medium - - Behavior on fill { - Anim { - type: Anim.DefaultEffects - } + onClicked: { + root.screenState.dashboardTab = tab.TabBar.index; } } - CustomText { - id: label + SnapLayout { + id: snapLayout + anchors.fill: parent + spacing: 0 + orientation: Qt.Vertical - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom + MaterialIcon { + id: icon - text: tab.text - color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant + text: tab.iconName + color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant + fill: tab.current ? 1 : 0 + fontStyle: Tokens.font.icon.medium + + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + + Behavior on fill { + Anim { + type: Anim.DefaultEffects + } + } + } + + CustomText { + id: label + + text: tab.text + color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant + + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + } } } } diff --git a/Modules/Dashboard/Weather/Graphs.qml b/Modules/Dashboard/Weather/Graphs.qml index f0ac43d..dc0d58b 100644 --- a/Modules/Dashboard/Weather/Graphs.qml +++ b/Modules/Dashboard/Weather/Graphs.qml @@ -1,11 +1,13 @@ import QtQuick import QtQuick.Layouts +import ZShell +import ZShell.Components import ZShell.Config import qs.Components import qs.Services import qs.Helpers -RowLayout { +SnapLayout { id: root spacing: Tokens.spacing.largeIncreased @@ -20,7 +22,7 @@ RowLayout { readonly property real markerX: { const d = root.now; - return d.getHours() + d.getMinutes() / 60; + return ZUtils.snap(d.getHours() + d.getMinutes() / 60, root); } function formatHour(h) { @@ -39,11 +41,13 @@ RowLayout { onTriggered: root.now = new Date() } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true + Layout.fillHeight: true Layout.preferredWidth: root.width / 2 - RowLayout { + SnapLayout { Layout.fillWidth: true MaterialIcon { @@ -90,11 +94,13 @@ RowLayout { } } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true + Layout.fillHeight: true Layout.preferredWidth: root.width / 2 - RowLayout { + SnapLayout { Layout.fillWidth: true MaterialIcon { diff --git a/Modules/Dashboard/WeatherTab.qml b/Modules/Dashboard/WeatherTab.qml index 7069abb..b40592f 100644 --- a/Modules/Dashboard/WeatherTab.qml +++ b/Modules/Dashboard/WeatherTab.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell.Components import qs.Components import qs.Modules.Dashboard.Weather import qs.Services @@ -18,13 +19,14 @@ Item { implicitHeight: layout.implicitHeight Component.onCompleted: Weather.reload() - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout anchors.fill: parent spacing: Tokens.spacing.medium - RowLayout { + SnapLayout { Layout.leftMargin: Tokens.padding.large Layout.rightMargin: Tokens.padding.large Layout.fillWidth: true @@ -82,7 +84,7 @@ Item { } } - RowLayout { + SnapLayout { Layout.fillWidth: true spacing: Tokens.spacing.medium @@ -121,7 +123,9 @@ Item { color: Colors.palette.m3onSurface } - RowLayout { + SnapLayout { + id: forecastLayout + Layout.fillWidth: true spacing: Tokens.spacing.medium @@ -137,12 +141,14 @@ Item { required property var modelData Layout.fillWidth: true + Layout.fillHeight: true implicitHeight: forecastItemColumn.implicitHeight + Tokens.padding.medium * 2 radius: root.radius color: Colors.tPalette.m3surfaceContainer - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: forecastItemColumn anchors.centerIn: parent @@ -196,7 +202,8 @@ Item { property color colour Layout.fillWidth: true - Layout.preferredHeight: 60 + Layout.fillHeight: true + implicitHeight: 60 radius: Tokens.rounding.medium color: Colors.tPalette.m3surfaceContainer @@ -230,7 +237,7 @@ Item { } } - component WeatherStat: RowLayout { + component WeatherStat: SnapLayout { id: weatherStat property string icon diff --git a/Modules/DesktopIcons/BackgroundContextMenu.qml b/Modules/DesktopIcons/BackgroundContextMenu.qml index 92a3347..05b7a38 100644 --- a/Modules/DesktopIcons/BackgroundContextMenu.qml +++ b/Modules/DesktopIcons/BackgroundContextMenu.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Widgets import Quickshell.Hyprland @@ -43,7 +44,8 @@ Item { } opacity: root.visible ? 1 : 0 - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: menuLayout anchors.centerIn: parent spacing: 0 @@ -53,7 +55,7 @@ Item { radius: popupBackground.radius - popupBackground.padding implicitHeight: openTerminalRow.implicitHeight + Tokens.padding.extraSmall * 2 - RowLayout { + SnapLayout { id: openTerminalRow spacing: 8 anchors.fill: parent @@ -92,7 +94,7 @@ Item { radius: popupBackground.radius - popupBackground.padding implicitHeight: settingsRow.implicitHeight + Tokens.padding.extraSmall * 2 - RowLayout { + SnapLayout { id: settingsRow spacing: 8 anchors.fill: parent @@ -132,7 +134,7 @@ Item { radius: popupBackground.radius - popupBackground.padding implicitHeight: logoutRow.implicitHeight + Tokens.padding.extraSmall * 2 - RowLayout { + SnapLayout { id: logoutRow spacing: 8 anchors.fill: parent @@ -171,7 +173,7 @@ Item { // radius: popupBackground.radius - popupBackground.padding // implicitHeight: desktopIconsRow.implicitHeight + Tokens.padding.extraSmall * 2 // - // RowLayout { + // SnapLayout { // id: desktopIconsRow // spacing: 8 // anchors.fill: parent diff --git a/Modules/DesktopIcons/DesktopIconContextMenu.qml b/Modules/DesktopIcons/DesktopIconContextMenu.qml index ea043f1..7a5c6b7 100644 --- a/Modules/DesktopIcons/DesktopIconContextMenu.qml +++ b/Modules/DesktopIcons/DesktopIconContextMenu.qml @@ -3,6 +3,7 @@ import QtQuick.Layouts import Quickshell import Quickshell.Widgets import qs.Components +import ZShell.Components import ZShell.Config import qs.Services @@ -57,22 +58,25 @@ Item { Anim {} } - ColumnLayout { + SnapLayout { id: menuLayout anchors.centerIn: parent + spacing: 0 + orientation: Qt.Vertical CustomRect { Layout.preferredWidth: 160 implicitHeight: openRow.implicitHeight + Tokens.padding.extraSmall * 2 radius: popupBackground.radius - popupBackground.padding - RowLayout { + SnapLayout { id: openRow anchors.fill: parent anchors.leftMargin: Tokens.padding.small + spacing: 8 MaterialIcon { @@ -111,11 +115,12 @@ Item { implicitHeight: openWithRow.implicitHeight + Tokens.padding.extraSmall * 2 radius: popupBackground.radius - popupBackground.padding - RowLayout { + SnapLayout { id: openWithRow anchors.fill: parent anchors.leftMargin: Tokens.padding.small + spacing: 8 MaterialIcon { @@ -156,11 +161,12 @@ Item { implicitHeight: copyPathRow.implicitHeight + Tokens.padding.extraSmall * 2 radius: popupBackground.radius - popupBackground.padding - RowLayout { + SnapLayout { id: copyPathRow anchors.fill: parent anchors.leftMargin: Tokens.padding.small + spacing: 8 MaterialIcon { @@ -190,11 +196,12 @@ Item { radius: popupBackground.radius - popupBackground.padding visible: contextMenu.targetPaths.length === 1 - RowLayout { + SnapLayout { id: renameRow anchors.fill: parent anchors.leftMargin: Tokens.padding.small + spacing: 8 MaterialIcon { @@ -231,11 +238,12 @@ Item { implicitHeight: deleteRow.implicitHeight + Tokens.padding.extraSmall * 2 radius: popupBackground.radius - popupBackground.padding - RowLayout { + SnapLayout { id: deleteRow anchors.fill: parent anchors.leftMargin: Tokens.padding.small + spacing: 8 MaterialIcon { diff --git a/Modules/Dock/Parts/DockAppButton.qml b/Modules/Dock/Parts/DockAppButton.qml index d6ca2f0..3a5db6d 100644 --- a/Modules/Dock/Parts/DockAppButton.qml +++ b/Modules/Dock/Parts/DockAppButton.qml @@ -4,6 +4,7 @@ import Quickshell import Quickshell.Widgets import qs.Components import qs.Helpers +import ZShell.Components import ZShell.Config import qs.Services @@ -29,7 +30,10 @@ CustomRect { active: !isSeparator anchors.centerIn: parent - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical + IconImage { id: icon @@ -38,8 +42,9 @@ CustomRect { source: Quickshell.iconPath(AppSearch.guessIcon(appToplevel?.appId), "image-missing") } - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignHCenter + spacing: 3 Repeater { diff --git a/Modules/Dock/Parts/DockSeparator.qml b/Modules/Dock/Parts/DockSeparator.qml index fac6f04..b13870f 100644 --- a/Modules/Dock/Parts/DockSeparator.qml +++ b/Modules/Dock/Parts/DockSeparator.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services diff --git a/Modules/Launcher/AppList.qml b/Modules/Launcher/AppList.qml index 5ff38f6..50712f2 100644 --- a/Modules/Launcher/AppList.qml +++ b/Modules/Launcher/AppList.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import Quickshell +import ZShell import ZShell.Config import qs.Components import qs.Services @@ -52,7 +53,7 @@ CustomListView { highlightFollowsCurrentItem: false highlightRangeMode: ListView.ApplyRange - implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing + implicitHeight: (Tokens.sizes.launcher.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing orientation: Qt.Vertical preferredHighlightBegin: 0 preferredHighlightEnd: height @@ -97,6 +98,7 @@ CustomListView { } } highlight: CustomRect { + id: hl color: Colors.palette.m3onSurface implicitHeight: root.currentItem?.implicitHeight ?? 0 implicitWidth: root.width diff --git a/Modules/Launcher/CarouselView.qml b/Modules/Launcher/CarouselView.qml index 3db4299..ecb5d10 100755 --- a/Modules/Launcher/CarouselView.qml +++ b/Modules/Launcher/CarouselView.qml @@ -22,7 +22,7 @@ CarouselView { delegateProperties: ({ screenState: root.screenState }) - focalWidth: Config.launcher.sizes.wallpaperWidth + focalWidth: Tokens.sizes.launcher.wallpaperWidth glideDuration: 250 glideEasingType: Easing.OutCubic implicitHeight: tileHeight + Tokens.spacing.small / 2 + Tokens.padding.large + Tokens.padding.small @@ -41,8 +41,7 @@ CarouselView { tileHeight: focalWidth / 16 * 9 delegate: Component { - WallpaperTile { - } + WallpaperTile {} } Component.onDestruction: Wallpapers.stopPreview() diff --git a/Modules/Launcher/Content.qml b/Modules/Launcher/Content.qml index 4db1508..9e86c49 100644 --- a/Modules/Launcher/Content.qml +++ b/Modules/Launcher/Content.qml @@ -2,17 +2,18 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick +import ZShell +import ZShell.Config import qs.Modules.Launcher.Services import qs.Components import qs.Helpers -import ZShell.Config import qs.Services Item { id: root required property real maxHeight - readonly property int padding: Tokens.padding.largeIncreased / 4 + readonly property int padding: ZUtils.snap(Tokens.padding.medium / 2, root) required property var panels readonly property int rounding: Tokens.rounding.largeIncreased required property ScreenState screenState diff --git a/Modules/Launcher/ContentList.qml b/Modules/Launcher/ContentList.qml index 54093de..48f1919 100644 --- a/Modules/Launcher/ContentList.qml +++ b/Modules/Launcher/ContentList.qml @@ -2,11 +2,12 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick +import ZShell +import ZShell.Config import qs.Paths import qs.Modules import qs.Components import qs.Helpers -import ZShell.Config import qs.Services Item { @@ -71,7 +72,7 @@ Item { PropertyChanges { appList.active: true root.implicitHeight: Math.min(root.maxHeight, appList.implicitHeight > 0 ? appList.implicitHeight : empty.implicitHeight) - root.implicitWidth: Config.launcher.sizes.itemWidth + root.implicitWidth: Tokens.sizes.launcher.itemWidth } AnchorChanges { @@ -83,8 +84,8 @@ Item { name: "wallpapers" PropertyChanges { - root.implicitHeight: Config.launcher.sizes.wallpaperHeight - root.implicitWidth: Math.max(Config.launcher.sizes.itemWidth * 1.2, wallpaperList.implicitWidth) + root.implicitHeight: Tokens.sizes.launcher.wallpaperHeight + root.implicitWidth: Math.max(Tokens.sizes.launcher.itemWidth * 1.2, wallpaperList.implicitWidth) wallpaperList.active: true } } diff --git a/Modules/Launcher/Items/ActionItem.qml b/Modules/Launcher/Items/ActionItem.qml index 30f0004..774e7bc 100644 --- a/Modules/Launcher/Items/ActionItem.qml +++ b/Modules/Launcher/Items/ActionItem.qml @@ -13,7 +13,7 @@ Item { anchors.left: parent?.left anchors.right: parent?.right - implicitHeight: Config.launcher.sizes.itemHeight + implicitHeight: Tokens.sizes.launcher.itemHeight StateLayer { radius: Tokens.rounding.medium diff --git a/Modules/Launcher/Items/AppItem.qml b/Modules/Launcher/Items/AppItem.qml index c93a8e5..fa29ecc 100644 --- a/Modules/Launcher/Items/AppItem.qml +++ b/Modules/Launcher/Items/AppItem.qml @@ -1,10 +1,13 @@ import Quickshell import Quickshell.Widgets import QtQuick +import QtQuick.Layouts +import ZShell.Config +import ZShell.Components +import ZShell import qs.Modules.Launcher.Services import qs.Components import qs.Helpers -import ZShell.Config import qs.Modules import qs.Services @@ -16,53 +19,72 @@ Item { anchors.left: parent?.left anchors.right: parent?.right - implicitHeight: Config.launcher.sizes.itemHeight + implicitHeight: ZUtils.snap(Tokens.sizes.launcher.itemHeight, root) StateLayer { radius: Tokens.rounding.medium onClicked: { - Apps.launch(root.modelData); - root.screenState.launcher = false; + // Apps.launch(root.modelData); + // root.screenState.launcher = false; + + ZUtils.logPlacement(icon, "icon"); + ZUtils.logPlacement(name, "name"); + ZUtils.logPlacement(favoriteIcon, "favoriteIcon"); + ZUtils.logPlacement(comment, "comment"); + ZUtils.logPlacement(text, "text"); + ZUtils.logPlacement(mainLayout, "main"); } } - Item { + SnapLayout { + id: mainLayout anchors.fill: parent anchors.leftMargin: Tokens.padding.medium - anchors.margins: Tokens.padding.small anchors.rightMargin: Tokens.padding.medium + spacing: Tokens.spacing.medium IconImage { id: icon - anchors.verticalCenter: parent.verticalCenter - implicitSize: parent.height + implicitSize: parent.height - Tokens.padding.small * 2 source: Quickshell.iconPath(root.modelData?.icon, "image-missing") } - Item { - anchors.left: icon.right - anchors.leftMargin: Tokens.spacing.medium - anchors.verticalCenter: icon.verticalCenter - implicitHeight: name.implicitHeight + comment.implicitHeight - implicitWidth: parent.width - icon.width + SnapLayout { + id: text + + Layout.fillHeight: true + Layout.fillWidth: true + Layout.topMargin: Tokens.padding.extraSmall + Layout.bottomMargin: Tokens.padding.extraSmall + + orientation: Qt.Vertical + spacing: 0 CustomText { id: name + Layout.fillHeight: true + Layout.fillWidth: true + text: root.modelData?.name ?? "" + verticalAlignment: CustomText.AlignVCenter + horizontalAlignment: CustomText.AlignLeft } CustomText { id: comment - anchors.top: name.bottom + Layout.fillHeight: true + Layout.fillWidth: true + color: Colors.palette.m3outline elide: Text.ElideRight font: Tokens.font.body.small text: (root.modelData?.comment || root.modelData?.genericName || root.modelData?.name) ?? "" - width: root.width - icon.width - Tokens.rounding.medium - Tokens.padding.medium * 2 + verticalAlignment: CustomText.AlignVCenter + horizontalAlignment: CustomText.AlignLeft } } @@ -70,14 +92,16 @@ Item { id: favoriteIcon active: root.modelData && Strings.testRegexList(Config.launcher.favoriteApps, root.modelData.id) - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter + Layout.fillHeight: true + asynchronous: true sourceComponent: MaterialIcon { color: Colors.palette.m3primary fill: 1 text: "favorite" + + verticalAlignment: MaterialIcon.AlignVCenter } } } diff --git a/Modules/Launcher/Items/CalcItem.qml b/Modules/Launcher/Items/CalcItem.qml index c52d71a..6f3d394 100644 --- a/Modules/Launcher/Items/CalcItem.qml +++ b/Modules/Launcher/Items/CalcItem.qml @@ -2,6 +2,7 @@ import ZShell import Quickshell import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import qs.Modules import qs.Helpers @@ -31,7 +32,7 @@ Item { } } - RowLayout { + SnapLayout { anchors.left: parent.left anchors.margins: Tokens.padding.small anchors.right: parent.right diff --git a/Modules/Lock/Center.qml b/Modules/Lock/Center.qml index c682ef2..d9409b1 100644 --- a/Modules/Lock/Center.qml +++ b/Modules/Lock/Center.qml @@ -2,14 +2,15 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Config +import ZShell.Components import qs.Paths import qs.Components import qs.Helpers -import ZShell.Config import qs.Modules import qs.Services -ColumnLayout { +SnapLayout { id: root readonly property real centerScale: Math.min(1, (lock.screen?.height ?? 1440) / 1440) @@ -19,10 +20,13 @@ ColumnLayout { Layout.fillHeight: true Layout.fillWidth: false Layout.preferredWidth: centerWidth + + orientation: Qt.Vertical spacing: Tokens.spacing.largeIncreased * 2 - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignHCenter + spacing: Tokens.spacing.small CustomText { @@ -109,11 +113,12 @@ ColumnLayout { } } - RowLayout { + SnapLayout { id: input anchors.fill: parent anchors.margins: Tokens.padding.extraSmall + spacing: Tokens.spacing.medium Item { diff --git a/Modules/Lock/Content.qml b/Modules/Lock/Content.qml index 1d8e734..7986939 100644 --- a/Modules/Lock/Content.qml +++ b/Modules/Lock/Content.qml @@ -1,8 +1,9 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components +import ZShell.Config import qs.Components import qs.Helpers -import ZShell.Config import qs.Services ClipRect { @@ -14,15 +15,18 @@ ClipRect { implicitWidth: layout.implicitWidth radius: Tokens.rounding.largeIncreased - RowLayout { + SnapLayout { id: layout anchors.fill: parent + spacing: Tokens.spacing.largeIncreased * 2 - ColumnLayout { + SnapLayout { Layout.fillWidth: true + spacing: Tokens.spacing.medium + orientation: Qt.Vertical WeatherInfo { id: weather @@ -50,9 +54,11 @@ ClipRect { lock: root.lock } - ColumnLayout { + SnapLayout { Layout.fillWidth: true + spacing: Tokens.spacing.medium + orientation: Qt.Vertical CustomRect { Layout.fillHeight: true diff --git a/Modules/Lock/InputField.qml b/Modules/Lock/InputField.qml index c7ac527..49398a1 100644 --- a/Modules/Lock/InputField.qml +++ b/Modules/Lock/InputField.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Modules import qs.Components import qs.Helpers diff --git a/Modules/Lock/Media.qml b/Modules/Lock/Media.qml index 0d08f40..4d8de5e 100644 --- a/Modules/Lock/Media.qml +++ b/Modules/Lock/Media.qml @@ -43,14 +43,16 @@ ClipRect { } } - ColumnLayout { + SnapLayout { id: layout anchors.left: parent.left anchors.margins: Tokens.padding.extraLarge anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical CustomText { Layout.fillWidth: true diff --git a/Modules/Lock/NotifDock.qml b/Modules/Lock/NotifDock.qml index af8ed98..0af1316 100644 --- a/Modules/Lock/NotifDock.qml +++ b/Modules/Lock/NotifDock.qml @@ -4,20 +4,23 @@ import Quickshell import Quickshell.Widgets import QtQuick import QtQuick.Layouts +import ZShell.Components +import ZShell.Config import qs.Modules import qs.Components import qs.Helpers -import ZShell.Config import qs.Daemons import qs.Services -ColumnLayout { +SnapLayout { id: root required property var lock anchors.fill: parent anchors.margins: Tokens.padding.large + + orientation: Qt.Vertical spacing: Tokens.spacing.small CustomText { @@ -46,8 +49,9 @@ ColumnLayout { duration: Tokens.anim.durations.extraLarge } } - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { spacing: Tokens.spacing.largeIncreased + orientation: Qt.Vertical Image { asynchronous: true diff --git a/Modules/Lock/NotifGroup.qml b/Modules/Lock/NotifGroup.qml index 12eeab1..27a79e9 100644 --- a/Modules/Lock/NotifGroup.qml +++ b/Modules/Lock/NotifGroup.qml @@ -5,10 +5,11 @@ import Quickshell.Widgets import Quickshell.Services.Notifications import QtQuick import QtQuick.Layouts +import ZShell.Components +import ZShell.Config import qs.Modules import qs.Components import qs.Helpers -import ZShell.Config import qs.Daemons import qs.Services @@ -36,13 +37,14 @@ CustomRect { } } - RowLayout { + SnapLayout { id: content anchors.left: parent.left anchors.margins: Tokens.padding.small anchors.right: parent.right anchors.top: parent.top + spacing: Tokens.spacing.medium Item { @@ -118,15 +120,18 @@ CustomRect { } } - ColumnLayout { + SnapLayout { Layout.bottomMargin: -Tokens.padding.extraSmall / 2 - (root.expanded ? 0 : spacing) Layout.fillWidth: true Layout.topMargin: -Tokens.padding.extraSmall - spacing: Math.round(Tokens.spacing.small / 2) - RowLayout { + spacing: Math.round(Tokens.spacing.small / 2) + orientation: Qt.Vertical + + SnapLayout { Layout.bottomMargin: -parent.spacing Layout.fillWidth: true + spacing: Tokens.spacing.small CustomText { @@ -167,10 +172,11 @@ CustomRect { } } - RowLayout { + SnapLayout { id: expandBtn anchors.centerIn: parent + spacing: Tokens.spacing.small / 2 CustomText { @@ -261,7 +267,10 @@ CustomRect { Behavior on opacity { Anim {} } - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { + orientation: Qt.Vertical + spacing: Tokens.spacing.extraSmall + Repeater { model: ScriptModel { values: root.notifs.slice(Config.notifs.groupPreviewNum) diff --git a/Modules/Lock/Resources.qml b/Modules/Lock/Resources.qml index 7ce6c90..04524c0 100644 --- a/Modules/Lock/Resources.qml +++ b/Modules/Lock/Resources.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import M3Shapes import ZShell.Services import ZShell.Config +import ZShell.Components import qs.Components import qs.Effects import qs.Services @@ -33,11 +34,12 @@ CustomRect { service: Storage } - RowLayout { + SnapLayout { id: layout anchors.fill: parent anchors.margins: Tokens.padding.large + spacing: Tokens.spacing.largeIncreased Resource { diff --git a/Modules/Lock/Weather/BriefInfo.qml b/Modules/Lock/Weather/BriefInfo.qml index cd92521..eaa4e10 100644 --- a/Modules/Lock/Weather/BriefInfo.qml +++ b/Modules/Lock/Weather/BriefInfo.qml @@ -1,11 +1,13 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Helpers import qs.Services -ColumnLayout { +SnapLayout { +orientation: Qt.Vertical id: root required property int rootHeight @@ -20,7 +22,7 @@ ColumnLayout { text: Weather.description } - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignHCenter spacing: Tokens.spacing.small diff --git a/Modules/Lock/Weather/Forecast.qml b/Modules/Lock/Weather/Forecast.qml index dd8cf82..c6476ab 100644 --- a/Modules/Lock/Weather/Forecast.qml +++ b/Modules/Lock/Weather/Forecast.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import M3Shapes import ZShell import qs.Components @@ -14,7 +15,7 @@ CustomRect { implicitHeight: header.anchors.margins + header.implicitHeight + Tokens.spacing.small + layout.implicitHeight + layout.anchors.bottomMargin radius: Tokens.rounding.small - RowLayout { + SnapLayout { id: header anchors.left: parent.left @@ -49,7 +50,8 @@ CustomRect { orientation: VerticalFadeListView.Horizontal spacing: Tokens.spacing.medium - delegate: ColumnLayout { + delegate: SnapLayout { +orientation: Qt.Vertical id: hour readonly property var cond: modelData diff --git a/Modules/Osd/Content.qml b/Modules/Osd/Content.qml index e1ac3d9..944d45c 100644 --- a/Modules/Osd/Content.qml +++ b/Modules/Osd/Content.qml @@ -2,9 +2,11 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell +import ZShell.Config +import ZShell.Components import qs.Components import qs.Helpers -import ZShell.Config import qs.Daemons import qs.Services @@ -19,14 +21,17 @@ Item { required property ScreenState screenState required property real volume - implicitHeight: layout.implicitHeight + Tokens.padding.smaller * 2 - implicitWidth: layout.implicitWidth + Tokens.padding.smaller * 2 + implicitHeight: layout.implicitHeight + layout.anchors.margins * 2 + implicitWidth: layout.implicitWidth + layout.anchors.margins * 2 - ColumnLayout { + SnapLayout { id: layout - anchors.centerIn: parent + anchors.fill: parent + anchors.margins: Tokens.padding.extraSmall + spacing: Tokens.spacing.medium + orientation: Qt.Vertical // Speaker volume CustomMouseArea { @@ -37,8 +42,8 @@ Item { Audio.decrementVolume(); } - implicitHeight: Config.osd.sizes.sliderHeight - implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: ZUtils.snap(Config.osd.sizes.sliderHeight, root) + implicitWidth: ZUtils.snap(Config.osd.sizes.sliderWidth, root) FilledSlider { anchors.fill: parent @@ -63,8 +68,8 @@ Item { Audio.decrementSourceVolume(); } - implicitHeight: Config.osd.sizes.sliderHeight - implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: ZUtils.snap(Config.osd.sizes.sliderHeight, root) + implicitWidth: ZUtils.snap(Config.osd.sizes.sliderWidth, root) FilledSlider { anchors.fill: parent @@ -93,8 +98,8 @@ Item { monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); } - implicitHeight: Config.osd.sizes.sliderHeight - implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: ZUtils.snap(Config.osd.sizes.sliderHeight, root) + implicitWidth: ZUtils.snap(Config.osd.sizes.sliderWidth, root) FilledSlider { anchors.fill: parent @@ -131,8 +136,7 @@ Item { } } Behavior on opacity { - Anim { - } + Anim {} } } } diff --git a/Modules/Osd/Wrapper.qml b/Modules/Osd/Wrapper.qml index e388beb..9779edc 100644 --- a/Modules/Osd/Wrapper.qml +++ b/Modules/Osd/Wrapper.qml @@ -2,9 +2,10 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick +import ZShell +import ZShell.Config import qs.Components import qs.Helpers -import ZShell.Config import qs.Daemons Item { @@ -30,8 +31,8 @@ Item { } anchors.rightMargin: (-implicitWidth - 5 - sidebarOffset) * offsetScale - implicitHeight: content.implicitHeight - implicitWidth: content.implicitWidth + implicitHeight: ZUtils.snap(content.implicitHeight, root) + implicitWidth: ZUtils.snap(content.implicitWidth, root) opacity: 1 - offsetScale visible: offsetScale < 1 @@ -98,8 +99,7 @@ Item { id: content active: root.shouldBeActive || root.visible - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter + anchors.fill: parent sourceComponent: Content { brightness: root.brightness diff --git a/Modules/Polkit/Polkit.qml b/Modules/Polkit/Polkit.qml index c598cd5..10e3006 100644 --- a/Modules/Polkit/Polkit.qml +++ b/Modules/Polkit/Polkit.qml @@ -83,13 +83,16 @@ Scope { opacity: 0 radius: Tokens.rounding.small * 2 - ColumnLayout { + SnapLayout { id: layout anchors.fill: parent anchors.margins: Tokens.padding.medium - RowLayout { + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical + + SnapLayout { id: contentRow spacing: 24 @@ -120,12 +123,15 @@ Scope { } } - ColumnLayout { + SnapLayout { id: contentColumn Layout.fillHeight: true Layout.fillWidth: true + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical + CustomText { Layout.alignment: Qt.AlignLeft Layout.preferredWidth: Math.min(600, contentWidth) @@ -210,13 +216,15 @@ Scope { } } - ColumnLayout { + SnapLayout { id: textDetailsColumn anchors.fill: parent anchors.margins: Tokens.padding.small opacity: 0 + spacing: Tokens.spacing.small + orientation: Qt.Vertical CustomText { text: `actionId: ${polkitAgent.flow?.actionId}` @@ -230,8 +238,9 @@ Scope { } } - RowLayout { + SnapLayout { Layout.preferredWidth: contentRow.implicitWidth + spacing: 8 IconButton { diff --git a/Modules/Resources/Cards/BatteryTank.qml b/Modules/Resources/Cards/BatteryTank.qml index 7c26d63..4d8ed33 100644 --- a/Modules/Resources/Cards/BatteryTank.qml +++ b/Modules/Resources/Cards/BatteryTank.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell.Services.UPower import ZShell.Config import qs.Components @@ -50,7 +51,8 @@ ClipRect { } } - component Contents: ColumnLayout { + component Contents: SnapLayout { +orientation: Qt.Vertical id: contents required property color accentColor @@ -100,7 +102,7 @@ ClipRect { } } - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignRight Layout.bottomMargin: -Tokens.padding.extraSmall Layout.rightMargin: -Tokens.padding.extraSmall diff --git a/Modules/Resources/Cards/HeroCard.qml b/Modules/Resources/Cards/HeroCard.qml index d5f8a87..cd3255e 100644 --- a/Modules/Resources/Cards/HeroCard.qml +++ b/Modules/Resources/Cards/HeroCard.qml @@ -1,5 +1,7 @@ import QtQuick import QtQuick.Layouts +import ZShell +import ZShell.Components import ZShell.Config import qs.Components import qs.Services @@ -15,8 +17,8 @@ CustomRect { required property real usage color: Colors.tPalette.m3surfaceContainer - implicitHeight: Math.max(tempProg.implicitHeight + detailsRow.implicitHeight + Tokens.spacing.largeIncreased, usageColumn.implicitHeight + usageLabel.implicitHeight) + Tokens.padding.large * 2 - implicitWidth: 450 + implicitHeight: ZUtils.snap(Math.max(tempProg.implicitHeight + detailsRow.implicitHeight + Tokens.spacing.largeIncreased, usageColumn.implicitHeight + usageLabel.implicitHeight) + Tokens.padding.large * 2, root) + implicitWidth: ZUtils.snapCeil(450, root) radius: Tokens.rounding.largeIncreased ClipRect { @@ -43,7 +45,7 @@ CustomRect { anchors.margins: Tokens.padding.large anchors.top: parent.top fgColor: root.accent - implicitSize: Math.max(icon.implicitWidth, icon.implicitHeight) + Tokens.padding.small * 2 + implicitSize: ZUtils.snap(Math.max(icon.implicitWidth, icon.implicitHeight) + Tokens.padding.small * 2, root) spacing: Tokens.spacing.extraSmall strokeWidth: Tokens.padding.extraSmall value: root.usage @@ -62,12 +64,14 @@ CustomRect { } } - ColumnLayout { + SnapLayout { anchors.left: tempProg.right anchors.margins: Tokens.spacing.largeIncreased anchors.right: usageColumn.left anchors.verticalCenter: tempProg.verticalCenter + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical CustomText { color: root.accent @@ -82,15 +86,17 @@ CustomRect { } } - ColumnLayout { + SnapLayout { id: detailsRow anchors.bottom: parent.bottom anchors.left: parent.left anchors.margins: Tokens.padding.largeIncreased - spacing: Tokens.spacing.extraSmall - RowLayout { + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical + + SnapLayout { Layout.leftMargin: -Tokens.padding.extraSmall spacing: Tokens.spacing.extraSmall @@ -108,32 +114,34 @@ CustomRect { CustomProgressBar { fgColor: root.accent - implicitHeight: Tokens.padding.extraSmall + implicitHeight: Tokens.padding.small indeterminate: isNaN(root.usage) || isNaN(root.temperature) value: root.temperature / 100 } } - Column { + SnapLayout { id: usageColumn anchors.margins: Tokens.padding.large anchors.right: parent.right - anchors.rightMargin: 32 + anchors.rightMargin: Tokens.padding.extraLarge anchors.verticalCenter: parent.verticalCenter + spacing: 0 + orientation: Qt.Vertical CustomText { id: usageLabel - anchors.right: parent.right + Layout.alignment: Qt.AlignRight color: Colors.palette.m3onSurfaceVariant font: Tokens.font.body.medium text: qsTr("Usage") } CustomText { - anchors.right: parent.right + Layout.alignment: Qt.AlignRight color: root.accent font: Tokens.font.headline.builders.small.width(50).build() text: isNaN(root.usage) ? "...%" : Math.round(root.usage * 100) + "%" diff --git a/Modules/Resources/Cards/MemoryCard.qml b/Modules/Resources/Cards/MemoryCard.qml index c2f8041..46b37d6 100644 --- a/Modules/Resources/Cards/MemoryCard.qml +++ b/Modules/Resources/Cards/MemoryCard.qml @@ -1,5 +1,7 @@ import QtQuick import QtQuick.Layouts +import ZShell +import ZShell.Components import ZShell.Services import ZShell.Config import qs.Components @@ -10,34 +12,39 @@ CustomRect { readonly property color accent: Colors.palette.m3tertiary + required property real perc + required property int used + required property int total + required property string label + required property string icon + Layout.fillWidth: true color: Colors.tPalette.m3surfaceContainer implicitHeight: layout.implicitHeight + Tokens.padding.large * 2 implicitWidth: layout.implicitWidth + Tokens.padding.extraLargeIncreased * 2 radius: Tokens.rounding.largeIncreased - ServiceRef { - service: Memory - } - - ColumnLayout { + SnapLayout { id: layout - anchors.centerIn: parent + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + orientation: Qt.Vertical spacing: Tokens.spacing.extraSmall - RowLayout { - Layout.leftMargin: -Tokens.padding.extraSmall + SnapLayout { + Layout.alignment: Qt.AlignHCenter spacing: Tokens.spacing.small MaterialIcon { color: root.accent fill: 1 - text: "memory_alt" + text: root.icon } CustomText { - text: qsTr("Memory") + text: root.label } } @@ -45,17 +52,17 @@ CustomRect { Layout.alignment: Qt.AlignHCenter Layout.topMargin: Tokens.spacing.largeIncreased fgColor: root.accent - implicitSize: usageColumn.implicitHeight + thickness + Tokens.padding.largeIncreased * 2 + implicitSize: ZUtils.snap(usageColumn.implicitHeight + thickness + Tokens.padding.largeIncreased * 2, root) startAngle: -225 sweepAngle: 270 - value: Memory.percentage + value: root.perc Behavior on clampedVal { - Anim { - } + Anim {} } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: usageColumn anchors.centerIn: parent @@ -66,7 +73,7 @@ CustomRect { Layout.alignment: Qt.AlignHCenter color: root.accent font: Tokens.font.body.large - text: Math.round(Memory.percentage * 100) + "%" + text: Math.round(root.perc * 100) + "%" } CustomText { @@ -80,7 +87,7 @@ CustomRect { CustomText { Layout.alignment: Qt.AlignHCenter text: { - const fmt = UsageFmt.formatKib(Memory.used, Memory.total); + const fmt = UsageFmt.formatKib(root.used, root.total); return `${fmt.value.toFixed(1)} / ${Math.floor(fmt.total)} ${fmt.unit}`; } } diff --git a/Modules/Resources/Cards/NetworkCard.qml b/Modules/Resources/Cards/NetworkCard.qml index ea6474c..5f443ef 100644 --- a/Modules/Resources/Cards/NetworkCard.qml +++ b/Modules/Resources/Cards/NetworkCard.qml @@ -18,15 +18,17 @@ CustomRect { service: NetworkUsage } - ColumnLayout { + SnapLayout { id: layout anchors.bottomMargin: Tokens.padding.small anchors.fill: parent anchors.margins: Tokens.padding.large - spacing: 0 - RowLayout { + spacing: 0 + orientation: Qt.Vertical + + SnapLayout { spacing: Tokens.spacing.small MaterialIcon { @@ -108,8 +110,11 @@ CustomRect { } // Download row - RowLayout { + SnapLayout { Layout.fillWidth: true + Layout.maximumWidth: root.width > root.implicitWidth * 2 ? root.width / 2 : -1 + Layout.alignment: Qt.AlignRight + spacing: Tokens.spacing.small MaterialIcon { @@ -136,8 +141,11 @@ CustomRect { } // Upload row - RowLayout { + SnapLayout { Layout.fillWidth: true + Layout.maximumWidth: root.width > root.implicitWidth * 2 ? root.width / 2 : -1 + Layout.alignment: Qt.AlignRight + spacing: Tokens.spacing.small MaterialIcon { @@ -164,8 +172,11 @@ CustomRect { } // Session totals - RowLayout { + SnapLayout { Layout.fillWidth: true + Layout.maximumWidth: root.width > root.implicitWidth * 2 ? root.width / 2 : -1 + Layout.alignment: Qt.AlignRight + spacing: Tokens.spacing.small MaterialIcon { diff --git a/Modules/Resources/Cards/StorageCard.qml b/Modules/Resources/Cards/StorageCard.qml index a1a1e57..ad8f1ba 100644 --- a/Modules/Resources/Cards/StorageCard.qml +++ b/Modules/Resources/Cards/StorageCard.qml @@ -1,6 +1,8 @@ import QtQuick import QtQuick.Layouts import Quickshell +import ZShell +import ZShell.Components import ZShell.Services import ZShell.Config import qs.Components @@ -21,23 +23,26 @@ CustomRect { service: Storage } - ColumnLayout { + SnapLayout { id: layout anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - spacing: 0 - RowLayout { + spacing: 0 + orientation: Qt.Vertical + + SnapLayout { id: row Layout.alignment: Qt.AlignHCenter + spacing: Tokens.spacing.largeIncreased CircularProgress { fgColor: root.accent - implicitSize: usageColumn.implicitHeight + thickness + Tokens.padding.large * 2 + implicitSize: ZUtils.snap(usageColumn.implicitHeight + thickness + Tokens.padding.large * 2, root) startAngle: -225 sweepAngle: 270 value: root.percentage @@ -46,7 +51,8 @@ CustomRect { Anim {} } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: usageColumn anchors.centerIn: parent @@ -74,8 +80,9 @@ CustomRect { } } - ColumnLayout { + SnapLayout { spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical CustomText { text: qsTr("Storage") diff --git a/Modules/Resources/Cards/VramCard.qml b/Modules/Resources/Cards/VramCard.qml deleted file mode 100644 index 034f00f..0000000 --- a/Modules/Resources/Cards/VramCard.qml +++ /dev/null @@ -1,89 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import ZShell.Services -import ZShell.Config -import qs.Components -import qs.Services - -CustomRect { - id: root - - readonly property color accent: Colors.palette.m3tertiary - - Layout.fillWidth: true - color: Colors.tPalette.m3surfaceContainer - implicitHeight: layout.implicitHeight + Tokens.padding.large * 2 - implicitWidth: layout.implicitWidth + Tokens.padding.extraLargeIncreased - radius: Tokens.rounding.largeIncreased - - ServiceRef { - service: Gpu - } - - ColumnLayout { - id: layout - - anchors.centerIn: parent - spacing: Tokens.spacing.extraSmall - - RowLayout { - Layout.leftMargin: -Tokens.padding.extraSmall - spacing: Tokens.spacing.small - - MaterialIcon { - color: root.accent - fill: 1 - text: "memory_alt" - } - - CustomText { - text: qsTr("Video memory") - } - } - - CircularProgress { - id: circularIndicator - - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: Tokens.spacing.largeIncreased - fgColor: root.accent - implicitSize: usageColumn.implicitHeight + thickness + Tokens.padding.largeIncreased * 2 - startAngle: -225 - sweepAngle: 270 - value: Gpu.memoryUsed / Gpu.memoryTotal - - Behavior on clampedVal { - Anim {} - } - - ColumnLayout { - id: usageColumn - - anchors.centerIn: parent - anchors.verticalCenterOffset: Tokens.padding.extraSmall - spacing: 0 - - CustomText { - Layout.alignment: Qt.AlignHCenter - color: root.accent - font: Tokens.font.body.large - text: Math.round(circularIndicator.value * 100) + "%" - } - - CustomText { - Layout.alignment: Qt.AlignHCenter - color: Colors.palette.m3onSurfaceVariant - text: qsTr("Used") - } - } - } - - CustomText { - Layout.alignment: Qt.AlignHCenter - text: { - const fmt = UsageFmt.formatKib(Gpu.memoryUsed, Gpu.memoryTotal); - return `${fmt.value.toFixed(1)} / ${Math.floor(fmt.total)} ${fmt.unit}`; - } - } - } -} diff --git a/Modules/Resources/Content.qml b/Modules/Resources/Content.qml index 53909d5..a813746 100644 --- a/Modules/Resources/Content.qml +++ b/Modules/Resources/Content.qml @@ -1,7 +1,10 @@ import QtQuick import QtQuick.Layouts +import ZShell +import ZShell.Components import ZShell.Services import ZShell.Config +import qs.Components import qs.Modules.Resources.Cards import qs.Helpers import qs.Services @@ -11,25 +14,25 @@ Item { required property Wrapper wrapper - implicitHeight: content.implicitHeight + Tokens.padding.small * 2 - implicitWidth: content.implicitWidth + implicitHeight: ZUtils.snap(content.implicitHeight + Tokens.padding.small * 2, root) + implicitWidth: ZUtils.snap(content.implicitWidth, root) - RowLayout { + SnapLayout { id: content - anchors.left: parent.left + anchors.fill: parent anchors.margins: Tokens.padding.small - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter spacing: Tokens.spacing.large - ColumnLayout { + SnapLayout { id: mainColumn Layout.fillWidth: true spacing: Tokens.spacing.medium + orientation: Qt.Vertical - RowLayout { + SnapLayout { + id: hero spacing: Tokens.spacing.medium visible: cpuCard.active || gpuCard.active @@ -72,7 +75,10 @@ Item { } } - RowLayout { + SnapLayout { + id: card + + Layout.fillWidth: true spacing: Tokens.spacing.medium visible: storageCard.active || memoryCard.active || vramCard.active || networkCard1.active @@ -81,8 +87,7 @@ Item { active: Config.dashboard.performance.showStorage - sourceComponent: StorageCard { - } + sourceComponent: StorageCard {} } WrappedLoader { @@ -91,6 +96,15 @@ Item { active: Config.dashboard.performance.showMemory sourceComponent: MemoryCard { + used: Memory.used + total: Memory.total + perc: Memory.percentage + label: qsTr("Memory") + icon: "memory_alt" + + ServiceRef { + service: Memory + } } } @@ -99,7 +113,12 @@ Item { active: Config.dashboard.performance.showVram - sourceComponent: VramCard { + sourceComponent: MemoryCard { + used: Gpu.memoryUsed + total: Gpu.memoryTotal + perc: Gpu.memoryUsed / Gpu.memoryTotal + label: qsTr("Video memory") + icon: "memory_alt" } } @@ -108,8 +127,7 @@ Item { active: Config.dashboard.performance.showNetwork && !vramCard.active - sourceComponent: NetworkCard { - } + sourceComponent: NetworkCard {} } } @@ -118,8 +136,7 @@ Item { active: Config.dashboard.performance.showNetwork && vramCard.active - sourceComponent: NetworkCard { - } + sourceComponent: NetworkCard {} } } @@ -127,8 +144,7 @@ Item { Layout.fillWidth: false active: Battery.isLaptop && Config.dashboard.performance.showBattery - sourceComponent: BatteryTank { - } + sourceComponent: BatteryTank {} } } diff --git a/Modules/Settings/Common/AudioDeviceList.qml b/Modules/Settings/Common/AudioDeviceList.qml index d0d21bb..dcbefe4 100644 --- a/Modules/Settings/Common/AudioDeviceList.qml +++ b/Modules/Settings/Common/AudioDeviceList.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Services.Pipewire import qs.Components @@ -39,7 +40,7 @@ ItemList { onClicked: root.selected(device.modelData) } - RowLayout { + SnapLayout { id: deviceLayout anchors.fill: parent diff --git a/Modules/Settings/Common/DialogRowButton.qml b/Modules/Settings/Common/DialogRowButton.qml index f06d808..3f446b1 100644 --- a/Modules/Settings/Common/DialogRowButton.qml +++ b/Modules/Settings/Common/DialogRowButton.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Blobs import qs.Components import ZShell.Config @@ -181,7 +182,8 @@ Item { onWheel: event => event.accepted = true - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.bottomMargin: Tokens.padding.largeIncreased anchors.fill: parent anchors.margins: Tokens.padding.extraLarge @@ -222,7 +224,7 @@ Item { } } - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignRight spacing: Tokens.spacing.extraSmall diff --git a/Modules/Settings/Common/InfoRow.qml b/Modules/Settings/Common/InfoRow.qml index 63f510d..53c8cf9 100644 --- a/Modules/Settings/Common/InfoRow.qml +++ b/Modules/Settings/Common/InfoRow.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services @@ -29,7 +30,7 @@ ConnectedRect { } } - RowLayout { + SnapLayout { id: rowLayout anchors.fill: parent @@ -44,7 +45,8 @@ ConnectedRect { visible: root.leadingComponent } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Common/ItemList.qml b/Modules/Settings/Common/ItemList.qml index d32f678..cf2c951 100644 --- a/Modules/Settings/Common/ItemList.qml +++ b/Modules/Settings/Common/ItemList.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services @@ -38,7 +39,8 @@ ConnectedRect { type: Anim.DefaultEffects } } - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { +orientation: Qt.Vertical spacing: Tokens.spacing.extraSmall MaterialIcon { diff --git a/Modules/Settings/Common/ListEditor.qml b/Modules/Settings/Common/ListEditor.qml index 9685068..712b0d4 100644 --- a/Modules/Settings/Common/ListEditor.qml +++ b/Modules/Settings/Common/ListEditor.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import ZShell.Config import qs.Components @@ -265,7 +266,7 @@ ListView { } } - RowLayout { + SnapLayout { id: row anchors.fill: parent diff --git a/Modules/Settings/Common/PageBase.qml b/Modules/Settings/Common/PageBase.qml index ef43398..976cfd1 100644 --- a/Modules/Settings/Common/PageBase.qml +++ b/Modules/Settings/Common/PageBase.qml @@ -2,12 +2,14 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Modules.Settings import qs.Components import ZShell.Config import qs.Services -ColumnLayout { +SnapLayout { +orientation: Qt.Vertical id: root property bool animateScroll: false @@ -118,7 +120,7 @@ ColumnLayout { onClicked: focus = true - RowLayout { + SnapLayout { id: header spacing: Tokens.spacing.largeIncreased diff --git a/Modules/Settings/Common/PopupRow.qml b/Modules/Settings/Common/PopupRow.qml index 0b3a22a..8233bc4 100644 --- a/Modules/Settings/Common/PopupRow.qml +++ b/Modules/Settings/Common/PopupRow.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import qs.Components import ZShell.Config @@ -27,7 +28,7 @@ ConnectedRect { onClicked: popup.open = true } - RowLayout { + SnapLayout { id: navLayout anchors.fill: parent @@ -43,7 +44,8 @@ ConnectedRect { fontStyle: Tokens.font.icon.medium } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Common/RowButton.qml b/Modules/Settings/Common/RowButton.qml index 419fae8..4dfea88 100644 --- a/Modules/Settings/Common/RowButton.qml +++ b/Modules/Settings/Common/RowButton.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Services @@ -30,7 +31,7 @@ ConnectedRect { onClicked: e => root.clicked(e) } - RowLayout { + SnapLayout { id: row anchors.left: parent.left diff --git a/Modules/Settings/Common/SearchPopup.qml b/Modules/Settings/Common/SearchPopup.qml index 4bfc086..4de753c 100644 --- a/Modules/Settings/Common/SearchPopup.qml +++ b/Modules/Settings/Common/SearchPopup.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Services @@ -19,7 +20,8 @@ DialogRowButton { separateContent: true content: Component { - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical VerticalFadeListView { bottomMargin: Tokens.padding.large Layout.fillHeight: true diff --git a/Modules/Settings/Common/SectionHeader.qml b/Modules/Settings/Common/SectionHeader.qml index b826399..07c8acb 100644 --- a/Modules/Settings/Common/SectionHeader.qml +++ b/Modules/Settings/Common/SectionHeader.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Layouts -import qs.Components import ZShell.Config +import qs.Components import qs.Services CustomText { diff --git a/Modules/Settings/Common/SelectRow.qml b/Modules/Settings/Common/SelectRow.qml index ce97cad..5c5de7d 100644 --- a/Modules/Settings/Common/SelectRow.qml +++ b/Modules/Settings/Common/SelectRow.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services @@ -22,7 +23,7 @@ ConnectedRect { implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2 z: splitButton.expanded ? 1 : 0 - RowLayout { + SnapLayout { id: rowLayout anchors.fill: parent @@ -31,7 +32,8 @@ ConnectedRect { anchors.rightMargin: Tokens.padding.largeIncreased spacing: Tokens.spacing.small - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Common/SliderRow.qml b/Modules/Settings/Common/SliderRow.qml index 10c69b1..da5bc4d 100644 --- a/Modules/Settings/Common/SliderRow.qml +++ b/Modules/Settings/Common/SliderRow.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services @@ -19,7 +20,7 @@ ConnectedRect { Layout.fillWidth: true implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins + rowLayout.anchors.topMargin - RowLayout { + SnapLayout { id: rowLayout anchors.fill: parent @@ -27,11 +28,12 @@ ConnectedRect { anchors.topMargin: Tokens.padding.large spacing: Tokens.spacing.small - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: Tokens.spacing.small - RowLayout { + SnapLayout { Layout.fillWidth: true spacing: Tokens.spacing.small diff --git a/Modules/Settings/Common/SpinRow.qml b/Modules/Settings/Common/SpinRow.qml index 429d4d1..66278c7 100644 --- a/Modules/Settings/Common/SpinRow.qml +++ b/Modules/Settings/Common/SpinRow.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services @@ -21,7 +22,7 @@ ConnectedRect { Layout.fillWidth: true implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2 - RowLayout { + SnapLayout { id: rowLayout anchors.fill: parent @@ -30,7 +31,8 @@ ConnectedRect { anchors.rightMargin: Tokens.padding.largeIncreased spacing: Tokens.spacing.small - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Common/TextFieldRow.qml b/Modules/Settings/Common/TextFieldRow.qml index 32ec8a4..f1814ed 100644 --- a/Modules/Settings/Common/TextFieldRow.qml +++ b/Modules/Settings/Common/TextFieldRow.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Services @@ -35,7 +36,7 @@ ConnectedRect { Layout.fillWidth: true implicitHeight: rowLayout.implicitHeight + Tokens.padding.medium + Math.max(0, Tokens.padding.large - input.verticalPadding) * 2 - RowLayout { + SnapLayout { id: rowLayout anchors.left: parent.left @@ -45,7 +46,8 @@ ConnectedRect { anchors.rightMargin: Tokens.padding.largeIncreased spacing: Tokens.spacing.medium - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Common/TimeDialogRow.qml b/Modules/Settings/Common/TimeDialogRow.qml index 701b2ed..07d153b 100644 --- a/Modules/Settings/Common/TimeDialogRow.qml +++ b/Modules/Settings/Common/TimeDialogRow.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Blobs import qs.Components import ZShell.Config @@ -185,7 +186,8 @@ Item { implicitWidth: innerLayout.implicitWidth + innerLayout.anchors.margins * 2 implicitHeight: innerLayout.implicitHeight + innerLayout.anchors.margins + innerLayout.anchors.bottomMargin - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: innerLayout anchors.bottomMargin: Tokens.padding.largeIncreased anchors.fill: parent @@ -206,7 +208,7 @@ Item { sourceComponent: root.content } - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignRight spacing: Tokens.spacing.extraSmall diff --git a/Modules/Settings/Common/TimeDialogToggle.qml b/Modules/Settings/Common/TimeDialogToggle.qml index 9d75041..0c0899b 100644 --- a/Modules/Settings/Common/TimeDialogToggle.qml +++ b/Modules/Settings/Common/TimeDialogToggle.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings diff --git a/Modules/Settings/Common/TimeInput.qml b/Modules/Settings/Common/TimeInput.qml index f01100f..3575b5f 100644 --- a/Modules/Settings/Common/TimeInput.qml +++ b/Modules/Settings/Common/TimeInput.qml @@ -6,7 +6,8 @@ import qs.Components import qs.Helpers import qs.Services -ColumnLayout { +SnapLayout { +orientation: Qt.Vertical id: root required property int start @@ -28,7 +29,7 @@ ColumnLayout { spacing: Tokens.spacing.medium - RowLayout { + SnapLayout { CustomRect { id: startHourRect @@ -470,7 +471,7 @@ ColumnLayout { } } - RowLayout { + SnapLayout { CustomText { Layout.preferredWidth: spacer.x + spacer.width text: qsTr("Start") diff --git a/Modules/Settings/Common/ToggleRow.qml b/Modules/Settings/Common/ToggleRow.qml index 2eea3f5..a9d809c 100644 --- a/Modules/Settings/Common/ToggleRow.qml +++ b/Modules/Settings/Common/ToggleRow.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Services diff --git a/Modules/Settings/Common/WallItem.qml b/Modules/Settings/Common/WallItem.qml index 84d15e5..3825ab0 100644 --- a/Modules/Settings/Common/WallItem.qml +++ b/Modules/Settings/Common/WallItem.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import qs.Components import ZShell.Config @@ -19,7 +20,8 @@ Item { Layout.fillWidth: true implicitHeight: layout.implicitHeight - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout anchors.fill: parent diff --git a/Modules/Settings/Common/WallpaperCropper.qml b/Modules/Settings/Common/WallpaperCropper.qml index 966f6ee..345e8f5 100644 --- a/Modules/Settings/Common/WallpaperCropper.qml +++ b/Modules/Settings/Common/WallpaperCropper.qml @@ -156,7 +156,7 @@ Item { } } - RowLayout { + SnapLayout { id: sliderLayout anchors.bottom: parent.bottom diff --git a/Modules/Settings/NavPane.qml b/Modules/Settings/NavPane.qml index 820e3e3..b5ea63a 100644 --- a/Modules/Settings/NavPane.qml +++ b/Modules/Settings/NavPane.qml @@ -1,11 +1,13 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import qs.Modules.Settings.NavPane import ZShell.Config import qs.Services -ColumnLayout { +SnapLayout { +orientation: Qt.Vertical id: root required property SettingsState sState diff --git a/Modules/Settings/NavPane/NavLocations.qml b/Modules/Settings/NavPane/NavLocations.qml index a73378d..e8f76a8 100644 --- a/Modules/Settings/NavPane/NavLocations.qml +++ b/Modules/Settings/NavPane/NavLocations.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import qs.Components import ZShell.Config @@ -48,7 +49,8 @@ VerticalFadeFlickable { onTapped: root.focus = true } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: content anchors.left: parent.left @@ -98,7 +100,7 @@ VerticalFadeFlickable { onClicked: root.sState.currentPageIdx = item.index } - RowLayout { + SnapLayout { id: layout anchors.fill: parent @@ -124,7 +126,8 @@ VerticalFadeFlickable { } } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 @@ -179,7 +182,8 @@ VerticalFadeFlickable { values: root.groups } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: group required property int index @@ -188,7 +192,7 @@ VerticalFadeFlickable { spacing: Tokens.spacing.small width: resultList.width - RowLayout { + SnapLayout { Layout.fillWidth: true Layout.leftMargin: Tokens.padding.extraSmall spacing: Tokens.spacing.small @@ -265,7 +269,8 @@ VerticalFadeFlickable { RadiusBehavior on topLeftRadius {} RadiusBehavior on topRightRadius {} - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: resultLayout anchors.fill: parent diff --git a/Modules/Settings/PageCompRegistry.qml b/Modules/Settings/PageCompRegistry.qml index 591e7e1..2cc5603 100644 --- a/Modules/Settings/PageCompRegistry.qml +++ b/Modules/Settings/PageCompRegistry.qml @@ -2,6 +2,7 @@ pragma Singleton import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Components import ZShell.Config import qs.Modules.Settings.Common @@ -158,7 +159,8 @@ QtObject { component PlaceholderComp: Item { property SettingsState sState // To avoid the warning from non-existent property - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.centerIn: parent spacing: Tokens.padding.extraSmall diff --git a/Modules/Settings/Pages/AboutPage.qml b/Modules/Settings/Pages/AboutPage.qml index 53bc19e..ca31d30 100644 --- a/Modules/Settings/Pages/AboutPage.qml +++ b/Modules/Settings/Pages/AboutPage.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell.Io import ZShell import qs.Modules.Settings.Common @@ -17,7 +18,8 @@ PageBase { title: qsTr("About") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 @@ -38,7 +40,8 @@ PageBase { implicitHeight: hero.implicitHeight + Tokens.padding.extraLarge * 2 last: true - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: hero anchors.centerIn: parent diff --git a/Modules/Settings/Pages/Apps/AllApps.qml b/Modules/Settings/Pages/Apps/AllApps.qml index 228ffab..48e4e50 100644 --- a/Modules/Settings/Pages/Apps/AllApps.qml +++ b/Modules/Settings/Pages/Apps/AllApps.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Widgets import qs.Components @@ -16,7 +17,8 @@ PageBase { isSubPage: true title: qsTr("All apps") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 @@ -45,7 +47,7 @@ PageBase { } } - RowLayout { + SnapLayout { id: appRow anchors.fill: parent @@ -60,7 +62,8 @@ PageBase { source: Quickshell.iconPath(appItem.modelData.icon, "image-missing") } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Pages/Apps/AppInfo.qml b/Modules/Settings/Pages/Apps/AppInfo.qml index 4f549da..ef653f5 100644 --- a/Modules/Settings/Pages/Apps/AppInfo.qml +++ b/Modules/Settings/Pages/Apps/AppInfo.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Widgets import qs.Components @@ -32,14 +33,15 @@ PageBase { sState.closeSubPage(); } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 width: root.cappedWidth // Header - RowLayout { + SnapLayout { Layout.bottomMargin: Tokens.spacing.largeIncreased Layout.fillWidth: true Layout.leftMargin: Tokens.padding.extraSmall @@ -51,7 +53,8 @@ PageBase { source: Quickshell.iconPath(root.app?.icon, "image-missing") } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: Tokens.spacing.extraSmall / 2 @@ -139,7 +142,7 @@ PageBase { Layout.fillWidth: true implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2 - RowLayout { + SnapLayout { id: rowLayout anchors.fill: parent diff --git a/Modules/Settings/Pages/AppsPage.qml b/Modules/Settings/Pages/AppsPage.qml index 32206a0..3015ebc 100644 --- a/Modules/Settings/Pages/AppsPage.qml +++ b/Modules/Settings/Pages/AppsPage.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Widgets import ZShell @@ -16,7 +17,8 @@ PageBase { title: qsTr("Apps") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 @@ -134,7 +136,7 @@ PageBase { row.selected(modelData); } - RowLayout { + SnapLayout { id: itemLayout anchors.fill: parent @@ -147,7 +149,8 @@ PageBase { source: Quickshell.iconPath(appItem.modelData.icon, "image-missing") } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Pages/Audio/AppVolumes.qml b/Modules/Settings/Pages/Audio/AppVolumes.qml index 9d59da6..835310f 100644 --- a/Modules/Settings/Pages/Audio/AppVolumes.qml +++ b/Modules/Settings/Pages/Audio/AppVolumes.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Services.Pipewire import qs.Modules.Settings.Common @@ -17,7 +18,8 @@ PageBase { isSubPage: true title: qsTr("App volumes") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/AudioPage.qml b/Modules/Settings/Pages/AudioPage.qml index 7c6e0f7..a0bb150 100644 --- a/Modules/Settings/Pages/AudioPage.qml +++ b/Modules/Settings/Pages/AudioPage.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import qs.Daemons import ZShell.Config import qs.Components @@ -14,7 +15,8 @@ PageBase { title: qsTr("Audio") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 @@ -93,7 +95,7 @@ PageBase { onClicked: root.sState.openSubPage(1) } - RowLayout { + SnapLayout { id: appLayout anchors.fill: parent @@ -107,7 +109,8 @@ PageBase { text: "tune" } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 diff --git a/Modules/Settings/Pages/Panels/Bar/BarClock.qml b/Modules/Settings/Pages/Panels/Bar/BarClock.qml index 63461bd..6f0606e 100644 --- a/Modules/Settings/Pages/Panels/Bar/BarClock.qml +++ b/Modules/Settings/Pages/Panels/Bar/BarClock.qml @@ -1,6 +1,7 @@ pragma ComponentBehavior: Bound import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -38,7 +39,8 @@ PageBase { isSubPage: true title: qsTr("Clock") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml b/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml index 7b0aea9..3de630d 100644 --- a/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml +++ b/Modules/Settings/Pages/Panels/Bar/BarStatusIcons.qml @@ -1,4 +1,5 @@ import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Modules.Settings.Common @@ -14,7 +15,8 @@ PageBase { isSubPage: true title: qsTr("System icons") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/Bar/BarTray.qml b/Modules/Settings/Pages/Panels/Bar/BarTray.qml index a4a7696..8d72b46 100644 --- a/Modules/Settings/Pages/Panels/Bar/BarTray.qml +++ b/Modules/Settings/Pages/Panels/Bar/BarTray.qml @@ -1,6 +1,7 @@ pragma ComponentBehavior: Bound import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Modules.Settings.Common @@ -10,7 +11,8 @@ PageBase { isSubPage: true title: qsTr("Tray") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/BarPanel.qml b/Modules/Settings/Pages/Panels/BarPanel.qml index 8f6ddb6..da8b716 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 ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -11,7 +12,8 @@ PageBase { isSubPage: true title: qsTr("Taskbar") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/DashboardPanel.qml b/Modules/Settings/Pages/Panels/DashboardPanel.qml index 12d7d3e..112b5d4 100644 --- a/Modules/Settings/Pages/Panels/DashboardPanel.qml +++ b/Modules/Settings/Pages/Panels/DashboardPanel.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -12,7 +13,8 @@ PageBase { isSubPage: true title: qsTr("Dashboard") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/LauncherPanel.qml b/Modules/Settings/Pages/Panels/LauncherPanel.qml index 3cc41f3..4521efa 100644 --- a/Modules/Settings/Pages/Panels/LauncherPanel.qml +++ b/Modules/Settings/Pages/Panels/LauncherPanel.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -12,7 +13,8 @@ PageBase { isSubPage: true title: qsTr("Launcher") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/ResourcesPanel.qml b/Modules/Settings/Pages/Panels/ResourcesPanel.qml index 3638a48..b29bb92 100644 --- a/Modules/Settings/Pages/Panels/ResourcesPanel.qml +++ b/Modules/Settings/Pages/Panels/ResourcesPanel.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -12,7 +13,8 @@ PageBase { isSubPage: true title: qsTr("Resources") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/Sidebar/SidebarLlm.qml b/Modules/Settings/Pages/Panels/Sidebar/SidebarLlm.qml index 9eda863..734fa1f 100644 --- a/Modules/Settings/Pages/Panels/Sidebar/SidebarLlm.qml +++ b/Modules/Settings/Pages/Panels/Sidebar/SidebarLlm.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -59,7 +60,8 @@ PageBase { isSubPage: true title: qsTr("Sidebar") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Panels/SidebarPanel.qml b/Modules/Settings/Pages/Panels/SidebarPanel.qml index 8de209b..7d6c645 100644 --- a/Modules/Settings/Pages/Panels/SidebarPanel.qml +++ b/Modules/Settings/Pages/Panels/SidebarPanel.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -22,7 +23,8 @@ PageBase { isSubPage: true title: qsTr("Sidebar") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/PanelsPage.qml b/Modules/Settings/Pages/PanelsPage.qml index 6a16a5b..b7b7cfb 100644 --- a/Modules/Settings/Pages/PanelsPage.qml +++ b/Modules/Settings/Pages/PanelsPage.qml @@ -1,4 +1,5 @@ import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Modules.Settings.Common @@ -7,7 +8,8 @@ PageBase { title: qsTr("Panels") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/ScreenshotPage.qml b/Modules/Settings/Pages/ScreenshotPage.qml index 2a08a2d..59df081 100644 --- a/Modules/Settings/Pages/ScreenshotPage.qml +++ b/Modules/Settings/Pages/ScreenshotPage.qml @@ -14,7 +14,8 @@ PageBase { title: qsTr("Screenshots") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Services/NotificationsPage.qml b/Modules/Settings/Pages/Services/NotificationsPage.qml index 75e4387..71f44b0 100644 --- a/Modules/Settings/Pages/Services/NotificationsPage.qml +++ b/Modules/Settings/Pages/Services/NotificationsPage.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Modules.Settings.Common @@ -10,7 +11,8 @@ PageBase { isSubPage: true title: qsTr("Notifications") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/ServicesPage.qml b/Modules/Settings/Pages/ServicesPage.qml index e636fb5..2d2db80 100644 --- a/Modules/Settings/Pages/ServicesPage.qml +++ b/Modules/Settings/Pages/ServicesPage.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import ZShell.Services import qs.Components @@ -28,7 +29,8 @@ PageBase { title: qsTr("Services") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Wallpaper/ColorsFonts.qml b/Modules/Settings/Pages/Wallpaper/ColorsFonts.qml index be09d14..ae138b0 100644 --- a/Modules/Settings/Pages/Wallpaper/ColorsFonts.qml +++ b/Modules/Settings/Pages/Wallpaper/ColorsFonts.qml @@ -4,6 +4,7 @@ import Quickshell import Quickshell.Io import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Paths import qs.Services @@ -59,7 +60,8 @@ PageBase { isSubPage: true title: qsTr("Colors & font") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.extraSmall / 2 diff --git a/Modules/Settings/Pages/Wallpaper/WallpaperSelect.qml b/Modules/Settings/Pages/Wallpaper/WallpaperSelect.qml index a4d4906..52bc8e5 100644 --- a/Modules/Settings/Pages/Wallpaper/WallpaperSelect.qml +++ b/Modules/Settings/Pages/Wallpaper/WallpaperSelect.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Models import qs.Paths import qs.Helpers @@ -16,7 +17,8 @@ PageBase { isSubPage: true title: qsTr("Wallpapers") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top @@ -75,7 +77,8 @@ PageBase { implicitHeight: noWallsLayout.implicitHeight + Tokens.padding.extraLarge * 3 radius: Tokens.rounding.largeIncreased - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: noWallsLayout anchors.centerIn: parent diff --git a/Modules/Settings/Pages/WallpaperPage.qml b/Modules/Settings/Pages/WallpaperPage.qml index f3fcb6e..a5c2445 100644 --- a/Modules/Settings/Pages/WallpaperPage.qml +++ b/Modules/Settings/Pages/WallpaperPage.qml @@ -15,7 +15,8 @@ PageBase { title: qsTr("Wallpaper & style") - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: Tokens.spacing.largeIncreased diff --git a/Modules/Sidebar/Chat/ChatContent.qml b/Modules/Sidebar/Chat/ChatContent.qml index f20e602..c9b38ec 100644 --- a/Modules/Sidebar/Chat/ChatContent.qml +++ b/Modules/Sidebar/Chat/ChatContent.qml @@ -148,7 +148,7 @@ Item { target.contentY = 0 } - RowLayout { + SnapLayout { id: header anchors.left: parent.left diff --git a/Modules/Sidebar/Chat/ChatList.qml b/Modules/Sidebar/Chat/ChatList.qml index a575bf2..2890fe2 100644 --- a/Modules/Sidebar/Chat/ChatList.qml +++ b/Modules/Sidebar/Chat/ChatList.qml @@ -5,6 +5,7 @@ import QtQuick import QtQuick.Layouts import ZShell.Llm import ZShell.Config +import ZShell.Components import qs.Modules.Sidebar.Chat.Content import qs.Services import qs.Components @@ -165,13 +166,16 @@ Item { } } - ColumnLayout { + SnapLayout { id: fabMenu anchors.bottom: fabRoot.top anchors.right: fabRoot.right anchors.bottomMargin: Tokens.padding.medium + orientation: Qt.Vertical + spacing: Tokens.spacing.small + Repeater { id: fabRep @@ -277,7 +281,7 @@ Item { } ] - RowLayout { + SnapLayout { id: fabMenuItemInner anchors.centerIn: parent diff --git a/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml b/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml index ae9549b..abb6c36 100644 --- a/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml +++ b/Modules/Sidebar/Chat/Content/ApprovalPrompt.qml @@ -26,11 +26,13 @@ Item { border.width: 1 border.color: Colors.palette.m3outlineVariant - ColumnLayout { + SnapLayout { id: approvalLayout anchors.fill: parent anchors.margins: Tokens.padding.medium + spacing: Tokens.spacing.small + orientation: Qt.Vertical CustomText { id: requestHeader @@ -187,19 +189,22 @@ Item { } } - ColumnLayout { + SnapLayout { id: toolList anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter anchors.margins: Tokens.padding.medium + spacing: Tokens.spacing.extraSmall + orientation: Qt.Vertical + Repeater { id: repeater model: root.current.pendingToolCalls?.slice(0, 4) ?? [] - delegate: RowLayout { + delegate: SnapLayout { id: toolText required property var modelData @@ -304,7 +309,7 @@ Item { Anim {} } - RowLayout { + SnapLayout { id: collapsedRow anchors.top: parent.top @@ -312,6 +317,8 @@ Item { anchors.right: parent.right anchors.margins: Tokens.padding.medium + spacing: Tokens.spacing.extraSmall + IconButton { id: toolExpandBtn diff --git a/Modules/Sidebar/Chat/Content/CodeBlockView.qml b/Modules/Sidebar/Chat/Content/CodeBlockView.qml index a101553..64ebbf0 100644 --- a/Modules/Sidebar/Chat/Content/CodeBlockView.qml +++ b/Modules/Sidebar/Chat/Content/CodeBlockView.qml @@ -1,8 +1,8 @@ import QtQuick -import QtQuick.Effects import QtQuick.Shapes import QtQuick.Layouts import Quickshell +import ZShell.Components import ZShell.Config import ZShell.Llm import qs.Components @@ -143,7 +143,7 @@ CustomRect { onTriggered: refresh() } - RowLayout { + SnapLayout { id: headerRow anchors.top: parent.top @@ -152,6 +152,7 @@ CustomRect { anchors.topMargin: Tokens.padding.small anchors.leftMargin: Tokens.padding.small anchors.rightMargin: Tokens.padding.small + spacing: Tokens.spacing.small Item { diff --git a/Modules/Sidebar/Chat/Content/ContentBubble.qml b/Modules/Sidebar/Chat/Content/ContentBubble.qml index efa390b..38cc691 100644 --- a/Modules/Sidebar/Chat/Content/ContentBubble.qml +++ b/Modules/Sidebar/Chat/Content/ContentBubble.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Llm import ZShell.Config import qs.Modules.Sidebar.Chat diff --git a/Modules/Sidebar/Chat/Content/EmptyBackground.qml b/Modules/Sidebar/Chat/Content/EmptyBackground.qml index af0bfef..214db05 100644 --- a/Modules/Sidebar/Chat/Content/EmptyBackground.qml +++ b/Modules/Sidebar/Chat/Content/EmptyBackground.qml @@ -1,10 +1,12 @@ import QtQuick import QtQuick.Layouts +import ZShell.Components import ZShell.Config import qs.Components import qs.Services -ColumnLayout { +SnapLayout { +orientation: Qt.Vertical id: root spacing: Tokens.spacing.small diff --git a/Modules/Sidebar/Chat/Content/ErrorBubble.qml b/Modules/Sidebar/Chat/Content/ErrorBubble.qml index 9a73c55..85dad7d 100644 --- a/Modules/Sidebar/Chat/Content/ErrorBubble.qml +++ b/Modules/Sidebar/Chat/Content/ErrorBubble.qml @@ -4,6 +4,7 @@ import ZShell.Llm import ZShell.Config import qs.Components import qs.Services +import ZShell.Components Item { id: root @@ -78,7 +79,7 @@ Item { color: Colors.palette.m3errorContainer implicitHeight: errorInner.implicitHeight + errorInner.anchors.margins * 2 - ColumnLayout { + SnapLayout { id: errorInner anchors.top: parent.top @@ -87,6 +88,7 @@ Item { anchors.margins: Tokens.padding.medium spacing: Tokens.spacing.small + orientation: Qt.Vertical CustomText { id: header diff --git a/Modules/Sidebar/Chat/Content/ModelsContainer.qml b/Modules/Sidebar/Chat/Content/ModelsContainer.qml index 0f9d039..d379dc8 100644 --- a/Modules/Sidebar/Chat/Content/ModelsContainer.qml +++ b/Modules/Sidebar/Chat/Content/ModelsContainer.qml @@ -212,12 +212,14 @@ Item { clip: true implicitHeight: innerLayout.implicitHeight + innerLayout.anchors.margins * 2 - ColumnLayout { + SnapLayout { id: innerLayout anchors.bottomMargin: Tokens.padding.largeIncreased anchors.fill: parent anchors.margins: Tokens.padding.extraLarge + spacing: 0 + orientation: Qt.Vertical CustomText { font: Tokens.font.title.builders.large.weight(Font.Normal).build() @@ -264,7 +266,7 @@ Item { } } - RowLayout { + SnapLayout { id: layout anchors.left: parent.left @@ -274,6 +276,8 @@ Item { anchors.leftMargin: Tokens.padding.large anchors.rightMargin: Tokens.padding.large + spacing: Tokens.spacing.extraSmall + CustomText { id: name @@ -313,8 +317,9 @@ Item { } } - RowLayout { + SnapLayout { Layout.alignment: Qt.AlignRight + spacing: Tokens.spacing.extraSmall TextButton { diff --git a/Modules/Sidebar/Chat/Content/ProcessBlock.qml b/Modules/Sidebar/Chat/Content/ProcessBlock.qml index 6458e0c..71ac860 100644 --- a/Modules/Sidebar/Chat/Content/ProcessBlock.qml +++ b/Modules/Sidebar/Chat/Content/ProcessBlock.qml @@ -43,7 +43,7 @@ Item { } } - RowLayout { + SnapLayout { id: layout anchors.top: parent.top @@ -160,7 +160,7 @@ Item { implicitWidth: ListView.view.width implicitHeight: header.implicitHeight + content.implicitHeight + content.anchors.topMargin - RowLayout { + SnapLayout { id: header anchors.left: parent.left diff --git a/Modules/Sidebar/Chat/SidebarView.qml b/Modules/Sidebar/Chat/SidebarView.qml index 1033684..b98d347 100644 --- a/Modules/Sidebar/Chat/SidebarView.qml +++ b/Modules/Sidebar/Chat/SidebarView.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import QtQuick.Controls import Quickshell import ZShell.Blobs diff --git a/Modules/Sidebar/Content.qml b/Modules/Sidebar/Content.qml index f6cb612..ee734f0 100644 --- a/Modules/Sidebar/Content.qml +++ b/Modules/Sidebar/Content.qml @@ -1,5 +1,7 @@ pragma ComponentBehavior: Bound +import ZShell +import ZShell.Components import ZShell.Config import ZShell.Llm import QtQuick @@ -22,21 +24,25 @@ Item { target: ChatState } - ColumnLayout { + SnapLayout { id: layout anchors.fill: parent + spacing: Tokens.spacing.small + orientation: Qt.Vertical Tabs { + id: tabs Layout.fillWidth: true - Layout.preferredHeight: ChatState.isWindow || !Config.llm.enabled ? 0 : implicitHeight + Layout.preferredHeight: ZUtils.snap(ChatState.isWindow || !Config.llm.enabled ? 0 : implicitHeight, root) screenState: root.screenState nonAnimWidth: layout.width visible: height > 0 } Item { + id: tabContent Layout.fillHeight: true Layout.fillWidth: true clip: true @@ -161,10 +167,11 @@ Item { } CustomRect { + id: separator Layout.fillWidth: true - Layout.topMargin: Tokens.padding.small - layout.spacing + Layout.topMargin: ZUtils.snap(Tokens.padding.small - layout.spacing, root) color: Colors.tPalette.m3outlineVariant - implicitHeight: 1 + implicitHeight: Math.abs(pages.x) > root.width / 2 ? ZUtils.snapFloor(1, root) : ZUtils.snap(1, root) } } } diff --git a/Modules/Sidebar/Notif.qml b/Modules/Sidebar/Notif.qml index ae7a016..ebc56b9 100644 --- a/Modules/Sidebar/Notif.qml +++ b/Modules/Sidebar/Notif.qml @@ -7,6 +7,7 @@ import ZShell.Config import qs.Components import qs.Services import qs.Daemons +import ZShell.Components CustomRect { id: root @@ -26,8 +27,7 @@ CustomRect { state: expanded ? "expanded" : "" Behavior on implicitHeight { - Anim { - } + Anim {} } states: State { name: "expanded" @@ -116,14 +116,14 @@ CustomRect { anchors.topMargin: Tokens.spacing.extraSmall shouldBeActive: root.expanded - sourceComponent: ExpandedBody { - } + sourceComponent: ExpandedBody {} } - component ExpandedBody: ColumnLayout { + component ExpandedBody: SnapLayout { readonly property alias body: bodyText spacing: Tokens.spacing.medium + orientation: Qt.Vertical CustomText { id: bodyText diff --git a/Modules/Sidebar/NotifActionList.qml b/Modules/Sidebar/NotifActionList.qml index 1bd33b5..9797e26 100644 --- a/Modules/Sidebar/NotifActionList.qml +++ b/Modules/Sidebar/NotifActionList.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import Quickshell import Quickshell.Widgets import ZShell.Config +import ZShell.Components import qs.Components import qs.Effects import qs.Services @@ -16,115 +17,107 @@ Item { required property NotifServer.Notif notif Layout.fillWidth: true - implicitHeight: flickable.contentHeight + implicitHeight: actionList.implicitHeight - CustomFlickable { - id: flickable + SnapLayout { + id: actionList anchors.fill: parent - contentHeight: actionList.implicitHeight - contentWidth: Math.max(width, actionList.implicitWidth) + spacing: Tokens.spacing.extraSmall - RowLayout { - id: actionList + Repeater { + model: [ + { + isClose: true + }, + ...(root.notif?.actions ?? []), + { + isCopy: true + } + ] - anchors.fill: parent - spacing: Tokens.spacing.extraSmall + CustomRect { + id: action - Repeater { - model: [ - { - isClose: true - }, - ...(root.notif?.actions ?? []), - { - isCopy: true + required property var modelData + + Layout.fillHeight: true + Layout.fillWidth: true + Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? Tokens.padding.large : 0) + color: Colors.layer(Colors.palette.m3surfaceContainerHighest, 4) + implicitHeight: actionInner.implicitHeight + Tokens.padding.small + implicitWidth: actionInner.implicitWidth + Tokens.padding.medium * 2 + radius: actionStateLayer.pressed ? Tokens.rounding.medium / 2 : Tokens.rounding.large + + Behavior on Layout.preferredWidth { + Anim { + type: Anim.FastSpatial } - ] + } + Behavior on radius { + Anim { + type: Anim.FastSpatial + } + } - CustomRect { - id: action + Timer { + id: copyTimer - required property var modelData + interval: 3000 - Layout.fillHeight: true - Layout.fillWidth: true - Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? Tokens.padding.large : 0) - color: Colors.layer(Colors.palette.m3surfaceContainerHighest, 4) - implicitHeight: actionInner.implicitHeight + Tokens.padding.small - implicitWidth: actionInner.implicitWidth + Tokens.padding.medium * 2 - radius: actionStateLayer.pressed ? Tokens.rounding.medium / 2 : Tokens.rounding.large + onTriggered: actionInner.item.text = "content_copy" + } - Behavior on Layout.preferredWidth { - Anim { - type: Anim.FastSpatial + StateLayer { + id: actionStateLayer + + onClicked: { + if (action.modelData.isClose) { + root.notif.close(); + } else if (action.modelData.isCopy) { + Quickshell.clipboardText = root.notif.body; + actionInner.item.text = "inventory"; + copyTimer.start(); + } else if (action.modelData.invoke) { + action.modelData.invoke(); + } else if (!root.notif.resident) { + root.notif.close(); } } - Behavior on radius { - Anim { - type: Anim.FastSpatial - } + } + + Loader { + id: actionInner + + anchors.centerIn: parent + sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif?.hasActionIcons ? iconComp : textComp + } + + Component { + id: iconBtn + + MaterialIcon { + animate: action.modelData.isCopy ?? false + color: Colors.palette.m3onSurfaceVariant + text: action.modelData.isCopy ? "content_copy" : "close" } + } - Timer { - id: copyTimer + Component { + id: iconComp - interval: 3000 - - onTriggered: actionInner.item.text = "content_copy" + IconImage { + asynchronous: true + source: Quickshell.iconPath(action.modelData.identifier) } + } - StateLayer { - id: actionStateLayer + Component { + id: textComp - onClicked: { - if (action.modelData.isClose) { - root.notif.close(); - } else if (action.modelData.isCopy) { - Quickshell.clipboardText = root.notif.body; - actionInner.item.text = "inventory"; - copyTimer.start(); - } else if (action.modelData.invoke) { - action.modelData.invoke(); - } else if (!root.notif.resident) { - root.notif.close(); - } - } - } - - Loader { - id: actionInner - - anchors.centerIn: parent - sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif?.hasActionIcons ? iconComp : textComp - } - - Component { - id: iconBtn - - MaterialIcon { - animate: action.modelData.isCopy ?? false - color: Colors.palette.m3onSurfaceVariant - text: action.modelData.isCopy ? "content_copy" : "close" - } - } - - Component { - id: iconComp - - IconImage { - asynchronous: true - source: Quickshell.iconPath(action.modelData.identifier) - } - } - - Component { - id: textComp - - CustomText { - color: Colors.palette.m3onSurfaceVariant - text: action.modelData.text - } + CustomText { + color: Colors.palette.m3onSurfaceVariant + text: action.modelData.text } } } diff --git a/Modules/Sidebar/NotifDock.qml b/Modules/Sidebar/NotifDock.qml index e9b9227..7ae85d1 100644 --- a/Modules/Sidebar/NotifDock.qml +++ b/Modules/Sidebar/NotifDock.qml @@ -1,13 +1,14 @@ pragma ComponentBehavior: Bound -import qs.Components -import ZShell.Config -import qs.Modules -import qs.Daemons import Quickshell import Quickshell.Widgets import QtQuick import QtQuick.Layouts +import ZShell.Components +import ZShell.Config +import qs.Components +import qs.Modules +import qs.Daemons import qs.Services Item { @@ -80,8 +81,9 @@ Item { Behavior on opacity { Anim {} } - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { spacing: 20 + orientation: Qt.Vertical CustomText { Layout.alignment: Qt.AlignHCenter diff --git a/Modules/Sidebar/NotifGroup.qml b/Modules/Sidebar/NotifGroup.qml index 4cb7b67..98e6cfb 100644 --- a/Modules/Sidebar/NotifGroup.qml +++ b/Modules/Sidebar/NotifGroup.qml @@ -9,6 +9,7 @@ import qs.Components import qs.Services import qs.Helpers import qs.Daemons +import ZShell.Components CustomRect { id: root @@ -52,8 +53,7 @@ CustomRect { radius: Tokens.rounding.large Behavior on implicitHeight { - Anim { - } + Anim {} } Component.onDestruction: { @@ -61,13 +61,16 @@ CustomRect { screenState.expandedNotifs.splice(screenState.expandedNotifs.indexOf(modelData), 1); } - RowLayout { + SnapLayout { id: content anchors.left: parent.left anchors.margins: Tokens.padding.small anchors.right: parent.right anchors.top: parent.top + + objectName: "notif-content" + spacing: Tokens.spacing.medium Item { @@ -148,24 +151,29 @@ CustomRect { } } - Column { + SnapLayout { id: column Layout.fillWidth: true + spacing: root.expanded ? Math.round(Tokens.spacing.extraSmall) : 0 + orientation: Qt.Vertical + + objectName: "notif-column" Behavior on spacing { - Anim { - } + Anim {} } - RowLayout { + SnapLayout { id: header - anchors.left: parent.left - anchors.right: parent.right + Layout.fillWidth: true + spacing: Tokens.spacing.small + objectName: "notif-header" + CustomText { Layout.fillWidth: true color: Colors.palette.m3onSurfaceVariant @@ -191,12 +199,14 @@ CustomRect { onClicked: root.toggleExpand(!root.expanded) } - RowLayout { + SnapLayout { id: expandBtn anchors.centerIn: parent spacing: Tokens.spacing.extraSmall + objectName: "notif-expand" + CustomText { id: groupCount @@ -214,12 +224,10 @@ CustomRect { text: "expand_more" Behavior on Layout.topMargin { - Anim { - } + Anim {} } Behavior on rotation { - Anim { - } + Anim {} } } } @@ -229,6 +237,8 @@ CustomRect { NotifGroupList { id: notifList + Layout.fillWidth: true + container: root.container expanded: root.expanded notifs: root.notifs diff --git a/Modules/Sidebar/NotifGroupList.qml b/Modules/Sidebar/NotifGroupList.qml index b047878..9da9aab 100644 --- a/Modules/Sidebar/NotifGroupList.qml +++ b/Modules/Sidebar/NotifGroupList.qml @@ -18,8 +18,6 @@ LazyListView { signal requestToggleExpand(expand: bool) - anchors.left: parent.left - anchors.right: parent.right asynchronous: true cacheBuffer: 400 implicitHeight: contentHeight @@ -59,18 +57,15 @@ LazyListView { } } Behavior on scale { - Anim { - } + Anim {} } Behavior on x { - Anim { - } + Anim {} } Behavior on y { enabled: notif.LazyListView.ready - Anim { - } + Anim {} } Component.onCompleted: modelData?.lock(this) diff --git a/Modules/Sidebar/Tabs.qml b/Modules/Sidebar/Tabs.qml index 3dbd448..2ef6570 100644 --- a/Modules/Sidebar/Tabs.qml +++ b/Modules/Sidebar/Tabs.qml @@ -4,6 +4,7 @@ import QtQuick import QtQuick.Layouts import QtQuick.Templates import Quickshell +import ZShell.Components import ZShell.Config import qs.Components import qs.Services @@ -27,7 +28,7 @@ Item { currentIndex: root.screenState.sidebarTab implicitHeight: contentHeight - contentItem: RowLayout { + contentItem: SnapLayout { spacing: 0 Repeater { @@ -105,7 +106,7 @@ Item { implicitWidth: Math.max(icon.width, label.width) StateLayer { - color: tab.current ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface + color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurface radius: Tokens.rounding.small onClicked: root.screenState.sidebarTab = tab.TabBar.index diff --git a/Modules/Sidebar/Utils/Cards/Record.qml b/Modules/Sidebar/Utils/Cards/Record.qml index 5094d86..c9f6197 100644 --- a/Modules/Sidebar/Utils/Cards/Record.qml +++ b/Modules/Sidebar/Utils/Cards/Record.qml @@ -3,8 +3,10 @@ pragma ComponentBehavior: Bound import Quickshell import QtQuick import QtQuick.Layouts -import qs.Components +import ZShell.Components +import ZShell import ZShell.Config +import qs.Components import qs.Helpers import qs.Services @@ -15,17 +17,18 @@ CustomRect { Layout.fillWidth: true color: Colors.tPalette.m3surfaceContainer - implicitHeight: layout.implicitHeight + layout.anchors.margins * 2 + implicitHeight: ZUtils.snap(layout.implicitHeight + layout.anchors.margins * 2, root) radius: Tokens.rounding.small - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout anchors.fill: parent anchors.margins: Tokens.padding.large spacing: Tokens.spacing.medium - RowLayout { + SnapLayout { spacing: Tokens.spacing.medium z: 1 @@ -50,7 +53,8 @@ CustomRect { } } - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical Layout.fillWidth: true spacing: 0 @@ -194,7 +198,7 @@ CustomRect { Component { id: recordingControls - RowLayout { + SnapLayout { spacing: Tokens.spacing.medium CustomRect { diff --git a/Modules/Sidebar/Utils/Cards/RecordingList.qml b/Modules/Sidebar/Utils/Cards/RecordingList.qml index e06e927..b8c1985 100644 --- a/Modules/Sidebar/Utils/Cards/RecordingList.qml +++ b/Modules/Sidebar/Utils/Cards/RecordingList.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import ZShell.Components import Quickshell import Quickshell.Widgets import ZShell.Models @@ -11,7 +12,8 @@ import qs.Paths import ZShell.Config import qs.Services -ColumnLayout { +SnapLayout { +orientation: Qt.Vertical id: root required property ScreenState screenState @@ -24,7 +26,7 @@ ColumnLayout { onClicked: root.screenState.recordingListExpanded = !root.screenState.recordingListExpanded - RowLayout { + SnapLayout { spacing: Tokens.spacing.small MaterialIcon { @@ -74,7 +76,7 @@ ColumnLayout { to: 1 } } - delegate: RowLayout { + delegate: SnapLayout { id: recording property string baseName @@ -168,7 +170,8 @@ ColumnLayout { Behavior on opacity { Anim {} } - sourceComponent: ColumnLayout { + sourceComponent: SnapLayout { +orientation: Qt.Vertical spacing: Tokens.spacing.small MaterialIcon { @@ -191,7 +194,7 @@ ColumnLayout { } } - RowLayout { + SnapLayout { spacing: Tokens.spacing.small MaterialIcon { diff --git a/Modules/Sidebar/Utils/Cards/Toggles.qml b/Modules/Sidebar/Utils/Cards/Toggles.qml index e0128f9..14d5785 100644 --- a/Modules/Sidebar/Utils/Cards/Toggles.qml +++ b/Modules/Sidebar/Utils/Cards/Toggles.qml @@ -45,7 +45,8 @@ CustomRect { implicitHeight: layout.implicitHeight + Tokens.padding.extraLargeIncreased radius: Tokens.rounding.small - ColumnLayout { + SnapLayout { +orientation: Qt.Vertical id: layout anchors.fill: parent diff --git a/Modules/Sidebar/Utils/Content.qml b/Modules/Sidebar/Utils/Content.qml index 81e9296..749adf2 100644 --- a/Modules/Sidebar/Utils/Content.qml +++ b/Modules/Sidebar/Utils/Content.qml @@ -2,22 +2,26 @@ import Quickshell import QtQuick import QtQuick.Layouts import ZShell.Config +import ZShell import qs.Components import qs.Modules.Sidebar.Utils.Cards +import ZShell.Components Item { id: root required property ScreenState screenState - implicitHeight: layout.implicitHeight - implicitWidth: layout.implicitWidth + implicitHeight: ZUtils.snap(layout.implicitHeight, root) + implicitWidth: ZUtils.snap(layout.implicitWidth, root) - ColumnLayout { + SnapLayout { id: layout anchors.fill: parent - spacing: 8 + + spacing: Tokens.spacing.small + orientation: Qt.Vertical IdleInhibit {} diff --git a/Modules/Sidebar/Utils/IdleInhibit.qml b/Modules/Sidebar/Utils/IdleInhibit.qml index 7cb4b6e..f5d85ca 100644 --- a/Modules/Sidebar/Utils/IdleInhibit.qml +++ b/Modules/Sidebar/Utils/IdleInhibit.qml @@ -1,8 +1,10 @@ -import qs.Components -import ZShell.Config -import qs.Helpers import QtQuick import QtQuick.Layouts +import ZShell +import ZShell.Config +import ZShell.Components +import qs.Components +import qs.Helpers import qs.Services CustomRect { @@ -11,21 +13,22 @@ CustomRect { Layout.fillWidth: true clip: true color: Colors.tPalette.m3surfaceContainer - implicitHeight: layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2 + implicitHeight: ZUtils.snap((layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2), root) radius: Tokens.rounding.small Behavior on implicitHeight { Anim {} } - RowLayout { + SnapLayout { id: layout anchors.left: parent.left anchors.margins: 18 anchors.right: parent.right anchors.top: parent.top - spacing: 10 + + spacing: Tokens.spacing.medium CustomRect { color: IdleInhibitor.enabled ? Colors.palette.m3secondary : Colors.palette.m3secondaryContainer @@ -43,9 +46,11 @@ CustomRect { } } - ColumnLayout { + SnapLayout { Layout.fillWidth: true + spacing: 0 + orientation: Qt.Vertical CustomText { Layout.fillWidth: true diff --git a/Plugins/CMakeLists.txt b/Plugins/CMakeLists.txt index 43f93e5..d543c69 100644 --- a/Plugins/CMakeLists.txt +++ b/Plugins/CMakeLists.txt @@ -7,10 +7,13 @@ find_package(Qt6 REQUIRED COMPONENTS Quick CanvasPainter QuickPrivate + QuickLayouts + QuickLayoutsPrivate Concurrent Sql Network DBus + Svg CanvasPainter WaylandClient WaylandClientPrivate diff --git a/Plugins/ZShell/CMakeLists.txt b/Plugins/ZShell/CMakeLists.txt index 7d1bbaf..0585b5b 100644 --- a/Plugins/ZShell/CMakeLists.txt +++ b/Plugins/ZShell/CMakeLists.txt @@ -9,12 +9,19 @@ qml_module(ZShell toaster.hpp toaster.cpp qalculator.hpp qalculator.cpp zutils.hpp zutils.cpp + alignaudit.hpp alignaudit.cpp + alignauditor.hpp alignauditor.cpp LIBRARIES - Qt::Gui - Qt::Quick - Qt::Concurrent - Qt::Sql - Qt::DBus + Qt6::Gui + Qt6::Quick + Qt6::QuickPrivate + Qt6::QuickLayouts + Qt6::QuickLayoutsPrivate + Qt6::QmlPrivate + Qt6::CorePrivate + Qt6::Concurrent + Qt6::Sql + Qt6::DBus PkgConfig::Qalculate zshell-util ) @@ -24,6 +31,9 @@ target_compile_definitions(ZShell PRIVATE GIT_REVISION="${GIT_REVISION}" ) +target_compile_definitions(ZShell PRIVATE ALIGN_AUDIT_USE_QML_PRIVATE) + + # Node macros expand to Q_OBJECT, automoc can't see it otherwise list(APPEND CMAKE_AUTOMOC_MACRO_NAMES CONFIG_NODE diff --git a/Plugins/ZShell/Components/CMakeLists.txt b/Plugins/ZShell/Components/CMakeLists.txt index f732ea2..af2766f 100644 --- a/Plugins/ZShell/Components/CMakeLists.txt +++ b/Plugins/ZShell/Components/CMakeLists.txt @@ -1,5 +1,6 @@ qml_module(ZShell-components URI ZShell.Components + DEPENDENCIES QtQuick.Layouts SOURCES lazylistview.hpp lazylistview.cpp chatlistview.hpp chatlistview.cpp @@ -12,10 +13,14 @@ qml_module(ZShell-components sparklinesceneitem.hpp sparklinesceneitem.cpp roundedmask.hpp roundedmask.cpp roundedclip.hpp roundedclip.cpp + snaplayout.hpp snaplayout.cpp wheelinverter.hpp LIBRARIES Qt::Quick Qt::QuickPrivate + Qt::QuickLayouts + Qt::QuickLayoutsPrivate + Qt::GuiPrivate Qt::CanvasPainter ZShell-internal ) diff --git a/Plugins/ZShell/Components/snaplayout.cpp b/Plugins/ZShell/Components/snaplayout.cpp new file mode 100644 index 0000000..44798a2 --- /dev/null +++ b/Plugins/ZShell/Components/snaplayout.cpp @@ -0,0 +1,419 @@ +#include "snaplayout.hpp" + +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(lcQuickLayouts, "qt.quick.layouts") + +namespace ZShell::components { +namespace { + +qint64 originResidual(qreal logical, qreal dpr) { + const qreal device = logical * dpr; + return std::llround((device - std::floor(device)) * 1024.0) % 1024; +} + +QPointF absoluteOrigin(const QQuickItem* item) { + qreal x = 0.0; + qreal y = 0.0; + for (const QQuickItem* it = item; it; it = it->parentItem()) { + x += it->x(); + y += it->y(); + } + return QPointF(x, y); +} + +} // namespace + +qreal SnapLayoutStyleInfo::spacing(Qt::Orientation /*orientation*/) const { +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_QNX) + qreal spacing = 8.0; +#else + qreal spacing = 5.0; +#endif +#if !defined(Q_OS_MACOS) && !defined(Q_OS_HARMONY) + spacing = qRound(spacing * (qreal(qt_defaultDpiX()) / 96.0)); +#endif + return spacing; +} + +qreal SnapLayoutStyleInfo::windowMargin(Qt::Orientation /*orientation*/) const { + return 0; +} + +bool SnapLayoutStyleInfo::hasChangedCore() const { + return false; +} + +SnapGridLayoutItem::SnapGridLayoutItem( + QQuickItem* item, + int row, + int column, + int rowSpan, + int columnSpan, + Qt::Alignment alignment, + SnapLayout* layout) + : QQuickGridLayoutItem(item, row, column, rowSpan, columnSpan, alignment) + , m_layout(layout) {} + +void SnapGridLayoutItem::setGeometry(const QRectF& rect) { + QQuickLayoutAttached* info = attachedLayoutObject(m_item, false); + QRectF placed = info ? rect.marginsRemoved(info->effectiveQMargins()) + : rect; + + const QQuickWindow* win = m_item->window(); + const qreal dpr = win ? win->effectiveDevicePixelRatio() : 1.0; + + if (dpr > 0.0) { + const QPointF origin = absoluteOrigin(m_layout); + const qreal left = (origin.x() + placed.x()) * dpr; + const qreal top = (origin.y() + placed.y()) * dpr; + const qreal right = (origin.x() + placed.right()) * dpr; + const qreal bottom = (origin.y() + placed.bottom()) * dpr; + + const qint64 nearX = std::llround(left); + const qint64 nearY = std::llround(top); + const qint64 farX = std::llround(right); + const qint64 farY = std::llround(bottom); + + placed = QRectF( + qreal(nearX) / dpr - origin.x(), + qreal(nearY) / dpr - origin.y(), + qreal(farX - nearX) / dpr, + qreal(farY - nearY) / dpr); + } + + const QSizeF oldSize(m_item->width(), m_item->height()); + const QSizeF newSize = placed.size(); + + m_item->setPosition(placed.topLeft()); + if (newSize == oldSize) { + if (QQuickLayout* lay = qobject_cast(m_item)) { + if (lay->invalidatedArrangement()) lay->rearrange(newSize); + } + } else { + m_item->setSize(newSize); + } +} + +void SnapLayoutPrivate::mirrorChange() { + Q_Q(SnapLayout); + q->invalidate(); +} + +SnapLayout::SnapLayout(QQuickItem* parent) + : QQuickLayout(*new SnapLayoutPrivate, parent) { + d_func()->styleInfo = new SnapLayoutStyleInfo; +} + +SnapLayout::~SnapLayout() { + Q_D(SnapLayout); + clearAncestorListeners(); + deactivateRecur(); + delete d->styleInfo; +} + +void SnapLayout::componentComplete() { + QQuickLayout::componentComplete(); + + invalidate(); + ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints); + + if (qobject_cast(parentItem())) return; + rearrange(QSizeF(width(), height())); +} + +void SnapLayout::itemChange(ItemChange change, const ItemChangeData& value) { + QQuickLayout::itemChange(change, value); + if (change == ItemDevicePixelRatioHasChanged || change == ItemSceneChange) + invalidate(); +} + +QSizeF SnapLayout::sizeHint(Qt::SizeHint whichSizeHint) const { + Q_D(const SnapLayout); + return d->engine.sizeHint(whichSizeHint, QSizeF(), d->styleInfo); +} + +Qt::Orientation SnapLayout::orientation() const { + return d_func()->orientation; +} + +void SnapLayout::setOrientation(Qt::Orientation orientation) { + Q_D(SnapLayout); + if (d->orientation == orientation) return; + d->orientation = orientation; + invalidate(); + emit orientationChanged(); +} + +Qt::LayoutDirection SnapLayout::layoutDirection() const { + return d_func()->layoutDirection; +} + +void SnapLayout::setLayoutDirection(Qt::LayoutDirection direction) { + Q_D(SnapLayout); + if (d->layoutDirection == direction) return; + d->layoutDirection = direction; + invalidate(); + emit layoutDirectionChanged(); +} + +Qt::LayoutDirection SnapLayout::effectiveLayoutDirection() const { + return !isMirrored() == (layoutDirection() == Qt::LeftToRight) + ? Qt::LeftToRight + : Qt::RightToLeft; +} + +qreal SnapLayout::spacing() const { + Q_D(const SnapLayout); + return d->engine.spacing(d->orientation, d->styleInfo); +} + +void SnapLayout::setSpacing(qreal space) { + Q_D(SnapLayout); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + if (std::isnan(space) || spacing() == space) return; +#pragma GCC diagnostic pop + d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical); + invalidate(); + emit spacingChanged(); +} + +bool SnapLayout::uniformCellSizes() const { + Q_D(const SnapLayout); + return d->engine.uniformCellWidths(); +} + +void SnapLayout::setUniformCellSizes(bool uniformCellSizes) { + Q_D(SnapLayout); + if (d->engine.uniformCellHeights() == uniformCellSizes) return; + d->engine.setUniformCellWidths(uniformCellSizes); + d->engine.setUniformCellHeights(uniformCellSizes); + invalidate(); + emit uniformCellSizesChanged(); +} + +void SnapLayout::setAlignment(QQuickItem* item, Qt::Alignment align) { + Q_D(SnapLayout); + if (QQuickGridLayoutItem* layoutItem = d->engine.findLayoutItem(item)) { + layoutItem->setAlignment(align); + d->engine.invalidate(); + } + maybeSubscribeToBaseLineOffsetChanges(item); +} + +void SnapLayout::setStretchFactor( + QQuickItem* item, int stretchFactor, Qt::Orientation orient) { + Q_D(SnapLayout); + if (QQuickGridLayoutItem* layoutItem = d->engine.findLayoutItem(item)) { + layoutItem->setStretchFactor(stretchFactor, orient); + d->engine.invalidate(); + } +} + +void SnapLayout::invalidate(QQuickItem* childItem) { + Q_D(SnapLayout); + if (!isReady()) return; + + if (childItem) { + if (d->rearranging) { + if (!d->invalidateAfterRearrange.contains(childItem)) + d->invalidateAfterRearrange << childItem; + return; + } + if (QQuickGridLayoutItem* layoutItem = + d->engine.findLayoutItem(childItem)) { + layoutItem->invalidate(); + } + } + + d->engine.invalidate(); + QQuickLayout::invalidate(); + + if (auto* parentLayout = qobject_cast(parentItem())) + parentLayout->invalidate(this); +} + +void SnapLayout::updateLayoutItems() { + Q_D(SnapLayout); + if (!isReady()) return; + + d->engine.deleteItems(); + insertLayoutItems(); +} + +QQuickItem* SnapLayout::itemAt(int index) const { + Q_D(const SnapLayout); + return static_cast(d->engine.itemAt(index)) + ->layoutItem(); +} + +int SnapLayout::itemCount() const { + Q_D(const SnapLayout); + return d->engine.itemCount(); +} + +void SnapLayout::insertLayoutItems() { + Q_D(SnapLayout); + const auto items = childItems(); + for (QQuickItem* child : items) { + Q_ASSERT(child); + checkAnchors(child); + + if (shouldIgnoreItem(child)) continue; + QQuickLayoutAttached* info = attachedLayoutObject(child, false); + + Qt::Alignment alignment; + int hStretch = -1; + int vStretch = -1; + bool fillWidth = false; + bool fillHeight = false; + if (info) { + alignment = info->alignment(); + hStretch = info->horizontalStretchFactor(); + vStretch = info->verticalStretchFactor(); + fillWidth = info->fillWidth(); + fillHeight = info->fillHeight(); + } + + const int index = d->engine.rowCount(d->orientation); + d->engine.insertRow(index, d->orientation); + + int gridRow = 0; + int gridColumn = index; + if (d->orientation == Qt::Vertical) qSwap(gridRow, gridColumn); + QGridLayoutItem* layoutItem = new SnapGridLayoutItem( + child, gridRow, gridColumn, 1, 1, alignment, this); + + if (hStretch >= 0) { + if (!fillWidth) + qWarning() << "horizontalStretchFactor requires fillWidth to " + "also be set to true"; + layoutItem->setStretchFactor(hStretch, Qt::Horizontal); + } + if (vStretch >= 0) { + if (!fillHeight) + qWarning() << "verticalStretchFactor requires fillHeight to " + "also be set to true"; + layoutItem->setStretchFactor(vStretch, Qt::Vertical); + } + d->engine.insertItem(layoutItem, index); + } +} + +void SnapLayout::removeGridItem(QGridLayoutItem* gridItem) { + Q_D(SnapLayout); + const int index = gridItem->firstRow(d->orientation); + d->engine.removeItem(gridItem); + d->engine.removeRows(index, 1, d->orientation); +} + +void SnapLayout::itemDestroyed(QQuickItem* item) { + if (!isReady()) return; + Q_D(SnapLayout); + if (QQuickGridLayoutItem* gridItem = d->engine.findLayoutItem(item)) { + removeGridItem(gridItem); + delete gridItem; + invalidate(); + } +} + +void SnapLayout::itemVisibilityChanged(QQuickItem* item) { + if (!isReady()) return; + invalidate(item); +} + +void SnapLayout::itemGeometryChanged( + QQuickItem* item, QQuickGeometryChange change, const QRectF& oldGeometry) { + Q_UNUSED(item); + Q_UNUSED(oldGeometry); + if (!isReady() || !change.positionChange()) return; + + Q_D(SnapLayout); + const QQuickWindow* win = window(); + const qreal dpr = win ? win->effectiveDevicePixelRatio() : 0.0; + if (dpr <= 0.0) return; + + const QPointF origin = absoluteOrigin(this); + if (originResidual(origin.x(), dpr) == d->originResidualX && + originResidual(origin.y(), dpr) == d->originResidualY) + return; + polish(); +} + +void SnapLayout::updateAncestorListeners() { + Q_D(SnapLayout); + QVector current; + for (QQuickItem* it = parentItem(); it; it = it->parentItem()) { + if (qobject_cast(it)) break; + current.append(it); + } + + for (const QPointer& ancestor : + std::as_const(d->ancestorListeners)) { + if (ancestor && !current.contains(ancestor.data())) + QQuickItemPrivate::get(ancestor.data()) + ->removeItemChangeListener(this, QQuickItemPrivate::Geometry); + } + for (QQuickItem* ancestor : std::as_const(current)) { + if (!d->ancestorListeners.contains(ancestor)) + QQuickItemPrivate::get(ancestor)->addItemChangeListener( + this, QQuickItemPrivate::Geometry); + } + d->ancestorListeners.clear(); + d->ancestorListeners.reserve(current.size()); + for (QQuickItem* ancestor : std::as_const(current)) + d->ancestorListeners.append(ancestor); +} + +void SnapLayout::clearAncestorListeners() { + Q_D(SnapLayout); + for (const QPointer& ancestor : + std::as_const(d->ancestorListeners)) { + if (ancestor) + QQuickItemPrivate::get(ancestor.data()) + ->removeItemChangeListener(this, QQuickItemPrivate::Geometry); + } + d->ancestorListeners.clear(); +} + +void SnapLayout::rearrange(const QSizeF& size) { + Q_D(SnapLayout); + if (!isReady() || !size.isValid()) return; + + const auto refCounter = qScopeGuard([&d] { --(d->recurRearrangeCounter); }); + if (d->recurRearrangeCounter++ == 2) { + qWarning() << "Qt Quick Layouts: Detected recursive rearrange. " + "Aborting after two iterations."; + return; + } + + ensureLayoutItemsUpdated( + QQuickLayout::ApplySizeHints | QQuickLayout::Recursive); + + d->rearranging = true; + d->engine.setVisualDirection(effectiveLayoutDirection()); + updateAncestorListeners(); + + if (const QQuickWindow* win = window()) { + if (const qreal dpr = win->effectiveDevicePixelRatio(); dpr > 0.0) { + const QPointF origin = absoluteOrigin(this); + d->originResidualX = originResidual(origin.x(), dpr); + d->originResidualY = originResidual(origin.y(), dpr); + } + } + + QQuickLayout::rearrange(size); + d->engine.setGeometries(QRectF(QPointF(0, 0), size), d->styleInfo); + d->rearranging = false; + + for (auto childItem : std::as_const(d->invalidateAfterRearrange)) + invalidate(childItem); + d->invalidateAfterRearrange.clear(); +} + +} // namespace ZShell::components diff --git a/Plugins/ZShell/Components/snaplayout.hpp b/Plugins/ZShell/Components/snaplayout.hpp new file mode 100644 index 0000000..150ae02 --- /dev/null +++ b/Plugins/ZShell/Components/snaplayout.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ZShell::components { + +class SnapLayout; +class SnapLayoutPrivate; + +class SnapLayoutStyleInfo : public QAbstractLayoutStyleInfo { + public: + qreal spacing(Qt::Orientation orientation) const override; + qreal windowMargin(Qt::Orientation orientation) const override; + bool hasChangedCore() const override; +}; + +class SnapGridLayoutItem : public QQuickGridLayoutItem { + public: + SnapGridLayoutItem( + QQuickItem* item, + int row, + int column, + int rowSpan, + int columnSpan, + Qt::Alignment alignment, + SnapLayout* layout); + + void setGeometry(const QRectF& rect) override; + + private: + SnapLayout* m_layout; +}; + +class SnapLayout : public QQuickLayout { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY( + Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY + orientationChanged) + Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) + Q_PROPERTY( + Qt::LayoutDirection layoutDirection READ layoutDirection WRITE + setLayoutDirection NOTIFY layoutDirectionChanged) + Q_PROPERTY( + bool uniformCellSizes READ uniformCellSizes WRITE setUniformCellSizes + NOTIFY uniformCellSizesChanged) + + public: + explicit SnapLayout(QQuickItem* parent = nullptr); + ~SnapLayout() override; + + void componentComplete() override; + QSizeF sizeHint(Qt::SizeHint whichSizeHint) const override; + void setAlignment(QQuickItem* item, Qt::Alignment align) override; + void setStretchFactor( + QQuickItem* item, int stretchFactor, Qt::Orientation orient) override; + void invalidate(QQuickItem* childItem = nullptr) override; + void updateLayoutItems() override; + QQuickItem* itemAt(int index) const override; + int itemCount() const override; + void rearrange(const QSizeF& size) override; + + void itemChange(ItemChange change, const ItemChangeData& value) override; + + void itemDestroyed(QQuickItem* item) override; + void itemVisibilityChanged(QQuickItem* item) override; + void itemGeometryChanged( + QQuickItem* item, + QQuickGeometryChange change, + const QRectF& oldGeometry) override; + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + + qreal spacing() const; + void setSpacing(qreal spacing); + + Qt::LayoutDirection layoutDirection() const; + void setLayoutDirection(Qt::LayoutDirection direction); + Qt::LayoutDirection effectiveLayoutDirection() const; + + bool uniformCellSizes() const; + void setUniformCellSizes(bool uniformCellSizes); + + signals: + void orientationChanged(); + void spacingChanged(); + void layoutDirectionChanged(); + void uniformCellSizesChanged(); + + private: + Q_DECLARE_PRIVATE(SnapLayout) + + void insertLayoutItems(); + void removeGridItem(QGridLayoutItem* gridItem); + + void updateAncestorListeners(); + void clearAncestorListeners(); +}; + +class SnapLayoutPrivate : public QQuickLayoutPrivate { + Q_DECLARE_PUBLIC(SnapLayout) + + public: + SnapLayoutPrivate() = default; + + void mirrorChange() override; + + QQuickGridLayoutEngine engine; + SnapLayoutStyleInfo* styleInfo = nullptr; + Qt::Orientation orientation = Qt::Horizontal; + Qt::LayoutDirection layoutDirection = Qt::LeftToRight; + bool rearranging = false; + int recurRearrangeCounter = 0; + QList invalidateAfterRearrange; + + QVector> ancestorListeners; + qint64 originResidualX = -1; + qint64 originResidualY = -1; +}; + +} // namespace ZShell::components diff --git a/Plugins/ZShell/Config/font.hpp b/Plugins/ZShell/Config/font.hpp index ac5c4a7..5e61794 100644 --- a/Plugins/ZShell/Config/font.hpp +++ b/Plugins/ZShell/Config/font.hpp @@ -137,12 +137,12 @@ class FontTokens : public QObject { Q_OBJECT QML_ANONYMOUS - Q_PROPERTY(FontStyle* headline READ headline CONSTANT FINAL) - Q_PROPERTY(FontStyle* title READ title CONSTANT FINAL) - Q_PROPERTY(FontStyle* body READ body CONSTANT FINAL) - Q_PROPERTY(FontStyle* label READ label CONSTANT FINAL) - Q_PROPERTY(FontStyle* mono READ mono CONSTANT FINAL) - Q_PROPERTY(IconFontStyle* icon READ icon CONSTANT FINAL) + Q_PROPERTY(ZShell::config::FontStyle* headline READ headline CONSTANT FINAL) + Q_PROPERTY(ZShell::config::FontStyle* title READ title CONSTANT FINAL) + Q_PROPERTY(ZShell::config::FontStyle* body READ body CONSTANT FINAL) + Q_PROPERTY(ZShell::config::FontStyle* label READ label CONSTANT FINAL) + Q_PROPERTY(ZShell::config::FontStyle* mono READ mono CONSTANT FINAL) + Q_PROPERTY(ZShell::config::IconFontStyle* icon READ icon CONSTANT FINAL) Q_PROPERTY( ZShell::config::FontBuilder clock READ clock NOTIFY clockChanged FINAL) Q_PROPERTY(QString workspaces READ workspaces NOTIFY workspacesChanged FINAL) diff --git a/Plugins/ZShell/Config/launcher.hpp b/Plugins/ZShell/Config/launcher.hpp index 27dafca..8e58b1a 100644 --- a/Plugins/ZShell/Config/launcher.hpp +++ b/Plugins/ZShell/Config/launcher.hpp @@ -21,15 +21,6 @@ class LauncherActionEntry : public settings::ObjectNode { CONFIG_LIST_TYPE(LauncherActionEntry, LauncherActionList) -class LauncherSizes : public settings::ObjectNode { - CONFIG_NODE(LauncherSizes, settings::ObjectNode) - - CONFIG_PROPERTY(int, itemHeight, 50) - CONFIG_PROPERTY(int, itemWidth, 600) - CONFIG_PROPERTY(int, wallpaperHeight, 200) - CONFIG_PROPERTY(int, wallpaperWidth, 280) -}; - class UseFuzzy : public settings::ObjectNode { CONFIG_NODE(UseFuzzy, settings::ObjectNode) @@ -127,7 +118,6 @@ class Launcher : public settings::ObjectNode { CONFIG_PROPERTY(QStringList, hiddenApps, {}) CONFIG_PROPERTY(int, maxAppsShown, 18) CONFIG_PROPERTY(int, maxWallpapers, 7) - CONFIG_SUBOBJECT(LauncherSizes, sizes) CONFIG_PROPERTY(QString, specialPrefix, QStringLiteral("@")) CONFIG_SUBOBJECT(UseFuzzy, useFuzzy) CONFIG_PROPERTY(bool, uwsm, true) diff --git a/Plugins/ZShell/Config/tokens.hpp b/Plugins/ZShell/Config/tokens.hpp index c19848f..07f6b52 100644 --- a/Plugins/ZShell/Config/tokens.hpp +++ b/Plugins/ZShell/Config/tokens.hpp @@ -164,11 +164,21 @@ class DashboardTokens : public settings::ObjectNode { CONFIG_PROPERTY(int, weatherWidth, 250) }; +class LauncherTokens : public settings::ObjectNode { + CONFIG_NODE(LauncherTokens, settings::ObjectNode) + + CONFIG_PROPERTY(int, itemHeight, 50) + CONFIG_PROPERTY(int, itemWidth, 600) + CONFIG_PROPERTY(int, wallpaperHeight, 200) + CONFIG_PROPERTY(int, wallpaperWidth, 280) +}; + class SizeTokens : public settings::ObjectNode { CONFIG_NODE(SizeTokens, settings::ObjectNode) CONFIG_SUBOBJECT(DashboardTokens, dashboard) CONFIG_SUBOBJECT(BarTokens, bar) + CONFIG_SUBOBJECT(LauncherTokens, launcher) }; } // namespace ZShell::config diff --git a/Plugins/ZShell/alignaudit.cpp b/Plugins/ZShell/alignaudit.cpp new file mode 100644 index 0000000..861a21b --- /dev/null +++ b/Plugins/ZShell/alignaudit.cpp @@ -0,0 +1,206 @@ +#include "alignaudit.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ALIGN_AUDIT_USE_QML_PRIVATE +#include +#endif + +namespace ZShell { +namespace { + +bool isOff(double v, double tol) { + return std::abs(v - std::round(v)) > tol; +} + +QString num(double v, bool off) { + return QString::number(v, 'f', 2) + (off ? QStringLiteral("*") : QString()); +} + +QString typeName(const QQuickItem* item) { + static const QRegularExpression suffix(QStringLiteral("_QML(TYPE)?_\\d+$")); + QString name = QString::fromUtf8(item->metaObject()->className()); + name.remove(suffix); + if (name.startsWith(QLatin1String("QQuick"))) { + name.remove(0, 6); + } + return name; +} + +QString label(const QQuickItem* item) { + QString s = typeName(item); + if (!item->objectName().isEmpty()) { + s += QLatin1Char('#') + item->objectName(); + } + return s; +} + +QString ancestry(const QQuickItem* item, int maxDepth = 8) { + QStringList parts; + for (const QQuickItem* i = item; i && parts.size() < maxDepth; + i = i->parentItem()) { + parts.prepend(label(i)); + } + return parts.join(QLatin1String(" > ")); +} + +struct Source { + QString file; + int line = 0; + int column = 0; +}; + +Source sourceOf(QQuickItem* item) { + Source s; + if (const QQmlContext* ctx = qmlContext(item)) { + const QUrl url = ctx->baseUrl(); + s.file = url.isLocalFile() ? url.toLocalFile() : url.toString(); + } +#ifdef ALIGN_AUDIT_USE_QML_PRIVATE + if (const QQmlData* d = QQmlData::get(item, false)) { + s.line = int(d->lineNumber); + s.column = int(d->columnNumber); + } +#endif + return s; +} + +void visit(QQuickItem* item, const std::function& fn) { + if (!item->isVisible() || item->opacity() <= 0.0) { + return; // whole subtree is invisible + } + fn(item); + for (QQuickItem* child : item->childItems()) { + visit(child, fn); + } +} + +int auditWindow(QQuickWindow* window, const Options& o, QTextStream& out) { + const double dpr = window->effectiveDevicePixelRatio(); + const double tol = o.tolerance; + int count = 0; + + visit(window->contentItem(), [&](QQuickItem* item) { + if (item->width() <= 0 || item->height() <= 0) { + return; + } + if (o.paintedOnly && + !item->flags().testFlag(QQuickItem::ItemHasContents) && + !item->clip()) { + return; + } + + const bool isText = item->inherits("QQuickText"); + + const QRectF r = + item->mapRectToScene(QRectF(0, 0, item->width(), item->height())); + const double l = r.left() * dpr, t = r.top() * dpr; + const double rt = r.right() * dpr, b = r.bottom() * dpr; + + const bool offL = isOff(l, tol), offT = isOff(t, tol); + const bool offR = !isText && isOff(rt, tol); + const bool offB = !isText && isOff(b, tol); + if (!(offL || offT || offR || offB)) { + return; + } + + const bool own = isOff(item->x() * dpr, tol) || + isOff(item->y() * dpr, tol) || + (!isText && (isOff(item->width() * dpr, tol) || + isOff(item->height() * dpr, tol))); + if (!own && !o.includeInherited) { + return; + } + + const Source src = sourceOf(item); + out << src.file; + if (src.line > 0) { + out << ':' << src.line << ':' << src.column; + } + out << ": " << label(item) << " unaligned (" + << (own ? "own" : "inherited") << ")\n" + << " device px: left=" << num(l, offL) << " top=" << num(t, offT) + << " right=" << num(rt, offR) << " bottom=" << num(b, offB) << "\n" + << " local: x=" << item->x() << " y=" << item->y() + << " w=" << item->width() << " h=" << item->height() << "\n" + << " path: " << ancestry(item) << "\n"; + ++count; + }); + return count; +} + +} // namespace + +struct ScreenReport { + double dpr = 1.0; + int windows = 0; + int count = 0; + QString body; +}; + +int run(const Options& options) { + QMap reports; + + for (QWindow* w : QGuiApplication::allWindows()) { + auto* qw = qobject_cast(w); + if (!qw || !qw->isVisible() || !qw->contentItem()) { + continue; + } + + const QString name = qw->screen() ? qw->screen()->name() + : QStringLiteral("?"); + ScreenReport& report = reports[name]; + report.dpr = qw->effectiveDevicePixelRatio(); + ++report.windows; + + QString windowBody; + QTextStream stream(&windowBody); + report.count += auditWindow(qw, options, stream); + stream.flush(); + report.body += windowBody; + } + + QFile file(options.outputPath); + if (!file.open( + QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + qWarning() << "AlignAudit: cannot open" << options.outputPath; + return -1; + } + QTextStream out(&file); + + int total = 0; + for (const ScreenReport& r : std::as_const(reports)) { + total += r.count; + } + + out << "# align audit " + << QDateTime::currentDateTime().toString(Qt::ISODate) + << " ('*' marks the off edges, values are device pixels)\n" + << "# total: " << total << "\n\n"; + + for (auto it = reports.cbegin(); it != reports.cend(); ++it) { + out << "# screen " << it.key() << " dpr=" << it.value().dpr + << " windows=" << it.value().windows + << " offenders=" << it.value().count << "\n" + << it.value().body << "\n"; + } + return total; +} + +void runLater(int delayMs, const Options& options) { + QTimer::singleShot(delayMs, qApp, [options] { run(options); }); +} + +} // namespace ZShell diff --git a/Plugins/ZShell/alignaudit.hpp b/Plugins/ZShell/alignaudit.hpp new file mode 100644 index 0000000..ff0a90f --- /dev/null +++ b/Plugins/ZShell/alignaudit.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace ZShell { + +struct Options { + QString outputPath = QStringLiteral("/tmp/align-audit.txt"); + bool paintedOnly = true; // skip items that draw nothing + bool includeInherited = + false; // also report items only off because an ancestor is + double tolerance = 1e-3; // in device pixels +}; + +Q_INVOKABLE void runLater(int delayMs, const Options& options = {}); + +int run(const Options& options = {}); + +} // namespace ZShell diff --git a/Plugins/ZShell/alignauditor.cpp b/Plugins/ZShell/alignauditor.cpp new file mode 100644 index 0000000..7d83519 --- /dev/null +++ b/Plugins/ZShell/alignauditor.cpp @@ -0,0 +1,26 @@ +#include "alignauditor.hpp" + +#include + +namespace ZShell { + +Options AlignAuditor::options() const { + Options o; + o.outputPath = m_outputPath; + o.paintedOnly = m_paintedOnly; + o.includeInherited = m_includeInherited; + o.tolerance = m_tolerance; + return o; +} + +int AlignAuditor::run() { + m_lastCount = ZShell::run(options()); + emit finished(m_lastCount); + return m_lastCount; +} + +void AlignAuditor::runLater() { + QTimer::singleShot(m_delayMs, this, [this] { run(); }); +} + +} // namespace ZShell diff --git a/Plugins/ZShell/alignauditor.hpp b/Plugins/ZShell/alignauditor.hpp new file mode 100644 index 0000000..17279a8 --- /dev/null +++ b/Plugins/ZShell/alignauditor.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include + +#include "alignaudit.hpp" + +namespace ZShell { + +class AlignAuditor : public QObject { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(QString outputPath MEMBER m_outputPath NOTIFY outputPathChanged) + Q_PROPERTY(int delayMs MEMBER m_delayMs NOTIFY delayMsChanged) + Q_PROPERTY(bool paintedOnly MEMBER m_paintedOnly NOTIFY paintedOnlyChanged) + Q_PROPERTY( + bool includeInherited MEMBER m_includeInherited NOTIFY + includeInheritedChanged) + Q_PROPERTY(double tolerance MEMBER m_tolerance NOTIFY toleranceChanged) + Q_PROPERTY(int lastCount READ lastCount NOTIFY finished) + + public: + explicit AlignAuditor(QObject* parent = nullptr) : QObject(parent) {} + + Q_INVOKABLE int run(); + + Q_INVOKABLE void runLater(); + + int lastCount() const { return m_lastCount; } + + signals: + void outputPathChanged(); + void delayMsChanged(); + void paintedOnlyChanged(); + void includeInheritedChanged(); + void toleranceChanged(); + void finished(int count); + + private: + Options options() const; + + QString m_outputPath = QStringLiteral("/tmp/align-audit.txt"); + int m_delayMs = 5000; + bool m_paintedOnly = true; + bool m_includeInherited = false; + double m_tolerance = 1e-3; + int m_lastCount = 0; +}; + +} // namespace ZShell diff --git a/Plugins/ZShell/zutils.cpp b/Plugins/ZShell/zutils.cpp index 8a81a39..fabcce0 100644 --- a/Plugins/ZShell/zutils.cpp +++ b/Plugins/ZShell/zutils.cpp @@ -1,8 +1,14 @@ #include "zutils.hpp" #include +#include +#include #include #include +#include +#include +#include +#include #include #include #include @@ -337,4 +343,422 @@ QStringList ZUtils::listFiles(const QString& dir, const QString& suffix) { return out; } +qreal ZUtils::dprFor(QQuickItem* item) { + if (item) { + if (const QQuickWindow* window = item->window()) { + return window->effectiveDevicePixelRatio(); + } + } + if (const QScreen* screen = QGuiApplication::primaryScreen()) { + return screen->devicePixelRatio(); + } + return 1.0; +} + +namespace { + +// Per-axis centering detected from the item's own state. Anchor lines are +// Q_GADGET values with no properties, so centering is read from the anchors' +// used-anchor bitmask instead of by evaluating `anchors.verticalCenter`. +// Layout alignment comes from the attached Layout object; an item with no +// attached object uses Qt's default (AlignLeft | AlignVCenter). +struct Centering { + bool horizontal = false; + bool vertical = false; + // anchors.alignWhenCentered: false makes Qt round half-sizes in logical px + // (y = qRound(parentSize/2) - qRound(size/2)) instead of dividing exactly. + bool alignWhenCentered = true; + QString source; +}; + +Centering detectCentering(QQuickItem* item) { + Centering c; + QQuickAnchors* anchors = QQuickItemPrivate::get(item)->_anchors; + if (anchors) { + const QQuickAnchorsPrivate* ad = QQuickAnchorsPrivate::get(anchors); + c.alignWhenCentered = ad->centerAligned; + if (ad->usedAnchors & QQuickAnchors::HCenterAnchor) { + c.horizontal = true; + c.source = QStringLiteral("hCenter"); + } + if (ad->usedAnchors & QQuickAnchors::VCenterAnchor) { + c.vertical = true; + c.source += (c.source.isEmpty() ? "" : " ") + QStringLiteral("vCenter"); + } + } + + QQuickItem* parent = item->parentItem(); + if (parent && parent->inherits("QQuickLayout")) { + QQuickLayoutAttached* info = attachedLayoutObject(item, false); + const Qt::Alignment flags = info ? info->alignment() : Qt::Alignment(); + // Filling an axis means the layout stretches that axis, so no centering. + if (info && !info->fillWidth() && (flags & Qt::AlignHCenter)) { + c.horizontal = true; + c.source += (c.source.isEmpty() ? "" : " ") + + QStringLiteral("Layout.HCenter"); + } + const bool defaultVCenter = flags == 0 || (flags & Qt::AlignVCenter); + if ((!info || !info->fillHeight()) && defaultVCenter && + !(flags & (Qt::AlignTop | Qt::AlignBottom))) { + c.vertical = true; + c.source += (c.source.isEmpty() ? "" : " ") + + QStringLiteral("Layout.VCenter"); + } + } + return c; +} + +// Parity (mod 2) of an item's whole-device-pixel size; no item = even. +int devParity(const QQuickItem* it, qreal dpr, bool horizontal) { + if (!it) + return 0; + const qint64 dev = std::llround((horizontal ? it->width() : it->height()) * dpr); + return static_cast(dev % 2); +} + +// Snap a size to a whole device-pixel count whose parity matches `parity` +// (the parent's device-size parity). An item centered by *exact* division +// (Layout alignment, or anchors with alignWhenCentered: true) lands on whole +// device pixels exactly when its device size shares the parent's parity, +// since edges = parentLeft + (parentSize - size) / 2. +qreal snapToParity(qreal value, qreal dpr, int parity, int mode) { + const double exact = value * dpr; + qint64 n = mode > 0 ? std::llround(std::ceil(exact - 1e-6)) + : mode < 0 ? std::llround(std::floor(exact + 1e-6)) + : std::llround(exact); + if (static_cast(n % 2) != parity) { + if (mode > 0) { + ++n; + } else if (mode < 0) { + --n; + } else { + // nearest: prefer the side closer to exact; exact ties go up + n = (exact >= static_cast(n)) ? n + 1 : n - 1; + } + } + if (n < 0) + n = 0; + return static_cast(n) / dpr; +} + +// qRound() semantics: round half away from zero. +qint64 roundAway(double value) { + return value >= 0.0 ? qint64(value + 0.5) : qint64(value - 0.5); +} + +// Snap a size for an item centered by anchors with `alignWhenCentered: false`. +// Qt resolves that as `y = qRound(parentSize / 2) + parentPos - size / 2` +// (qquickanchors.cpp: the *anchor target* rounds its half, the anchored item +// divides exactly), so with the parent's half at a whole device offset the +// child's device size must be even; if the parent's half sits on a half device +// pixel, the child's device size must be odd instead. +qreal snapCenteredSize(qreal value, qreal dpr, qint64 parentHalfRounded, int mode) { + const double exact = value * dpr; + const double anchorDev = double(parentHalfRounded) * dpr; + const bool anchorWhole = + std::fabs(anchorDev - std::round(anchorDev)) < 1e-6; + const qint64 parity = anchorWhole ? 0 : 1; + + qint64 base = mode > 0 ? std::llround(std::ceil(exact - 1e-6)) + : mode < 0 ? std::llround(std::floor(exact + 1e-6)) + : std::llround(exact); + for (qint64 step = 0; step < 8; ++step) { + if (base + step >= 0 && (base + step) % 2 == parity) + return qreal(base + step) / dpr; + if (step > 0 && base - step >= 0 && (base - step) % 2 == parity) + return qreal(base - step) / dpr; + } + return qreal(std::max(0, base)) / dpr; +} + +// Snap a size along `horizontal` for an item whose placement on that axis is +// centered. Anchor-centered items follow Qt's rounding (`alignWhenCentered`); +// anything else only needs the parent's device-size parity. +qreal snapCenteredAxis( + qreal value, + QQuickItem* item, + qreal dpr, + bool horizontal, + const Centering& centering, + int mode) { + QQuickItem* parent = item->parentItem(); + if (!centering.alignWhenCentered && parent) { + const qreal parentSize = horizontal ? parent->width() : parent->height(); + return snapCenteredSize(value, dpr, roundAway(parentSize / 2.0), mode); + } + return snapToParity(value, dpr, devParity(parent, dpr, horizontal), mode); +} + +} // namespace + +qreal ZUtils::snap(qreal value, QQuickItem* item) { + const qreal dpr = dprFor(item); + if (item) { + const Centering c = detectCentering(item); + if (c.horizontal) + return snapCenteredAxis(value, item, dpr, true, c, 0); + if (c.vertical) + return snapCenteredAxis(value, item, dpr, false, c, 0); + } + return std::round(value * dpr) / dpr; +} + +qreal ZUtils::snapCeil(qreal value, QQuickItem* item) { + const qreal dpr = dprFor(item); + if (item) { + const Centering c = detectCentering(item); + if (c.horizontal) + return snapCenteredAxis(value, item, dpr, true, c, 1); + if (c.vertical) + return snapCenteredAxis(value, item, dpr, false, c, 1); + } + return std::ceil(value * dpr - 1e-6) / dpr; +} + +qreal ZUtils::snapFloor(qreal value, QQuickItem* item) { + const qreal dpr = dprFor(item); + if (item) { + const Centering c = detectCentering(item); + if (c.horizontal) + return snapCenteredAxis(value, item, dpr, true, c, -1); + if (c.vertical) + return snapCenteredAxis(value, item, dpr, false, c, -1); + } + return std::floor(value * dpr + 1e-6) / dpr; +} + +bool ZUtils::logPlacement(QQuickItem* item, const QString& tag) { + if (!item) { + qWarning() << "logPlacement: null item"; + return false; + } + + constexpr double tol = 1e-3; + const auto isOff = [](double v) { + return std::abs(v - std::round(v)) > tol; + }; + const auto fmt = [&](double v) { + return QString::number(v, 'f', 2) + + (isOff(v) ? QStringLiteral("*") : QString()); + }; + + // Centering is detected from the item: anchors.centerIn, the individual + // center anchor lines, and Layout alignment. + const Centering c = detectCentering(item); + const bool centeredH = c.horizontal; + const bool centeredV = c.vertical; + const QString& centerSrc = c.source; + + const double dpr = dprFor(item); + const QRectF r = + item->mapRectToScene(QRectF(0, 0, item->width(), item->height())); + const double l = r.left() * dpr; + const double t = r.top() * dpr; + const double rt = r.right() * dpr; + const double b = r.bottom() * dpr; + + // Same rule as the audit: a Text's fractional implicit size doesn't blur anything. + const bool isText = item->inherits("QQuickText"); + + // Centered rule per axis: whole device size, and the center on the grid + // with parity matching that size (even size -> integer center, odd -> + // pixel center at .5). That is what makes both edges land on whole device + // pixels when the center is divided exactly (`alignWhenCentered: true`). + // With `alignWhenCentered: false` Qt rounds the anchor target's half + // instead of dividing, so the edges are what matter. + const auto centeredAxisOk = [&](double lo, double hi) { + const double size = hi - lo; + if (isOff(size)) + return false; + if (!c.alignWhenCentered) + return !isOff(lo) && !isOff(hi); + const double center = (lo + hi) / 2.0; + const double parity = (std::llround(size) % 2 == 0) ? 0.0 : 0.5; + double err = std::fmod(center - parity, 1.0); + if (err < 0) + err += 1.0; + return std::min(err, 1.0 - err) <= tol; + }; + + bool aligned; + if (centeredH && centeredV) { + aligned = centeredAxisOk(l, rt) && (isText || centeredAxisOk(t, b)); + } else if (centeredH) { + aligned = centeredAxisOk(l, rt) && !isOff(t) && (isText || !isOff(b)); + } else if (centeredV) { + aligned = !isOff(l) && centeredAxisOk(t, b) && (isText || !isOff(rt)); + } else { + aligned = !isOff(l) && !isOff(t) && + (isText || (!isOff(rt) && !isOff(b))); + } + + QString file; + if (const QQmlContext* ctx = qmlContext(item)) { + const QUrl url = ctx->baseUrl(); + file = url.isLocalFile() ? url.toLocalFile() : url.toString(); + } + + qInfo().noquote() + << (aligned ? "[ALIGNED] " : "[UNALIGNED]") + << (tag.isEmpty() ? QString::fromUtf8(item->metaObject()->className()) + : tag) + << "\n device px: left=" << fmt(l) << " top=" << fmt(t) + << " right=" << fmt(rt) << " bottom=" << fmt(b) + << (isText ? " (right/bottom ignored: Text)" : "") + << (!centerSrc.isEmpty() + ? " (centered: " + centerSrc + ")" + : QString()) + << (centeredH || centeredV + ? QString("\n center: x=%1 y=%2 size=%3 x %4") + .arg(QString::number((l + rt) / 2, 'f', 2)) + .arg(QString::number((t + b) / 2, 'f', 2)) + .arg(QString::number(rt - l, 'f', 2)) + .arg(QString::number(b - t, 'f', 2)) + : QString()) + << "\n size: " << fmt(item->width() * dpr) << " x " + << fmt(item->height() * dpr) << "\n local: x=" << item->x() + << " y=" << item->y() << " w=" << item->width() + << " h=" << item->height() << "\n dpr=" << dpr + << (item->window() ? "" : " (NO WINDOW, using fallback dpr)") + << (file.isEmpty() ? QString() : "\n file: " + file); + + return aligned; +} + +bool ZUtils::logCurvePlacement( + QQuickItem* item, + const QList& samples, + qreal lineWidth, + const QString& tag) { + if (!item) { + qWarning() << "logCurvePlacement: null item"; + return false; + } + if (samples.size() < 4 || samples.size() % 2 != 0) { + qWarning() << "logCurvePlacement: need flat x,y pairs (>= 2 points)"; + return false; + } + + constexpr double tol = 1e-3; + + const double dpr = dprFor(item); + const int devW = static_cast( + std::max(1, std::llround(lineWidth * dpr))); + const double half = devW / 2.0; + + qsizetype offCount = 0; + qsizetype sloped = 0; + double worst = 0.0; + double worstX = 0.0; + double worstY = 0.0; + double worstEdge = 0.0; + int worstSide = 0; // -1 top edge, +1 bottom edge + + for (qsizetype i = 0; i < samples.size(); i += 2) { + const double x = samples[i]; + const double y = samples[i + 1]; + + // A sloped stroke's edge is never horizontal in device space, so + // only locally-flat samples can (and must) sit on pixel boundaries + const double yPrev = i >= 2 ? samples[i - 1] : y; + const double yNext = i + 3 < samples.size() ? samples[i + 3] : y; + if (std::abs(yNext - yPrev) > tol) { + ++sloped; + continue; + } + + const double yc = y * dpr; + const double top = yc - half; + const double bottom = yc + half; + for (int side = -1; side <= 1; side += 2) { + const double edge = side < 0 ? top : bottom; + const double dev = std::abs(edge - std::round(edge)); + if (dev > tol) { + ++offCount; + if (dev > worst) { + worst = dev; + worstX = x; + worstY = y; + worstEdge = edge; + worstSide = side; + } + } + } + } + + const qsizetype total = samples.size() / 2; + const qsizetype flat = total - sloped; + const bool aligned = offCount == 0; + + qInfo().noquote() + << (aligned ? "[CURVE ALIGNED] " : "[CURVE UNALIGNED]") + << (tag.isEmpty() ? QString::fromUtf8(item->metaObject()->className()) + : tag) + << "\n samples: " << total << " points (" << flat << " flat, " + << sloped << " sloped ignored), dpr=" << dpr + << ", stroke width=" << lineWidth << " logical = " << devW + << " device px" + << "\n edges: " << offCount << " of " << flat * 2 + << " flat stroke edges off the device grid"; + if (!aligned) { + qInfo().noquote() + << " worst: deviation=" << QString::number(worst, 'f', 3) + << " device px at logical x=" << QString::number(worstX, 'f', 2) + << " y=" << QString::number(worstY, 'f', 2) + << " (" << (worstSide < 0 ? "top" : "bottom") << " edge device=" + << QString::number(worstEdge, 'f', 3) << ")"; + } + + return aligned; +} + +QList ZUtils::distribute( + qreal total, const QList& preferred, QQuickItem* item) { + const qsizetype n = preferred.size(); + QList out(n, 0.0); + if (n == 0) { + return out; + } + + const qreal dpr = dprFor(item); + const qint64 totalPx = std::max(0, std::llround(total * dpr)); + + QList px; + px.reserve(n); + qint64 sum = 0; + for (const qreal p : preferred) { + const qint64 v = + std::max(0, std::llround(std::ceil(p * dpr - 1e-6))); + px.append(v); + sum += v; + } + + const qint64 left = totalPx - sum; + if (left >= 0) { + // Extra space: split evenly, remainder pixels to the first items. + const qint64 base = left / n; + const qint64 rem = left % n; + for (qsizetype i = 0; i < n; ++i) { + px[i] += base + (i < rem ? 1 : 0); + } + } else if (sum > 0) { + // Not enough space: shrink proportionally, then hand out the rounding leftovers. + qint64 assigned = 0; + for (qsizetype i = 0; i < n; ++i) { + px[i] = static_cast(std::floor( + static_cast(px[i]) * static_cast(totalPx) / + static_cast(sum))); + assigned += px[i]; + } + for (qsizetype i = 0; assigned < totalPx; i = (i + 1) % n, ++assigned) { + ++px[i]; + } + } + + for (qsizetype i = 0; i < n; ++i) { + out[i] = static_cast(px[i]) / dpr; + } + return out; +} + } // namespace ZShell diff --git a/Plugins/ZShell/zutils.hpp b/Plugins/ZShell/zutils.hpp index 3900cc0..b9f8aa8 100644 --- a/Plugins/ZShell/zutils.hpp +++ b/Plugins/ZShell/zutils.hpp @@ -53,6 +53,44 @@ class ZUtils : public QObject { Q_INVOKABLE static QList findChildrenMatching( QQuickItem* root, const QString& pattern); + // Device pixel ratio of the window the item lives in (falls back to the primary screen, then 1.0) + Q_INVOKABLE static qreal dprFor(QQuickItem* item); + + // Snap a logical value to the device pixel grid of the item's window. + // Centering is detected from the item: anchors.centerIn, + // anchors.horizontalCenter / verticalCenter, and Layout alignment. A size + // along a centered axis is snapped so the centered edges land on whole + // device pixels — using Qt's own rounding rule for that anchor style + // (exact halves when `alignWhenCentered` is true, the rounded half of the + // anchor target when it is false). + Q_INVOKABLE static qreal snap(qreal value, QQuickItem* item); + Q_INVOKABLE static qreal snapCeil(qreal value, QQuickItem* item); // text-derived sizes + Q_INVOKABLE static qreal snapFloor(qreal value, QQuickItem* item); + // Logs where an item sits in device pixels and whether it is aligned. + // Returns true if aligned. `tag` is an optional label for the log line. + // Items centered on a target are judged by the centering rule above + // (whole device size, plus the offset the anchor produces), which is + // detected from the item's anchors and Layout alignment. + Q_INVOKABLE static bool logPlacement( + QQuickItem* item, + const QString& tag = QString()); + + // Walks a stroked curve path (flat x,y pairs in the item's logical coords, + // every point along the curve, not just its defined points) and checks + // whether both stroke edges land on device pixel boundaries at `lineWidth`. + // Returns true if every sample is aligned. + Q_INVOKABLE static bool logCurvePlacement( + QQuickItem* item, + const QList& samples, + qreal lineWidth, + const QString& tag = QString()); + + // Distributes `total` (logical px) across items with the given preferred widths. + // Every result is a whole number of device pixels and the results sum exactly to + // the snapped total. If the preferred widths don't fit, they shrink proportionally. + Q_INVOKABLE static QList distribute( + qreal total, const QList& preferred, QQuickItem* item); + [[nodiscard]] QString version() const; [[nodiscard]] QString qtVersion() const; }; diff --git a/shell.qml b/shell.qml index 7458221..519ddc5 100644 --- a/shell.qml +++ b/shell.qml @@ -3,8 +3,10 @@ //@ pragma DefaultEnv QS_NO_RELOAD_POPUP=1 //@ pragma DefaultEnv QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000 //@ pragma DropExpensiveFonts +import QtQuick import Quickshell import Quickshell.Services.UPower +import ZShell import qs.Modules import qs.Modules.Lock import qs.Drawers @@ -18,6 +20,18 @@ ShellRoot { settings.watchFiles: true + // AlignAuditor { + // id: alignAudit + // + // outputPath: "/tmp/align-audit.txt" + // delayMs: 10000 + // + // onFinished: count => console.log("FINISHED SCAN:", count) + // + // Component.onCompleted: if (Quickshell.env("ZSHELL_ALIGN")) + // alignAudit.runLater() + // } + Drawers {} Lock {