Author SHA1 Message Date
AramJonghu 355117fd92 feat(makefile): adds a make formatter as task runner
C++ / fmt (pull_request) Successful in 5s
C++ / build & lint (pull_request) Failing after 10s
JS/TS / fmt & lint (pull_request) Successful in 11s
Python / fmt & lint (pull_request) Successful in 28s
Python / test & nuitka build (pull_request) Failing after 1m23s
Rust / build, clippy & fmt (pull_request) Failing after 5m10s
2026-10-30 02:22:27 +01:00
AramJonghu a9b7e10b6c fix(ci): cpp clang-tidy now properly reads non-build files only 2026-10-30 02:19:30 +01:00
AramJonghu 9ad94f1e3e feat(makefile): added no nuitka option for cpp-compile task 2026-10-25 16:01:40 +01:00
AramJonghu 856c78c380 chore(gitignore): ordering known files and directories 2026-10-25 16:01:40 +01:00
AramJonghu 0c4e8e805a chore(gitignore): nuitka compile files ignored and categorized 2026-10-25 16:01:40 +01:00
AramJonghu 18c474669b fix(clang-tidy): make cpp-lint has proper clang-tidy check 2026-10-25 16:01:40 +01:00
AramJonghu 5eb84285a4 chore(Dockerfile): add future dependencies 2026-10-25 16:01:40 +01:00
zachandAramJonghu 02fb847268 Merge branch 'main' into feat/task-runner-ci 2026-10-25 16:01:40 +01:00
AramJonghu a96211a5b5 feat(makefile): added qmlformat + install -> compile in cpp step 2026-10-25 16:01:40 +01:00
AramJonghu cbb108a6dd feat(makefile): C++, Python, and Rust checks included (incomplete) 2026-10-25 16:01:40 +01:00
AramJonghu 9f9d09bc5b feat(makefile): makefile build & install + progress on cpp and py 2026-10-25 16:01:40 +01:00
AramJonghu a2326dc641 format(clang): make cpp-fmt result 2026-10-25 16:01:39 +01:00
AramJonghu b4f0239e2a ci: rework Dockerfile image + buildx dep added 2026-10-25 16:01:39 +01:00
AramJonghu fd938d4e47 refactor(workflows): combined steps where it makes sense 2026-10-25 16:01:39 +01:00
AramJonghu c5dfb306dd fix(ci): missing dependency wayland-scanner 2026-10-25 16:01:39 +01:00
260 changed files with 3329 additions and 12178 deletions
-3
View File
@@ -1,3 +0,0 @@
#omz revision: d2b7f557cceaddb16ba89bbf8200d8a8df35c4d8
#omz fpath: /home/zach/.oh-my-zsh/plugins/colored-man-pages /home/zach/.oh-my-zsh/plugins/universalarchive /home/zach/.oh-my-zsh/plugins/tldr /home/zach/.oh-my-zsh/plugins/extract /home/zach/.oh-my-zsh/plugins/copypath /home/zach/.oh-my-zsh/plugins/cp /home/zach/.oh-my-zsh/plugins/conda-env /home/zach/.oh-my-zsh/plugins/command-not-found /home/zach/.oh-my-zsh/plugins/dirhistory /home/zach/.oh-my-zsh/plugins/copybuffer /home/zach/.oh-my-zsh/plugins/copyfile /home/zach/.oh-my-zsh/custom/plugins/fast-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-autosuggestions /home/zach/.oh-my-zsh/plugins/archlinux /home/zach/.oh-my-zsh/plugins/web-search /home/zach/.oh-my-zsh/plugins/sudo /home/zach/.oh-my-zsh/plugins/git /home/zach/.oh-my-zsh/functions /home/zach/.oh-my-zsh/completions /home/zach/.oh-my-zsh/custom/functions /home/zach/.oh-my-zsh/custom/completions /home/zach/tools/ripgrep/complete /home/linuxbrew/.linuxbrew/share/zsh/site-functions /home/zach/.oh-my-zsh/plugins/colored-man-pages /home/zach/.oh-my-zsh/plugins/universalarchive /home/zach/.oh-my-zsh/plugins/tldr /home/zach/.oh-my-zsh/plugins/extract /home/zach/.oh-my-zsh/plugins/copypath /home/zach/.oh-my-zsh/plugins/cp /home/zach/.oh-my-zsh/plugins/conda-env /home/zach/.oh-my-zsh/plugins/command-not-found /home/zach/.oh-my-zsh/plugins/dirhistory /home/zach/.oh-my-zsh/plugins/copybuffer /home/zach/.oh-my-zsh/plugins/copyfile /home/zach/.oh-my-zsh/custom/plugins/fast-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-autosuggestions /home/zach/.oh-my-zsh/plugins/archlinux /home/zach/.oh-my-zsh/plugins/web-search /home/zach/.oh-my-zsh/plugins/sudo /home/zach/.oh-my-zsh/plugins/git /home/zach/.oh-my-zsh/functions /home/zach/.oh-my-zsh/completions /home/zach/.oh-my-zsh/custom/functions /home/zach/.oh-my-zsh/custom/completions /home/zach/.oh-my-zsh/cache/completions /home/zach/tools/ripgrep/complete /home/linuxbrew/.linuxbrew/share/zsh/site-functions /usr/local/share/zsh/site-functions /usr/share/zsh/site-functions /usr/share/zsh/functions/Calendar /usr/share/zsh/functions/Chpwd /usr/share/zsh/functions/Completion /usr/share/zsh/functions/Completion/Base /usr/share/zsh/functions/Completion/Linux /usr/share/zsh/functions/Completion/Unix /usr/share/zsh/functions/Completion/X /usr/share/zsh/functions/Completion/Zsh /usr/share/zsh/functions/Exceptions /usr/share/zsh/functions/MIME /usr/share/zsh/functions/Math /usr/share/zsh/functions/Misc /usr/share/zsh/functions/Newuser /usr/share/zsh/functions/Prompts /usr/share/zsh/functions/TCP /usr/share/zsh/functions/VCS_Info /usr/share/zsh/functions/VCS_Info/Backends /usr/share/zsh/functions/Zftp /usr/share/zsh/functions/Zle /home/zach/.zfunc
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@v4
- name: Install Docker CLI
run: apk add --no-cache docker-cli
run: apk add --no-cache docker-cli docker-cli-buildx
- name: Login to registry
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.aramjonghu.dev --username aramjonghu --password-stdin
+5 -21
View File
@@ -20,28 +20,10 @@ jobs:
-exec clang-format -i --style=file {} +
git diff --exit-code && echo "clang-format: passed"
build:
build & lint:
runs-on: alpine
container:
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure
run: cmake -B build -G Ninja -DENABLE_MODULES=plugin -DCMAKE_BUILD_TYPE=Release
- name: Build
run: ninja -C build
clang-tidy:
runs-on: alpine
container:
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -58,5 +40,7 @@ jobs:
run: |
sed -i 's/-mno-direct-extern-access //g' build/compile_commands.json
set -o pipefail
run-clang-tidy -p build -j $(nproc) -header-filter="Plugins/.*" 2>&1 | \
grep -v 'Suppressed\|non-user\|non-system\|unknown argument.*mno-direct\|Found compiler error\|warnings generated\.\|^Use -header-filter'
run-clang-tidy -p build -j "$(nproc)" \
-source-filter="^$(pwd)/Plugins/" \
-header-filter=".*Plugins/.*" \
-removed-arg=-mno-direct-extern-access
+1 -15
View File
@@ -4,7 +4,7 @@ on:
pull_request:
jobs:
fmt:
fmt & lint:
runs-on: alpine
container: node:26-alpine
@@ -24,20 +24,6 @@ jobs:
else
echo "No JS/TS files found"
fi
lint:
runs-on: alpine
container: node:26-alpine
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apk add --no-cache \
git
- name: ESLint
run: |
if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then
+3 -3
View File
@@ -7,7 +7,7 @@ on:
pull_request:
jobs:
static:
fmt & lint:
runs-on: debian
container: node:26-trixie-slim
@@ -33,7 +33,7 @@ jobs:
. .venv/bin/activate
ruff check .
verify:
test & nuitka build:
if: always()
runs-on: debian
container: node:26-trixie-slim
@@ -64,4 +64,4 @@ jobs:
- name: Nuitka module check
run: |
. .venv/bin/activate
nuitka --module --include-package=zshell cli/src/zshell/
nuitka --module --include-package=zshell cli/src/zshell/
+21 -86
View File
@@ -3,8 +3,9 @@ name: Rust
on:
pull_request:
# jobs can be separated if we integrate tests
jobs:
build:
build, clippy & fmt:
runs-on: alpine
container: node:26-alpine
env:
@@ -34,7 +35,9 @@ jobs:
apk add --no-cache \
git \
cargo \
rust
rust \
rust-clippy \
rustfmt
- name: Cargo check
run: |
@@ -50,90 +53,6 @@ jobs:
else
echo "No Rust project found"
fi
fmt:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-fmt-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rustfmt
- name: Format check
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo fmt --manifest-path "$manifest" --check && \
echo "$manifest: formatting OK" || \
{ echo "$manifest: needs formatting"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
clippy:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-clippy-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rust-clippy
- name: Clippy
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
@@ -150,3 +69,19 @@ jobs:
else
echo "No Rust project found"
fi
- name: Format check
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo fmt --manifest-path "$manifest" --check && \
echo "$manifest: formatting OK" || \
{ echo "$manifest: needs formatting"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
+22 -10
View File
@@ -1,23 +1,35 @@
**/__pycache__/
./result/
.pyre/
.cache/
.venv/
.qmlls.ini
build/
compile_commands.json
testpython
pkg/
*.tar.*
uv.lock
.qtcreator/
dist/
**/target/
**/test-plugins/
**/Charts/
network-dev/
**/zshell.build/
**/zshell.dist/
# Qml
.qtcreator/
.qmlls.ini
# CMake compile artifacts
.cache/
compile_commands.json
build/
# Python
uv.lock
testpython
.venv/
**/__pycache__/
# Nuitka compile
**/zshell.pyi
**/zshell.cpython-*
**/zshell.build/
# Agents stuff
.opencode/
run-agent.sh
AGENTS.md
+2 -3
View File
@@ -1,5 +1,4 @@
import QtQuick
import Quickshell
import ZShell.Components
Item {
@@ -20,7 +19,7 @@ Item {
}
ShaderEffectSource {
id: src
id: source
hideSource: true
sourceItem: contentItem
@@ -28,7 +27,7 @@ Item {
RoundedMask {
anchors.fill: parent
source: src
source: source
topLeftRadius: root.topLeftRadius
topRightRadius: root.topRightRadius
bottomRightRadius: root.bottomRightRadius
+4 -3
View File
@@ -99,7 +99,6 @@ ProgressBar {
}
Line {
id: dot
property real implicitSize
anchors.right: parent.right
@@ -125,7 +124,8 @@ ProgressBar {
anchors.left: parent.left
Behavior on implicitWidth {
Anim {}
Anim {
}
}
Component.onCompleted: implicitWidth = Qt.binding(() => parent.width * root.visualPosition)
@@ -222,7 +222,8 @@ ProgressBar {
}
}
Behavior on color {
CAnim {}
CAnim {
}
}
Anim on waveProgress {
duration: root.waveDuration
+6 -6
View File
@@ -2,10 +2,10 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Templates
import ZShell
import ZShell.Components
import ZShell.Config
import ZShell
import qs.Components
import ZShell.Config
import qs.Services
Slider {
@@ -28,7 +28,7 @@ Slider {
signal interaction(v: real)
implicitHeight: ZUtils.snap(12, root)
implicitHeight: 12
implicitWidth: 200
contentItem: Item {
@@ -123,7 +123,7 @@ Slider {
bottomRightRadius: Tokens.rounding.extraSmall / 2
color: root.fgColor
implicitHeight: root.height
implicitWidth: ZUtils.snap(root.filledWidth, root)
implicitWidth: root.filledWidth
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: ZUtils.snap(root.filledWidth, root)
lineWidth: ZUtils.snap(root.height * 0.7, root)
implicitWidth: root.filledWidth
lineWidth: root.height * 0.7
startX: x
Behavior on color {
+2 -3
View File
@@ -1,5 +1,4 @@
import QtQuick
import ZShell
import ZShell.Config
import qs.Services
@@ -16,9 +15,9 @@ ButtonBase {
const h = label.implicitHeight + padding * 2;
if (h % 2 !== 0)
return h + 1;
return ZUtils.snap(h, root);
return h;
}
implicitWidth: ZUtils.snap(implicitHeight, root)
implicitWidth: implicitHeight
inactiveColor: {
if (!isToggle && type === IconButton.Filled)
return Colors.palette.m3primary;
+1 -3
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -35,11 +34,10 @@ ButtonBase {
}
verticalPadding: Tokens.padding.extraSmall
SnapLayout {
RowLayout {
id: row
anchors.centerIn: parent
spacing: Tokens.spacing.small
MaterialIcon {
+66 -89
View File
@@ -1,8 +1,6 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtCanvas2D
import ZShell
Item {
id: root
@@ -38,62 +36,54 @@ Item {
property real fillAlpha: 0.15
property real lineWidth: 2
property real markerDotRadius: 4
property real labelFontSize: 8
property real labelFontSize: 10
Canvas2D {
Canvas {
id: canvas
anchors.fill: parent
alphaBlending: true
fillColor: "transparent"
renderStrategy: Canvas.Immediate
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);
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);
if (root.curveSmoothing && pts.length > 2) {
const k = 1 / 6;
const n = pts.length;
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));
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);
}
ctx.lineTo(p2.x, p2.y);
}
}
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;
}
// Control points for segment i (pts[i] -> pts[i+1]), matching strokeCurve
function segmentControls(pts, i) {
const p0 = pts[Math.max(i - 1, 0)];
const p1 = pts[i];
@@ -119,6 +109,7 @@ 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++) {
@@ -147,16 +138,10 @@ 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
};
}
function cutPoint(pts, targetX) {
return pointAtX(pts, targetX);
return { x: targetX, y };
}
// Part of the curve left/right of a cut x, including the cut point
function cutLeft(pts, targetX) {
if (targetX <= pts[0].x)
return [];
@@ -173,7 +158,7 @@ Item {
const left = pts.slice(0, j + 1);
if (targetX > pts[j].x)
left.push(cutPoint(pts, targetX));
left.push(pointAtX(pts, targetX));
return left;
}
@@ -199,20 +184,17 @@ 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 * 5;
const padRight = 0;
const padTop = 0;
const padBottom = root.labelFontSize + 14;
const padLeft = root.labelFontSize * 3.4;
const padRight = 2;
const padTop = 2;
const padBottom = root.labelFontSize + 8;
const plot = {
x: padLeft,
y: padTop,
@@ -222,6 +204,8 @@ 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);
@@ -295,17 +279,11 @@ 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;
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;
// 1. Grid lines
ctx.strokeStyle = Qt.alpha(root.gridColor, root.gridAlpha);
ctx.lineWidth = gridW;
ctx.lineWidth = 1;
if (root.verticalLineStep > 0) {
for (let i = 0; i <= root.xSteps; i += root.verticalLineStep) {
@@ -314,7 +292,7 @@ Item {
if (i === root.xSteps && !root.lastXLine)
continue;
const x = snapLine(xAt(i), 1);
const x = crisp(xAt(i));
ctx.beginPath();
ctx.moveTo(x, plot.y);
ctx.lineTo(x, H);
@@ -322,11 +300,12 @@ 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 = snapLine(yAt(v), 1);
const y = crisp(yAt(v));
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(plot.x + plot.w, y);
@@ -334,8 +313,9 @@ Item {
}
}
// 2. Labels
ctx.fillStyle = Qt.alpha(root.labelColor, root.labelAlpha);
ctx.font = root.labelFontSize + "pt 'sans-serif'";
ctx.font = root.labelFontSize + "px sans-serif";
ctx.textAlign = "left";
ctx.textBaseline = "top";
@@ -348,7 +328,7 @@ Item {
const text = root.xLabel(i);
if (text)
ctx.fillText(text, xAt(i) + 4, plot.y + plot.h + 8);
ctx.fillText(text, xAt(i) + 4, plot.y + plot.h + 4);
}
}
@@ -361,6 +341,7 @@ Item {
}
}
// 3. Curve, split into segments at null gaps
const segments = [];
let current = null;
for (let i = 0; i < series.length; i++) {
@@ -371,7 +352,7 @@ Item {
continue;
}
const pt = {
x: snapV(xAt(i)),
x: xAt(i),
y: yAt(series[i])
};
if (!current)
@@ -388,6 +369,8 @@ 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)
@@ -399,6 +382,7 @@ 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);
@@ -406,6 +390,7 @@ 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) {
@@ -413,32 +398,24 @@ Item {
continue;
ctx.strokeStyle = root.lineColor;
ctx.lineWidth = ZUtils.snap(root.lineWidth, root);
ctx.lineWidth = root.lineWidth;
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 = 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;
}
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(crisp(x), plot.y);
ctx.lineTo(crisp(x), H);
ctx.stroke();
ctx.setLineDash([]);
const i0 = Math.floor(root.markerX);
const v0 = series[i0];
@@ -453,7 +430,7 @@ Item {
if (y != null) {
ctx.fillStyle = root.markerColor;
ctx.beginPath();
ctx.circle(snapV(x), y, root.markerDotRadius);
ctx.arc(x, y, root.markerDotRadius, 0, Math.PI * 2);
ctx.fill();
}
}
+7 -9
View File
@@ -4,7 +4,6 @@ import QtQuick
import QtQuick.Layouts
import Quickshell
import ZShell.Config
import ZShell.Components
import qs.Drawers
import qs.Services
@@ -35,7 +34,7 @@ MouseArea {
cursorShape: expanded ? Qt.ArrowCursor : undefined
enabled: expanded
hoverEnabled: expanded
layer.enabled: false
layer.enabled: opacity < 1
opacity: expanded ? 1 : 0
parent: {
const win = QsWindow.window;
@@ -102,7 +101,8 @@ MouseArea {
yScale: root.expanded ? 1 : 0.1
Behavior on yScale {
Anim {}
Anim {
}
}
}
@@ -111,14 +111,12 @@ MouseArea {
color: Colors.palette.m3surfaceContainerLow
radius: parent.radius
SnapLayout {
ColumnLayout {
id: column
anchors.fill: parent
anchors.margins: Tokens.padding.extraSmall
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
Repeater {
id: repeater
@@ -139,7 +137,8 @@ MouseArea {
radius: menu.radius - column.anchors.margins
Behavior on radius {
Anim {}
Anim {
}
}
StateLayer {
@@ -154,12 +153,11 @@ MouseArea {
}
}
SnapLayout {
RowLayout {
id: menuOptionRow
anchors.fill: parent
anchors.margins: Tokens.padding.medium
spacing: Tokens.spacing.small
MaterialIcon {
+1 -2
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -54,7 +53,7 @@ Row {
onClicked: root.active?.clicked()
}
SnapLayout {
RowLayout {
id: textRow
anchors.centerIn: parent
+2 -5
View File
@@ -1,5 +1,4 @@
import ZShell
import ZShell.Components
import QtQuick
import QtQuick.Layouts
import qs.Components
@@ -48,7 +47,7 @@ CustomRect {
z: -1
}
SnapLayout {
RowLayout {
id: layout
anchors.fill: parent
@@ -89,11 +88,9 @@ CustomRect {
}
}
SnapLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: 0
orientation: Qt.Vertical
CustomText {
id: title
-7
View File
@@ -4,16 +4,12 @@ import Quickshell
import QtQuick
import ZShell.Internal
import qs.Components
import qs.Services
Item {
id: root
readonly property alias content: contentLoader.item
required property ScreenState screenState
property rect holeRect
property real holeRadius: 0
Loader {
id: contentLoader
@@ -22,9 +18,6 @@ Item {
anchors.fill: parent
sourceComponent: StrokeCanvas {
anchors.fill: parent
hole: root.holeRect
holeRadius: root.holeRadius
penColor: root.screenState.penColor
penWidth: root.screenState.penWidth
}
-95
View File
@@ -1,95 +0,0 @@
import Quickshell
import QtQuick
import ZShell.Config
import qs.Components
CustomMouseArea {
id: root
required property real borderThickness
required property Drawing drawing
required property Panels panels
required property ScreenState screenState
required property EdgeGeometry geometry
function inLeftPanel(panel: Item, x: real, y: real): bool {
return x < panel.x + panel.width + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
}
function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = panel.y + geometry.insetTop(borderThickness);
return y >= panelY && y <= panelY + panel.height;
}
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.BlankCursor
enabled: z > 0
hoverEnabled: true
focus: root.screenState.isDrawing
z: 2
Binding {
target: root.drawing.content
property: "hoverPoint"
value: Qt.point(root.mouseX, root.mouseY)
}
Keys.onPressed: e => {
const mod = e.modifiers;
const key = e.key;
if ((key == Qt.Key_Z) && (mod & Qt.ControlModifier) && (mod & Qt.ShiftModifier)) {
root.drawing.content.redo();
e.accepted = true;
} else if ((key == Qt.Key_Z) && (mod & Qt.ControlModifier)) {
root.drawing.content.undoLastGroup();
e.accepted = true;
}
}
onPositionChanged: event => {
const x = event.x;
const y = event.y;
if (!drawing.content.hoverVisible)
drawing.content.showHover();
if (event.buttons & Qt.LeftButton) {
drawing.content.appendPoint(x, y);
return;
}
if (!(event.buttons & Qt.LeftButton) && inLeftPanel(panels.drawing, x, y)) {
z = -2;
panels.drawing.expand();
drawing.content.hideHover();
}
}
onPressed: event => {
const x = event.x;
const y = event.y;
panels.drawing.collapse();
if (event.buttons & Qt.LeftButton) {
panels.drawing.collapse();
drawing.content.beginStroke(x, y);
return;
}
if (event.button & Qt.RightButton) {
drawing.content.clear();
return;
}
}
onReleased: event => {
const x = event.x;
const y = event.y;
if (event.button & Qt.LeftButton) {
drawing.content.endStroke();
drawing.content.showHover();
}
}
}
+198 -121
View File
@@ -1,33 +1,25 @@
import Quickshell
import QtQuick
import ZShell.Config
import ZShell.Internal
import qs.Components
import qs.Helpers
import qs.Modules.Bar.Popouts
CustomMouseArea {
Item {
id: root
required property Drawing drawing
required property DrawingInput input
required property Item bar
required property real borderThickness
property bool dashboardShortcutActive
required property Drawing drawing
required property EdgeGeometry geometry
property bool osdShortcutActive
required property Panels panels
required property Wrapper popouts
required property ShellScreen screen
required property ScreenState screenState
property bool dashboardShortcutActive
property point dragStart
property bool osdShortcutActive
property bool setInitialPoint: false
property bool singleGestureTriggered: false
property bool utilitiesShortcutActive
required property ScreenState screenState
function inBottomPanel(panel: Item, x: real, y: real): bool {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
@@ -64,116 +56,124 @@ CustomMouseArea {
return x >= panelX && x <= panelX + panel.width;
}
acceptedButtons: bar.fullscreen ? Qt.NoButton : Qt.AllButtons
anchors.fill: parent
hoverEnabled: true
onContainsMouseChanged: {
if (!containsMouse) {
if (!osdShortcutActive) {
screenState.osd = false;
panels.osd.hovered = false;
DragHandler {
id: singleHandler
cursorShape: (active && centroid.pressPosition.y < root.bar.implicitHeight) ? Qt.ClosedHandCursor : undefined
dragThreshold: 0
enabled: !root.screenState.isDrawing
grabPermissions: PointerHandler.CanTakeOverFromHandlersOfSameType | PointerHandler.ApprovesTakeOverByAnything
maximumPointCount: 1
minimumPointCount: 1
target: null
onActiveChanged: {
if (!active)
root.singleGestureTriggered = false;
}
onCentroidChanged: {
const x = centroid.position.x;
const y = centroid.position.y;
const pressX = centroid.pressPosition.x;
const pressY = centroid.pressPosition.y;
const dragX = x - pressX;
const dragY = y - pressY;
if (pressY >= root.screen.height - Config.bar.border && pressX > root.screen.width / 5 && dragY < -Config.launcher.dragThreshold)
root.screenState.launcher = true;
if (root.singleGestureTriggered)
return;
const inDashboard = root.inTopPanel(root.panels.dashboardWrapper, pressX, pressY);
if (inDashboard && root.withinPanelWidth(root.panels.dashboardWrapper, x, y)) {
if (dragY > Config.dashboard.dragThreshold) {
root.screenState.dashboard = true;
root.singleGestureTriggered = true;
} else if (dragY < -Config.dashboard.dragThreshold) {
root.screenState.dashboard = false;
root.singleGestureTriggered = true;
}
}
if (!popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover) {
popouts.hasCurrent = false;
if (root.geometry.insetTop(root.borderThickness) > pressY && (Config.dashboard.showOnHover || !inDashboard)) {
if (dragY > 20) {
root.screenState.settings = true;
root.singleGestureTriggered = true;
} else if (dragY < -20) {
root.screenState.settings = false;
root.singleGestureTriggered = true;
}
}
if (Config.bar.autoHide || bar.fullscreen)
bar.isHovered = false;
if (pressY > root.screen.height - root.geometry.insetBottom(root.borderThickness) && pressX < root.screen.width / 5 && dragY < -50)
root.screenState.clipboard = true;
if (screenState.dashboard && Config.dashboard.showOnHover)
screenState.dashboard = false;
if (!Config.dock.hoverToReveal && pressY > root.screen.height - root.geometry.insetTop(root.borderThickness) && pressX > root.screen.width / 5 && !root.screenState.launcher)
if (dragY < -10) {
root.screenState.dock = true;
root.singleGestureTriggered = true;
}
if (pressX > root.screen.width - Config.bar.border && pressY < (root.screen.height / 2) && dragX < -Config.sidebar.dragThreshold) {
root.screenState.sidebar = true;
root.singleGestureTriggered = true;
}
if (pressX >= root.screen.width - Config.bar.border && pressY > (root.screen.height / 2) && dragX < -20) {
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`);
root.singleGestureTriggered = true;
}
if (pressX <= Config.bar.border && dragX > 20) {
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`);
root.singleGestureTriggered = true;
}
}
}
onPositionChanged: event => {
const x = event.x;
const y = event.y;
const dragX = x - dragStart.x;
const dragY = y - dragStart.y;
if (screenState.isDrawing && !inLeftPanel(panels.drawing, x, y)) {
input.z = 2;
panels.drawing.collapse();
}
PointHandler {
id: drawingHandler
if (root.bar.fullscreen && !root.bar.isHovered)
unhideTimer.start();
property bool setInitialPoint: false
if (pressed && dragStart.y >= screen.height - Config.bar.border && dragStart.x > screen.width / 5 && dragY < -Config.launcher.dragThreshold)
screenState.launcher = true;
acceptedButtons: Qt.LeftButton | Qt.RightButton
enabled: root.screenState.isDrawing && (!root.inLeftPanel(root.panels.drawing, hoverHandler.point.position.x, hoverHandler.point.position.y) || !root.panels.drawing.expanded)
const entryAt = bar.entryAt(geometry.axisPos(x, y));
const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboardWrapper, x, y) && (!entryAt || entryAt === "activeWindow");
if (!dashboardShortcutActive) {
screenState.dashboard = showDashboard;
} else if (showDashboard) {
dashboardShortcutActive = false;
}
if (pressed && geometry.insetTop(borderThickness) > dragStart.y && withinPanelWidth(panels.dashboardWrapper, x, y)) {
if (dragY > Config.dashboard.dragThreshold)
screenState.dashboard = true;
else if (dragY < -Config.dashboard.dragThreshold)
screenState.dashboard = false;
}
if (pressed && geometry.insetTop(borderThickness) > dragStart.y && !inTopPanel(panels.dashboardWrapper, dragStart.x, dragStart.y)) {
if (dragY > 20) {
screenState.settings = true;
} else if (dragY < -20) {
screenState.settings = false;
onActiveChanged: {
if (!active) {
setInitialPoint = false;
root.drawing.content.endStroke();
} else {
root.panels.drawing.collapse();
}
}
onPointChanged: {
if (!active)
return;
const x = point.position.x;
const y = point.position.y;
const origX = point.pressPosition.x;
const origY = point.pressPosition.y;
if (pressed && dragStart.y > screen.height - geometry.insetBottom(borderThickness) && dragStart.x < screen.width / 5 && dragY < -50)
screenState.clipboard = true;
if (pressed && !Config.dock.hoverToReveal && dragStart.y > screen.height - geometry.insetTop(borderThickness) && dragStart.x > screen.width / 5 && !screenState.launcher)
if (dragY < -10)
screenState.dock = true;
if (pressed && dragStart.x > screen.width - Config.bar.border && dragStart.y < (screen.height / 2) && dragX < -Config.sidebar.dragThreshold)
screenState.sidebar = true;
if (pressed && dragStart.x >= screen.width - Config.bar.border && dragStart.y > (screen.height / 2) && dragX < -20)
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`);
if (pressed && dragStart.x <= Config.bar.border && dragX > 20)
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`);
if (!screenState.bar && Config.bar.autoHide && geometry.barContains(x, y, true))
bar.isHovered = true;
if (panels.sidebar.offsetScale === 1) {
const showOsd = inRightPanel(panels.osdWrapper, x, y);
if (showOsd) {
osdShortcutActive = false;
panels.osd.hovered = true;
if (point.pressedButtons & Qt.RightButton) {
root.drawing.content.clear();
return;
}
} else {
const outOfSidebar = x < width - panels.sidebar.width * (1 - panels.sidebar.offsetScale);
const showOsd = outOfSidebar && inRightPanel(panels.osdWrapper, x, y);
if (x === 0 && y === 0 && origX === 0 && origY === 0)
return;
if (!osdShortcutActive) {
screenState.osd = showOsd;
panels.osd.hovered = showOsd;
} else if (showOsd) {
osdShortcutActive = false;
panels.osd.hovered = true;
if (!setInitialPoint) {
setInitialPoint = true;
root.drawing.content.beginStroke(origX, origY);
return;
}
root.drawing.content.appendPoint(x, y);
}
if (Config.dock.enable && Config.dock.hoverToReveal && !screenState.dock && !screenState.launcher && inBottomPanel(panels.dock, x, y))
screenState.dock = true;
if (geometry.barContains(x, y))
bar.checkPopout(geometry.axisPos(x, y));
}
onPressed: event => {
dragStart = Qt.point(event.x, event.y);
}
Timer {
@@ -184,20 +184,98 @@ CustomMouseArea {
running: false
onTriggered: {
if (root.containsMouse)
if (hoverHandler.hovered)
root.bar.isHovered = true;
}
}
HoverHandler {
id: hoverHandler
cursorShape: root.screenState.isDrawing && !root.inLeftPanel(root.panels.drawing, point.position.x, point.position.y) ? Qt.BlankCursor : undefined
onHoveredChanged: {
if (!hovered) {
if (!root.osdShortcutActive) {
root.screenState.osd = false;
root.panels.osd.hovered = false;
}
if (!root.popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover) {
root.popouts.hasCurrent = false;
}
if (Config.bar.autoHide || root.bar.fullscreen)
root.bar.isHovered = false;
if (root.screenState.dashboard && Config.dashboard.showOnHover)
root.screenState.dashboard = false;
}
}
onPointChanged: {
const x = point.position.x;
const y = point.position.y;
if (root.screenState.isDrawing) {
if (root.inLeftPanel(root.panels.drawing, x, y) && !(drawingHandler.point.pressedButtons & Qt.LeftButton)) {
root.panels.drawing.expand();
root.drawing.content.hideHover();
return;
}
root.drawing.content.showHover(x, y);
return;
}
if (!root.screenState.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true))
root.bar.isHovered = true;
if (root.bar.fullscreen && !root.bar.isHovered)
unhideTimer.start();
if (root.panels.sidebar.offsetScale === 1) {
const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);
if (showOsd) {
root.osdShortcutActive = false;
root.panels.osd.hovered = true;
}
} else {
const outOfSidebar = x < root.width - root.panels.sidebar.width * (1 - root.panels.sidebar.offsetScale);
const showOsd = outOfSidebar && root.inRightPanel(root.panels.osdWrapper, x, y);
if (!root.osdShortcutActive) {
root.screenState.osd = showOsd;
root.panels.osd.hovered = showOsd;
} else if (showOsd) {
root.osdShortcutActive = false;
root.panels.osd.hovered = true;
}
}
if (Config.dock.enable && Config.dock.hoverToReveal && !root.screenState.dock && !root.screenState.launcher && root.inBottomPanel(root.panels.dock, x, y))
root.screenState.dock = true;
const inDashboard = root.inTopPanel(root.panels.dashboardWrapper, x, y);
if (Config.dashboard.showOnHover)
root.screenState.dashboard = inDashboard;
if (root.geometry.barContains(x, y))
root.bar.checkPopout(root.geometry.axisPos(x, y));
}
}
Connections {
function onDashboardChanged(): void {
function onDashboardChanged() {
if (root.screenState.dashboard) {
const inDashboardArea = root.inTopPanel(root.panels.dashboardWrapper, root.mouseX, root.mouseY);
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.dashboardShortcutActive = true;
}
if (root.panels.launcher.x + root.panels.launcher.width > root.panels.dashboardWrapper.x)
root.screenState.launcher = false;
root.screenState.launcher = false;
root.screenState.settings = false;
root.screenState.sidebar = false;
root.screenState.resources = false;
@@ -207,15 +285,12 @@ CustomMouseArea {
}
}
function onIsDrawingChanged(): void {
if (root.screenState.isDrawing) {
root.drawing.content.showHover();
} else {
root.drawing.content.clear();
}
function onIsDrawingChanged() {
if (!root.screenState.isDrawing)
root.drawing.clear();
}
function onLauncherChanged(): void {
function onLauncherChanged() {
if (!root.screenState.launcher) {
root.dashboardShortcutActive = false;
root.osdShortcutActive = false;
@@ -230,13 +305,16 @@ CustomMouseArea {
}
if (root.screenState.launcher) {
root.screenState.dashboard = false;
if (root.panels.dashboardWrapper.x < root.panels.launcher.x + root.panels.launcher.width) {
root.screenState.dashboard = false;
}
root.screenState.dock = false;
root.screenState.settings = false;
}
}
function onOsdChanged(): void {
function onOsdChanged() {
if (root.screenState.osd) {
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
if (!inOsdArea) {
@@ -247,7 +325,7 @@ CustomMouseArea {
}
}
function onResourcesChanged(): void {
function onResourcesChanged() {
if (root.screenState.resources) {
if (root.popouts.currentName.startsWith("audio") || root.popouts.currentName.startsWith("updates"))
root.popouts.hasCurrent = false;
@@ -257,7 +335,7 @@ CustomMouseArea {
}
}
function onSettingsChanged(): void {
function onSettingsChanged() {
if (root.screenState.settings) {
root.screenState.resources = false;
root.screenState.dashboard = false;
@@ -267,10 +345,9 @@ CustomMouseArea {
}
}
function onSidebarChanged(): void {
function onSidebarChanged() {
if (root.screenState.sidebar) {
if (root.panels.dashboardWrapper.x + root.panels.dashboardWrapper.width > root.panels.sidebar.x)
root.screenState.dashboard = false;
root.screenState.dashboard = false;
root.screenState.settings = false;
root.popouts.hasCurrent = false;
}
+315
View File
@@ -0,0 +1,315 @@
import Quickshell
import QtQuick
import ZShell.Config
import ZShell.Internal
import qs.Components
import qs.Helpers
import qs.Modules.Bar.Popouts
CustomMouseArea {
id: root
required property Item bar
required property real borderThickness
property bool dashboardShortcutActive
property point dragStart
required property Drawing drawing
required property EdgeGeometry geometry
property bool osdShortcutActive
required property Panels panels
required property Wrapper popouts
required property ShellScreen screen
required property ScreenState screenState
property bool setInitialPoint: false
property bool singleGestureTriggered: false
property bool utilitiesShortcutActive
function inBottomPanel(panel: Item, x: real, y: real): bool {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
return y > root.height - (panelHeight + geometry.insetBottom(borderThickness)) && withinPanelWidth(panel, x, y);
}
function inLeftPanel(panel: Item, x: real, y: real): bool {
return x < panel.x + panel.width + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
}
function inPopoutArea(x: real, y: real): bool {
const panel = panels.popoutsWrapper;
if (!geometry.horizontal)
return inLeftPanel(panel, x, y);
return withinPanelWidth(panel, x, y) && withinPanelHeight(panel, x, y);
}
function inRightPanel(panel: Item, x: real, y: real): bool {
return x > panel.x + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
}
function inTopPanel(panel: Item, x: real, y: real): bool {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
return y < geometry.insetTop(borderThickness) + panelHeight && withinPanelWidth(panel, x, y);
}
function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = panel.y + geometry.insetTop(borderThickness);
return y >= panelY && y <= panelY + panel.height;
}
function withinPanelWidth(panel: Item, x: real, y: real): bool {
const panelX = panel.x + geometry.insetLeft(borderThickness);
return x >= panelX && x <= panelX + panel.width;
}
acceptedButtons: bar.fullscreen ? Qt.NoButton : Qt.AllButtons
anchors.fill: parent
hoverEnabled: true
onContainsMouseChanged: {
if (!containsMouse) {
if (!osdShortcutActive) {
screenState.osd = false;
panels.osd.hovered = false;
}
if (!popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover) {
popouts.hasCurrent = false;
}
if (Config.bar.autoHide || bar.fullscreen)
bar.isHovered = false;
if (screenState.dashboard && Config.dashboard.showOnHover)
screenState.dashboard = false;
}
}
onPositionChanged: event => {
const x = event.x;
const y = event.y;
const dragX = x - dragStart.x;
const dragY = y - dragStart.y;
if (screenState.isDrawing) {
if (pressed) {
drawing.content.appendPoint(x, y);
} else {
if (inLeftPanel(panels.drawing, x, y)) {
if (!(pressedButtons & Qt.LeftButton)) {
panels.drawing.expand();
drawing.content.hideHover();
Cursor.clearOverride();
}
} else {
Cursor.setOverride(Qt.BlankCursor);
drawing.content.showHover(x, y);
}
}
if (drawing.content.hoverVisible)
drawing.content.showHover(x, y);
return;
}
if (root.bar.fullscreen && !root.bar.isHovered)
unhideTimer.start();
if (pressed && dragStart.y >= screen.height - Config.bar.border && dragStart.x > screen.width / 5 && dragY < -Config.launcher.dragThreshold)
screenState.launcher = true;
const entryAt = bar.entryAt(geometry.axisPos(x, y));
const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboardWrapper, x, y) && (!entryAt || entryAt === "activeWindow");
if (!dashboardShortcutActive) {
screenState.dashboard = showDashboard;
} else if (showDashboard) {
dashboardShortcutActive = false;
}
if (pressed && geometry.insetTop(borderThickness) > dragStart.y && withinPanelWidth(panels.dashboardWrapper, x, y)) {
if (dragY > Config.dashboard.dragThreshold)
screenState.dashboard = true;
else if (dragY < -Config.dashboard.dragThreshold)
screenState.dashboard = false;
}
if (pressed && geometry.insetTop(borderThickness) > dragStart.y && !inTopPanel(panels.dashboardWrapper, dragStart.x, dragStart.y)) {
if (dragY > 20) {
screenState.settings = true;
} else if (dragY < -20) {
screenState.settings = false;
}
}
if (pressed && dragStart.y > screen.height - geometry.insetBottom(borderThickness) && dragStart.x < screen.width / 5 && dragY < -50)
screenState.clipboard = true;
if (pressed && !Config.dock.hoverToReveal && dragStart.y > screen.height - geometry.insetTop(borderThickness) && dragStart.x > screen.width / 5 && !screenState.launcher)
if (dragY < -10)
screenState.dock = true;
if (pressed && dragStart.x > screen.width - Config.bar.border && dragStart.y < (screen.height / 2) && dragX < -Config.sidebar.dragThreshold)
screenState.sidebar = true;
if (pressed && dragStart.x >= screen.width - Config.bar.border && dragStart.y > (screen.height / 2) && dragX < -20)
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`);
if (pressed && dragStart.x <= Config.bar.border && dragX > 20)
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`);
if (!screenState.bar && Config.bar.autoHide && geometry.barContains(x, y, true))
bar.isHovered = true;
if (panels.sidebar.offsetScale === 1) {
const showOsd = inRightPanel(panels.osdWrapper, x, y);
if (showOsd) {
osdShortcutActive = false;
panels.osd.hovered = true;
}
} else {
const outOfSidebar = x < width - panels.sidebar.width * (1 - panels.sidebar.offsetScale);
const showOsd = outOfSidebar && inRightPanel(panels.osdWrapper, x, y);
if (!osdShortcutActive) {
screenState.osd = showOsd;
panels.osd.hovered = showOsd;
} else if (showOsd) {
osdShortcutActive = false;
panels.osd.hovered = true;
}
}
if (Config.dock.enable && Config.dock.hoverToReveal && !screenState.dock && !screenState.launcher && inBottomPanel(panels.dock, x, y))
screenState.dock = true;
if (geometry.barContains(x, y))
bar.checkPopout(geometry.axisPos(x, y));
}
onPressed: event => {
dragStart = Qt.point(event.x, event.y);
if (screenState.isDrawing) {
if (event.button & Qt.RightButton) {
drawing.content.clear();
return;
}
if (!inLeftPanel(panels.drawing, mouseX, mouseY))
drawing.content.beginStroke(event.x, event.y);
}
}
onPressedChanged: {
if (!pressed) {
if (screenState.isDrawing) {
setInitialPoint = false;
drawing.content.endStroke();
if (!inLeftPanel(panels.drawing, mouseX, mouseY))
drawing.content.showHover(mouseX, mouseY);
}
} else {
if (screenState.isDrawing) {
panels.drawing.collapse();
}
}
}
Timer {
id: unhideTimer
interval: Config.bar.revealDelay
repeat: false
running: false
onTriggered: {
if (root.containsMouse)
root.bar.isHovered = true;
}
}
Connections {
function onDashboardChanged(): void {
if (root.screenState.dashboard) {
const inDashboardArea = root.inTopPanel(root.panels.dashboardWrapper, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.dashboardShortcutActive = true;
}
root.screenState.launcher = false;
root.screenState.settings = false;
root.screenState.sidebar = false;
root.screenState.resources = false;
root.popouts.hasCurrent = false;
} else {
root.dashboardShortcutActive = false;
}
}
function onIsDrawingChanged(): void {
if (root.screenState.isDrawing) {
Cursor.setOverride(Qt.BlankCursor);
} else {
Cursor.clearOverride();
}
}
function onLauncherChanged(): void {
if (!root.screenState.launcher) {
root.dashboardShortcutActive = false;
root.osdShortcutActive = false;
root.utilitiesShortcutActive = false;
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
if (!inOsdArea) {
root.screenState.osd = false;
root.panels.osd.hovered = false;
}
}
if (root.screenState.launcher) {
root.screenState.dashboard = false;
root.screenState.dock = false;
root.screenState.settings = false;
}
}
function onOsdChanged(): void {
if (root.screenState.osd) {
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
if (!inOsdArea) {
root.osdShortcutActive = true;
}
} else {
root.osdShortcutActive = false;
}
}
function onResourcesChanged(): void {
if (root.screenState.resources) {
if (root.popouts.currentName.startsWith("audio") || root.popouts.currentName.startsWith("updates"))
root.popouts.hasCurrent = false;
root.screenState.settings = false;
root.screenState.dashboard = false;
}
}
function onSettingsChanged(): void {
if (root.screenState.settings) {
root.screenState.resources = false;
root.screenState.dashboard = false;
root.screenState.sidebar = false;
root.panels.popouts.hasCurrent = false;
root.screenState.launcher = false;
}
}
function onSidebarChanged(): void {
if (root.screenState.sidebar) {
if (root.panels.dashboardWrapper.x + root.panels.dashboardWrapper.width > root.panels.sidebar.x)
root.screenState.dashboard = false;
root.screenState.settings = false;
root.popouts.hasCurrent = false;
}
}
target: root.screenState
}
}
+8 -17
View File
@@ -1,7 +1,5 @@
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
@@ -16,6 +14,7 @@ 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
@@ -75,10 +74,7 @@ Item {
anchors.right: parent.right
anchors.rightMargin: sidebar.width * (1 - sidebar.offsetScale)
y: ZUtils.snap((parent.height - implicitHeight) / 2, root)
// anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: parent.verticalCenter
clip: sidebar.visible
implicitHeight: osd.implicitHeight
implicitWidth: osd.implicitWidth * (1 - osd.offsetScale)
@@ -86,7 +82,8 @@ Item {
Osd.Wrapper {
id: osd
anchors.fill: parent
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
screen: root.screen
screenState: root.screenState
sidebarOrSessionVisible: sidebar.visible
@@ -132,9 +129,8 @@ 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
@@ -154,10 +150,8 @@ Item {
property real offsetScale: dashboard.shouldBeActive ? 0 : 1
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
x: ZUtils.snap((parent.width - implicitWidth) / 2, dashboardWrapper)
clip: offsetScale > 0
implicitHeight: dashboard.implicitHeight * (1 - offsetScale)
implicitWidth: dashboard.implicitWidth
@@ -196,11 +190,8 @@ Item {
Settings.Wrapper {
id: settings
x: ZUtils.snap((parent.width - implicitWidth) / 2, settings)
y: ZUtils.snap((parent.height - implicitHeight) / 2 - (implicitHeight + 5 + (parent.height - implicitHeight) / 2) * offsetScale, settings)
// anchors.centerIn: parent
// anchors.verticalCenterOffset: (-implicitHeight - 5 - ((root.height - implicitHeight) / 2)) * offsetScale
anchors.centerIn: parent
anchors.verticalCenterOffset: (-implicitHeight - 5 - ((root.height - implicitHeight) / 2)) * offsetScale
panels: root
screen: root.screen
screenState: root.screenState
+2 -24
View File
@@ -56,7 +56,7 @@ CustomWindow {
property color surfaceColor: Colors.tPalette.m3surface
WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.keyboardFocus: screenState.screenshot ? WlrKeyboardFocus.Exclusive : screenState.launcher || screenState.settings || screenState.sidebar || screenState.isDrawing ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
WlrLayershell.keyboardFocus: screenState.screenshot ? WlrKeyboardFocus.Exclusive : screenState.launcher || screenState.settings || screenState.sidebar ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
color: "transparent"
mask: screenState.isDrawing || screenState.screenshot ? null : (hasFullscreen && !bar.isHovered ? emptyRegion : regions)
@@ -347,31 +347,12 @@ CustomWindow {
Drawing {
id: drawing
readonly property int extraWidth: drawingBg.radius * 2
anchors.fill: parent
holeRect: Qt.rect(root.borderThickness + panels.drawing.x - extraWidth, panels.drawing.y + bar.implicitHeight, panels.drawing.implicitWidth + extraWidth, panels.drawing.implicitHeight)
holeRadius: drawingBg.radius
screenState: root.screenState
z: 2
}
LazyLoader {
id: lazyLoader
activeAsync: root.screenState.isDrawing
component: DrawingInput {
borderThickness: root.borderLayoutThickness
drawing: drawing
panels: panels
screenState: root.screenState
geometry: geometry
parent: root.contentItem
}
}
Interactions {
Interactions2 {
id: interactions
anchors.fill: parent
@@ -384,8 +365,6 @@ CustomWindow {
popouts: panels.popouts
screen: root.screen
screenState: root.screenState
input: lazyLoader.item
z: 1
Panels {
id: panels
@@ -463,7 +442,6 @@ CustomWindow {
parent: root.contentItem
screen: root.screen
screenState: root.screenState
z: 4
}
}
+3 -6
View File
@@ -3,12 +3,11 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Helpers
import qs.Services
SnapLayout {
ColumnLayout {
id: root
readonly property real centerScale: Math.min(1, screenHeight / 1440)
@@ -19,11 +18,9 @@ SnapLayout {
Layout.fillHeight: true
Layout.fillWidth: false
Layout.preferredWidth: centerWidth
orientation: Qt.Vertical
spacing: Tokens.spacing.largeIncreased * 2
SnapLayout {
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Tokens.spacing.small
@@ -119,7 +116,7 @@ SnapLayout {
}
}
SnapLayout {
RowLayout {
id: input
anchors.fill: parent
+2 -3
View File
@@ -1,12 +1,11 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Helpers
import ZShell.Config
import qs.Services
SnapLayout {
RowLayout {
id: root
required property var greeter
-1
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
+4 -10
View File
@@ -3,20 +3,17 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Services
SnapLayout {
ColumnLayout {
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
@@ -40,9 +37,8 @@ SnapLayout {
duration: Tokens.anim.durations.extraLarge
}
}
sourceComponent: SnapLayout {
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.largeIncreased
orientation: Qt.Vertical
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
@@ -88,7 +84,7 @@ SnapLayout {
}
}
SnapLayout {
RowLayout {
id: row
anchors.fill: parent
@@ -101,11 +97,9 @@ SnapLayout {
text: modelData.kind === "x11" ? "tv" : "desktop_windows"
}
SnapLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.small / 2
orientation: Qt.Vertical
CustomText {
Layout.fillWidth: true
+4 -10
View File
@@ -3,21 +3,18 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Helpers
import qs.Services
SnapLayout {
ColumnLayout {
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
@@ -41,9 +38,8 @@ SnapLayout {
duration: Tokens.anim.durations.extraLarge
}
}
sourceComponent: SnapLayout {
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.largeIncreased
orientation: Qt.Vertical
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
@@ -90,7 +86,7 @@ SnapLayout {
}
}
SnapLayout {
RowLayout {
id: row
anchors.fill: parent
@@ -116,11 +112,9 @@ SnapLayout {
}
}
SnapLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.small / 2
orientation: Qt.Vertical
CustomText {
Layout.fillWidth: true
+1 -1
View File
@@ -53,7 +53,7 @@ CustomRect {
radius: Tokens.rounding.full
width: row.implicitWidth + Tokens.padding.small * 2
SnapLayout {
RowLayout {
id: row
anchors.centerIn: parent
+43 -105
View File
@@ -5,7 +5,7 @@ import Quickshell
import Quickshell.Io
import QtQuick
import ZShell.Models
import ZShell.Wallpaper
import ZShell.Internal
import ZShell.Config
import qs.Components
import qs.Services
@@ -16,48 +16,24 @@ Searcher {
id: root
property string actualCurrent: WallpaperPath.currentWallpaperPath
property alias crops: adapter.monitorCrops
readonly property string current: showPreview ? previewPath : actualCurrent
readonly property string currentThumbnail: thumbnailFor(current)
readonly property bool currentIsVideo: isVideoPath(current)
property alias monitorCrops: monitorCrops
property bool pendingPreviewClear
property bool previewColorLock
property string previewPath
property bool recentlyChanged
property bool showPreview: false
property int cropVersion: 0
function getCategoryFor(w: WallpaperEntry): string {
function getCategoryFor(w: FileSystemEntry): string {
let category = w.parentDir.slice(Paths.wallsdir.length + 1);
if (category.includes("/"))
category = category.slice(0, category.indexOf("/"));
return category;
}
readonly property var videoExts: ["mp4", "mkv", "webm", "avi", "mov", "wmv", "flv", "m4v", "mpg", "mpeg", "3gp", "ogv", "ts", "vob"]
function isVideoPath(path: string): bool {
if (!path)
return false;
const dot = path.lastIndexOf(".");
if (dot < 0)
return false;
return videoExts.includes(path.slice(dot + 1).toLowerCase());
}
function thumbnailFor(path: string): string {
if (!path)
return "";
for (const entry of root.list) {
if (entry.path === path)
return entry.thumbnailPath || path;
}
return path;
}
function getCrop(screen: string): var {
return wallpapers.crop(root.current, screen);
return root.crops[screen];
}
function preview(path: string): void {
@@ -74,18 +50,19 @@ Searcher {
else if (zoom > 5.0)
zoom = 5.0;
wallpapers.setCrop(root.current, screen, {
root.crops[screen] = {
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
zoom: zoom
});
};
}
function setWallpaper(path: string): void {
actualCurrent = path;
WallpaperPath.currentWallpaperPath = path;
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), 1.0));
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
if (Config.colors.schemeGen)
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.colors.mode}`]);
@@ -119,13 +96,38 @@ Searcher {
target: "wallpaper"
}
WallpaperDb {
FileView {
id: monitorCrops
path: `${Paths.state}/wallpaper-crops.json`
watchChanges: true
onAdapterUpdated: cropWriteDelay.restart()
onFileChanged: reload()
JsonAdapter {
id: adapter
property var monitorCrops: ({})
}
}
Timer {
id: cropWriteDelay
interval: 100
repeat: false
running: false
onTriggered: monitorCrops.writeAdapter()
}
FileSystemModel {
id: wallpapers
dbPath: `${Paths.state}/wallpapers.sqlite`
cacheSize: wallpaper.largestBufferSize
requireHardwareCodec: true
filter: FileSystemModel.Images
path: Config.general.wallpaperPath
recursive: true
}
Process {
@@ -144,100 +146,36 @@ Searcher {
WallpaperService {
id: wallpaper
dbPath: wallpapers.dbPath
path: root.current
}
Connections {
target: wallpapers
function onCacheStored(path: string): void {
if (path === root.current)
wallpaper.invalidateCache();
}
function onCropsChanged(path: string): void {
if (path === root.current)
root.cropVersion++;
}
}
Variants {
id: screenVariants
model: Quickshell.screens
WallpaperObject {
id: obj
readonly property var crops: root.getCrop(modelData.name)
required property var modelData
// Crop animation only for edits, never for wallpaper swaps.
property bool animateCrop: false
cropHeight: crops?.height ?? 1.0
cropWidth: crops?.width ?? 1.0
cropX: crops?.x ?? 0.0
cropY: crops?.y ?? 0.0
screen: modelData.name
service: wallpaper
// Apply the wallpaper's own crop. Driven off the service's pathChanged
// (which fires after applyPath has snapshotted the outgoing frame with
// the outgoing crop) and off crop edits, never as a reactive binding on
// the wallpaper path — so a swap applies the incoming crop atomically
// after the base is captured.
function seedCrop(): void {
// Load the current wallpaper's crop without pushing: the service
// already read it from the database. This only seeds the values so
// a later edit animates from the right starting point.
obj.syncCrop(root.getCrop(modelData.name));
}
// Apply an edited crop: assign via the setters so the Behaviors animate
// the numbers and push each intermediate value to the service.
function editCrop(): void {
const c = root.getCrop(modelData.name);
obj.cropX = c?.x ?? 0.0;
obj.cropY = c?.y ?? 0.0;
obj.cropWidth = c?.width ?? 1.0;
obj.cropHeight = c?.height ?? 1.0;
obj.zoom = c?.zoom ?? 1.0;
}
Component.onCompleted: seedCrop()
onScreenChanged: seedCrop()
zoom: crops?.zoom ?? 1.0
Behavior on cropHeight {
enabled: obj.animateCrop
Anim {}
}
Behavior on cropWidth {
enabled: obj.animateCrop
Anim {}
}
Behavior on cropX {
enabled: obj.animateCrop
Anim {}
}
Behavior on cropY {
enabled: obj.animateCrop
Anim {}
}
}
}
Connections {
target: wallpaper
function onPathChanged(): void {
for (const obj of screenVariants.instances) {
obj.animateCrop = false;
obj.seedCrop();
}
}
}
Connections {
target: root
function onCropVersionChanged(): void {
for (const obj of screenVariants.instances) {
obj.animateCrop = true;
obj.editCrop();
}
}
}
}
+10 -59
View File
@@ -4,13 +4,11 @@ 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
import ZShell
SnapLayout {
GridLayout {
id: root
required property bool fullscreen
@@ -24,7 +22,7 @@ SnapLayout {
function axisCenterOf(item: Item): real {
const c = item.mapToItem(root, item.implicitWidth / 2, item.implicitHeight / 2);
return horizontal ? ZUtils.snap(c.x, item) : ZUtils.snap(c.y, item);
return horizontal ? Math.floor(c.x) : Math.floor(c.y);
}
function checkPopout(pos: real): void {
@@ -76,47 +74,9 @@ SnapLayout {
return ch?.entryId ?? "";
}
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
columnSpacing: Tokens.spacing.small
columns: horizontal ? -1 : 1
rowSpacing: Tokens.spacing.small
Repeater {
id: repeater
@@ -250,7 +210,8 @@ SnapLayout {
roleValue: "network"
delegate: EntryWrapper {
NetworkWidget {}
NetworkWidget {
}
}
}
@@ -268,26 +229,16 @@ SnapLayout {
}
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
required property var modelData
default property Item item
required property var modelData
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
Layout.bottomMargin: !root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.spacing + Tokens.spacing.extraSmall : 0
Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.rowSpacing + Tokens.spacing.extraSmall : 0
Layout.rightMargin: root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.spacing + Tokens.spacing.extraSmall : 0
Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.columnSpacing + Tokens.spacing.extraSmall : 0
children: item
implicitHeight: item?.implicitHeight ?? 0
implicitWidth: item?.implicitWidth ?? 0
-1
View File
@@ -9,7 +9,6 @@ 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
+3 -7
View File
@@ -4,7 +4,6 @@ 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
@@ -44,11 +43,9 @@ WidgetBase {
timeTokens: timeTokens
};
}
required property SnapLayout loader
required property GridLayout loader
required property Wrapper popouts
readonly property int roundedWidth: Math.round(timeText.implicitWidth)
readonly property int evenWidth: roundedWidth % 2 === 0 ? roundedWidth : roundedWidth + 1
readonly property real size: horizontal ? evenWidth + Tokens.padding.medium * 2 : verticalColumn.implicitHeight + Tokens.padding.medium * 2
readonly property real size: horizontal ? timeText.contentWidth + Tokens.padding.medium * 2 : verticalColumn.implicitHeight + Tokens.padding.medium * 2
required property ScreenState screenState
implicitHeight: horizontal ? baseSize : size
@@ -70,8 +67,7 @@ WidgetBase {
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: verticalColumn
anchors.centerIn: parent
@@ -24,7 +24,7 @@ Row {
color: Battery.getColors(root.percentage, root.devState).bg
height: root.batHeight
radius: root.radius
width: root.batWidth - 1
width: root.batWidth
CustomText {
color: Battery.getColors(root.percentage, root.devState).fg
+1 -2
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Modules.Bar.Components.Common
@@ -14,7 +13,7 @@ WidgetBase {
readonly property int textWidth: Math.min(metrics.width, 200)
implicitHeight: horizontal ? baseSize : layout.implicitHeight + Tokens.padding.small * 2
implicitWidth: horizontal ? (layout.implicitWidth % 2 === 0 ? layout.implicitWidth : layout.implicitWidth + 1) + Tokens.padding.small * 2 : baseSize
implicitWidth: horizontal ? layout.implicitWidth + Tokens.padding.small * 2 : baseSize
radius: Tokens.rounding.full
Behavior on implicitHeight {
+1 -2
View File
@@ -1,7 +1,6 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import qs.Modules
@@ -12,7 +11,7 @@ Item {
anchors.top: parent.top
implicitWidth: layout.implicitWidth
SnapLayout {
RowLayout {
id: layout
anchors.bottom: parent.bottom
+12 -9
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import qs.Components
import ZShell.Config
@@ -13,6 +12,7 @@ GridLayout {
property real animatedPercentage: 0
readonly property real arcStartAngle: 0.75 * Math.PI
readonly property real arcSweep: 1.5 * Math.PI
readonly property real dpr: (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1
required property bool horizontal
property string icon
required property color iconColor
@@ -23,12 +23,17 @@ GridLayout {
property bool warning: percentage * 100 >= warningThreshold
property int warningThreshold: 80
function snap(v) {
return Math.round(v * dpr) / dpr;
}
columnSpacing: Tokens.spacing.medium
columns: horizontal ? -1 : 1
percentage: 0
Behavior on animatedPercentage {
Anim {}
Anim {
}
}
Component.onCompleted: animatedPercentage = percentage
@@ -54,7 +59,7 @@ GridLayout {
Layout.preferredHeight: root.horizontal ? icon.implicitHeight - Tokens.padding.extraSmall : 4
Layout.preferredWidth: root.horizontal ? 4 : icon.implicitWidth
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
radius: Tokens.rounding.full
radius: Math.min(width, height) / 2
Item {
id: clipper
@@ -64,20 +69,18 @@ GridLayout {
anchors.left: root.horizontal ? undefined : parent.left
anchors.verticalCenter: root.horizontal ? undefined : parent.verticalCenter
clip: true
implicitHeight: root.horizontal ? root.percentage * track.height : track.height * 2
implicitWidth: root.horizontal ? track.width * 2 : root.percentage * track.width
height: root.horizontal ? root.snap(root.percentage * track.height) : track.height * 2
width: root.horizontal ? track.width * 2 : root.snap(root.percentage * track.width)
CustomRect {
anchors.bottom: root.horizontal ? parent.bottom : undefined
anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined
anchors.left: root.horizontal ? undefined : parent.left
anchors.verticalCenter: root.horizontal ? undefined : parent.verticalCenter
color: root.mainColor
height: track.height
radius: track.radius
implicitHeight: track.height
implicitWidth: track.width
width: track.width
}
}
}
-3
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import ZShell.Services
import qs.Services
@@ -34,7 +33,6 @@ WidgetBase {
anchors.horizontalCenterOffset: root.horizontal ? 0 : 1
anchors.verticalCenterOffset: root.horizontal ? 0 : -3
columnSpacing: Tokens.spacing.small
rowSpacing: 0
columns: root.horizontal ? -1 : 1
ServiceRef {
@@ -53,7 +51,6 @@ WidgetBase {
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: root.horizontal
Layout.fillWidth: !root.horizontal
horizontal: root.horizontal
icon: "memory"
iconColor: root.screenState.resources ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
+11 -10
View File
@@ -4,7 +4,6 @@ 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
@@ -32,7 +31,7 @@ WidgetBase {
return -1;
}
readonly property real size: horizontal ? grid.implicitWidth + grid.anchors.leftMargin + grid.anchors.rightMargin : grid.implicitHeight + grid.anchors.bottomMargin + grid.anchors.topMargin
readonly property int spacing: Tokens.spacing.extraSmall
readonly property int spacing: Tokens.spacing.medium / 2
// Entries that can shrink to nothing, spacing included
function collapsed(entry: var): bool {
@@ -52,15 +51,17 @@ WidgetBase {
Behavior on implicitHeight {
enabled: !root.horizontal
Anim {}
Anim {
}
}
Behavior on implicitWidth {
enabled: root.horizontal
Anim {}
Anim {
}
}
SnapLayout {
GridLayout {
id: grid
anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.medium
@@ -68,8 +69,7 @@ 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
orientation: root.horizontal ? Qt.Horizontal : Qt.Vertical
spacing: root.horizontal ? Tokens.spacing.extraSmall : -2
columns: root.horizontal ? -1 : 1
Repeater {
model: ScriptModel {
@@ -111,7 +111,8 @@ WidgetBase {
delegate: EntryWrapper {
name: "upower"
UPowerWidget {}
UPowerWidget {
}
}
}
}
@@ -134,8 +135,8 @@ WidgetBase {
Layout.rightMargin: root.horizontal ? Math.round(rightGap) : 0
Layout.topMargin: root.horizontal ? 0 : Math.round(leftGap)
children: item
implicitHeight: item?.height ?? item?.implicitHeight ?? 0
implicitWidth: item?.width ?? item?.implicitWidth ?? 0
implicitHeight: item?.implicitHeight ?? 0
implicitWidth: item?.implicitWidth ?? 0
Behavior on leftGap {
Anim {
@@ -1,13 +1,12 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Daemons
import qs.Components
import qs.Services
MaterialIcon {
id: root
id: speaker
required property bool horizontal
@@ -16,8 +15,6 @@ MaterialIcon {
fill: 1
fontStyle: Tokens.font.icon.small
text: Audio.muted ? "volume_off" : "volume_up"
width: Math.round(implicitWidth)
height: Math.round(implicitHeight)
Behavior on Layout.maximumWidth {
Anim {}
@@ -1,13 +1,12 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Daemons
import qs.Components
import qs.Services
MaterialIcon {
id: root
id: mic
required property bool horizontal
@@ -16,8 +15,6 @@ MaterialIcon {
fill: 1
fontStyle: Tokens.font.icon.small
text: Audio.sourceMuted ? "mic_off" : "mic"
width: Math.round(implicitWidth)
height: Math.round(implicitHeight)
Behavior on Layout.maximumWidth {
Anim {}
@@ -1,7 +1,6 @@
import Quickshell.Services.UPower
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Modules.Bar.Components.Common
import qs.Components
+2 -3
View File
@@ -2,11 +2,10 @@ 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 {
@@ -16,7 +15,7 @@ Item {
readonly property real dpr: Hypr.monitorFor(loader?.screen).scale
required property int ind
required property SystemTrayItem item
required property SnapLayout loader
required property GridLayout loader
required property Wrapper popouts
function resolveIcon(app: string, icon: string): string {
+4 -5
View File
@@ -4,7 +4,6 @@ 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
@@ -16,7 +15,7 @@ WidgetBase {
readonly property alias items: repeater
readonly property alias layout: sysGrid
required property SnapLayout loader
required property GridLayout 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
@@ -29,7 +28,7 @@ WidgetBase {
radius: Tokens.rounding.full
topRightRadius: horizontal ? Tokens.rounding.small / 2 : Tokens.rounding.full
SnapLayout {
GridLayout {
id: sysGrid
anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.extraSmall
@@ -37,8 +36,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
orientation: root.horizontal ? Qt.Horizontal : Qt.Vertical
spacing: root.horizontal ? Tokens.spacing.extraSmall : -2
columns: root.horizontal ? -1 : 1
rowSpacing: -2
Repeater {
id: repeater
-1
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Modules.Bar.Components.Common
+1 -1
View File
@@ -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.spacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.spacing * (bar.children.length - 1) - bar.vPadding * 4);
return horizontal ? (bar.width - otherSize - bar.columnSpacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.rowSpacing * (bar.children.length - 1) - bar.vPadding * 4);
}
clip: true
+27 -25
View File
@@ -12,14 +12,13 @@ import qs.Services
Item {
id: root
property real activeWorkspaceMargin: Tokens.padding.extraSmall / 2
readonly property int spacing: Tokens.spacing.extraSmall / 2
property real activeWorkspaceMargin: Math.ceil(Tokens.padding.medium / 4)
readonly property int effectiveActiveWorkspaceId: monitor?.activeWorkspace?.id ?? 1
required property bool horizontal
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
required property ShellScreen screen
readonly property real shortSize: Math.max(Config.bar.height, Tokens.sizes.bar.innerSize)
readonly property real size: (workspaceButtonWidth * workspacesShown) + (spacing * Math.max(0, workspacesShown - 1)) + activeWorkspaceMargin * 2
readonly property real size: (workspaceButtonWidth * workspacesShown) + activeWorkspaceMargin * 2
property int workspaceButtonWidth: (horizontal ? bgRect.implicitHeight : bgRect.implicitWidth) - root.activeWorkspaceMargin * 2
property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown
readonly property list<var> workspaces: Hyprland.workspaces.values.filter(w => w.monitor === root.monitor)
@@ -60,17 +59,15 @@ Item {
anchors.fill: parent
anchors.margins: root.activeWorkspaceMargin
columnSpacing: root.spacing
columnSpacing: 0
columns: root.horizontal ? root.workspacesShown : 1
rowSpacing: root.spacing
rowSpacing: 0
rows: root.horizontal ? 1 : root.workspacesShown
layer.enabled: true
layer.mipmap: true
Repeater {
model: root.workspaces
CustomRect {
Button {
id: button
required property int index
@@ -78,19 +75,27 @@ Item {
implicitHeight: indicator.indicatorThickness
implicitWidth: indicator.indicatorThickness
radius: Tokens.rounding.full
width: root.workspaceButtonWidth
CustomText {
anchors.centerIn: parent
color: Colors.palette.m3onSecondaryContainer
text: button.modelData?.name ?? ""
background: Item {
id: workspaceButtonBackground
implicitHeight: root.workspaceButtonWidth
implicitWidth: root.workspaceButtonWidth
CustomText {
anchors.centerIn: parent
color: Colors.palette.m3onSecondaryContainer
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: button.modelData?.name ?? ""
verticalAlignment: Text.AlignVCenter
}
}
StateLayer {
onPressed: {
const ws = button.modelData.name;
Hyprland.dispatch(Hyprland.usingLua ? `hl.dsp.focus({ workspace= "${ws}"})` : `workspace ${ws}`);
}
onPressed: {
const ws = button.modelData.name;
Hyprland.dispatch(Hyprland.usingLua ? `hl.dsp.focus({ workspace= "${ws}"})` : `workspace ${ws}`);
}
}
}
@@ -99,10 +104,8 @@ Item {
CustomRect {
id: indicator
readonly property real step: root.workspaceButtonWidth + root.spacing
property real indicatorLength: (Math.abs(idxPair.idx1 - idxPair.idx2) + 1) * root.workspaceButtonWidth + Math.abs(idxPair.idx1 - idxPair.idx2) * root.spacing
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * step + root.activeWorkspaceMargin
property real indicatorLength: (Math.abs(idxPair.idx1 - idxPair.idx2) + 1) * root.workspaceButtonWidth
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceMargin
property real indicatorThickness: root.workspaceButtonWidth
anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter
@@ -126,10 +129,9 @@ Item {
implicitHeight: grid.height
implicitWidth: grid.width
source: grid
autoPaddingEnabled: false
sourceColor: Colors.palette.m3onSurface
x: root.horizontal ? -indicator.x + root.activeWorkspaceMargin : 0
y: root.horizontal ? 0 : -indicator.y + root.activeWorkspaceMargin
x: root.horizontal ? -indicator.x + 3 : 0
y: root.horizontal ? 0 : -indicator.y + 3
}
}
}
+10 -15
View File
@@ -5,7 +5,6 @@ import Quickshell.Services.Pipewire
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import QtQuick.Controls
import ZShell.Config
import qs.Components
@@ -47,8 +46,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
}
component VolumesTab: SnapLayout {
orientation: Qt.Vertical
component VolumesTab: ColumnLayout {
spacing: 12
CustomRect {
@@ -58,15 +56,14 @@ orientation: Qt.Vertical
color: Colors.tPalette.m3surfaceContainer
radius: root.rounding - vol.anchors.margins
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
anchors.topMargin: Tokens.padding.small
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -84,7 +81,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
spacing: Tokens.spacing.largeIncreased
CustomMouseArea {
@@ -156,15 +153,14 @@ orientation: Qt.Vertical
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
anchors.topMargin: Tokens.padding.small
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -182,7 +178,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
spacing: Tokens.spacing.largeIncreased
CustomMouseArea {
@@ -280,15 +276,14 @@ orientation: Qt.Vertical
text: Audio.getStreamName(appBox.modelData)
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
anchors.topMargin: Tokens.padding.small
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -307,7 +302,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
spacing: Tokens.spacing.largeIncreased
CustomMouseArea {
+4 -4
View File
@@ -4,7 +4,6 @@ import QtQuick
import Quickshell
import qs.Components
import ZShell.Config
import ZShell
Item {
id: root
@@ -37,7 +36,7 @@ Item {
const diff = parent.width - Math.floor(off + content.nonAnimWidth);
if (diff < 0)
return off + diff;
return ZUtils.snap(Math.max(off, 0), root);
return Math.floor(Math.max(off, 0));
}
y: {
if (horizontal)
@@ -47,11 +46,12 @@ Item {
const diff = parent.height - Math.floor(off + content.nonAnimHeight);
if (diff < 0)
return off + diff;
return ZUtils.snap(Math.max(off, 0), root);
return Math.max(off, 0);
}
Behavior on offsetScale {
Anim {}
Anim {
}
}
Behavior on x {
enabled: !root.horizontal || root.offsetScale < 1
+1 -3
View File
@@ -4,7 +4,6 @@ import Quickshell
import Quickshell.Networking
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import ZShell.Config
import qs.Modules
@@ -15,8 +14,7 @@ Item {
required property var wrapper
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: layout
spacing: 8
+1 -3
View File
@@ -4,7 +4,6 @@ import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import QtQuick.Controls
import QtQuick.Effects
import qs.Components
@@ -48,8 +47,7 @@ StackView {
duration: 0
}
}
component SubMenu: SnapLayout {
orientation: Qt.Vertical
component SubMenu: ColumnLayout {
id: menu
required property QsMenuHandle handle
+1 -2
View File
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell.Services.UPower
import ZShell.Config
import qs.Modules.Bar.Components.Common
@@ -36,7 +35,7 @@ Column {
Repeater {
model: Battery.allPeripherals
SnapLayout {
RowLayout {
id: layout
required property var modelData
+3 -5
View File
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import ZShell.Config
import qs.Components
@@ -87,7 +86,7 @@ CustomRect {
implicitWidth: 600
radius: root.radius - Tokens.padding.extraSmall
SnapLayout {
RowLayout {
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
@@ -97,8 +96,7 @@ CustomRect {
text: "package_2"
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
Layout.fillWidth: true
CustomText {
@@ -116,7 +114,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.preferredWidth: 300
+2 -3
View File
@@ -2,7 +2,6 @@ import Quickshell
import QtQuick
import qs.Components
import ZShell.Config
import ZShell
Item {
id: root
@@ -27,8 +26,8 @@ Item {
detachedMode = "";
}
implicitHeight: ZUtils.snap(nonAnimHeight, root)
implicitWidth: ZUtils.snap(nonAnimWidth, root)
implicitHeight: nonAnimHeight
implicitWidth: nonAnimWidth
Behavior on implicitHeight {
enabled: root.offsetScale < 1
+4 -7
View File
@@ -4,7 +4,6 @@ import Quickshell
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import qs.Helpers
import ZShell.Config
@@ -55,7 +54,7 @@ Item {
}
}
CustomRect {
ClipRect {
id: preview
anchors.bottom: parent.bottom
@@ -65,7 +64,6 @@ Item {
color: Colors.tPalette.m3surfaceContainer
implicitWidth: ClipHistory.previewIsImage ? Math.max(Math.min(imagePreview.sourceSize.width + Tokens.padding.large * 2, Config.clipboard.sizes.previewWidth), Config.clipboard.sizes.minPreviewWidth) : Math.max(Math.min(textPreviewColumn.width + textPreviewColumn.anchors.margins * 2, Config.clipboard.sizes.previewWidth), Config.clipboard.sizes.minPreviewWidth)
radius: 25
clip: true
Behavior on implicitWidth {
Anim {}
@@ -112,7 +110,7 @@ Item {
Repeater {
model: lineRow.modelData.text.split("\t").slice(1)
SnapLayout {
RowLayout {
height: lineText.height
width: lineText.height + Tokens.spacing.extraSmall
@@ -226,16 +224,15 @@ Item {
}
}
SnapLayout {
RowLayout {
anchors.fill: parent
spacing: Tokens.spacing.small
Item {
ClipRect {
id: textRect
Layout.fillHeight: true
Layout.fillWidth: true
clip: true
Item {
id: textWrapper
+4 -5
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import ZShell
import qs.Components
@@ -40,8 +39,8 @@ Item {
];
return allTabs.filter(tab => tab.enabled);
}
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)
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
required property ScreenState screenState
implicitHeight: nonAnimHeight
@@ -94,8 +93,8 @@ Item {
}
anchors.fill: parent
implicitHeight: currentItem?.height ?? currentItem?.implicitHeight ?? 0
implicitWidth: currentItem?.width ?? currentItem?.implicitWidth ?? 0
implicitHeight: currentItem?.implicitHeight ?? 0
implicitWidth: currentItem?.implicitWidth ?? 0
Repeater {
id: repeater
+75 -53
View File
@@ -1,82 +1,104 @@
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
SnapLayout {
orientation: Qt.Vertical
GridLayout {
id: root
readonly property bool dashboardVisible: screenState.dashboard
required property int radius
required property ScreenState screenState
spacing: ZUtils.snap(Tokens.spacing.small, root)
columnSpacing: Tokens.spacing.small
rowSpacing: Tokens.spacing.small
height: ZUtils.snap(implicitHeight, root)
width: ZUtils.snap(implicitWidth, root)
ParallelAnimation {
id: openAnim
SnapLayout {
Layout.fillWidth: true
spacing: parent.spacing
Rect {
id: weatherRect
Layout.fillHeight: true
Layout.preferredWidth: ZUtils.snap(Tokens.sizes.dashboard.weatherWidth, root)
radius: root.radius
Weather {}
Anim {
property: "opacity"
target: root
to: 1
}
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
}
Anim {
property: "scale"
target: root
to: 1
}
}
SnapLayout {
Layout.fillWidth: true
spacing: parent.spacing
ParallelAnimation {
id: closeAnim
Rect {
id: calendarRect
Layout.fillWidth: true
Layout.fillHeight: true
implicitHeight: ZUtils.snap(calendar.implicitHeight, root)
radius: root.radius
Calendar {
id: calendar
screenState: root.screenState
}
Anim {
property: "opacity"
target: root
to: 0
}
Rect {
id: resourcesRect
Layout.fillHeight: true
implicitWidth: ZUtils.snap(resources.implicitWidth, root)
radius: root.radius
Anim {
property: "scale"
target: root
to: 0.9
}
}
Resources {
id: resources
}
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
Layout.fillWidth: true
Layout.preferredHeight: calendar.implicitHeight
Layout.row: 1
radius: root.radius
Calendar {
id: calendar
screenState: root.screenState
}
}
Rect {
Layout.column: 3
Layout.columnSpan: 2
Layout.fillHeight: true
Layout.preferredWidth: resources.implicitWidth
Layout.row: 1
radius: root.radius
Resources {
id: resources
}
}
+2 -4
View File
@@ -4,7 +4,6 @@ import Quickshell
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import ZShell.Config
import qs.Services
@@ -118,15 +117,14 @@ CustomMouseArea {
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: inner
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.extraSmall
SnapLayout {
RowLayout {
id: monthNavigationRow
Layout.fillWidth: true
+9 -11
View File
@@ -1,7 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell
import ZShell.Services
import ZShell.Config
import qs.Components
@@ -10,8 +8,9 @@ import qs.Services
Item {
id: root
anchors.fill: parent
implicitWidth: ZUtils.snap(layout.implicitWidth + layout.anchors.margins * 2, root)
anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: layout.implicitWidth + layout.anchors.margins * 4
ServiceRef {
service: Storage
@@ -29,16 +28,13 @@ Item {
service: Gpu
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
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 {
@@ -77,10 +73,12 @@ orientation: Qt.Vertical
required property string icon
implicitSize: ZUtils.snap((root.height - layout.anchors.margins * 2 - layout.spacing * 4) / 5, root)
Layout.fillHeight: true
implicitSize: height
Behavior on clampedVal {
Anim {}
Anim {
}
}
MaterialIcon {
+5 -9
View File
@@ -1,8 +1,6 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import M3Shapes
import ZShell
import ZShell.Config
import qs.Modules.Dashboard.Media
import qs.Components
@@ -15,8 +13,8 @@ Item {
property ScreenState screenState
required property int radius
implicitWidth: ZUtils.snap(1000, root)
implicitHeight: ZUtils.snap(320, root)
implicitWidth: 1000
implicitHeight: 320
ClipRect {
anchors.fill: parent
@@ -27,7 +25,7 @@ Item {
}
}
SnapLayout {
RowLayout {
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.extraLarge
@@ -96,8 +94,7 @@ Item {
active: opacity > 0
opacity: 0
sourceComponent: SnapLayout {
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.small
MaterialShape {
@@ -143,12 +140,11 @@ orientation: Qt.Vertical
asynchronous: true
active: opacity > 0
sourceComponent: SnapLayout {
sourceComponent: RowLayout {
spacing: Tokens.spacing.extraLarge
Details {
Layout.fillWidth: true
Layout.fillHeight: true
}
LyricsAndSelector {
+154 -178
View File
@@ -1,14 +1,13 @@
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
Item {
ColumnLayout {
id: root
readonly property bool hasUnknownLength: (Players.active?.length ?? 0) > 2147483647
@@ -26,187 +25,46 @@ Item {
return `${mins}:${secs}`;
}
implicitHeight: ZUtils.snap(layout.implicitHeight, root)
implicitWidth: layout.implicitWidth
spacing: Tokens.spacing.extraSmall
SnapLayout {
orientation: Qt.Vertical
id: layout
anchors.left: parent.left
anchors.right: parent.right
y: ZUtils.snap((parent.height - implicitHeight) / 2, root)
Timer {
running: Players.active?.isPlaying ?? false
interval: Config.dashboard.mediaUpdateInterval
triggeredOnStart: true
repeat: true
onTriggered: Players.active?.positionChanged()
}
spacing: ZUtils.snap(Tokens.spacing.extraSmall, root)
CustomText {
Layout.fillWidth: true
text: Players.active?.trackTitle ?? ""
font: Tokens.font.title.large
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?.trackArtist || qsTr("Unknown artist")
color: Colors.palette.m3onSurfaceVariant
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
}
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: 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)
}
}
RowLayout {
Layout.topMargin: Tokens.spacing.extraLargeIncreased
Layout.fillWidth: true
spacing: Tokens.spacing.small
TextMetrics {
id: timeMetrics
@@ -214,5 +72,123 @@ orientation: Qt.Vertical
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)
}
}
}
+2 -5
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import ZShell.Services
import qs.Components
@@ -158,8 +157,7 @@ Item {
active: opacity > 0
opacity: 0
sourceComponent: SnapLayout {
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.large
CustomRect {
@@ -200,8 +198,7 @@ orientation: Qt.Vertical
active: opacity > 0
opacity: 0
sourceComponent: SnapLayout {
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.small
MaterialIcon {
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import Quickshell.Services.Mpris
import ZShell.Config
@@ -9,15 +8,14 @@ import qs.Helpers
import qs.Services
Item {
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: layout
anchors.fill: parent
anchors.leftMargin: Tokens.padding.medium
spacing: Tokens.spacing.medium
SnapLayout {
RowLayout {
Layout.bottomMargin: -Tokens.spacing.medium
spacing: Tokens.spacing.medium
z: 1
+4 -6
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell
import ZShell.Blobs
import ZShell.Config
@@ -17,7 +16,7 @@ Item {
implicitWidth: btn.implicitWidth * 0.9
implicitHeight: btn.implicitHeight * 0.9
BlobGroup2 {
BlobGroup {
id: blobGroup
color: Colors.palette.m3surfaceContainerHighest
@@ -29,7 +28,7 @@ Item {
}
}
BlobRect2 {
BlobRect {
id: btnRect
anchors.fill: parent
@@ -42,7 +41,7 @@ Item {
}
}
BlobRect2 {
BlobRect {
id: rect
anchors.right: parent.right
@@ -142,9 +141,8 @@ Item {
}
]
SnapLayout {
ColumnLayout {
id: layout
orientation: Qt.Vertical
anchors.centerIn: parent
spacing: Tokens.spacing.extraSmall
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import ZShell.Config
import ZShell.Internal
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import Quickshell.Widgets
import ZShell.Config
@@ -39,7 +38,7 @@ CustomListView {
id: rowHover
}
SnapLayout {
RowLayout {
id: rowLayout
anchors.left: parent.left
+4 -6
View File
@@ -23,7 +23,7 @@ Item {
service: Memory
}
SnapLayout {
RowLayout {
id: layout
anchors.fill: parent
spacing: Tokens.spacing.medium
@@ -60,14 +60,13 @@ Item {
Layout.fillHeight: true
implicitHeight: mainLayout.implicitHeight + mainLayout.anchors.margins * 2
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: mainLayout
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: 0
SnapLayout {
RowLayout {
spacing: Tokens.spacing.small
MaterialIcon {
@@ -132,8 +131,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: infoColumn
anchors.right: parent.right
anchors.bottom: parent.bottom
+32 -57
View File
@@ -4,8 +4,6 @@ import QtQuick
import QtQuick.Layouts
import QtQuick.Templates
import Quickshell
import ZShell
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
@@ -18,17 +16,9 @@ Item {
required property var tabs
readonly property alias count: bar.count
readonly property int tabIndicatorSpacing: ZUtils.snap(Tokens.spacing.small, root)
readonly property int tabIndicatorSpacing: Tokens.spacing.small
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)
implicitHeight: bar.implicitHeight + bar.anchors.topMargin + indicator.implicitHeight + indicator.anchors.topMargin + separator.implicitHeight
TabBar {
id: bar
@@ -41,11 +31,9 @@ Item {
currentIndex: root.screenState.dashboardTab
onCurrentIndexChanged: root.screenState.dashboardTab = currentIndex
topPadding: 0
bottomPadding: 0
implicitHeight: implicitContentHeight
implicitHeight: contentHeight
background: null
contentItem: SnapLayout {
contentItem: RowLayout {
spacing: 0
Repeater {
@@ -128,13 +116,10 @@ Item {
readonly property bool current: TabBar.tabBar.currentItem === this
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: 1
Layout.preferredWidth: 1 // Uniform width across all tabs
implicitWidth: implicitContentWidth
implicitHeight: implicitContentHeight
background: null
topPadding: 0
bottomPadding: 0
contentItem: CustomMouseArea {
id: mouse
@@ -146,8 +131,8 @@ Item {
root.screenState.dashboardTab = Math.max(root.screenState.dashboardTab - 1, 0);
}
implicitWidth: Math.max(icon.implicitWidth, label.implicitWidth)
implicitHeight: snapLayout.implicitHeight
implicitWidth: Math.max(icon.width, label.width)
implicitHeight: icon.height + label.height
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
@@ -161,49 +146,39 @@ Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.alignWhenCentered: false
implicitHeight: ZUtils.snap(parent.height + Tokens.sizes.dashboard.tabIndicatorSpacing * 2, stateLayer)
implicitHeight: parent.height + root.tabIndicatorSpacing * 2
radius: Tokens.rounding.medium
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurface
onClicked: {
root.screenState.dashboardTab = tab.TabBar.index;
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
}
}
}
SnapLayout {
id: snapLayout
anchors.fill: parent
spacing: 0
orientation: Qt.Vertical
CustomText {
id: label
MaterialIcon {
id: icon
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
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
}
text: tab.text
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
}
}
}
+6 -12
View File
@@ -1,13 +1,11 @@
import QtQuick
import QtQuick.Layouts
import ZShell
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
import qs.Helpers
SnapLayout {
RowLayout {
id: root
spacing: Tokens.spacing.largeIncreased
@@ -22,7 +20,7 @@ SnapLayout {
readonly property real markerX: {
const d = root.now;
return ZUtils.snap(d.getHours() + d.getMinutes() / 60, root);
return d.getHours() + d.getMinutes() / 60;
}
function formatHour(h) {
@@ -41,13 +39,11 @@ SnapLayout {
onTriggered: root.now = new Date()
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: root.width / 2
SnapLayout {
RowLayout {
Layout.fillWidth: true
MaterialIcon {
@@ -94,13 +90,11 @@ orientation: Qt.Vertical
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: root.width / 2
SnapLayout {
RowLayout {
Layout.fillWidth: true
MaterialIcon {
+7 -14
View File
@@ -3,7 +3,6 @@ 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
@@ -19,14 +18,13 @@ Item {
implicitHeight: layout.implicitHeight
Component.onCompleted: Weather.reload()
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: layout
anchors.fill: parent
spacing: Tokens.spacing.medium
SnapLayout {
RowLayout {
Layout.leftMargin: Tokens.padding.large
Layout.rightMargin: Tokens.padding.large
Layout.fillWidth: true
@@ -84,7 +82,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.medium
@@ -123,9 +121,7 @@ orientation: Qt.Vertical
color: Colors.palette.m3onSurface
}
SnapLayout {
id: forecastLayout
RowLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.medium
@@ -141,14 +137,12 @@ orientation: Qt.Vertical
required property var modelData
Layout.fillWidth: true
Layout.fillHeight: true
implicitHeight: forecastItemColumn.implicitHeight + Tokens.padding.medium * 2
radius: root.radius
color: Colors.tPalette.m3surfaceContainer
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: forecastItemColumn
anchors.centerIn: parent
@@ -202,8 +196,7 @@ orientation: Qt.Vertical
property color colour
Layout.fillWidth: true
Layout.fillHeight: true
implicitHeight: 60
Layout.preferredHeight: 60
radius: Tokens.rounding.medium
color: Colors.tPalette.m3surfaceContainer
@@ -237,7 +230,7 @@ orientation: Qt.Vertical
}
}
component WeatherStat: SnapLayout {
component WeatherStat: RowLayout {
id: weatherStat
property string icon
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import Quickshell.Widgets
import Quickshell.Hyprland
@@ -44,8 +43,7 @@ Item {
}
opacity: root.visible ? 1 : 0
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: menuLayout
anchors.centerIn: parent
spacing: 0
@@ -55,7 +53,7 @@ orientation: Qt.Vertical
radius: popupBackground.radius - popupBackground.padding
implicitHeight: openTerminalRow.implicitHeight + Tokens.padding.extraSmall * 2
SnapLayout {
RowLayout {
id: openTerminalRow
spacing: 8
anchors.fill: parent
@@ -94,7 +92,7 @@ orientation: Qt.Vertical
radius: popupBackground.radius - popupBackground.padding
implicitHeight: settingsRow.implicitHeight + Tokens.padding.extraSmall * 2
SnapLayout {
RowLayout {
id: settingsRow
spacing: 8
anchors.fill: parent
@@ -134,7 +132,7 @@ orientation: Qt.Vertical
radius: popupBackground.radius - popupBackground.padding
implicitHeight: logoutRow.implicitHeight + Tokens.padding.extraSmall * 2
SnapLayout {
RowLayout {
id: logoutRow
spacing: 8
anchors.fill: parent
@@ -173,7 +171,7 @@ orientation: Qt.Vertical
// radius: popupBackground.radius - popupBackground.padding
// implicitHeight: desktopIconsRow.implicitHeight + Tokens.padding.extraSmall * 2
//
// SnapLayout {
// RowLayout {
// id: desktopIconsRow
// spacing: 8
// anchors.fill: parent
@@ -3,7 +3,6 @@ import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import qs.Components
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -58,25 +57,22 @@ Item {
Anim {}
}
SnapLayout {
ColumnLayout {
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
SnapLayout {
RowLayout {
id: openRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -115,12 +111,11 @@ Item {
implicitHeight: openWithRow.implicitHeight + Tokens.padding.extraSmall * 2
radius: popupBackground.radius - popupBackground.padding
SnapLayout {
RowLayout {
id: openWithRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -161,12 +156,11 @@ Item {
implicitHeight: copyPathRow.implicitHeight + Tokens.padding.extraSmall * 2
radius: popupBackground.radius - popupBackground.padding
SnapLayout {
RowLayout {
id: copyPathRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -196,12 +190,11 @@ Item {
radius: popupBackground.radius - popupBackground.padding
visible: contextMenu.targetPaths.length === 1
SnapLayout {
RowLayout {
id: renameRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -238,12 +231,11 @@ Item {
implicitHeight: deleteRow.implicitHeight + Tokens.padding.extraSmall * 2
radius: popupBackground.radius - popupBackground.padding
SnapLayout {
RowLayout {
id: deleteRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
+2 -7
View File
@@ -4,7 +4,6 @@ import Quickshell
import Quickshell.Widgets
import qs.Components
import qs.Helpers
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -30,10 +29,7 @@ CustomRect {
active: !isSeparator
anchors.centerIn: parent
sourceComponent: SnapLayout {
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
IconImage {
id: icon
@@ -42,9 +38,8 @@ CustomRect {
source: Quickshell.iconPath(AppSearch.guessIcon(appToplevel?.appId), "image-missing")
}
SnapLayout {
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 3
Repeater {
-1
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import ZShell.Config
import qs.Services
+1 -3
View File
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import ZShell
import ZShell.Config
import qs.Components
import qs.Services
@@ -53,7 +52,7 @@ CustomListView {
highlightFollowsCurrentItem: false
highlightRangeMode: ListView.ApplyRange
implicitHeight: (Tokens.sizes.launcher.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing
implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing
orientation: Qt.Vertical
preferredHighlightBegin: 0
preferredHighlightEnd: height
@@ -98,7 +97,6 @@ CustomListView {
}
}
highlight: CustomRect {
id: hl
color: Colors.palette.m3onSurface
implicitHeight: root.currentItem?.implicitHeight ?? 0
implicitWidth: root.width
+3 -2
View File
@@ -22,7 +22,7 @@ CarouselView {
delegateProperties: ({
screenState: root.screenState
})
focalWidth: Tokens.sizes.launcher.wallpaperWidth
focalWidth: Config.launcher.sizes.wallpaperWidth
glideDuration: 250
glideEasingType: Easing.OutCubic
implicitHeight: tileHeight + Tokens.spacing.small / 2 + Tokens.padding.large + Tokens.padding.small
@@ -41,7 +41,8 @@ CarouselView {
tileHeight: focalWidth / 16 * 9
delegate: Component {
WallpaperTile {}
WallpaperTile {
}
}
Component.onDestruction: Wallpapers.stopPreview()
+2 -3
View File
@@ -2,18 +2,17 @@ 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: ZUtils.snap(Tokens.padding.medium / 2, root)
readonly property int padding: Tokens.padding.largeIncreased / 4
required property var panels
readonly property int rounding: Tokens.rounding.largeIncreased
required property ScreenState screenState
+4 -5
View File
@@ -2,12 +2,11 @@ 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 {
@@ -72,7 +71,7 @@ Item {
PropertyChanges {
appList.active: true
root.implicitHeight: Math.min(root.maxHeight, appList.implicitHeight > 0 ? appList.implicitHeight : empty.implicitHeight)
root.implicitWidth: Tokens.sizes.launcher.itemWidth
root.implicitWidth: Config.launcher.sizes.itemWidth
}
AnchorChanges {
@@ -84,8 +83,8 @@ Item {
name: "wallpapers"
PropertyChanges {
root.implicitHeight: Tokens.sizes.launcher.wallpaperHeight
root.implicitWidth: Math.max(Tokens.sizes.launcher.itemWidth * 1.2, wallpaperList.implicitWidth)
root.implicitHeight: Config.launcher.sizes.wallpaperHeight
root.implicitWidth: Math.max(Config.launcher.sizes.itemWidth * 1.2, wallpaperList.implicitWidth)
wallpaperList.active: true
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ Item {
anchors.left: parent?.left
anchors.right: parent?.right
implicitHeight: Tokens.sizes.launcher.itemHeight
implicitHeight: Config.launcher.sizes.itemHeight
StateLayer {
radius: Tokens.rounding.medium
+18 -42
View File
@@ -1,13 +1,10 @@
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
@@ -19,72 +16,53 @@ Item {
anchors.left: parent?.left
anchors.right: parent?.right
implicitHeight: ZUtils.snap(Tokens.sizes.launcher.itemHeight, root)
implicitHeight: Config.launcher.sizes.itemHeight
StateLayer {
radius: Tokens.rounding.medium
onClicked: {
// 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");
Apps.launch(root.modelData);
root.screenState.launcher = false;
}
}
SnapLayout {
id: mainLayout
Item {
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
implicitSize: parent.height - Tokens.padding.small * 2
anchors.verticalCenter: parent.verticalCenter
implicitSize: parent.height
source: Quickshell.iconPath(root.modelData?.icon, "image-missing")
}
SnapLayout {
id: text
Layout.fillHeight: true
Layout.fillWidth: true
Layout.topMargin: Tokens.padding.extraSmall
Layout.bottomMargin: Tokens.padding.extraSmall
orientation: Qt.Vertical
spacing: 0
Item {
anchors.left: icon.right
anchors.leftMargin: Tokens.spacing.medium
anchors.verticalCenter: icon.verticalCenter
implicitHeight: name.implicitHeight + comment.implicitHeight
implicitWidth: parent.width - icon.width
CustomText {
id: name
Layout.fillHeight: true
Layout.fillWidth: true
text: root.modelData?.name ?? ""
verticalAlignment: CustomText.AlignVCenter
horizontalAlignment: CustomText.AlignLeft
}
CustomText {
id: comment
Layout.fillHeight: true
Layout.fillWidth: true
anchors.top: name.bottom
color: Colors.palette.m3outline
elide: Text.ElideRight
font: Tokens.font.body.small
text: (root.modelData?.comment || root.modelData?.genericName || root.modelData?.name) ?? ""
verticalAlignment: CustomText.AlignVCenter
horizontalAlignment: CustomText.AlignLeft
width: root.width - icon.width - Tokens.rounding.medium - Tokens.padding.medium * 2
}
}
@@ -92,16 +70,14 @@ Item {
id: favoriteIcon
active: root.modelData && Strings.testRegexList(Config.launcher.favoriteApps, root.modelData.id)
Layout.fillHeight: true
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
asynchronous: true
sourceComponent: MaterialIcon {
color: Colors.palette.m3primary
fill: 1
text: "favorite"
verticalAlignment: MaterialIcon.AlignVCenter
}
}
}
+1 -2
View File
@@ -2,7 +2,6 @@ import ZShell
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import qs.Modules
import qs.Helpers
@@ -32,7 +31,7 @@ Item {
}
}
SnapLayout {
RowLayout {
anchors.left: parent.left
anchors.margins: Tokens.padding.small
anchors.right: parent.right
+8 -60
View File
@@ -1,5 +1,3 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import ZShell.Config
@@ -11,7 +9,7 @@ Item {
id: root
required property bool isCurrent
required property var modelData
required property var modelData // FileSystemEntry-like {path, relativePath}
required property real tileHeight
required property real tileWidth
required property ScreenState screenState
@@ -31,75 +29,25 @@ Item {
radius: Tokens.rounding.small
y: Tokens.padding.large
Loader {
active: opacity > 0
MaterialIcon {
anchors.centerIn: parent
opacity: img.status === Image.Ready ? 0 : 1
Behavior on opacity {
Anim {}
}
sourceComponent: CustomRect {
color: Colors.palette.m3primaryContainer
implicitHeight: loadingIndicator.implicitSize + Tokens.padding.large * 2
implicitWidth: loadingIndicator.implicitSize + Tokens.padding.large * 2
radius: Tokens.rounding.full
LoadingIndicator {
id: loadingIndicator
anchors.centerIn: parent
containsIcon: true
implicitSize: Math.min(image.width, image.height) * 0.3
}
}
color: Colors.tPalette.m3outline
fontStyle: Tokens.font.icon.builders.extraLarge.scale(2).weight(Font.DemiBold).build()
text: "image"
}
Image {
id: img
CachingImage {
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
asynchronous: true
cache: true
fillMode: Image.PreserveAspectCrop
height: root.tileHeight
source: root.modelData ? root.modelData.thumbnailPath : ""
path: root.modelData ? root.modelData.path : ""
smooth: root.isCurrent
sourceSize.height: root.tileHeight
sourceSize.width: root.tileHeight * (16 / 9)
width: root.tileHeight * (16 / 9)
opacity: status === Image.Ready ? 1 : 0
Behavior on opacity {
Anim {
type: Anim.SlowEffects
}
}
Loader {
opacity: root.modelData.isVideo && img.status === Image.Ready ? 1 : 0
active: opacity > 0
anchors.centerIn: parent
Behavior on opacity {
Anim {
type: Anim.SlowEffects
}
}
sourceComponent: CustomRect {
implicitWidth: videoIcon.implicitWidth + Tokens.padding.extraLarge * 2
implicitHeight: implicitWidth
radius: Tokens.rounding.full
color: Colors.tPalette.m3surface
MaterialIcon {
id: videoIcon
anchors.centerIn: parent
text: "video_library"
fontStyle: Tokens.font.icon.extraLarge
}
}
}
}
StateLayer {
+4 -9
View File
@@ -2,15 +2,14 @@ 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
SnapLayout {
ColumnLayout {
id: root
readonly property real centerScale: Math.min(1, (lock.screen?.height ?? 1440) / 1440)
@@ -20,13 +19,10 @@ SnapLayout {
Layout.fillHeight: true
Layout.fillWidth: false
Layout.preferredWidth: centerWidth
orientation: Qt.Vertical
spacing: Tokens.spacing.largeIncreased * 2
SnapLayout {
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Tokens.spacing.small
CustomText {
@@ -113,12 +109,11 @@ SnapLayout {
}
}
SnapLayout {
RowLayout {
id: input
anchors.fill: parent
anchors.margins: Tokens.padding.extraSmall
spacing: Tokens.spacing.medium
Item {
+20 -11
View File
@@ -1,31 +1,28 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Helpers
import ZShell.Config
import qs.Services
Item {
ClipRect {
id: root
required property var lock
implicitHeight: layout.implicitHeight
implicitWidth: layout.implicitWidth
radius: Tokens.rounding.largeIncreased
SnapLayout {
RowLayout {
id: layout
anchors.fill: parent
spacing: Tokens.spacing.largeIncreased * 2
SnapLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.medium
orientation: Qt.Vertical
WeatherInfo {
id: weather
@@ -53,10 +50,22 @@ Item {
lock: root.lock
}
NotifDock {
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
lock: root.lock
spacing: Tokens.spacing.medium
CustomRect {
Layout.fillHeight: true
Layout.fillWidth: true
bottomRightRadius: Tokens.rounding.largeIncreased
color: Colors.tPalette.m3surfaceContainer
radius: Tokens.rounding.small
topRightRadius: Tokens.rounding.largeIncreased
NotifDock {
lock: root.lock
}
}
}
}
}
-1
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Modules
import qs.Components
import qs.Helpers
+1 -1
View File
@@ -221,9 +221,9 @@ WlSessionLockSurface {
anchors.fill: parent
color: Colors.palette.m3surface
layer.enabled: true
opacity: Colors.transparency.enabled ? Colors.transparency.base : 1
radius: lockContent.radius
layer.enabled: true
layer.effect: MultiEffect {
blurMax: 15
+27 -34
View File
@@ -7,57 +7,50 @@ import qs.Components
import qs.Helpers
import qs.Services
Item {
ClipRect {
id: root
required property var lock
color: Colors.tPalette.m3surfaceContainer
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
radius: Tokens.rounding.small
FadeImage {
id: image
ClipRect {
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
layer.enabled: true
opacity: status === Image.Ready ? 1 : 0
source: Players.getArtUrl(Players.active)
sourceSize: {
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
return Qt.size(width * dpr, height * dpr);
}
color: Colors.tPalette.m3surfaceContainer
radius: Tokens.rounding.small
bottomLeftRadius: Tokens.rounding.largeIncreased
FadeImage {
id: image
Behavior on opacity {
Anim {
type: Anim.StandardExtraLarge
}
}
CustomRect {
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
opacity: status === Image.Ready ? 1 : 0
source: Players.getArtUrl(Players.active)
sourceSize: {
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
return Qt.size(width * dpr, height * dpr);
}
Behavior on opacity {
Anim {
type: Anim.StandardExtraLarge
}
}
CustomRect {
anchors.fill: parent
color: Colors.palette.m3surface
opacity: 0.7
}
color: Colors.palette.m3surface
opacity: 0.7
}
}
SnapLayout {
ColumnLayout {
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
@@ -84,7 +77,7 @@ Item {
spacing: Tokens.spacing.extraSmall
IconButton {
enabled: Players.active?.canGoPrevious ?? false
enabled: Players.active?.canGoPrevious
icon: "skip_previous"
isRound: true
shapeMorph: true
@@ -95,7 +88,7 @@ Item {
IconButton {
checked: Players.active?.isPlaying ?? false
enabled: Players.active?.canTogglePlaying ?? false
enabled: Players.active?.canTogglePlaying
icon: Players.active?.isPlaying ? "pause" : "play_arrow"
implicitWidth: implicitHeight + Tokens.padding.largeIncreased * 2
isRound: true
@@ -105,7 +98,7 @@ Item {
}
IconButton {
enabled: Players.active?.canGoNext ?? false
enabled: Players.active?.canGoNext
icon: "skip_next"
isRound: true
shapeMorph: true
+95 -83
View File
@@ -4,121 +4,133 @@ 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
CustomRect {
ColumnLayout {
id: root
required property var lock
bottomRightRadius: Tokens.rounding.largeIncreased
color: Colors.tPalette.m3surfaceContainer
radius: Tokens.rounding.small
topRightRadius: Tokens.rounding.largeIncreased
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.small
SnapLayout {
anchors.fill: parent
anchors.margins: Tokens.padding.large
CustomText {
Layout.fillWidth: true
color: Colors.palette.m3outline
elide: Text.ElideRight
font: Tokens.font.mono.builders.small.weight(Font.Medium).build()
text: NotifServer.list.length > 0 ? qsTr("%1 notification%2").arg(NotifServer.list.length).arg(NotifServer.list.length === 1 ? "" : "s") : qsTr("Notifications")
}
orientation: Qt.Vertical
spacing: Tokens.spacing.small
ClipRect {
id: clipRect
CustomText {
Layout.fillWidth: true
color: Colors.palette.m3outline
elide: Text.ElideRight
font: Tokens.font.mono.builders.small.weight(Font.Medium).build()
text: NotifServer.list.length > 0 ? qsTr("%1 notification%2").arg(NotifServer.list.length).arg(NotifServer.list.length === 1 ? "" : "s") : qsTr("Notifications")
}
Layout.fillHeight: true
Layout.fillWidth: true
color: "transparent"
radius: Tokens.rounding.small
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Loader {
active: opacity > 0
anchors.centerIn: parent
opacity: NotifServer.list.length > 0 ? 0 : 1
Loader {
active: opacity > 0
anchors.centerIn: parent
opacity: NotifServer.list.length > 0 ? 0 : 1
Behavior on opacity {
Anim {
duration: Tokens.anim.durations.extraLarge
}
}
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.largeIncreased
Behavior on opacity {
Anim {
duration: Tokens.anim.durations.extraLarge
Image {
asynchronous: true
fillMode: Image.PreserveAspectFit
layer.enabled: true
source: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/dino.png`)
sourceSize.width: clipRect.width * 0.8
layer.effect: Coloriser {
brightness: 1
colorizationColor: Colors.palette.m3outlineVariant
}
}
sourceComponent: CustomText {
CustomText {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3outlineVariant
font: Tokens.font.headline.builders.small.width(90).build()
text: qsTr("No Notifications")
}
}
}
CustomListView {
anchors.fill: parent
clip: true
spacing: Tokens.spacing.small
CustomListView {
anchors.fill: parent
clip: true
spacing: Tokens.spacing.small
add: Transition {
Anim {
from: 0
property: "opacity"
to: 1
}
Anim {
duration: Tokens.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial
from: 0
property: "scale"
to: 1
}
add: Transition {
Anim {
from: 0
property: "opacity"
to: 1
}
delegate: NotifGroup {}
displaced: Transition {
Anim {
properties: "opacity,scale"
to: 1
}
Anim {
duration: Tokens.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial
property: "y"
}
Anim {
duration: Tokens.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial
from: 0
property: "scale"
to: 1
}
model: ScriptModel {
values: {
const list = NotifServer.notClosed.map(n => [n.appName, null]);
return [...new Map(list).keys()];
}
}
delegate: NotifGroup {}
displaced: Transition {
Anim {
properties: "opacity,scale"
to: 1
}
move: Transition {
Anim {
properties: "opacity,scale"
to: 1
}
Anim {
duration: Tokens.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial
property: "y"
}
Anim {
duration: Tokens.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial
property: "y"
}
}
model: ScriptModel {
values: {
const list = NotifServer.notClosed.map(n => [n.appName, null]);
return [...new Map(list).keys()];
}
}
move: Transition {
Anim {
properties: "opacity,scale"
to: 1
}
remove: Transition {
Anim {
property: "opacity"
to: 0
}
Anim {
property: "scale"
to: 0.6
}
Anim {
duration: Tokens.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial
property: "y"
}
}
remove: Transition {
Anim {
property: "opacity"
to: 0
}
Anim {
property: "scale"
to: 0.6
}
}
}
+6 -15
View File
@@ -5,11 +5,10 @@ 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
@@ -37,14 +36,13 @@ CustomRect {
}
}
SnapLayout {
RowLayout {
id: content
anchors.left: parent.left
anchors.margins: Tokens.padding.small
anchors.right: parent.right
anchors.top: parent.top
spacing: Tokens.spacing.medium
Item {
@@ -120,18 +118,15 @@ CustomRect {
}
}
SnapLayout {
ColumnLayout {
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)
orientation: Qt.Vertical
SnapLayout {
RowLayout {
Layout.bottomMargin: -parent.spacing
Layout.fillWidth: true
spacing: Tokens.spacing.small
CustomText {
@@ -172,11 +167,10 @@ CustomRect {
}
}
SnapLayout {
RowLayout {
id: expandBtn
anchors.centerIn: parent
spacing: Tokens.spacing.small / 2
CustomText {
@@ -267,10 +261,7 @@ CustomRect {
Behavior on opacity {
Anim {}
}
sourceComponent: SnapLayout {
orientation: Qt.Vertical
spacing: Tokens.spacing.extraSmall
sourceComponent: ColumnLayout {
Repeater {
model: ScriptModel {
values: root.notifs.slice(Config.notifs.groupPreviewNum)
+1 -3
View File
@@ -5,7 +5,6 @@ import QtQuick.Layouts
import M3Shapes
import ZShell.Services
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Effects
import qs.Services
@@ -34,12 +33,11 @@ CustomRect {
service: Storage
}
SnapLayout {
RowLayout {
id: layout
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.largeIncreased
Resource {
+5 -8
View File
@@ -1,13 +1,11 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import ZShell.Config
import qs.Helpers
import qs.Services
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: root
required property int rootHeight
@@ -18,11 +16,11 @@ orientation: Qt.Vertical
Layout.alignment: Qt.AlignHCenter
animate: true
color: Colors.palette.m3onSurfaceVariant
font: Tokens.font.body.large
font: Tokens.font.title.large
text: Weather.description
}
SnapLayout {
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Tokens.spacing.small
@@ -31,7 +29,7 @@ orientation: Qt.Vertical
animate: true
color: Colors.palette.m3primary
font: Tokens.font.title.large
font: Tokens.font.body.large
text: Weather.temp
}
@@ -39,7 +37,6 @@ orientation: Qt.Vertical
animate: true
color: Colors.palette.m3secondary
text: Weather.icon
fontStyle: Tokens.font.icon.large
}
}
@@ -56,7 +53,7 @@ orientation: Qt.Vertical
Layout.alignment: Qt.AlignHCenter
animate: true
color: Colors.palette.m3onSurfaceVariant
font: Tokens.font.body.medium
font: Tokens.font.body.normal
text: {
const today = Weather.forecast[0];
return qsTr("High %1 • Low %2").arg(Weather.formatTemp(today?.maxTempC)).arg(Weather.formatTemp(today?.minTempC));
+7 -16
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import M3Shapes
import ZShell
import qs.Components
@@ -15,7 +14,7 @@ CustomRect {
implicitHeight: header.anchors.margins + header.implicitHeight + Tokens.spacing.small + layout.implicitHeight + layout.anchors.bottomMargin
radius: Tokens.rounding.small
SnapLayout {
RowLayout {
id: header
anchors.left: parent.left
@@ -37,7 +36,7 @@ CustomRect {
}
}
CustomListView {
VerticalFadeListView {
id: layout
anchors.bottom: parent.bottom
@@ -46,21 +45,13 @@ CustomRect {
anchors.margins: Tokens.padding.large
anchors.right: parent.right
implicitHeight: contentItem.childrenRect.height
currentIndex: Weather.currentHourIndex
// highlightFollowsCurrentItem: true
// preferredHighlightEnd: currentItem.implicitWidth
// preferredHighlightBegin: 0
// highlightRangeMode: ListView.ApplyRange
clip: true
model: Weather.hourlyForecast.slice(Weather.currentHourIndex - 1)
model: Weather.hourlyForecast
orientation: VerticalFadeListView.Horizontal
spacing: Tokens.spacing.medium
delegate: SnapLayout {
orientation: Qt.Vertical
delegate: ColumnLayout {
id: hour
readonly property bool current: ListView.view.currentItem === this
readonly property var cond: modelData
required property int index
required property var modelData
@@ -69,7 +60,7 @@ orientation: Qt.Vertical
MaterialShape {
Layout.alignment: Qt.AlignHCenter
color: Qt.alpha(Colors.palette.m3primary, hour.current ? 1 : 0)
color: Qt.alpha(Colors.palette.m3primary, hour.index === Weather.currentHourIndex ? 1 : 0)
implicitSize: temp.implicitHeight + Tokens.padding.small * 2
shape: MaterialShape.Cookie4Sided
@@ -81,7 +72,7 @@ orientation: Qt.Vertical
id: temp
anchors.centerIn: parent
color: hour.current ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
color: hour.index === Weather.currentHourIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
font: Tokens.font.body.medium
text: Weather.formatTemp(hour.cond.tempC).slice(0, -1) // Remove C/F
}
@@ -105,7 +96,7 @@ orientation: Qt.Vertical
Layout.topMargin: Tokens.spacing.extraSmall
color: Colors.palette.m3onSurfaceVariant
font: Tokens.font.body.small
text: hour.current ? qsTr("Now") : Qt.formatDateTime(new Date(hour.cond.timestamp.replace("T", " ")), Config.services.useTwelveHourClock ? "ha" : "hh:00")
text: hour.index === 0 ? qsTr("Now") : Qt.formatDateTime(new Date(hour.cond.timestamp.replace("T", " ")), Config.services.useTwelveHourClock ? "ha" : "hh:00")
}
}
}
+2 -2
View File
@@ -19,7 +19,6 @@ CustomRect {
return base + brief.anchors.topMargin;
}
radius: Tokens.rounding.small
topLeftRadius: Tokens.rounding.largeIncreased
Timer {
interval: 900000 // 15 minutes
@@ -49,6 +48,7 @@ CustomRect {
anchors.right: parent.right
asynchronous: true
sourceComponent: Forecast {}
sourceComponent: Forecast {
}
}
}
+13 -17
View File
@@ -2,11 +2,9 @@ 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
@@ -21,17 +19,14 @@ Item {
required property ScreenState screenState
required property real volume
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
implicitWidth: layout.implicitWidth + layout.anchors.margins * 2
implicitHeight: layout.implicitHeight + Tokens.padding.smaller * 2
implicitWidth: layout.implicitWidth + Tokens.padding.smaller * 2
SnapLayout {
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: Tokens.padding.extraSmall
anchors.centerIn: parent
spacing: Tokens.spacing.medium
orientation: Qt.Vertical
// Speaker volume
CustomMouseArea {
@@ -42,8 +37,8 @@ Item {
Audio.decrementVolume();
}
implicitHeight: ZUtils.snap(Config.osd.sizes.sliderHeight, root)
implicitWidth: ZUtils.snap(Config.osd.sizes.sliderWidth, root)
implicitHeight: Config.osd.sizes.sliderHeight
implicitWidth: Config.osd.sizes.sliderWidth
FilledSlider {
anchors.fill: parent
@@ -68,8 +63,8 @@ Item {
Audio.decrementSourceVolume();
}
implicitHeight: ZUtils.snap(Config.osd.sizes.sliderHeight, root)
implicitWidth: ZUtils.snap(Config.osd.sizes.sliderWidth, root)
implicitHeight: Config.osd.sizes.sliderHeight
implicitWidth: Config.osd.sizes.sliderWidth
FilledSlider {
anchors.fill: parent
@@ -98,8 +93,8 @@ Item {
monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement);
}
implicitHeight: ZUtils.snap(Config.osd.sizes.sliderHeight, root)
implicitWidth: ZUtils.snap(Config.osd.sizes.sliderWidth, root)
implicitHeight: Config.osd.sizes.sliderHeight
implicitWidth: Config.osd.sizes.sliderWidth
FilledSlider {
anchors.fill: parent
@@ -136,7 +131,8 @@ Item {
}
}
Behavior on opacity {
Anim {}
Anim {
}
}
}
}
+5 -5
View File
@@ -2,10 +2,9 @@ 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 {
@@ -31,8 +30,8 @@ Item {
}
anchors.rightMargin: (-implicitWidth - 5 - sidebarOffset) * offsetScale
implicitHeight: ZUtils.snap(content.implicitHeight, root)
implicitWidth: ZUtils.snap(content.implicitWidth, root)
implicitHeight: content.implicitHeight
implicitWidth: content.implicitWidth
opacity: 1 - offsetScale
visible: offsetScale < 1
@@ -99,7 +98,8 @@ Item {
id: content
active: root.shouldBeActive || root.visible
anchors.fill: parent
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
sourceComponent: Content {
brightness: root.brightness
+5 -14
View File
@@ -83,16 +83,13 @@ Scope {
opacity: 0
radius: Tokens.rounding.small * 2
SnapLayout {
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: Tokens.padding.medium
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
SnapLayout {
RowLayout {
id: contentRow
spacing: 24
@@ -123,15 +120,12 @@ Scope {
}
}
SnapLayout {
ColumnLayout {
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)
@@ -216,15 +210,13 @@ Scope {
}
}
SnapLayout {
ColumnLayout {
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}`
@@ -238,9 +230,8 @@ Scope {
}
}
SnapLayout {
RowLayout {
Layout.preferredWidth: contentRow.implicitWidth
spacing: 8
IconButton {
+2 -4
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell.Services.UPower
import ZShell.Config
import qs.Components
@@ -51,8 +50,7 @@ ClipRect {
}
}
component Contents: SnapLayout {
orientation: Qt.Vertical
component Contents: ColumnLayout {
id: contents
required property color accentColor
@@ -102,7 +100,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
Layout.alignment: Qt.AlignRight
Layout.bottomMargin: -Tokens.padding.extraSmall
Layout.rightMargin: -Tokens.padding.extraSmall
+11 -19
View File
@@ -1,7 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
@@ -17,8 +15,8 @@ CustomRect {
required property real usage
color: Colors.tPalette.m3surfaceContainer
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)
implicitHeight: Math.max(tempProg.implicitHeight + detailsRow.implicitHeight + Tokens.spacing.largeIncreased, usageColumn.implicitHeight + usageLabel.implicitHeight) + Tokens.padding.large * 2
implicitWidth: 450
radius: Tokens.rounding.largeIncreased
ClipRect {
@@ -45,7 +43,7 @@ CustomRect {
anchors.margins: Tokens.padding.large
anchors.top: parent.top
fgColor: root.accent
implicitSize: ZUtils.snap(Math.max(icon.implicitWidth, icon.implicitHeight) + Tokens.padding.small * 2, root)
implicitSize: Math.max(icon.implicitWidth, icon.implicitHeight) + Tokens.padding.small * 2
spacing: Tokens.spacing.extraSmall
strokeWidth: Tokens.padding.extraSmall
value: root.usage
@@ -64,14 +62,12 @@ CustomRect {
}
}
SnapLayout {
ColumnLayout {
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
@@ -86,17 +82,15 @@ CustomRect {
}
}
SnapLayout {
ColumnLayout {
id: detailsRow
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: Tokens.padding.largeIncreased
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
SnapLayout {
RowLayout {
Layout.leftMargin: -Tokens.padding.extraSmall
spacing: Tokens.spacing.extraSmall
@@ -114,34 +108,32 @@ CustomRect {
CustomProgressBar {
fgColor: root.accent
implicitHeight: Tokens.padding.small
implicitHeight: Tokens.padding.extraSmall
indeterminate: isNaN(root.usage) || isNaN(root.temperature)
value: root.temperature / 100
}
}
SnapLayout {
Column {
id: usageColumn
anchors.margins: Tokens.padding.large
anchors.right: parent.right
anchors.rightMargin: Tokens.padding.extraLarge
anchors.rightMargin: 32
anchors.verticalCenter: parent.verticalCenter
spacing: 0
orientation: Qt.Vertical
CustomText {
id: usageLabel
Layout.alignment: Qt.AlignRight
anchors.right: parent.right
color: Colors.palette.m3onSurfaceVariant
font: Tokens.font.body.medium
text: qsTr("Usage")
}
CustomText {
Layout.alignment: Qt.AlignRight
anchors.right: parent.right
color: root.accent
font: Tokens.font.headline.builders.small.width(50).build()
text: isNaN(root.usage) ? "...%" : Math.round(root.usage * 100) + "%"
+17 -24
View File
@@ -1,7 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell
import ZShell.Components
import ZShell.Services
import ZShell.Config
import qs.Components
@@ -12,39 +10,34 @@ 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
SnapLayout {
ServiceRef {
service: Memory
}
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
orientation: Qt.Vertical
anchors.centerIn: parent
spacing: Tokens.spacing.extraSmall
SnapLayout {
Layout.alignment: Qt.AlignHCenter
RowLayout {
Layout.leftMargin: -Tokens.padding.extraSmall
spacing: Tokens.spacing.small
MaterialIcon {
color: root.accent
fill: 1
text: root.icon
text: "memory_alt"
}
CustomText {
text: root.label
text: qsTr("Memory")
}
}
@@ -52,17 +45,17 @@ CustomRect {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Tokens.spacing.largeIncreased
fgColor: root.accent
implicitSize: ZUtils.snap(usageColumn.implicitHeight + thickness + Tokens.padding.largeIncreased * 2, root)
implicitSize: usageColumn.implicitHeight + thickness + Tokens.padding.largeIncreased * 2
startAngle: -225
sweepAngle: 270
value: root.perc
value: Memory.percentage
Behavior on clampedVal {
Anim {}
Anim {
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: usageColumn
anchors.centerIn: parent
@@ -73,7 +66,7 @@ orientation: Qt.Vertical
Layout.alignment: Qt.AlignHCenter
color: root.accent
font: Tokens.font.body.large
text: Math.round(root.perc * 100) + "%"
text: Math.round(Memory.percentage * 100) + "%"
}
CustomText {
@@ -87,7 +80,7 @@ orientation: Qt.Vertical
CustomText {
Layout.alignment: Qt.AlignHCenter
text: {
const fmt = UsageFmt.formatKib(root.used, root.total);
const fmt = UsageFmt.formatKib(Memory.used, Memory.total);
return `${fmt.value.toFixed(1)} / ${Math.floor(fmt.total)} ${fmt.unit}`;
}
}
+5 -16
View File
@@ -18,17 +18,15 @@ CustomRect {
service: NetworkUsage
}
SnapLayout {
ColumnLayout {
id: layout
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: 0
orientation: Qt.Vertical
SnapLayout {
RowLayout {
spacing: Tokens.spacing.small
MaterialIcon {
@@ -110,11 +108,8 @@ CustomRect {
}
// Download row
SnapLayout {
RowLayout {
Layout.fillWidth: true
Layout.maximumWidth: root.width > root.implicitWidth * 2 ? root.width / 2 : -1
Layout.alignment: Qt.AlignRight
spacing: Tokens.spacing.small
MaterialIcon {
@@ -141,11 +136,8 @@ CustomRect {
}
// Upload row
SnapLayout {
RowLayout {
Layout.fillWidth: true
Layout.maximumWidth: root.width > root.implicitWidth * 2 ? root.width / 2 : -1
Layout.alignment: Qt.AlignRight
spacing: Tokens.spacing.small
MaterialIcon {
@@ -172,11 +164,8 @@ CustomRect {
}
// Session totals
SnapLayout {
RowLayout {
Layout.fillWidth: true
Layout.maximumWidth: root.width > root.implicitWidth * 2 ? root.width / 2 : -1
Layout.alignment: Qt.AlignRight
spacing: Tokens.spacing.small
MaterialIcon {
+5 -12
View File
@@ -1,8 +1,6 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import ZShell
import ZShell.Components
import ZShell.Services
import ZShell.Config
import qs.Components
@@ -23,26 +21,23 @@ CustomRect {
service: Storage
}
SnapLayout {
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 0
orientation: Qt.Vertical
SnapLayout {
RowLayout {
id: row
Layout.alignment: Qt.AlignHCenter
spacing: Tokens.spacing.largeIncreased
CircularProgress {
fgColor: root.accent
implicitSize: ZUtils.snap(usageColumn.implicitHeight + thickness + Tokens.padding.large * 2, root)
implicitSize: usageColumn.implicitHeight + thickness + Tokens.padding.large * 2
startAngle: -225
sweepAngle: 270
value: root.percentage
@@ -51,8 +46,7 @@ CustomRect {
Anim {}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: usageColumn
anchors.centerIn: parent
@@ -80,9 +74,8 @@ orientation: Qt.Vertical
}
}
SnapLayout {
ColumnLayout {
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
CustomText {
text: qsTr("Storage")

Some files were not shown because too many files have changed in this diff Show More