45 Commits
Author SHA1 Message Date
zach 4f544981c1 delete unknown json objects + write missing objects to config file 2026-08-16 12:17:50 +02:00
zach 02bb7e43d8 Merge pull request 'Feat: Reposition bar' (#147) from feat/reposition-bar into main
Reviewed-on: #147
Reviewed-by: AramJonghu <aramjonghu@tutamail.com>
2026-08-16 11:02:22 +02:00
zach fb0c75a2ba remove debug logging
C++ / fmt (pull_request) Successful in 8s
JS/TS / fmt (pull_request) Successful in 11s
JS/TS / lint (pull_request) Successful in 15s
Python / fmt (pull_request) Successful in 24s
Python / lint (pull_request) Successful in 25s
Python / test (pull_request) Successful in 48s
Python / typecheck (pull_request) Successful in 1m1s
Rust / fmt (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 1m45s
C++ / build (pull_request) Successful in 4m18s
Python / buildcheck (pull_request) Successful in 2m20s
Rust / clippy (pull_request) Successful in 1m1s
C++ / clang-tidy (pull_request) Successful in 5m23s
2026-08-15 19:38:33 +02:00
zach 5efa0de3a5 WidgetBase for bar widget + fixed resources and dashboard popouts in left- and bottom-edge bar
C++ / fmt (pull_request) Successful in 3s
JS/TS / fmt (pull_request) Successful in 17s
JS/TS / lint (pull_request) Successful in 20s
Python / fmt (pull_request) Successful in 31s
Python / lint (pull_request) Successful in 30s
Python / test (pull_request) Successful in 1m40s
Python / typecheck (pull_request) Successful in 1m38s
C++ / build (pull_request) Successful in 2m15s
Rust / build (pull_request) Successful in 1m41s
Rust / fmt (pull_request) Successful in 59s
Python / buildcheck (pull_request) Successful in 2m40s
Rust / clippy (pull_request) Successful in 2m15s
C++ / clang-tidy (pull_request) Successful in 6m29s
2026-08-15 19:37:44 +02:00
zach 858ef68565 Merge branch 'main' into feat/reposition-bar
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 21s
JS/TS / lint (pull_request) Successful in 22s
Python / lint (pull_request) Successful in 31s
Python / fmt (pull_request) Successful in 34s
Python / test (pull_request) Successful in 59s
Python / typecheck (pull_request) Successful in 1m22s
Rust / fmt (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 1m46s
C++ / build (pull_request) Successful in 2m33s
Rust / clippy (pull_request) Successful in 1m5s
Python / buildcheck (pull_request) Successful in 2m29s
C++ / clang-tidy (pull_request) Successful in 3m56s
2026-08-15 18:04:14 +02:00
zach 5e97ea6867 Merge pull request 'CI: typecheck fixes include dependencies + arch Dockerfile build fix' (#148) from fix/cli-typecheck into main
Reviewed-on: #148
Reviewed-by: zach <zach@brohn.se>
2026-08-15 18:03:54 +02:00
zach 9823c66299 restructure bar components layout
C++ / fmt (pull_request) Successful in 4s
JS/TS / lint (pull_request) Successful in 19s
JS/TS / fmt (pull_request) Successful in 21s
Python / fmt (pull_request) Successful in 30s
Python / lint (pull_request) Successful in 31s
Python / test (pull_request) Successful in 1m2s
Python / typecheck (pull_request) Failing after 1m5s
Rust / fmt (pull_request) Successful in 43s
C++ / build (pull_request) Successful in 2m25s
Rust / build (pull_request) Successful in 1m42s
Python / buildcheck (pull_request) Successful in 2m27s
Rust / clippy (pull_request) Successful in 1m29s
C++ / clang-tidy (pull_request) Successful in 3m56s
2026-08-15 14:18:00 +02:00
zach 0092b41a05 fix config file writing + positioning issues
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 22s
JS/TS / lint (pull_request) Successful in 27s
Python / fmt (pull_request) Successful in 33s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 1m3s
Python / typecheck (pull_request) Failing after 1m4s
Rust / fmt (pull_request) Successful in 41s
Rust / build (pull_request) Successful in 1m39s
C++ / build (pull_request) Successful in 2m33s
Rust / clippy (pull_request) Successful in 1m18s
Python / buildcheck (pull_request) Successful in 2m23s
C++ / clang-tidy (pull_request) Successful in 3m56s
2026-08-14 22:15:11 +02:00
AramJonghu abf7382771 ci: libcava dev headers
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 12s
JS/TS / lint (pull_request) Successful in 16s
Python / lint (pull_request) Successful in 33s
Python / fmt (pull_request) Successful in 36s
Python / test (pull_request) Successful in 1m3s
Python / typecheck (pull_request) Successful in 1m21s
Rust / fmt (pull_request) Successful in 33s
C++ / build (pull_request) Successful in 2m26s
Rust / build (pull_request) Successful in 1m43s
Python / buildcheck (pull_request) Successful in 2m12s
Rust / clippy (pull_request) Successful in 1m41s
C++ / clang-tidy (pull_request) Successful in 4m10s
2026-08-14 20:00:27 +02:00
AramJonghu a1a8a6e695 ci: add relevant dependencies; resolves MissingImport
C++ / fmt (pull_request) Successful in 4s
JS/TS / lint (pull_request) Successful in 15s
JS/TS / fmt (pull_request) Successful in 21s
Python / fmt (pull_request) Successful in 31s
Python / lint (pull_request) Successful in 34s
Python / test (pull_request) Successful in 1m0s
Python / typecheck (pull_request) Successful in 1m20s
Rust / fmt (pull_request) Successful in 34s
C++ / build (pull_request) Successful in 2m29s
Rust / build (pull_request) Successful in 1m45s
Rust / clippy (pull_request) Successful in 1m2s
Python / buildcheck (pull_request) Successful in 2m18s
C++ / clang-tidy (pull_request) Successful in 3m52s
2026-08-14 19:40:28 +02:00
zach abef1eb259 Merge branch 'main' into feat/reposition-bar
C++ / fmt (pull_request) Successful in 4s
JS/TS / lint (pull_request) Successful in 16s
JS/TS / fmt (pull_request) Successful in 23s
Python / fmt (pull_request) Successful in 33s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 1m0s
Python / typecheck (pull_request) Failing after 1m8s
Rust / fmt (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 1m46s
C++ / build (pull_request) Successful in 2m33s
Rust / clippy (pull_request) Successful in 1m30s
Python / buildcheck (pull_request) Successful in 2m41s
C++ / clang-tidy (pull_request) Successful in 7m9s
2026-08-14 19:16:01 +02:00
zach 6c80862ce8 Merge pull request 'Rewrite shell configuration options as well as read/write functionality as plugin' (#143) from refactor/config-rw-plugin into main
Reviewed-on: #143
Reviewed-by: AramJonghu <aramjonghu@tutamail.com>
2026-08-14 18:54:32 +02:00
zach 97ecf68b46 add file+dir watcher & gatekeep reloads
C++ / fmt (pull_request) Successful in 5s
JS/TS / lint (pull_request) Successful in 21s
JS/TS / fmt (pull_request) Successful in 20s
Python / lint (pull_request) Successful in 32s
Python / fmt (pull_request) Successful in 34s
Python / test (pull_request) Successful in 58s
Python / typecheck (pull_request) Failing after 58s
Rust / fmt (pull_request) Successful in 43s
Rust / build (pull_request) Successful in 1m48s
C++ / build (pull_request) Successful in 2m36s
Rust / clippy (pull_request) Successful in 1m18s
Python / buildcheck (pull_request) Successful in 2m21s
C++ / clang-tidy (pull_request) Successful in 3m54s
2026-08-14 18:40:50 +02:00
zach ef8811724f better height/width for bar
C++ / fmt (pull_request) Successful in 3s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 19s
Python / lint (pull_request) Successful in 30s
Python / fmt (pull_request) Successful in 34s
Python / test (pull_request) Successful in 1m0s
Python / typecheck (pull_request) Failing after 1m18s
C++ / build (pull_request) Successful in 1m49s
Rust / fmt (pull_request) Successful in 33s
Rust / build (pull_request) Successful in 1m33s
Rust / clippy (pull_request) Successful in 1m17s
Python / buildcheck (pull_request) Successful in 2m40s
C++ / clang-tidy (pull_request) Successful in 3m25s
2026-08-14 18:03:56 +02:00
zach 4517e5ecd0 left-bar working, bottom bar semi-broken 2026-08-14 16:31:52 +02:00
zach bda2c3821e fix resources colors
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 18s
Python / fmt (pull_request) Successful in 33s
Python / lint (pull_request) Successful in 31s
Python / test (pull_request) Successful in 1m4s
Python / typecheck (pull_request) Failing after 1m14s
Rust / fmt (pull_request) Successful in 37s
Rust / build (pull_request) Successful in 1m47s
C++ / build (pull_request) Successful in 2m39s
Rust / clippy (pull_request) Successful in 1m10s
Python / buildcheck (pull_request) Successful in 2m27s
C++ / clang-tidy (pull_request) Successful in 3m55s
2026-08-13 21:43:28 +02:00
zach 6ec58cb73a remove debug statelayer
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 11s
JS/TS / lint (pull_request) Successful in 23s
Python / fmt (pull_request) Successful in 30s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 59s
Python / typecheck (pull_request) Failing after 1m0s
Rust / fmt (pull_request) Successful in 45s
C++ / build (pull_request) Successful in 2m31s
Rust / build (pull_request) Successful in 1m49s
Rust / clippy (pull_request) Successful in 1m17s
Python / buildcheck (pull_request) Successful in 2m25s
C++ / clang-tidy (pull_request) Successful in 3m56s
2026-08-13 21:26:48 +02:00
zach 501e866a68 fix font & greeter bin
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 26s
JS/TS / lint (pull_request) Successful in 29s
Python / lint (pull_request) Successful in 33s
Python / fmt (pull_request) Successful in 35s
Python / test (pull_request) Successful in 58s
Python / typecheck (pull_request) Failing after 1m8s
Rust / fmt (pull_request) Successful in 46s
C++ / build (pull_request) Successful in 2m22s
Rust / build (pull_request) Successful in 1m31s
Python / buildcheck (pull_request) Successful in 2m18s
Rust / clippy (pull_request) Successful in 1m26s
C++ / clang-tidy (pull_request) Successful in 3m55s
2026-08-13 21:22:21 +02:00
zach 566ccd67d9 fix greeter start script
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 21s
JS/TS / lint (pull_request) Successful in 23s
Python / fmt (pull_request) Successful in 34s
Python / lint (pull_request) Successful in 33s
Python / test (pull_request) Successful in 1m0s
Python / typecheck (pull_request) Failing after 1m5s
Rust / fmt (pull_request) Successful in 37s
Rust / build (pull_request) Successful in 1m46s
C++ / build (pull_request) Successful in 2m40s
Rust / clippy (pull_request) Successful in 1m15s
Python / buildcheck (pull_request) Successful in 2m28s
C++ / clang-tidy (pull_request) Successful in 3m57s
2026-08-13 15:54:41 +02:00
zach b2e092d0be changes to config plugin, reduce file amount + code, fix greeter 2026-08-13 15:41:16 +02:00
zach 9d2f78eb5e fix cmake take 2 2026-08-13 02:30:56 +02:00
zach 3a4ee148bf fix cmake 2026-08-13 02:29:46 +02:00
zach 3cd3209b28 config moved to c++ plugin, removed old qml + fileview implementation 2026-08-13 02:25:26 +02:00
zach 1d150292d3 initial commit for repositioning bar, currently broken 2026-08-12 20:15:55 +02:00
zach c29b91cd26 Merge pull request 'Screenshot tools features' (#141) from screenshot-picker-improvements into main
Reviewed-on: #141
Reviewed-by: Inorishio <inorishio@gmail.com>
2026-08-11 21:59:32 +02:00
zach 06fb202e36 ctrl + c & ctrl + s shortcuts + screenshot destination dir env var
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 17s
Python / fmt (pull_request) Successful in 32s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 1m0s
C++ / build (pull_request) Successful in 1m35s
Python / typecheck (pull_request) Failing after 1m12s
Rust / fmt (pull_request) Successful in 38s
Rust / build (pull_request) Successful in 1m34s
Rust / clippy (pull_request) Successful in 1m28s
Python / buildcheck (pull_request) Successful in 2m35s
C++ / clang-tidy (pull_request) Successful in 3m23s
2026-08-11 18:57:36 +02:00
zach ad5fda2718 Merge branch 'main' into screenshot-picker-improvements
C++ / fmt (pull_request) Successful in 7s
JS/TS / fmt (pull_request) Successful in 13s
JS/TS / lint (pull_request) Successful in 15s
Python / fmt (pull_request) Successful in 29s
Python / lint (pull_request) Successful in 27s
Python / test (pull_request) Successful in 50s
Python / typecheck (pull_request) Failing after 48s
Rust / fmt (pull_request) Successful in 38s
C++ / build (pull_request) Successful in 3m0s
Rust / build (pull_request) Successful in 1m40s
Python / buildcheck (pull_request) Successful in 2m26s
Rust / clippy (pull_request) Successful in 1m15s
C++ / clang-tidy (pull_request) Successful in 4m27s
2026-08-11 15:03:12 +02:00
zach 7482741e46 Merge pull request 'Status icons' (#142) from refactor/status-icons into main
Reviewed-on: #142
2026-08-11 15:03:04 +02:00
zach 2e4517b0a6 simpler model for status entries
C++ / fmt (pull_request) Successful in 3s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 16s
Python / fmt (pull_request) Successful in 29s
Python / lint (pull_request) Successful in 30s
Python / test (pull_request) Successful in 59s
Python / typecheck (pull_request) Failing after 1m7s
C++ / build (pull_request) Successful in 1m51s
Rust / fmt (pull_request) Successful in 40s
Rust / build (pull_request) Successful in 1m36s
Python / buildcheck (pull_request) Successful in 2m26s
Rust / clippy (pull_request) Successful in 1m42s
C++ / clang-tidy (pull_request) Successful in 5m31s
2026-08-11 15:00:44 +02:00
zach d81808dd8f refactor: use entries directly in bar object instead of nested components + various fixes and additions to settings
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 11s
JS/TS / lint (pull_request) Successful in 23s
Python / lint (pull_request) Successful in 30s
Python / fmt (pull_request) Successful in 32s
Python / test (pull_request) Successful in 1m1s
Python / typecheck (pull_request) Failing after 52s
C++ / build (pull_request) Successful in 1m45s
Rust / fmt (pull_request) Successful in 57s
Rust / build (pull_request) Successful in 1m50s
Rust / clippy (pull_request) Successful in 1m44s
Python / buildcheck (pull_request) Successful in 2m29s
C++ / clang-tidy (pull_request) Successful in 3m31s
2026-08-11 14:05:57 +02:00
zach 47c842941f screenshot tools baked-in: drawing uses optimized qcanvaspainter, direct to clipboard, eliminate forking to swappy
C++ / fmt (pull_request) Successful in 7s
JS/TS / lint (pull_request) Successful in 21s
JS/TS / fmt (pull_request) Successful in 20s
Python / lint (pull_request) Successful in 31s
Python / fmt (pull_request) Successful in 33s
Python / typecheck (pull_request) Failing after 1m4s
Python / test (pull_request) Successful in 1m7s
C++ / build (pull_request) Successful in 1m48s
Rust / fmt (pull_request) Successful in 37s
Rust / build (pull_request) Successful in 1m42s
Python / buildcheck (pull_request) Successful in 2m33s
Rust / clippy (pull_request) Successful in 1m32s
C++ / clang-tidy (pull_request) Successful in 3m35s
2026-08-10 12:02:34 +02:00
zach 93c6ac251e Merge pull request 'pr and issue templates + typecheck ci python' (#138) from 135-issue-pr-templates into main
Reviewed-on: #138
Reviewed-by: zach <zach@brohn.se>
2026-07-10 18:19:23 +02:00
zach 1af6bf33ff Merge branch 'main' into 135-issue-pr-templates
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 17s
JS/TS / lint (pull_request) Successful in 22s
Python / lint (pull_request) Successful in 31s
Python / fmt (pull_request) Successful in 34s
Python / test (pull_request) Successful in 59s
Python / typecheck (pull_request) Failing after 59s
C++ / build (pull_request) Successful in 2m4s
Rust / fmt (pull_request) Successful in 1m0s
Rust / build (pull_request) Successful in 1m53s
Python / buildcheck (pull_request) Successful in 2m41s
Rust / clippy (pull_request) Successful in 2m31s
C++ / clang-tidy (pull_request) Successful in 6m12s
2026-07-10 15:21:24 +02:00
zach 5eaebacbab remove unrelated directory 2026-07-10 15:00:02 +02:00
AramJonghu 4cb30647a9 hotfix(bugreport): adding optional input field; which init system?
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 15s
Python / lint (pull_request) Successful in 32s
Python / fmt (pull_request) Successful in 35s
Python / test (pull_request) Successful in 1m8s
Python / typecheck (pull_request) Failing after 1m10s
C++ / build (pull_request) Successful in 1m41s
Rust / build (pull_request) Successful in 1m44s
Rust / fmt (pull_request) Successful in 1m5s
Python / buildcheck (pull_request) Successful in 2m39s
Rust / clippy (pull_request) Successful in 2m3s
C++ / clang-tidy (pull_request) Successful in 3m42s
2026-07-10 12:07:27 +02:00
AramJonghu b3820ce1e0 Merge branch 'main' into 135-issue-pr-templates
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 15s
JS/TS / lint (pull_request) Successful in 17s
Python / fmt (pull_request) Successful in 35s
Python / lint (pull_request) Successful in 32s
Python / typecheck (pull_request) Failing after 55s
Python / test (pull_request) Successful in 1m1s
C++ / build (pull_request) Successful in 1m53s
Rust / fmt (pull_request) Successful in 1m13s
Rust / build (pull_request) Successful in 1m48s
Python / buildcheck (pull_request) Successful in 2m43s
Rust / clippy (pull_request) Successful in 2m9s
C++ / clang-tidy (pull_request) Successful in 3m48s
2026-07-10 11:58:35 +02:00
zach d1e3897d02 fix: logo colors 2026-07-10 11:44:01 +02:00
zach 46e24f8543 add initial logo to about page + assets and readme 2026-07-10 11:32:09 +02:00
AramJonghu 1ff7c36723 Merge branch 'main' into 135-issue-pr-templates
C++ / fmt (pull_request) Successful in 11s
JS/TS / fmt (pull_request) Successful in 17s
JS/TS / lint (pull_request) Successful in 17s
Python / fmt (pull_request) Successful in 30s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 57s
Python / typecheck (pull_request) Failing after 52s
C++ / build (pull_request) Successful in 3m4s
Rust / fmt (pull_request) Successful in 1m1s
Rust / build (pull_request) Successful in 1m49s
Python / buildcheck (pull_request) Successful in 2m34s
Rust / clippy (pull_request) Successful in 1m41s
C++ / clang-tidy (pull_request) Successful in 4m41s
2026-07-10 01:32:39 +02:00
AramJonghu f75fef3f55 chore(template): checklist adjustment
C++ / fmt (pull_request) Successful in 8s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 22s
Python / lint (pull_request) Successful in 32s
Python / fmt (pull_request) Successful in 35s
Python / test (pull_request) Successful in 1m4s
Python / typecheck (pull_request) Failing after 1m3s
C++ / build (pull_request) Successful in 1m55s
Rust / build (pull_request) Successful in 1m54s
Rust / fmt (pull_request) Successful in 1m16s
Python / buildcheck (pull_request) Successful in 2m46s
Rust / clippy (pull_request) Successful in 2m40s
C++ / clang-tidy (pull_request) Successful in 5m36s
2026-07-10 01:16:21 +02:00
AramJonghu 246ee67fb3 update(typecheck): added typecheck in workflow and pyproject
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 17s
Python / fmt (pull_request) Successful in 34s
Python / lint (pull_request) Successful in 31s
Python / test (pull_request) Successful in 59s
Python / typecheck (pull_request) Failing after 53s
C++ / build (pull_request) Successful in 1m56s
Rust / fmt (pull_request) Successful in 1m18s
Rust / build (pull_request) Successful in 1m50s
Rust / clippy (pull_request) Successful in 2m7s
Python / buildcheck (pull_request) Successful in 2m42s
C++ / clang-tidy (pull_request) Successful in 3m49s
2026-07-10 01:09:08 +02:00
AramJonghu 5b5f38a48d feat(templates): Added template yaml files 2026-07-10 01:09:01 +02:00
zach 1266166676 fix: text input field bounds 2026-07-09 14:20:06 +02:00
AramJonghu 8d4b910e23 Merge branch 'main' into 135-issue-pr-templates
C++ / fmt (pull_request) Successful in 9s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 20s
Python / fmt (pull_request) Successful in 31s
Python / lint (pull_request) Successful in 29s
Python / test (pull_request) Successful in 1m0s
C++ / build (pull_request) Successful in 3m25s
Rust / fmt (pull_request) Successful in 1m12s
Python / buildcheck (pull_request) Successful in 2m51s
Rust / build (pull_request) Successful in 2m14s
Rust / clippy (pull_request) Successful in 1m52s
C++ / clang-tidy (pull_request) Successful in 6m7s
2026-07-08 22:14:09 +02:00
AramJonghu 5e78b3b492 init(new branch): New branch
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 13s
Python / lint-format (pull_request) Successful in 23s
Python / test (pull_request) Successful in 1m3s
Lint & Format (Rust) / lint-format (pull_request) Successful in 2m36s
C++ / build (pull_request) Successful in 6m21s
2026-07-04 04:54:28 +02:00
394 changed files with 8702 additions and 9524 deletions
+108
View File
@@ -0,0 +1,108 @@
name: Bug Report
about: Something broke
title: "bug: "
labels:
- bug
body:
- type: textarea
id: description
attributes:
label: What happened
placeholder: Describe the bug
validations:
required: true
- type: textarea
id: expected
attributes:
label: What should happen
placeholder: Expected behavior
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
placeholder: |
1.
2.
3.
render: shell
validations:
required: true
- type: dropdown
id: os
attributes:
label: OS
options:
- NixOS
- Arch
- Debian / Ubuntu
- Fedora
- Alpine
- Artix
- Gentoo
- Other
validations:
required: false
- type: input
id: other-os
attributes:
label: Other OS (if "Other" above)
placeholder: e.g. Void, Gentoo, FreeBSD
validations:
required: false
- type: dropdown
id: init
attributes:
label: Init system
description: Relevant for UWSM configuration
options:
- systemd
- non-systemd (openrc / runit / s6 / ...)
validations:
required: false
- type: input
id: other-init
attributes:
label: Other init system (if "non-systemd" above)
placeholder: e.g. openrc, runit, s6, dinit
validations:
required: false
- type: input
id: qt-version
attributes:
label: Qt version
placeholder: 6.11.1
validations:
required: false
- type: input
id: commit
attributes:
label: Branch / commit
placeholder: main / abc1234
validations:
required: false
- type: textarea
id: logs
attributes:
label: Logs / backtrace / screenshots
render: shell
validations:
required: false
- type: textarea
id: workaround
attributes:
label: Found a workaround?
validations:
required: false
+51
View File
@@ -0,0 +1,51 @@
name: Feature Request
about: Idea or improvement
title: "feat: "
labels:
- enhancement
body:
- type: textarea
id: problem
attributes:
label: What's missing / annoying
placeholder: The use case or pain point
validations:
required: true
- type: textarea
id: solution
attributes:
label: How should it work
placeholder: Describe the desired behavior
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Other approaches considered
validations:
required: false
- type: dropdown
id: scope
attributes:
label: Area
options:
- Core / Daemon
- UI / Components
- Plugin system
- CMake / Build
- CI / Tooling
- Documentation
- Other
validations:
required: false
- type: textarea
id: context
attributes:
label: Mockups / references / notes
validations:
required: false
+59
View File
@@ -0,0 +1,59 @@
name: Pull Request
about: Submit changes
title: ""
labels: []
body:
- type: textarea
id: description
attributes:
label: What & why
placeholder: Describe the change and motivation
validations:
required: true
- type: input
id: issue
attributes:
label: Related issue
placeholder: "#123"
validations:
required: false
- type: dropdown
id: type
attributes:
label: Type
options:
- Bug fix
- New feature
- Refactor / style
- CI / build / tooling
- Documentation
validations:
required: true
- type: checkboxes
id: tested
attributes:
label: Tested
options:
- label: Build succeeds
- label: Existing tests pass
- label: Manually verified
- type: textarea
id: breaking
attributes:
label: Breaking changes?
placeholder: API/ABI breakage? Migration path?
- type: checkboxes
id: checklist
attributes:
label: Checklist
options:
- label: CI passes (format, lint, typecheck)
- label: Clean commits
- label: No new warnings
- label: Docs updated if needed
+23
View File
@@ -81,6 +81,29 @@ jobs:
cd cli cd cli
python -m pytest tests/ -v python -m pytest tests/ -v
typecheck:
runs-on: alpine
container: node:26-alpine
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apk add --no-cache \
git \
python3 \
py3-pip
python3 -m venv .venv
. .venv/bin/activate
pip install --no-cache-dir basedpyright typer pillow materialyoucolor jinja2
- name: Type check
run: |
. .venv/bin/activate
basedpyright
buildcheck: buildcheck:
runs-on: alpine runs-on: alpine
container: node:26-alpine container: node:26-alpine
+1
View File
@@ -15,3 +15,4 @@ dist/
**/target/ **/target/
**/test-plugins/ **/test-plugins/
**/Charts/ **/Charts/
network-dev/
+1 -1
View File
@@ -155,7 +155,7 @@ if("plugin" IN_LIST ENABLE_MODULES)
endif() endif()
if("shell" IN_LIST ENABLE_MODULES) if("shell" IN_LIST ENABLE_MODULES)
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths) foreach(dir assets scripts Components Services Modules Daemons Drawers Effects Helpers Paths)
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}") install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
endforeach() endforeach()
+12 -12
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
AnchorAnimation { AnchorAnimation {
enum Type { enum Type {
@@ -20,32 +20,32 @@ AnchorAnimation {
duration: { duration: {
if (type < AnchorAnim.StandardSmall || type > AnchorAnim.SlowSpatial) if (type < AnchorAnim.StandardSmall || type > AnchorAnim.SlowSpatial)
return Appearance.anim.durations.expressiveDefaultSpatial; return Tokens.anim.durations.expressiveDefaultSpatial;
if (type == AnchorAnim.FastSpatial) if (type == AnchorAnim.FastSpatial)
return Appearance.anim.durations.expressiveFastSpatial; return Tokens.anim.durations.expressiveFastSpatial;
if (type == AnchorAnim.DefaultSpatial) if (type == AnchorAnim.DefaultSpatial)
return Appearance.anim.durations.expressiveDefaultSpatial; return Tokens.anim.durations.expressiveDefaultSpatial;
if (type == AnchorAnim.SlowSpatial) if (type == AnchorAnim.SlowSpatial)
return Appearance.anim.durations.large; return Tokens.anim.durations.large;
const types = ["small", "normal", "large", "extraLarge"]; const types = ["small", "normal", "large", "extraLarge"];
const idx = type % 4; const idx = type % 4;
return Appearance.anim.durations[types[idx]]; return Tokens.anim.durations[types[idx]];
} }
easing.bezierCurve: { easing.bezierCurve: {
if (type == AnchorAnim.FastSpatial) if (type == AnchorAnim.FastSpatial)
return Appearance.anim.curves.expressiveFastSpatial; return Tokens.anim.curves.expressiveFastSpatial;
if (type == AnchorAnim.DefaultSpatial) if (type == AnchorAnim.DefaultSpatial)
return Appearance.anim.curves.expressiveDefaultSpatial; return Tokens.anim.curves.expressiveDefaultSpatial;
if (type == AnchorAnim.SlowSpatial) if (type == AnchorAnim.SlowSpatial)
return Appearance.anim.curves.expressiveSlowSpatial; return Tokens.anim.curves.expressiveSlowSpatial;
if (type >= AnchorAnim.StandardSmall && type <= AnchorAnim.StandardExtraLarge) if (type >= AnchorAnim.StandardSmall && type <= AnchorAnim.StandardExtraLarge)
return Appearance.anim.curves.standard; return Tokens.anim.curves.standard;
if (type >= AnchorAnim.EmphasizedSmall && type <= AnchorAnim.EmphasizedExtraLarge) if (type >= AnchorAnim.EmphasizedSmall && type <= AnchorAnim.EmphasizedExtraLarge)
return Appearance.anim.curves.emphasized; return Tokens.anim.curves.emphasized;
return Appearance.anim.curves.expressiveDefaultSpatial; return Tokens.anim.curves.expressiveDefaultSpatial;
} }
} }
+17 -17
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
NumberAnimation { NumberAnimation {
enum Type { enum Type {
@@ -23,41 +23,41 @@ NumberAnimation {
duration: { duration: {
if (type < Anim.StandardSmall || type > Anim.SlowEffects) if (type < Anim.StandardSmall || type > Anim.SlowEffects)
return Appearance.anim.durations.normal; return Tokens.anim.durations.normal;
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Appearance.anim.durations.expressiveFastSpatial; return Tokens.anim.durations.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Appearance.anim.durations.expressiveDefaultSpatial; return Tokens.anim.durations.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Appearance.anim.durations.large; return Tokens.anim.durations.large;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Appearance.anim.durations.expressiveFastEffects; return Tokens.anim.durations.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Appearance.anim.durations.expressiveEffects; return Tokens.anim.durations.expressiveEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Appearance.anim.durations.expressiveSlowEffects; return Tokens.anim.durations.expressiveSlowEffects;
const types = ["small", "normal", "large", "extraLarge"]; const types = ["small", "normal", "large", "extraLarge"];
const idx = type % 4; const idx = type % 4;
return Appearance.anim.durations[types[idx]]; return Tokens.anim.durations[types[idx]];
} }
easing.bezierCurve: { easing.bezierCurve: {
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Appearance.anim.curves.expressiveFastSpatial; return Tokens.anim.curves.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Appearance.anim.curves.expressiveDefaultSpatial; return Tokens.anim.curves.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Appearance.anim.curves.expressiveSlowSpatial; return Tokens.anim.curves.expressiveSlowSpatial;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Appearance.anim.curves.expressiveFastEffects; return Tokens.anim.curves.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Appearance.anim.curves.expressiveDefaultEffects; return Tokens.anim.curves.expressiveDefaultEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Appearance.anim.curves.expressiveSlowEffects; return Tokens.anim.curves.expressiveSlowEffects;
if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge) if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge)
return Appearance.anim.curves.emphasized; return Tokens.anim.curves.emphasized;
return Appearance.anim.curves.standard; return Tokens.anim.curves.standard;
} }
} }
+15 -14
View File
@@ -1,11 +1,12 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Config import ZShell.Config
import qs.Services
Slider { Slider {
id: root id: root
property color color: DynamicColors.palette.m3secondary property color color: Colors.palette.m3secondary
required property string icon required property string icon
property bool initialized: false property bool initialized: false
readonly property bool isHorizontal: orientation === Qt.Horizontal readonly property bool isHorizontal: orientation === Qt.Horizontal
@@ -19,9 +20,9 @@ Slider {
background: CustomRect { background: CustomRect {
id: groove id: groove
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2) color: Colors.layer(Colors.palette.m3surfaceContainer, 2)
height: root.availableHeight height: root.availableHeight
radius: Appearance.rounding.full radius: Tokens.rounding.full
width: root.availableWidth width: root.availableWidth
x: root.leftPadding x: root.leftPadding
y: root.topPadding y: root.topPadding
@@ -62,8 +63,8 @@ Slider {
id: rect id: rect
anchors.fill: parent anchors.fill: parent
color: DynamicColors.palette.m3inverseSurface color: Colors.palette.m3inverseSurface
radius: Appearance.rounding.full radius: Tokens.rounding.full
MouseArea { MouseArea {
id: handleInteraction id: handleInteraction
@@ -82,12 +83,12 @@ Slider {
function update(): void { function update(): void {
animate = !moving; animate = !moving;
binding.when = moving; binding.when = moving;
font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger; font.pointSize = moving ? Tokens.font.size.small : Tokens.font.size.larger;
font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material; font.family = moving ? Config.appearance.font.family.sans : Config.appearance.font.family.material;
} }
anchors.centerIn: parent anchors.centerIn: parent
color: DynamicColors.palette.m3inverseOnSurface color: Colors.palette.m3inverseOnSurface
text: root.icon text: root.icon
onMovingChanged: anim.restart() onMovingChanged: anim.restart()
@@ -105,8 +106,8 @@ Slider {
id: anim id: anim
Anim { Anim {
duration: Appearance.anim.durations.normal / 2 duration: Tokens.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardAccel easing.bezierCurve: Tokens.anim.curves.standardAccel
property: "scale" property: "scale"
target: icon target: icon
to: 0 to: 0
@@ -117,8 +118,8 @@ Slider {
} }
Anim { Anim {
duration: Appearance.anim.durations.normal / 2 duration: Tokens.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardDecel easing.bezierCurve: Tokens.anim.curves.standardDecel
property: "scale" property: "scale"
target: icon target: icon
to: 1 to: 1
@@ -129,7 +130,7 @@ Slider {
} }
Behavior on value { Behavior on value {
Anim { Anim {
duration: Appearance.anim.durations.large duration: Tokens.anim.durations.large
} }
} }
+10 -9
View File
@@ -1,5 +1,6 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Services
CustomRect { CustomRect {
id: root id: root
@@ -13,14 +14,14 @@ CustomRect {
property color activeColor property color activeColor
property color activeOnColor property color activeOnColor
property bool checked property bool checked
property real checkedRadius: Appearance.rounding.medium property real checkedRadius: Tokens.rounding.medium
property real defaultRadius: Appearance.rounding.large property real defaultRadius: Tokens.rounding.large
property color disabledColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1) property color disabledColor: Qt.alpha(Colors.palette.m3onSurface, 0.1)
property color disabledOnColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38) property color disabledOnColor: Qt.alpha(Colors.palette.m3onSurface, 0.38)
property bool fillWidth property bool fillWidth
property font font: ({ property font font: ({
family: Appearance.font.family.sans, family: Config.appearance.font.family.sans,
pointSize: Appearance.font.size.larger, pointSize: Tokens.font.size.larger,
bold: false bold: false
}) })
property real horizontalPadding: padding property real horizontalPadding: padding
@@ -35,7 +36,7 @@ CustomRect {
readonly property color onColor: !enabled ? disabledOnColor : internalChecked ? activeOnColor : inactiveOnColor readonly property color onColor: !enabled ? disabledOnColor : internalChecked ? activeOnColor : inactiveOnColor
property real padding property real padding
readonly property alias pressed: stateLayer.pressed readonly property alias pressed: stateLayer.pressed
property real pressedRadius: Appearance.rounding.small property real pressedRadius: Tokens.rounding.smallest
readonly property alias radiusAnim: radiusAnim readonly property alias radiusAnim: radiusAnim
property bool radiusMorph: true property bool radiusMorph: true
property alias shapeMorph: stateLayer.shapeMorph property alias shapeMorph: stateLayer.shapeMorph
@@ -53,7 +54,7 @@ CustomRect {
if (internalChecked) if (internalChecked)
return checkedRadius; return checkedRadius;
if (isRound) if (isRound)
return (height || implicitHeight) / 2 * Math.min(1, Appearance.rounding.scale); return (height || implicitHeight) / 2 * Math.min(1, Tokens.rounding.scale);
return defaultRadius; return defaultRadius;
} }
+59 -4
View File
@@ -1,8 +1,63 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
ColorAnimation { ColorAnimation {
duration: MaterialEasing.standardTime enum Type {
easing.bezierCurve: MaterialEasing.standard StandardSmall = 0,
easing.type: Easing.BezierSpline Standard,
StandardLarge,
StandardExtraLarge,
EmphasizedSmall,
Emphasized,
EmphasizedLarge,
EmphasizedExtraLarge,
FastSpatial,
DefaultSpatial,
SlowSpatial,
FastEffects,
DefaultEffects,
SlowEffects
}
property int type: CAnim.DefaultSpatial
duration: {
if (type < CAnim.StandardSmall || type > Anim.SlowEffects)
return Tokens.anim.durations.normal;
if (type === CAnim.FastSpatial)
return Tokens.anim.durations.expressiveFastSpatial;
if (type === CAnim.DefaultSpatial)
return Tokens.anim.durations.expressiveDefaultSpatial;
if (type === CAnim.SlowSpatial)
return Tokens.anim.durations.large;
if (type === CAnim.FastEffects)
return Tokens.anim.durations.expressiveFastEffects;
if (type === CAnim.DefaultEffects)
return Tokens.anim.durations.expressiveEffects;
if (type === CAnim.SlowEffects)
return Tokens.anim.durations.expressiveSlowEffects;
const types = ["small", "normal", "large", "extraLarge"];
const idx = type % 4;
return Tokens.anim.durations[types[idx]];
}
easing.bezierCurve: {
if (type === CAnim.FastSpatial)
return Tokens.anim.curves.expressiveFastSpatial;
if (type === CAnim.DefaultSpatial)
return Tokens.anim.curves.expressiveDefaultSpatial;
if (type === CAnim.SlowSpatial)
return Tokens.anim.curves.expressiveSlowSpatial;
if (type === CAnim.FastEffects)
return Tokens.anim.curves.expressiveFastEffects;
if (type === CAnim.DefaultEffects)
return Tokens.anim.curves.expressiveDefaultEffects;
if (type === CAnim.SlowEffects)
return Tokens.anim.curves.expressiveSlowEffects;
if (type >= CAnim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge)
return Tokens.anim.curves.emphasized;
return Tokens.anim.curves.standard;
}
} }
+9 -8
View File
@@ -1,7 +1,8 @@
import qs.Config import ZShell.Config
import ZShell.Internal import ZShell.Internal
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Services
BusyIndicator { BusyIndicator {
id: root id: root
@@ -17,12 +18,12 @@ BusyIndicator {
} }
property int animState property int animState
property color bgColor: DynamicColors.palette.m3secondaryContainer property color bgColor: Colors.palette.m3secondaryContainer
property color fgColor: DynamicColors.palette.m3primary property color fgColor: Colors.palette.m3primary
property real implicitSize: Appearance.font.size.normal * 3 property real implicitSize: Tokens.font.size.normal * 3
property real internalStrokeWidth: strokeWidth property real internalStrokeWidth: strokeWidth
readonly property alias progress: manager.progress readonly property alias progress: manager.progress
property real strokeWidth: Appearance.padding.small * 0.8 property real strokeWidth: Tokens.padding.small * 0.8
property alias type: manager.indeterminateAnimationType property alias type: manager.indeterminateAnimationType
implicitHeight: implicitSize implicitHeight: implicitSize
@@ -50,7 +51,7 @@ BusyIndicator {
} }
transitions: Transition { transitions: Transition {
Anim { Anim {
duration: manager.completeEndDuration * Appearance.anim.durations.scale duration: manager.completeEndDuration * Tokens.anim.durations.scale
properties: "opacity,internalStrokeWidth" properties: "opacity,internalStrokeWidth"
} }
} }
@@ -76,7 +77,7 @@ BusyIndicator {
} }
NumberAnimation { NumberAnimation {
duration: manager.duration * Appearance.anim.durations.scale duration: manager.duration * Tokens.anim.durations.scale
from: 0 from: 0
loops: Animation.Infinite loops: Animation.Infinite
property: "progress" property: "progress"
@@ -86,7 +87,7 @@ BusyIndicator {
} }
NumberAnimation { NumberAnimation {
duration: manager.completeEndDuration * Appearance.anim.durations.scale duration: manager.completeEndDuration * Tokens.anim.durations.scale
from: 0 from: 0
property: "completeEndProgress" property: "completeEndProgress"
running: root.animState === CircularIndicator.Completing running: root.animState === CircularIndicator.Completing
+7 -6
View File
@@ -3,24 +3,25 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import ZShell.Components import ZShell.Components
import qs.Config import ZShell.Config
import qs.Services
Item { Item {
id: root id: root
readonly property real arcRadius: (size - padding - strokeWidth * (1 + waveAmplitude * 2)) / 2 readonly property real arcRadius: (size - padding - strokeWidth * (1 + waveAmplitude * 2)) / 2
property color bgColor: DynamicColors.palette.m3secondaryContainer property color bgColor: Colors.palette.m3secondaryContainer
property real clampedVal: Math.max(1 / 360, Math.min(1, isNaN(value) ? 0 : value)) property real clampedVal: Math.max(1 / 360, Math.min(1, isNaN(value) ? 0 : value))
readonly property real dotAngleRad: (startAngle + sweepAngle - gapAngle * (sweepAngle < 360 ? 0 : 1)) * Math.PI / 180 readonly property real dotAngleRad: (startAngle + sweepAngle - gapAngle * (sweepAngle < 360 ? 0 : 1)) * Math.PI / 180
property color fgColor: DynamicColors.palette.m3primary property color fgColor: Colors.palette.m3primary
readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI) readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI)
property alias hasEndIndicator: dot.active property alias hasEndIndicator: dot.active
property real implicitSize property real implicitSize
property int padding: 0 property int padding: 0
readonly property real size: Math.min(width, height) readonly property real size: Math.min(width, height)
property int spacing: Appearance.spacing.small property int spacing: Tokens.spacing.small
property int startAngle: -90 property int startAngle: -90
property int strokeWidth: Appearance.padding.small property int strokeWidth: Tokens.padding.small
property int sweepAngle: 360 property int sweepAngle: 360
readonly property real thickness: strokeWidth * (1 + waveAmplitude) * 2 readonly property real thickness: strokeWidth * (1 + waveAmplitude) * 2
property real value property real value
@@ -110,7 +111,7 @@ Item {
implicitHeight: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth) implicitHeight: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth)
implicitWidth: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth) implicitWidth: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth)
opacity: Math.min(1, remainingArc.sweepAngle) opacity: Math.min(1, remainingArc.sweepAngle)
radius: Appearance.rounding.full radius: Tokens.rounding.full
} }
} }
} }
+7 -6
View File
@@ -1,7 +1,8 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Services
Item { Item {
id: root id: root
@@ -18,9 +19,9 @@ Item {
property real lastChromaticHue: 0 property real lastChromaticHue: 0
readonly property real radius: (Math.min(width, height) - handleSize) / 2 readonly property real radius: (Math.min(width, height) - handleSize) / 2
readonly property int segmentCount: 240 readonly property int segmentCount: 240
readonly property color thumbColor: DynamicColors.palette.m3inverseSurface readonly property color thumbColor: Colors.palette.m3inverseSurface
readonly property color thumbContentColor: DynamicColors.palette.m3inverseOnSurface readonly property color thumbContentColor: Colors.palette.m3inverseOnSurface
readonly property color trackColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2) readonly property color trackColor: Colors.layer(Colors.palette.m3surfaceContainer, 2)
function hueToAngle(hue) { function hueToAngle(hue) {
return arcStartAngle + arcSweep * hue; return arcStartAngle + arcSweep * hue;
@@ -153,8 +154,8 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
color: root.drawing?.drawingState.penColor color: root.drawing?.drawingState.penColor
implicitHeight: implicitWidth implicitHeight: implicitWidth
implicitWidth: canvas.height - root.handleSize - Appearance.padding.extraLarge * 2 implicitWidth: canvas.height - root.handleSize - Tokens.padding.extraLarge * 2
radius: Appearance.rounding.full radius: Tokens.rounding.full
Behavior on color { Behavior on color {
enabled: false enabled: false
+6 -5
View File
@@ -1,6 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import qs.Config import ZShell.Config
import qs.Services
CheckBox { CheckBox {
id: control id: control
@@ -18,14 +19,14 @@ CheckBox {
indicator: CustomRect { indicator: CustomRect {
// x: control.leftPadding // x: control.leftPadding
// y: parent.implicitHeight / 2 - implicitHeight / 2 // y: parent.implicitHeight / 2 - implicitHeight / 2
border.color: control.checked ? DynamicColors.palette.m3primary : "transparent" border.color: control.checked ? Colors.palette.m3primary : "transparent"
color: DynamicColors.palette.m3surfaceVariant color: Colors.palette.m3surfaceVariant
implicitHeight: control.checkHeight implicitHeight: control.checkHeight
implicitWidth: control.checkWidth implicitWidth: control.checkWidth
radius: Appearance.rounding.smallest / 2 radius: Tokens.rounding.smallest / 2
CustomRect { CustomRect {
color: DynamicColors.palette.m3primary color: Colors.palette.m3primary
implicitHeight: control.checkHeight - (y * 2) implicitHeight: control.checkHeight - (y * 2)
implicitWidth: control.checkWidth - (x * 2) implicitWidth: control.checkWidth - (x * 2)
radius: 3 radius: 3
+8 -7
View File
@@ -5,7 +5,8 @@ import QtQuick.Templates
import ZShell import ZShell
import ZShell.Components import ZShell.Components
import ZShell.Internal import ZShell.Internal
import qs.Config import ZShell.Config
import qs.Services
ProgressBar { ProgressBar {
id: root id: root
@@ -16,8 +17,8 @@ ProgressBar {
Stopped Stopped
} }
property color bgColor: DynamicColors.palette.m3secondaryContainer property color bgColor: Colors.palette.m3secondaryContainer
property color fgColor: DynamicColors.palette.m3primary property color fgColor: Colors.palette.m3primary
property int indeterminateAnimState: CustomProgressBar.Stopped property int indeterminateAnimState: CustomProgressBar.Stopped
property real waveAmplitude: 0.5 property real waveAmplitude: 0.5
property int waveDuration: 1000 property int waveDuration: 1000
@@ -64,7 +65,7 @@ ProgressBar {
LinearIndicatorManager { LinearIndicatorManager {
id: manager id: manager
gap: Appearance.spacing.extraSmall gap: Tokens.spacing.extraSmall
Anim on completeEndProgress { Anim on completeEndProgress {
duration: manager.completeEndDuration duration: manager.completeEndDuration
@@ -94,7 +95,7 @@ ProgressBar {
id: remaining id: remaining
anchors.right: parent.right anchors.right: parent.right
implicitWidth: parent.width - wave.implicitWidth - Appearance.spacing.extraSmall implicitWidth: parent.width - wave.implicitWidth - Tokens.spacing.extraSmall
} }
Line { Line {
@@ -106,7 +107,7 @@ ProgressBar {
color: root.fgColor color: root.fgColor
implicitHeight: implicitSize implicitHeight: implicitSize
implicitWidth: implicitSize implicitWidth: implicitSize
radius: Appearance.rounding.full radius: Tokens.rounding.full
Behavior on implicitSize { Behavior on implicitSize {
Anim { Anim {
@@ -200,7 +201,7 @@ ProgressBar {
color: root.bgColor color: root.bgColor
implicitHeight: parent.height implicitHeight: parent.height
implicitWidth: bounds.y - bounds.x implicitWidth: bounds.y - bounds.x
radius: Appearance.rounding.full radius: Tokens.rounding.full
x: bounds.x x: bounds.x
} }
component Wave: WavyLine { component Wave: WavyLine {
+8 -7
View File
@@ -1,11 +1,12 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Config import ZShell.Config
import qs.Services
RadioButton { RadioButton {
id: root id: root
font.pointSize: Appearance.font.size.normal font.pointSize: Tokens.font.size.normal
implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight) implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight)
implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin
@@ -20,12 +21,12 @@ RadioButton {
id: outerCircle id: outerCircle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
border.color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant border.color: root.checked ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
border.width: 2 border.width: 2
color: "transparent" color: "transparent"
implicitHeight: 16 implicitHeight: 16
implicitWidth: 16 implicitWidth: 16
radius: Appearance.rounding.full radius: Tokens.rounding.full
Behavior on border.color { Behavior on border.color {
CAnim { CAnim {
@@ -34,7 +35,7 @@ RadioButton {
StateLayer { StateLayer {
anchors.margins: -7 anchors.margins: -7
color: root.checked ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3primary color: root.checked ? Colors.palette.m3onSurface : Colors.palette.m3primary
z: -1 z: -1
onClicked: { onClicked: {
@@ -44,10 +45,10 @@ RadioButton {
CustomRect { CustomRect {
anchors.centerIn: parent anchors.centerIn: parent
color: Qt.alpha(DynamicColors.palette.m3primary, root.checked ? 1 : 0) color: Qt.alpha(Colors.palette.m3primary, root.checked ? 1 : 0)
implicitHeight: 8 implicitHeight: 8
implicitWidth: 8 implicitWidth: 8
radius: Appearance.rounding.full radius: Tokens.rounding.full
} }
} }
} }
+7 -6
View File
@@ -1,7 +1,8 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Helpers import qs.Helpers
import qs.Config import ZShell.Config
import qs.Services
ScrollBar { ScrollBar {
id: root id: root
@@ -17,7 +18,7 @@ ScrollBar {
readonly property real travelScale: root.rawTravel > 0 ? root.effectiveTravel / root.rawTravel : 0 readonly property real travelScale: root.rawTravel > 0 ? root.effectiveTravel / root.rawTravel : 0
enabled: !Visibilities.getForActive().isDrawing enabled: !Visibilities.getForActive().isDrawing
implicitWidth: Appearance.padding.extraSmall * 2 implicitWidth: Tokens.padding.extraSmall * 2
contentItem: Item { contentItem: Item {
} }
@@ -51,15 +52,15 @@ ScrollBar {
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
implicitWidth: handle.implicitWidth implicitWidth: handle.implicitWidth
radius: Appearance.rounding.full radius: Tokens.rounding.full
CustomRect { CustomRect {
id: handle id: handle
anchors.right: parent.right anchors.right: parent.right
color: DynamicColors.palette.m3secondary color: Colors.palette.m3secondary
implicitHeight: root.height * root.effectiveSize implicitHeight: root.height * root.effectiveSize
implicitWidth: fullMouse.pressed || fullMouse.containsMouse ? Appearance.padding.extraSmall * 2 : Appearance.padding.extraSmall implicitWidth: fullMouse.pressed || fullMouse.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
opacity: { opacity: {
if (!root.enabled) if (!root.enabled)
return 0; return 0;
@@ -73,7 +74,7 @@ ScrollBar {
return 0.6; return 0.6;
return 0; return 0;
} }
radius: Appearance.rounding.full radius: Tokens.rounding.full
y: root.reversed ? root.height * (1 + root.nonAnimY) * root.travelScale : root.height * root.nonAnimY * root.travelScale y: root.reversed ? root.height * (1 + root.nonAnimY) * root.travelScale : root.height * root.nonAnimY * root.travelScale
Behavior on implicitWidth { Behavior on implicitWidth {
+17 -16
View File
@@ -5,20 +5,21 @@ import QtQuick.Templates
import ZShell.Components import ZShell.Components
import ZShell import ZShell
import qs.Components import qs.Components
import qs.Config import ZShell.Config
import qs.Services
Slider { Slider {
id: root id: root
property bool animateWave property bool animateWave
property color bgColor: enabled ? DynamicColors.palette.m3secondaryContainer : Qt.alpha(DynamicColors.palette.m3onSurface, 0.1) property color bgColor: enabled ? Colors.palette.m3secondaryContainer : Qt.alpha(Colors.palette.m3onSurface, 0.1)
property color fgColor: enabled ? DynamicColors.palette.m3primary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.38) property color fgColor: enabled ? Colors.palette.m3primary : Qt.alpha(Colors.palette.m3onSurface, 0.38)
property real filledWidth property real filledWidth
property alias inset: inset property alias inset: inset
property color insetColor: enabled ? (inset.attached ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onPrimary) : DynamicColors.palette.m3onSurface property color insetColor: enabled ? (inset.attached ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onPrimary) : Colors.palette.m3onSurface
property string insetIcon: "" property string insetIcon: ""
property real pos: visualPosition property real pos: visualPosition
property int radius: Appearance.rounding.small property int radius: Tokens.rounding.small
property int waveDuration: 1000 property int waveDuration: 1000
property real waveFrequency: 6 property real waveFrequency: 6
property bool wavy property bool wavy
@@ -35,15 +36,15 @@ Slider {
id: remaining id: remaining
anchors.left: handle.right anchors.left: handle.right
anchors.leftMargin: Appearance.spacing.extraSmall anchors.leftMargin: Tokens.spacing.extraSmall
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
bottomLeftRadius: Appearance.rounding.extraSmall / 2 bottomLeftRadius: Tokens.rounding.extraSmall / 2
color: root.bgColor color: root.bgColor
implicitHeight: parent.height * (parent.height <= 12 ? opacity : Math.min(opacity * 2, 1)) implicitHeight: parent.height * (parent.height <= 12 ? opacity : Math.min(opacity * 2, 1))
opacity: Math.min(width, 12) / 12 opacity: Math.min(width, 12) / 12
radius: root.radius radius: root.radius
topLeftRadius: Appearance.rounding.extraSmall / 2 topLeftRadius: Tokens.rounding.extraSmall / 2
} }
CustomRect { CustomRect {
@@ -54,14 +55,14 @@ Slider {
implicitHeight: 4 * remaining.opacity implicitHeight: 4 * remaining.opacity
implicitWidth: implicitHeight implicitWidth: implicitHeight
opacity: remaining.opacity opacity: remaining.opacity
radius: Appearance.rounding.full radius: Tokens.rounding.full
} }
CustomRect { CustomRect {
id: handle id: handle
anchors.left: filled.right anchors.left: filled.right
anchors.leftMargin: Appearance.spacing.extraSmall anchors.leftMargin: Tokens.spacing.extraSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.fgColor color: root.fgColor
implicitHeight: { implicitHeight: {
@@ -70,7 +71,7 @@ Slider {
return parent.height * (mouse.pressed ? lerp(3.5, 1.5) : lerp(3, 1.2)); return parent.height * (mouse.pressed ? lerp(3.5, 1.5) : lerp(3, 1.2));
} }
implicitWidth: 4 implicitWidth: 4
radius: Appearance.rounding.full radius: Tokens.rounding.full
Behavior on implicitHeight { Behavior on implicitHeight {
Anim { Anim {
@@ -91,17 +92,17 @@ Slider {
MaterialIcon { MaterialIcon {
id: inset id: inset
readonly property bool attached: root.width ? (root.width - handle.implicitWidth - handle.anchors.leftMargin) * root.pos < inset.paintedWidth + Appearance.spacing.extraSmall * 2 : false readonly property bool attached: root.width ? (root.width - handle.implicitWidth - handle.anchors.leftMargin) * root.pos < inset.paintedWidth + Tokens.spacing.extraSmall * 2 : false
property real dockT: attached ? 1 : 0 property real dockT: attached ? 1 : 0
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.top: parent.top anchors.top: parent.top
color: root.insetColor color: root.insetColor
font.pixelSize: Appearance.font.size.smaller * 2 font.pixelSize: Tokens.font.size.smaller * 2
text: root.insetIcon text: root.insetIcon
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: !root.wavy && root.insetIcon !== "" visible: !root.wavy && root.insetIcon !== ""
x: Appearance.spacing.extraSmall + dockT * (handle.x + Appearance.spacing.small) x: Tokens.spacing.extraSmall + dockT * (handle.x + Tokens.spacing.small)
Behavior on dockT { Behavior on dockT {
Anim { Anim {
@@ -113,12 +114,12 @@ Slider {
id: lineComp id: lineComp
CustomRect { CustomRect {
bottomRightRadius: Appearance.rounding.extraSmall / 2 bottomRightRadius: Tokens.rounding.extraSmall / 2
color: root.fgColor color: root.fgColor
implicitHeight: root.height implicitHeight: root.height
implicitWidth: root.filledWidth implicitWidth: root.filledWidth
radius: root.radius radius: root.radius
topRightRadius: Appearance.rounding.extraSmall / 2 topRightRadius: Tokens.rounding.extraSmall / 2
} }
} }
+19 -18
View File
@@ -1,6 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Config import ZShell.Config
import qs.Services
DoubleSpinBox { DoubleSpinBox {
id: root id: root
@@ -29,36 +30,36 @@ DoubleSpinBox {
editable: true editable: true
implicitHeight: Math.max(up.indicator.implicitHeight, down.indicator.implicitHeight, contentItem.implicitHeight) + topPadding + bottomPadding implicitHeight: Math.max(up.indicator.implicitHeight, down.indicator.implicitHeight, contentItem.implicitHeight) + topPadding + bottomPadding
implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding
leftPadding: up.indicator.implicitWidth + Appearance.spacing.extraSmall / 2 leftPadding: up.indicator.implicitWidth + Tokens.spacing.extraSmall / 2
rightPadding: down.indicator.implicitWidth + Appearance.spacing.extraSmall / 2 rightPadding: down.indicator.implicitWidth + Tokens.spacing.extraSmall / 2
spacing: Appearance.spacing.small spacing: Tokens.spacing.small
contentItem: TextFieldBase { contentItem: TextFieldBase {
horizontalAlignment: TextField.AlignHCenter horizontalAlignment: TextField.AlignHCenter
implicitWidth: 65 implicitWidth: 65
inputMethodHints: Qt.ImhFormattedNumbersOnly inputMethodHints: Qt.ImhFormattedNumbersOnly
leftPadding: Appearance.padding.larger leftPadding: Tokens.padding.larger
readOnly: !root.editable readOnly: !root.editable
rightPadding: Appearance.padding.larger rightPadding: Tokens.padding.larger
text: root.textFromValue(root.value, root.locale) text: root.textFromValue(root.value, root.locale)
validator: root.validator validator: root.validator
background: CustomRect { background: CustomRect {
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) color: Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer)
radius: Appearance.rounding.extraSmall radius: Tokens.rounding.extraSmall
} }
} }
down.indicator: IconButton { down.indicator: IconButton {
id: downButton id: downButton
bottomRightRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall bottomRightRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall
color: enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor color: enabled ? Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor
disabledColor: Qt.alpha(DynamicColors.palette.m3surfaceContainerHighest, 0.4) disabledColor: Qt.alpha(Colors.palette.m3surfaceContainerHighest, 0.4)
icon: "remove" icon: "remove"
isRound: true isRound: true
label.anchors.horizontalCenterOffset: pressed ? 0 : 2 label.anchors.horizontalCenterOffset: pressed ? 0 : 2
padding: Appearance.padding.extraSmall padding: Tokens.padding.extraSmall
topRightRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall topRightRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall
type: IconButton.Text type: IconButton.Text
Behavior on bottomRightRadius { Behavior on bottomRightRadius {
@@ -81,14 +82,14 @@ DoubleSpinBox {
id: upButton id: upButton
anchors.right: parent.right anchors.right: parent.right
bottomLeftRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall bottomLeftRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall
color: enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor color: enabled ? Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor
disabledColor: Qt.alpha(DynamicColors.palette.m3surfaceContainerHighest, 0.4) disabledColor: Qt.alpha(Colors.palette.m3surfaceContainerHighest, 0.4)
icon: "add" icon: "add"
isRound: true isRound: true
label.anchors.horizontalCenterOffset: pressed ? 0 : -2 label.anchors.horizontalCenterOffset: pressed ? 0 : -2
padding: Appearance.padding.extraSmall padding: Tokens.padding.extraSmall
topLeftRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall topLeftRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall
type: IconButton.Text type: IconButton.Text
Behavior on bottomLeftRadius { Behavior on bottomLeftRadius {
+16 -15
View File
@@ -1,6 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Config import ZShell.Config
import qs.Services
Row { Row {
id: root id: root
@@ -11,14 +12,14 @@ Row {
} }
property alias active: menu.active property alias active: menu.active
property color color: type == CustomSplitButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondaryContainer property color color: type == CustomSplitButton.Filled ? Colors.palette.m3primary : Colors.palette.m3secondaryContainer
property color disabledColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1) property color disabledColor: Qt.alpha(Colors.palette.m3onSurface, 0.1)
property color disabledTextColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38) property color disabledTextColor: Qt.alpha(Colors.palette.m3onSurface, 0.38)
readonly property alias expandBtn: expandBtn readonly property alias expandBtn: expandBtn
property alias expanded: menu.expanded property alias expanded: menu.expanded
property string fallbackIcon property string fallbackIcon
property string fallbackText property string fallbackText
property real horizontalPadding: Appearance.padding.larger property real horizontalPadding: Tokens.padding.larger
readonly property alias iconLabel: iconLabel readonly property alias iconLabel: iconLabel
readonly property alias label: label readonly property alias label: label
readonly property alias menu: menu readonly property alias menu: menu
@@ -26,20 +27,20 @@ Row {
property bool menuOnTop property bool menuOnTop
property real minLeftWidth property real minLeftWidth
readonly property alias stateLayer: stateLayer readonly property alias stateLayer: stateLayer
property color textColor: type == CustomSplitButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondaryContainer property color textColor: type == CustomSplitButton.Filled ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondaryContainer
readonly property alias textRow: textRow readonly property alias textRow: textRow
property int type: CustomSplitButton.Filled property int type: CustomSplitButton.Filled
property real verticalPadding: Appearance.padding.small property real verticalPadding: Tokens.padding.small
spacing: Math.floor(Appearance.spacing.extraSmall) spacing: Math.floor(Tokens.spacing.extraSmall)
CustomRect { CustomRect {
bottomRightRadius: Appearance.rounding.small / 2 bottomRightRadius: Tokens.rounding.small / 2
color: !root.enabled ? root.disabledColor : root.color color: !root.enabled ? root.disabledColor : root.color
implicitHeight: expandBtn.implicitHeight implicitHeight: expandBtn.implicitHeight
implicitWidth: Math.max(root.minLeftWidth, textRow.implicitWidth + root.horizontalPadding * 2) implicitWidth: Math.max(root.minLeftWidth, textRow.implicitWidth + root.horizontalPadding * 2)
radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) radius: implicitHeight / 2 * Math.min(1, Tokens.rounding.scale)
topRightRadius: Appearance.rounding.small / 2 topRightRadius: Tokens.rounding.small / 2
StateLayer { StateLayer {
id: stateLayer id: stateLayer
@@ -57,7 +58,7 @@ Row {
anchors.centerIn: parent anchors.centerIn: parent
anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4) anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4)
spacing: Appearance.spacing.small spacing: Tokens.spacing.small
MaterialIcon { MaterialIcon {
id: iconLabel id: iconLabel
@@ -91,13 +92,13 @@ Row {
CustomRect { CustomRect {
id: expandBtn id: expandBtn
property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) : Appearance.rounding.small / 2 property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Tokens.rounding.scale) : Tokens.rounding.small / 2
bottomLeftRadius: rad bottomLeftRadius: rad
color: !root.enabled ? root.disabledColor : root.color color: !root.enabled ? root.disabledColor : root.color
implicitHeight: expandIcon.implicitHeight + root.verticalPadding * 2 implicitHeight: expandIcon.implicitHeight + root.verticalPadding * 2
implicitWidth: implicitHeight implicitWidth: implicitHeight
radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) radius: implicitHeight / 2 * Math.min(1, Tokens.rounding.scale)
topLeftRadius: rad topLeftRadius: rad
Behavior on rad { Behavior on rad {
@@ -141,7 +142,7 @@ Row {
attachSideY: root.menuOnTop ? Menu.Top : Menu.Bottom attachSideY: root.menuOnTop ? Menu.Top : Menu.Bottom
attachTo: expandBtn attachTo: expandBtn
marginY: Appearance.spacing.small * (root.menuOnTop ? -1 : 1) marginY: Tokens.spacing.small * (root.menuOnTop ? -1 : 1)
thisSideY: root.menuOnTop ? Menu.Bottom : Menu.Top thisSideY: root.menuOnTop ? Menu.Bottom : Menu.Top
} }
} }
+7 -6
View File
@@ -2,7 +2,8 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Config import ZShell.Config
import qs.Services
Item { Item {
id: root id: root
@@ -21,7 +22,7 @@ Item {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
clip: false clip: false
implicitHeight: row.implicitHeight + Appearance.padding.smaller * 2 implicitHeight: row.implicitHeight + Tokens.padding.smaller * 2
opacity: shouldBeActive ? 1 : 0 opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8 scale: shouldBeActive ? 1 : 0.8
z: splitButton.menu.implicitHeight > 0 ? expandedZ : 1 z: splitButton.menu.implicitHeight > 0 ? expandedZ : 1
@@ -39,15 +40,15 @@ Item {
id: row id: row
anchors.left: parent.left anchors.left: parent.left
anchors.margins: Appearance.padding.small anchors.margins: Tokens.padding.small
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal spacing: Tokens.spacing.normal
CustomText { CustomText {
Layout.fillWidth: true Layout.fillWidth: true
color: root.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSurfaceVariant color: root.enabled ? Colors.palette.m3onSurface : Colors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.larger font.pointSize: Tokens.font.size.larger
text: root.label text: root.label
} }
+15 -14
View File
@@ -1,7 +1,8 @@
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import QtQuick.Templates import QtQuick.Templates
import qs.Config import ZShell.Config
import qs.Services
Switch { Switch {
id: root id: root
@@ -12,20 +13,20 @@ Switch {
implicitWidth: implicitIndicatorWidth implicitWidth: implicitIndicatorWidth
indicator: CustomRect { indicator: CustomRect {
color: root.checked && root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) color: root.checked && root.enabled ? Colors.palette.m3primary : Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer)
implicitHeight: Appearance.font.size.medium + Appearance.padding.normal * 2 implicitHeight: Tokens.font.size.medium + Tokens.padding.normal * 2
implicitWidth: implicitHeight * 1.7 implicitWidth: implicitHeight * 1.7
radius: Appearance.rounding.full radius: Tokens.rounding.full
CustomRect { CustomRect {
readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.2 : implicitHeight readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.2 : implicitHeight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.checked && root.enabled ? DynamicColors.palette.m3onPrimary : DynamicColors.layer(DynamicColors.palette.m3outline, root.cLayer + 1) color: root.checked && root.enabled ? Colors.palette.m3onPrimary : Colors.layer(Colors.palette.m3outline, root.cLayer + 1)
implicitHeight: parent.implicitHeight - Appearance.padding.extraSmall implicitHeight: parent.implicitHeight - Tokens.padding.extraSmall
implicitWidth: nonAnimWidth implicitWidth: nonAnimWidth
radius: Appearance.rounding.full radius: Tokens.rounding.full
x: root.checked ? parent.implicitWidth - nonAnimWidth - Appearance.padding.extraSmall / 2 : Appearance.padding.extraSmall / 2 x: root.checked ? parent.implicitWidth - nonAnimWidth - Tokens.padding.extraSmall / 2 : Tokens.padding.extraSmall / 2
Behavior on implicitWidth { Behavior on implicitWidth {
Anim { Anim {
@@ -40,7 +41,7 @@ Switch {
CustomRect { CustomRect {
anchors.fill: parent anchors.fill: parent
color: root.checked && root.enabled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface color: root.checked && root.enabled ? Colors.palette.m3primary : Colors.palette.m3onSurface
opacity: root.pressed ? 0.1 : root.hovered ? 0.08 : 0 opacity: root.pressed ? 0.1 : root.hovered ? 0.08 : 0
radius: parent.radius radius: parent.radius
@@ -91,7 +92,7 @@ Switch {
anchors.centerIn: parent anchors.centerIn: parent
asynchronous: true asynchronous: true
height: parent.implicitHeight - Appearance.padding.larger height: parent.implicitHeight - Tokens.padding.larger
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
width: height width: height
@@ -117,8 +118,8 @@ Switch {
fillColor: "transparent" fillColor: "transparent"
startX: icon.start1.x startX: icon.start1.x
startY: icon.start1.y startY: icon.start1.y
strokeColor: root.checked && root.enabled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3surfaceContainerHighest strokeColor: root.checked && root.enabled ? Colors.palette.m3primary : Colors.palette.m3surfaceContainerHighest
strokeWidth: Appearance.font.size.larger * 0.15 strokeWidth: Tokens.font.size.larger * 0.15
Behavior on strokeColor { Behavior on strokeColor {
CAnim { CAnim {
@@ -151,7 +152,7 @@ Switch {
} }
component PropAnim: PropertyAnimation { component PropAnim: PropertyAnimation {
duration: Appearance.anim.durations.expressiveFastSpatial duration: Tokens.anim.durations.expressiveFastSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial easing.bezierCurve: Tokens.anim.curves.expressiveFastSpatial
} }
} }
+6 -5
View File
@@ -1,7 +1,8 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Services
Text { Text {
id: root id: root
@@ -12,10 +13,10 @@ Text {
property string animateProp: "scale" property string animateProp: "scale"
property real animateTo: 1 property real animateTo: 1
color: DynamicColors.palette.m3onSurface color: Colors.palette.m3onSurface
font.family: Appearance.font.family.sans font.family: Config.appearance.font.family.sans
font.pointSize: Appearance.font.size.normal font.pointSize: Tokens.font.size.normal
linkColor: DynamicColors.palette.m3onPrimaryFixedVariant linkColor: Colors.palette.m3onPrimaryFixedVariant
renderType: Text.NativeRendering renderType: Text.NativeRendering
textFormat: Text.PlainText textFormat: Text.PlainText
+54 -48
View File
@@ -2,7 +2,8 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import qs.Config import ZShell.Config
import qs.Services
TextFieldBase { TextFieldBase {
id: root id: root
@@ -16,28 +17,26 @@ TextFieldBase {
readonly property string effectiveSupportingText: isError && errorText ? errorText : supportingText readonly property string effectiveSupportingText: isError && errorText ? errorText : supportingText
property bool emptyIsValid: true property bool emptyIsValid: true
property string errorText property string errorText
readonly property int filledOffset: type === CustomTextField.Filled ? Appearance.spacing.small : 0 readonly property int filledOffset: type === CustomTextField.Filled ? Tokens.spacing.small : 0
readonly property int horizontalPadding: Appearance.padding.large readonly property int horizontalPadding: Tokens.padding.large
property bool isError property bool isError
property string leadingIcon property string leadingIcon
readonly property int leadingOffset: leadingIcon ? leadingIconLoader.width + leadingIconLoader.anchors.leftMargin : 0 readonly property int leadingOffset: leadingIcon ? leadingIconLoader.width + leadingIconLoader.anchors.leftMargin : 0
readonly property real outlineGap: placeholder.width * root.smallFontScale + Appearance.spacing.extraSmall * 2 property int radius: Tokens.rounding.small
property real outlineGapScale: activeFocus || text ? 1 : 0
property int radius: Appearance.rounding.small
readonly property real smallFontScale: smallFontSize / font.pointSize readonly property real smallFontScale: smallFontSize / font.pointSize
property int smallFontSize: Appearance.font.size.small property int smallFontSize: Tokens.font.size.small
property string supportingText property string supportingText
readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Appearance.spacing.extraSmall : 0 readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Tokens.spacing.extraSmall : 0
property string trailingIcon property string trailingIcon
readonly property int trailingOffset: trailingIcon ? trailingIconLoader.width + trailingIconLoader.anchors.rightMargin : 0 readonly property int trailingOffset: trailingIcon ? trailingIconLoader.width + trailingIconLoader.anchors.rightMargin : 0
property int type: CustomTextField.Outlined property int type: CustomTextField.Outlined
readonly property bool valid: !validate || (!text && emptyIsValid) || (validate instanceof RegExp ? validate.test(text) : !!validate(text)) readonly property bool valid: !validate || (!text && emptyIsValid) || (validate instanceof RegExp ? validate.test(text) : !!validate(text))
property var validate // Regex or function property var validate // Regex or function
bottomPadding: Appearance.padding.large + supportingTextOffset - filledOffset bottomPadding: Tokens.padding.large + supportingTextOffset - filledOffset
leftPadding: horizontalPadding + leadingOffset leftPadding: horizontalPadding + leadingOffset
rightPadding: horizontalPadding + trailingOffset rightPadding: horizontalPadding + trailingOffset
topPadding: Appearance.padding.large + filledOffset topPadding: Tokens.padding.large + filledOffset
background: Loader { background: Loader {
anchors.bottomMargin: root.supportingTextOffset anchors.bottomMargin: root.supportingTextOffset
@@ -57,11 +56,6 @@ TextFieldBase {
onClicked: root.focus = true onClicked: root.focus = true
} }
} }
Behavior on outlineGapScale {
Anim {
type: Anim.DefaultEffects
}
}
onEditingFinished: { onEditingFinished: {
if (!valid) if (!valid)
@@ -87,9 +81,9 @@ TextFieldBase {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: root.leftPadding anchors.leftMargin: root.leftPadding
anchors.topMargin: Appearance.padding.extraSmall anchors.topMargin: Tokens.padding.extraSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : root.text ? DynamicColors.palette.m3outline : root.placeholderTextColor) color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : root.text ? Colors.palette.m3outline : root.placeholderTextColor)
font.family: root.font.family font.family: root.font.family
font.pointSize: root.font.pointSize font.pointSize: root.font.pointSize
font.variableAxes: root.font.variableAxes font.variableAxes: root.font.variableAxes
@@ -103,7 +97,7 @@ TextFieldBase {
when: root.type === CustomTextField.Outlined && (root.activeFocus || root.text) when: root.type === CustomTextField.Outlined && (root.activeFocus || root.text)
PropertyChanges { PropertyChanges {
placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + -Appearance.spacing.extraSmall placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding
placeholder.scale: root.smallFontScale placeholder.scale: root.smallFontScale
} }
@@ -135,8 +129,8 @@ TextFieldBase {
} }
AnchorAnim { AnchorAnim {
duration: Appearance.anim.durations.expressiveEffects duration: Tokens.anim.durations.expressiveEffects
easing: Appearance.anim.curves.expressiveDefaultEffects easing.bezierCurve: Tokens.anim.curves.expressiveEffects
} }
} }
} }
@@ -146,12 +140,11 @@ TextFieldBase {
active: root.leadingIcon active: root.leadingIcon
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Appearance.padding.larger anchors.leftMargin: Tokens.padding.normal
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
sourceComponent: MaterialIcon { sourceComponent: MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant color: Colors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
text: root.leadingIcon text: root.leadingIcon
} }
} }
@@ -161,12 +154,11 @@ TextFieldBase {
active: root.trailingIcon active: root.trailingIcon
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Appearance.padding.larger anchors.rightMargin: Tokens.padding.normal
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
sourceComponent: MaterialIcon { sourceComponent: MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant color: Colors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
text: root.trailingIcon text: root.trailingIcon
} }
} }
@@ -181,8 +173,8 @@ TextFieldBase {
anchors.leftMargin: root.horizontalPadding anchors.leftMargin: root.horizontalPadding
sourceComponent: CustomText { sourceComponent: CustomText {
color: root.isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurfaceVariant color: root.isError ? Colors.palette.m3error : Colors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.small font.pointSize: Tokens.font.size.small
text: root.effectiveSupportingText text: root.effectiveSupportingText
} }
} }
@@ -201,12 +193,24 @@ TextFieldBase {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
id: path
readonly property real inset: strokeWidth / 2
readonly property real outlineGap: placeholder.width * root.smallFontScale + Tokens.spacing.small * 2
property real outlineGapScale: root.activeFocus || root.text ? 1 : 0
capStyle: ShapePath.RoundCap capStyle: ShapePath.RoundCap
fillColor: "transparent" fillColor: "transparent"
startX: root.horizontalPadding - root.clampedRadius + root.outlineGap * (1 - root.outlineGapScale) / 2 + root.outlineGap * root.outlineGapScale startX: path.inset + root.horizontalPadding - root.clampedRadius + path.outlineGap * (1 - path.outlineGapScale) / 2 + path.outlineGap * path.outlineGapScale
strokeColor: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : DynamicColors.palette.m3outline) startY: path.inset
strokeColor: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline)
strokeWidth: root.activeFocus ? 2 : 1 strokeWidth: root.activeFocus ? 2 : 1
Behavior on outlineGapScale {
Anim {
type: Anim.DefaultEffects
}
}
Behavior on strokeColor { Behavior on strokeColor {
CAnim { CAnim {
} }
@@ -217,54 +221,56 @@ TextFieldBase {
} }
PathLine { PathLine {
x: bg.width - root.clampedRadius x: bg.width - path.inset - root.clampedRadius
y: path.inset
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: bg.width x: bg.width - path.inset
y: root.clampedRadius y: path.inset + root.clampedRadius
} }
PathLine { PathLine {
x: bg.width x: bg.width - path.inset
y: bg.height - root.clampedRadius y: bg.height - path.inset - root.clampedRadius
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: bg.width - root.clampedRadius x: bg.width - path.inset - root.clampedRadius
y: bg.height y: bg.height - path.inset
} }
PathLine { PathLine {
x: root.clampedRadius x: path.inset + root.clampedRadius
y: bg.height y: bg.height - path.inset
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: 0 x: path.inset
y: bg.height - root.clampedRadius y: bg.height - path.inset - root.clampedRadius
} }
PathLine { PathLine {
x: 0 x: path.inset
y: root.clampedRadius y: path.inset + root.clampedRadius
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: root.clampedRadius x: path.inset + root.clampedRadius
y: 0 y: path.inset
} }
PathLine { PathLine {
x: root.horizontalPadding - root.clampedRadius + root.outlineGap * (1 - root.outlineGapScale) / 2 x: path.inset + root.horizontalPadding - root.clampedRadius / 2 + path.outlineGap * (1 - path.outlineGapScale) / 2
y: path.inset
} }
} }
} }
@@ -274,7 +280,7 @@ TextFieldBase {
id: filledComp id: filledComp
CustomRect { CustomRect {
color: root.activeFocus ? DynamicColors.tPalette.m3surfaceContainerHighest : DynamicColors.tPalette.m3surfaceContainerHigh color: root.activeFocus ? Colors.tPalette.m3surfaceContainerHighest : Colors.tPalette.m3surfaceContainerHigh
topLeftRadius: root.clampedRadius topLeftRadius: root.clampedRadius
topRightRadius: root.clampedRadius topRightRadius: root.clampedRadius
@@ -282,7 +288,7 @@ TextFieldBase {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : DynamicColors.palette.m3outline) color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline)
implicitHeight: root.activeFocus ? 2 : 1 implicitHeight: root.activeFocus ? 2 : 1
Behavior on implicitHeight { Behavior on implicitHeight {
+6 -5
View File
@@ -1,15 +1,16 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import qs.Config import ZShell.Config
import qs.Services
TextInput { TextInput {
renderType: Text.NativeRendering renderType: Text.NativeRendering
selectedTextColor: DynamicColors.palette.m3onSecondaryContainer selectedTextColor: Colors.palette.m3onSecondaryContainer
selectionColor: DynamicColors.tPalette.colSecondaryContainer selectionColor: Colors.tPalette.colSecondaryContainer
font { font {
family: Appearance?.font.family.sans ?? "sans-serif" family: Config.appearance?.font.family.sans ?? "sans-serif"
hintingPreference: Font.PreferFullHinting hintingPreference: Font.PreferFullHinting
pixelSize: Appearance?.font.size.normal ?? 15 pixelSize: Config.appearance?.font.size.normal ?? 15
} }
} }
+3 -2
View File
@@ -1,13 +1,14 @@
import QtQuick import QtQuick
import QtQuick.Effects import QtQuick.Effects
import qs.Config import ZShell.Config
import qs.Services
RectangularShadow { RectangularShadow {
property real dp: [0, 1, 3, 6, 8, 12][level] property real dp: [0, 1, 3, 6, 8, 12][level]
property int level property int level
blur: (dp * 5) ** 0.7 blur: (dp * 5) ** 0.7
color: Qt.alpha(DynamicColors.palette.m3shadow, 0.7) color: Qt.alpha(Colors.palette.m3shadow, 0.7)
offset.y: dp / 2 offset.y: dp / 2
spread: -dp * 0.3 + (dp * 0.1) ** 2 spread: -dp * 0.3 + (dp * 0.1) ** 2
+1 -1
View File
@@ -1,6 +1,6 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Config import ZShell.Config
Image { Image {
id: root id: root
+1 -1
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
BaseStyledSlider { BaseStyledSlider {
id: root id: root
+1 -1
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
BaseStyledSlider { BaseStyledSlider {
id: root id: root
+9 -8
View File
@@ -1,5 +1,6 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Services
ButtonBase { ButtonBase {
id: root id: root
@@ -7,8 +8,8 @@ ButtonBase {
property alias icon: label.text property alias icon: label.text
readonly property alias label: label readonly property alias label: label
activeColor: type === IconButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary activeColor: type === IconButton.Filled ? Colors.palette.m3primary : Colors.palette.m3secondary
activeOnColor: type === IconButton.Filled ? DynamicColors.palette.m3onPrimary : type === IconButton.Tonal ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3primary activeOnColor: type === IconButton.Filled ? Colors.palette.m3onPrimary : type === IconButton.Tonal ? Colors.palette.m3onSecondary : Colors.palette.m3primary
implicitHeight: { implicitHeight: {
const h = label.implicitHeight + padding * 2; const h = label.implicitHeight + padding * 2;
if (h % 2 !== 0) if (h % 2 !== 0)
@@ -18,15 +19,15 @@ ButtonBase {
implicitWidth: implicitHeight implicitWidth: implicitHeight
inactiveColor: { inactiveColor: {
if (!isToggle && type === IconButton.Filled) if (!isToggle && type === IconButton.Filled)
return DynamicColors.palette.m3primary; return Colors.palette.m3primary;
return type === IconButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer; return type === IconButton.Filled ? Colors.tPalette.m3surfaceContainer : Colors.palette.m3secondaryContainer;
} }
inactiveOnColor: { inactiveOnColor: {
if (!isToggle && type === IconButton.Filled) if (!isToggle && type === IconButton.Filled)
return DynamicColors.palette.m3onPrimary; return Colors.palette.m3onPrimary;
return type === IconButton.Tonal ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurfaceVariant; return type === IconButton.Tonal ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onSurfaceVariant;
} }
padding: type === IconButton.Text ? Appearance.padding.extraSmall / 2 : Appearance.padding.small padding: type === IconButton.Text ? Tokens.padding.extraSmall / 2 : Tokens.padding.small
MaterialIcon { MaterialIcon {
id: label id: label
+13 -12
View File
@@ -1,6 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Config import ZShell.Config
import qs.Services
ButtonBase { ButtonBase {
id: root id: root
@@ -10,34 +11,34 @@ ButtonBase {
readonly property alias label: label readonly property alias label: label
property alias text: label.text property alias text: label.text
activeColor: type === TextButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary activeColor: type === TextButton.Filled ? Colors.palette.m3primary : Colors.palette.m3secondary
activeOnColor: { activeOnColor: {
if (type === TextButton.Text) if (type === TextButton.Text)
return DynamicColors.palette.m3primary; return Colors.palette.m3primary;
return type === TextButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondary; return type === TextButton.Filled ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondary;
} }
horizontalPadding: Appearance.padding.larger horizontalPadding: Tokens.padding.larger
implicitHeight: row.implicitHeight + verticalPadding * 2 implicitHeight: row.implicitHeight + verticalPadding * 2
implicitWidth: row.implicitWidth + horizontalPadding * 2 implicitWidth: row.implicitWidth + horizontalPadding * 2
inactiveColor: { inactiveColor: {
if (!isToggle && type === TextButton.Filled) if (!isToggle && type === TextButton.Filled)
return DynamicColors.palette.m3primary; return Colors.palette.m3primary;
return type === TextButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer; return type === TextButton.Filled ? Colors.tPalette.m3surfaceContainer : Colors.palette.m3secondaryContainer;
} }
inactiveOnColor: { inactiveOnColor: {
if (!isToggle && type === TextButton.Filled) if (!isToggle && type === TextButton.Filled)
return DynamicColors.palette.m3onPrimary; return Colors.palette.m3onPrimary;
if (type === TextButton.Text) if (type === TextButton.Text)
return DynamicColors.palette.m3primary; return Colors.palette.m3primary;
return type === TextButton.Filled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer; return type === TextButton.Filled ? Colors.palette.m3onSurface : Colors.palette.m3onSecondaryContainer;
} }
verticalPadding: Appearance.padding.small verticalPadding: Tokens.padding.small
RowLayout { RowLayout {
id: row id: row
anchors.centerIn: parent anchors.centerIn: parent
spacing: Appearance.spacing.small spacing: Tokens.spacing.small
MaterialIcon { MaterialIcon {
id: iconLabel id: iconLabel
+3 -2
View File
@@ -1,7 +1,8 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import M3Shapes import M3Shapes
import qs.Config import ZShell.Config
import qs.Services
MaterialShape { MaterialShape {
id: root id: root
@@ -48,7 +49,7 @@ MaterialShape {
return [pos, vel]; return [pos, vel];
} }
color: DynamicColors.palette.m3primary color: Colors.palette.m3primary
implicitSize: 38 implicitSize: 38
toShape: shapes[0] toShape: shapes[0]
+151 -132
View File
@@ -1,12 +1,13 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Services
Item { Item {
id: root id: root
property alias anim: marqueeAnim property alias anim: marqueeAnim
property bool animate: false property bool animate: false
property color color: DynamicColors.palette.m3onSurface property color color: Colors.palette.m3onSurface
property int fadeStrengthAnimMs: 180 property int fadeStrengthAnimMs: 180
property real fadeStrengthIdle: 0.0 property real fadeStrengthIdle: 0.0
property real fadeStrengthMoving: 1.0 property real fadeStrengthMoving: 1.0
@@ -17,13 +18,14 @@ Item {
property real leftFadeStrength: overflowing && leftFadeEnabled ? fadeStrengthMoving : fadeStrengthIdle property real leftFadeStrength: overflowing && leftFadeEnabled ? fadeStrengthMoving : fadeStrengthIdle
property int leftFadeWidth: 28 property int leftFadeWidth: 28
property bool marqueeEnabled: true property bool marqueeEnabled: true
readonly property bool overflowing: metrics.width > root.width readonly property bool overflowing: metrics.width > content.width
property int pauseMs: 1200 property int pauseMs: 1200
property real pixelsPerSecond: 40 property real pixelsPerSecond: 40
property real rightFadeStrength: overflowing ? fadeStrengthMoving : fadeStrengthIdle property real rightFadeStrength: overflowing ? fadeStrengthMoving : fadeStrengthIdle
property int rightFadeWidth: 28 property int rightFadeWidth: 28
property bool sliding: false property bool sliding: false
property alias text: elideText.text property alias text: elideText.text
property bool vertical: false
function durationForDistance(px): int { function durationForDistance(px): int {
return Math.max(1, Math.round(Math.abs(px) / root.pixelsPerSecond * 1000)); return Math.max(1, Math.round(Math.abs(px) / root.pixelsPerSecond * 1000));
@@ -40,8 +42,9 @@ Item {
} }
} }
clip: true clip: false
implicitHeight: elideText.implicitHeight implicitHeight: vertical ? elideText.implicitWidth : elideText.implicitHeight
implicitWidth: vertical ? elideText.implicitHeight : elideText.implicitWidth
Behavior on leftFadeStrength { Behavior on leftFadeStrength {
Anim { Anim {
@@ -52,171 +55,187 @@ Item {
} }
} }
onHeightChanged: resetMarquee()
onTextChanged: resetMarquee() onTextChanged: resetMarquee()
onVerticalChanged: resetMarquee()
onVisibleChanged: if (!visible) onVisibleChanged: if (!visible)
resetMarquee() resetMarquee()
onWidthChanged: resetMarquee() onWidthChanged: resetMarquee()
TextMetrics {
id: metrics
font: elideText.font
text: elideText.text
}
CustomText {
id: elideText
anchors.verticalCenter: parent.verticalCenter
animate: root.animate
animateProp: "scale,opacity"
color: root.color
elide: Text.ElideNone
visible: !root.overflowing
width: root.width
}
Item { Item {
id: marqueeViewport id: content
anchors.fill: parent anchors.centerIn: parent
clip: true height: root.vertical ? root.width : root.height
layer.enabled: true width: root.vertical ? root.height : root.width
visible: root.overflowing
layer.effect: OpacityMask { transform: Rotation {
maskSource: rightFadeMask angle: root.vertical ? -90 : 0
origin.x: content.width / 2
origin.y: content.height / 2
}
TextMetrics {
id: metrics
font: elideText.font
text: elideText.text
}
CustomText {
id: elideText
anchors.verticalCenter: parent.verticalCenter
animate: root.animate
animateProp: "scale,opacity"
color: root.color
elide: Text.ElideNone
visible: !root.overflowing
width: content.width
} }
Item { Item {
id: strip id: marqueeViewport
anchors.verticalCenter: parent.verticalCenter anchors.fill: parent
height: t1.implicitHeight clip: false
width: t1.width + root.gap + t2.width layer.enabled: true
x: 0 visible: root.overflowing
CustomText { layer.effect: OpacityMask {
id: t1 maskSource: rightFadeMask
animate: root.animate
animateProp: "opacity"
color: root.color
font.pointSize: elideText.font.pointSize
text: elideText.text
} }
CustomText { Item {
id: t2 id: strip
animate: root.animate anchors.verticalCenter: parent.verticalCenter
animateProp: "opacity" height: t1.implicitHeight
color: root.color width: t1.width + root.gap + t2.width
font.pointSize: elideText.font.pointSize x: 0
text: t1.text
x: t1.width + root.gap
}
}
SequentialAnimation { CustomText {
id: marqueeAnim id: t1
running: false animate: root.animate
animateProp: "opacity"
color: root.color
font.pointSize: elideText.font.pointSize
text: elideText.text
}
onFinished: pauseTimer.restart() CustomText {
id: t2
ScriptAction { animate: root.animate
script: { animateProp: "opacity"
root.sliding = true; color: root.color
root.leftFadeEnabled = true; font.pointSize: elideText.font.pointSize
text: t1.text
x: t1.width + root.gap
} }
} }
Anim { SequentialAnimation {
duration: root.durationForDistance(t1.width) id: marqueeAnim
easing.bezierCurve: Easing.Linear
easing.type: Easing.Linear
from: 0
property: "x"
target: strip
to: -t1.width
}
ScriptAction { running: false
script: {
root.leftFadeEnabled = false; onFinished: pauseTimer.restart()
ScriptAction {
script: {
root.sliding = true;
root.leftFadeEnabled = true;
}
}
Anim {
duration: root.durationForDistance(t1.width)
easing.bezierCurve: Easing.Linear
easing.type: Easing.Linear
from: 0
property: "x"
target: strip
to: -t1.width
}
ScriptAction {
script: {
root.leftFadeEnabled = false;
}
}
Anim {
duration: root.durationForDistance(root.gap)
easing.bezierCurve: Easing.Linear
easing.type: Easing.Linear
from: -t1.width
property: "x"
target: strip
to: -(t1.width + root.gap)
}
ScriptAction {
script: {
root.sliding = false;
strip.x = 0;
}
} }
} }
Anim { Timer {
duration: root.durationForDistance(root.gap) id: pauseTimer
easing.bezierCurve: Easing.Linear
easing.type: Easing.Linear
from: -t1.width
property: "x"
target: strip
to: -(t1.width + root.gap)
}
ScriptAction { interval: root.pauseMs
script: { repeat: false
root.sliding = false; running: true
strip.x = 0;
onTriggered: {
if (root.marqueeEnabled)
marqueeAnim.start();
} }
} }
} }
Timer { Rectangle {
id: pauseTimer id: rightFadeMask
interval: root.pauseMs readonly property real fadeStartPos: {
repeat: false const w = Math.max(1, width);
running: true return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w));
onTriggered: {
if (root.marqueeEnabled)
marqueeAnim.start();
} }
} readonly property real leftFadeEndPos: {
} const w = Math.max(1, width);
return Math.max(0, Math.min(1, root.leftFadeWidth / w));
Rectangle {
id: rightFadeMask
readonly property real fadeStartPos: {
const w = Math.max(1, width);
return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w));
}
readonly property real leftFadeEndPos: {
const w = Math.max(1, width);
return Math.max(0, Math.min(1, root.leftFadeWidth / w));
}
anchors.fill: marqueeViewport
layer.enabled: true
visible: false
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength)
position: 0.0
} }
GradientStop { anchors.fill: marqueeViewport
color: Qt.rgba(1, 1, 1, 1.0) layer.enabled: true
position: rightFadeMask.leftFadeEndPos visible: false
}
GradientStop { gradient: Gradient {
color: Qt.rgba(1, 1, 1, 1.0) orientation: Gradient.Horizontal
position: rightFadeMask.fadeStartPos
}
GradientStop { GradientStop {
color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength) color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength)
position: 1.0 position: 0.0
}
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0)
position: rightFadeMask.leftFadeEndPos
}
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0)
position: rightFadeMask.fadeStartPos
}
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength)
position: 1.0
}
} }
} }
} }
+4 -3
View File
@@ -1,11 +1,12 @@
import qs.Config import ZShell.Config
import qs.Services
CustomText { CustomText {
id: root id: root
readonly property list<int> allowed: [20, 24, 40, 48] readonly property list<int> allowed: [20, 24, 40, 48]
property real fill: 0 property real fill: 0
property int grade: DynamicColors.light ? 0 : -25 property int grade: Colors.light ? 0 : -25
readonly property int opsz: clampOpsz(optical) readonly property int opsz: clampOpsz(optical)
property int optical: fontInfo.pixelSize property int optical: fontInfo.pixelSize
@@ -16,7 +17,7 @@ CustomText {
} }
font.family: "Material Symbols Rounded" font.family: "Material Symbols Rounded"
font.pointSize: Appearance.font.size.larger font.pointSize: Tokens.font.size.larger
font.variableAxes: ({ font.variableAxes: ({
FILL: fill, FILL: fill,
GRAD: grade, GRAD: grade,
+20 -19
View File
@@ -3,8 +3,9 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import qs.Config import ZShell.Config
import qs.Drawers import qs.Drawers
import qs.Services
MouseArea { MouseArea {
id: root id: root
@@ -77,7 +78,7 @@ MouseArea {
implicitHeight: column.implicitHeight + column.anchors.margins * 2 implicitHeight: column.implicitHeight + column.anchors.margins * 2
implicitWidth: Math.max(200, column.implicitWidth + column.anchors.margins * 2) implicitWidth: Math.max(200, column.implicitWidth + column.anchors.margins * 2)
level: 2 level: 2
radius: Appearance.rounding.medium radius: Tokens.rounding.medium
x: { x: {
watcher.transform; watcher.transform;
const item = root.attachTo; const item = root.attachTo;
@@ -107,15 +108,15 @@ MouseArea {
CustomRect { CustomRect {
anchors.fill: parent anchors.fill: parent
color: DynamicColors.palette.m3surfaceContainerLow color: Colors.palette.m3surfaceContainerLow
radius: parent.radius radius: parent.radius
ColumnLayout { ColumnLayout {
id: column id: column
anchors.fill: parent anchors.fill: parent
anchors.margins: Appearance.padding.extraSmall anchors.margins: Tokens.padding.extraSmall
spacing: Appearance.spacing.extraSmall spacing: Tokens.spacing.extraSmall
Repeater { Repeater {
id: repeater id: repeater
@@ -125,15 +126,15 @@ MouseArea {
CustomRect { CustomRect {
id: item id: item
readonly property bool active: modelData === root.active readonly property bool active: modelData === root?.active
required property int index required property int index
required property MenuItem modelData required property MenuItem modelData
Layout.fillWidth: true Layout.fillWidth: true
color: Qt.alpha(DynamicColors.palette.m3tertiaryContainer, active ? 1 : 0) color: Qt.alpha(Colors.palette.m3tertiaryContainer, active ? 1 : 0)
implicitHeight: menuOptionRow.implicitHeight + Appearance.padding.larger * 2 implicitHeight: menuOptionRow.implicitHeight + Tokens.padding.larger * 2
implicitWidth: menuOptionRow.implicitWidth + Appearance.padding.larger * 2 implicitWidth: menuOptionRow.implicitWidth + Tokens.padding.larger * 2
radius: Appearance.rounding.small radius: Tokens.rounding.small
Behavior on radius { Behavior on radius {
Anim { Anim {
@@ -141,7 +142,7 @@ MouseArea {
} }
StateLayer { StateLayer {
color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.palette.m3onSurface color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
enabled: root.expanded enabled: root.expanded
onClicked: { onClicked: {
@@ -156,30 +157,30 @@ MouseArea {
id: menuOptionRow id: menuOptionRow
anchors.fill: parent anchors.fill: parent
anchors.margins: Appearance.padding.larger anchors.margins: Tokens.padding.larger
spacing: Appearance.spacing.small spacing: Tokens.spacing.small
MaterialIcon { MaterialIcon {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.palette.m3onSurfaceVariant color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant
text: item.modelData.icon text: item.modelData?.icon ?? ""
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true Layout.fillWidth: true
color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.palette.m3onSurface color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
text: item.modelData.text text: item.modelData?.text ?? ""
} }
Loader { Loader {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
active: item.modelData.trailingIcon.length > 0 active: item.modelData?.trailingIcon.length > 0
asynchronous: true asynchronous: true
visible: active visible: active
sourceComponent: MaterialIcon { sourceComponent: MaterialIcon {
color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.palette.m3onSurfaceVariant color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant
text: item.modelData.trailingIcon text: item.modelData.trailingIcon
} }
} }
+13 -12
View File
@@ -1,5 +1,6 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Services
TextFieldBase { TextFieldBase {
id: root id: root
@@ -8,17 +9,17 @@ TextFieldBase {
readonly property alias clearIcon: clearIcon readonly property alias clearIcon: clearIcon
readonly property alias searchIcon: searchIcon readonly property alias searchIcon: searchIcon
bottomPadding: Appearance.padding.large bottomPadding: Tokens.padding.large
leftPadding: searchIcon.width + searchIcon.anchors.leftMargin + Appearance.spacing.small leftPadding: searchIcon.width + searchIcon.anchors.leftMargin + Tokens.spacing.small
rightPadding: clearIcon.width + clearIcon.anchors.rightMargin + Appearance.spacing.small rightPadding: clearIcon.width + clearIcon.anchors.rightMargin + Tokens.spacing.small
topPadding: Appearance.padding.large topPadding: Tokens.padding.large
background: CustomRect { background: CustomRect {
id: bg id: bg
anchors.fill: parent anchors.fill: parent
color: DynamicColors.tPalette.m3surfaceContainer color: Colors.tPalette.m3surfaceContainer
radius: Appearance.rounding.full radius: Tokens.rounding.full
StateLayer { StateLayer {
id: stateLayer id: stateLayer
@@ -58,10 +59,10 @@ TextFieldBase {
id: searchIcon id: searchIcon
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Appearance.padding.large anchors.leftMargin: Tokens.padding.large
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3onSurfaceVariant color: Colors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large font.pointSize: Tokens.font.size.large
text: "search" text: "search"
} }
@@ -69,12 +70,12 @@ TextFieldBase {
id: clearIcon id: clearIcon
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Appearance.padding.larger anchors.rightMargin: Tokens.padding.larger
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
enabled: root.text enabled: root.text
icon: "clear" icon: "clear"
opacity: root.text ? 1 : 0 opacity: root.text ? 1 : 0
radius: Appearance.rounding.full radius: Tokens.rounding.full
radiusMorph: false radiusMorph: false
stateLayer.hoverEnabled: enabled stateLayer.hoverEnabled: enabled
type: IconButton.Text type: IconButton.Text
+5 -4
View File
@@ -3,7 +3,8 @@ import QtQuick.Shapes
import ZShell import ZShell
import ZShell.Components import ZShell.Components
import qs.Helpers import qs.Helpers
import qs.Config import ZShell.Config
import qs.Services
MouseArea { MouseArea {
id: root id: root
@@ -79,8 +80,8 @@ MouseArea {
id: rippleAnim id: rippleAnim
alwaysRunToEnd: true alwaysRunToEnd: true
duration: Appearance.anim.durations.expressiveSlowEffects * 2 duration: Tokens.anim.durations.expressiveSlowEffects * 2
easing.bezierCurve: Appearance.anim.curves.standard easing.bezierCurve: Tokens.anim.curves.standard
property: "circleRadius" property: "circleRadius"
target: root target: root
to: root.endRadius to: root.endRadius
@@ -101,7 +102,7 @@ MouseArea {
anchors.fill: parent anchors.fill: parent
bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0 bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0
bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0 bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0
color: DynamicColors.palette.m3onSurface color: Colors.palette.m3onSurface
opacity: root.stateOpacity opacity: root.stateOpacity
// Pick up radius from parent if it has one (parent can be anything with radius props) // Pick up radius from parent if it has one (parent can be anything with radius props)
// qmllint disable missing-property // qmllint disable missing-property
+12 -11
View File
@@ -1,5 +1,6 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Services
ButtonBase { ButtonBase {
id: root id: root
@@ -7,28 +8,28 @@ ButtonBase {
readonly property alias label: label readonly property alias label: label
property alias text: label.text property alias text: label.text
activeColor: type === TextButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary activeColor: type === TextButton.Filled ? Colors.palette.m3primary : Colors.palette.m3secondary
activeOnColor: { activeOnColor: {
if (type === TextButton.Text) if (type === TextButton.Text)
return DynamicColors.palette.m3primary; return Colors.palette.m3primary;
return type === TextButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondary; return type === TextButton.Filled ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondary;
} }
horizontalPadding: Appearance.padding.normal horizontalPadding: Tokens.padding.normal
implicitHeight: label.implicitHeight + verticalPadding * 2 implicitHeight: label.implicitHeight + verticalPadding * 2
implicitWidth: label.implicitWidth + horizontalPadding * 2 implicitWidth: label.implicitWidth + horizontalPadding * 2
inactiveColor: { inactiveColor: {
if (!isToggle && type === TextButton.Filled) if (!isToggle && type === TextButton.Filled)
return DynamicColors.palette.m3primary; return Colors.palette.m3primary;
return type === TextButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer; return type === TextButton.Filled ? Colors.tPalette.m3surfaceContainer : Colors.palette.m3secondaryContainer;
} }
inactiveOnColor: { inactiveOnColor: {
if (!isToggle && type === TextButton.Filled) if (!isToggle && type === TextButton.Filled)
return DynamicColors.palette.m3onPrimary; return Colors.palette.m3onPrimary;
if (type === TextButton.Text) if (type === TextButton.Text)
return DynamicColors.palette.m3primary; return Colors.palette.m3primary;
return type === TextButton.Filled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer; return type === TextButton.Filled ? Colors.palette.m3onSurface : Colors.palette.m3onSecondaryContainer;
} }
verticalPadding: Appearance.padding.small verticalPadding: Tokens.padding.small
CustomText { CustomText {
id: label id: label
+9 -8
View File
@@ -1,19 +1,20 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Config import ZShell.Config
import qs.Services
TextField { TextField {
id: root id: root
color: DynamicColors.palette.m3onSurface color: Colors.palette.m3onSurface
cursorVisible: !readOnly cursorVisible: !readOnly
font.pointSize: Appearance.font.size.small font.pointSize: Tokens.font.size.small
implicitHeight: contentHeight + topPadding + bottomPadding implicitHeight: contentHeight + topPadding + bottomPadding
implicitWidth: contentWidth + leftPadding + rightPadding implicitWidth: contentWidth + leftPadding + rightPadding
placeholderTextColor: DynamicColors.palette.m3onSurfaceVariant // No anim cause placeholder is custom placeholderTextColor: Colors.palette.m3onSurfaceVariant // No anim cause placeholder is custom
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
selectedTextColor: color selectedTextColor: color
selectionColor: Qt.alpha(DynamicColors.palette.m3primary, 0.4) selectionColor: Qt.alpha(Colors.palette.m3primary, 0.4)
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
Behavior on color { Behavior on color {
@@ -32,10 +33,10 @@ TextField {
property bool disableBlink property bool disableBlink
color: DynamicColors.palette.m3primary color: Colors.palette.m3primary
implicitHeight: root.cursorRectangle.height implicitHeight: root.cursorRectangle.height
implicitWidth: 1.5 implicitWidth: 1.5
radius: Appearance.rounding.large radius: Tokens.rounding.large
x: root.cursorRectangle.x x: root.cursorRectangle.x
y: root.cursorRectangle.y y: root.cursorRectangle.y
@@ -46,7 +47,7 @@ TextField {
} }
Behavior on x { Behavior on x {
Anim { Anim {
duration: Appearance.anim.durations.expressiveFastEffects duration: Tokens.anim.durations.expressiveFastEffects
easing.bezierCurve: [0.2, 1, 0.21, 1, 1, 1] easing.bezierCurve: [0.2, 1, 0.21, 1, 1, 1]
} }
} }
+36 -35
View File
@@ -2,7 +2,8 @@ import ZShell
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Components import qs.Components
import qs.Config import ZShell.Config
import qs.Services
CustomRect { CustomRect {
id: root id: root
@@ -12,27 +13,27 @@ CustomRect {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
border.color: { border.color: {
let colour = DynamicColors.palette.m3outlineVariant; let colour = Colors.palette.m3outlineVariant;
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
colour = DynamicColors.palette.m3success; colour = Colors.palette.m3success;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
colour = DynamicColors.palette.m3secondaryContainer; colour = Colors.palette.m3secondaryContainer;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
colour = DynamicColors.palette.m3error; colour = Colors.palette.m3error;
return Qt.alpha(colour, 0.3); return Qt.alpha(colour, 0.3);
} }
border.width: 1 border.width: 1
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3successContainer; return Colors.palette.m3successContainer;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return DynamicColors.palette.m3secondary; return Colors.palette.m3secondary;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return DynamicColors.palette.m3errorContainer; return Colors.palette.m3errorContainer;
return DynamicColors.palette.m3surface; return Colors.palette.m3surface;
} }
implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2 implicitHeight: layout.implicitHeight + Tokens.padding.smaller * 2
radius: Appearance.rounding.normal radius: Tokens.rounding.normal
Behavior on border.color { Behavior on border.color {
CAnim { CAnim {
@@ -51,24 +52,24 @@ CustomRect {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal anchors.leftMargin: Tokens.padding.normal
anchors.margins: Appearance.padding.smaller anchors.margins: Tokens.padding.smaller
anchors.rightMargin: Appearance.padding.normal anchors.rightMargin: Tokens.padding.normal
spacing: Appearance.spacing.normal spacing: Tokens.spacing.normal
CustomRect { CustomRect {
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3success; return Colors.palette.m3success;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return DynamicColors.palette.m3secondaryContainer; return Colors.palette.m3secondaryContainer;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return DynamicColors.palette.m3error; return Colors.palette.m3error;
return DynamicColors.palette.m3surfaceContainerHigh; return Colors.palette.m3surfaceContainerHigh;
} }
implicitHeight: icon.implicitHeight + Appearance.padding.smaller * 2 implicitHeight: icon.implicitHeight + Tokens.padding.smaller * 2
implicitWidth: implicitHeight implicitWidth: implicitHeight
radius: Appearance.rounding.normal radius: Tokens.rounding.normal
MaterialIcon { MaterialIcon {
id: icon id: icon
@@ -76,14 +77,14 @@ CustomRect {
anchors.centerIn: parent anchors.centerIn: parent
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3onSuccess; return Colors.palette.m3onSuccess;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return DynamicColors.palette.m3onSecondaryContainer; return Colors.palette.m3onSecondaryContainer;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return DynamicColors.palette.m3onError; return Colors.palette.m3onError;
return DynamicColors.palette.m3onSurfaceVariant; return Colors.palette.m3onSurfaceVariant;
} }
font.pointSize: Math.round(Appearance.font.size.large * 1.2) font.pointSize: Math.round(Tokens.font.size.large * 1.2)
text: root.modelData.icon text: root.modelData.icon
} }
} }
@@ -98,15 +99,15 @@ CustomRect {
Layout.fillWidth: true Layout.fillWidth: true
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3onSuccessContainer; return Colors.palette.m3onSuccessContainer;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return DynamicColors.palette.m3onSecondary; return Colors.palette.m3onSecondary;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return DynamicColors.palette.m3onErrorContainer; return Colors.palette.m3onErrorContainer;
return DynamicColors.palette.m3onSurface; return Colors.palette.m3onSurface;
} }
elide: Text.ElideRight elide: Text.ElideRight
font.pointSize: Appearance.font.size.normal font.pointSize: Tokens.font.size.normal
text: root.modelData.title text: root.modelData.title
} }
@@ -114,12 +115,12 @@ CustomRect {
Layout.fillWidth: true Layout.fillWidth: true
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3onSuccessContainer; return Colors.palette.m3onSuccessContainer;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return DynamicColors.palette.m3onSecondary; return Colors.palette.m3onSecondary;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return DynamicColors.palette.m3onErrorContainer; return Colors.palette.m3onErrorContainer;
return DynamicColors.palette.m3onSurface; return Colors.palette.m3onSurface;
} }
elide: Text.ElideRight elide: Text.ElideRight
opacity: 0.8 opacity: 0.8
+7 -7
View File
@@ -4,13 +4,13 @@ import ZShell
import Quickshell import Quickshell
import QtQuick import QtQuick
import qs.Components import qs.Components
import qs.Config import ZShell.Config
Item { Item {
id: root id: root
property bool flag property bool flag
readonly property int spacing: Appearance.spacing.small readonly property int spacing: Tokens.spacing.small
implicitHeight: { implicitHeight: {
let h = -spacing; let h = -spacing;
@@ -21,7 +21,7 @@ Item {
} }
return h; return h;
} }
implicitWidth: Config.utilities.sizes.toastWidth - Appearance.padding.normal * 2 implicitWidth: Config.utilities.sizes.toastWidth - Tokens.padding.normal * 2
Repeater { Repeater {
id: repeater id: repeater
@@ -81,8 +81,8 @@ Item {
Behavior on anchors.bottomMargin { Behavior on anchors.bottomMargin {
Anim { Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Tokens.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Tokens.anim.curves.expressiveDefaultSpatial
} }
} }
Behavior on opacity { Behavior on opacity {
@@ -104,8 +104,8 @@ Item {
Anim { Anim {
id: initAnim id: initAnim
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Tokens.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Tokens.anim.curves.expressiveDefaultSpatial
from: 0 from: 0
properties: "opacity,scale" properties: "opacity,scale"
target: toast target: toast
+3 -2
View File
@@ -1,12 +1,13 @@
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import qs.Config import ZShell.Config
import qs.Services
Shape { Shape {
id: root id: root
property real amplitude: 3 property real amplitude: 3
property color color: DynamicColors.palette.m3surfaceContainer property color color: Colors.palette.m3surfaceContainer
readonly property real waveHeight: amplitude * 2 readonly property real waveHeight: amplitude * 2
property int waves: 4 property int waves: 4
-13
View File
@@ -1,13 +0,0 @@
import Quickshell.Io
JsonObject {
property Accents accents: Accents {
}
component Accents: JsonObject {
property string primary: "#4080ff"
property string primaryAlt: "#60a0ff"
property string warning: "#ff6b6b"
property string warningAlt: "#ff8787"
}
}
-13
View File
@@ -1,13 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
readonly property AppearanceConf.Anim anim: Config.appearance.anim
readonly property AppearanceConf.Deform deform: Config.appearance.deform
readonly property AppearanceConf.FontStuff font: Config.appearance.font
readonly property AppearanceConf.Padding padding: Config.appearance.padding
readonly property AppearanceConf.Rounding rounding: Config.appearance.rounding
readonly property AppearanceConf.Spacing spacing: Config.appearance.spacing
readonly property AppearanceConf.Transparency transparency: Config.appearance.transparency
}
-116
View File
@@ -1,116 +0,0 @@
import Quickshell.Io
JsonObject {
property Anim anim: Anim {
}
property Deform deform: Deform {
}
property FontStuff font: FontStuff {
}
property Padding padding: Padding {
}
property Rounding rounding: Rounding {
}
property Spacing spacing: Spacing {
}
property Transparency transparency: Transparency {
}
component Anim: JsonObject {
property AnimCurves curves: AnimCurves {
}
property AnimDurations durations: AnimDurations {
}
property real mediaGifSpeedAdjustment: 300
property real sessionGifSpeed: 0.7
}
component AnimCurves: JsonObject {
property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
property list<real> expressiveDefaultEffects: [0.34, 0.8, 0.34, 1, 1, 1]
property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1]
property list<real> expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1]
property list<real> expressiveFastEffects: [0.31, 0.94, 0.34, 1, 1, 1]
property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1]
property list<real> expressiveSlowEffects: [0.34, 0.88, 0.34, 1, 1, 1]
property list<real> expressiveSlowSpatial: [0.39, 1.29, 0.35, 0.98, 1, 1]
property list<real> standard: [0.2, 0, 0, 1, 1, 1]
property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
}
component AnimDurations: JsonObject {
property int expressiveDefaultSpatial: 500 * scale
property int expressiveEffects: 200 * scale
property int expressiveFastEffects: 150 * scale
property int expressiveFastSpatial: 350 * scale
property int expressiveSlowEffects: 300 * scale
property int extraLarge: 1000 * scale
property int large: 600 * scale
property int normal: 400 * scale
property real scale: 1
property int small: 200 * scale
}
component Deform: JsonObject {
property real scale: 1
}
component FontFamily: JsonObject {
property string clock: "Rubik"
property string material: "Material Symbols Rounded"
property string mono: "CaskaydiaCove NF"
property string sans: "Segoe UI Variable Text"
}
component FontSize: JsonObject {
property int extraLarge: 28 * scale
property int large: 18 * scale
property int larger: 16 * scale
property int medium: 14 * scale
property int normal: 13 * scale
property real scale: 1
property int small: 11 * scale
property int smaller: 12 * scale
}
component FontStuff: JsonObject {
property FontFamily family: FontFamily {
}
property FontSize size: FontSize {
}
}
component Padding: JsonObject {
property int extraLarge: 28 * scale
property int extraLargeIncreased: 32 * scale
property int extraSmall: 4 * scale
property int large: 16 * scale
property int largeIncreased: 20 * scale
property int larger: 12 * scale
property int normal: 8 * scale
property real scale: 1
property int small: 5 * scale
property int smaller: 7 * scale
property int smallest: 2 * scale
}
component Rounding: JsonObject {
property int extraSmall: 4 * scale
property int full: 1000 * scale
property int large: 24 * scale
property int medium: 16 * scale
property int normal: 18 * scale
property real scale: 1
property int small: 12 * scale
property int smallest: 8 * scale
}
component Spacing: JsonObject {
property int extraSmall: 4 * scale
property int large: 20 * scale
property int larger: 16 * scale
property int normal: 12 * scale
property real scale: 1
property int small: 8 * scale
property int smaller: 10 * scale
}
component Transparency: JsonObject {
property real base: 0.85
property bool enabled: false
property real layers: 0.4
}
}
-14
View File
@@ -1,14 +0,0 @@
import Quickshell.Io
import qs.Config
JsonObject {
property bool enabled: true
property int wallFadeDuration: MaterialEasing.standardTime
property real alignX: 0.5
property real alignY: 0.5
property real zoom: 1.0
property real sourceClipX: 0
property real sourceClipY: 0
property real sourceClipW: 0
property real sourceClipH: 0
}
-85
View File
@@ -1,85 +0,0 @@
import Quickshell.Io
JsonObject {
property bool autoHide: false
property int border: 8
property list<var> entries: [
{
id: "workspaces",
enabled: true
},
{
id: "media",
enabled: true
},
{
id: "resources",
enabled: true
},
{
id: "updates",
enabled: true
},
{
id: "spacer",
enabled: true
},
{
id: "activeWindow",
enabled: true
},
{
id: "spacer",
enabled: true
},
{
id: "hyprsunset",
enabled: true
},
{
id: "tray",
enabled: true
},
{
id: "network",
enabled: false
},
{
id: "clock",
enabled: true
},
{
id: "notifBell",
enabled: true
},
]
property int height: 34
property bool hideWhenNotif: false
property Popouts popouts: Popouts {
}
property int rounding: 8
property int smoothing: 32
property Tray tray: Tray {
}
component Popouts: JsonObject {
property bool activeWindow: true
property bool audio: true
property bool clock: true
property bool network: true
property bool resources: true
property bool tray: true
property bool upower: true
}
component Tray: JsonObject {
property bool recolorIcons: false
property bool showAudio: true
property bool showBluetooth: false
property bool showMicrophone: true
property bool showNetwork: false
property bool showOnHover: false
property bool showPower: true
property bool showWifi: false
property int trayIconSize: 24
}
}
-15
View File
@@ -1,15 +0,0 @@
import Quickshell.Io
JsonObject {
property bool enabled: true
property int maxEntriesShown: 10
property Sizes sizes: Sizes {
}
component Sizes: JsonObject {
property int itemHeight: 60
property int minPreviewWidth: 200
property int previewWidth: 500
property int width: 500
}
}
-13
View File
@@ -1,13 +0,0 @@
import Quickshell.Io
JsonObject {
property Presets presets: Presets {
}
property string schemeType: "vibrant"
component Presets: JsonObject {
property string accent: ""
property string name: ""
property string variant: ""
}
}
-186
View File
@@ -1,186 +0,0 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import ZShell
import QtQuick
import qs.Helpers
import qs.Paths
Singleton {
id: root
property alias appearance: adapter.appearance
property alias background: adapter.background
property alias bar: adapter.bar
property alias clipboard: adapter.clipboard
property alias colors: adapter.colors
property alias dashboard: adapter.dashboard
property alias dock: adapter.dock
property alias general: adapter.general
property alias launcher: adapter.launcher
property alias lock: adapter.lock
property bool migratingLegacyBar: false
property alias notifs: adapter.notifs
property alias osd: adapter.osd
property alias overview: adapter.overview
property bool recentlySaved: false
property alias screenshot: adapter.screenshot
property alias services: adapter.services
property alias sidebar: adapter.sidebar
property alias utilities: adapter.utilities
function applyLegacyBarConfig(legacy): void {
const tray = legacy.tray ?? {};
const popouts = legacy.popouts ?? {};
bar.autoHide = pick(legacy.autoHide, bar.autoHide);
bar.hideWhenNotif = pick(legacy.hideWhenNotif, bar.hideWhenNotif);
bar.rounding = pick(legacy.rounding, bar.rounding);
bar.border = pick(legacy.border, bar.border);
bar.smoothing = pick(legacy.smoothing, bar.smoothing);
bar.height = pick(legacy.height, bar.height);
bar.tray.trayIconSize = pick(tray.trayIconSize, bar.tray.trayIconSize);
bar.popouts.tray = pick(popouts.tray, bar.popouts.tray);
bar.popouts.audio = pick(popouts.audio, bar.popouts.audio);
bar.popouts.activeWindow = pick(popouts.activeWindow, bar.popouts.activeWindow);
bar.popouts.resources = pick(popouts.resources, bar.popouts.resources);
bar.popouts.clock = pick(popouts.clock, bar.popouts.clock);
bar.popouts.network = pick(popouts.network, bar.popouts.network);
bar.popouts.upower = pick(popouts.upower, bar.popouts.upower);
bar.entries = pick(legacy.entries, bar.entries);
}
function migrateLegacyBarConfig(raw): bool {
if (raw.bar !== undefined || raw.barConfig === undefined)
return false;
migratingLegacyBar = true;
applyLegacyBarConfig(raw.barConfig);
migratingLegacyBar = false;
return true;
}
function pick(value, fallback) {
return value === undefined ? fallback : value;
}
function save(): void {
saveTimer.restart();
recentlySaved = true;
recentSaveCooldown.restart();
}
function saveNoToast(): void {
saveTimer.restart();
}
ElapsedTimer {
id: timer
}
Timer {
id: saveTimer
interval: 500
onTriggered: {
timer.restart();
fileView.writeAdapter();
}
}
Timer {
id: recentSaveCooldown
interval: 2000
onTriggered: {
root.recentlySaved = false;
}
}
FileView {
id: fileView
path: `${Paths.config}/config.json`
watchChanges: true
onAdapterUpdated: {
if (!root.migratingLegacyBar)
root.save();
}
onFileChanged: {
if (!root.recentlySaved) {
timer.restart();
reload();
} else {
reload();
}
}
onLoadFailed: err => {
if (err !== FileViewError.FileNotFound)
Toaster.toast(qsTr("Failed to read config"), FileViewError.toString(err), "settings_alert", Toast.Warning);
}
onLoaded: {
ModeScheduler.checkStartup();
Hyprsunset.checkStartup();
try {
const raw = JSON.parse(text());
const migrated = root.migrateLegacyBarConfig(raw);
if (migrated)
root.save();
const elapsed = timer.elapsedMs();
if (adapter.utilities.toasts.configLoaded && !root.recentlySaved) {
Toaster.toast(qsTr("Config loaded"), qsTr("Config loaded in %1ms").arg(elapsed), "rule_settings");
} else if (adapter.utilities.toasts.configLoaded && root.recentlySaved) {
Toaster.toast(qsTr("Config saved"), qsTr("Config reloaded in %1ms").arg(elapsed), "settings_alert");
}
} catch (e) {
Toaster.toast(qsTr("Failed to load config"), e.message, "settings_alert", Toast.Error);
}
}
onSaveFailed: err => Toaster.toast(qsTr("Failed to save config"), FileViewError.toString(err), "settings_alert", Toast.Error)
JsonAdapter {
id: adapter
property AppearanceConf appearance: AppearanceConf {
}
property BackgroundConfig background: BackgroundConfig {
}
property BarConfig bar: BarConfig {
}
property ClipboardConfig clipboard: ClipboardConfig {
}
property Colors colors: Colors {
}
property DashboardConfig dashboard: DashboardConfig {
}
property DockConfig dock: DockConfig {
}
property General general: General {
}
property Launcher launcher: Launcher {
}
property LockConf lock: LockConf {
}
property NotifConfig notifs: NotifConfig {
}
property Osd osd: Osd {
}
property Overview overview: Overview {
}
property Screenshot screenshot: Screenshot {
}
property Services services: Services {
}
property SidebarConfig sidebar: SidebarConfig {
}
property UtilConfig utilities: UtilConfig {
}
}
}
}
-37
View File
@@ -1,37 +0,0 @@
import Quickshell.Io
JsonObject {
property bool enabled: true
property int mediaUpdateInterval: 500
property Performance performance: Performance {
}
property int resourceUpdateInterval: 1000
property Sizes sizes: Sizes {
}
component Performance: JsonObject {
property bool enabled: true
property bool showBattery: true
property bool showCpu: true
property bool showGpu: true
property bool showMemory: true
property bool showNetwork: true
property bool showStorage: true
property bool showVram: true
}
component Sizes: JsonObject {
readonly property int dateTimeWidth: 110
readonly property int infoIconSize: 25
readonly property int infoWidth: 200
readonly property int mediaCoverArtSize: 150
readonly property int mediaProgressSweep: 180
readonly property int mediaProgressThickness: 8
readonly property int mediaVisualizerSize: 200
readonly property int mediaWidth: 200
readonly property int resourceProgessThickness: 10
readonly property int resourceSize: 200
readonly property int tabIndicatorHeight: 3
readonly property int tabIndicatorSpacing: 5
readonly property int weatherWidth: 250
}
}
-10
View File
@@ -1,10 +0,0 @@
import Quickshell.Io
JsonObject {
property bool enable: false
property real height: 60
property bool hoverToReveal: true
property list<string> ignoredAppRegexes: []
property list<string> pinnedApps: ["org.kde.dolphin", "kitty",]
property bool pinnedOnStartup: false
}
-68
View File
@@ -1,68 +0,0 @@
import Quickshell.Io
import Quickshell
JsonObject {
property Apps apps: Apps {
}
property Battery battery: Battery {
}
property Color color: Color {
}
property string dateFormat: "ddd d MMM - hh:mm:ss"
property bool desktopIcons: false
property Idle idle: Idle {
}
property string logo: ""
property bool showOverFullscreen: true
property string wallpaperPath: Quickshell.env("HOME") + "/Pictures/Wallpapers"
component Apps: JsonObject {
property list<string> archiver: ["ark"]
property list<string> audio: ["pavucontrol"]
property list<string> document: ["libreoffice"]
property list<string> editor: ["kate"]
property list<string> explorer: ["dolphin"]
property list<string> image: ["imv"]
property list<string> playback: ["mpv"]
property list<string> terminal: ["kitty"]
}
component Battery: JsonObject {
property int critPerc: 5
property list<var> popupThresholds: [
{
perc: 20,
name: qsTr("Low battery"),
message: qsTr("Battery is low"),
icon: "battery_android_frame_2"
},
]
}
component Color: JsonObject {
property int hyprsunsetTemp: 5000
property string mode: "dark"
property bool neovimColors: false
property bool scheduleDark: false
property int scheduleDarkEnd: 0
property int scheduleDarkStart: 0
property bool scheduleHyprsunset: false
property int scheduleHyprsunsetEnd: 0
property int scheduleHyprsunsetStart: 0
property bool schemeGeneration: true
property bool smart: false
}
component Idle: JsonObject {
property list<var> timeouts: [
{
name: "Lock",
timeout: 180,
idleAction: "lock"
},
{
name: "Screen",
timeout: 300,
idleAction: "dpms off",
activeAction: "dpms on"
}
]
}
}
-15
View File
@@ -1,15 +0,0 @@
import Quickshell.Io
JsonObject {
property list<var> timeouts: [
{
timeout: 180,
idleAction: "lock"
},
{
timeout: 300,
idleAction: "dpms off",
activeAction: "dpms on"
}
]
}
-114
View File
@@ -1,114 +0,0 @@
import Quickshell.Io
JsonObject {
property string actionPrefix: ">"
property list<var> actions: [
{
name: "Calculator",
icon: "calculate",
description: "Do simple math equations",
command: ["autocomplete", "calc"],
enabled: true,
dangerous: false
},
{
name: "Light",
icon: "light_mode",
description: "Change to light mode",
command: ["setMode", "light"],
enabled: true,
dangerous: false
},
{
name: "Dark",
icon: "dark_mode",
description: "Change to dark mode",
command: ["setMode", "dark"],
enabled: true,
dangerous: false
},
{
name: "Wallpaper",
icon: "image",
description: "Change the current wallpaper",
command: ["autocomplete", "wallpaper"],
enabled: true,
dangerous: false
},
{
name: "Variant",
icon: "colors",
description: "Change the current scheme variant",
command: ["autocomplete", "variant"],
enabled: true,
dangerous: false
},
{
name: "Shutdown",
icon: "power_settings_new",
description: "Shutdown the system",
command: ["systemctl", "poweroff"],
enabled: true,
dangerous: true
},
{
name: "Reboot",
icon: "cached",
description: "Reboot the system",
command: ["systemctl", "reboot"],
enabled: true,
dangerous: true
},
{
name: "Logout",
icon: "logout",
description: "Log out of the current session",
command: ["loginctl", "terminate-user", ""],
enabled: true,
dangerous: true
},
{
name: "Lock",
icon: "lock",
description: "Lock the current session",
command: ["loginctl", "lock-session"],
enabled: true,
dangerous: false
},
{
name: "Sleep",
icon: "bedtime",
description: "Suspend then hibernate",
command: ["systemctl", "suspend-then-hibernate"],
enabled: true,
dangerous: false
},
]
property int dragThreshold: 50
property bool enableDangerousActions: false
property bool enabled: true
property list<string> favoriteApps: []
property list<string> hiddenApps: []
property int maxAppsShown: 10
property int maxWallpapers: 7
property Sizes sizes: Sizes {
}
property string specialPrefix: "@"
property UseFuzzy useFuzzy: UseFuzzy {
}
property bool uwsm: true
component Sizes: JsonObject {
property int itemHeight: 50
property int itemWidth: 600
property int wallpaperHeight: 200
property int wallpaperWidth: 280
}
component UseFuzzy: JsonObject {
property bool actions: false
property bool apps: false
property bool schemes: false
property bool variants: false
property bool wallpapers: false
}
}
-18
View File
@@ -1,18 +0,0 @@
import Quickshell.Io
JsonObject {
property int blurAmount: 40
property bool enableFprint: true
property int maxFprintTries: 3
property bool recolorLogo: false
property bool showNotifContent: false
property bool showNotifIcon: true
property Sizes sizes: Sizes {
}
component Sizes: JsonObject {
property int centerWidth: 600
property real heightMult: 0.7
property real ratio: 16 / 9
}
}
-26
View File
@@ -1,26 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
id: root
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
readonly property int emphasizedAccelTime: 200 * scale
readonly property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
readonly property int emphasizedDecelTime: 400 * scale
readonly property int emphasizedTime: 500 * scale
readonly property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1]
readonly property int expressiveDefaultSpatialTime: 500 * scale
readonly property list<real> expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1]
readonly property int expressiveEffectsTime: 200 * scale
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1]
readonly property int expressiveFastSpatialTime: 350 * scale
property real scale: Appearance.anim.durations.scale
readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1]
readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
readonly property int standardAccelTime: 200 * scale
readonly property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
readonly property int standardDecelTime: 250 * scale
readonly property int standardTime: 300 * scale
}
-21
View File
@@ -1,21 +0,0 @@
import Quickshell.Io
JsonObject {
property bool actionOnClick: false
property int appNotifCooldown: 0
property real clearThreshold: 0.3
property int defaultExpireTimeout: 5000
property int expandThreshold: 20
property bool expire: true
property int groupPreviewNum: 3
property bool openExpanded: false
property bool showInFullscreen: true
property Sizes sizes: Sizes {
}
component Sizes: JsonObject {
property int badge: 20
property int image: 41
property int width: 400
}
}
-16
View File
@@ -1,16 +0,0 @@
import Quickshell.Io
JsonObject {
property bool allMonBrightness: false
property bool enableBrightness: true
property bool enableMicrophone: true
property bool enabled: true
property int hideDelay: 3000
property Sizes sizes: Sizes {
}
component Sizes: JsonObject {
property int sliderHeight: 150
property int sliderWidth: 30
}
}
-8
View File
@@ -1,8 +0,0 @@
import Quickshell.Io
JsonObject {
property int columns: 5
property bool enable: false
property int rows: 2
property real scale: 0.16
}
-13
View File
@@ -1,13 +0,0 @@
import Quickshell.Io
JsonObject {
property bool enable_pp: true
property string mode: "manual"
property real radius: 12.0
property bool rounding: false
property bool shadow: true
property real shadow_blur: 22.0
property list<int> shadow_color: [0, 0, 0, 160]
property real shadow_offset_x: 5.0
property real shadow_offset_y: 5.0
}
-23
View File
@@ -1,23 +0,0 @@
import Quickshell.Io
import QtQuick
JsonObject {
property real audioIncrement: 0.1
property real brightnessIncrement: 0.1
property bool ddcutilService: false
property string defaultPlayer: "Spotify"
property string gpuType: ""
property real maxVolume: 1.0
property real minBrightness: 0.01
property list<var> playerAliases: [
{
"from": "com.github.th_ch.youtube_music",
"to": "YT Music"
}
]
property bool updates: true
property bool useFahrenheit: false
property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a")
property int visualizerBars: 30
property string weatherLocation: ""
}
-12
View File
@@ -1,12 +0,0 @@
import Quickshell.Io
JsonObject {
property int dragThreshold: 30
property bool enabled: true
property Sizes sizes: Sizes {
}
component Sizes: JsonObject {
property int width: 430
}
}
-7
View File
@@ -1,7 +0,0 @@
import Quickshell.Io
JsonObject {
property real base: 0.85
property bool enabled: false
property real layers: 0.4
}
-35
View File
@@ -1,35 +0,0 @@
import Quickshell.Io
JsonObject {
property bool enabled: true
property int maxToasts: 4
property Sizes sizes: Sizes {
}
property Toasts toasts: Toasts {
}
property Vpn vpn: Vpn {
}
component Sizes: JsonObject {
property int toastWidth: 430
property int width: 430
}
component Toasts: JsonObject {
property bool audioInputChanged: true
property bool audioOutputChanged: true
property bool capsLockChanged: true
property bool chargingChanged: true
property bool configLoaded: true
property bool dndChanged: true
property bool gameModeChanged: true
property bool kbLayoutChanged: true
property bool kbLimit: true
property bool nowPlaying: false
property bool numLockChanged: true
property bool vpnChanged: true
}
component Vpn: JsonObject {
property bool enabled: false
property list<var> provider: ["netbird"]
}
}
-6
View File
@@ -1,6 +0,0 @@
import Quickshell.Io
JsonObject {
property string inactiveTextColor: "white"
property string textColor: "black"
}
+1 -1
View File
@@ -5,7 +5,7 @@ import ZShell
import Quickshell import Quickshell
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import QtQuick import QtQuick
import qs.Config import ZShell.Config
Singleton { Singleton {
id: root id: root
+1 -1
View File
@@ -2,7 +2,7 @@ import Quickshell
import Quickshell.Services.UPower import Quickshell.Services.UPower
import QtQuick import QtQuick
import ZShell import ZShell
import qs.Config import ZShell.Config
import qs.Components.Toast import qs.Components.Toast
import qs.Helpers import qs.Helpers
+1 -1
View File
@@ -11,7 +11,7 @@ import qs.Components
import qs.Modules import qs.Modules
import qs.Helpers import qs.Helpers
import qs.Paths import qs.Paths
import qs.Config import ZShell.Config
Singleton { Singleton {
id: root id: root
+33 -2
View File
@@ -11,15 +11,46 @@ Variants {
required property ShellScreen modelData required property ShellScreen modelData
function rebuild(): void {
loader.active = false;
loader.active = true;
}
LazyLoader {
id: loader
active: true
Drawer {
screen: scope.modelData
}
}
Connections {
function onConfigPositionChanged(): void {
Qt.callLater(scope.rebuild);
}
target: (loader.item as Drawer)?.geometry ?? null
}
}
component Drawer: Scope {
id: drawer
readonly property alias geometry: content.geometry
required property ShellScreen screen
Exclusions { Exclusions {
bar: content.bar bar: content.bar
screen: scope.modelData geometry: content.geometry
screen: drawer.screen
} }
Windows { Windows {
id: content id: content
screen: scope.modelData screen: drawer.screen
} }
} }
} }
+55
View File
@@ -0,0 +1,55 @@
import QtQuick
import qs.Modules.Bar as Bar
QtObject {
id: root
required property Bar.BarLoader bar
readonly property real barClamped: bar.clampedExtent
readonly property real barExtent: bar.extent
readonly property bool barOnBottom: position === "bottom"
readonly property bool barOnLeft: position === "left"
readonly property bool barOnTop: position === "top"
required property string configPosition
readonly property bool horizontal: position !== "left"
readonly property string position: configPosition === "top" || configPosition === "bottom" ? configPosition : "left"
required property var win
function axisPos(x: real, y: real): real {
return horizontal ? x : y;
}
function barContains(x: real, y: real, clamped = false): bool {
const extent = clamped ? barClamped : barExtent;
if (barOnTop)
return y < extent;
if (barOnBottom)
return y > win.height - extent;
return x < extent;
}
function insetBottom(border: real, clamped = false): real {
return barOnBottom ? (clamped ? barClamped : barExtent) : border;
}
function insetLeft(border: real, clamped = false): real {
return barOnLeft ? (clamped ? barClamped : barExtent) : border;
}
function insetTop(border: real, clamped = false): real {
return barOnTop ? (clamped ? barClamped : barExtent) : border;
}
function inwardDrag(dragX: real, dragY: real): real {
if (barOnTop)
return dragY;
if (barOnBottom)
return -dragY;
return dragX;
}
onConfigPositionChanged: {
if (!["left", "top", "bottom"].includes(configPosition))
console.warn(`Invalid bar position '${configPosition}', falling back to left`);
}
}
+8 -3
View File
@@ -2,26 +2,28 @@ pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import QtQuick import QtQuick
import qs.Config import ZShell.Config
import qs.Components import qs.Components
Scope { Scope {
id: root id: root
required property Item bar required property Item bar
required property EdgeGeometry geometry
required property ShellScreen screen required property ShellScreen screen
ExclusionZone { ExclusionZone {
id: top id: top
anchors.top: true anchors.top: true
exclusiveZone: root.bar.exclusiveZone hasBar: root.geometry.barOnTop
} }
ExclusionZone { ExclusionZone {
id: left id: left
anchors.left: true anchors.left: true
hasBar: root.geometry.barOnLeft
} }
ExclusionZone { ExclusionZone {
@@ -34,6 +36,7 @@ Scope {
id: bottom id: bottom
anchors.bottom: true anchors.bottom: true
hasBar: root.geometry.barOnBottom
} }
Timer { Timer {
@@ -44,7 +47,9 @@ Scope {
} }
component ExclusionZone: CustomWindow { component ExclusionZone: CustomWindow {
exclusiveZone: Config.bar.border property bool hasBar
exclusiveZone: hasBar ? root.bar.exclusiveZone : Config.bar.border
implicitHeight: 1 implicitHeight: 1
implicitWidth: 1 implicitWidth: 1
name: "Bar-Exclusion" name: "Bar-Exclusion"
+25 -23
View File
@@ -1,9 +1,9 @@
import Quickshell import Quickshell
import QtQuick import QtQuick
import qs.Components import qs.Components
import qs.Config import ZShell.Config
import qs.Helpers import qs.Helpers
import qs.Modules as BarPopouts import qs.Modules.Bar.Popouts
Item { Item {
id: root id: root
@@ -12,43 +12,47 @@ Item {
required property real borderThickness required property real borderThickness
property bool dashboardShortcutActive property bool dashboardShortcutActive
required property Drawing drawing required property Drawing drawing
required property EdgeGeometry geometry
property bool osdShortcutActive property bool osdShortcutActive
required property Panels panels required property Panels panels
required property BarPopouts.Wrapper popouts required property Wrapper popouts
required property ShellScreen screen required property ShellScreen screen
property bool singleGestureTriggered: false property bool singleGestureTriggered: false
property bool utilitiesShortcutActive property bool utilitiesShortcutActive
required property PersistentProperties visibilities required property PersistentProperties visibilities
function inBottomPanel(panel: Item, x: real, y: real): bool { function inBottomPanel(panel: Item, x: real, y: real): bool {
return y > root.height - panel.height - Config.bar.border && withinPanelWidth(panel, x, y); const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
return y > root.height - (panelHeight + geometry.insetBottom(borderThickness)) && withinPanelWidth(panel, x, y);
} }
function inLeftPanel(panel: Item, x: real, y: real): bool { function inLeftPanel(panel: Item, x: real, y: real): bool {
return x < panel.x + panel.width + Config.bar.border && withinPanelHeight(panel, x, y); return x < panel.x + panel.width + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
}
function inPopoutArea(x: real, y: real): bool {
const panel = panels.popoutsWrapper;
if (!geometry.horizontal)
return inLeftPanel(panel, x, y);
return withinPanelWidth(panel, x, y) && withinPanelHeight(panel, x, y);
} }
function inRightPanel(panel: Item, x: real, y: real): bool { function inRightPanel(panel: Item, x: real, y: real): bool {
return x > panel.x - Config.bar.border && withinPanelHeight(panel, x, y); return x > panel.x + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
} }
function inTopPanel(panel: Item, x: real, y: real): bool { function inTopPanel(panel: Item, x: real, y: real): bool {
return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y); const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
} return y < geometry.insetTop(borderThickness) + panelHeight && withinPanelWidth(panel, x, y);
function onWheel(event: WheelEvent): void {
if (event.x < bar.implicitWidth) {
bar.handleWheel(event.y, event.angleDelta);
}
} }
function withinPanelHeight(panel: Item, x: real, y: real): bool { function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = panel.y + bar.implicitHeight; const panelY = panel.y + geometry.insetTop(borderThickness);
return y >= panelY && y <= panelY + panel.height; return y >= panelY && y <= panelY + panel.height;
} }
function withinPanelWidth(panel: Item, x: real, y: real): bool { function withinPanelWidth(panel: Item, x: real, y: real): bool {
const panelX = panel.x + root.borderThickness; const panelX = panel.x + geometry.insetLeft(borderThickness);
return x >= panelX && x <= panelX + panel.width; return x >= panelX && x <= panelX + panel.width;
} }
@@ -81,7 +85,7 @@ Item {
if (root.singleGestureTriggered) if (root.singleGestureTriggered)
return; return;
if (centroid.pressPosition.y < root.bar.implicitHeight) { if (root.geometry.insetTop(root.borderThickness) > centroid.pressPosition.y) {
if (dragY > 20) { if (dragY > 20) {
root.visibilities.settings = true; root.visibilities.settings = true;
root.singleGestureTriggered = true; root.singleGestureTriggered = true;
@@ -91,10 +95,10 @@ Item {
} }
} }
if (centroid.pressPosition.y > root.screen.height - Config.bar.border && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50) if (centroid.pressPosition.y > root.screen.height - root.geometry.insetBottom(root.borderThickness) && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50)
root.visibilities.clipboard = true; root.visibilities.clipboard = true;
if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.bar.implicitHeight && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher) if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.geometry.insetTop(root.borderThickness) && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher)
if (dragY < -10) { if (dragY < -10) {
root.visibilities.dock = true; root.visibilities.dock = true;
root.singleGestureTriggered = true; root.singleGestureTriggered = true;
@@ -193,7 +197,7 @@ Item {
return; return;
} }
if (!root.visibilities.bar && Config.bar.autoHide && y < root.bar.implicitHeight) if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true))
root.bar.isHovered = true; root.bar.isHovered = true;
if (root.panels.sidebar.offsetScale === 1) { if (root.panels.sidebar.offsetScale === 1) {
@@ -219,8 +223,8 @@ Item {
if (Config.dock.enable && Config.dock.hoverToReveal && !root.visibilities.dock && !root.visibilities.launcher && root.inBottomPanel(root.panels.dock, x, y)) if (Config.dock.enable && Config.dock.hoverToReveal && !root.visibilities.dock && !root.visibilities.launcher && root.inBottomPanel(root.panels.dock, x, y))
root.visibilities.dock = true; root.visibilities.dock = true;
if (y < root.bar.implicitHeight) if (root.geometry.barContains(x, y))
root.bar.checkPopout(x); root.bar.checkPopout(root.geometry.axisPos(x, y));
} }
} }
@@ -298,8 +302,6 @@ Item {
root.visibilities.sidebar = false; root.visibilities.sidebar = false;
root.panels.popouts.hasCurrent = false; root.panels.popouts.hasCurrent = false;
root.visibilities.launcher = false; root.visibilities.launcher = false;
} else {
Config.save();
} }
} }
+23 -20
View File
@@ -1,7 +1,7 @@
import Quickshell import Quickshell
import QtQuick import QtQuick
import qs.Components import qs.Components
import qs.Modules as Modules import qs.Modules.Bar.Popouts as Popouts
import qs.Modules.Notifications as Notifications import qs.Modules.Notifications as Notifications
import qs.Modules.Notifications.Sidebar as Sidebar import qs.Modules.Notifications.Sidebar as Sidebar
import qs.Modules.Notifications.Sidebar.Utils as Utils import qs.Modules.Notifications.Sidebar.Utils as Utils
@@ -14,7 +14,7 @@ import qs.Modules.Settings as Settings
import qs.Modules.Drawing as Drawing import qs.Modules.Drawing as Drawing
import qs.Modules.Dock as Dock import qs.Modules.Dock as Dock
import qs.Modules.Clipboard as Clipboard import qs.Modules.Clipboard as Clipboard
import qs.Config import ZShell.Config
Item { Item {
id: root id: root
@@ -27,6 +27,7 @@ Item {
readonly property alias dock: dock readonly property alias dock: dock
readonly property alias drawing: drawing readonly property alias drawing: drawing
required property var drawingItem required property var drawingItem
required property EdgeGeometry geometry
readonly property alias launcher: launcher readonly property alias launcher: launcher
readonly property alias notifications: notifications readonly property alias notifications: notifications
readonly property alias osd: osd readonly property alias osd: osd
@@ -43,24 +44,26 @@ Item {
readonly property alias utilities: utilities readonly property alias utilities: utilities
required property PersistentProperties visibilities required property PersistentProperties visibilities
anchors.bottomMargin: geometry.insetBottom(borderThickness)
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: geometry.insetLeft(borderThickness)
anchors.margins: borderThickness anchors.margins: borderThickness
anchors.topMargin: bar.implicitHeight anchors.topMargin: geometry.insetTop(borderThickness)
Item { Item {
id: resourcesWrapper id: resourcesWrapper
anchors.bottom: root.geometry.position === "bottom" ? parent.bottom : undefined
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: root.geometry.position !== "bottom" ? parent.top : undefined
clip: true clip: true
implicitHeight: resources.implicitHeight * (1 - resources.offsetScale) implicitHeight: root.geometry.horizontal ? resources.implicitHeight * (1 - resources.offsetScale) : resources.implicitHeight
implicitWidth: resources.implicitWidth implicitWidth: root.geometry.horizontal ? resources.implicitWidth : resources.implicitWidth * (1 - resources.offsetScale)
Resources.Wrapper { Resources.Wrapper {
id: resources id: resources
anchors.left: parent.left position: root.geometry.position
anchors.top: parent.top
visibilities: root.visibilities visibilities: root.visibilities
} }
} }
@@ -96,11 +99,11 @@ Item {
visibilities: root.visibilities visibilities: root.visibilities
} }
Modules.ClipWrapper { Popouts.ClipWrapper {
id: popouts id: popouts
anchors.top: parent.top
borderThickness: root.borderThickness borderThickness: root.borderThickness
position: root.geometry.position
screen: root.screen screen: root.screen
} }
@@ -108,7 +111,7 @@ Item {
id: toasts id: toasts
anchors.bottom: sidebar.visible ? parent.bottom : utilities.top anchors.bottom: sidebar.visible ? parent.bottom : utilities.top
anchors.margins: Appearance.padding.normal anchors.margins: Tokens.padding.normal
anchors.right: sidebar.left anchors.right: sidebar.left
} }
@@ -147,26 +150,26 @@ Item {
property real offsetScale: dashboard.shouldBeActive ? 0 : 1 property real offsetScale: dashboard.shouldBeActive ? 0 : 1
anchors.right: parent.right anchors.bottom: root.geometry.barOnLeft || root.geometry.barOnBottom ? parent.bottom : undefined
anchors.top: parent.top anchors.left: root.geometry.barOnLeft ? parent.left : undefined
anchors.right: root.geometry.barOnLeft ? undefined : parent.right
anchors.top: root.geometry.barOnBottom || root.geometry.barOnLeft ? undefined : parent.top
clip: true clip: true
implicitHeight: dashboard.implicitHeight * (1 - offsetScale) implicitHeight: root.geometry.horizontal ? dashboard.implicitHeight * (1 - offsetScale) : dashboard.implicitHeight
implicitWidth: dashboard.implicitWidth implicitWidth: root.geometry.horizontal ? dashboard.implicitWidth : dashboard.implicitWidth * (1 - offsetScale)
Behavior on offsetScale { Behavior on offsetScale {
Anim { Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Tokens.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Tokens.anim.curves.expressiveDefaultSpatial
} }
} }
Dashboard.Wrapper { Dashboard.Wrapper {
id: dashboard id: dashboard
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: (-implicitHeight - 5) * offsetScale
offsetScale: dashboardWrapper.offsetScale offsetScale: dashboardWrapper.offsetScale
position: root.geometry.position
visibilities: root.visibilities visibilities: root.visibilities
} }
} }
+13 -8
View File
@@ -7,17 +7,18 @@ import qs.Modules.Bar as Bar
Region { Region {
id: root id: root
required property Bar.BarLoader bar // required property Bar.BarLoader bar
readonly property real borderThickness: win.borderThickness readonly property real borderThickness: win.borderThickness
required property EdgeGeometry geometry
readonly property alias menuPopoutRegion: menuPopoutRegion readonly property alias menuPopoutRegion: menuPopoutRegion
required property Panels panels required property Panels panels
required property var win required property var win
height: win.height - bar.implicitHeight - win.borderThickness - win.dragMaskPadding * 2 height: win.height - geometry.insetTop(borderThickness, true) - geometry.insetBottom(borderThickness, true) - win.dragMaskPadding * 2
intersection: Intersection.Xor intersection: Intersection.Xor
width: win.width - win.borderThickness * 2 - win.dragMaskPadding * 2 width: win.width - geometry.insetLeft(borderThickness, true) * 2 - win.dragMaskPadding * 2
x: win.borderThickness + win.dragMaskPadding x: geometry.insetLeft(borderThickness, true) + win.dragMaskPadding
y: bar.implicitHeight + win.dragMaskPadding y: geometry.insetTop(borderThickness, true) + win.dragMaskPadding
R { R {
panel: root.panels.dashboardWrapper panel: root.panels.dashboardWrapper
@@ -41,17 +42,21 @@ Region {
} }
R { R {
height: panel.height + root.geometry.insetTop(root.borderThickness)
panel: root.panels.notifications panel: root.panels.notifications
y: 0
} }
R { R {
height: panel.height * (1 - root.panels.utilities.offsetScale) + root.borderThickness height: panel.height * (1 - root.panels.utilities.offsetScale) + root.geometry.insetBottom(root.borderThickness)
panel: root.panels.utilities panel: root.panels.utilities
y: root.win.height - height y: root.win.height - height
} }
R { R {
height: root.geometry.horizontal ? panel.height * (1 - root.panels.popoutsWrapper.offsetScale) : panel.height
panel: root.panels.popoutsWrapper panel: root.panels.popoutsWrapper
width: root.geometry.horizontal ? panel.width : panel.width * (1 - root.panels.popoutsWrapper.offsetScale)
} }
R { R {
@@ -82,7 +87,7 @@ Region {
height: panel.height height: panel.height
intersection: Intersection.Subtract intersection: Intersection.Subtract
width: panel.width width: panel.width
x: panel.x + root.borderThickness x: panel.x + root.geometry.insetLeft(root.borderThickness)
y: panel.y + root.bar.implicitHeight y: panel.y + root.geometry.insetTop(root.borderThickness)
} }
} }
+52 -37
View File
@@ -11,9 +11,10 @@ import ZShell.Blobs
import qs.Daemons import qs.Daemons
import qs.Components import qs.Components
import qs.Modules.Bar import qs.Modules.Bar
import qs.Config import ZShell.Config
import qs.Helpers import qs.Helpers
import qs.Drawers import qs.Drawers
import qs.Services
CustomWindow { CustomWindow {
id: root id: root
@@ -32,6 +33,7 @@ CustomWindow {
return 100; return 100;
} }
property real fsTransitionProg: hasFullscreen ? 1 : 0 property real fsTransitionProg: hasFullscreen ? 1 : 0
readonly property alias geometry: geometry
readonly property bool hasFullscreen: { readonly property bool hasFullscreen: {
if (hasSpecialWorkspace) { if (hasSpecialWorkspace) {
const specialName = monitor?.lastIpcObject.specialWorkspace?.name; const specialName = monitor?.lastIpcObject.specialWorkspace?.name;
@@ -50,7 +52,7 @@ CustomWindow {
property var root: Quickshell.shellDir property var root: Quickshell.shellDir
readonly property real sdfBorderOffset: 2 * fsTransitionProg readonly property real sdfBorderOffset: 2 * fsTransitionProg
readonly property real shadowOpacity: 0.7 * (1 - fsTransitionProg) readonly property real shadowOpacity: 0.7 * (1 - fsTransitionProg)
property color surfaceColor: DynamicColors.tPalette.m3surface property color surfaceColor: Colors.tPalette.m3surface
WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.settings ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.settings ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
@@ -94,13 +96,21 @@ CustomWindow {
panels.popouts.hasCurrent = false; panels.popouts.hasCurrent = false;
} }
EdgeGeometry {
id: geometry
bar: bar
configPosition: Config.bar.position
win: root
}
Region { Region {
id: emptyRegion id: emptyRegion
height: panels.notifications.height height: panels.notifications.height
width: panels.notifications.width width: panels.notifications.width
x: panels.notifications.x + root.borderThickness x: panels.notifications.x + geometry.insetLeft(root.borderThickness)
y: panels.notifications.y + bar.implicitHeight y: panels.notifications.y + geometry.insetTop(root.borderThickness)
Region { Region {
height: panels.osd.height height: panels.osd.height
@@ -113,7 +123,7 @@ CustomWindow {
Regions { Regions {
id: regions id: regions
bar: bar geometry: geometry
panels: panels panels: panels
win: root win: root
} }
@@ -178,7 +188,7 @@ CustomWindow {
layer.effect: MultiEffect { layer.effect: MultiEffect {
blurMax: 32 blurMax: 32
shadowColor: Qt.alpha(DynamicColors.palette.m3shadow, Math.max(0, root.shadowOpacity)) shadowColor: Qt.alpha(Colors.palette.m3shadow, Math.max(0, root.shadowOpacity))
shadowEnabled: true shadowEnabled: true
} }
@@ -192,10 +202,10 @@ CustomWindow {
BlobInvertedRect { BlobInvertedRect {
anchors.fill: parent anchors.fill: parent
anchors.margins: -50 anchors.margins: -50
borderBottom: root.borderThickness - anchors.margins - root.sdfBorderOffset borderBottom: geometry.insetBottom(root.borderThickness) - anchors.margins - root.sdfBorderOffset
borderLeft: root.borderThickness - anchors.margins - root.sdfBorderOffset borderLeft: geometry.insetLeft(root.borderThickness) - anchors.margins - root.sdfBorderOffset
borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderTop: bar.implicitHeight - anchors.margins - root.sdfBorderOffset borderTop: geometry.insetTop(root.borderThickness) - anchors.margins - root.sdfBorderOffset
group: blobGroup group: blobGroup
radius: root.borderRounding radius: root.borderRounding
} }
@@ -203,15 +213,15 @@ CustomWindow {
PanelBg { PanelBg {
id: dashBg id: dashBg
property real extraHeight: 0.2 property real extraExtent: 0.2
deformAmount: 0.06 deformAmount: 0.06
implicitHeight: panels.dashboard.height * (1 + extraHeight) implicitHeight: panels.dashboard.height * (geometry.horizontal ? 1 + extraExtent : 1)
implicitWidth: panels.dashboard.width implicitWidth: panels.dashboard.width * (geometry.horizontal ? 1 : 1 + extraExtent)
panel: panels.dashboardWrapper panel: panels.dashboardWrapper
radius: Appearance.rounding.normal radius: Tokens.rounding.normal
x: panels.dashboardWrapper.x + panels.dashboard.x + root.borderThickness x: panels.dashboardWrapper.x + panels.dashboard.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.dashboard.width * extraExtent)
y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight - panels.dashboard.height * extraHeight y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - (geometry.horizontal && geometry.position !== "bottom" ? panels.dashboard.height * extraExtent : 0)
} }
PanelBg { PanelBg {
@@ -222,8 +232,8 @@ CustomWindow {
deformAmount: 0.06 deformAmount: 0.06
implicitHeight: panels.launcher.height * (1 + extraHeight) implicitHeight: panels.launcher.height * (1 + extraHeight)
panel: panels.launcher panel: panels.launcher
radius: Appearance.rounding.smallest + 5 radius: Tokens.rounding.smallest + 5
y: panels.launcher.y + bar.implicitHeight y: panels.launcher.y + geometry.insetTop(root.borderThickness)
} }
PanelBg { PanelBg {
@@ -244,15 +254,14 @@ CustomWindow {
implicitWidth: panels.osd.width implicitWidth: panels.osd.width
panel: panels.osdWrapper panel: panels.osdWrapper
radius: 20 radius: 20
x: panels.osdWrapper.x + panels.osd.x + root.borderThickness x: panels.osdWrapper.x + panels.osd.x + geometry.insetLeft(root.borderThickness)
y: panels.osdWrapper.y + panels.osd.y + bar.implicitHeight
} }
PanelBg { PanelBg {
id: notifsBg id: notifsBg
panel: panels.notifications panel: panels.notifications
radius: Appearance.rounding.normal radius: Tokens.rounding.normal
} }
PanelBg { PanelBg {
@@ -267,17 +276,17 @@ CustomWindow {
PanelBg { PanelBg {
id: popoutBg id: popoutBg
property real extraHeight: 0.2 property real extraExtent: 0.2
deformAmount: panels.popouts.currentName.startsWith("traymenu") ? 0.15 : 0.08 deformAmount: panels.popouts.currentName.startsWith("traymenu") ? 0.15 : 0.08
implicitHeight: panels.popouts.height * (1 + extraHeight) implicitHeight: panels.popouts.height * (geometry.horizontal ? 1 + extraExtent : 1)
implicitWidth: panels.popouts.width implicitWidth: panels.popouts.width * (geometry.horizontal ? 1 : 1 + extraExtent)
panel: panels.popoutsWrapper panel: panels.popoutsWrapper
radius: panels.popouts.current?.panelRadius ?? Appearance.rounding.normal radius: panels.popouts.current?.panelRadius ?? Tokens.rounding.normal
x: panels.popoutsWrapper.x + panels.popouts.x + root.borderThickness x: panels.popoutsWrapper.x + panels.popouts.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.popouts.width * extraExtent)
y: panels.popoutsWrapper.y + panels.popouts.y + bar.implicitHeight - panels.popouts.height * extraHeight y: panels.popoutsWrapper.y + panels.popouts.y + geometry.insetTop(root.borderThickness) - (geometry.barOnTop ? panels.popouts.height * extraExtent : 0)
Behavior on extraHeight { Behavior on extraExtent {
Anim { Anim {
} }
} }
@@ -290,9 +299,9 @@ CustomWindow {
implicitHeight: panels.resources.height implicitHeight: panels.resources.height
implicitWidth: panels.resources.width implicitWidth: panels.resources.width
panel: panels.resourcesWrapper panel: panels.resourcesWrapper
radius: Appearance.rounding.large radius: Tokens.rounding.large
x: panels.resourcesWrapper.x + panels.resources.x + root.borderThickness x: panels.resourcesWrapper.x + panels.resources.x + geometry.insetLeft(root.borderThickness)
y: panels.resourcesWrapper.y + panels.resources.y + bar.implicitHeight y: panels.resourcesWrapper.y + panels.resources.y + geometry.insetTop(root.borderThickness)
} }
PanelBg { PanelBg {
@@ -300,7 +309,7 @@ CustomWindow {
deformAmount: 0.03 deformAmount: 0.03
panel: panels.settings panel: panels.settings
radius: Appearance.rounding.large + Appearance.padding.normal radius: Tokens.rounding.large + Tokens.padding.normal
} }
PanelBg { PanelBg {
@@ -308,7 +317,7 @@ CustomWindow {
deformAmount: 0.08 deformAmount: 0.08
panel: panels.dock panel: panels.dock
radius: Appearance.rounding.normal radius: Tokens.rounding.normal
} }
PanelBg { PanelBg {
@@ -316,7 +325,7 @@ CustomWindow {
deformAmount: 0.08 deformAmount: 0.08
panel: panels.drawing panel: panels.drawing
radius: Appearance.rounding.normal radius: Tokens.rounding.normal
} }
PanelBg { PanelBg {
@@ -370,6 +379,7 @@ CustomWindow {
borderThickness: root.borderLayoutThickness borderThickness: root.borderLayoutThickness
drawing: drawing drawing: drawing
enabled: true enabled: true
geometry: geometry
panels: panels panels: panels
popouts: panels.popouts popouts: panels.popouts
screen: root.screen screen: root.screen
@@ -381,6 +391,7 @@ CustomWindow {
bar: bar bar: bar
borderThickness: root.borderThickness borderThickness: root.borderThickness
drawingItem: drawing drawingItem: drawing
geometry: geometry
screen: root.screen screen: root.screen
visibilities: visibilities visibilities: visibilities
@@ -422,14 +433,18 @@ CustomWindow {
BarLoader { BarLoader {
id: bar id: bar
anchors.bottom: geometry.barOnBottom ? parent.bottom : undefined
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.top: geometry.barOnBottom ? undefined : parent.top
enabled: !visibilities.isDrawing enabled: !visibilities.isDrawing
fullscreen: root.hasFullscreen fullscreen: root.hasFullscreen
height: geometry.horizontal ? implicitHeight : parent.height
popouts: panels.popouts popouts: panels.popouts
popoutsWrapper: panels.popoutsWrapper popoutsWrapper: panels.popoutsWrapper
position: geometry.position
screen: root.screen screen: root.screen
visibilities: visibilities visibilities: visibilities
width: geometry.horizontal ? parent.width : implicitWidth
} }
} }
@@ -441,8 +456,8 @@ CustomWindow {
group: blobGroup group: blobGroup
implicitHeight: panel.height implicitHeight: panel.height
implicitWidth: panel.width implicitWidth: panel.width
radius: Appearance.rounding.smallest radius: Tokens.rounding.smallest
x: panel.x + root.borderThickness x: panel.x + geometry.insetLeft(root.borderThickness)
y: panel.y + bar.implicitHeight y: panel.y + geometry.insetTop(root.borderThickness)
} }
} }
+45 -45
View File
@@ -2,10 +2,10 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Paths import ZShell.Config
import qs.Components import qs.Components
import qs.Helpers import qs.Helpers
import qs.Config import qs.Services
ColumnLayout { ColumnLayout {
id: root id: root
@@ -18,61 +18,61 @@ ColumnLayout {
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: false Layout.fillWidth: false
Layout.preferredWidth: centerWidth Layout.preferredWidth: centerWidth
spacing: Appearance.spacing.large * 2 spacing: Tokens.spacing.large * 2
RowLayout { RowLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
spacing: Appearance.spacing.small spacing: Tokens.spacing.small
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: DynamicColors.palette.m3secondary color: Colors.palette.m3secondary
font.bold: true font.bold: true
font.family: Appearance.font.family.clock font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: Time.hourStr text: Time.hourStr
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: DynamicColors.palette.m3primary color: Colors.palette.m3primary
font.bold: true font.bold: true
font.family: Appearance.font.family.clock font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: ":" text: ":"
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: DynamicColors.palette.m3secondary color: Colors.palette.m3secondary
font.bold: true font.bold: true
font.family: Appearance.font.family.clock font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: Time.minuteStr text: Time.minuteStr
} }
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.topMargin: -Appearance.padding.large * 2 Layout.topMargin: -Tokens.padding.large * 2
color: DynamicColors.palette.m3tertiary color: Colors.palette.m3tertiary
font.bold: true font.bold: true
font.family: Appearance.font.family.mono font.family: Config.appearance.font.family.mono
font.pointSize: Math.floor(Appearance.font.size.extraLarge * root.centerScale) font.pointSize: Math.floor(Tokens.font.size.extraLarge * root.centerScale)
text: Time.format("dddd, d MMMM yyyy") text: Time.format("dddd, d MMMM yyyy")
} }
CustomClippingRect { CustomClippingRect {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Appearance.spacing.large * 2 Layout.topMargin: Tokens.spacing.large * 2
color: DynamicColors.tPalette.m3surfaceContainer color: Colors.tPalette.m3surfaceContainer
implicitHeight: root.centerWidth / 2 implicitHeight: root.centerWidth / 2
implicitWidth: root.centerWidth / 2 implicitWidth: root.centerWidth / 2
radius: Appearance.rounding.full radius: Tokens.rounding.full
MaterialIcon { MaterialIcon {
anchors.centerIn: parent anchors.centerIn: parent
color: DynamicColors.palette.m3onSurfaceVariant color: Colors.palette.m3onSurfaceVariant
font.pointSize: Math.floor(root.centerWidth / 4) font.pointSize: Math.floor(root.centerWidth / 4)
text: "person" text: "person"
} }
@@ -87,9 +87,9 @@ ColumnLayout {
CustomText { CustomText {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
color: DynamicColors.palette.m3onSurfaceVariant color: Colors.palette.m3onSurfaceVariant
font.family: Appearance.font.family.mono font.family: Config.appearance.font.family.mono
font.pointSize: Appearance.font.size.normal font.pointSize: Tokens.font.size.normal
font.weight: 600 font.weight: 600
text: root.greeter.username text: root.greeter.username
visible: text.length > 0 visible: text.length > 0
@@ -97,11 +97,11 @@ ColumnLayout {
CustomRect { CustomRect {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
color: DynamicColors.tPalette.m3surfaceContainer color: Colors.tPalette.m3surfaceContainer
focus: true focus: true
implicitHeight: input.implicitHeight + Appearance.padding.small * 2 implicitHeight: input.implicitHeight + Tokens.padding.small * 2
implicitWidth: root.centerWidth * 0.8 implicitWidth: root.centerWidth * 0.8
radius: Appearance.rounding.full radius: Tokens.rounding.full
Keys.onPressed: event => { Keys.onPressed: event => {
if (root.greeter.launching) if (root.greeter.launching)
@@ -130,11 +130,11 @@ ColumnLayout {
id: input id: input
anchors.fill: parent anchors.fill: parent
anchors.margins: Appearance.padding.small anchors.margins: Tokens.padding.small
spacing: Appearance.spacing.normal spacing: Tokens.spacing.normal
Item { Item {
implicitHeight: statusIcon.implicitHeight + Appearance.padding.small * 2 implicitHeight: statusIcon.implicitHeight + Tokens.padding.small * 2
implicitWidth: implicitHeight implicitWidth: implicitHeight
MaterialIcon { MaterialIcon {
@@ -142,7 +142,7 @@ ColumnLayout {
anchors.centerIn: parent anchors.centerIn: parent
animate: true animate: true
color: root.greeter.errorMessage ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurface color: root.greeter.errorMessage ? Colors.palette.m3error : Colors.palette.m3onSurface
opacity: root.greeter.launching ? 0 : 1 opacity: root.greeter.launching ? 0 : 1
text: { text: {
if (root.greeter.errorMessage) if (root.greeter.errorMessage)
@@ -173,13 +173,13 @@ ColumnLayout {
} }
CustomRect { CustomRect {
color: root.greeter.buffer && !root.greeter.launching ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2) color: root.greeter.buffer && !root.greeter.launching ? Colors.palette.m3primary : Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
implicitHeight: enterIcon.implicitHeight + Appearance.padding.small * 2 implicitHeight: enterIcon.implicitHeight + Tokens.padding.small * 2
implicitWidth: implicitHeight implicitWidth: implicitHeight
radius: Appearance.rounding.full radius: Tokens.rounding.full
StateLayer { StateLayer {
color: root.greeter.buffer && !root.greeter.launching ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface color: root.greeter.buffer && !root.greeter.launching ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
onClicked: { onClicked: {
root.greeter.submit(); root.greeter.submit();
@@ -190,7 +190,7 @@ ColumnLayout {
id: enterIcon id: enterIcon
anchors.centerIn: parent anchors.centerIn: parent
color: root.greeter.buffer && !root.greeter.launching ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface color: root.greeter.buffer && !root.greeter.launching ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
font.weight: 500 font.weight: 500
text: root.greeter.launching ? "hourglass_top" : "arrow_forward" text: root.greeter.launching ? "hourglass_top" : "arrow_forward"
} }
@@ -200,7 +200,7 @@ ColumnLayout {
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: -Appearance.spacing.large Layout.topMargin: -Tokens.spacing.large
implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight) implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight)
Behavior on implicitHeight { Behavior on implicitHeight {
@@ -236,8 +236,8 @@ ColumnLayout {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
animateProp: "opacity" animateProp: "opacity"
color: DynamicColors.palette.m3onSurfaceVariant color: Colors.palette.m3onSurfaceVariant
font.family: Appearance.font.family.mono font.family: Config.appearance.font.family.mono
horizontalAlignment: Qt.AlignHCenter horizontalAlignment: Qt.AlignHCenter
lineHeight: 1.2 lineHeight: 1.2
opacity: shouldBeVisible && !message.msg ? 1 : 0 opacity: shouldBeVisible && !message.msg ? 1 : 0
@@ -291,9 +291,9 @@ ColumnLayout {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: isError ? Colors.palette.m3error : Colors.palette.m3primary
font.family: Appearance.font.family.mono font.family: Config.appearance.font.family.mono
font.pointSize: Appearance.font.size.small font.pointSize: Tokens.font.size.small
horizontalAlignment: Qt.AlignHCenter horizontalAlignment: Qt.AlignHCenter
opacity: 0 opacity: 0
scale: 0.7 scale: 0.7
@@ -363,14 +363,14 @@ ColumnLayout {
id: exitAnim id: exitAnim
Anim { Anim {
duration: Appearance.anim.durations.large duration: Tokens.anim.durations.large
property: "scale" property: "scale"
target: message target: message
to: 0.7 to: 0.7
} }
Anim { Anim {
duration: Appearance.anim.durations.large duration: Tokens.anim.durations.large
property: "opacity" property: "opacity"
target: message target: message
to: 0 to: 0
@@ -380,7 +380,7 @@ ColumnLayout {
} }
component FlashAnim: NumberAnimation { component FlashAnim: NumberAnimation {
duration: Appearance.anim.durations.small duration: Tokens.anim.durations.small
easing.type: Easing.Linear easing.type: Easing.Linear
property: "opacity" property: "opacity"
target: message target: message
+17 -17
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
NumberAnimation { NumberAnimation {
enum Type { enum Type {
@@ -23,41 +23,41 @@ NumberAnimation {
duration: { duration: {
if (type < Anim.StandardSmall || type > Anim.SlowEffects) if (type < Anim.StandardSmall || type > Anim.SlowEffects)
return Appearance.anim.durations.normal; return Tokens.anim.durations.normal;
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Appearance.anim.durations.expressiveFastSpatial; return Tokens.anim.durations.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Appearance.anim.durations.expressiveDefaultSpatial; return Tokens.anim.durations.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Appearance.anim.durations.large; return Tokens.anim.durations.large;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Appearance.anim.durations.expressiveFastEffects; return Tokens.anim.durations.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Appearance.anim.durations.expressiveEffects; return Tokens.anim.durations.expressiveEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Appearance.anim.durations.expressiveSlowEffects; return Tokens.anim.durations.expressiveSlowEffects;
const types = ["small", "normal", "large", "extraLarge"]; const types = ["small", "normal", "large", "extraLarge"];
const idx = type % 4; // 0-7 are the 4 standard types const idx = type % 4; // 0-7 are the 4 standard types
return Appearance.anim.durations[types[idx]]; return Tokens.anim.durations[types[idx]];
} }
easing.bezierCurve: { easing.bezierCurve: {
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Appearance.anim.curves.expressiveFastSpatial; return Tokens.anim.curves.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Appearance.anim.curves.expressiveDefaultSpatial; return Tokens.anim.curves.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Appearance.anim.curves.expressiveSlowSpatial; return Tokens.anim.curves.expressiveSlowSpatial;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Appearance.anim.curves.expressiveFastEffects; return Tokens.anim.curves.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Appearance.anim.curves.expressiveDefaultEffects; return Tokens.anim.curves.expressiveDefaultEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Appearance.anim.curves.expressiveSlowEffects; return Tokens.anim.curves.expressiveSlowEffects;
if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge) if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge)
return Appearance.anim.curves.emphasized; return Tokens.anim.curves.emphasized;
return Appearance.anim.curves.standard; return Tokens.anim.curves.standard;
} }
} }
@@ -1,24 +0,0 @@
import QtQuick
QtObject {
id: root
property real idx1: index
property int idx1Duration: 100
property real idx2: index
property int idx2Duration: 300
required property int index
Behavior on idx1 {
NumberAnimation {
duration: root.idx1Duration
easing.type: Easing.OutSine
}
}
Behavior on idx2 {
NumberAnimation {
duration: root.idx2Duration
easing.type: Easing.OutSine
}
}
}
-165
View File
@@ -1,165 +0,0 @@
import QtQuick
import QtQuick.Templates
import qs.Config
Slider {
id: root
property color color: DynamicColors.palette.m3secondary
required property string icon
property bool initialized: false
readonly property bool isHorizontal: orientation === Qt.Horizontal
readonly property bool isVertical: orientation === Qt.Vertical
property real multiplier: 100
property real oldValue
// Wrapper components can inject their own track visuals here.
property Component trackContent
// Keep current behavior for existing usages.
orientation: Qt.Vertical
background: CustomRect {
id: groove
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
height: root.availableHeight
radius: Appearance.rounding.full
width: root.availableWidth
x: root.leftPadding
y: root.topPadding
Loader {
id: trackLoader
anchors.fill: parent
sourceComponent: root.trackContent
onLoaded: {
if (!item)
return;
item.rootSlider = root;
item.groove = groove;
item.handleItem = handle;
}
}
}
handle: Item {
id: handle
property alias moving: icon.moving
implicitHeight: Math.min(root.width, root.height)
implicitWidth: Math.min(root.width, root.height)
x: root.isHorizontal ? root.leftPadding + root.visualPosition * (root.availableWidth - width) : root.leftPadding + (root.availableWidth - width) / 2
y: root.isVertical ? root.topPadding + root.visualPosition * (root.availableHeight - height) : root.topPadding + (root.availableHeight - height) / 2
Elevation {
anchors.fill: parent
level: handleInteraction.containsMouse ? 2 : 1
radius: rect.radius
}
CustomRect {
id: rect
anchors.fill: parent
color: DynamicColors.palette.m3inverseSurface
radius: Appearance.rounding.full
MouseArea {
id: handleInteraction
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
MaterialIcon {
id: icon
property bool moving
function update(): void {
animate = !moving;
binding.when = moving;
font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger;
font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material;
}
anchors.centerIn: parent
color: DynamicColors.palette.m3inverseOnSurface
text: root.icon
onMovingChanged: anim.restart()
Binding {
id: binding
property: "text"
target: icon
value: Math.round(root.value * root.multiplier)
when: false
}
SequentialAnimation {
id: anim
Anim {
duration: Appearance.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardAccel
property: "scale"
target: icon
to: 0
}
ScriptAction {
script: icon.update()
}
Anim {
duration: Appearance.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardDecel
property: "scale"
target: icon
to: 1
}
}
}
}
}
Behavior on value {
Anim {
duration: Appearance.anim.durations.large
}
}
onPressedChanged: handle.moving = pressed
onValueChanged: {
if (!initialized) {
initialized = true;
oldValue = value;
return;
}
if (Math.abs(value - oldValue) < 0.01)
return;
oldValue = value;
handle.moving = true;
stateChangeDelay.restart();
}
Timer {
id: stateChangeDelay
interval: 500
onTriggered: {
if (!root.pressed)
handle.moving = false;
}
}
}
+59 -4
View File
@@ -1,8 +1,63 @@
import QtQuick import QtQuick
import qs.Config import ZShell.Config
ColorAnimation { ColorAnimation {
duration: MaterialEasing.standardTime enum Type {
easing.bezierCurve: MaterialEasing.standard StandardSmall = 0,
easing.type: Easing.BezierSpline Standard,
StandardLarge,
StandardExtraLarge,
EmphasizedSmall,
Emphasized,
EmphasizedLarge,
EmphasizedExtraLarge,
FastSpatial,
DefaultSpatial,
SlowSpatial,
FastEffects,
DefaultEffects,
SlowEffects
}
property int type: CAnim.DefaultSpatial
duration: {
if (type < CAnim.StandardSmall || type > Anim.SlowEffects)
return Tokens.anim.durations.normal;
if (type === CAnim.FastSpatial)
return Tokens.anim.durations.expressiveFastSpatial;
if (type === CAnim.DefaultSpatial)
return Tokens.anim.durations.expressiveDefaultSpatial;
if (type === CAnim.SlowSpatial)
return Tokens.anim.durations.large;
if (type === CAnim.FastEffects)
return Tokens.anim.durations.expressiveFastEffects;
if (type === CAnim.DefaultEffects)
return Tokens.anim.durations.expressiveEffects;
if (type === CAnim.SlowEffects)
return Tokens.anim.durations.expressiveSlowEffects;
const types = ["small", "normal", "large", "extraLarge"];
const idx = type % 4;
return Tokens.anim.durations[types[idx]];
}
easing.bezierCurve: {
if (type === CAnim.FastSpatial)
return Tokens.anim.curves.expressiveFastSpatial;
if (type === CAnim.DefaultSpatial)
return Tokens.anim.curves.expressiveDefaultSpatial;
if (type === CAnim.SlowSpatial)
return Tokens.anim.curves.expressiveSlowSpatial;
if (type === CAnim.FastEffects)
return Tokens.anim.curves.expressiveFastEffects;
if (type === CAnim.DefaultEffects)
return Tokens.anim.curves.expressiveDefaultEffects;
if (type === CAnim.SlowEffects)
return Tokens.anim.curves.expressiveSlowEffects;
if (type >= CAnim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge)
return Tokens.anim.curves.emphasized;
return Tokens.anim.curves.standard;
}
} }
+11 -11
View File
@@ -1,7 +1,8 @@
import qs.Config import ZShell.Config
import ZShell.Internal import ZShell.Internal
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Services
BusyIndicator { BusyIndicator {
id: root id: root
@@ -17,12 +18,12 @@ BusyIndicator {
} }
property int animState property int animState
property color bgColour: DynamicColors.palette.m3secondaryContainer property color bgColor: Colors.palette.m3secondaryContainer
property color fgColour: DynamicColors.palette.m3primary property color fgColor: Colors.palette.m3primary
property real implicitSize: Appearance.font.size.normal * 3 property real implicitSize: Tokens.font.size.normal * 3
property real internalStrokeWidth: strokeWidth property real internalStrokeWidth: strokeWidth
readonly property alias progress: manager.progress readonly property alias progress: manager.progress
property real strokeWidth: Appearance.padding.small * 0.8 property real strokeWidth: Tokens.padding.small * 0.8
property alias type: manager.indeterminateAnimationType property alias type: manager.indeterminateAnimationType
implicitHeight: implicitSize implicitHeight: implicitSize
@@ -31,8 +32,8 @@ BusyIndicator {
contentItem: CircularProgress { contentItem: CircularProgress {
anchors.fill: parent anchors.fill: parent
bgColour: root.bgColour bgColor: root.bgColor
fgColour: root.fgColour fgColor: root.fgColor
padding: root.padding padding: root.padding
rotation: manager.rotation rotation: manager.rotation
startAngle: manager.startFraction * 360 startAngle: manager.startFraction * 360
@@ -50,7 +51,7 @@ BusyIndicator {
} }
transitions: Transition { transitions: Transition {
Anim { Anim {
duration: manager.completeEndDuration * Appearance.anim.durations.scale duration: manager.completeEndDuration * Tokens.anim.durations.scale
properties: "opacity,internalStrokeWidth" properties: "opacity,internalStrokeWidth"
} }
} }
@@ -73,11 +74,10 @@ BusyIndicator {
CircularIndicatorManager { CircularIndicatorManager {
id: manager id: manager
} }
NumberAnimation { NumberAnimation {
duration: manager.duration * Appearance.anim.durations.scale duration: manager.duration * Tokens.anim.durations.scale
from: 0 from: 0
loops: Animation.Infinite loops: Animation.Infinite
property: "progress" property: "progress"
@@ -87,7 +87,7 @@ BusyIndicator {
} }
NumberAnimation { NumberAnimation {
duration: manager.completeEndDuration * Appearance.anim.durations.scale duration: manager.completeEndDuration * Tokens.anim.durations.scale
from: 0 from: 0
property: "completeEndProgress" property: "completeEndProgress"
running: root.animState === CircularIndicator.Completing running: root.animState === CircularIndicator.Completing
+92 -41
View File
@@ -1,66 +1,117 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import qs.Config import ZShell.Components
import ZShell.Config
import qs.Services
Shape { Item {
id: root id: root
readonly property real arcRadius: (size - padding - strokeWidth) / 2 readonly property real arcRadius: (size - padding - strokeWidth * (1 + waveAmplitude * 2)) / 2
property color bgColour: DynamicColors.palette.m3secondaryContainer property color bgColor: Colors.palette.m3secondaryContainer
property color fgColour: DynamicColors.palette.m3primary property real clampedVal: Math.max(1 / 360, Math.min(1, isNaN(value) ? 0 : value))
readonly property real dotAngleRad: (startAngle + sweepAngle - gapAngle * (sweepAngle < 360 ? 0 : 1)) * Math.PI / 180
property color fgColor: Colors.palette.m3primary
readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI) readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI)
property alias hasEndIndicator: dot.active
property real implicitSize
property int padding: 0 property int padding: 0
readonly property real size: Math.min(width, height) readonly property real size: Math.min(width, height)
property int spacing: Appearance.spacing.small property int spacing: Tokens.spacing.small
property int startAngle: -90 property int startAngle: -90
property int strokeWidth: Appearance.padding.smaller property int strokeWidth: Tokens.padding.small
readonly property real vValue: value || 1 / 360 property int sweepAngle: 360
readonly property real thickness: strokeWidth * (1 + waveAmplitude) * 2
property real value property real value
property alias waveAmplitude: wave.amplitudeMultiplier
property alias waveDuration: waveProgAnim.duration
property alias waveFrequency: wave.frequency
property bool wavePaused
property bool wavy: false
asynchronous: true implicitHeight: implicitSize
preferredRendererType: Shape.CurveRenderer implicitWidth: implicitSize
ShapePath { Shape {
capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap asynchronous: true
fillColor: "transparent" opacity: Math.min(1, remainingArc.sweepAngle)
strokeColor: root.bgColour preferredRendererType: Shape.CurveRenderer
strokeWidth: root.strokeWidth
Behavior on strokeColor { ShapePath {
CAnim { capStyle: ShapePath.RoundCap
duration: Appearance.anim.durations.large fillColor: "transparent"
strokeColor: root.bgColor
strokeWidth: Math.min(1, remainingArc.sweepAngle) * root.strokeWidth
Behavior on strokeColor {
CAnim {
}
} }
}
PathAngleArc { PathAngleArc {
centerX: root.size / 2 id: remainingArc
centerY: root.size / 2
radiusX: root.arcRadius centerX: root.size / 2
radiusY: root.arcRadius centerY: root.size / 2
startAngle: root.startAngle + 360 * root.vValue + root.gapAngle radiusX: root.arcRadius
sweepAngle: Math.max(-root.gapAngle, 360 * (1 - root.vValue) - root.gapAngle * 2) radiusY: root.arcRadius
startAngle: root.startAngle + root.clampedVal * root.sweepAngle + root.gapAngle
sweepAngle: Math.max(1 / 360, root.sweepAngle * (1 - root.clampedVal) - root.gapAngle * (root.sweepAngle < 360 ? 1 : 2))
}
} }
} }
ShapePath { WavyLine {
capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap id: wave
fillColor: "transparent"
strokeColor: root.fgColour
strokeWidth: root.strokeWidth
Behavior on strokeColor { amplitudeMultiplier: root.wavy ? 0.5 : 0
CAnim { anchors.fill: parent
duration: Appearance.anim.durations.large anchors.margins: -lineWidth * amplitudeMultiplier
color: root.fgColor
frequency: 8
fullAngle: root.sweepAngle
lineWidth: root.strokeWidth
pathType: WavyLine.Arc
radius: root.arcRadius
startAngle: root.startAngle
value: root.clampedVal
Behavior on amplitudeMultiplier {
Anim {
type: Anim.DefaultEffects
} }
} }
Behavior on color {
CAnim {
}
}
Anim on waveProgress {
id: waveProgAnim
PathAngleArc { duration: 2000
centerX: root.size / 2 easing.type: Easing.Linear
centerY: root.size / 2 from: 0
radiusX: root.arcRadius loops: Animation.Infinite
radiusY: root.arcRadius paused: root.wavePaused || wave.amplitudeMultiplier === 0
startAngle: root.startAngle running: true
sweepAngle: 360 * root.vValue to: 1
}
}
Loader {
id: dot
x: root.size / 2 + root.arcRadius * Math.cos(root.dotAngleRad) - width / 2
y: root.size / 2 + root.arcRadius * Math.sin(root.dotAngleRad) - height / 2
sourceComponent: CustomRect {
color: root.fgColor
implicitHeight: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth)
implicitWidth: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth)
opacity: Math.min(1, remainingArc.sweepAngle)
radius: Tokens.rounding.full
} }
} }
} }
-135
View File
@@ -1,135 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs.Config
ColumnLayout {
id: root
default property alias content: contentColumn.data
property string description: ""
property bool expanded: false
property bool nested: false
property bool showBackground: false
required property string title
signal toggleRequested
Layout.fillWidth: true
spacing: Appearance.spacing.small
Item {
id: sectionHeaderItem
Layout.fillWidth: true
Layout.preferredHeight: Math.max(titleRow.implicitHeight + Appearance.padding.normal * 2, 48)
RowLayout {
id: titleRow
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.normal
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal
CustomText {
font.pointSize: Appearance.font.size.larger
font.weight: 500
text: root.title
}
Item {
Layout.fillWidth: true
}
MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.normal
rotation: root.expanded ? 180 : 0
text: "expand_more"
Behavior on rotation {
Anim {
duration: Appearance.anim.durations.small
easing.bezierCurve: Appearance.anim.curves.standard
}
}
}
}
StateLayer {
anchors.fill: parent
color: DynamicColors.palette.m3onSurface
radius: Appearance.rounding.normal
showHoverBackground: false
onClicked: {
root.toggleRequested();
root.expanded = !root.expanded;
}
}
}
Item {
id: contentWrapper
Layout.fillWidth: true
Layout.preferredHeight: root.expanded ? (contentColumn.implicitHeight + Appearance.spacing.small * 2) : 0
clip: true
Behavior on Layout.preferredHeight {
Anim {
easing.bezierCurve: Appearance.anim.curves.standard
}
}
CustomRect {
id: backgroundRect
anchors.fill: parent
color: DynamicColors.transparency.enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, root.nested ? 3 : 2) : (root.nested ? DynamicColors.palette.m3surfaceContainerHigh : DynamicColors.palette.m3surfaceContainer)
opacity: root.showBackground && root.expanded ? 1.0 : 0.0
radius: Appearance.rounding.normal
visible: root.showBackground
Behavior on opacity {
Anim {
easing.bezierCurve: Appearance.anim.curves.standard
}
}
}
ColumnLayout {
id: contentColumn
anchors.bottomMargin: Appearance.spacing.small
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.normal
opacity: root.expanded ? 1.0 : 0.0
spacing: Appearance.spacing.small
y: Appearance.spacing.small
Behavior on opacity {
Anim {
easing.bezierCurve: Appearance.anim.curves.standard
}
}
CustomText {
id: descriptionText
Layout.bottomMargin: root.description !== "" ? Appearance.spacing.small : 0
Layout.fillWidth: true
Layout.topMargin: root.description !== "" ? Appearance.spacing.smaller : 0
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.small
text: root.description
visible: root.description !== ""
wrapMode: Text.Wrap
}
}
}
}
-208
View File
@@ -1,208 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.Config
Item {
id: root
readonly property real arcStartAngle: 0.75 * Math.PI
readonly property real arcSweep: 1.5 * Math.PI
property real currentHue: 0
property bool dragActive: false
required property var drawing
readonly property real handleAngle: hueToAngle(currentHue)
readonly property real handleCenterX: width / 2 + radius * Math.cos(handleAngle)
readonly property real handleCenterY: height / 2 + radius * Math.sin(handleAngle)
property real handleSize: 32
property real lastChromaticHue: 0
readonly property real radius: (Math.min(width, height) - handleSize) / 2
readonly property int segmentCount: 240
readonly property color thumbColor: DynamicColors.palette.m3inverseSurface
readonly property color thumbContentColor: DynamicColors.palette.m3inverseOnSurface
readonly property color trackColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
function hueToAngle(hue) {
return arcStartAngle + arcSweep * hue;
}
function normalizeAngle(angle) {
const tau = Math.PI * 2;
let a = angle % tau;
if (a < 0)
a += tau;
return a;
}
function pointIsOnTrack(x, y) {
const cx = width / 2;
const cy = height / 2;
const dx = x - cx;
const dy = y - cy;
const distance = Math.sqrt(dx * dx + dy * dy);
return distance >= radius - handleSize / 2 && distance <= radius + handleSize / 2;
}
function syncFromPenColor() {
if (!drawing)
return;
const c = drawing.penColor;
if (c.hsvSaturation > 0) {
currentHue = c.hsvHue;
lastChromaticHue = c.hsvHue;
} else {
currentHue = lastChromaticHue;
}
canvas.requestPaint();
}
function updateHueFromPoint(x, y, force = false) {
const cx = width / 2;
const cy = height / 2;
const dx = x - cx;
const dy = y - cy;
const distance = Math.sqrt(dx * dx + dy * dy);
if (!force && (distance < radius - handleSize / 2 || distance > radius + handleSize / 2))
return;
const angle = normalizeAngle(Math.atan2(dy, dx));
const start = normalizeAngle(arcStartAngle);
let relative = angle - start;
if (relative < 0)
relative += Math.PI * 2;
if (relative > arcSweep) {
const gap = Math.PI * 2 - arcSweep;
relative = relative < arcSweep + gap / 2 ? arcSweep : 0;
}
currentHue = relative / arcSweep;
lastChromaticHue = currentHue;
drawing.penColor = Qt.hsva(currentHue, drawing.penColor.hsvSaturation, drawing.penColor.hsvValue, drawing.penColor.a);
}
implicitHeight: 180
implicitWidth: 220
Component.onCompleted: syncFromPenColor()
onCurrentHueChanged: canvas.requestPaint()
onDrawingChanged: syncFromPenColor()
onHandleSizeChanged: canvas.requestPaint()
onHeightChanged: canvas.requestPaint()
onWidthChanged: canvas.requestPaint()
Connections {
function onPenColorChanged() {
root.syncFromPenColor();
}
target: root.drawing
}
Canvas {
id: canvas
anchors.fill: parent
renderStrategy: Canvas.Threaded
renderTarget: Canvas.Image
Component.onCompleted: requestPaint()
onPaint: {
const ctx = getContext("2d");
ctx.reset();
ctx.clearRect(0, 0, width, height);
const cx = width / 2;
const cy = height / 2;
const radius = root.radius;
const trackWidth = root.handleSize;
// Background track: always show the full hue spectrum
for (let i = 0; i < root.segmentCount; ++i) {
const t1 = i / root.segmentCount;
const t2 = (i + 1) / root.segmentCount;
const a1 = root.arcStartAngle + root.arcSweep * t1;
const a2 = root.arcStartAngle + root.arcSweep * t2;
ctx.beginPath();
ctx.arc(cx, cy, radius, a1, a2);
ctx.lineWidth = trackWidth;
ctx.lineCap = "round";
ctx.strokeStyle = Qt.hsla(t1, 1.0, 0.5, 1.0);
ctx.stroke();
}
}
}
Item {
id: handle
height: root.handleSize
width: root.handleSize
x: root.handleCenterX - width / 2
y: root.handleCenterY - height / 2
z: 1
Elevation {
anchors.fill: parent
level: handleHover.containsMouse ? 2 : 1
radius: rect.radius
}
Rectangle {
id: rect
anchors.fill: parent
color: root.thumbColor
radius: width / 2
MouseArea {
id: handleHover
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
Rectangle {
anchors.centerIn: parent
color: root.drawing ? root.drawing.penColor : Qt.hsla(root.currentHue, 1.0, 0.5, 1.0)
height: width
radius: width / 2
width: parent.width - 12
}
}
}
MouseArea {
id: dragArea
acceptedButtons: Qt.LeftButton
anchors.fill: parent
hoverEnabled: true
onCanceled: {
root.dragActive = false;
}
onPositionChanged: mouse => {
if ((mouse.buttons & Qt.LeftButton) && root.dragActive)
root.updateHueFromPoint(mouse.x, mouse.y, true);
}
onPressed: mouse => {
root.dragActive = root.pointIsOnTrack(mouse.x, mouse.y);
if (root.dragActive)
root.updateHueFromPoint(mouse.x, mouse.y);
}
onReleased: {
root.dragActive = false;
}
}
}
-34
View File
@@ -1,34 +0,0 @@
pragma ComponentBehavior: Bound
import ZShell
import Quickshell.Widgets
import QtQuick
IconImage {
id: root
required property color color
asynchronous: true
layer.enabled: true
layer.effect: Coloriser {
colorizationColor: root.color
sourceColor: analyser.dominantColour
}
layer.onEnabledChanged: {
if (layer.enabled && status === Image.Ready)
analyser.requestUpdate();
}
onStatusChanged: {
if (layer.enabled && status === Image.Ready)
analyser.requestUpdate();
}
ImageAnalyser {
id: analyser
sourceItem: root
}
}
-14
View File
@@ -1,14 +0,0 @@
import QtQuick
import QtQuick.Effects
MultiEffect {
property color sourceColor: "black"
brightness: 1 - sourceColor.hslLightness
colorization: 1
Behavior on colorizationColor {
CAnim {
}
}
}
-70
View File
@@ -1,70 +0,0 @@
import QtQuick
import QtQuick.Templates
import qs.Config
Slider {
id: root
property color nonPeakColor: DynamicColors.tPalette.m3primary
required property real peak
property color peakColor: DynamicColors.palette.m3primary
background: Item {
CustomRect {
anchors.bottom: parent.bottom
anchors.bottomMargin: root.implicitHeight / 3
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 3
bottomRightRadius: root.implicitHeight / 15
color: root.nonPeakColor
implicitWidth: root.handle.x - root.implicitHeight
radius: Appearance.rounding.full
topRightRadius: root.implicitHeight / 15
CustomRect {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
bottomRightRadius: root.implicitHeight / 15
color: root.peakColor
implicitWidth: parent.width * root.peak
radius: Appearance.rounding.full
topRightRadius: root.implicitHeight / 15
Behavior on implicitWidth {
Anim {
duration: 50
}
}
}
}
CustomRect {
anchors.bottom: parent.bottom
anchors.bottomMargin: root.implicitHeight / 3
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 3
bottomLeftRadius: root.implicitHeight / 15
color: DynamicColors.tPalette.m3surfaceContainer
implicitWidth: root.implicitWidth - root.handle.x - root.handle.implicitWidth - root.implicitHeight
radius: Appearance.rounding.full
topLeftRadius: root.implicitHeight / 15
}
}
handle: CustomRect {
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3primary
implicitHeight: 15
implicitWidth: 5
radius: Appearance.rounding.full
x: root.visualPosition * root.availableWidth - implicitWidth / 2
MouseArea {
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
}
}
}
@@ -1,69 +0,0 @@
import QtQuick
import QtQuick.Controls.Basic
BusyIndicator {
id: control
property int busySize: 64
property color color: delegate.color
contentItem: Item {
implicitHeight: control.busySize
implicitWidth: control.busySize
Item {
id: item
height: control.busySize
opacity: control.running ? 1 : 0
width: control.busySize
x: parent.width / 2 - (control.busySize / 2)
y: parent.height / 2 - (control.busySize / 2)
Behavior on opacity {
OpacityAnimator {
duration: 250
}
}
RotationAnimator {
duration: 1250
from: 0
loops: Animation.Infinite
running: control.visible && control.running
target: item
to: 360
}
Repeater {
id: repeater
model: 6
CustomRect {
id: delegate
required property int index
color: control.color
implicitHeight: 10
implicitWidth: 10
radius: 5
x: item.width / 2 - width / 2
y: item.height / 2 - height / 2
transform: [
Translate {
y: -Math.min(item.width, item.height) * 0.5 + 5
},
Rotation {
angle: delegate.index / repeater.count * 360
origin.x: 5
origin.y: 5
}
]
}
}
}
}
}
-32
View File
@@ -1,32 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Config
Button {
id: control
property color bgColor: DynamicColors.palette.m3primary
property int radius: Appearance.rounding.smallest / 2
property color textColor: DynamicColors.palette.m3onPrimary
background: CustomRect {
color: control.bgColor
opacity: control.enabled ? 1.0 : 0.5
radius: control.radius
}
contentItem: CustomText {
color: control.textColor
horizontalAlignment: Text.AlignHCenter
opacity: control.enabled ? 1.0 : 0.5
text: control.text
verticalAlignment: Text.AlignVCenter
}
StateLayer {
radius: control.radius
onClicked: {
control.clicked();
}
}
}
-37
View File
@@ -1,37 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Config
CheckBox {
id: control
property int checkHeight: 20
property int checkWidth: 20
contentItem: CustomText {
anchors.left: parent.left
anchors.leftMargin: control.checkWidth + control.leftPadding + 8
anchors.verticalCenter: parent.verticalCenter
font.pointSize: control.font.pointSize
text: control.text
}
indicator: CustomRect {
// x: control.leftPadding
// y: parent.implicitHeight / 2 - implicitHeight / 2
border.color: control.checked ? DynamicColors.palette.m3primary : "transparent"
color: DynamicColors.palette.m3surfaceVariant
implicitHeight: control.checkHeight
implicitWidth: control.checkWidth
radius: Appearance.rounding.smallest / 2
CustomRect {
color: DynamicColors.palette.m3primary
implicitHeight: control.checkHeight - (y * 2)
implicitWidth: control.checkWidth - (x * 2)
radius: 3
visible: control.checked
x: 4
y: 4
}
}
}
-169
View File
@@ -1,169 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import qs.Config
ComboBox {
id: root
property int cornerRadius: Appearance.rounding.normal
property int fieldHeight: 42
property bool filled: true
property real focusRingOpacity: 0.70
property int hPadding: 16
property int menuCornerRadius: 16
property int menuRowHeight: 46
property int menuVisibleRows: 7
property bool preferPopupWindow: false
hoverEnabled: true
implicitHeight: fieldHeight
implicitWidth: 240
spacing: 8
// ---------- Field background (filled/outlined + state layers + focus ring) ----------
background: Item {
anchors.fill: parent
CustomRect {
id: container
anchors.fill: parent
color: DynamicColors.palette.m3surfaceVariant
radius: root.cornerRadius
StateLayer {
}
}
}
// ---------- Content ----------
contentItem: RowLayout {
anchors.fill: parent
anchors.leftMargin: root.hPadding
anchors.rightMargin: root.hPadding
spacing: 12
// Display text
CustomText {
Layout.fillWidth: true
color: root.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSurfaceVariant
elide: Text.ElideRight
font.pixelSize: 16
font.weight: Font.Medium
text: root.currentText
verticalAlignment: Text.AlignVCenter
}
// Indicator chevron (simple, replace with your icon system)
CustomText {
color: root.enabled ? DynamicColors.palette.m3onSurfaceVariant : DynamicColors.palette.m3onSurfaceVariant
rotation: root.popup.visible ? 180 : 0
text: "▾"
transformOrigin: Item.Center
verticalAlignment: Text.AlignVCenter
Behavior on rotation {
NumberAnimation {
duration: 140
easing.type: Easing.OutCubic
}
}
}
}
popup: Popup {
id: p
implicitHeight: list.contentItem.height + Appearance.padding.small * 2
implicitWidth: root.width
modal: true
popupType: root.preferPopupWindow ? Popup.Window : Popup.Item
y: -list.currentIndex * (root.menuRowHeight + Appearance.spacing.small) - Appearance.padding.small
background: CustomRect {
color: DynamicColors.palette.m3surface
radius: root.menuCornerRadius
}
contentItem: ListView {
id: list
anchors.bottomMargin: Appearance.padding.small
anchors.fill: parent
anchors.topMargin: Appearance.padding.small
clip: true
currentIndex: root.currentIndex
model: root.delegateModel
spacing: Appearance.spacing.small
delegate: CustomRect {
required property int index
required property var modelData
anchors.horizontalCenter: parent.horizontalCenter
color: (index === root.currentIndex) ? DynamicColors.palette.m3primary : "transparent"
implicitHeight: root.menuRowHeight
implicitWidth: p.implicitWidth - Appearance.padding.small * 2
radius: Appearance.rounding.normal - Appearance.padding.small
RowLayout {
anchors.fill: parent
spacing: 10
CustomText {
Layout.fillWidth: true
color: DynamicColors.palette.m3onSurface
elide: Text.ElideRight
font.pixelSize: 15
text: modelData
verticalAlignment: Text.AlignVCenter
}
CustomText {
color: DynamicColors.palette.m3onSurfaceVariant
text: "✓"
verticalAlignment: Text.AlignVCenter
visible: index === root.currentIndex
}
}
StateLayer {
onClicked: {
root.currentIndex = index;
p.close();
}
}
}
}
// Expressive-ish open/close motion: subtle scale+fade (tune to taste). :contentReference[oaicite:5]{index=5}
enter: Transition {
Anim {
from: 0
property: "opacity"
to: 1
}
Anim {
from: 0.98
property: "scale"
to: 1.0
}
}
exit: Transition {
Anim {
from: 1
property: "opacity"
to: 0
}
}
Elevation {
anchors.fill: parent
level: 2
radius: root.menuCornerRadius
z: -1
}
}
}
-10
View File
@@ -1,10 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell.Widgets
import QtQuick
IconImage {
id: root
asynchronous: true
}
-53
View File
@@ -1,53 +0,0 @@
import QtQuick
import QtQuick.Templates
import qs.Config
RadioButton {
id: root
font.pointSize: Appearance.font.size.normal
implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight)
implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin
contentItem: CustomText {
anchors.left: outerCircle.right
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
font.pointSize: root.font.pointSize
text: root.text
}
indicator: Rectangle {
id: outerCircle
anchors.verticalCenter: parent.verticalCenter
border.color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant
border.width: 2
color: "transparent"
implicitHeight: 16
implicitWidth: 16
radius: Appearance.rounding.full
Behavior on border.color {
CAnim {
}
}
StateLayer {
anchors.margins: -7
color: root.checked ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3primary
z: -1
onClicked: {
root.click();
}
}
CustomRect {
anchors.centerIn: parent
color: Qt.alpha(DynamicColors.palette.m3primary, root.checked ? 1 : 0)
implicitHeight: 8
implicitWidth: 8
radius: Appearance.rounding.full
}
}
}
-189
View File
@@ -1,189 +0,0 @@
import qs.Config
import QtQuick
import QtQuick.Templates
ScrollBar {
id: root
property bool _updatingFromFlickable: false
property bool _updatingFromUser: false
property bool animating
required property Flickable flickable
property real nonAnimPosition
property bool shouldBeActive
implicitWidth: 8
contentItem: CustomRect {
anchors.left: parent.left
anchors.right: parent.right
color: DynamicColors.palette.m3secondary
opacity: {
if (root.size === 1)
return 0;
if (fullMouse.pressed)
return 1;
if (mouse.containsMouse)
return 0.8;
if (root.policy === ScrollBar.AlwaysOn || root.shouldBeActive)
return 0.6;
return 0;
}
radius: Appearance.rounding.full
Behavior on opacity {
Anim {
}
}
MouseArea {
id: mouse
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
}
Behavior on position {
enabled: !fullMouse.pressed
Anim {
}
}
Component.onCompleted: {
if (flickable) {
const contentHeight = flickable.contentHeight;
const height = flickable.height;
if (contentHeight > height) {
nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height)));
}
}
}
onHoveredChanged: {
if (hovered)
shouldBeActive = true;
else
shouldBeActive = flickable.moving;
}
// Sync nonAnimPosition with Qt's automatic position binding
onPositionChanged: {
if (_updatingFromUser) {
_updatingFromUser = false;
return;
}
if (position === nonAnimPosition) {
animating = false;
return;
}
if (!animating && !_updatingFromFlickable && !fullMouse.pressed) {
nonAnimPosition = position;
}
}
// Sync nonAnimPosition with flickable when not animating
Connections {
function onContentYChanged() {
if (!animating && !fullMouse.pressed) {
_updatingFromFlickable = true;
const contentHeight = flickable.contentHeight;
const height = flickable.height;
if (contentHeight > height) {
nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height)));
} else {
nonAnimPosition = 0;
}
_updatingFromFlickable = false;
}
}
target: flickable
}
Connections {
function onMovingChanged(): void {
if (root.flickable.moving)
root.shouldBeActive = true;
else
hideDelay.restart();
}
target: root.flickable
}
Timer {
id: hideDelay
interval: 600
onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered
}
CustomMouseArea {
id: fullMouse
function onWheel(event: WheelEvent): void {
root.animating = true;
root._updatingFromUser = true;
let newPos = root.nonAnimPosition;
if (event.angleDelta.y > 0)
newPos = Math.max(0, root.nonAnimPosition - 0.1);
else if (event.angleDelta.y < 0)
newPos = Math.min(1 - root.size, root.nonAnimPosition + 0.1);
root.nonAnimPosition = newPos;
// Update flickable position
// Map scrollbar position [0, 1-size] to contentY [0, maxContentY]
if (root.flickable) {
const contentHeight = root.flickable.contentHeight;
const height = root.flickable.height;
if (contentHeight > height) {
const maxContentY = contentHeight - height;
const maxPos = 1 - root.size;
const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0;
root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY));
}
}
}
anchors.fill: parent
preventStealing: true
onPositionChanged: event => {
root._updatingFromUser = true;
const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2));
root.nonAnimPosition = newPos;
// Update flickable position
// Map scrollbar position [0, 1-size] to contentY [0, maxContentY]
if (root.flickable) {
const contentHeight = root.flickable.contentHeight;
const height = root.flickable.height;
if (contentHeight > height) {
const maxContentY = contentHeight - height;
const maxPos = 1 - root.size;
const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0;
root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY));
}
}
}
onPressed: event => {
root.animating = true;
root._updatingFromUser = true;
const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2));
root.nonAnimPosition = newPos;
// Update flickable position
// Map scrollbar position [0, 1-size] to contentY [0, maxContentY]
if (root.flickable) {
const contentHeight = root.flickable.contentHeight;
const height = root.flickable.height;
if (contentHeight > height) {
const maxContentY = contentHeight - height;
const maxPos = 1 - root.size;
const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0;
root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY));
}
}
}
}
}
-5
View File
@@ -1,5 +0,0 @@
import Quickshell.Hyprland
GlobalShortcut {
appid: "zshell"
}
-174
View File
@@ -1,174 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Templates
import ZShell.Components
import ZShell
import qs.Components
import qs.Config
Slider {
id: root
property bool animateWave
property color bgColor: enabled ? DynamicColors.palette.m3secondaryContainer : Qt.alpha(DynamicColors.palette.m3onSurface, 0.1)
property color fgColor: enabled ? DynamicColors.palette.m3primary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.38)
property real filledWidth
property real pos: visualPosition
property int waveDuration: 1000
property real waveFrequency: 6
property bool wavy
signal interaction(v: real)
implicitHeight: 12
implicitWidth: 200
contentItem: Item {
anchors.fill: parent
CustomRect {
id: remaining
anchors.left: handle.right
anchors.leftMargin: Appearance.spacing.extraSmall
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
bottomLeftRadius: Appearance.rounding.extraSmall / 2
color: root.bgColor
implicitHeight: parent.height * (parent.height <= 12 ? opacity : Math.min(opacity * 2, 1))
opacity: Math.min(width, 12) / 12
radius: Appearance.rounding.small
topLeftRadius: Appearance.rounding.extraSmall / 2
}
CustomRect {
anchors.right: parent.right
anchors.rightMargin: 4 * remaining.opacity
anchors.verticalCenter: parent.verticalCenter
color: root.fgColor
implicitHeight: 4 * remaining.opacity
implicitWidth: implicitHeight
opacity: remaining.opacity
radius: Appearance.rounding.full
}
CustomRect {
id: handle
anchors.left: filled.right
anchors.leftMargin: Appearance.spacing.extraSmall
anchors.verticalCenter: parent.verticalCenter
color: root.fgColor
implicitHeight: {
const mult = parent.height <= 12 ? 3 : 1.2;
const pressMult = parent.height <= 12 ? 4 : 1.5;
return parent.height * (mouse.pressed ? pressMult : mult);
}
implicitWidth: 4
radius: Appearance.rounding.full
Behavior on implicitHeight {
Anim {
type: Anim.FastSpatial
}
}
}
Loader {
id: filled
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
asynchronous: true
sourceComponent: root.wavy ? waveComp : lineComp
}
Component {
id: lineComp
CustomRect {
bottomRightRadius: Appearance.rounding.extraSmall / 2
color: root.fgColor
implicitHeight: root.height
implicitWidth: root.filledWidth
radius: Appearance.rounding.small
topRightRadius: Appearance.rounding.extraSmall / 2
}
}
Component {
id: waveComp
WavyLine {
color: root.fgColor
frequency: root.waveFrequency
fullLength: root.width - handle.implicitWidth - handle.anchors.leftMargin
implicitHeight: lineWidth * amplitudeMultiplier * 2 + lineWidth
implicitWidth: root.filledWidth
lineWidth: root.height * 0.7
startX: x
Behavior on color {
CAnim {
}
}
Anim on waveProgress {
duration: root.waveDuration
easing.type: Easing.Linear
from: 0
loops: Animation.Infinite
paused: !root.animateWave
running: true
to: 1
}
}
}
}
Behavior on filledWidth {
id: widthBehavior
Anim {
}
}
Component.onCompleted: filledWidth = Qt.binding(() => (width - handle.implicitWidth - handle.anchors.leftMargin) * pos)
Binding {
id: posBinding
property: "pos"
target: root
value: ZUtils.clamp(mouse.pressStartPos + mouse.dragMovement, 0, 1)
when: mouse.pressed
}
MouseArea {
id: mouse
property real dragMovement
property real pressStartPos
property real pressStartX
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
implicitHeight: handle.implicitHeight
preventStealing: true
onPositionChanged: e => {
dragMovement = (e.x - pressStartX) / width;
root.interaction(posBinding.value);
}
onPressed: e => {
widthBehavior.enabled = false;
pressStartX = e.x;
pressStartPos = root.visualPosition;
}
onReleased: e => {
root.interaction(posBinding.value);
widthBehavior.enabled = true;
dragMovement = 0;
}
}
}
-168
View File
@@ -1,168 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
RowLayout {
id: root
property string displayText: root.value.toString()
property bool isEditing: false
property real max: Infinity
property real min: -Infinity
property alias repeatRate: timer.interval
property real step: 1
property real value
signal valueModified(value: real)
spacing: Appearance.spacing.small
onValueChanged: {
if (!root.isEditing) {
root.displayText = root.value.toString();
}
}
CustomTextField {
id: textField
color: root.enabled ? DynamicColors.palette.m3onSurface : Qt.alpha(DynamicColors.palette.m3onSurface, 0.5)
implicitHeight: upButton.implicitHeight
inputMethodHints: Qt.ImhFormattedNumbersOnly
leftPadding: Appearance.padding.normal
padding: Appearance.padding.small
rightPadding: Appearance.padding.normal
text: root.isEditing ? text : root.displayText
background: CustomRect {
color: root.enabled ? DynamicColors.tPalette.m3surfaceContainerHigh : DynamicColors.tPalette.m3surfaceContainerLow
implicitWidth: 100
radius: Appearance.rounding.full
}
validator: DoubleValidator {
bottom: root.min
decimals: root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0
top: root.max
}
onAccepted: {
const numValue = parseFloat(text);
if (!isNaN(numValue)) {
const clampedValue = Math.max(root.min, Math.min(root.max, numValue));
root.value = clampedValue;
root.displayText = clampedValue.toString();
root.valueModified(clampedValue);
} else {
text = root.displayText;
}
root.isEditing = false;
}
onActiveFocusChanged: {
if (activeFocus) {
root.isEditing = true;
} else {
root.isEditing = false;
root.displayText = root.value.toString();
}
}
onEditingFinished: {
if (text !== root.displayText) {
const numValue = parseFloat(text);
if (!isNaN(numValue)) {
const clampedValue = Math.max(root.min, Math.min(root.max, numValue));
root.value = clampedValue;
root.displayText = clampedValue.toString();
root.valueModified(clampedValue);
} else {
text = root.displayText;
}
}
root.isEditing = false;
}
}
CustomRect {
id: upButton
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
radius: Appearance.rounding.full
StateLayer {
id: upState
color: DynamicColors.palette.m3onPrimary
onClicked: {
let newValue = Math.min(root.max, root.value + root.step);
// Round to avoid floating point precision errors
const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
root.value = newValue;
root.displayText = newValue.toString();
root.valueModified(newValue);
}
onPressAndHold: timer.start()
onReleased: timer.stop()
}
MaterialIcon {
id: upIcon
anchors.centerIn: parent
color: root.enabled ? DynamicColors.palette.m3onPrimary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.5)
text: "keyboard_arrow_up"
}
}
CustomRect {
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
implicitHeight: downIcon.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
radius: Appearance.rounding.full
StateLayer {
id: downState
color: DynamicColors.palette.m3onPrimary
onClicked: {
let newValue = Math.max(root.min, root.value - root.step);
// Round to avoid floating point precision errors
const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
root.value = newValue;
root.displayText = newValue.toString();
root.valueModified(newValue);
}
onPressAndHold: timer.start()
onReleased: timer.stop()
}
MaterialIcon {
id: downIcon
anchors.centerIn: parent
color: root.enabled ? DynamicColors.palette.m3onPrimary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.5)
text: "keyboard_arrow_down"
}
}
Timer {
id: timer
interval: 100
repeat: true
triggeredOnStart: true
onTriggered: {
if (upState.pressed)
upState.onClicked();
else if (downState.pressed)
downState.onClicked();
}
}
}
-148
View File
@@ -1,148 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs.Config
Row {
id: root
enum Type {
Filled,
Tonal
}
property alias active: menu.active
property color colour: type == CustomSplitButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondaryContainer
property bool disabled
property color disabledColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1)
property color disabledTextColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38)
readonly property alias expandBtn: expandBtn
property alias expanded: menu.expanded
property string fallbackIcon
property string fallbackText
property real horizontalPadding: Appearance.padding.larger
readonly property alias iconLabel: iconLabel
readonly property alias label: label
readonly property alias menu: menu
property alias menuItems: menu.items
property bool menuOnTop
property real minLeftWidth
readonly property alias stateLayer: stateLayer
property color textColour: type == CustomSplitButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondaryContainer
readonly property alias textRow: textRow
property int type: CustomSplitButton.Filled
property real verticalPadding: Appearance.padding.small
spacing: Math.floor(Appearance.spacing.extraSmall)
CustomRect {
bottomRightRadius: Appearance.rounding.small / 2
color: root.disabled ? root.disabledColour : root.colour
implicitHeight: expandBtn.implicitHeight
implicitWidth: Math.max(root.minLeftWidth, textRow.implicitWidth + root.horizontalPadding * 2)
radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale)
topRightRadius: Appearance.rounding.small / 2
StateLayer {
id: stateLayer
bottomRightRadius: parent.bottomRightRadius
color: root.textColour
disabled: root.disabled
topRightRadius: parent.topRightRadius
onClicked: root.active?.clicked()
}
RowLayout {
id: textRow
anchors.centerIn: parent
anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4)
spacing: Appearance.spacing.small
MaterialIcon {
id: iconLabel
Layout.alignment: Qt.AlignVCenter
animate: true
color: root.disabled ? root.disabledTextColour : root.textColour
fill: 1
text: root.active?.activeIcon ?? root.fallbackIcon
}
CustomText {
id: label
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: implicitWidth
animate: true
clip: true
color: root.disabled ? root.disabledTextColour : root.textColour
text: root.active?.activeText ?? root.fallbackText
Behavior on Layout.preferredWidth {
Anim {
type: Anim.Emphasized
}
}
}
}
}
CustomRect {
id: expandBtn
property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) : Appearance.rounding.small / 2
bottomLeftRadius: rad
color: root.disabled ? root.disabledColour : root.colour
implicitHeight: expandIcon.implicitHeight + root.verticalPadding * 2
implicitWidth: implicitHeight
radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale)
topLeftRadius: rad
Behavior on rad {
Anim {
}
}
StateLayer {
id: expandStateLayer
color: root.textColour
disabled: root.disabled
rect.bottomLeftRadius: parent.bottomLeftRadius
rect.topLeftRadius: parent.topLeftRadius
onClicked: root.expanded = !root.expanded
}
MaterialIcon {
id: expandIcon
anchors.centerIn: parent
anchors.horizontalCenterOffset: root.expanded ? 0 : -Math.floor(root.verticalPadding / 4)
color: root.disabled ? root.disabledTextColour : root.textColour
rotation: root.expanded ? 180 : 0
text: "expand_more"
Behavior on anchors.horizontalCenterOffset {
Anim {
}
}
Behavior on rotation {
Anim {
}
}
}
}
Menu {
id: menu
attachSideY: root.menuOnTop ? Menu.Top : Menu.Bottom
attachTo: expandBtn
marginY: Appearance.spacing.small * (root.menuOnTop ? -1 : 1)
thisSideY: root.menuOnTop ? Menu.Bottom : Menu.Top
}
}

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