Author SHA1 Message Date
zach 53f0aa80ae Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 30s
Python / test (pull_request) Successful in 42s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m36s
C++ / build (pull_request) Successful in 2m20s
2026-07-08 13:41:27 +02:00
Inorishio d9856c9409 Chore: created NetworkItem component, renamed network header to Wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 14s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m51s
C++ / build (pull_request) Successful in 2m36s
2026-07-02 22:46:09 +02:00
zach 8dc9753e2b feat: don't add the same network twice
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 30s
Python / lint-format (pull_request) Successful in 48s
Python / test (pull_request) Successful in 40s
C++ / build (pull_request) Successful in 2m8s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m13s
2026-07-02 22:09:25 +02:00
zach 2a4bd3dfdd chore: remove old code
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 17s
Python / lint-format (pull_request) Successful in 31s
Python / test (pull_request) Successful in 39s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m31s
C++ / build (pull_request) Successful in 2m17s
2026-07-02 21:58:01 +02:00
zach f75f51ef50 fix: sort is now correct
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 18s
Python / lint-format (pull_request) Successful in 21s
Python / test (pull_request) Successful in 48s
C++ / build (pull_request) Successful in 2m59s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m12s
2026-07-02 21:54:58 +02:00
zach e0873304d1 add sorting by strength
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 15s
Python / lint-format (pull_request) Successful in 32s
Python / test (pull_request) Successful in 39s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m45s
C++ / build (pull_request) Successful in 2m47s
2026-07-02 21:53:42 +02:00
zach 99a0155c17 Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 14s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m30s
C++ / build (pull_request) Successful in 2m32s
2026-07-02 21:46:15 +02:00
zach f309debea5 set scannerEnabled when popout is visible + remove scan button
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 18s
Python / lint-format (pull_request) Successful in 20s
Python / test (pull_request) Successful in 47s
C++ / build (pull_request) Successful in 3m9s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m15s
2026-07-02 16:06:52 +02:00
zach 0979fd014d Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 16s
Python / lint-format (pull_request) Successful in 32s
Python / test (pull_request) Successful in 38s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m49s
C++ / build (pull_request) Successful in 3m5s
2026-07-02 15:16:22 +02:00
zach 656bd0a54d Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 16s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m37s
C++ / build (pull_request) Successful in 2m22s
2026-06-30 22:42:51 +02:00
zach f01001dcfa merge main into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 9s
Python / lint-format (pull_request) Successful in 16s
Python / test (pull_request) Successful in 49s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m42s
C++ / build (pull_request) Successful in 2m28s
2026-06-30 18:15:43 +02:00
zach bc6b0d50ab Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 34s
Python / lint-format (pull_request) Successful in 35s
Python / test (pull_request) Successful in 1m11s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m58s
C++ / build (pull_request) Successful in 4m31s
2026-06-29 22:10:45 +02:00
zach f27c9afc25 more methods for wifi and scanning + layout
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 15s
Python / test (pull_request) Successful in 29s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m6s
2026-06-26 15:15:03 +02:00
Inorishio 5962fc8354 Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 17s
Python / lint-format (pull_request) Successful in 27s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m39s
2026-06-24 18:58:36 +02:00
Inorishio 1adcb9841c Added network properties, nicNames, netDevices, networkName < reminder I should use layouts.
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 16s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m52s
2026-06-22 23:34:58 +02:00
Inorishio 0e0f8555ed fixing singleton in helpers for network + getting output from systray 2026-06-15 20:48:01 +02:00
Inorishio 1d63e67554 removed network module and moved it to tray, have a popout window without content! everything still in wi.i.p. 2026-06-13 18:22:03 +02:00
437 changed files with 13380 additions and 16019 deletions
-108
View File
@@ -1,108 +0,0 @@
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
@@ -1,51 +0,0 @@
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
@@ -1,59 +0,0 @@
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
+3 -3
View File
@@ -2,7 +2,7 @@ name: Rebuild CI Image
on: on:
schedule: schedule:
- cron: "0 6 * * 1" - cron: '0 6 * * 1'
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@@ -11,7 +11,7 @@ jobs:
container: container:
image: node:26-alpine image: node:26-alpine
env: env:
IMAGE: git.aramjonghu.dev/aramjonghu/zshell-ci:latest IMAGE: git.aramjonghu.nl/aramjonghu/zshell-ci:latest
steps: steps:
- name: Checkout - name: Checkout
@@ -21,7 +21,7 @@ jobs:
run: apk add --no-cache docker-cli run: apk add --no-cache docker-cli
- name: Login to registry - name: Login to registry
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.aramjonghu.dev --username aramjonghu --password-stdin run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.aramjonghu.nl --username aramjonghu --password-stdin
- name: Build image - name: Build image
run: docker build -t "$IMAGE" -f ci/Dockerfile . run: docker build -t "$IMAGE" -f ci/Dockerfile .
+1 -34
View File
@@ -4,43 +4,10 @@ on:
pull_request: pull_request:
jobs: jobs:
fmt:
runs-on: alpine
container:
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Format check
run: |
find . \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) \
-not -path './build/*' \
-exec clang-format -i --style=file {} +
git diff --exit-code && echo "clang-format: passed"
build: build:
runs-on: alpine runs-on: alpine
container: container:
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest image: git.aramjonghu.nl/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure
run: cmake -B build -G Ninja -DENABLE_MODULES=plugin -DCMAKE_BUILD_TYPE=Release
- name: Build
run: ninja -C build
clang-tidy:
runs-on: alpine
container:
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
steps: steps:
- name: Checkout - name: Checkout
@@ -1,10 +1,10 @@
name: JS/TS name: Lint & Format (JS/TS)
on: on:
pull_request: pull_request:
jobs: jobs:
fmt: lint-format:
runs-on: alpine runs-on: alpine
container: node:26-alpine container: node:26-alpine
@@ -18,6 +18,7 @@ jobs:
git git
- name: Prettier - name: Prettier
continue-on-error: true
run: | run: |
if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then
npx --yes prettier --check "**/*.{js,jsx,ts,tsx,mjs,cjs}" --ignore-path .prettierignore npx --yes prettier --check "**/*.{js,jsx,ts,tsx,mjs,cjs}" --ignore-path .prettierignore
@@ -25,19 +26,6 @@ jobs:
echo "No JS/TS files found" echo "No JS/TS files found"
fi fi
lint:
runs-on: alpine
container: node:26-alpine
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apk add --no-cache \
git
- name: ESLint - name: ESLint
run: | run: |
if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then
+65
View File
@@ -0,0 +1,65 @@
name: Python
on:
pull_request:
jobs:
lint-format:
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 ruff
- name: Format check
continue-on-error: true
run: |
. .venv/bin/activate
ruff format --check .
- name: Lint
run: |
. .venv/bin/activate
ruff check .
test:
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 \
py3-pillow \
build-base
python3 -m venv .venv
. .venv/bin/activate
pip install --no-cache-dir \
typer \
pillow \
materialyoucolor \
jinja2 \
pytest
- name: Test
run: |
. .venv/bin/activate
cd cli
python -m pytest tests/ -v
+85
View File
@@ -0,0 +1,85 @@
name: Lint & Format (Rust)
on:
pull_request:
jobs:
lint-format:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rustfmt \
rust-clippy
- id: format-check
name: Format check
continue-on-error: true
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo fmt --manifest-path "$manifest" --check && \
echo "$manifest: formatting OK" || \
{ echo "$manifest: needs formatting"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
- id: clippy
name: Clippy
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo clippy --manifest-path "$manifest" --all-targets --all-features -- -D warnings && \
echo "$manifest: Clippy passed" || \
{ echo "$manifest: Clippy failed"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
- name: Check results
if: always()
run: |
if [ "${{ steps.format-check.outcome }}" = "failure" ] || [ "${{ steps.clippy.outcome }}" = "failure" ]; then
echo "One or more checks failed"
exit 1
fi
echo "All checks passed"
-67
View File
@@ -1,67 +0,0 @@
name: Python
env:
APT_DEPS: git python3 python3-pip python3-venv python3-gi python3-cairo python3-dbus python3-pyudev python3-psutil python3-evdev python3-yaml python3-xlib python3-pillow gir1.2-gtk-3.0
on:
pull_request:
jobs:
static:
runs-on: debian
container: node:26-trixie-slim
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apt-get update
apt-get install -y --no-install-recommends git python3 python3-pip python3-venv
python3 -m venv .venv
. .venv/bin/activate
pip install --no-cache-dir ruff
- name: Format check
run: |
. .venv/bin/activate
ruff format --check .
- name: Lint
run: |
. .venv/bin/activate
ruff check .
verify:
if: always()
runs-on: debian
container: node:26-trixie-slim
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apt-get update
apt-get install -y --no-install-recommends $APT_DEPS build-essential python3-dev
python3 -m venv --system-site-packages .venv
. .venv/bin/activate
pip install --no-cache-dir basedpyright nuitka .
- name: Type check
run: |
. .venv/bin/activate
basedpyright
- name: Test
run: |
. .venv/bin/activate
cd cli
python -m pytest tests/ -v
- name: Nuitka module check
run: |
. .venv/bin/activate
nuitka --module --include-package=zshell cli/src/zshell/
-152
View File
@@ -1,152 +0,0 @@
name: Rust
on:
pull_request:
jobs:
build:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-build-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust
- name: Cargo check
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
for manifest in $(find . -name "Cargo.toml"); do
cargo check --manifest-path "$manifest" && \
echo "$manifest: check passed" || \
{ echo "$manifest: check failed"; exit 1; }
done
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
fmt:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-fmt-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rustfmt
- name: Format check
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo fmt --manifest-path "$manifest" --check && \
echo "$manifest: formatting OK" || \
{ echo "$manifest: needs formatting"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
clippy:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-clippy-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rust-clippy
- name: Clippy
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo clippy --manifest-path "$manifest" --all-targets --all-features -- -D warnings && \
echo "$manifest: Clippy passed" || \
{ echo "$manifest: Clippy failed"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
+1 -3
View File
@@ -15,6 +15,4 @@ dist/
**/target/ **/target/
**/test-plugins/ **/test-plugins/
**/Charts/ **/Charts/
network-dev/ **/network-dev/
**/zshell.build/
**/zshell.dist/
+33 -92
View File
@@ -36,15 +36,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(ENABLE_MODULES "plugin;shell;m3shapes" CACHE STRING "Modules to build/install") set(ENABLE_MODULES "plugin;shell" CACHE STRING "Modules to build/install")
set(INSTALL_LIBDIR "usr/lib/ZShell" CACHE STRING "Library install dir") set(INSTALL_LIBDIR "usr/lib/ZShell" CACHE STRING "Library install dir")
set(INSTALL_QMLDIR "usr/lib/qt6/qml" CACHE STRING "QML install dir") set(INSTALL_QMLDIR "usr/lib/qt6/qml" CACHE STRING "QML install dir")
set(INSTALL_QSCONFDIR "etc/xdg/quickshell/zshell" CACHE STRING "Quickshell config install dir") set(INSTALL_QSCONFDIR "etc/xdg/quickshell/zshell" CACHE STRING "Quickshell config install dir")
set(INSTALL_GREETERCONFDIR "etc/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir") set(INSTALL_GREETERCONFDIR "etc/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir")
set(CMAKE_INSTALL_MESSAGE NEVER)
add_compile_options( add_compile_options(
-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wall -Wextra -Wpedantic -Wshadow -Wconversion
-Wold-style-cast -Wnull-dereference -Wdouble-promotion -Wold-style-cast -Wnull-dereference -Wdouble-promotion
@@ -74,90 +72,52 @@ if("shell" IN_LIST ENABLE_MODULES)
set(ZSHELL_CLI_DIST "${ZSHELL_CLI_BUILD_DIR}/zshell.dist") set(ZSHELL_CLI_DIST "${ZSHELL_CLI_BUILD_DIR}/zshell.dist")
set(ZSHELL_CLI_SRC "${CMAKE_SOURCE_DIR}/cli/src/zshell") set(ZSHELL_CLI_SRC "${CMAKE_SOURCE_DIR}/cli/src/zshell")
find_program(NUITKA_EXECUTABLE nuitka) find_program(NUITKA_EXECUTABLE nuitka REQUIRED)
if(NUITKA_EXECUTABLE) file(GLOB_RECURSE ZSHELL_CLI_SOURCES CONFIGURE_DEPENDS
file(GLOB_RECURSE ZSHELL_CLI_SOURCES CONFIGURE_DEPENDS "${ZSHELL_CLI_SRC}/*.py"
"${ZSHELL_CLI_SRC}/*.py" )
) file(GLOB_RECURSE ZSHELL_CLI_ASSETS CONFIGURE_DEPENDS
file(GLOB_RECURSE ZSHELL_CLI_ASSETS CONFIGURE_DEPENDS "${ZSHELL_CLI_SRC}/assets/*"
"${ZSHELL_CLI_SRC}/assets/*" )
)
add_custom_command( add_custom_command(
OUTPUT "${ZSHELL_CLI_DIST}/zshell-cli" OUTPUT "${ZSHELL_CLI_DIST}/zshell-cli"
COMMAND ${CMAKE_COMMAND} -E make_directory "${ZSHELL_CLI_BUILD_DIR}" COMMAND ${CMAKE_COMMAND} -E make_directory "${ZSHELL_CLI_BUILD_DIR}"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${ZSHELL_CLI_DIST}" COMMAND ${CMAKE_COMMAND} -E rm -rf "${ZSHELL_CLI_DIST}"
COMMAND COMMAND
${NUITKA_EXECUTABLE} ${NUITKA_EXECUTABLE}
--standalone --standalone
--include-data-dir=${CMAKE_SOURCE_DIR}/cli/src/zshell/assets=zshell/assets --include-data-dir=${CMAKE_SOURCE_DIR}/cli/src/zshell/assets=zshell/assets
--include-package=gi.overrides --output-dir=${ZSHELL_CLI_BUILD_DIR}
--include-package-data=solaar --output-filename=zshell-cli
--output-dir=${ZSHELL_CLI_BUILD_DIR} ${CMAKE_SOURCE_DIR}/cli/src/zshell/
--output-filename=zshell-cli
${CMAKE_SOURCE_DIR}/cli/src/zshell/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/cli WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/cli
DEPENDS ${ZSHELL_CLI_SOURCES} ${ZSHELL_CLI_ASSETS} DEPENDS ${ZSHELL_CLI_SOURCES} ${ZSHELL_CLI_ASSETS}
) )
add_custom_target(zshell-cli ALL DEPENDS "${ZSHELL_CLI_DIST}/zshell-cli") add_custom_target(zshell-cli ALL DEPENDS "${ZSHELL_CLI_DIST}/zshell-cli")
install(PROGRAMS "${ZSHELL_CLI_DIST}/zshell-cli" DESTINATION "${INSTALL_LIBDIR}/zshell-cli") install(PROGRAMS "${ZSHELL_CLI_DIST}/zshell-cli" DESTINATION "${INSTALL_LIBDIR}/zshell-cli")
install(DIRECTORY "${ZSHELL_CLI_DIST}/" DESTINATION "${INSTALL_LIBDIR}/zshell-cli" PATTERN "zshell-cli" EXCLUDE) install(DIRECTORY "${ZSHELL_CLI_DIST}/" DESTINATION "${INSTALL_LIBDIR}/zshell-cli" PATTERN "zshell-cli" EXCLUDE)
configure_file( configure_file(
"${CMAKE_SOURCE_DIR}/Plugins/cmake/zshell-cli.cmake.in" "${CMAKE_SOURCE_DIR}/Plugins/cmake/zshell-cli.cmake.in"
"${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli.cmake" "${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli.cmake"
@ONLY @ONLY
) )
install(SCRIPT "${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli.cmake") install(SCRIPT "${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli.cmake")
else()
message(STATUS "Nuitka not found, building zshell-cli as a Python wheel instead")
find_package(Python3 COMPONENTS Interpreter REQUIRED)
set(ZSHELL_CLI_DIR "${CMAKE_SOURCE_DIR}")
set(ZSHELL_CLI_DIST_DIR "${ZSHELL_CLI_DIR}/dist")
set(ZSHELL_CLI_WHEEL_STAMP "${CMAKE_BINARY_DIR}/zshell-cli/wheel.stamp")
file(GLOB_RECURSE ZSHELL_CLI_SOURCES CONFIGURE_DEPENDS
"${ZSHELL_CLI_DIR}/src/zshell/*.py"
)
file(GLOB_RECURSE ZSHELL_CLI_ASSETS CONFIGURE_DEPENDS
"${ZSHELL_CLI_DIR}/src/zshell/assets/*"
)
add_custom_command(
OUTPUT "${ZSHELL_CLI_WHEEL_STAMP}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/zshell-cli"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${ZSHELL_CLI_DIST_DIR}"
COMMAND ${Python3_EXECUTABLE} -m build --wheel --no-isolation
COMMAND ${CMAKE_COMMAND} -E touch "${ZSHELL_CLI_WHEEL_STAMP}"
WORKING_DIRECTORY "${ZSHELL_CLI_DIR}"
DEPENDS ${ZSHELL_CLI_SOURCES} ${ZSHELL_CLI_ASSETS}
COMMENT "Building zshell-cli python wheel"
)
add_custom_target(zshell-cli ALL DEPENDS "${ZSHELL_CLI_WHEEL_STAMP}")
configure_file(
"${CMAKE_SOURCE_DIR}/Plugins/cmake/zshell-cli-python.cmake.in"
"${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli-python.cmake"
@ONLY
)
install(SCRIPT "${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli-python.cmake")
endif()
endif() endif()
if("plugin" IN_LIST ENABLE_MODULES) if("plugin" IN_LIST ENABLE_MODULES)
add_subdirectory(Plugins) add_subdirectory(Plugins)
endif() endif()
if("shell" IN_LIST ENABLE_MODULES) if("shell" IN_LIST ENABLE_MODULES)
foreach(dir assets scripts Components Services Modules Daemons Drawers Effects Helpers Paths) foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}") install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
endforeach() endforeach()
@@ -170,22 +130,3 @@ if("shell" IN_LIST ENABLE_MODULES)
# Greeter # Greeter
install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}") install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}")
endif() endif()
if("m3shapes" IN_LIST ENABLE_MODULES)
message(STATUS "Fetching M3Shapes module")
include(FetchContent)
set(M3SHAPES_REV bdc327b29f95394a732baf3c9b19658ba23755b6)
FetchContent_Declare(
m3shapes_external
GIT_REPOSITORY https://github.com/soramanew/m3shapes.git
GIT_TAG ${M3SHAPES_REV}
SOURCE_DIR "${CMAKE_BINARY_DIR}/_deps/m3shapes-${M3SHAPES_REV}"
)
FetchContent_MakeAvailable(m3shapes_external)
message(STATUS "Done fetching M3Shapes module")
# Fix m3shapes wrong rpath
if(TARGET m3shapesplugin)
set_target_properties(m3shapesplugin PROPERTIES INSTALL_RPATH "$ORIGIN")
endif()
endif()
+14 -14
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.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 Tokens.anim.durations.expressiveDefaultSpatial; return Appearance.anim.durations.expressiveDefaultSpatial;
if (type == AnchorAnim.FastSpatial) if (type == AnchorAnim.FastSpatial)
return Tokens.anim.durations.expressiveFastSpatial; return Appearance.anim.durations.expressiveFastSpatial;
if (type == AnchorAnim.DefaultSpatial) if (type == AnchorAnim.DefaultSpatial)
return Tokens.anim.durations.expressiveDefaultSpatial; return Appearance.anim.durations.expressiveDefaultSpatial;
if (type == AnchorAnim.SlowSpatial) if (type == AnchorAnim.SlowSpatial)
return Tokens.anim.durations.expressiveSlowSpatial; return Appearance.anim.durations.large;
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;
return Tokens.anim.durations[types[idx]]; return Appearance.anim.durations[types[idx]];
} }
easing: { easing.bezierCurve: {
if (type == AnchorAnim.FastSpatial) if (type == AnchorAnim.FastSpatial)
return Tokens.anim.expressiveFastSpatial; return Appearance.anim.curves.expressiveFastSpatial;
if (type == AnchorAnim.DefaultSpatial) if (type == AnchorAnim.DefaultSpatial)
return Tokens.anim.expressiveDefaultSpatial; return Appearance.anim.curves.expressiveDefaultSpatial;
if (type == AnchorAnim.SlowSpatial) if (type == AnchorAnim.SlowSpatial)
return Tokens.anim.expressiveSlowSpatial; return Appearance.anim.curves.expressiveSlowSpatial;
if (type >= AnchorAnim.StandardSmall && type <= AnchorAnim.StandardExtraLarge) if (type >= AnchorAnim.StandardSmall && type <= AnchorAnim.StandardExtraLarge)
return Tokens.anim.standard; return Appearance.anim.curves.standard;
if (type >= AnchorAnim.EmphasizedSmall && type <= AnchorAnim.EmphasizedExtraLarge) if (type >= AnchorAnim.EmphasizedSmall && type <= AnchorAnim.EmphasizedExtraLarge)
return Tokens.anim.emphasized; return Appearance.anim.curves.emphasized;
return Tokens.anim.expressiveDefaultSpatial; return Appearance.anim.curves.expressiveDefaultSpatial;
} }
} }
+19 -19
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.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 Tokens.anim.durations.normal; return Appearance.anim.durations.normal;
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Tokens.anim.durations.expressiveFastSpatial; return Appearance.anim.durations.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Tokens.anim.durations.expressiveDefaultSpatial; return Appearance.anim.durations.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Tokens.anim.durations.expressiveSlowSpatial; return Appearance.anim.durations.large;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Tokens.anim.durations.expressiveFastEffects; return Appearance.anim.durations.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Tokens.anim.durations.expressiveDefaultEffects; return Appearance.anim.durations.expressiveEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Tokens.anim.durations.expressiveSlowEffects; return Appearance.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;
return Tokens.anim.durations[types[idx]]; return Appearance.anim.durations[types[idx]];
} }
easing: { easing.bezierCurve: {
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Tokens.anim.expressiveFastSpatial; return Appearance.anim.curves.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Tokens.anim.expressiveDefaultSpatial; return Appearance.anim.curves.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Tokens.anim.expressiveSlowSpatial; return Appearance.anim.curves.expressiveSlowSpatial;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Tokens.anim.expressiveFastEffects; return Appearance.anim.curves.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Tokens.anim.expressiveDefaultEffects; return Appearance.anim.curves.expressiveDefaultEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Tokens.anim.expressiveSlowEffects; return Appearance.anim.curves.expressiveSlowEffects;
if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge) if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge)
return Tokens.anim.emphasized; return Appearance.anim.curves.emphasized;
return Tokens.anim.standard; return Appearance.anim.curves.standard;
} }
} }
+14 -15
View File
@@ -1,12 +1,11 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import ZShell.Config import qs.Config
import qs.Services
Slider { Slider {
id: root id: root
property color color: Colors.palette.m3secondary property color color: DynamicColors.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
@@ -20,9 +19,9 @@ Slider {
background: CustomRect { background: CustomRect {
id: groove id: groove
color: Colors.layer(Colors.palette.m3surfaceContainer, 2) color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
height: root.availableHeight height: root.availableHeight
radius: Tokens.rounding.full radius: Appearance.rounding.full
width: root.availableWidth width: root.availableWidth
x: root.leftPadding x: root.leftPadding
y: root.topPadding y: root.topPadding
@@ -63,8 +62,8 @@ Slider {
id: rect id: rect
anchors.fill: parent anchors.fill: parent
color: Colors.palette.m3inverseSurface color: DynamicColors.palette.m3inverseSurface
radius: Tokens.rounding.full radius: Appearance.rounding.full
MouseArea { MouseArea {
id: handleInteraction id: handleInteraction
@@ -83,12 +82,12 @@ Slider {
function update(): void { function update(): void {
animate = !moving; animate = !moving;
binding.when = moving; binding.when = moving;
font.pointSize = moving ? Tokens.font.size.small : Tokens.font.size.larger; font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger;
font.family = moving ? Config.appearance.font.family.sans : Config.appearance.font.family.material; font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material;
} }
anchors.centerIn: parent anchors.centerIn: parent
color: Colors.palette.m3inverseOnSurface color: DynamicColors.palette.m3inverseOnSurface
text: root.icon text: root.icon
onMovingChanged: anim.restart() onMovingChanged: anim.restart()
@@ -106,8 +105,8 @@ Slider {
id: anim id: anim
Anim { Anim {
duration: Tokens.anim.durations.normal / 2 duration: Appearance.anim.durations.normal / 2
easing: Tokens.anim.standardAccel easing.bezierCurve: Appearance.anim.curves.standardAccel
property: "scale" property: "scale"
target: icon target: icon
to: 0 to: 0
@@ -118,8 +117,8 @@ Slider {
} }
Anim { Anim {
duration: Tokens.anim.durations.normal / 2 duration: Appearance.anim.durations.normal / 2
easing: Tokens.anim.standardDecel easing.bezierCurve: Appearance.anim.curves.standardDecel
property: "scale" property: "scale"
target: icon target: icon
to: 1 to: 1
@@ -130,7 +129,7 @@ Slider {
} }
Behavior on value { Behavior on value {
Anim { Anim {
duration: Tokens.anim.durations.large duration: Appearance.anim.durations.large
} }
} }
+9 -11
View File
@@ -1,7 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
import qs.Components
import qs.Services
CustomRect { CustomRect {
id: root id: root
@@ -15,14 +13,14 @@ CustomRect {
property color activeColor property color activeColor
property color activeOnColor property color activeOnColor
property bool checked property bool checked
property real checkedRadius: Tokens.rounding.medium property real checkedRadius: Appearance.rounding.medium
property real defaultRadius: Tokens.rounding.large property real defaultRadius: Appearance.rounding.large
property color disabledColor: Qt.alpha(Colors.palette.m3onSurface, 0.1) property color disabledColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1)
property color disabledOnColor: Qt.alpha(Colors.palette.m3onSurface, 0.38) property color disabledOnColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38)
property bool fillWidth property bool fillWidth
property font font: ({ property font font: ({
family: Config.appearance.font.family.sans, family: Appearance.font.family.sans,
pointSize: Tokens.font.size.larger, pointSize: Appearance.font.size.larger,
bold: false bold: false
}) })
property real horizontalPadding: padding property real horizontalPadding: padding
@@ -37,7 +35,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: Tokens.rounding.small property real pressedRadius: Appearance.rounding.small
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
@@ -55,7 +53,7 @@ CustomRect {
if (internalChecked) if (internalChecked)
return checkedRadius; return checkedRadius;
if (isRound) if (isRound)
return (height || implicitHeight) / 2 * Math.min(1, Tokens.rounding.scale); return (height || implicitHeight) / 2 * Math.min(1, Appearance.rounding.scale);
return defaultRadius; return defaultRadius;
} }
+4 -3
View File
@@ -1,7 +1,8 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
ColorAnimation { ColorAnimation {
duration: Tokens.anim.durations.expressiveSlowEffects duration: MaterialEasing.standardTime
easing: Tokens.anim.expressiveSlowEffects easing.bezierCurve: MaterialEasing.standard
easing.type: Easing.BezierSpline
} }
+8 -9
View File
@@ -1,8 +1,7 @@
import ZShell.Config import qs.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
@@ -18,12 +17,12 @@ BusyIndicator {
} }
property int animState property int animState
property color bgColor: Colors.palette.m3secondaryContainer property color bgColor: DynamicColors.palette.m3secondaryContainer
property color fgColor: Colors.palette.m3primary property color fgColor: DynamicColors.palette.m3primary
property real implicitSize: Tokens.font.size.normal * 3 property real implicitSize: Appearance.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: Tokens.padding.extraSmall * 0.8 property real strokeWidth: Appearance.padding.small * 0.8
property alias type: manager.indeterminateAnimationType property alias type: manager.indeterminateAnimationType
implicitHeight: implicitSize implicitHeight: implicitSize
@@ -51,7 +50,7 @@ BusyIndicator {
} }
transitions: Transition { transitions: Transition {
Anim { Anim {
duration: manager.completeEndDuration * Tokens.anim.durations.scale duration: manager.completeEndDuration * Appearance.anim.durations.scale
properties: "opacity,internalStrokeWidth" properties: "opacity,internalStrokeWidth"
} }
} }
@@ -77,7 +76,7 @@ BusyIndicator {
} }
NumberAnimation { NumberAnimation {
duration: manager.duration * Tokens.anim.durations.scale duration: manager.duration * Appearance.anim.durations.scale
from: 0 from: 0
loops: Animation.Infinite loops: Animation.Infinite
property: "progress" property: "progress"
@@ -87,7 +86,7 @@ BusyIndicator {
} }
NumberAnimation { NumberAnimation {
duration: manager.completeEndDuration * Tokens.anim.durations.scale duration: manager.completeEndDuration * Appearance.anim.durations.scale
from: 0 from: 0
property: "completeEndProgress" property: "completeEndProgress"
running: root.animState === CircularIndicator.Completing running: root.animState === CircularIndicator.Completing
+6 -7
View File
@@ -3,25 +3,24 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import ZShell.Components import ZShell.Components
import ZShell.Config import qs.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: Colors.palette.m3secondaryContainer property color bgColor: DynamicColors.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: Colors.palette.m3primary property color fgColor: DynamicColors.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: Tokens.spacing.small property int spacing: Appearance.spacing.small
property int startAngle: -90 property int startAngle: -90
property int strokeWidth: Tokens.padding.extraSmall property int strokeWidth: Appearance.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
@@ -111,7 +110,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: Tokens.rounding.full radius: Appearance.rounding.full
} }
} }
} }
+6 -7
View File
@@ -1,8 +1,7 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import ZShell.Config import qs.Config
import qs.Services
Item { Item {
id: root id: root
@@ -19,9 +18,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: Colors.palette.m3inverseSurface readonly property color thumbColor: DynamicColors.palette.m3inverseSurface
readonly property color thumbContentColor: Colors.palette.m3inverseOnSurface readonly property color thumbContentColor: DynamicColors.palette.m3inverseOnSurface
readonly property color trackColor: Colors.layer(Colors.palette.m3surfaceContainer, 2) readonly property color trackColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
function hueToAngle(hue) { function hueToAngle(hue) {
return arcStartAngle + arcSweep * hue; return arcStartAngle + arcSweep * hue;
@@ -154,8 +153,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 - Tokens.padding.extraLarge * 2 implicitWidth: canvas.height - root.handleSize - Appearance.padding.extraLarge * 2
radius: Tokens.rounding.full radius: Appearance.rounding.full
Behavior on color { Behavior on color {
enabled: false enabled: false
+5 -6
View File
@@ -1,7 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import ZShell.Config import qs.Config
import qs.Services
CheckBox { CheckBox {
id: control id: control
@@ -19,14 +18,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 ? Colors.palette.m3primary : "transparent" border.color: control.checked ? DynamicColors.palette.m3primary : "transparent"
color: Colors.palette.m3surfaceVariant color: DynamicColors.palette.m3surfaceVariant
implicitHeight: control.checkHeight implicitHeight: control.checkHeight
implicitWidth: control.checkWidth implicitWidth: control.checkWidth
radius: Tokens.rounding.small / 2 radius: Appearance.rounding.smallest / 2
CustomRect { CustomRect {
color: Colors.palette.m3primary color: DynamicColors.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
+1 -1
View File
@@ -6,7 +6,7 @@ ListView {
property bool doneFakeFlick property bool doneFakeFlick
interactive: !Visibilities.getForActive()?.isDrawing interactive: !Visibilities.getForActive().isDrawing
maximumFlickVelocity: 3000 maximumFlickVelocity: 3000
rebound: Transition { rebound: Transition {
+7 -8
View File
@@ -5,8 +5,7 @@ import QtQuick.Templates
import ZShell import ZShell
import ZShell.Components import ZShell.Components
import ZShell.Internal import ZShell.Internal
import ZShell.Config import qs.Config
import qs.Services
ProgressBar { ProgressBar {
id: root id: root
@@ -17,8 +16,8 @@ ProgressBar {
Stopped Stopped
} }
property color bgColor: Colors.palette.m3secondaryContainer property color bgColor: DynamicColors.palette.m3secondaryContainer
property color fgColor: Colors.palette.m3primary property color fgColor: DynamicColors.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
@@ -65,7 +64,7 @@ ProgressBar {
LinearIndicatorManager { LinearIndicatorManager {
id: manager id: manager
gap: Tokens.spacing.extraSmall gap: Appearance.spacing.extraSmall
Anim on completeEndProgress { Anim on completeEndProgress {
duration: manager.completeEndDuration duration: manager.completeEndDuration
@@ -95,7 +94,7 @@ ProgressBar {
id: remaining id: remaining
anchors.right: parent.right anchors.right: parent.right
implicitWidth: parent.width - wave.implicitWidth - Tokens.spacing.extraSmall implicitWidth: parent.width - wave.implicitWidth - Appearance.spacing.extraSmall
} }
Line { Line {
@@ -107,7 +106,7 @@ ProgressBar {
color: root.fgColor color: root.fgColor
implicitHeight: implicitSize implicitHeight: implicitSize
implicitWidth: implicitSize implicitWidth: implicitSize
radius: Tokens.rounding.full radius: Appearance.rounding.full
Behavior on implicitSize { Behavior on implicitSize {
Anim { Anim {
@@ -201,7 +200,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: Tokens.rounding.full radius: Appearance.rounding.full
x: bounds.x x: bounds.x
} }
component Wave: WavyLine { component Wave: WavyLine {
+7 -8
View File
@@ -1,12 +1,11 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import ZShell.Config import qs.Config
import qs.Services
RadioButton { RadioButton {
id: root id: root
font.pointSize: Tokens.font.size.normal font.pointSize: Appearance.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
@@ -21,12 +20,12 @@ RadioButton {
id: outerCircle id: outerCircle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
border.color: root.checked ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant border.color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant
border.width: 2 border.width: 2
color: "transparent" color: "transparent"
implicitHeight: 16 implicitHeight: 16
implicitWidth: 16 implicitWidth: 16
radius: Tokens.rounding.full radius: Appearance.rounding.full
Behavior on border.color { Behavior on border.color {
CAnim { CAnim {
@@ -35,7 +34,7 @@ RadioButton {
StateLayer { StateLayer {
anchors.margins: -7 anchors.margins: -7
color: root.checked ? Colors.palette.m3onSurface : Colors.palette.m3primary color: root.checked ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3primary
z: -1 z: -1
onClicked: { onClicked: {
@@ -45,10 +44,10 @@ RadioButton {
CustomRect { CustomRect {
anchors.centerIn: parent anchors.centerIn: parent
color: Qt.alpha(Colors.palette.m3primary, root.checked ? 1 : 0) color: Qt.alpha(DynamicColors.palette.m3primary, root.checked ? 1 : 0)
implicitHeight: 8 implicitHeight: 8
implicitWidth: 8 implicitWidth: 8
radius: Tokens.rounding.full radius: Appearance.rounding.full
} }
} }
} }
+6 -7
View File
@@ -1,8 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import qs.Helpers import qs.Helpers
import ZShell.Config import qs.Config
import qs.Services
ScrollBar { ScrollBar {
id: root id: root
@@ -18,7 +17,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: Tokens.padding.extraSmall * 2 implicitWidth: Appearance.padding.extraSmall * 2
contentItem: Item { contentItem: Item {
} }
@@ -52,15 +51,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: Tokens.rounding.full radius: Appearance.rounding.full
CustomRect { CustomRect {
id: handle id: handle
anchors.right: parent.right anchors.right: parent.right
color: Colors.palette.m3secondary color: DynamicColors.palette.m3secondary
implicitHeight: root.height * root.effectiveSize implicitHeight: root.height * root.effectiveSize
implicitWidth: fullMouse.pressed || fullMouse.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall implicitWidth: fullMouse.pressed || fullMouse.containsMouse ? Appearance.padding.extraSmall * 2 : Appearance.padding.extraSmall
opacity: { opacity: {
if (!root.enabled) if (!root.enabled)
return 0; return 0;
@@ -74,7 +73,7 @@ ScrollBar {
return 0.6; return 0.6;
return 0; return 0;
} }
radius: Tokens.rounding.full radius: Appearance.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 -21
View File
@@ -5,23 +5,20 @@ import QtQuick.Templates
import ZShell.Components import ZShell.Components
import ZShell import ZShell
import qs.Components import qs.Components
import ZShell.Config import qs.Config
import qs.Services
Slider { Slider {
id: root id: root
property bool animateWave property bool animateWave
property color bgColor: enabled ? Colors.palette.m3secondaryContainer : Qt.alpha(Colors.palette.m3onSurface, 0.1) property color bgColor: enabled ? DynamicColors.palette.m3secondaryContainer : Qt.alpha(DynamicColors.palette.m3onSurface, 0.1)
readonly property bool dragging: mouse.pressed 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 ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onPrimary) : Colors.palette.m3onSurface property color insetColor: enabled ? (inset.attached ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onPrimary) : DynamicColors.palette.m3onSurface
property string insetIcon: "" property string insetIcon: ""
property bool interactionOnMove: true
property real pos: visualPosition property real pos: visualPosition
property int radius: Tokens.rounding.small property int radius: Appearance.rounding.small
property int waveDuration: 1000 property int waveDuration: 1000
property real waveFrequency: 6 property real waveFrequency: 6
property bool wavy property bool wavy
@@ -38,15 +35,15 @@ Slider {
id: remaining id: remaining
anchors.left: handle.right anchors.left: handle.right
anchors.leftMargin: Tokens.spacing.extraSmall anchors.leftMargin: Appearance.spacing.extraSmall
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
bottomLeftRadius: Tokens.rounding.extraSmall / 2 bottomLeftRadius: Appearance.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: Tokens.rounding.extraSmall / 2 topLeftRadius: Appearance.rounding.extraSmall / 2
} }
CustomRect { CustomRect {
@@ -57,14 +54,14 @@ Slider {
implicitHeight: 4 * remaining.opacity implicitHeight: 4 * remaining.opacity
implicitWidth: implicitHeight implicitWidth: implicitHeight
opacity: remaining.opacity opacity: remaining.opacity
radius: Tokens.rounding.full radius: Appearance.rounding.full
} }
CustomRect { CustomRect {
id: handle id: handle
anchors.left: filled.right anchors.left: filled.right
anchors.leftMargin: Tokens.spacing.extraSmall anchors.leftMargin: Appearance.spacing.extraSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.fgColor color: root.fgColor
implicitHeight: { implicitHeight: {
@@ -73,7 +70,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: Tokens.rounding.full radius: Appearance.rounding.full
Behavior on implicitHeight { Behavior on implicitHeight {
Anim { Anim {
@@ -94,17 +91,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 + Tokens.spacing.extraSmall * 2 : false readonly property bool attached: root.width ? (root.width - handle.implicitWidth - handle.anchors.leftMargin) * root.pos < inset.paintedWidth + Appearance.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: Tokens.font.size.smaller * 2 font.pixelSize: Appearance.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: Tokens.spacing.extraSmall + dockT * (handle.x + Tokens.spacing.small) x: Appearance.spacing.extraSmall + dockT * (handle.x + Appearance.spacing.small)
Behavior on dockT { Behavior on dockT {
Anim { Anim {
@@ -116,12 +113,12 @@ Slider {
id: lineComp id: lineComp
CustomRect { CustomRect {
bottomRightRadius: Tokens.rounding.extraSmall / 2 bottomRightRadius: Appearance.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: Tokens.rounding.extraSmall / 2 topRightRadius: Appearance.rounding.extraSmall / 2
} }
} }
@@ -188,8 +185,7 @@ Slider {
onPositionChanged: e => { onPositionChanged: e => {
dragMovement = (e.x - pressStartX) / width; dragMovement = (e.x - pressStartX) / width;
if (root.interactionOnMove) root.interaction(posBinding.value);
root.interaction(posBinding.value);
} }
onPressed: e => { onPressed: e => {
widthBehavior.enabled = false; widthBehavior.enabled = false;
+18 -19
View File
@@ -1,7 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import ZShell.Config import qs.Config
import qs.Services
DoubleSpinBox { DoubleSpinBox {
id: root id: root
@@ -30,36 +29,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 + Tokens.spacing.extraSmall / 2 leftPadding: up.indicator.implicitWidth + Appearance.spacing.extraSmall / 2
rightPadding: down.indicator.implicitWidth + Tokens.spacing.extraSmall / 2 rightPadding: down.indicator.implicitWidth + Appearance.spacing.extraSmall / 2
spacing: Tokens.spacing.small spacing: Appearance.spacing.small
contentItem: TextFieldBase { contentItem: TextFieldBase {
horizontalAlignment: TextField.AlignHCenter horizontalAlignment: TextField.AlignHCenter
implicitWidth: 65 implicitWidth: 65
inputMethodHints: Qt.ImhFormattedNumbersOnly inputMethodHints: Qt.ImhFormattedNumbersOnly
leftPadding: Tokens.padding.small leftPadding: Appearance.padding.larger
readOnly: !root.editable readOnly: !root.editable
rightPadding: Tokens.padding.small rightPadding: Appearance.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: Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer)
radius: Tokens.rounding.extraSmall radius: Appearance.rounding.extraSmall
} }
} }
down.indicator: IconButton { down.indicator: IconButton {
id: downButton id: downButton
bottomRightRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall bottomRightRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
color: enabled ? Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor color: enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor
disabledColor: Qt.alpha(Colors.palette.m3surfaceContainerHighest, 0.4) disabledColor: Qt.alpha(DynamicColors.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: Tokens.padding.extraSmall padding: Appearance.padding.extraSmall
topRightRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall topRightRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
type: IconButton.Text type: IconButton.Text
Behavior on bottomRightRadius { Behavior on bottomRightRadius {
@@ -82,14 +81,14 @@ DoubleSpinBox {
id: upButton id: upButton
anchors.right: parent.right anchors.right: parent.right
bottomLeftRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall bottomLeftRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
color: enabled ? Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor color: enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor
disabledColor: Qt.alpha(Colors.palette.m3surfaceContainerHighest, 0.4) disabledColor: Qt.alpha(DynamicColors.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: Tokens.padding.extraSmall padding: Appearance.padding.extraSmall
topLeftRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall topLeftRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
type: IconButton.Text type: IconButton.Text
Behavior on bottomLeftRadius { Behavior on bottomLeftRadius {
@@ -1,7 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import ZShell.Config import qs.Config
import qs.Services
Row { Row {
id: root id: root
@@ -12,14 +11,14 @@ Row {
} }
property alias active: menu.active property alias active: menu.active
property color color: type == SplitButton.Filled ? Colors.palette.m3primary : Colors.palette.m3secondaryContainer property color color: type == CustomSplitButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondaryContainer
property color disabledColor: Qt.alpha(Colors.palette.m3onSurface, 0.1) property color disabledColor: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1)
property color disabledTextColor: Qt.alpha(Colors.palette.m3onSurface, 0.38) property color disabledTextColor: Qt.alpha(DynamicColors.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: Tokens.padding.medium property real horizontalPadding: Appearance.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
@@ -27,20 +26,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 == SplitButton.Filled ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondaryContainer property color textColor: type == CustomSplitButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondaryContainer
readonly property alias textRow: textRow readonly property alias textRow: textRow
property int type: SplitButton.Filled property int type: CustomSplitButton.Filled
property real verticalPadding: Tokens.padding.small property real verticalPadding: Appearance.padding.small
spacing: Math.floor(Tokens.spacing.extraSmall / 2) spacing: Math.floor(Appearance.spacing.extraSmall)
CustomRect { CustomRect {
bottomRightRadius: Tokens.rounding.medium / 2 bottomRightRadius: Appearance.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, Tokens.rounding.scale) radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale)
topRightRadius: Tokens.rounding.medium / 2 topRightRadius: Appearance.rounding.small / 2
StateLayer { StateLayer {
id: stateLayer id: stateLayer
@@ -58,7 +57,7 @@ Row {
anchors.centerIn: parent anchors.centerIn: parent
anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4) anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4)
spacing: Tokens.spacing.small spacing: Appearance.spacing.small
MaterialIcon { MaterialIcon {
id: iconLabel id: iconLabel
@@ -92,13 +91,13 @@ Row {
CustomRect { CustomRect {
id: expandBtn id: expandBtn
property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Tokens.rounding.scale) : Tokens.rounding.medium / 2 property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) : Appearance.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, Tokens.rounding.scale) radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale)
topLeftRadius: rad topLeftRadius: rad
Behavior on rad { Behavior on rad {
@@ -142,7 +141,7 @@ Row {
attachSideY: root.menuOnTop ? Menu.Top : Menu.Bottom attachSideY: root.menuOnTop ? Menu.Top : Menu.Bottom
attachTo: expandBtn attachTo: expandBtn
marginY: Tokens.spacing.small * (root.menuOnTop ? -1 : 1) marginY: Appearance.spacing.small * (root.menuOnTop ? -1 : 1)
thisSideY: root.menuOnTop ? Menu.Bottom : Menu.Top thisSideY: root.menuOnTop ? Menu.Bottom : Menu.Top
} }
} }
+69
View File
@@ -0,0 +1,69 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
Item {
id: root
property alias active: splitButton.active
property alias buttonAlias: splitButton
property alias expanded: splitButton.expanded
property int expandedZ: 100
required property string label
property alias menuItems: splitButton.menuItems
property bool shouldBeActive: true
property alias type: splitButton.type
signal selected(item: MenuItem)
anchors.left: parent.left
anchors.right: parent.right
clip: false
implicitHeight: row.implicitHeight + Appearance.padding.smaller * 2
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
z: splitButton.menu.implicitHeight > 0 ? expandedZ : 1
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal
CustomText {
Layout.fillWidth: true
color: root.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.larger
text: root.label
}
CustomSplitButton {
id: splitButton
enabled: root.enabled
type: CustomSplitButton.Filled
z: 2
menu.onItemSelected: item => {
root.selected(item);
}
stateLayer.onClicked: {
splitButton.expanded = !splitButton.expanded;
}
}
}
}
+15 -28
View File
@@ -1,8 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import QtQuick.Templates import QtQuick.Templates
import ZShell.Config import qs.Config
import qs.Services
Switch { Switch {
id: root id: root
@@ -13,28 +12,20 @@ Switch {
implicitWidth: implicitIndicatorWidth implicitWidth: implicitIndicatorWidth
indicator: CustomRect { indicator: CustomRect {
color: { color: root.checked && root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer)
if (!root.enabled) implicitHeight: Appearance.font.size.medium + Appearance.padding.normal * 2
return root.checked ? Qt.alpha(Colors.palette.m3onSurface, 0.12) : Qt.alpha(Colors.palette.m3surfaceContainerHighest, 0.38);
return root.checked ? Colors.palette.m3primary : Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer);
}
implicitHeight: 14 + Tokens.padding.small * 2
implicitWidth: implicitHeight * 1.7 implicitWidth: implicitHeight * 1.7
radius: Tokens.rounding.full radius: Appearance.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: { color: root.checked && root.enabled ? DynamicColors.palette.m3onPrimary : DynamicColors.layer(DynamicColors.palette.m3outline, root.cLayer + 1)
if (!root.enabled) implicitHeight: parent.implicitHeight - Appearance.padding.extraSmall
return root.checked ? Qt.alpha(Colors.palette.m3surface, 0.7) : Qt.alpha(Colors.palette.m3onSurface, 0.12);
return root.checked ? Colors.palette.m3onPrimary : Colors.layer(Colors.palette.m3outline, root.cLayer + 1);
}
implicitHeight: parent.implicitHeight - Tokens.padding.extraSmall
implicitWidth: nonAnimWidth implicitWidth: nonAnimWidth
radius: Tokens.rounding.full radius: Appearance.rounding.full
x: root.checked ? parent.implicitWidth - nonAnimWidth - Tokens.padding.extraSmall / 2 : Tokens.padding.extraSmall / 2 x: root.checked ? parent.implicitWidth - nonAnimWidth - Appearance.padding.extraSmall / 2 : Appearance.padding.extraSmall / 2
Behavior on implicitWidth { Behavior on implicitWidth {
Anim { Anim {
@@ -49,7 +40,7 @@ Switch {
CustomRect { CustomRect {
anchors.fill: parent anchors.fill: parent
color: root.checked && root.enabled ? Colors.palette.m3primary : Colors.palette.m3onSurface color: root.checked && root.enabled ? DynamicColors.palette.m3primary : DynamicColors.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
@@ -100,7 +91,7 @@ Switch {
anchors.centerIn: parent anchors.centerIn: parent
asynchronous: true asynchronous: true
height: parent.implicitHeight - Tokens.padding.medium height: parent.implicitHeight - Appearance.padding.larger
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
width: height width: height
@@ -122,16 +113,12 @@ Switch {
} }
ShapePath { ShapePath {
capStyle: Tokens.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap capStyle: ShapePath.RoundCap
fillColor: "transparent" fillColor: "transparent"
startX: icon.start1.x startX: icon.start1.x
startY: icon.start1.y startY: icon.start1.y
strokeColor: { strokeColor: root.checked && root.enabled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3surfaceContainerHighest
if (!root.enabled) strokeWidth: Appearance.font.size.larger * 0.15
return root.checked ? Colors.palette.m3outline : Colors.palette.m3surfaceContainer;
return root.checked ? Colors.palette.m3primary : Colors.palette.m3surfaceContainerHighest;
}
strokeWidth: 16 * 0.15
Behavior on strokeColor { Behavior on strokeColor {
CAnim { CAnim {
@@ -164,7 +151,7 @@ Switch {
} }
component PropAnim: PropertyAnimation { component PropAnim: PropertyAnimation {
duration: Tokens.anim.durations.expressiveFastSpatial duration: Appearance.anim.durations.expressiveFastSpatial
easing: Tokens.anim.expressiveFastSpatial easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
} }
} }
+5 -6
View File
@@ -1,8 +1,7 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import ZShell.Config import qs.Config
import qs.Services
Text { Text {
id: root id: root
@@ -13,10 +12,10 @@ Text {
property string animateProp: "scale" property string animateProp: "scale"
property real animateTo: 1 property real animateTo: 1
color: Colors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
font.family: Config.appearance.font.family.sans font.family: Appearance.font.family.sans
font.pointSize: Tokens.font.size.normal font.pointSize: Appearance.font.size.normal
linkColor: Colors.palette.m3onPrimaryFixedVariant linkColor: DynamicColors.palette.m3onPrimaryFixedVariant
renderType: Text.NativeRendering renderType: Text.NativeRendering
textFormat: Text.PlainText textFormat: Text.PlainText
+48 -54
View File
@@ -2,8 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import ZShell.Config import qs.Config
import qs.Services
TextFieldBase { TextFieldBase {
id: root id: root
@@ -17,26 +16,28 @@ 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 ? Tokens.spacing.small : 0 readonly property int filledOffset: type === CustomTextField.Filled ? Appearance.spacing.small : 0
readonly property int horizontalPadding: Tokens.padding.large readonly property int horizontalPadding: Appearance.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
property int radius: Tokens.rounding.small readonly property real outlineGap: placeholder.width * root.smallFontScale + Appearance.spacing.extraSmall * 2
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: Tokens.font.size.small property int smallFontSize: Appearance.font.size.small
property string supportingText property string supportingText
readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Tokens.spacing.extraSmall : 0 readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Appearance.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: Tokens.padding.large + supportingTextOffset - filledOffset bottomPadding: Appearance.padding.large + supportingTextOffset - filledOffset
leftPadding: horizontalPadding + leadingOffset leftPadding: horizontalPadding + leadingOffset
rightPadding: horizontalPadding + trailingOffset rightPadding: horizontalPadding + trailingOffset
topPadding: Tokens.padding.large + filledOffset topPadding: Appearance.padding.large + filledOffset
background: Loader { background: Loader {
anchors.bottomMargin: root.supportingTextOffset anchors.bottomMargin: root.supportingTextOffset
@@ -56,6 +57,11 @@ TextFieldBase {
onClicked: root.focus = true onClicked: root.focus = true
} }
} }
Behavior on outlineGapScale {
Anim {
type: Anim.DefaultEffects
}
}
onEditingFinished: { onEditingFinished: {
if (!valid) if (!valid)
@@ -81,9 +87,9 @@ TextFieldBase {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: root.leftPadding anchors.leftMargin: root.leftPadding
anchors.topMargin: Tokens.padding.extraSmall anchors.topMargin: Appearance.padding.extraSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : root.text ? Colors.palette.m3outline : root.placeholderTextColor) color: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : root.text ? DynamicColors.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
@@ -97,7 +103,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 placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + -Appearance.spacing.extraSmall
placeholder.scale: root.smallFontScale placeholder.scale: root.smallFontScale
} }
@@ -129,8 +135,8 @@ TextFieldBase {
} }
AnchorAnim { AnchorAnim {
duration: Tokens.anim.durations.expressiveDefaultEffects duration: Appearance.anim.durations.expressiveEffects
easing: Tokens.anim.expressiveDefaultEffects easing: Appearance.anim.curves.expressiveDefaultEffects
} }
} }
} }
@@ -140,11 +146,12 @@ TextFieldBase {
active: root.leadingIcon active: root.leadingIcon
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Tokens.padding.small anchors.leftMargin: Appearance.padding.larger
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
sourceComponent: MaterialIcon { sourceComponent: MaterialIcon {
color: Colors.palette.m3onSurfaceVariant color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
text: root.leadingIcon text: root.leadingIcon
} }
} }
@@ -154,11 +161,12 @@ TextFieldBase {
active: root.trailingIcon active: root.trailingIcon
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Tokens.padding.small anchors.rightMargin: Appearance.padding.larger
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
sourceComponent: MaterialIcon { sourceComponent: MaterialIcon {
color: Colors.palette.m3onSurfaceVariant color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
text: root.trailingIcon text: root.trailingIcon
} }
} }
@@ -173,8 +181,8 @@ TextFieldBase {
anchors.leftMargin: root.horizontalPadding anchors.leftMargin: root.horizontalPadding
sourceComponent: CustomText { sourceComponent: CustomText {
color: root.isError ? Colors.palette.m3error : Colors.palette.m3onSurfaceVariant color: root.isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.small font.pointSize: Appearance.font.size.small
text: root.effectiveSupportingText text: root.effectiveSupportingText
} }
} }
@@ -193,24 +201,12 @@ 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: path.inset + root.horizontalPadding - root.clampedRadius + path.outlineGap * (1 - path.outlineGapScale) / 2 + path.outlineGap * path.outlineGapScale startX: root.horizontalPadding - root.clampedRadius + root.outlineGap * (1 - root.outlineGapScale) / 2 + root.outlineGap * root.outlineGapScale
startY: path.inset strokeColor: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : DynamicColors.palette.m3outline)
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 {
} }
@@ -221,56 +217,54 @@ TextFieldBase {
} }
PathLine { PathLine {
x: bg.width - path.inset - root.clampedRadius x: bg.width - root.clampedRadius
y: path.inset
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: bg.width - path.inset x: bg.width
y: path.inset + root.clampedRadius y: root.clampedRadius
} }
PathLine { PathLine {
x: bg.width - path.inset x: bg.width
y: bg.height - path.inset - root.clampedRadius y: bg.height - root.clampedRadius
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: bg.width - path.inset - root.clampedRadius x: bg.width - root.clampedRadius
y: bg.height - path.inset y: bg.height
} }
PathLine { PathLine {
x: path.inset + root.clampedRadius x: root.clampedRadius
y: bg.height - path.inset y: bg.height
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: path.inset x: 0
y: bg.height - path.inset - root.clampedRadius y: bg.height - root.clampedRadius
} }
PathLine { PathLine {
x: path.inset x: 0
y: path.inset + root.clampedRadius y: root.clampedRadius
} }
PathArc { PathArc {
radiusX: root.clampedRadius radiusX: root.clampedRadius
radiusY: root.clampedRadius radiusY: root.clampedRadius
x: path.inset + root.clampedRadius x: root.clampedRadius
y: path.inset y: 0
} }
PathLine { PathLine {
x: path.inset + root.horizontalPadding - root.clampedRadius / 2 + path.outlineGap * (1 - path.outlineGapScale) / 2 x: root.horizontalPadding - root.clampedRadius + root.outlineGap * (1 - root.outlineGapScale) / 2
y: path.inset
} }
} }
} }
@@ -280,7 +274,7 @@ TextFieldBase {
id: filledComp id: filledComp
CustomRect { CustomRect {
color: root.activeFocus ? Colors.tPalette.m3surfaceContainerHighest : Colors.tPalette.m3surfaceContainerHigh color: root.activeFocus ? DynamicColors.tPalette.m3surfaceContainerHighest : DynamicColors.tPalette.m3surfaceContainerHigh
topLeftRadius: root.clampedRadius topLeftRadius: root.clampedRadius
topRightRadius: root.clampedRadius topRightRadius: root.clampedRadius
@@ -288,7 +282,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 ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline) color: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : DynamicColors.palette.m3outline)
implicitHeight: root.activeFocus ? 2 : 1 implicitHeight: root.activeFocus ? 2 : 1
Behavior on implicitHeight { Behavior on implicitHeight {
+5 -6
View File
@@ -1,16 +1,15 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import ZShell.Config import qs.Config
import qs.Services
TextInput { TextInput {
renderType: Text.NativeRendering renderType: Text.NativeRendering
selectedTextColor: Colors.palette.m3onSecondaryContainer selectedTextColor: DynamicColors.palette.m3onSecondaryContainer
selectionColor: Colors.tPalette.colSecondaryContainer selectionColor: DynamicColors.tPalette.colSecondaryContainer
font { font {
family: Config.appearance?.font.family.sans ?? "sans-serif" family: Appearance?.font.family.sans ?? "sans-serif"
hintingPreference: Font.PreferFullHinting hintingPreference: Font.PreferFullHinting
pixelSize: Config.appearance?.font.size.normal ?? 15 pixelSize: Appearance?.font.size.normal ?? 15
} }
} }
+2 -3
View File
@@ -1,14 +1,13 @@
import QtQuick import QtQuick
import QtQuick.Effects import QtQuick.Effects
import ZShell.Config import qs.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(Colors.palette.m3shadow, 0.7) color: Qt.alpha(DynamicColors.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 ZShell.Config import qs.Config
Image { Image {
id: root id: root
+1 -1
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
BaseStyledSlider { BaseStyledSlider {
id: root id: root
+1 -1
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
BaseStyledSlider { BaseStyledSlider {
id: root id: root
+8 -9
View File
@@ -1,6 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
import qs.Services
ButtonBase { ButtonBase {
id: root id: root
@@ -8,8 +7,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 ? Colors.palette.m3primary : Colors.palette.m3secondary activeColor: type === IconButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary
activeOnColor: type === IconButton.Filled ? Colors.palette.m3onPrimary : type === IconButton.Tonal ? Colors.palette.m3onSecondary : Colors.palette.m3primary activeOnColor: type === IconButton.Filled ? DynamicColors.palette.m3onPrimary : type === IconButton.Tonal ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3primary
implicitHeight: { implicitHeight: {
const h = label.implicitHeight + padding * 2; const h = label.implicitHeight + padding * 2;
if (h % 2 !== 0) if (h % 2 !== 0)
@@ -19,15 +18,15 @@ ButtonBase {
implicitWidth: implicitHeight implicitWidth: implicitHeight
inactiveColor: { inactiveColor: {
if (!isToggle && type === IconButton.Filled) if (!isToggle && type === IconButton.Filled)
return Colors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === IconButton.Filled ? Colors.tPalette.m3surfaceContainer : Colors.palette.m3secondaryContainer; return type === IconButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer;
} }
inactiveOnColor: { inactiveOnColor: {
if (!isToggle && type === IconButton.Filled) if (!isToggle && type === IconButton.Filled)
return Colors.palette.m3onPrimary; return DynamicColors.palette.m3onPrimary;
return type === IconButton.Tonal ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onSurfaceVariant; return type === IconButton.Tonal ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurfaceVariant;
} }
padding: type === IconButton.Text ? Tokens.padding.extraSmall / 2 : Tokens.padding.extraSmall padding: type === IconButton.Text ? Appearance.padding.extraSmall / 2 : Appearance.padding.small
MaterialIcon { MaterialIcon {
id: label id: label
+12 -13
View File
@@ -1,7 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import ZShell.Config import qs.Config
import qs.Services
ButtonBase { ButtonBase {
id: root id: root
@@ -11,34 +10,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 ? Colors.palette.m3primary : Colors.palette.m3secondary activeColor: type === TextButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary
activeOnColor: { activeOnColor: {
if (type === TextButton.Text) if (type === TextButton.Text)
return Colors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === TextButton.Filled ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondary; return type === TextButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondary;
} }
horizontalPadding: Tokens.padding.small horizontalPadding: Appearance.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 Colors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === TextButton.Filled ? Colors.tPalette.m3surfaceContainer : Colors.palette.m3secondaryContainer; return type === TextButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer;
} }
inactiveOnColor: { inactiveOnColor: {
if (!isToggle && type === TextButton.Filled) if (!isToggle && type === TextButton.Filled)
return Colors.palette.m3onPrimary; return DynamicColors.palette.m3onPrimary;
if (type === TextButton.Text) if (type === TextButton.Text)
return Colors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === TextButton.Filled ? Colors.palette.m3onSurface : Colors.palette.m3onSecondaryContainer; return type === TextButton.Filled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer;
} }
verticalPadding: Tokens.padding.extraSmall verticalPadding: Appearance.padding.small
RowLayout { RowLayout {
id: row id: row
anchors.centerIn: parent anchors.centerIn: parent
spacing: Tokens.spacing.small spacing: Appearance.spacing.small
MaterialIcon { MaterialIcon {
id: iconLabel id: iconLabel
-115
View File
@@ -1,115 +0,0 @@
import QtQuick
import Quickshell
import M3Shapes
import ZShell.Config
import qs.Services
MaterialShape {
id: root
property bool animated: true
property real cRotation
property bool containsIcon
property real dampingRatio: 0.6
property real lRotation
property int morphAnimRotation: 60
property real morphScale: 0.14
property alias rotateAnimDuration: rotateAnim.duration
property int shapeIndex
property list<int> shapes: {
if (containsIcon)
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pentagon, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
}
readonly property real springDuration: {
const wn = Math.sqrt(stiffness);
const r = -dampingRatio * wn;
const c = 1 / Math.sqrt(1 - dampingRatio * dampingRatio);
return Math.log(visibilityThreshold / c) / r;
}
readonly property real springMaxVelocity: {
const wn = Math.sqrt(stiffness);
const factor = Math.exp(-z * Math.acos(z) / Math.sqrt(1 - z * z));
return wn * factor;
}
property bool springSettled: true
property real stiffness: 180
property real thisLRotation
property real visibilityThreshold: 0.075
function spring(t: real): var {
const wn = Math.sqrt(stiffness);
const za = dampingRatio * wn;
const wd = wn * Math.sqrt(1 - dampingRatio * dampingRatio);
const r = za / wd;
const pos = 1 - Math.exp(-za * t) * (Math.cos(wd * t) + r * Math.sin(wd * t));
const vel = Math.exp(-za * t) * (wn * wn / wd) * Math.sin(wd * t);
return [pos, vel];
}
color: Colors.palette.m3primary
implicitSize: 38
toShape: shapes[0]
RotationAnimation on cRotation {
id: rotateAnim
duration: 4666
easing.type: Easing.Linear
from: 0
loops: Animation.Infinite
running: root.animated
to: 360
}
Behavior on color {
CAnim {
}
}
ElapsedTimer {
id: timer
}
FrameAnimation {
running: root.animated && !root.springSettled
onTriggered: {
const t = timer.elapsed();
if (t >= root.springDuration) {
root.springSettled = true;
} else {
const [pos, vel] = root.spring(t);
root.morphProgress = Math.min(1, pos); // Overshooting the morph looks weird
root.thisLRotation = pos * root.morphAnimRotation;
root.scale = 1 + vel * root.morphScale / root.springMaxVelocity;
}
}
}
Timer {
interval: 650
repeat: true
running: root.animated
triggeredOnStart: true
onTriggered: {
root.beginBatchUpdate();
root.fromShape = root.toShape;
root.shapeIndex = (root.shapeIndex + 1) % root.shapes.length;
root.toShape = root.shapes[root.shapeIndex];
root.morphProgress = 0;
root.rotation = root.rotation;
root.lRotation = (root.lRotation + root.thisLRotation) % 360;
root.thisLRotation = 0;
root.rotation = Qt.binding(() => root.cRotation + root.lRotation + root.thisLRotation);
root.springSettled = false;
timer.restart();
root.endBatchUpdate();
}
}
}
+132 -151
View File
@@ -1,13 +1,12 @@
import QtQuick import QtQuick
import ZShell.Config import qs.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: Colors.palette.m3onSurface property color color: DynamicColors.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
@@ -18,14 +17,13 @@ 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 > content.width readonly property bool overflowing: metrics.width > root.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));
@@ -42,9 +40,8 @@ Item {
} }
} }
clip: false clip: true
implicitHeight: vertical ? elideText.implicitWidth : elideText.implicitHeight implicitHeight: elideText.implicitHeight
implicitWidth: vertical ? elideText.implicitHeight : elideText.implicitWidth
Behavior on leftFadeStrength { Behavior on leftFadeStrength {
Anim { Anim {
@@ -55,187 +52,171 @@ 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: content id: marqueeViewport
anchors.centerIn: parent anchors.fill: parent
height: root.vertical ? root.width : root.height clip: true
width: root.vertical ? root.height : root.width layer.enabled: true
visible: root.overflowing
transform: Rotation { layer.effect: OpacityMask {
angle: root.vertical ? -90 : 0 maskSource: rightFadeMask
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: marqueeViewport id: strip
anchors.fill: parent anchors.verticalCenter: parent.verticalCenter
clip: false height: t1.implicitHeight
layer.enabled: true width: t1.width + root.gap + t2.width
visible: root.overflowing x: 0
layer.effect: OpacityMask { CustomText {
maskSource: rightFadeMask id: t1
animate: root.animate
animateProp: "opacity"
color: root.color
font.pointSize: elideText.font.pointSize
text: elideText.text
} }
Item { CustomText {
id: strip id: t2
anchors.verticalCenter: parent.verticalCenter animate: root.animate
height: t1.implicitHeight animateProp: "opacity"
width: t1.width + root.gap + t2.width color: root.color
x: 0 font.pointSize: elideText.font.pointSize
text: t1.text
x: t1.width + root.gap
}
}
CustomText { SequentialAnimation {
id: t1 id: marqueeAnim
animate: root.animate running: false
animateProp: "opacity"
color: root.color
font.pointSize: elideText.font.pointSize
text: elideText.text
}
CustomText { onFinished: pauseTimer.restart()
id: t2
animate: root.animate ScriptAction {
animateProp: "opacity" script: {
color: root.color root.sliding = true;
font.pointSize: elideText.font.pointSize root.leftFadeEnabled = true;
text: t1.text
x: t1.width + root.gap
} }
} }
SequentialAnimation { Anim {
id: marqueeAnim duration: root.durationForDistance(t1.width)
easing.bezierCurve: Easing.Linear
easing.type: Easing.Linear
from: 0
property: "x"
target: strip
to: -t1.width
}
running: false ScriptAction {
script: {
onFinished: pauseTimer.restart() root.leftFadeEnabled = false;
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;
}
} }
} }
Timer { Anim {
id: pauseTimer 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)
}
interval: root.pauseMs ScriptAction {
repeat: false script: {
running: true root.sliding = false;
strip.x = 0;
onTriggered: {
if (root.marqueeEnabled)
marqueeAnim.start();
} }
} }
} }
Rectangle { Timer {
id: rightFadeMask id: pauseTimer
readonly property real fadeStartPos: { interval: root.pauseMs
const w = Math.max(1, width); repeat: false
return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w)); running: true
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
} }
anchors.fill: marqueeViewport GradientStop {
layer.enabled: true color: Qt.rgba(1, 1, 1, 1.0)
visible: false position: rightFadeMask.leftFadeEndPos
}
gradient: Gradient { GradientStop {
orientation: Gradient.Horizontal color: Qt.rgba(1, 1, 1, 1.0)
position: rightFadeMask.fadeStartPos
}
GradientStop { GradientStop {
color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength) color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength)
position: 0.0 position: 1.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
}
} }
} }
} }
+3 -4
View File
@@ -1,12 +1,11 @@
import ZShell.Config import qs.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: Colors.light ? 0 : -25 property int grade: DynamicColors.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
@@ -17,7 +16,7 @@ CustomText {
} }
font.family: "Material Symbols Rounded" font.family: "Material Symbols Rounded"
font.pointSize: Tokens.font.size.larger font.pointSize: Appearance.font.size.larger
font.variableAxes: ({ font.variableAxes: ({
FILL: fill, FILL: fill,
GRAD: grade, GRAD: grade,
+19 -20
View File
@@ -3,9 +3,8 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import ZShell.Config import qs.Config
import qs.Drawers import qs.Drawers
import qs.Services
MouseArea { MouseArea {
id: root id: root
@@ -78,7 +77,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: Tokens.rounding.large radius: Appearance.rounding.medium
x: { x: {
watcher.transform; watcher.transform;
const item = root.attachTo; const item = root.attachTo;
@@ -108,15 +107,15 @@ MouseArea {
CustomRect { CustomRect {
anchors.fill: parent anchors.fill: parent
color: Colors.palette.m3surfaceContainerLow color: DynamicColors.palette.m3surfaceContainerLow
radius: parent.radius radius: parent.radius
ColumnLayout { ColumnLayout {
id: column id: column
anchors.fill: parent anchors.fill: parent
anchors.margins: Tokens.padding.extraSmall anchors.margins: Appearance.padding.extraSmall
spacing: Tokens.spacing.extraSmall spacing: Appearance.spacing.extraSmall
Repeater { Repeater {
id: repeater id: repeater
@@ -126,15 +125,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(Colors.palette.m3tertiaryContainer, active ? 1 : 0) color: Qt.alpha(DynamicColors.palette.m3tertiaryContainer, active ? 1 : 0)
implicitHeight: menuOptionRow.implicitHeight + Tokens.padding.medium * 2 implicitHeight: menuOptionRow.implicitHeight + Appearance.padding.larger * 2
implicitWidth: menuOptionRow.implicitWidth + Tokens.padding.medium * 2 implicitWidth: menuOptionRow.implicitWidth + Appearance.padding.larger * 2
radius: menu.radius - column.anchors.margins radius: Appearance.rounding.small
Behavior on radius { Behavior on radius {
Anim { Anim {
@@ -142,7 +141,7 @@ MouseArea {
} }
StateLayer { StateLayer {
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.palette.m3onSurface
enabled: root.expanded enabled: root.expanded
onClicked: { onClicked: {
@@ -157,30 +156,30 @@ MouseArea {
id: menuOptionRow id: menuOptionRow
anchors.fill: parent anchors.fill: parent
anchors.margins: Tokens.padding.medium anchors.margins: Appearance.padding.larger
spacing: Tokens.spacing.small spacing: Appearance.spacing.small
MaterialIcon { MaterialIcon {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.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 ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.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 ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant color: item.active ? DynamicColors.palette.m3onTertiaryContainer : DynamicColors.palette.m3onSurfaceVariant
text: item.modelData.trailingIcon text: item.modelData.trailingIcon
} }
} }
+12 -13
View File
@@ -1,6 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
import qs.Services
TextFieldBase { TextFieldBase {
id: root id: root
@@ -9,17 +8,17 @@ TextFieldBase {
readonly property alias clearIcon: clearIcon readonly property alias clearIcon: clearIcon
readonly property alias searchIcon: searchIcon readonly property alias searchIcon: searchIcon
bottomPadding: Tokens.padding.large bottomPadding: Appearance.padding.large
leftPadding: searchIcon.width + searchIcon.anchors.leftMargin + Tokens.spacing.small leftPadding: searchIcon.width + searchIcon.anchors.leftMargin + Appearance.spacing.small
rightPadding: clearIcon.width + clearIcon.anchors.rightMargin + Tokens.spacing.small rightPadding: clearIcon.width + clearIcon.anchors.rightMargin + Appearance.spacing.small
topPadding: Tokens.padding.large topPadding: Appearance.padding.large
background: CustomRect { background: CustomRect {
id: bg id: bg
anchors.fill: parent anchors.fill: parent
color: Colors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: Tokens.rounding.full radius: Appearance.rounding.full
StateLayer { StateLayer {
id: stateLayer id: stateLayer
@@ -59,10 +58,10 @@ TextFieldBase {
id: searchIcon id: searchIcon
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Tokens.padding.large anchors.leftMargin: Appearance.padding.large
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: Colors.palette.m3onSurfaceVariant color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.large font.pointSize: Appearance.font.size.large
text: "search" text: "search"
} }
@@ -70,12 +69,12 @@ TextFieldBase {
id: clearIcon id: clearIcon
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Tokens.padding.small anchors.rightMargin: Appearance.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: Tokens.rounding.full radius: Appearance.rounding.full
radiusMorph: false radiusMorph: false
stateLayer.hoverEnabled: enabled stateLayer.hoverEnabled: enabled
type: IconButton.Text type: IconButton.Text
+6 -6
View File
@@ -1,9 +1,9 @@
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import ZShell import ZShell
import ZShell.Config import ZShell.Components
import qs.Helpers import qs.Helpers
import qs.Services import qs.Config
MouseArea { MouseArea {
id: root id: root
@@ -52,7 +52,7 @@ MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: !enabled ? undefined : Qt.PointingHandCursor cursorShape: !enabled ? undefined : Qt.PointingHandCursor
enabled: parent.enabled && !Visibilities.getForActive()?.isDrawing enabled: parent.enabled && !Visibilities.getForActive().isDrawing
hoverEnabled: true hoverEnabled: true
Behavior on stateOpacity { Behavior on stateOpacity {
@@ -79,8 +79,8 @@ MouseArea {
id: rippleAnim id: rippleAnim
alwaysRunToEnd: true alwaysRunToEnd: true
duration: Tokens.anim.durations.expressiveSlowEffects * 2 duration: Appearance.anim.durations.expressiveSlowEffects * 2
easing: Tokens.anim.standard easing.bezierCurve: Appearance.anim.curves.standard
property: "circleRadius" property: "circleRadius"
target: root target: root
to: root.endRadius to: root.endRadius
@@ -101,7 +101,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: Colors.palette.m3onSurface color: DynamicColors.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
+11 -12
View File
@@ -1,6 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
import qs.Services
ButtonBase { ButtonBase {
id: root id: root
@@ -8,28 +7,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 ? Colors.palette.m3primary : Colors.palette.m3secondary activeColor: type === TextButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary
activeOnColor: { activeOnColor: {
if (type === TextButton.Text) if (type === TextButton.Text)
return Colors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === TextButton.Filled ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondary; return type === TextButton.Filled ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondary;
} }
horizontalPadding: Tokens.padding.small horizontalPadding: Appearance.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 Colors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === TextButton.Filled ? Colors.tPalette.m3surfaceContainer : Colors.palette.m3secondaryContainer; return type === TextButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer;
} }
inactiveOnColor: { inactiveOnColor: {
if (!isToggle && type === TextButton.Filled) if (!isToggle && type === TextButton.Filled)
return Colors.palette.m3onPrimary; return DynamicColors.palette.m3onPrimary;
if (type === TextButton.Text) if (type === TextButton.Text)
return Colors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === TextButton.Filled ? Colors.palette.m3onSurface : Colors.palette.m3onSecondaryContainer; return type === TextButton.Filled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer;
} }
verticalPadding: Tokens.padding.extraSmall verticalPadding: Appearance.padding.small
CustomText { CustomText {
id: label id: label
+8 -9
View File
@@ -1,20 +1,19 @@
import QtQuick import QtQuick
import QtQuick.Templates import QtQuick.Templates
import ZShell.Config import qs.Config
import qs.Services
TextField { TextField {
id: root id: root
color: Colors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
cursorVisible: !readOnly cursorVisible: !readOnly
font.pointSize: Tokens.font.size.small font.pointSize: Appearance.font.size.small
implicitHeight: contentHeight + topPadding + bottomPadding implicitHeight: contentHeight + topPadding + bottomPadding
implicitWidth: contentWidth + leftPadding + rightPadding implicitWidth: contentWidth + leftPadding + rightPadding
placeholderTextColor: Colors.palette.m3onSurfaceVariant // No anim cause placeholder is custom placeholderTextColor: DynamicColors.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(Colors.palette.m3primary, 0.4) selectionColor: Qt.alpha(DynamicColors.palette.m3primary, 0.4)
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
Behavior on color { Behavior on color {
@@ -33,10 +32,10 @@ TextField {
property bool disableBlink property bool disableBlink
color: Colors.palette.m3primary color: DynamicColors.palette.m3primary
implicitHeight: root.cursorRectangle.height implicitHeight: root.cursorRectangle.height
implicitWidth: 1.5 implicitWidth: 1.5
radius: Tokens.rounding.largeIncreased radius: Appearance.rounding.large
x: root.cursorRectangle.x x: root.cursorRectangle.x
y: root.cursorRectangle.y y: root.cursorRectangle.y
@@ -47,7 +46,7 @@ TextField {
} }
Behavior on x { Behavior on x {
Anim { Anim {
duration: Tokens.anim.durations.expressiveFastEffects duration: Appearance.anim.durations.expressiveFastEffects
easing.bezierCurve: [0.2, 1, 0.21, 1, 1, 1] easing.bezierCurve: [0.2, 1, 0.21, 1, 1, 1]
} }
} }
+35 -36
View File
@@ -2,8 +2,7 @@ import ZShell
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Components import qs.Components
import ZShell.Config import qs.Config
import qs.Services
CustomRect { CustomRect {
id: root id: root
@@ -13,27 +12,27 @@ CustomRect {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
border.color: { border.color: {
let colour = Colors.palette.m3outlineVariant; let colour = DynamicColors.palette.m3outlineVariant;
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
colour = Colors.palette.m3success; colour = DynamicColors.palette.m3success;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
colour = Colors.palette.m3secondaryContainer; colour = DynamicColors.palette.m3secondaryContainer;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
colour = Colors.palette.m3error; colour = DynamicColors.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 Colors.palette.m3successContainer; return DynamicColors.palette.m3successContainer;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return Colors.palette.m3secondary; return DynamicColors.palette.m3secondary;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return Colors.palette.m3errorContainer; return DynamicColors.palette.m3errorContainer;
return Colors.palette.m3surface; return DynamicColors.palette.m3surface;
} }
implicitHeight: layout.implicitHeight + Tokens.padding.small * 2 implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2
radius: Tokens.rounding.medium radius: Appearance.rounding.normal
Behavior on border.color { Behavior on border.color {
CAnim { CAnim {
@@ -52,24 +51,24 @@ CustomRect {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: Tokens.padding.small anchors.leftMargin: Appearance.padding.normal
anchors.margins: Tokens.padding.small anchors.margins: Appearance.padding.smaller
anchors.rightMargin: Tokens.padding.small anchors.rightMargin: Appearance.padding.normal
spacing: Tokens.spacing.medium spacing: Appearance.spacing.normal
CustomRect { CustomRect {
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return Colors.palette.m3success; return DynamicColors.palette.m3success;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return Colors.palette.m3secondaryContainer; return DynamicColors.palette.m3secondaryContainer;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return Colors.palette.m3error; return DynamicColors.palette.m3error;
return Colors.palette.m3surfaceContainerHigh; return DynamicColors.palette.m3surfaceContainerHigh;
} }
implicitHeight: icon.implicitHeight + Tokens.padding.small * 2 implicitHeight: icon.implicitHeight + Appearance.padding.smaller * 2
implicitWidth: implicitHeight implicitWidth: implicitHeight
radius: Tokens.rounding.medium radius: Appearance.rounding.normal
MaterialIcon { MaterialIcon {
id: icon id: icon
@@ -77,14 +76,14 @@ CustomRect {
anchors.centerIn: parent anchors.centerIn: parent
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return Colors.palette.m3onSuccess; return DynamicColors.palette.m3onSuccess;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return Colors.palette.m3onSecondaryContainer; return DynamicColors.palette.m3onSecondaryContainer;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return Colors.palette.m3onError; return DynamicColors.palette.m3onError;
return Colors.palette.m3onSurfaceVariant; return DynamicColors.palette.m3onSurfaceVariant;
} }
font.pointSize: Math.round(Tokens.font.size.large * 1.2) font.pointSize: Math.round(Appearance.font.size.large * 1.2)
text: root.modelData.icon text: root.modelData.icon
} }
} }
@@ -99,15 +98,15 @@ CustomRect {
Layout.fillWidth: true Layout.fillWidth: true
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return Colors.palette.m3onSuccessContainer; return DynamicColors.palette.m3onSuccessContainer;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return Colors.palette.m3onSecondary; return DynamicColors.palette.m3onSecondary;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return Colors.palette.m3onErrorContainer; return DynamicColors.palette.m3onErrorContainer;
return Colors.palette.m3onSurface; return DynamicColors.palette.m3onSurface;
} }
elide: Text.ElideRight elide: Text.ElideRight
font.pointSize: Tokens.font.size.normal font.pointSize: Appearance.font.size.normal
text: root.modelData.title text: root.modelData.title
} }
@@ -115,12 +114,12 @@ CustomRect {
Layout.fillWidth: true Layout.fillWidth: true
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return Colors.palette.m3onSuccessContainer; return DynamicColors.palette.m3onSuccessContainer;
if (root.modelData.type === Toast.Warning) if (root.modelData.type === Toast.Warning)
return Colors.palette.m3onSecondary; return DynamicColors.palette.m3onSecondary;
if (root.modelData.type === Toast.Error) if (root.modelData.type === Toast.Error)
return Colors.palette.m3onErrorContainer; return DynamicColors.palette.m3onErrorContainer;
return Colors.palette.m3onSurface; return DynamicColors.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 ZShell.Config import qs.Config
Item { Item {
id: root id: root
property bool flag property bool flag
readonly property int spacing: Tokens.spacing.small readonly property int spacing: Appearance.spacing.small
implicitHeight: { implicitHeight: {
let h = -spacing; let h = -spacing;
@@ -21,7 +21,7 @@ Item {
} }
return h; return h;
} }
implicitWidth: Config.utilities.sizes.toastWidth - Tokens.padding.small * 2 implicitWidth: Config.utilities.sizes.toastWidth - Appearance.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: Tokens.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
} }
Behavior on opacity { Behavior on opacity {
@@ -104,8 +104,8 @@ Item {
Anim { Anim {
id: initAnim id: initAnim
duration: Tokens.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
from: 0 from: 0
properties: "opacity,scale" properties: "opacity,scale"
target: toast target: toast
+13 -43
View File
@@ -6,55 +6,25 @@ import qs.Effects
CustomListView { CustomListView {
id: root id: root
property real endFadeOpacity: fadeShouldBeActive(false) ? 0 : 1 property real bottomFadeOpacity: fadeShouldBeActive(false) ? 0 : 1
property real fadeAmount: 0.1 property real fadeAmount: 0.1
readonly property bool horizontal: orientation === ListView.Horizontal property real topFadeOpacity: fadeShouldBeActive(true) ? 0 : 1
property real startFadeOpacity: fadeShouldBeActive(true) ? 0 : 1
function contentSize(): real {
return horizontal ? contentWidth : contentHeight;
}
function fadeShouldBeActive(isStart: bool): bool { function fadeShouldBeActive(isStart: bool): bool {
// When content is smaller than flickable size, hide fade when rebound starts. // When content is smaller than flickable size, hide fade when rebound starts
if (contentSize() + marginStart() + marginEnd() < viewportSize() && rebound.running && ((isStart ? overshootStart() > 0 : overshootStart() < 0))) { if (contentHeight + topMargin + bottomMargin < height && rebound.running && ((isStart ? verticalOvershoot > 0 : verticalOvershoot < 0)))
return false; return false;
}
if (isStart) if (isStart)
return visibleStart() > 0; return visibleArea.yPosition > 0;
return visibleArea.yPosition + visibleArea.heightRatio < 1;
return visibleStart() + visibleRatio() < 1;
} }
function marginEnd(): real { flickableDirection: Flickable.VerticalFlick
return horizontal ? rightMargin : bottomMargin;
}
function marginStart(): real {
return horizontal ? leftMargin : topMargin;
}
function overshootStart(): real {
return horizontal ? horizontalOvershoot : verticalOvershoot;
}
function viewportSize(): real {
return horizontal ? width : height;
}
function visibleRatio(): real {
return horizontal ? visibleArea.widthRatio : visibleArea.heightRatio;
}
function visibleStart(): real {
return horizontal ? visibleArea.xPosition : visibleArea.yPosition;
}
flickableDirection: horizontal ? Flickable.HorizontalFlick : Flickable.VerticalFlick
layer.enabled: true layer.enabled: true
orientation: ListView.Vertical
Behavior on endFadeOpacity { Behavior on bottomFadeOpacity {
Anim { Anim {
type: Anim.SlowEffects type: Anim.SlowEffects
} }
@@ -70,10 +40,10 @@ CustomListView {
visible: false visible: false
gradient: Gradient { gradient: Gradient {
orientation: root.horizontal ? Gradient.Horizontal : Gradient.Vertical orientation: Gradient.Vertical
GradientStop { GradientStop {
color: Qt.rgba(0, 0, 0, root.startFadeOpacity) color: Qt.rgba(0, 0, 0, root.topFadeOpacity)
position: 0 position: 0
} }
@@ -88,13 +58,13 @@ CustomListView {
} }
GradientStop { GradientStop {
color: Qt.rgba(0, 0, 0, root.endFadeOpacity) color: Qt.rgba(0, 0, 0, root.bottomFadeOpacity)
position: 1 position: 1
} }
} }
} }
} }
Behavior on startFadeOpacity { Behavior on topFadeOpacity {
Anim { Anim {
type: Anim.SlowEffects type: Anim.SlowEffects
} }
-47
View File
@@ -1,47 +0,0 @@
import QtQuick
import QtQuick.Shapes
import ZShell.Config
import qs.Services
Shape {
id: root
property real amplitude: 3
property color color: Colors.palette.m3surfaceContainer
readonly property real waveHeight: amplitude * 2
property int waves: 4
asynchronous: true
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: root.color
strokeColor: "transparent"
strokeWidth: 0
Behavior on fillColor {
CAnim {
}
}
PathSvg {
path: {
const w = root.width;
const h = root.height;
const a = root.amplitude;
const n = Math.max(1, root.waves);
const wl = w / n;
const half = wl / 2;
let d = `M 0,${a} `;
for (let i = 0; i < n; ++i) {
const x = i * wl;
d += `Q ${x + half / 2},${-a} ${x + half},${a} `;
d += `Q ${x + half + half / 2},${3 * a} ${x + wl},${a} `;
}
d += `L ${w},${h} L 0,${h} Z`;
return d;
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
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
@@ -0,0 +1,13 @@
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
@@ -0,0 +1,116 @@
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
@@ -0,0 +1,14 @@
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
}
+81
View File
@@ -0,0 +1,81 @@
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: "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
@@ -0,0 +1,15 @@
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
@@ -0,0 +1,13 @@
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
@@ -0,0 +1,186 @@
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
@@ -0,0 +1,37 @@
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
@@ -0,0 +1,10 @@
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
}
@@ -6,7 +6,6 @@ import Quickshell.Io
import Quickshell.Hyprland import Quickshell.Hyprland
import QtQuick import QtQuick
import ZShell import ZShell
import ZShell.Config
import qs.Helpers import qs.Helpers
import qs.Paths import qs.Paths
@@ -69,7 +68,7 @@ Singleton {
} }
for (const [name, color] of Object.entries(scheme.colors)) { for (const [name, color] of Object.entries(scheme.colors)) {
const propName = `m3${name}`; const propName = name.startsWith("term") ? name : `m3${name}`;
if (colors.hasOwnProperty(propName)) if (colors.hasOwnProperty(propName))
colors[propName] = `${color}`; colors[propName] = `${color}`;
} }
@@ -113,6 +112,7 @@ Singleton {
function setMode(mode: string): void { function setMode(mode: string): void {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]); Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
Config.general.color.mode = mode; Config.general.color.mode = mode;
Config.save();
} }
function swapRG(c: color): color { function swapRG(c: color): color {
@@ -280,9 +280,9 @@ Singleton {
readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor) readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor)
} }
component Transparency: QtObject { component Transparency: QtObject {
readonly property real base: Math.max(0, Math.min(1, Config.appearance.transparency.base - (root.light ? 0.1 : 0))) readonly property real base: Math.max(0, Math.min(1, Appearance.transparency.base - (root.light ? 0.1 : 0)))
readonly property bool enabled: Config.appearance.transparency.enabled readonly property bool enabled: Appearance.transparency.enabled
readonly property real layers: Config.appearance.transparency.layers readonly property real layers: Appearance.transparency.layers
onBaseChanged: debounceTimer.restart() onBaseChanged: debounceTimer.restart()
onEnabledChanged: debounceTimer.restart() onEnabledChanged: debounceTimer.restart()
+68
View File
@@ -0,0 +1,68 @@
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
@@ -0,0 +1,15 @@
import Quickshell.Io
JsonObject {
property list<var> timeouts: [
{
timeout: 180,
idleAction: "lock"
},
{
timeout: 300,
idleAction: "dpms off",
activeAction: "dpms on"
}
]
}
+114
View File
@@ -0,0 +1,114 @@
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
@@ -0,0 +1,18 @@
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
@@ -0,0 +1,26 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,8 @@
import Quickshell.Io
JsonObject {
property int columns: 5
property bool enable: false
property int rows: 2
property real scale: 0.16
}
+13
View File
@@ -0,0 +1,13 @@
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
@@ -0,0 +1,23 @@
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
@@ -0,0 +1,12 @@
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
@@ -0,0 +1,7 @@
import Quickshell.Io
JsonObject {
property real base: 0.85
property bool enabled: false
property real layers: 0.4
}
+35
View File
@@ -0,0 +1,35 @@
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
@@ -0,0 +1,6 @@
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 ZShell.Config import qs.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 ZShell.Config import qs.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 ZShell.Config import qs.Config
Singleton { Singleton {
id: root id: root
+2 -33
View File
@@ -11,46 +11,15 @@ 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
geometry: content.geometry screen: scope.modelData
screen: drawer.screen
} }
Windows { Windows {
id: content id: content
screen: drawer.screen screen: scope.modelData
} }
} }
} }
-55
View File
@@ -1,55 +0,0 @@
import QtQuick
import qs.Modules.Bar as Bar
QtObject {
id: root
required property Bar.BarLoader bar
readonly property real barClamped: bar.clampedExtent
readonly property real barExtent: bar.extent
readonly property bool barOnBottom: position === "bottom"
readonly property bool barOnLeft: position === "left"
readonly property bool barOnTop: position === "top"
required property string configPosition
readonly property bool horizontal: position !== "left"
readonly property string position: configPosition === "top" || configPosition === "bottom" ? configPosition : "left"
required property var win
function axisPos(x: real, y: real): real {
return horizontal ? x : y;
}
function barContains(x: real, y: real, clamped = false): bool {
const extent = clamped ? barClamped : barExtent;
if (barOnTop)
return y < extent;
if (barOnBottom)
return y > win.height - extent;
return x < extent;
}
function insetBottom(border: real, clamped = false): real {
return barOnBottom ? (clamped ? barClamped : barExtent) : border;
}
function insetLeft(border: real, clamped = false): real {
return barOnLeft ? (clamped ? barClamped : barExtent) : border;
}
function insetTop(border: real, clamped = false): real {
return barOnTop ? (clamped ? barClamped : barExtent) : border;
}
function inwardDrag(dragX: real, dragY: real): real {
if (barOnTop)
return dragY;
if (barOnBottom)
return -dragY;
return dragX;
}
onConfigPositionChanged: {
if (!["left", "top", "bottom"].includes(configPosition))
console.warn(`Invalid bar position '${configPosition}', falling back to left`);
}
}
+3 -12
View File
@@ -1,33 +1,27 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Wayland
import QtQuick import QtQuick
import ZShell.Config import qs.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
WlrLayershell.layer: WlrLayer.Overlay
anchors.left: true
anchors.right: true
anchors.top: true anchors.top: true
hasBar: root.geometry.barOnTop exclusiveZone: root.bar.exclusiveZone
} }
ExclusionZone { ExclusionZone {
id: left id: left
anchors.left: true anchors.left: true
hasBar: root.geometry.barOnLeft
} }
ExclusionZone { ExclusionZone {
@@ -40,7 +34,6 @@ Scope {
id: bottom id: bottom
anchors.bottom: true anchors.bottom: true
hasBar: root.geometry.barOnBottom
} }
Timer { Timer {
@@ -51,9 +44,7 @@ Scope {
} }
component ExclusionZone: CustomWindow { component ExclusionZone: CustomWindow {
property bool hasBar exclusiveZone: Config.bar.border
exclusiveZone: hasBar ? root.bar.exclusiveZone : Config.bar.border
implicitHeight: 1 implicitHeight: 1
implicitWidth: 1 implicitWidth: 1
name: "Bar-Exclusion" name: "Bar-Exclusion"
+35 -42
View File
@@ -1,9 +1,9 @@
import Quickshell import Quickshell
import QtQuick import QtQuick
import qs.Components import qs.Components
import ZShell.Config import qs.Config
import qs.Helpers import qs.Helpers
import qs.Modules.Bar.Popouts import qs.Modules as BarPopouts
Item { Item {
id: root id: root
@@ -12,47 +12,43 @@ 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 Wrapper popouts required property BarPopouts.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 {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); return y > root.height - panel.height - Config.bar.border && withinPanelWidth(panel, x, y);
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 + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y); return x < panel.x + panel.width + Config.bar.border && 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 + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y); return x > panel.x - Config.bar.border && withinPanelHeight(panel, x, y);
} }
function inTopPanel(panel: Item, x: real, y: real): bool { function inTopPanel(panel: Item, x: real, y: real): bool {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y);
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 + geometry.insetTop(borderThickness); const panelY = panel.y + bar.implicitHeight;
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 + geometry.insetLeft(borderThickness); const panelX = panel.x + root.borderThickness;
return x >= panelX && x <= panelX + panel.width; return x >= panelX && x <= panelX + panel.width;
} }
@@ -85,7 +81,7 @@ Item {
if (root.singleGestureTriggered) if (root.singleGestureTriggered)
return; return;
if (root.geometry.insetTop(root.borderThickness) > centroid.pressPosition.y) { if (centroid.pressPosition.y < root.bar.implicitHeight) {
if (dragY > 20) { if (dragY > 20) {
root.visibilities.settings = true; root.visibilities.settings = true;
root.singleGestureTriggered = true; root.singleGestureTriggered = true;
@@ -95,10 +91,10 @@ Item {
} }
} }
if (centroid.pressPosition.y > root.screen.height - root.geometry.insetBottom(root.borderThickness) && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50) if (centroid.pressPosition.y > root.screen.height - Config.bar.border && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50)
root.visibilities.clipboard = true; root.visibilities.clipboard = true;
if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.geometry.insetTop(root.borderThickness) && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher) if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.bar.implicitHeight && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher)
if (dragY < -10) { if (dragY < -10) {
root.visibilities.dock = true; root.visibilities.dock = true;
root.singleGestureTriggered = true; root.singleGestureTriggered = true;
@@ -162,19 +158,6 @@ Item {
} }
} }
Timer {
id: unhideTimer
interval: Config.bar.revealDelay
repeat: false
running: false
onTriggered: {
if (hoverHandler.hovered)
root.bar.isHovered = true;
}
}
HoverHandler { HoverHandler {
id: hoverHandler id: hoverHandler
@@ -191,7 +174,7 @@ Item {
root.popouts.hasCurrent = false; root.popouts.hasCurrent = false;
} }
if (Config.bar.autoHide || root.bar.fullscreen) if (Config.bar.autoHide)
root.bar.isHovered = false; root.bar.isHovered = false;
} }
} }
@@ -210,12 +193,9 @@ Item {
return; return;
} }
if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true)) if (!root.visibilities.bar && Config.bar.autoHide && y < root.bar.implicitHeight)
root.bar.isHovered = true; root.bar.isHovered = true;
if (root.bar.fullscreen && !root.bar.isHovered)
unhideTimer.start();
if (root.panels.sidebar.offsetScale === 1) { if (root.panels.sidebar.offsetScale === 1) {
const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y); const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);
@@ -239,8 +219,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 (root.geometry.barContains(x, y)) if (y < root.bar.implicitHeight)
root.bar.checkPopout(root.geometry.axisPos(x, y)); root.bar.checkPopout(x);
} }
} }
@@ -318,6 +298,8 @@ 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();
} }
} }
@@ -329,6 +311,17 @@ Item {
} }
} }
function onUtilitiesChanged() {
if (root.visibilities.utilities) {
const inUtilitiesArea = root.inBottomPanel(root.panels.utilities, root.mouseX, root.mouseY);
if (!inUtilitiesArea) {
root.utilitiesShortcutActive = true;
}
} else {
root.utilitiesShortcutActive = false;
}
}
target: root.visibilities target: root.visibilities
} }
} }
+20 -23
View File
@@ -1,7 +1,7 @@
import Quickshell import Quickshell
import QtQuick import QtQuick
import qs.Components import qs.Components
import qs.Modules.Bar.Popouts as Popouts import qs.Modules as Modules
import qs.Modules.Notifications as Notifications import qs.Modules.Notifications 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 ZShell.Config import qs.Config
Item { Item {
id: root id: root
@@ -27,7 +27,6 @@ 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
@@ -44,26 +43,24 @@ 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: geometry.insetTop(borderThickness) anchors.topMargin: bar.implicitHeight
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: root.geometry.position !== "bottom" ? parent.top : undefined anchors.top: parent.top
clip: true clip: true
implicitHeight: root.geometry.horizontal ? resources.implicitHeight * (1 - resources.offsetScale) : resources.implicitHeight implicitHeight: resources.implicitHeight * (1 - resources.offsetScale)
implicitWidth: root.geometry.horizontal ? resources.implicitWidth : resources.implicitWidth * (1 - resources.offsetScale) implicitWidth: resources.implicitWidth
Resources.Wrapper { Resources.Wrapper {
id: resources id: resources
position: root.geometry.position anchors.left: parent.left
anchors.top: parent.top
visibilities: root.visibilities visibilities: root.visibilities
} }
} }
@@ -99,11 +96,11 @@ Item {
visibilities: root.visibilities visibilities: root.visibilities
} }
Popouts.ClipWrapper { Modules.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
} }
@@ -111,7 +108,7 @@ Item {
id: toasts id: toasts
anchors.bottom: sidebar.visible ? parent.bottom : utilities.top anchors.bottom: sidebar.visible ? parent.bottom : utilities.top
anchors.margins: Tokens.padding.small anchors.margins: Appearance.padding.normal
anchors.right: sidebar.left anchors.right: sidebar.left
} }
@@ -150,26 +147,26 @@ Item {
property real offsetScale: dashboard.shouldBeActive ? 0 : 1 property real offsetScale: dashboard.shouldBeActive ? 0 : 1
anchors.bottom: root.geometry.barOnLeft || root.geometry.barOnBottom ? parent.bottom : undefined anchors.right: parent.right
anchors.left: root.geometry.barOnLeft ? parent.left : undefined anchors.top: parent.top
anchors.right: root.geometry.barOnLeft ? undefined : parent.right
anchors.top: root.geometry.barOnBottom || root.geometry.barOnLeft ? undefined : parent.top
clip: true clip: true
implicitHeight: root.geometry.horizontal ? dashboard.implicitHeight * (1 - offsetScale) : dashboard.implicitHeight implicitHeight: dashboard.implicitHeight * (1 - offsetScale)
implicitWidth: root.geometry.horizontal ? dashboard.implicitWidth : dashboard.implicitWidth * (1 - offsetScale) implicitWidth: dashboard.implicitWidth
Behavior on offsetScale { Behavior on offsetScale {
Anim { Anim {
duration: Tokens.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing: Tokens.anim.expressiveDefaultSpatial easing.bezierCurve: Appearance.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
} }
} }
+9 -13
View File
@@ -7,18 +7,17 @@ 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 - geometry.insetTop(borderThickness, true) - geometry.insetBottom(borderThickness, true) - win.dragMaskPadding * 2 height: win.height - bar.implicitHeight - win.borderThickness - win.dragMaskPadding * 2
intersection: Intersection.Xor intersection: Intersection.Xor
width: win.width - geometry.insetLeft(borderThickness, true) * 2 - win.dragMaskPadding * 2 width: win.width - win.borderThickness * 2 - win.dragMaskPadding * 2
x: geometry.insetLeft(borderThickness, true) + win.dragMaskPadding x: win.borderThickness + win.dragMaskPadding
y: geometry.insetTop(borderThickness, true) + win.dragMaskPadding y: bar.implicitHeight + win.dragMaskPadding
R { R {
panel: root.panels.dashboardWrapper panel: root.panels.dashboardWrapper
@@ -39,24 +38,21 @@ Region {
R { R {
panel: root.panels.osdWrapper panel: root.panels.osdWrapper
width: panel.width * (1 - root.panels.osd.offsetScale) + root.borderThickness width: panel.width * (1 - root.panels.osd.offsetScale) + root.borderThickness
x: root.win.width - width
} }
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.geometry.insetBottom(root.borderThickness) height: panel.height * (1 - root.panels.utilities.offsetScale) + 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 {
@@ -87,7 +83,7 @@ Region {
height: panel.height height: panel.height
intersection: Intersection.Subtract intersection: Intersection.Subtract
width: panel.width width: panel.width
x: panel.x + root.geometry.insetLeft(root.borderThickness) x: panel.x + root.borderThickness
y: panel.y + root.geometry.insetTop(root.borderThickness) y: panel.y + root.bar.implicitHeight
} }
} }
+48 -61
View File
@@ -11,10 +11,9 @@ import ZShell.Blobs
import qs.Daemons import qs.Daemons
import qs.Components import qs.Components
import qs.Modules.Bar import qs.Modules.Bar
import ZShell.Config import qs.Config
import qs.Helpers import qs.Helpers
import qs.Drawers import qs.Drawers
import qs.Services
CustomWindow { CustomWindow {
id: root id: root
@@ -27,13 +26,12 @@ CustomWindow {
if (focusGrab.active) if (focusGrab.active)
return 0; return 0;
if (monitor?.lastIpcObject.specialWorkspace?.name || monitor?.activeWorkspace?.lastIpcObject.windows > 0) if (monitor?.lastIpcObject.specialWorkspace?.name || monitor?.activeWorkspace.lastIpcObject.windows > 0)
return 0; return 0;
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;
@@ -51,15 +49,15 @@ CustomWindow {
readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen) readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
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 - (bar.isHovered ? 0 : fsTransitionProg)) readonly property real shadowOpacity: 0.7 * (1 - fsTransitionProg)
property color surfaceColor: Colors.tPalette.m3surface property color surfaceColor: DynamicColors.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
WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
color: "transparent" color: "transparent"
contentItem.focus: true contentItem.focus: true
mask: visibilities.isDrawing ? null : (hasFullscreen && !bar.isHovered ? emptyRegion : regions) mask: visibilities.isDrawing ? null : (hasFullscreen ? emptyRegion : regions)
name: "Bar" name: "Bar"
Behavior on fsTransitionProg { Behavior on fsTransitionProg {
@@ -96,21 +94,13 @@ 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 + geometry.insetLeft(root.borderThickness) x: panels.notifications.x + root.borderThickness
y: panels.notifications.y + geometry.insetTop(root.borderThickness) y: panels.notifications.y + bar.implicitHeight
Region { Region {
height: panels.osd.height height: panels.osd.height
@@ -118,18 +108,12 @@ CustomWindow {
x: root.width - width x: root.width - width
y: panels.osdWrapper.y + bar.implicitHeight y: panels.osdWrapper.y + bar.implicitHeight
} }
Region {
height: geometry.horizontal ? 1 : root.screen.height
width: geometry.horizontal ? root.screen.width : 1
y: geometry.position === "bottom" ? root.screen.height - 1 : 0
}
} }
Regions { Regions {
id: regions id: regions
geometry: geometry bar: bar
panels: panels panels: panels
win: root win: root
} }
@@ -178,6 +162,14 @@ CustomWindow {
Component.onCompleted: Visibilities.load(root.screen, this) Component.onCompleted: Visibilities.load(root.screen, this)
} }
IpcHandler {
function toggleLauncher(fix: string): void {
visibilities.launcher = !visibilities.launcher;
}
target: "visibilities"
}
Binding { Binding {
property: "bar" property: "bar"
target: visibilities target: visibilities
@@ -194,7 +186,7 @@ CustomWindow {
layer.effect: MultiEffect { layer.effect: MultiEffect {
blurMax: 32 blurMax: 32
shadowColor: Qt.alpha(Colors.palette.m3shadow, Math.max(0, root.shadowOpacity)) shadowColor: Qt.alpha(DynamicColors.palette.m3shadow, Math.max(0, root.shadowOpacity))
shadowEnabled: true shadowEnabled: true
} }
@@ -208,10 +200,10 @@ CustomWindow {
BlobInvertedRect { BlobInvertedRect {
anchors.fill: parent anchors.fill: parent
anchors.margins: -50 anchors.margins: -50
borderBottom: geometry.insetBottom(root.borderThickness) - anchors.margins - root.sdfBorderOffset borderBottom: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderLeft: geometry.insetLeft(root.borderThickness) - anchors.margins - root.sdfBorderOffset borderLeft: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderTop: geometry.insetTop(root.borderThickness) - anchors.margins - root.sdfBorderOffset borderTop: bar.implicitHeight - anchors.margins - root.sdfBorderOffset
group: blobGroup group: blobGroup
radius: root.borderRounding radius: root.borderRounding
} }
@@ -219,15 +211,15 @@ CustomWindow {
PanelBg { PanelBg {
id: dashBg id: dashBg
property real extraExtent: 0.2 property real extraHeight: 0.2
deformAmount: 0.06 deformAmount: 0.06
implicitHeight: panels.dashboard.height * (geometry.horizontal ? 1 + extraExtent : 1) implicitHeight: panels.dashboard.height * (1 + extraHeight)
implicitWidth: panels.dashboard.width * (geometry.horizontal ? 1 : 1 + extraExtent) implicitWidth: panels.dashboard.width
panel: panels.dashboardWrapper panel: panels.dashboardWrapper
radius: Tokens.rounding.extraLarge radius: Appearance.rounding.normal
x: panels.dashboardWrapper.x + panels.dashboard.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.dashboard.width * extraExtent) x: panels.dashboardWrapper.x + panels.dashboard.x + root.borderThickness
y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - (geometry.horizontal && geometry.position !== "bottom" ? panels.dashboard.height * extraExtent : 0) y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight - panels.dashboard.height * extraHeight
} }
PanelBg { PanelBg {
@@ -238,8 +230,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: Tokens.rounding.medium + (Tokens.padding.largeIncreased / 4) radius: Appearance.rounding.smallest + 5
y: panels.launcher.y + geometry.insetTop(root.borderThickness) y: panels.launcher.y + bar.implicitHeight
} }
PanelBg { PanelBg {
@@ -260,14 +252,15 @@ 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 + geometry.insetLeft(root.borderThickness) x: panels.osdWrapper.x + panels.osd.x + root.borderThickness
y: panels.osdWrapper.y + panels.osd.y + bar.implicitHeight
} }
PanelBg { PanelBg {
id: notifsBg id: notifsBg
panel: panels.notifications panel: panels.notifications
radius: Tokens.rounding.large radius: Appearance.rounding.normal
} }
PanelBg { PanelBg {
@@ -282,17 +275,17 @@ CustomWindow {
PanelBg { PanelBg {
id: popoutBg id: popoutBg
property real extraExtent: 0.2 property real extraHeight: 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 * (geometry.horizontal ? 1 + extraExtent : 1) implicitHeight: panels.popouts.height * (1 + extraHeight)
implicitWidth: panels.popouts.width * (geometry.horizontal ? 1 : 1 + extraExtent) implicitWidth: panels.popouts.width
panel: panels.popoutsWrapper panel: panels.popoutsWrapper
radius: panels.popouts.current?.panelRadius ?? Tokens.rounding.large radius: panels.popouts.current?.panelRadius ?? Appearance.rounding.normal
x: panels.popoutsWrapper.x + panels.popouts.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.popouts.width * extraExtent) x: panels.popoutsWrapper.x + panels.popouts.x + root.borderThickness
y: panels.popoutsWrapper.y + panels.popouts.y + geometry.insetTop(root.borderThickness) - (geometry.barOnTop ? panels.popouts.height * extraExtent : 0) y: panels.popoutsWrapper.y + panels.popouts.y + bar.implicitHeight - panels.popouts.height * extraHeight
Behavior on extraExtent { Behavior on extraHeight {
Anim { Anim {
} }
} }
@@ -305,9 +298,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: Tokens.rounding.largeIncreased + Tokens.padding.small radius: Appearance.rounding.large
x: panels.resourcesWrapper.x + panels.resources.x + geometry.insetLeft(root.borderThickness) x: panels.resourcesWrapper.x + panels.resources.x + root.borderThickness
y: panels.resourcesWrapper.y + panels.resources.y + geometry.insetTop(root.borderThickness) y: panels.resourcesWrapper.y + panels.resources.y + bar.implicitHeight
} }
PanelBg { PanelBg {
@@ -315,7 +308,7 @@ CustomWindow {
deformAmount: 0.03 deformAmount: 0.03
panel: panels.settings panel: panels.settings
radius: Tokens.rounding.largeIncreased + Tokens.padding.small radius: Appearance.rounding.large + Appearance.padding.normal
} }
PanelBg { PanelBg {
@@ -323,7 +316,7 @@ CustomWindow {
deformAmount: 0.08 deformAmount: 0.08
panel: panels.dock panel: panels.dock
radius: Tokens.rounding.medium radius: Appearance.rounding.normal
} }
PanelBg { PanelBg {
@@ -331,7 +324,7 @@ CustomWindow {
deformAmount: 0.08 deformAmount: 0.08
panel: panels.drawing panel: panels.drawing
radius: Tokens.rounding.medium radius: Appearance.rounding.normal
} }
PanelBg { PanelBg {
@@ -385,7 +378,6 @@ 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
@@ -397,7 +389,6 @@ 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
@@ -439,18 +430,14 @@ CustomWindow {
BarLoader { BarLoader {
id: bar id: bar
anchors.bottom: geometry.barOnBottom ? parent.bottom : undefined
anchors.left: parent.left anchors.left: parent.left
anchors.top: geometry.barOnBottom ? undefined : parent.top anchors.right: parent.right
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
} }
} }
@@ -462,8 +449,8 @@ CustomWindow {
group: blobGroup group: blobGroup
implicitHeight: panel.height implicitHeight: panel.height
implicitWidth: panel.width implicitWidth: panel.width
radius: Tokens.rounding.small radius: Appearance.rounding.smallest
x: panel.x + geometry.insetLeft(root.borderThickness) x: panel.x + root.borderThickness
y: panel.y + geometry.insetTop(root.borderThickness) y: panel.y + bar.implicitHeight
} }
} }
+33
View File
@@ -0,0 +1,33 @@
import QtQuick
import QtQuick.Effects
Item {
id: root
property real radius
Rectangle {
id: shadowRect
anchors.fill: root
color: "black"
layer.enabled: true
radius: root.radius
visible: false
}
MultiEffect {
id: effects
anchors.fill: shadowRect
autoPaddingEnabled: true
maskEnabled: true
maskInverted: true
maskSource: shadowRect
shadowBlur: 2.0
shadowColor: "black"
shadowEnabled: true
shadowOpacity: 1
source: shadowRect
}
}
+45 -45
View File
@@ -2,10 +2,10 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import ZShell.Config import qs.Paths
import qs.Components import qs.Components
import qs.Helpers import qs.Helpers
import qs.Services import qs.Config
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: Tokens.spacing.largeIncreased * 2 spacing: Appearance.spacing.large * 2
RowLayout { RowLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
spacing: Tokens.spacing.small spacing: Appearance.spacing.small
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3secondary color: DynamicColors.palette.m3secondary
font.bold: true font.bold: true
font.family: Config.appearance.font.family.clock font.family: Appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale)
text: Time.hourStr text: Time.hourStr
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3primary color: DynamicColors.palette.m3primary
font.bold: true font.bold: true
font.family: Config.appearance.font.family.clock font.family: Appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale)
text: ":" text: ":"
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3secondary color: DynamicColors.palette.m3secondary
font.bold: true font.bold: true
font.family: Config.appearance.font.family.clock font.family: Appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale) font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale)
text: Time.minuteStr text: Time.minuteStr
} }
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.topMargin: -Tokens.padding.large * 2 Layout.topMargin: -Appearance.padding.large * 2
color: Colors.palette.m3tertiary color: DynamicColors.palette.m3tertiary
font.bold: true font.bold: true
font.family: Config.appearance.font.family.mono font.family: Appearance.font.family.mono
font.pointSize: Math.floor(Tokens.font.size.extraLarge * root.centerScale) font.pointSize: Math.floor(Appearance.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: Tokens.spacing.largeIncreased * 2 Layout.topMargin: Appearance.spacing.large * 2
color: Colors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: root.centerWidth / 2 implicitHeight: root.centerWidth / 2
implicitWidth: root.centerWidth / 2 implicitWidth: root.centerWidth / 2
radius: Tokens.rounding.full radius: Appearance.rounding.full
MaterialIcon { MaterialIcon {
anchors.centerIn: parent anchors.centerIn: parent
color: Colors.palette.m3onSurfaceVariant color: DynamicColors.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: Colors.palette.m3onSurfaceVariant color: DynamicColors.palette.m3onSurfaceVariant
font.family: Config.appearance.font.family.mono font.family: Appearance.font.family.mono
font.pointSize: Tokens.font.size.normal font.pointSize: Appearance.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: Colors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
focus: true focus: true
implicitHeight: input.implicitHeight + Tokens.padding.extraSmall * 2 implicitHeight: input.implicitHeight + Appearance.padding.small * 2
implicitWidth: root.centerWidth * 0.8 implicitWidth: root.centerWidth * 0.8
radius: Tokens.rounding.full radius: Appearance.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: Tokens.padding.extraSmall anchors.margins: Appearance.padding.small
spacing: Tokens.spacing.medium spacing: Appearance.spacing.normal
Item { Item {
implicitHeight: statusIcon.implicitHeight + Tokens.padding.extraSmall * 2 implicitHeight: statusIcon.implicitHeight + Appearance.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 ? Colors.palette.m3error : Colors.palette.m3onSurface color: root.greeter.errorMessage ? DynamicColors.palette.m3error : DynamicColors.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 ? Colors.palette.m3primary : Colors.layer(Colors.palette.m3surfaceContainerHigh, 2) color: root.greeter.buffer && !root.greeter.launching ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
implicitHeight: enterIcon.implicitHeight + Tokens.padding.extraSmall * 2 implicitHeight: enterIcon.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight implicitWidth: implicitHeight
radius: Tokens.rounding.full radius: Appearance.rounding.full
StateLayer { StateLayer {
color: root.greeter.buffer && !root.greeter.launching ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface color: root.greeter.buffer && !root.greeter.launching ? DynamicColors.palette.m3onPrimary : DynamicColors.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 ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface color: root.greeter.buffer && !root.greeter.launching ? DynamicColors.palette.m3onPrimary : DynamicColors.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: -Tokens.spacing.largeIncreased Layout.topMargin: -Appearance.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: Colors.palette.m3onSurfaceVariant color: DynamicColors.palette.m3onSurfaceVariant
font.family: Config.appearance.font.family.mono font.family: 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 ? Colors.palette.m3error : Colors.palette.m3primary color: isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
font.family: Config.appearance.font.family.mono font.family: Appearance.font.family.mono
font.pointSize: Tokens.font.size.small font.pointSize: Appearance.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: Tokens.anim.durations.large duration: Appearance.anim.durations.large
property: "scale" property: "scale"
target: message target: message
to: 0.7 to: 0.7
} }
Anim { Anim {
duration: Tokens.anim.durations.large duration: Appearance.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: Tokens.anim.durations.small duration: Appearance.anim.durations.small
easing.type: Easing.Linear easing.type: Easing.Linear
property: "opacity" property: "opacity"
target: message target: message
+18 -18
View File
@@ -1,5 +1,5 @@
import QtQuick import QtQuick
import ZShell.Config import qs.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 Tokens.anim.durations.normal; return Appearance.anim.durations.normal;
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Tokens.anim.durations.expressiveFastSpatial; return Appearance.anim.durations.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Tokens.anim.durations.expressiveDefaultSpatial; return Appearance.anim.durations.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Tokens.anim.durations.expressiveSlowSpatial; return Appearance.anim.durations.large;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Tokens.anim.durations.expressiveFastEffects; return Appearance.anim.durations.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Tokens.anim.durations.expressiveDefaultEffects; return Appearance.anim.durations.expressiveEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Tokens.anim.durations.expressiveSlowEffects; return Appearance.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 Tokens.anim.durations[types[idx]]; return Appearance.anim.durations[types[idx]];
} }
easing: { easing.bezierCurve: {
if (type === Anim.FastSpatial) if (type === Anim.FastSpatial)
return Tokens.anim.expressiveFastSpatial; return Appearance.anim.curves.expressiveFastSpatial;
if (type === Anim.DefaultSpatial) if (type === Anim.DefaultSpatial)
return Tokens.anim.expressiveDefaultSpatial; return Appearance.anim.curves.expressiveDefaultSpatial;
if (type === Anim.SlowSpatial) if (type === Anim.SlowSpatial)
return Tokens.anim.expressiveSlowSpatial; return Appearance.anim.curves.expressiveSlowSpatial;
if (type === Anim.FastEffects) if (type === Anim.FastEffects)
return Tokens.anim.expressiveFastEffects; return Appearance.anim.curves.expressiveFastEffects;
if (type === Anim.DefaultEffects) if (type === Anim.DefaultEffects)
return Tokens.anim.expressiveDefaultEffects; return Appearance.anim.curves.expressiveDefaultEffects;
if (type === Anim.SlowEffects) if (type === Anim.SlowEffects)
return Tokens.anim.expressiveSlowEffects; return Appearance.anim.curves.expressiveSlowEffects;
if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge) if (type >= Anim.EmphasizedSmall && type <= Anim.EmphasizedExtraLarge)
return Tokens.anim.emphasized; return Appearance.anim.curves.emphasized;
return Tokens.anim.standard; return Appearance.anim.curves.standard;
} }
} }
@@ -0,0 +1,24 @@
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
@@ -0,0 +1,165 @@
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;
}
}
}
+4 -3
View File
@@ -1,7 +1,8 @@
import QtQuick import QtQuick
import ZShell.Config import qs.Config
ColorAnimation { ColorAnimation {
duration: Tokens.anim.durations.expressiveSlowEffects duration: MaterialEasing.standardTime
easing: Tokens.anim.expressiveSlowEffects easing.bezierCurve: MaterialEasing.standard
easing.type: Easing.BezierSpline
} }
+11 -11
View File
@@ -1,8 +1,7 @@
import ZShell.Config import qs.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
@@ -18,12 +17,12 @@ BusyIndicator {
} }
property int animState property int animState
property color bgColor: Colors.palette.m3secondaryContainer property color bgColour: DynamicColors.palette.m3secondaryContainer
property color fgColor: Colors.palette.m3primary property color fgColour: DynamicColors.palette.m3primary
property real implicitSize: Tokens.font.size.normal * 3 property real implicitSize: Appearance.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: Tokens.padding.extraSmall * 0.8 property real strokeWidth: Appearance.padding.small * 0.8
property alias type: manager.indeterminateAnimationType property alias type: manager.indeterminateAnimationType
implicitHeight: implicitSize implicitHeight: implicitSize
@@ -32,8 +31,8 @@ BusyIndicator {
contentItem: CircularProgress { contentItem: CircularProgress {
anchors.fill: parent anchors.fill: parent
bgColor: root.bgColor bgColour: root.bgColour
fgColor: root.fgColor fgColour: root.fgColour
padding: root.padding padding: root.padding
rotation: manager.rotation rotation: manager.rotation
startAngle: manager.startFraction * 360 startAngle: manager.startFraction * 360
@@ -51,7 +50,7 @@ BusyIndicator {
} }
transitions: Transition { transitions: Transition {
Anim { Anim {
duration: manager.completeEndDuration * Tokens.anim.durations.scale duration: manager.completeEndDuration * Appearance.anim.durations.scale
properties: "opacity,internalStrokeWidth" properties: "opacity,internalStrokeWidth"
} }
} }
@@ -74,10 +73,11 @@ BusyIndicator {
CircularIndicatorManager { CircularIndicatorManager {
id: manager id: manager
} }
NumberAnimation { NumberAnimation {
duration: manager.duration * Tokens.anim.durations.scale duration: manager.duration * Appearance.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 * Tokens.anim.durations.scale duration: manager.completeEndDuration * Appearance.anim.durations.scale
from: 0 from: 0
property: "completeEndProgress" property: "completeEndProgress"
running: root.animState === CircularIndicator.Completing running: root.animState === CircularIndicator.Completing
+41 -92
View File
@@ -1,117 +1,66 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import ZShell.Components import qs.Config
import ZShell.Config
import qs.Services
Item { Shape {
id: root id: root
readonly property real arcRadius: (size - padding - strokeWidth * (1 + waveAmplitude * 2)) / 2 readonly property real arcRadius: (size - padding - strokeWidth) / 2
property color bgColor: Colors.palette.m3secondaryContainer property color bgColour: DynamicColors.palette.m3secondaryContainer
property real clampedVal: Math.max(1 / 360, Math.min(1, isNaN(value) ? 0 : value)) property color fgColour: DynamicColors.palette.m3primary
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: Tokens.spacing.small property int spacing: Appearance.spacing.small
property int startAngle: -90 property int startAngle: -90
property int strokeWidth: Tokens.padding.extraSmall property int strokeWidth: Appearance.padding.smaller
property int sweepAngle: 360 readonly property real vValue: value || 1 / 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
implicitHeight: implicitSize asynchronous: true
implicitWidth: implicitSize preferredRendererType: Shape.CurveRenderer
Shape { ShapePath {
asynchronous: true capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap
opacity: Math.min(1, remainingArc.sweepAngle) fillColor: "transparent"
preferredRendererType: Shape.CurveRenderer strokeColor: root.bgColour
strokeWidth: root.strokeWidth
ShapePath { Behavior on strokeColor {
capStyle: ShapePath.RoundCap
fillColor: "transparent"
strokeColor: root.bgColor
strokeWidth: Math.min(1, remainingArc.sweepAngle) * root.strokeWidth
Behavior on strokeColor {
CAnim {
}
}
PathAngleArc {
id: remainingArc
centerX: root.size / 2
centerY: root.size / 2
radiusX: root.arcRadius
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))
}
}
}
WavyLine {
id: wave
amplitudeMultiplier: root.wavy ? 0.5 : 0
anchors.fill: parent
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 { CAnim {
duration: Appearance.anim.durations.large
} }
} }
Anim on waveProgress {
id: waveProgAnim
duration: 2000 PathAngleArc {
easing.type: Easing.Linear centerX: root.size / 2
from: 0 centerY: root.size / 2
loops: Animation.Infinite radiusX: root.arcRadius
paused: root.wavePaused || wave.amplitudeMultiplier === 0 radiusY: root.arcRadius
running: true startAngle: root.startAngle + 360 * root.vValue + root.gapAngle
to: 1 sweepAngle: Math.max(-root.gapAngle, 360 * (1 - root.vValue) - root.gapAngle * 2)
} }
} }
Loader { ShapePath {
id: dot capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap
fillColor: "transparent"
strokeColor: root.fgColour
strokeWidth: root.strokeWidth
x: root.size / 2 + root.arcRadius * Math.cos(root.dotAngleRad) - width / 2 Behavior on strokeColor {
y: root.size / 2 + root.arcRadius * Math.sin(root.dotAngleRad) - height / 2 CAnim {
duration: Appearance.anim.durations.large
}
}
sourceComponent: CustomRect { PathAngleArc {
color: root.fgColor centerX: root.size / 2
implicitHeight: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth) centerY: root.size / 2
implicitWidth: Math.min(1, remainingArc.sweepAngle) * Math.min(4, root.strokeWidth) radiusX: root.arcRadius
opacity: Math.min(1, remainingArc.sweepAngle) radiusY: root.arcRadius
radius: Tokens.rounding.full startAngle: root.startAngle
sweepAngle: 360 * root.vValue
} }
} }
} }
+135
View File
@@ -0,0 +1,135 @@
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
@@ -0,0 +1,208 @@
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
@@ -0,0 +1,34 @@
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
@@ -0,0 +1,14 @@
import QtQuick
import QtQuick.Effects
MultiEffect {
property color sourceColor: "black"
brightness: 1 - sourceColor.hslLightness
colorization: 1
Behavior on colorizationColor {
CAnim {
}
}
}
+70
View File
@@ -0,0 +1,70 @@
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
}
}
}

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