Compare commits
248 Commits
v26.1.2-ge
...
main
| Author | SHA1 | Date |
|---|---|---|
|
|
4daff7300f | |
|
|
ba8dbc9c14 | |
|
|
3799ae6629 | |
|
|
2523618522 | |
|
|
6563bbd7de | |
|
|
a0c33bc744 | |
|
|
c77e465343 | |
|
|
e2e4ff95c0 | |
|
|
e166d46806 | |
|
|
169fa0d32a | |
|
|
741ffee62e | |
|
|
951dbbd87f | |
|
|
1742d5f589 | |
|
|
698ff86c14 | |
|
|
0d0b5b8633 | |
|
|
1a11b475ae | |
|
|
a9986e6b67 | |
|
|
34bd920f3b | |
|
|
07b7d89be6 | |
|
|
e93bbdba7b | |
|
|
b074983a70 | |
|
|
3f858e5e2f | |
|
|
a3b1fdcd0d | |
|
|
b906bc6656 | |
|
|
638af5a608 | |
|
|
ba598ee77f | |
|
|
374f85ee81 | |
|
|
5e316fe0d3 | |
|
|
025c6a0998 | |
|
|
8a8c41bd9e | |
|
|
4edc6053ce | |
|
|
0962f4c015 | |
|
|
d4a64d6490 | |
|
|
e7a9df17cf | |
|
|
65fd75eb4a | |
|
|
f3bb2e070b | |
|
|
5014cda64a | |
|
|
6a24399a9c | |
|
|
42a7175b7f | |
|
|
28da0347ae | |
|
|
da394ec2c7 | |
|
|
3c8f878ede | |
|
|
5723c3c1df | |
|
|
37896620eb | |
|
|
6dc76c881f | |
|
|
4b78e39af7 | |
|
|
7f97dc884f | |
|
|
9806027e19 | |
|
|
066f033a91 | |
|
|
1591466a8d | |
|
|
901c18520e | |
|
|
e39085aa2b | |
|
|
48d58f61d2 | |
|
|
8691cf99d2 | |
|
|
80bfb177be | |
|
|
20743f91eb | |
|
|
5cf7b986f3 | |
|
|
3d71746ff2 | |
|
|
c7b16c5713 | |
|
|
ed1d708802 | |
|
|
557a0775c3 | |
|
|
2309f89701 | |
|
|
cdd658d4ea | |
|
|
ec2e0501c1 | |
|
|
f30c650bba | |
|
|
45af52ddf9 | |
|
|
10b14794ed | |
|
|
6b81f07cc8 | |
|
|
9734955ebb | |
|
|
dd3108d423 | |
|
|
bf7276b2dd | |
|
|
90c4567505 | |
|
|
6cddb43b0f | |
|
|
f3732c7087 | |
|
|
07bd841bc6 | |
|
|
9986b71b26 | |
|
|
16446f7808 | |
|
|
5615186654 | |
|
|
244822ffb3 | |
|
|
266b0fd507 | |
|
|
0d8937ff80 | |
|
|
c59e195d94 | |
|
|
994dffc4fb | |
|
|
701e41296b | |
|
|
b0dba25f36 | |
|
|
1bee41aea9 | |
|
|
2035d9ba76 | |
|
|
24e3099b7b | |
|
|
aee5bf69da | |
|
|
62881c08b3 | |
|
|
0c87d47ce6 | |
|
|
47bb5ab7a2 | |
|
|
e5e798b599 | |
|
|
68daa5b3df | |
|
|
f2dcdcc6c3 | |
|
|
a3460fbe70 | |
|
|
7f822b6787 | |
|
|
1d8b22d992 | |
|
|
1238808d87 | |
|
|
26f5be36b6 | |
|
|
0c1b0906c1 | |
|
|
5eb258e310 | |
|
|
bec00c6f48 | |
|
|
db1675d399 | |
|
|
18f99b5daf | |
|
|
543f157895 | |
|
|
8ad31cfa28 | |
|
|
80277e0c12 | |
|
|
0a4fc34fac | |
|
|
e035fb9d27 | |
|
|
97fcde1a3b | |
|
|
c16c403966 | |
|
|
d5148e2107 | |
|
|
0f6f344c97 | |
|
|
41c6f43a3c | |
|
|
f44c4b78bc | |
|
|
5420efa4d3 | |
|
|
89f43b95ef | |
|
|
00bc179655 | |
|
|
a4115f5e4b | |
|
|
6c896bb956 | |
|
|
d9c8689c18 | |
|
|
5df6ce93f8 | |
|
|
ee4bb5ca29 | |
|
|
b89ae4726c | |
|
|
b0bbc25083 | |
|
|
635df298fe | |
|
|
786847cc2f | |
|
|
d9f89faf33 | |
|
|
769978560e | |
|
|
bebc39e766 | |
|
|
bb15a4e867 | |
|
|
84015c7972 | |
|
|
f2c34fba8f | |
|
|
1a74eb1507 | |
|
|
6b3f8a7b42 | |
|
|
ad78fdab24 | |
|
|
12ceebec6d | |
|
|
6f9ca5b3b7 | |
|
|
c54b211872 | |
|
|
cb899235b4 | |
|
|
a83af3d833 | |
|
|
e8c8a67fc0 | |
|
|
2b4a0b6a0d | |
|
|
5ffa5e59bf | |
|
|
ed8ca1e068 | |
|
|
f21776b123 | |
|
|
ab3f873a38 | |
|
|
de6047107e | |
|
|
39152b8548 | |
|
|
b517afc379 | |
|
|
b84d565b1e | |
|
|
46f3a54203 | |
|
|
4afaa6d048 | |
|
|
26f078d512 | |
|
|
124d817752 | |
|
|
2ddb419676 | |
|
|
841241a7e6 | |
|
|
c902f0cd44 | |
|
|
756c42609d | |
|
|
4fc439abe2 | |
|
|
9685576272 | |
|
|
d2f01c06ec | |
|
|
94c36076af | |
|
|
a4134030fe | |
|
|
ebacbf175a | |
|
|
6c987b4492 | |
|
|
8acb2236bd | |
|
|
5dae6f8387 | |
|
|
5ab242f8e0 | |
|
|
fcbb5fab73 | |
|
|
f9a57e58bb | |
|
|
d713302d0d | |
|
|
d398e6fb5a | |
|
|
903a6b351c | |
|
|
b3e09b330f | |
|
|
c63089b944 | |
|
|
ca770c1c05 | |
|
|
ac65bca05a | |
|
|
e61fd66210 | |
|
|
1dc7d4340c | |
|
|
a22bb2bf1a | |
|
|
e1c72fa446 | |
|
|
676a96b2cd | |
|
|
4821123c73 | |
|
|
32c8b7ae62 | |
|
|
d97bbfc796 | |
|
|
19083cfd83 | |
|
|
2c60196ead | |
|
|
b17de39ef0 | |
|
|
46e54db969 | |
|
|
554029aacf | |
|
|
a5146e0396 | |
|
|
6960652379 | |
|
|
3ec1dd7f4e | |
|
|
157c88127f | |
|
|
18e628f083 | |
|
|
ab83d44a5e | |
|
|
fa6492a422 | |
|
|
160e84120d | |
|
|
c222c25ddf | |
|
|
ee8391a45f | |
|
|
3ac6f70725 | |
|
|
d23b058d0e | |
|
|
37fde4c642 | |
|
|
2ade8c542e | |
|
|
03a1f449b5 | |
|
|
7b3a2a1e48 | |
|
|
dabd122a1d | |
|
|
0181119393 | |
|
|
2e1d07abc2 | |
|
|
fe61319fc2 | |
|
|
da644c97d3 | |
|
|
b67914b956 | |
|
|
e4caa1d6d4 | |
|
|
ea62be8ad7 | |
|
|
6ab1db9a76 | |
|
|
cd0d49eaf6 | |
|
|
a97ee2cee2 | |
|
|
9d43068271 | |
|
|
c7ebb7492e | |
|
|
c5356724fd | |
|
|
d02efc2657 | |
|
|
40cd532134 | |
|
|
869c0ba5e2 | |
|
|
fd24060d7b | |
|
|
1318f23947 | |
|
|
d2385fd3b2 | |
|
|
7059a85742 | |
|
|
2e5dcd62c1 | |
|
|
72e64ad965 | |
|
|
0e004e7b3f | |
|
|
91bc46defe | |
|
|
b8f266ea6a | |
|
|
a33d4ec9d0 | |
|
|
4c3500ea16 | |
|
|
bc1c993e17 | |
|
|
3889c9d2ea | |
|
|
8eda46fb5e | |
|
|
a0451408aa | |
|
|
84d4fb7cc2 | |
|
|
b48320c7bc | |
|
|
ce5191ddd1 | |
|
|
37e3ab1bda | |
|
|
6b98d5f188 | |
|
|
f059c5668a | |
|
|
e7fc7be950 | |
|
|
6136fae885 |
|
|
@ -0,0 +1 @@
|
|||
open_collective: wayvr-org
|
||||
|
|
@ -22,25 +22,28 @@ If this is a regression, please mention which version was working previously.
|
|||
**Kernel version**:
|
||||
|
||||
**VR Runtime**:
|
||||
- [ ] Monado/WiVRn
|
||||
- [ ] SteamVR/ALVR
|
||||
- [ ] Monado
|
||||
- [ ] WiVRn
|
||||
- [ ] ALVR
|
||||
- [ ] SteamLink
|
||||
- [ ] SteamVR (not SteamLink)
|
||||
|
||||
<!-- Run `vulkaninfo --summary` and paste the devices section from the bottom. -->
|
||||
**GPU models and driver versions**:
|
||||
|
||||
## Overlay Logs
|
||||
|
||||
<!-- Start the overlay once more with the following environment variables:
|
||||
RUST_BACKTRACE=full
|
||||
RUST_LOG=debug
|
||||
If your issue is graphical or crash or freeze, also add:
|
||||
VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation
|
||||
<!-- Start the overlay from terminal, with additional environment variables:
|
||||
|
||||
Next, create the empty log file: echo > /tmp/wlx.log
|
||||
AppImage:
|
||||
RUST_BACKTRACE=full RUST_LOG=debug /path/to/WayVR.AppImage
|
||||
|
||||
Be sure to go and reproduce the issue once more, after these have been set.
|
||||
System or AUR package:
|
||||
RUST_BACKTRACE=full RUST_LOG=debug wayvr
|
||||
|
||||
Upload the log file from: /tmp/wlx.log
|
||||
Reproduce the issue once more, while WayVR is running from the terminal.
|
||||
|
||||
Upload the log file from: /tmp/wayvr.log
|
||||
|
||||
-->
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ env:
|
|||
|
||||
jobs:
|
||||
build_appimage:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ env:
|
|||
|
||||
jobs:
|
||||
make_release:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./wayvr
|
||||
|
|
@ -36,10 +36,9 @@ jobs:
|
|||
cargo build --release
|
||||
- name: Make tarball
|
||||
run: |
|
||||
pip install portage pycargoebuild
|
||||
wget https://github.com/gentoo/gentoo/raw/refs/heads/master/metadata/license-mapping.conf
|
||||
mkdir dist
|
||||
pycargoebuild --distdir dist --license-mapping license-mapping.conf --crate-tarball --crate-tarball-path wayvr-crates.tar.xz
|
||||
cargo vendor > vendor-config.toml
|
||||
mv vendor-config.toml vendor
|
||||
tar --xz -cf vendor.tar.xz vendor
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
|
|
@ -81,12 +80,12 @@ jobs:
|
|||
asset_name: WayVR-${{ github.ref_name }}-x86_64.AppImage
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload crates tarball
|
||||
- name: Upload vendor tarball
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_KEY }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./wayvr/wayvr-crates.tar.xz
|
||||
asset_name: WayVR-${{ github.ref_name }}-crates.tar.xz
|
||||
asset_path: ./wayvr/vendor.tar.xz
|
||||
asset_name: vendor.tar.xz
|
||||
asset_content_type: application/x-gtar
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
sudo add-apt-repository -syn universe
|
||||
sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 libwayland-dev libegl-dev libxcb-glx0 libxcb-glx0-dev
|
||||
sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 libwayland-dev libegl-dev libxcb-glx0 libxcb-glx0-dev dav1d libdav1d-dev
|
||||
rustup update
|
||||
|
||||
if [ "$APPDIR" != "" ]; then
|
||||
|
|
|
|||
78
Cargo.toml
|
|
@ -1,3 +1,45 @@
|
|||
[workspace]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"dash-frontend",
|
||||
"scripts/prost_build",
|
||||
"uidev",
|
||||
"wayvr",
|
||||
"wayvr-ipc",
|
||||
"wayvrctl",
|
||||
"wgui",
|
||||
"wlx-capture",
|
||||
"wlx-common",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.100"
|
||||
bytes = { version = "1.11.1" }
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
glam = { version = "0.30.9", features = ["mint", "serde"] }
|
||||
idmap = "0.2.2"
|
||||
idmap-derive = "0.2.22"
|
||||
log = "0.4.29"
|
||||
regex = "1.12.2"
|
||||
rust-embed = "8.9.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1.0.145"
|
||||
serde_json5 = "0.2.1"
|
||||
slotmap = "1.1.1"
|
||||
smol = "2.0.2"
|
||||
strum = { version = "0.27.2", features = ["derive"] }
|
||||
uuid = { version = "1.19.0", features = ["fast-rng", "serde", "v4"] }
|
||||
vulkano = { version = "0.35.2", default-features = false, features = [
|
||||
"macros",
|
||||
] }
|
||||
vulkano-shaders = "0.35.0"
|
||||
wayland-client = { version = "0.31.11" }
|
||||
wayland-protocols-misc = { version = "0.3.12" }
|
||||
xdg = "3.0.0"
|
||||
|
||||
[patch.crates-io]
|
||||
vulkano = { git = "https://github.com/galister/vulkano.git", rev = "cf7f92867928a56ce16b376037c1120f2b167678" }
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
debug = true
|
||||
|
|
@ -19,39 +61,3 @@ incremental = true
|
|||
[profile.release-with-debug]
|
||||
inherits = "release"
|
||||
debug = true
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"uidev",
|
||||
"wgui",
|
||||
"wlx-common",
|
||||
"wayvr",
|
||||
"wlx-capture",
|
||||
"dash-frontend",
|
||||
"wayvr-ipc",
|
||||
"wayvrctl",
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
[patch.crates-io]
|
||||
vulkano = { git = "https://github.com/galister/vulkano.git", rev = "cf7f92867928a56ce16b376037c1120f2b167678" }
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.100"
|
||||
glam = { version = "0.30.9", features = ["mint", "serde"] }
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
xdg = "3.0.0"
|
||||
idmap = "0.2.2"
|
||||
idmap-derive = "0.2.22"
|
||||
log = "0.4.29"
|
||||
regex = "1.12.2"
|
||||
rust-embed = "8.9.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1.0.145"
|
||||
slotmap = "1.1.1"
|
||||
strum = { version = "0.27.2", features = ["derive"] }
|
||||
vulkano = { version = "0.35.2", default-features = false, features = [
|
||||
"macros",
|
||||
] }
|
||||
vulkano-shaders = "0.35.0"
|
||||
wayland-client = { version = "0.31.11" }
|
||||
|
|
|
|||
85
README.md
|
|
@ -1,20 +1,20 @@
|
|||

|
||||

|
||||
|
||||
# WayVR (previously WlxOverlay-S)
|
||||
|
||||
A lightweight OpenXR/OpenVR overlay for Wayland and X11 desktops.
|
||||
|
||||
WayVR lets you to access your desktop screens while in VR, and even launch apps directly in VR.
|
||||
WayVR lets you access your desktop screens while in VR, and even launch apps directly in VR.
|
||||
|
||||
In comparison to similar overlays, WayVR aims to run alongside VR games and experiences while having as little performance impact as possible. The UI appearance and rendering techniques are kept as simple and efficient as possible, while still allowing a high degree of customizability.
|
||||
|
||||

|
||||

|
||||
|
||||
## Join the Linux VR Community
|
||||
|
||||
We are available on either **Discord** or **Matrix space**:
|
||||
|
||||
[](https://discord.gg/EHAYe3tTYa) [](https://matrix.to/#/#linux-vr-adventures:matrix.org)
|
||||
[](https://discord.gg/EHAYe3tTYa) [](https://matrix.to/#/#linux-vr-adventures:matrix.org)
|
||||
|
||||
Questions/issues specific to WayVR will be handled in the `wayvr` chat room. Feel free to ask anything.
|
||||
|
||||
|
|
@ -24,14 +24,11 @@ Questions/issues specific to WayVR will be handled in the `wayvr` chat room. Fee
|
|||
|
||||
There are multiple ways to install WayVR:
|
||||
|
||||
1. AppImage: Download from [Releases](https://github.com/wlx-team/wayvr/releases)
|
||||
1. AppImage: Download from [Releases](https://github.com/wayvr-org/wayvr/releases)
|
||||
1. AUR package: [wayvr](https://aur.archlinux.org/packages/wayvr) or [wayvr-git](https://aur.archlinux.org/packages/wayvr-git)
|
||||
1. Homebrew:
|
||||
|
||||
- Add AtomicXR tap: `brew tap matrixfurry.com/atomicxr https://tangled.sh/@matrixfurry.com/homebrew-atomicxr`
|
||||
- Install WayVR: `brew install wlx-overlay-s`
|
||||
|
||||
1. [Building from source](https://github.com/wlx-team/wayvr/wiki/Building-from-Source).
|
||||
1. Nix package: [wayvr](https://search.nixos.org/packages?channel=unstable&show=wayvr&query=wayvr) or [unstable package from nixpkgs-xr](https://github.com/nix-community/nixpkgs-xr)
|
||||
1. [Homebrew-XR](https://tangled.org/matrixfurry.com/homebrew-xr) package (for Bazzite, etc.): [wayvr](https://tangled.org/matrixfurry.com/homebrew-xr/#installing-applications)
|
||||
1. [Docs: Building from source](https://wayvr.org/docs/basics/building-from-source/).
|
||||
|
||||
### General Setup
|
||||
|
||||
|
|
@ -44,7 +41,7 @@ There are multiple ways to install WayVR:
|
|||
|
||||
For users specifically running **SteamVR via Steam Flatpak**, follow these steps:
|
||||
|
||||
1. Grab the latest AppImage from [Releases](https://github.com/wlx-team/wayvr/releases).
|
||||
1. Grab the latest AppImage from [Releases](https://github.com/wayvr-org/wayvr/releases).
|
||||
1. `WayVR-*.AppImage --appimage-extract`
|
||||
1. `chmod +x squashfs-root/AppRun`
|
||||
1. Move the newly created `squashfs-root` folder to a location accessible by the Steam Flatpak.
|
||||
|
|
@ -60,15 +57,15 @@ For users specifically running **SteamVR via Steam Flatpak**, follow these steps
|
|||
In case screens were selected in the wrong order:
|
||||
|
||||
- Go to Settings and press `Clear PipeWire tokens` and then `Restart software`
|
||||
- Pay attention to your notifications, it tells you in which order to pick the screens.
|
||||
- If notifications don't show, try start WayVR from the terminal and look for instructions in there.
|
||||
- Pay attention to your notifications, which tell you in which order to pick the screens.
|
||||
- If notifications don't show, try starting WayVR from the terminal and look for instructions in there.
|
||||
|
||||
**WiVRn users**: Select WayVR from the `Application` drop-down. If there's no such entry, select `Custom` and browse to your WayVR executable or AppImage.
|
||||
|
||||
**Envision users**: Go to the Plugins menu and select the WayVR plugin. This will download and run the AppImage version of the overlay.
|
||||
In order to run a standalone installation (for instance from the AUR), create a bash script containing `wayvr --openxr --show` and then set this bash script as a custom Envision plugin.
|
||||
To run a standalone installation (for instance, from the AUR), create a bash script containing `wayvr --openxr --show` and then set this bash script as a custom Envision plugin.
|
||||
|
||||
This will show a home environment with headset passthrough by default or a [customizable background](https://github.com/wlx-team/wayvr/wiki/OpenXR-Skybox)!
|
||||
This will show a home environment with headset passthrough enabled by default or a [customizable background](https://wayvr.org/docs/various/openxr-skybox/)!
|
||||
|
||||
**SteamVR users**: WayVR will register itself for auto-start, so there is no need to start it every time. Disclaimer: SteamVR will sometimes disregard this and not start WayVR anyway.
|
||||
|
||||
|
|
@ -78,7 +75,7 @@ This will show a home environment with headset passthrough by default or a [cust
|
|||
|
||||
### Working Set
|
||||
|
||||
The working set consists of all currently selected overlays; screens, mirrors, keyboard, etc.
|
||||
The working set consists of all currently selected overlays: screens, mirrors, keyboard, etc.
|
||||
|
||||
The working set appears in front of the headset when shown, and can be re-centered by hiding and showing again.
|
||||
|
||||
|
|
@ -108,17 +105,17 @@ Check your left wrist for the watch. The watch is the primary tool for controlli
|
|||
|
||||
The top of the watch shows device batteries, and the bottom shows your overlay controls.
|
||||
|
||||
Enter edit mode (leftmost button on bottom) to edit your overlay sets.
|
||||
Enter edit mode (the leftmost button at the bottom) to edit your overlay sets.
|
||||
|
||||
While in edit mode, the watch can also be grabbed, and passed between your hands.
|
||||
While in edit mode, the watch can also be grabbed and passed between your hands.
|
||||
|
||||
After grabbing, the watch will automatically attach to the hand that's opposite from the one that held it.
|
||||
|
||||
In edit mode, try hovering other overlays to see their advanced options!
|
||||
In edit mode, try hovering over other overlays to see their advanced options!
|
||||
|
||||
### The screens
|
||||
|
||||
Hovering a pointer over a screen will move the mouse. If there are more than one pointers hovering a screen, the pointer that was last used to click will take precedence.
|
||||
Hovering a pointer over a screen will move the mouse. If more than one pointer is hovering over a screen, the pointer that was last used to click will take precedence.
|
||||
|
||||
The click type depends on the laser color:
|
||||
|
||||
|
|
@ -132,29 +129,45 @@ The click type depends on the laser color:
|
|||
Typing
|
||||
|
||||
- Use the BLUE laser when typing regularly.
|
||||
- While using ORANGE laser, all keystrokes will have SHIFT applied.
|
||||
- While using the ORANGE laser, all keystrokes will have SHIFT applied.
|
||||
- Purple laser is customizable via the settings, no modifier by default.
|
||||
|
||||
**Modifier Keys** are sticky. They will remain pressed until a non-modifier key is pressed, the modifier gets toggled off, or the keyboard gets hidden.
|
||||
**Modifier Keys are sticky**. They will remain pressed until either:
|
||||
|
||||
- a non-modifier key is pressed
|
||||
- the modifier is toggled off by clicking again
|
||||
- the keyboard is hidden (including via show-hide)
|
||||
|
||||
### Default Bindings
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
To customize bindings on OpenXR, refer to the [OpenXR Bindings wiki page](https://github.com/wlx-team/wayvr/wiki/OpenXR-Bindings).
|
||||
### Changing Bindings
|
||||
|
||||
If your bindings are not supported, please reach out. \
|
||||
SteamVR: Simply change the bindings from the SteamVR bindings section. If WayVR doesn't show up on the list, select any other title and then press back on the top left. (SteamVR is weird like that sometimes)
|
||||
|
||||
OpenXR (Monado/WiVRn): See [Docs: OpenXR Bindings](https://wayvr.org/docs/various/openxr-bindings/)
|
||||
|
||||
If your controllers are not supported, please reach out. \
|
||||
We would like to work with you and include additional bindings.
|
||||
|
||||
## Customization
|
||||
|
||||
See these relevant wiki pages:
|
||||
|
||||
- For all available config options, check [Docs: Configuration](https://wayvr.org/docs/basics/configuration/)
|
||||
- Looking to customize look & feel, or add functionality? See [Docs: Customization](https://wayvr.org/docs/basics/customization/)
|
||||
- Looking to change the OpenXR background? See [Docs: OpenXR Skybox](https://wayvr.org/docs/various/openxr-skybox/)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
When an error is detected, we often print tips for fixing into the log file.
|
||||
When an error is detected, we often print tips for fixing it into the log file.
|
||||
|
||||
Logs will be at `/tmp/wayvr.log` for most distros.
|
||||
|
||||
Check [here](https://github.com/wlx-team/wayvr/wiki/Troubleshooting) for tips.
|
||||
Check [here](https://wayvr.org/docs/various/troubleshooting/) for tips.
|
||||
|
||||
## Known Issues
|
||||
|
||||
|
|
@ -163,8 +176,8 @@ Check [here](https://github.com/wlx-team/wayvr/wiki/Troubleshooting) for tips.
|
|||
If the mouse is moving on a completely different screen, the screens were likely selected in the wrong order:
|
||||
|
||||
- Go to Settings and press `Clear PipeWire tokens` and then `Restart software`
|
||||
- Pay attention to your notifications, it tells you in which order to pick the screens.
|
||||
- If notifications don't show, try start WayVR from the terminal and look for instructions in there.
|
||||
- Pay attention to your notifications, which tell you in which order to pick the screens.
|
||||
- If notifications don't show, try starting WayVR from the terminal and look for instructions in there.
|
||||
|
||||
COSMIC desktop:
|
||||
|
||||
|
|
@ -176,23 +189,23 @@ X11 users:
|
|||
- DPI scaling is not supported and will mess with the mouse.
|
||||
- Upright screens are not supported and will mess with the mouse.
|
||||
|
||||
### Screens are blank or black or frozen on Steam Link
|
||||
### Screens are blank or black or frozen on SteamVR 2.14+
|
||||
|
||||
As of SteamVR version 2.14.x, PipeWire capture no longer works when using Steam Link.
|
||||
|
||||
We're unable to completely troubleshoot how and why Steam Link interferes with PipeWire, so consider the following workarounds for the time being:
|
||||
We're unable to completely troubleshoot how and why SteamVR interferes with PipeWire, so consider the following workarounds for the time being:
|
||||
|
||||
- Use another streamer, such as WiVRn or ALVR
|
||||
- Use another streamer, such as WiVRn or ALVR. Note that SteamVR on Linux is considered experimental by Valve themselves [disclaimer](https://github.com/ValveSoftware/SteamVR-for-Linux?tab=readme-ov-file#steamvr-release-notes-and-known-issues).
|
||||
- If your desktop [supports ScreenCopy](https://wayland.app/protocols/wlr-screencopy-unstable-v1#compositor-support), go to Settings and set `Wayland capture method` to `ScreenCopy`
|
||||
- If your desktop has an X11 mode, try using that
|
||||
|
||||
### Modifiers get stuck
|
||||
|
||||
Hiding the keyboard will un-press all of its buttons. Alternatively, go to Settings and use the `Restart software` button.
|
||||
Hiding the keyboard will unpress all of its buttons. Alternatively, go to Settings and use the `Restart software` button.
|
||||
|
||||
### X11 limitations
|
||||
|
||||
- X11 capture can generally seem slow. This is because zero-copy GPU capture is not supported on the general X11 desktop. Consider trying Wayland.
|
||||
- DPI scaling is not supported and may cause the mouse to not follow the laser properly.
|
||||
- Upright screens are not supported and can cause the mouse to not follow the laser properly.
|
||||
- Screen changes (connecting / disconnecting a display, resolution changes, etc) are not handled at runtime. Restart the overlay for these to take effect.
|
||||
- Screen changes (connecting/disconnecting a display, resolution changes, etc) are not handled at runtime. Restart the overlay for these to take effect.
|
||||
|
|
|
|||
|
|
@ -8,27 +8,27 @@ authors = ["galister", "oo8dev"]
|
|||
repository = "https://github.com/wlx-team/wayvr"
|
||||
|
||||
[dependencies]
|
||||
wayvr-ipc = { path = "../wayvr-ipc", default-features = false }
|
||||
wgui = { path = "../wgui/" }
|
||||
wlx-common = { path = "../wlx-common" }
|
||||
|
||||
anyhow.workspace = true
|
||||
async-native-tls = "0.5.0"
|
||||
chrono = "0.4.42"
|
||||
glam = { workspace = true, features = ["mint", "serde"] }
|
||||
http-body-util = "0.1.3"
|
||||
hyper = { version = "1.8.1", features = ["client", "http1", "http2"] }
|
||||
keyvalues-parser = { git = "https://codeberg.org/CosmicHarper/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" }
|
||||
log.workspace = true
|
||||
xdg.workspace = true
|
||||
lz4_flex = { version = "0.13.1", features = ["frame"] }
|
||||
rust-embed.workspace = true
|
||||
serde = { workspace = true, features = ["rc"] }
|
||||
serde_json.workspace = true
|
||||
strum.workspace = true
|
||||
|
||||
chrono = "0.4.42"
|
||||
keyvalues-parser = { git = "https://github.com/CosmicHorrorDev/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" }
|
||||
smol = "2.0.2"
|
||||
hyper = { version = "1.8.1", features = ["client", "http1", "http2"] }
|
||||
http-body-util = "0.1.3"
|
||||
async-native-tls = "0.5.0"
|
||||
smol = { workspace = true }
|
||||
smol-hyper = "0.1.1"
|
||||
strum.workspace = true
|
||||
uuid.workspace = true
|
||||
wayvr-ipc = { path = "../wayvr-ipc", default-features = false }
|
||||
wgui = { path = "../wgui/" }
|
||||
wlx-common = { path = "../wlx-common" }
|
||||
xdg.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["monado" ]
|
||||
default = ["monado"]
|
||||
monado = []
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
|
||||
<path fill="currentColor" d="m10 18l-6-6l6-6l1.4 1.45L7.85 11H20v2H7.85l3.55 3.55z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 294 B |
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
|
||||
<path fill="currentColor" d="m14 18l-1.4-1.45L16.15 13H4v-2h12.15L12.6 7.45L14 6l6 6z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 9.8 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="#F55" d="m8.4 17l3.6-3.6l3.6 3.6l1.4-1.4l-3.6-3.6L17 8.4L15.6 7L12 10.6L8.4 7L7 8.4l3.6 3.6L7 15.6zm3.6 5q-2.075 0-3.9-.788t-3.175-2.137T2.788 15.9T2 12t.788-3.9t2.137-3.175T8.1 2.788T12 2t3.9.788t3.175 2.137T21.213 8.1T22 12t-.788 3.9t-2.137 3.175t-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8"/></svg>
|
||||
|
After Width: | Height: | Size: 573 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="#33FF99" d="m9.55 18l-5.7-5.7l1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"/></svg>
|
||||
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 22 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M11.7 18q-2.4-.125-4.05-1.85T6 12q0-2.5 1.75-4.25T12 6q2.425 0 4.15 1.65T18 11.7l-2.1-.625q-.325-1.35-1.4-2.212T12 8q-1.65 0-2.825 1.175T8 12q0 1.425.863 2.5t2.212 1.4zm8.825 4.5l-4.275-4.275L15 22l-3-10l10 3l-3.775 1.25l4.275 4.275z"/></svg>
|
||||
|
After Width: | Height: | Size: 470 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z"/></svg>
|
||||
|
After Width: | Height: | Size: 360 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="m12 22l-4.25-4.25l1.425-1.425L11 18.15V13H5.875L7.7 14.8l-1.45 1.45L2 12l4.225-4.225L7.65 9.2L5.85 11H11V5.85L9.175 7.675L7.75 6.25L12 2l4.25 4.25l-1.425 1.425L13 5.85V11h5.125L16.3 9.2l1.45-1.45L22 12l-4.25 4.25l-1.425-1.425L18.15 13H13v5.125l1.8-1.825l1.45 1.45z"/></svg>
|
||||
|
After Width: | Height: | Size: 500 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="#FF4455" d="M12 17q.425 0 .713-.288T13 16t-.288-.712T12 15t-.712.288T11 16t.288.713T12 17m-1-4h2V7h-2zm1 9q-2.075 0-3.9-.788t-3.175-2.137T2.788 15.9T2 12t.788-3.9t2.137-3.175T8.1 2.788T12 2t3.9.788t3.175 2.137T21.213 8.1T22 12t-.788 3.9t-2.137 3.175t-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8"/></svg>
|
||||
|
After Width: | Height: | Size: 574 B |
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="gravity.svg"
|
||||
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="23.234375"
|
||||
inkscape:cx="17.861466"
|
||||
inkscape:cy="22.488231"
|
||||
inkscape:window-width="1582"
|
||||
inkscape:window-height="1302"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
|
||||
<!-- Modified it a little bit, there's no "space gravity" icon available. -->
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m 15.76786,18.274928 -1.391472,0.295932 -0.674684,-2.9751 -3.051267,-0.735557 -2.4062791,-3.292082 -0.8846145,1.824345 1.561484,2.213127 -1.1706157,0.808349 -1.9932655,-2.862487 1.752944,-3.7745856 Q 7.740355,9.2978686 8.2693798,9.1366908 8.7984057,8.9755132 9.3446883,8.9671549 9.9537305,8.9704882 10.547911,8.8283107 11.142091,8.6861403 11.667399,8.364791 12.192707,8.0434408 12.541821,7.5511898 12.890935,7.0589389 13.170167,6.5208564 l 1.228561,0.6477209 q -0.321651,0.575352 -0.696034,1.1164692 -0.374382,0.5411172 -0.890945,0.9726251 -0.466314,0.3718768 -0.998843,0.6112737 -0.532529,0.2393967 -1.117089,0.3386867 L 12,12 l 2.176682,-1.469824 4.352172,0.934365 -0.326914,1.35612 -3.582453,-0.734464 -2.11263,1.442217 2.281549,0.535655 z M 7.5517982,8.9044443 Q 7.0233673,9.1322023 6.4853273,8.9182692 5.9472884,8.7043353 5.7186139,8.1755407 5.4899403,7.6467461 5.7054294,7.108795 5.9209195,6.5708439 6.4475175,6.3423563 6.9741154,6.1138698 7.5149037,6.3288971 8.0556931,6.5439235 8.2807018,7.07126 8.5057095,7.5985974 8.2948017,8.1383704 8.0838948,8.6781445 7.5517982,8.9044443"
|
||||
id="path1"
|
||||
style="stroke-width:0.697484" />
|
||||
<path
|
||||
id="path2"
|
||||
style="fill:none;stroke:currentColor;stroke-width:2.43525;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:0, 7.30575"
|
||||
d="M 22.480952,12 C 22.480952,17.78847 17.78847,22.480952 12,22.480952 6.2115299,22.480952 1.5190477,17.78847 1.5190477,12 1.5190475,6.2115298 6.2115298,1.5190477 12,1.5190477 c 0.653263,0 1.292568,0.059766 1.912744,0.1741274 C 18.787854,2.5921561 22.480952,6.8647934 22.480952,12 Z"
|
||||
sodipodi:nodetypes="ssssss" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 384.00001 383.99998"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="hand_left.svg"
|
||||
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:clip-to-page="false"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="24"
|
||||
inkscape:cy="15.9375"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE -->
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m 223.99926,120.14002 v 90.93 c 0,46.2 -36.85,84.55 -83,85.06 a 83.7,83.7 0 0 1 -60.400003,-24.59 c -21.81,-23.07 -46.45,-79.4 -46.45,-79.4 a 16,16 0 0 1 6.53,-22.23 c 7.66,-4 17.1,-0.84 21.4,6.62 l 21,36.44 a 6.09,6.09 0 0 0 6,3.09 h 0.12 a 8.19,8.19 0 0 0 6.800001,-8.18 v -103.74 A 16,16 0 0 1 112.76926,88.140018 c 8.61,0.4 15.23,7.82 15.23,16.430002 v 63.57 a 8,8 0 0 0 8.53,8 8.17,8.17 0 0 0 7.47,-8.25 V 88.140018 a 16,16 0 0 1 16.77,-15.999999 c 8.61,0.4 15.23,7.82 15.23,16.429999 v 87.570002 a 8,8 0 0 0 8.53,8 8.17,8.17 0 0 0 7.47,-8.25 v -55.3 c 0,-8.61 6.62,-16 15.23,-16.43 a 16,16 0 0 1 16.77,15.98"
|
||||
id="path1" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M 263.19112,258.73409 V 112.03922 h 18.49095 v 130.25847 h 64.10196 v 16.4364 z"
|
||||
id="text1"
|
||||
aria-label="L" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 384 383.99998"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="hand_right.svg"
|
||||
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="24"
|
||||
inkscape:cy="15.9375"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE -->
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M 30.079989,119.60999 V 210.54 c 0,46.2 36.85,84.55 83.000011,85.06 a 83.7,83.7 0 0 0 60.4,-24.59 c 21.81,-23.07 46.45,-79.4 46.45,-79.4 a 16,16 0 0 0 -6.53,-22.23 c -7.66,-4.00001 -17.1,-0.84 -21.4,6.62 l -21,36.44 a 6.09,6.09 0 0 1 -6,3.09 h -0.12 a 8.19,8.19 0 0 1 -6.8,-8.18 V 103.60999 a 16,16 0 0 0 -16.77,-16 c -8.61,0.4 -15.23,7.82 -15.23,16.43 V 167.61 a 8,8 0 0 1 -8.53,8 8.17,8.17 0 0 1 -7.47,-8.25 V 87.60999 A 16,16 0 0 0 93.309986,71.609992 c -8.609997,0.4 -15.229997,7.819999 -15.229997,16.429998 V 175.61 a 8,8 0 0 1 -8.53,8 8.17,8.17 0 0 1 -7.47,-8.25 v -55.30001 c 0,-8.61 -6.62,-16 -15.23,-16.43 a 16,16 0 0 0 -16.77,15.98"
|
||||
id="path1" />
|
||||
<path
|
||||
d="m 301.74274,111.50919 q 27.32551,0 40.26918,10.4782 13.14912,10.27275 13.14912,31.22916 0,11.71094 -4.31456,19.51824 -4.31455,7.80729 -11.09457,12.53275 -6.57456,4.52001 -13.97094,7.19093 l 40.26918,65.7456 h -21.57277 l -35.54372,-60.60923 h -29.17461 v 60.60923 H 261.2681 V 111.50919 Z m -1.02728,16.02549 h -20.95641 v 54.44558 h 21.98369 q 17.87458,0 26.09278,-6.98547 8.2182,-7.19092 8.2182,-20.95642 0,-14.38185 -8.62911,-20.34004 -8.62911,-6.16365 -26.70915,-6.16365 z"
|
||||
id="text1"
|
||||
fill="currentColor"
|
||||
aria-label="R" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M11 17h2v-6h-2zm1.713-8.287Q13 8.425 13 8t-.288-.712T12 7t-.712.288T11 8t.288.713T12 9t.713-.288M12 22q-2.075 0-3.9-.788t-3.175-2.137T2.788 15.9T2 12t.788-3.9t2.137-3.175T8.1 2.788T12 2t3.9.788t3.175 2.137T21.213 8.1T22 12t-.788 3.9t-2.137 3.175t-3.175 2.138T12 22"/></svg>
|
||||
|
After Width: | Height: | Size: 501 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Design Icons by Pictogrammers - https://github.com/Templarian/MaterialDesign/blob/master/LICENSE --><path fill="currentColor" d="M12 4V2A10 10 0 0 0 2 12h2a8 8 0 0 1 8-8"/></svg>
|
||||
|
After Width: | Height: | Size: 286 B |
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
|
||||
<path fill="currentColor" d="M12 19q1.65 0 2.825-1.175T16 15v-4q0-1.65-1.175-2.825T12 7T9.175 8.175T8 11v4q0 1.65 1.175 2.825T12 19m-2-3h4v-2h-4zm0-4h4v-2h-4zm2 9q-1.625 0-3.012-.8T6.8 18H4v-2h2.1q-.075-.5-.088-1T6 14H4v-2h2q0-.5.012-1t.088-1H4V8h2.8q.35-.575.788-1.075T8.6 6.05L7 4.4L8.4 3l2.15 2.15q.7-.225 1.425-.225t1.425.225L15.6 3L17 4.4l-1.65 1.65q.575.375 1.038.862T17.2 8H20v2h-2.1q.075.5.088 1T18 12h2v2h-2q0 .5-.013 1t-.087 1H20v2h-2.8q-.8 1.4-2.187 2.2T12 21" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 682 B |
|
After Width: | Height: | Size: 22 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zM17 6H7v13h10zM9 17h2V8H9zm4 0h2V8h-2zM7 6v13z"/></svg>
|
||||
|
After Width: | Height: | Size: 360 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Google Material Icons by Material Design Authors - https://github.com/material-icons/material-icons/blob/master/LICENSE --><path fill="currentColor" d="M20 12c0-2.54-1.19-4.81-3.04-6.27L16 0H8l-.95 5.73C5.19 7.19 4 9.45 4 12s1.19 4.81 3.05 6.27L8 24h8l.96-5.73A7.98 7.98 0 0 0 20 12M6 12c0-3.31 2.69-6 6-6s6 2.69 6 6s-2.69 6-6 6s-6-2.69-6-6"/></svg>
|
||||
|
After Width: | Height: | Size: 448 B |
|
After Width: | Height: | Size: 22 KiB |
|
|
@ -1,110 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="30"
|
||||
height="30"
|
||||
viewBox="0 0 7.9375004 7.9375004"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="dashboard_logo.svg"
|
||||
inkscape:export-filename="dashboard_logo.png"
|
||||
inkscape:export-xdpi="409.60001"
|
||||
inkscape:export-ydpi="409.60001"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="11.8125"
|
||||
inkscape:cy="16.78125"
|
||||
inkscape:window-width="1836"
|
||||
inkscape:window-height="1185"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
showguides="false">
|
||||
<inkscape:grid
|
||||
id="grid2"
|
||||
units="mm"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingx="0.26458333"
|
||||
spacingy="0.26458333"
|
||||
empcolor="#0099e5"
|
||||
empopacity="0.30196078"
|
||||
color="#0099e5"
|
||||
opacity="0.14901961"
|
||||
empspacing="5"
|
||||
enabled="true"
|
||||
visible="true" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1">
|
||||
<linearGradient
|
||||
id="linearGradient1"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#ad70ff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1" />
|
||||
<stop
|
||||
style="stop-color:#00ffff;stop-opacity:1;"
|
||||
offset="0.99844205"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient2"
|
||||
x1="0"
|
||||
y1="8.4666653"
|
||||
x2="8.4664993"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="scale(0.93751843,0.93750002)" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="back"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="font-variation-settings:'wght' 700;fill:url(#linearGradient2);stroke-width:0.468754;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1"
|
||||
width="7.9380002"
|
||||
height="7.9375"
|
||||
x="0"
|
||||
y="0"
|
||||
rx="1.5874999"
|
||||
ry="1.5874999" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.05833;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1.5874998,3.7041664 v 1.3229167 h 1.3229166 v 1.3229165 l 1.3229165,-1e-7"
|
||||
id="path3"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.05833;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 1.5874998,2.6458332 V 1.5875 c 3.1749997,-2e-7 4.7624995,1.5874997 4.7624995,4.7624995 H 5.2916661"
|
||||
id="path4"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="front"
|
||||
style="stroke-width:2.11667;stroke-dasharray:none" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Design Icons by Pictogrammers - https://github.com/Templarian/MaterialDesign/blob/master/LICENSE --><path fill="currentColor" d="M1.5 4v1.5c0 4.15 2.21 7.78 5.5 9.8V20h15v-2c0-2.66-5.33-4-8-4h-.25C9 14 5 10 5 5.5V4m9 0a4 4 0 0 0-4 4a4 4 0 0 0 4 4a4 4 0 0 0 4-4a4 4 0 0 0-4-4"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<theme>
|
||||
<var key="side_size" value="48" />
|
||||
<var key="top_size" value="40" />
|
||||
<var key="side_sprite_size" value="26" />
|
||||
<var key="side_button_size" value="48" />
|
||||
</theme>
|
||||
|
|
@ -25,13 +26,6 @@
|
|||
</template>
|
||||
|
||||
<elements>
|
||||
<div position="absolute" width="100%" justify_content="space_between">
|
||||
<div />
|
||||
<div padding="6">
|
||||
<Button id="btn_close" sprite_src_builtin="dashboard/close.svg" color="#000000" border="2" border_color="~color_faded" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- left/right separator (menu and rest) -->
|
||||
<div flex_direction="row" gap="8" width="100%" height="100%" padding="4" interactable="0">
|
||||
<!-- LEFT MENU -->
|
||||
|
|
@ -55,21 +49,34 @@
|
|||
<SideButton id="btn_side_apps" src_builtin="dashboard/apps.svg" tooltip="APPLICATIONS" tooltip_side="right" />
|
||||
<SideButton id="btn_side_games" src_builtin="dashboard/games.svg" tooltip="GAMES" tooltip_side="right" />
|
||||
<SideButton id="btn_side_monado" src_builtin="dashboard/monado.svg" tooltip="MONADO_RUNTIME" tooltip_side="right" />
|
||||
<!-- SideButton id="btn_side_processes" src_builtin="dashboard/window.svg" tooltip="PROCESSES" tooltip_side="right" /-->
|
||||
<rectangle height="2" color="#FFFFFF33" width="~side_sprite_size" />
|
||||
<SideButton id="btn_side_settings" src_builtin="dashboard/settings.svg" tooltip="SETTINGS" tooltip_side="right" />
|
||||
</rectangle>
|
||||
</div>
|
||||
<!-- REST -->
|
||||
<!-- content/bottom panel separator -->
|
||||
<!-- top/content/bottom panel separator -->
|
||||
<div
|
||||
flex_direction="column"
|
||||
gap="8"
|
||||
width="100%"
|
||||
height="100%"
|
||||
overflow_x="scroll">
|
||||
<!-- CONTENT -->
|
||||
<!-- TOP PANEL -->
|
||||
<div position="relative" width="100%" height="~top_size" min_height="~top_size" max_height="~top_size" justify_content="end">
|
||||
<!-- Title bar -->
|
||||
<div width="100%" align_items="center" justify_content="center">
|
||||
<rectangle min_width="300" height="100%" consume_mouse_events="1" round="100%" color="~color_top_panel" align_items="center" justify_content="center" gap="8">
|
||||
<sprite id="sprite_titlebar_icon" width="24" height="24" />
|
||||
<label id="label_titlebar_title" weight="bold" size="16" text="Title" />
|
||||
</rectangle>
|
||||
</div>
|
||||
<!-- Close button -->
|
||||
<Button position="absolute" id="btn_close" color="~color_top_panel" round="100%" width="~top_size" height="~top_size" tooltip="CLOSE_WINDOW" tooltip_side="left">
|
||||
<sprite src_builtin="dashboard/close.svg" width="32" height="32" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<!-- color and color2 alpha will be modified at runtime -->
|
||||
<rectangle
|
||||
id="rect_content"
|
||||
|
|
@ -79,29 +86,26 @@
|
|||
round="8"
|
||||
flex_grow="1"
|
||||
width="100%"
|
||||
overflow_y="scroll"
|
||||
overflow="scroll"
|
||||
position="relative"
|
||||
>
|
||||
<!-- radial gradient -->
|
||||
<rectangle
|
||||
position="absolute" width="100%" height="100%"
|
||||
gradient="radial" color="#44BBFF11" color2="#00000000" />
|
||||
|
||||
<div overflow_x="scroll" overflow_y="scroll" width="100%" height="100%">
|
||||
<div
|
||||
id="content"
|
||||
flex_direction="column"
|
||||
overflow_x="scroll"
|
||||
overflow_y="scroll"
|
||||
padding_top="8"
|
||||
padding_bottom="8"
|
||||
padding_left="16"
|
||||
padding_right="16"
|
||||
gap="8"
|
||||
width="100%"
|
||||
min_height="100%"
|
||||
height="100%"
|
||||
>
|
||||
<!-- padding set at runtime -->
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div position="absolute" id="popup_manager" width="100%" height="100%" />
|
||||
</rectangle>
|
||||
<!-- BOTTOM PANEL -->
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@
|
|||
border_color="#FFFFFF66"
|
||||
justify_content="space_between" />
|
||||
|
||||
<!-- id, text, translation, tooltip -->
|
||||
<!-- id, text, translation, tooltip, min_width -->
|
||||
<template name="DropdownButton">
|
||||
<label text="${text}" translation="${translation}" />
|
||||
<Button id="${id}" height="32" tooltip="${tooltip}" >
|
||||
<div padding_left="8" padding_right="8" min_width="200">
|
||||
<div padding_left="8" padding_right="8" min_width="${min_width}">
|
||||
<label id="${id}_value" weight="bold" />
|
||||
</div>
|
||||
<div gap="2">
|
||||
<div padding_top="4" padding_bottom="4">
|
||||
<rectangle width="2" height="100%" color="#FFFFFF66" />
|
||||
<rectangle width="2" height="100%" color="#FFFFFF1A" />
|
||||
</div>
|
||||
<sprite margin_left="-4" width="30" height="30" color="~color_text" src_builtin="dashboard/down.svg" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
gap="8"
|
||||
round="8" />
|
||||
|
||||
<!-- src, text, translation -->
|
||||
<!-- src_builtin, text, translation -->
|
||||
<template name="GroupBoxTitle">
|
||||
<div flex_direction="row" align_items="center" gap="8">
|
||||
<sprite src="${src}" src_builtin="${src_builtin}" width="24" height="24" />
|
||||
<sprite src_builtin="${src_builtin}" width="24" height="24" />
|
||||
<label text="${text}" translation="${translation}" weight="bold" size="18" />
|
||||
</div>
|
||||
<rectangle color="#FFFFFF44" width="100%" height="2" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
<layout>
|
||||
<template name="LoadingWithText">
|
||||
<div id="root" width="100%" height="100%" align_items="center" justify_content="center">
|
||||
<div flex_direction="row" gap="8" align_items="center" >
|
||||
<sprite id="sprite_loading" src_builtin="dashboard/loading.svg" width="32" height="32"/>
|
||||
<label translation="LOADING" weight="bold"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="LoadingWithoutText">
|
||||
<div id="root" width="100%" height="100%" align_items="center" justify_content="center">
|
||||
<sprite id="sprite_loading" src_builtin="dashboard/loading.svg" width="32" height="32"/>
|
||||
</div>
|
||||
</template>
|
||||
</layout>
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
<layout>
|
||||
<include src="theme.xml" />
|
||||
|
||||
<macro name="home_button" round="8" color="#00000033" border_color="#FFFFFF77" hover_color="~color_accent" hover_border_color="#FFFFFF" />
|
||||
|
||||
<template name="MenuButton">
|
||||
<Button
|
||||
id="${id}"
|
||||
width="120"
|
||||
height="82"
|
||||
color="#00000033"
|
||||
border_color="#FFFFFF77"
|
||||
hover_color="~color_accent"
|
||||
hover_border_color="#FFFFFF"
|
||||
round="8">
|
||||
macro="home_button">
|
||||
<div gap="8"
|
||||
align_items="center"
|
||||
justify_content="center"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
<include src="../theme.xml" />
|
||||
|
||||
<template name="AppEntry">
|
||||
|
|
@ -25,7 +24,6 @@
|
|||
</template>
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="APPLICATIONS" icon="dashboard/apps.svg" />
|
||||
<!-- placeholders for now -->
|
||||
<!--
|
||||
<div gap="4" align_items="center">
|
||||
|
|
@ -46,7 +44,6 @@
|
|||
flex_direction="row"
|
||||
flex_wrap="wrap"
|
||||
gap="4"
|
||||
overflow_y="scroll"
|
||||
/>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="GAMES" icon="dashboard/games.svg" />
|
||||
<div id="game_list_parent" align_items="center" />
|
||||
<div id="running_games_list_parent" align_self="center" />
|
||||
<div id="game_list_parent" align_items="center" flex_direction="column" gap="8" />
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
align_items="center"
|
||||
flex_grow="1"
|
||||
gap="24">
|
||||
<sprite src_builtin="dashboard/wayvr_dashboard.svg" width="96" height="96" />
|
||||
<sprite src_builtin="dashboard/wayvr_dashboard.png" width="96" height="96" />
|
||||
<label id="label_hello" size="32" weight="bold" />
|
||||
|
||||
<!-- main button list -->
|
||||
|
|
@ -16,9 +16,12 @@
|
|||
<MenuButton id="btn_apps" icon="dashboard/apps.svg" translation="APPLICATIONS" />
|
||||
<MenuButton id="btn_games" icon="dashboard/games.svg" translation="GAMES" />
|
||||
<MenuButton id="btn_monado" icon="dashboard/monado.svg" text="Monado" />
|
||||
<!--MenuButton id="btn_processes" icon="dashboard/window.svg" translation="PROCESSES" /-->
|
||||
<MenuButton id="btn_settings" icon="dashboard/settings.svg" translation="SETTINGS" />
|
||||
</div>
|
||||
|
||||
<Button id="btn_welcome_screen" macro="home_button" tooltip="APP_SETTINGS.SHOW_WELCOME_SCREEN">
|
||||
<sprite src_builtin="dashboard/welcome.svg" width="32" height="32" margin="16"/>
|
||||
</Button>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
|
|||
|
|
@ -1,40 +1,14 @@
|
|||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
|
||||
<!-- key: str, value: str -->
|
||||
<template name="BoolFlag">
|
||||
<div flex_direction="row" gap="4">
|
||||
<label text="${key}" />
|
||||
<label weight="bold" text="${value}" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- name, checked, flag_* -->
|
||||
<template name="Cell">
|
||||
<rectangle macro="group_box">
|
||||
<CheckBox id="checkbox" text="${name}" checked="${checked}" />
|
||||
<div flex_direction="row" gap="8">
|
||||
<BoolFlag key="Active:" value="${flag_active}" />
|
||||
<BoolFlag key="Focused:" value="${flag_focused}" />
|
||||
<BoolFlag key="IO active:" value="${flag_io_active}" />
|
||||
<BoolFlag key="Overlay:" value="${flag_overlay}" />
|
||||
<BoolFlag key="Primary:" value="${flag_primary}" />
|
||||
<BoolFlag key="Visible:" value="${flag_visible}" />
|
||||
</div>
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="MONADO_RUNTIME" icon="dashboard/monado.svg" />
|
||||
<label translation="DISPLAY_BRIGHTNESS" />
|
||||
<Slider id="slider_brightness" width="300" height="24" min_value="0" max_value="140" />
|
||||
|
||||
<label translation="LIST_OF_PROCESSES" />
|
||||
<div id="list_parent" flex_direction="column" gap="8">
|
||||
<!-- filled at runtime -->
|
||||
<div gap="4">
|
||||
<Tabs id="tabs">
|
||||
<Tab name="general_settings" translation="GENERAL_SETTINGS" sprite_src_builtin="dashboard/settings.svg" />
|
||||
<Tab name="process_list" translation="PROCESS_LIST" sprite_src_builtin="dashboard/cpu.svg" />
|
||||
<Tab name="debug_timings" translation="DEBUG_INFO" sprite_src_builtin="dashboard/not_a_bug.svg" />
|
||||
</Tabs>
|
||||
<div gap="4" id="content" width="100%">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<!-- name, limit_min, limit_max -->
|
||||
<template name="DebugGraph">
|
||||
<rectangle flex_direction="column" align_items="center" gap="8" border="2" color="#ffffff11" color2="#ffffff22" gradient="vertical" border_color="#ffffff33" round="4" padding="4">
|
||||
<label text="${name}" size="9" weight="bold" />
|
||||
<BarGraph id="graph" width="180" height="70" unit="ms" limit_min="${limit_min}" limit_max="${limit_max}" capacity="50" />
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<!-- text -->
|
||||
<template name="SessionButton">
|
||||
<Button id="button" text="${text}" />
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/apps.svg" text="Sessions" />
|
||||
<div id="session_list_parent" flex_wrap="wrap" flex_direction="row" gap="8" />
|
||||
<GroupBoxTitle src_builtin="dashboard/not_a_bug.svg" text="Debug timings" />
|
||||
<div id="timings_parent" flex_wrap="wrap" flex_direction="row" gap="8">
|
||||
<label text="Please select which session you want to monitor" />
|
||||
</div>
|
||||
</rectangle>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<macro name="slider" width="100%" height="24"/>
|
||||
|
||||
<theme>
|
||||
<var key="s_width" value="500"/>
|
||||
</theme>
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" gap="8">
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/settings.svg" translation="GENERAL_SETTINGS" />
|
||||
|
||||
<label translation="DISPLAY_BRIGHTNESS" />
|
||||
<Slider id="slider_brightness" width="300" height="24" min_value="0" max_value="140" />
|
||||
</rectangle>
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/settings.svg" translation="APP_SETTINGS.COLOR_KEYING" />
|
||||
<div gap="8" width="~s_width">
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Color"/>
|
||||
<ColorSelector id="cs_keying" height="24" width="100%"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Despill"/>
|
||||
<Slider id="slider_keying_despill" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Curve (0 = disabled)"/>
|
||||
<Slider id="slider_keying_curve" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div gap="8" width="~s_width">
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Hue range"/>
|
||||
<Slider id="slider_keying_hue_range" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Saturation range"/>
|
||||
<Slider id="slider_keying_saturation_range" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Value range"/>
|
||||
<Slider id="slider_keying_value_range" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
</div>
|
||||
</rectangle>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<!-- key: str, value: str -->
|
||||
<template name="BoolFlag">
|
||||
<div flex_direction="row" gap="4">
|
||||
<label text="${key}" />
|
||||
<label weight="bold" text="${value}" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- name, checked, flag_* -->
|
||||
<template name="Cell">
|
||||
<rectangle macro="group_box">
|
||||
<CheckBox id="checkbox" text="${name}" checked="${checked}" />
|
||||
<div flex_direction="row" gap="8" flex_wrap="wrap">
|
||||
<BoolFlag key="Active:" value="${flag_active}" />
|
||||
<BoolFlag key="Focused:" value="${flag_focused}" />
|
||||
<BoolFlag key="IO active:" value="${flag_io_active}" />
|
||||
<BoolFlag key="Overlay:" value="${flag_overlay}" />
|
||||
<BoolFlag key="Primary:" value="${flag_primary}" />
|
||||
<BoolFlag key="Visible:" value="${flag_visible}" />
|
||||
</div>
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/cpu.svg" translation="PROCESS_LIST" />
|
||||
<div id="list_parent" flex_direction="column" gap="8">
|
||||
<!-- filled at runtime -->
|
||||
</div>
|
||||
</rectangle>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="LIST_OF_WINDOWS" icon="dashboard/window.svg" />
|
||||
<div id="window_list_parent" />
|
||||
<TabTitle translation="LIST_OF_PROCESSES" icon="dashboard/cpu.svg" />
|
||||
<div id="process_list_parent" />
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
<include src="../t_group_box.xml" />
|
||||
<include src="../t_dropdown_button.xml" />
|
||||
|
||||
|
|
@ -14,8 +13,13 @@
|
|||
</template>
|
||||
|
||||
<template name="SliderSetting">
|
||||
<label text="${text}" translation="${translation}" />
|
||||
<Slider id="${id}" width="250" height="24" min_value="${min}" max_value="${max}" step="${step}" value="${value}" tooltip="${tooltip}" />
|
||||
<Slider id="${id}" width="200" height="24" min_value="${min}" max_value="${max}" step="${step}" value="${value}" tooltip="${tooltip}" />
|
||||
<label text="${text}" weight="bold" translation="${translation}" />
|
||||
</template>
|
||||
|
||||
<template name="RangeSetting">
|
||||
<Slider id="${id}" width="200" height="24" min_value="${min}" max_value="${max}" step="${step}" value="${value}" value2="${value2}" tooltip="${tooltip}" />
|
||||
<label text="${text}" weight="bold" translation="${translation}" />
|
||||
</template>
|
||||
|
||||
<template name="SelectSetting">
|
||||
|
|
@ -27,8 +31,15 @@
|
|||
<RadioBox text="${text}" translation="${translation}" value="${value}" tooltip="${tooltip}" />
|
||||
</template>
|
||||
|
||||
<template name="ButtonText">
|
||||
<Button id="${id}" height="32" tooltip="${translation}_HELP" padding="4" gap="8">
|
||||
<sprite src_builtin="${icon}" height="24" width="24" />
|
||||
<label align="left" translation="${translation}" weight="bold" min_width="200" />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<template name="DangerButton">
|
||||
<Button id="${id}" color="#AA3333" height="32" tooltip="${translation}_HELP" padding="4" gap="8" >
|
||||
<Button id="${id}" color="#AA3333" height="32" tooltip="${translation}_HELP" padding="4" gap="8">
|
||||
<sprite src_builtin="${icon}" height="24" width="24" />
|
||||
<label align="left" translation="${translation}" weight="bold" min_width="200" />
|
||||
</Button>
|
||||
|
|
@ -36,17 +47,30 @@
|
|||
|
||||
<template name="AutostartApp">
|
||||
<div id="${id}_root" flex_direction="row">
|
||||
<Button id="${id}" color="#AA3333" height="24" padding="4" margin_top="-2" margin_bottom="-2" >
|
||||
<Button id="${id}" color="#AA3333" height="24" padding="4" margin_top="-2" margin_bottom="-2">
|
||||
<sprite src_builtin="dashboard/close.svg" height="20" width="20" />
|
||||
</Button>
|
||||
<div padding_left="8" >
|
||||
<label align="left" text="${text}" weight="bold" overflow="hidden"/>
|
||||
<div padding_left="8">
|
||||
<label align="left" text="${text}" weight="bold" overflow="hidden" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="SETTINGS" icon="dashboard/settings.svg" />
|
||||
<div flex_wrap="wrap" justify_content="stretch" gap="4" id="settings_root" />
|
||||
<div gap="4">
|
||||
<Tabs id="tabs">
|
||||
<Tab name="look_and_feel" translation="APP_SETTINGS.LOOK_AND_FEEL" sprite_src_builtin="dashboard/palette.svg" />
|
||||
<Tab name="skybox" translation="APP_SETTINGS.SKYBOX" sprite_src_builtin="dashboard/globe.svg" />
|
||||
<Tab name="features" translation="APP_SETTINGS.FEATURES" sprite_src_builtin="dashboard/options.svg" />
|
||||
<Tab name="controls" translation="APP_SETTINGS.CONTROLS" sprite_src_builtin="dashboard/controller.svg" />
|
||||
<Tab name="space_drag" translation="APP_SETTINGS.SPACE_DRAG" sprite_src_builtin="dashboard/drag.svg" />
|
||||
<Tab name="misc" translation="APP_SETTINGS.MISC" sprite_src_builtin="dashboard/blocks.svg" />
|
||||
<Tab name="autostart_apps" translation="APP_SETTINGS.AUTOSTART_APPS" sprite_src_builtin="dashboard/apps.svg" />
|
||||
<Tab name="troubleshooting" translation="APP_SETTINGS.TROUBLESHOOTING" sprite_src_builtin="dashboard/cpu.svg" />
|
||||
</Tabs>
|
||||
<div flex_wrap="wrap" justify_content="stretch" gap="4" id="settings_root" width="100%">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<elements>
|
||||
<div id="common_options_parent" flex_direction="column" gap="8"/>
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/gravity.svg" translation="APP_SETTINGS.SPACE_GRAVITY_GRAVITY" />
|
||||
<div id="gravity_enabled_parent"/>
|
||||
<div id="space_gravity_parent" flex_direction="column" gap="8">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
</rectangle>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<layout>
|
||||
<!-- translation, icon -->
|
||||
<template name="TabTitle">
|
||||
<div gap="8" align_items="center">
|
||||
<sprite src_builtin="${icon}" width="24" height="24" />
|
||||
<label translation="${translation}" size="18" weight="bold" />
|
||||
</div>
|
||||
</template>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<layout>
|
||||
<template name="Pip">
|
||||
<rectangle id="pip" width="8" height="8" round="100%" color="${COLOR}"/>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div position="relative" flex_grow="1">
|
||||
<!-- Content -->
|
||||
<div position="absolute" id="content" flex_direction="column" flex_grow="1" align_items="center" justify_content="center" gap="16" width="100%" height="100%">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
<!-- Page buttons -->
|
||||
<div position="absolute" align_self="end" justify_self="end" width="100%" flex_direction="column" align_items="center" margin_bottom="8">
|
||||
<div flex_direction="row" gap="8" align_items="center">
|
||||
<Button id="btn_prev" width="32" height="32" round="100%" sprite_src_builtin="dashboard/arrow_left.svg" />
|
||||
<div id="pips" gap="4" align_items="center">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
<Button id="btn_next" width="32" height="32" round="100%" sprite_src_builtin="dashboard/arrow_right.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<layout>
|
||||
<!-- icon, title -->
|
||||
<template name="PageTitle">
|
||||
<div position="absolute" align_self="start" justify_self="center" width="100%" margin_top="16" gap="8" align_items="center" justify_content="center">
|
||||
<sprite width="48" height="48" src_builtin="${icon}" color="#FFFFFF"/>
|
||||
<label size="28" weight="bold" text="${title}" shadow="#000000" shadow_x="3" shadow_y="3" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- text -->
|
||||
<template name="TextDesc">
|
||||
<label wrap="1" text="${text}" size="20" width="500" shadow="#000000" weight="bold"/>
|
||||
</template>
|
||||
|
||||
<template name="TextDescBig">
|
||||
<label text="${text}" size="24" shadow="#000000" weight="bold"/>
|
||||
</template>
|
||||
|
||||
<macro name="video_overlay_component" looping="1" width="100%" height="auto" max_height="100%" aspect_ratio="1.777777" position="relative"/>
|
||||
|
||||
<macro name="video_overlay_content" new_pass="1" position="absolute" width="100%" height="100%" padding_bottom="32"/>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<layout>
|
||||
<elements>
|
||||
<image src_builtin="dashboard/splash.png" min_width="431" min_height="128" />
|
||||
|
||||
<rectangle color="#FFFFFF11" width="100%" height="2"/>
|
||||
|
||||
<label weight="bold" size="32" text="Hi there!"/>
|
||||
<label weight="bold" size="20" text="Thank you for installing WayVR ❤️"/>
|
||||
|
||||
<label size="20" margin_top="16" text="Let us guide you through your first steps."/>
|
||||
<label size="20" text="Press "Next" button below to get started."/>
|
||||
|
||||
<div height="42"/> <!-- empty space -->
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<layout>
|
||||
<include src_builtin="welcome_common.xml"/>
|
||||
|
||||
<elements>
|
||||
<rectangle color="#103142" width="100%" height="100%" position="absolute"/>
|
||||
<Video macro="video_overlay_component" src_builtin="video/onboarding_watch.ivf" aspect_ratio="1.0">
|
||||
<div macro="video_overlay_content">
|
||||
<PageTitle icon="dashboard/watch.svg" title="Watch"/>
|
||||
<div position="relative" align_self="end" padding="16">
|
||||
<TextDesc text="Look at your left wrist. That's your watch."/>
|
||||
</div>
|
||||
</div>
|
||||
</Video>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<layout>
|
||||
<include src_builtin="welcome_common.xml"/>
|
||||
|
||||
<elements>
|
||||
<Video macro="video_overlay_component" src_builtin="video/onboarding_double_press.ivf">
|
||||
<div macro="video_overlay_content">
|
||||
<PageTitle icon="dashboard/panorama.svg" title="Working Set"/>
|
||||
<div position="relative" align_self="end" padding="16">
|
||||
<TextDesc text="Double-press B (on Index) or Y (on Meta) to toggle the visibility of your workspace. Try it now."/>
|
||||
</div>
|
||||
</div>
|
||||
</Video>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<layout>
|
||||
<include src_builtin="welcome_common.xml"/>
|
||||
|
||||
<elements>
|
||||
<Video macro="video_overlay_component" src_builtin="video/onboarding_laser_colors.ivf">
|
||||
<div macro="video_overlay_content">
|
||||
<PageTitle icon="dashboard/click.svg" title="Laser Colors"/>
|
||||
<div position="relative" flex_direction="row" gap="16" margin="16" align_self="end" justify_self="end" align_items="center">
|
||||
<rectangle flex_direction="column" gap="8" padding="8" round="4" border_color="~color_accent" border="2" >
|
||||
<label size="16" weight="bold" color="#00FFFF" text="— Regular Mode: Blue laser"/>
|
||||
<label size="16" weight="bold" color="#FFAA00" text="— Right-click Mode: Orange laser" />
|
||||
<label size="16" weight="bold" color="#FF88FF" text="— Middle-click Mode: Purple laser" />
|
||||
</rectangle>
|
||||
<label wrap="1" size="18" width="450" weight="bold" shadow="#000000" text="Much of the functionality in WayVR depends on what color of laser is used to interact with a UI element. You don't need to press these buttons, just touch them!"/>
|
||||
</div>
|
||||
</div>
|
||||
</Video>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<layout>
|
||||
<include src_builtin="welcome_common.xml"/>
|
||||
|
||||
<elements>
|
||||
<rectangle color="#0A2939" width="100%" height="100%" position="absolute"/>
|
||||
<Video macro="video_overlay_component" src_builtin="video/onboarding_center_marker.ivf" aspect_ratio="1.33333">
|
||||
<div macro="video_overlay_content">
|
||||
<PageTitle icon="dashboard/panorama.svg" title="Moving your set"/>
|
||||
<div position="relative" align_self="end" padding="16" flex_direction="column" gap="4">
|
||||
<label shadow="#000000" size="14" weight="bold" wrap="1" color="#aaffcc" text="— Grab it with one hand to move your set."/>
|
||||
<label shadow="#000000" size="14" weight="bold" wrap="1" color="#ccaaff" text="— Grab it with both hands if you want to move a specific overlay in your set."/>
|
||||
<div align_items="center" gap="8">
|
||||
<sprite src_builtin="dashboard/info.svg" width="24" height="24" color="#ffff00"/>
|
||||
<label shadow="#000000" size="16" weight="bold" wrap="1" color="#ffff00" text="Center marker determines the center or your set."/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Video>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<layout>
|
||||
<include src_builtin="welcome_common.xml"/>
|
||||
|
||||
<elements>
|
||||
<div flex_direction="row" align_items="center">
|
||||
<image src_builtin="dashboard/check_3d.png" width="256" height="256"/>
|
||||
<div flex_direction="column" gap="8" max_width="480">
|
||||
<TextDescBig text="You're all set!"/>
|
||||
<label size="16" wrap="1" text="These basics will allow you to start using WayVR with ease."/>
|
||||
<label size="16" wrap="1" text="There are many other features worth customizing. For more information, check the documentation at"/>
|
||||
<div flex_direction="row" align_items="center" gap="8">
|
||||
<sprite src_builtin="dashboard/globe.svg" width="24" height="24" color="~color_accent"/>
|
||||
<label size="20" weight="bold" text="wayvr.org" color="~color_accent"/>
|
||||
</div>
|
||||
<Button margin_top="16" sprite_src_builtin="dashboard/home.svg" id="btn_home_screen" text="Go back to Home screen" min_height="32" align_self="baseline"/>
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
<theme>
|
||||
<var key="color_menu_dark" value="#0A0A0ACC" />
|
||||
<var key="color_accent" value="#008cff" />
|
||||
<var key="color_top_panel" value="#00000099" />
|
||||
<var key="color_bottom_panel" value="#141e28" />
|
||||
</theme>
|
||||
</layout>
|
||||
|
|
@ -37,18 +37,18 @@
|
|||
<Separator />
|
||||
<label translation="APP_LAUNCHER.ASPECT_TITLE" />
|
||||
<RadioGroup id="radio_orientation" flex_direction="row" gap="16">
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.WIDE" value="Wide" tooltip="16:9" checked="1" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_WIDE" value="SemiWide" tooltip="3:2" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.SQUARE" value="Square" tooltip="1:1" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_TALL" value="SemiTall" tooltip="2:3" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.TALL" value="Tall" tooltip="9:16" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.WIDE" value="Wide" tooltip_str="16:9" checked="1" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_WIDE" value="SemiWide" tooltip_str="3:2" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.SQUARE" value="Square" tooltip_str="1:1" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.SEMI_TALL" value="SemiTall" tooltip_str="2:3" />
|
||||
<RadioBox translation="APP_LAUNCHER.ASPECT.TALL" value="Tall" tooltip_str="9:16" />
|
||||
</RadioGroup>
|
||||
<!-- Separator /> // saved settings override this, so let's hide it for now
|
||||
<label translation="APP_LAUNCHER.POS_TITLE" />
|
||||
<RadioGroup id="radio_pos" flex_direction="row" gap="16">
|
||||
<RadioBox translation="APP_LAUNCHER.POS.FLOATING" value="Floating" tooltip="APP_LAUNCHER.POS.FLOATING_HELP" />
|
||||
<RadioBox translation="APP_LAUNCHER.POS.ANCHORED" value="Anchored" tooltip="APP_LAUNCHER.POS.ANCHORED_HELP" checked="1" />
|
||||
<RadioBox translation="APP_LAUNCHER.POS.STATIC" value="Static" tooltip="APP_LAUNCHER.POS.STATIC_HELP" />
|
||||
<RadioBox translation="APP_LAUNCHER.POS.FLOATING" value="Floating" tooltip_str="APP_LAUNCHER.POS.FLOATING_HELP" />
|
||||
<RadioBox translation="APP_LAUNCHER.POS.ANCHORED" value="Anchored" tooltip_str="APP_LAUNCHER.POS.ANCHORED_HELP" checked="1" />
|
||||
<RadioBox translation="APP_LAUNCHER.POS.STATIC" value="Static" tooltip_str="APP_LAUNCHER.POS.STATIC_HELP" />
|
||||
</RadioGroup -->
|
||||
<Separator />
|
||||
<div flex_direction="row" justify_content="space_between" gap="16">
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
<include src_builtin="../t_group_box.xml" />
|
||||
|
||||
<!-- device_name, device_icon -->
|
||||
<template name="DeviceSlider">
|
||||
<rectangle macro="group_box">
|
||||
<div width="100%" align_items="center" justify_content="center" gap="8">
|
||||
<sprite src="${device_icon}" width="16" height="16" />
|
||||
<sprite src_builtin="${device_icon}" width="16" height="16" />
|
||||
<label text="${device_name}" margin_right="8" size="12" weight="bold" />
|
||||
</div>
|
||||
<div width="100%" align_items="center">
|
||||
<CheckBox id="checkbox" />
|
||||
<Button sprite_src="${volume_icon}" id="btn_mute" width="32" />
|
||||
<Button sprite_src_builtin="${volume_icon}" id="btn_mute" width="32" />
|
||||
<Slider id="slider" flex_grow="1" height="16" min_value="0" max_value="150" margin_left="8" />
|
||||
</div>
|
||||
</rectangle>
|
||||
|
|
@ -41,12 +41,13 @@
|
|||
flex_grow="1"
|
||||
id="${id}"
|
||||
translation="${translation}"
|
||||
sprite_src="${src}">
|
||||
sprite_src_builtin="${src}">
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div id="devices" flex_direction="column" gap="4">
|
||||
<div flex_direction="column" gap="4">
|
||||
<div id="devices" flex_direction="column" gap="4" max_height="400" overflow_y="scroll">
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -64,5 +65,6 @@
|
|||
<BottomButton id="btn_sources" src_builtin="dashboard/microphone.svg" translation="AUDIO.MICROPHONES" />
|
||||
<BottomButton id="btn_cards" src_builtin="dashboard/cpu.svg" translation="AUDIO.CARDS" />
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<!-- used at runtime [!!!] -->
|
||||
<include src="../t_dropdown_button.xml" />
|
||||
|
||||
<!-- id, min, max, step, value, value2, tooltip -->
|
||||
<template name="ThresholdSlider">
|
||||
<Slider id="${id}" width="200" height="24" min_value="${min}" max_value="${max}" step="${step}" value="${value}" value2="${value2}" tooltip="${tooltip}" />
|
||||
</template>
|
||||
|
||||
<!-- id, translation -->
|
||||
<template name="ActionRow">
|
||||
<rectangle macro="group_box" id="${id}">
|
||||
<!-- top row -->
|
||||
<div flex_direction="row" gap="8" align_items="center">
|
||||
<sprite src_builtin="dashboard/controller.svg" width="24" height="24"/>
|
||||
<label translation="${translation}" color="~color_accent" weight="bold" size="14" />
|
||||
</div>
|
||||
<!-- filled-in at runtime -->
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" gap="8" width="100%">
|
||||
<div flex_direction="column" gap="8" align_items="center" overflow_y="scroll" width="100%" padding="16">
|
||||
<div id="list_parent" flex_direction="column" gap="6" width="100%"></div>
|
||||
</div>
|
||||
<rectangle color="#000000cc" flex_direction="row" gap="8" justify_content="end" padding="8">
|
||||
<Button id="btn_cancel" sprite_src_builtin="dashboard/cancel.svg" min_width="100" height="32" translation="APP_SETTINGS.CANCEL" />
|
||||
<Button id="btn_save" sprite_src_builtin="dashboard/check.svg" min_width="100" height="32" translation="APP_SETTINGS.SAVE" />
|
||||
</rectangle>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<layout>
|
||||
<template name="DialogBoxButton">
|
||||
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="${icon}"/>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" align_items="center" justify_content="center" width="100%" gap="32">
|
||||
<label id="label_message" size="18" weight="bold"/>
|
||||
|
||||
<div id="buttons" gap="8">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<layout>
|
||||
<include src="../t_separator.xml"/>
|
||||
|
||||
<template name="btn_close">
|
||||
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="dashboard/check.svg"/>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div align_items="center" justify_content="center" width="100%">
|
||||
<div id="content" flex_direction="column" gap="8" width="100%">
|
||||
<label translation="DOWNLOADING_FILE" size="24" weight="bold"/>
|
||||
<Separator/>
|
||||
<label id="label_target_path" color="~color_text_translucent" />
|
||||
|
||||
<div gap="8" align_items="center">
|
||||
<div id="loading_parent"/>
|
||||
<label id="label_status"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" padding_top="8" padding_bottom="8">
|
||||
<div id="list_parent" gap="8" flex_direction="row" flex_wrap="wrap" justify_content="center" />
|
||||
</div>
|
||||
<div align_items="center" justify_content="center" gap="16">
|
||||
<Button id="btn_prev" sprite_src_builtin="dashboard/arrow_left.svg" width="32" height="32" />
|
||||
<label id="label_page" text="Page X" weight="bold" />
|
||||
<Button id="btn_next" sprite_src_builtin="dashboard/arrow_right.svg" width="32" height="32" />
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<layout>
|
||||
<!-- id, text -->
|
||||
<template name="InputProfileButton">
|
||||
<Button id="${id}" width="350" gap="8" justify_content="start" >
|
||||
<sprite margin_left="8" src_builtin="dashboard/controller.svg" min_width="24" min_height="24"/>
|
||||
<label text="${text}" weight="bold"/>
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" gap="8" width="100%" align_items="center">
|
||||
<div id="list_parent" flex_grow="1" flex_wrap="wrap" flex_direction="row" gap="4" width="100%" justify_content="center"></div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
width="100%"
|
||||
height="100%"
|
||||
flex_direction="column"
|
||||
position="absolute"
|
||||
>
|
||||
<!-- Top black bar -->
|
||||
<rectangle
|
||||
|
|
@ -32,13 +33,18 @@
|
|||
</div>
|
||||
</rectangle>
|
||||
|
||||
<!-- Content -->
|
||||
<rectangle height="100%"
|
||||
<rectangle
|
||||
width="100%"
|
||||
height="100%"
|
||||
color="#010310fe"
|
||||
color2="#051c55fc"
|
||||
gradient="vertical"
|
||||
padding="16"
|
||||
id="content">
|
||||
position="relative"
|
||||
>
|
||||
<div id="content" width="100%" height="100%" position="absolute" overflow_y="scroll">
|
||||
<!-- Padding set at runtime -->
|
||||
<!-- Content, filled-in at runtime -->
|
||||
</div>
|
||||
</rectangle>
|
||||
</div>
|
||||
</elements>
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<elements>
|
||||
<rectangle macro="group_box" flex_direction="row" align_items="center">
|
||||
<div id="list_parent" gap="8" flex_direction="column" flex_wrap="wrap" flex_grow="1" />
|
||||
</rectangle>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<layout>
|
||||
|
||||
<!--
|
||||
parameters:
|
||||
"text"
|
||||
"sprite"
|
||||
|
||||
ids:
|
||||
"button"
|
||||
-->
|
||||
<template name="ResolutionButton">
|
||||
<Button id="button" sprite_src_builtin="${sprite}" text="${text}"/>
|
||||
</template>
|
||||
|
||||
<include src="../t_separator.xml"/>
|
||||
|
||||
<elements>
|
||||
<div gap="8" flex_direction="column" min_width="100%" overflow_y="scroll">
|
||||
<div gap="8" flex_direction="column" align_items="center">
|
||||
<div id="resolution_buttons" gap="8" flex_direction="row">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
<image id="image" width="400" height="200" round="8" border="2" border_color="~color_accent"/>
|
||||
<label id="label_author" weight="bold"/>
|
||||
<label id="label_description" wrap="1"/>
|
||||
<Separator/>
|
||||
<!-- nerdy stuff below -->
|
||||
<div gap="24" justify_content="center">
|
||||
<label size="10" id="label_creation_date"/>
|
||||
<label size="10" id="label_modification_date"/>
|
||||
<label size="10" id="label_version"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<layout>
|
||||
<elements>
|
||||
<div id="list" gap="8" flex_wrap="wrap" align_self="baseline">
|
||||
<!-- filled-in at runtime -->
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<template name="RunningGameCell">
|
||||
<rectangle macro="group_box" flex_direction="row">
|
||||
<Button id="btn_stop" sprite_src_builtin="dashboard/remove_circle.svg" tooltip="PROCESS.STOP" />
|
||||
<Button id="btn_kill" sprite_src_builtin="dashboard/knife.svg" tooltip="PROCESS.FORCE_KILL" />
|
||||
<label id="label_name" weight="bold" />
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div align_items="center" gap="8">
|
||||
<Button id="btn_refresh" tooltip="REFRESH" width="32" height="32" sprite_src_builtin="dashboard/refresh.svg" />
|
||||
<sprite src_builtin="dashboard/cpu.svg" width="24" height="24" />
|
||||
<label translation="GAME_LIST.RUNNING_GAMES_LIST" />
|
||||
</div>
|
||||
<div id="list_parent" gap="8" />
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<layout>
|
||||
<elements>
|
||||
<div flex_direction="column" gap="8" width="100%" align_items="center">
|
||||
<div flex_direction="row" gap="4" align_self="end">
|
||||
<Button id="btn_refresh" tooltip="RELOAD_FROM_DISK" width="32" height="32" sprite_src_builtin="dashboard/refresh.svg" />
|
||||
<Button id="btn_download_skymaps" height="32" translation="APP_SETTINGS.BROWSE_ONLINE_CATALOG" sprite_src_builtin="dashboard/download.svg"/>
|
||||
</div>
|
||||
<div id="list_parent" gap="8" flex_direction="row" flex_wrap="wrap" />
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<layout>
|
||||
|
||||
<!--
|
||||
ids:
|
||||
"button"
|
||||
"image_preview"
|
||||
"label_title"
|
||||
"label_desc"
|
||||
-->
|
||||
<template name="Cell">
|
||||
<Button
|
||||
id="button"
|
||||
padding="8"
|
||||
round="8"
|
||||
flex_direction="column"
|
||||
gap="4"
|
||||
width="256"
|
||||
align_items="center"
|
||||
align_self="start">
|
||||
<image id="image_preview" width="100%" height="128" round="6">
|
||||
<!-- new_pass is required, because we need to render rectangles at the top of the image. Sorry. -->
|
||||
<div new_pass="1" id="resolution_pips" gap="4" margin="6"/>
|
||||
</image>
|
||||
<label id="label_title" wrap="1" weight="bold"/>
|
||||
<label id="label_author" wrap="1"/>
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
|
||||
params:
|
||||
"color"
|
||||
"text"
|
||||
-->
|
||||
<template name="ResolutionPip">
|
||||
<rectangle color="${color}" padding_left="4" padding_right="4" padding_top="2" padding_bottom="2" round="3" align_self="start">
|
||||
<label text="${text}" weight="bold" size="12" shadow="#000000" shadow_x="2" shadow_y="2"/>
|
||||
</rectangle>
|
||||
</template>
|
||||
</layout>
|
||||
|
|
@ -4,14 +4,12 @@
|
|||
"APPLICATIONS": "Anwendungen",
|
||||
"GAMES": "Spiele",
|
||||
"SETTINGS": "Einstellungen",
|
||||
"PROCESSES": "Prozesse",
|
||||
"HELLO_USER": "Hallo, {USER}!",
|
||||
"GENERAL_SETTINGS": "Allgemeine Einstellungen",
|
||||
"APPLICATION_LAUNCHER": "Anwendung Launcher",
|
||||
"APP_SETTINGS": {
|
||||
"HIDE_USERNAME": "Benutzernamen ausblenden",
|
||||
"OPAQUE_BACKGROUND": "Undurchsichtiger Hintergrund",
|
||||
"WLX": {},
|
||||
"LOOK_AND_FEEL": "Aussehen und Verhalten",
|
||||
"HIDE_GRAB_HELP": "Greif-Hilfe ausblenden",
|
||||
"ANIMATION_SPEED": "UI-Animationsgeschwindigkeit",
|
||||
|
|
@ -37,8 +35,6 @@
|
|||
"SCROLL_SPEED": "Scrollgeschwindigkeit",
|
||||
"LONG_PRESS_DURATION": "Dauer für lange Drückvorgänge",
|
||||
"POINTER_LERP_FACTOR": "Zeigerglättung",
|
||||
"XR_CLICK_SENSITIVITY": "XR-Klicksensitivität",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE": "XR-Loslassempfindlichkeit",
|
||||
"CLICK_FREEZE_TIME_MS": "Klick-Freeze-Zeit (ms)",
|
||||
"MISC": "Verschiedenes",
|
||||
"XWAYLAND_BY_DEFAULT": "Standardmäßig Apps im Kompatibilitätsmodus ausführen",
|
||||
|
|
@ -47,8 +43,6 @@
|
|||
"SCREEN_RENDER_DOWN": "Bildschirm bei niedrigerer Auflösung rendern",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Behebt hochstehende Bildschirme auf einigen Desktops",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Aktivieren Sie dies, wenn Sie 2 Cursor sehen",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Analoge Trigger-Empfindlichkeit",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Muss niedriger als Klick sein",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "Hilft bei der Präzision von Doppelklicks",
|
||||
"LEFT_HANDED_MOUSE_HELP": "Verwenden Sie diese Option, wenn die Maustasten vertauscht sind",
|
||||
"BLOCK_GAME_INPUT_HELP": "Blockiert alle Eingaben, wenn ein Overlay angefahren wird",
|
||||
|
|
@ -76,9 +70,113 @@
|
|||
"PIPEWIRE_HELP": "Schnelle GPU-Erfassung,\nStandard auf allen Desktops.",
|
||||
"PW_FALLBACK_HELP": "Langsame Methode mit hoher CPU-Auslastung.\nVersuchen Sie es, falls PipeWire GPU nicht funktioniert.",
|
||||
"SCREENCOPY_GPU_HELP": "Schnell, keine Bildschirmfreigabe-Popups.\nFunktioniert mit: Hyprland, Niri, River, Sway",
|
||||
"SCREENCOPY_HELP": "Langsam, keine Bildschirmfreigabe-Popups.\nFunktioniert mit: Hyprland, Niri, River, Sway"
|
||||
"SCREENCOPY_HELP": "Langsam, keine Bildschirmfreigabe-Popups.\nFunktioniert mit: Hyprland, Niri, River, Sway",
|
||||
"NONE": "Keine",
|
||||
"HMD_PINCH": "HMD + Kneifen",
|
||||
"EYE_PINCH": "Auge + Kneifen",
|
||||
"EYE_ONLY": "Nur Auge",
|
||||
"HMD_ONLY": "Nur HMD",
|
||||
"NONE_INPUT_HELP": "Maus und Tastatur nicht emulieren.\nEs wird nicht möglich sein, mit Displays zu interagieren.",
|
||||
"UINPUT": "Gerätesimulation",
|
||||
"UINPUT_HELP": "Verwendet das uinput-Modul, um ein Gerät zu emulieren.\nIhr Benutzer muss in der Gruppe „input“ sein.\nBekannt dafür, auf den meisten Desktops gut zu funktionieren.",
|
||||
"WL_VIRTUAL": "Wayland-virtueller Input",
|
||||
"WL_VIRTUAL_HELP": "Sendet Ereignisse an den Wayland-Compositor unter Verwendung von\nzwlr_virtual_pointer und zwp_virtual_keyboard.\nFunktioniert nur zuverlässig auf einigen Desktops.\nFunktioniert NICHT auf KDE, GNOME oder COSMIC."
|
||||
},
|
||||
"AUTOSTART_APPS": "Anwendungen, die beim Start ausgeführt werden sollen"
|
||||
"AUTOSTART_APPS": "Anwendungen, die beim Start ausgeführt werden sollen",
|
||||
"HANDSFREE_POINTER": "Freihändige Modus",
|
||||
"HANDSFREE_POINTER_HELP": "Eingabe, die bei Bewegung\nder Controller verwendet wird, wenn diese nicht verfügbar sind.\nLinkes Kneifen greift, rechtes klickt.",
|
||||
"UI_GRADIENT_INTENSITY": "UI-Verlaufsintensität",
|
||||
"RESET_PLAYSPACE": "Spielbereich zurücksetzen",
|
||||
"RESET_PLAYSPACE_HELP": "Den Abstand des Spielbereichs zurücksetzen.",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Posen beim Interagieren mit der Tastatur blockieren",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Verhindert, dass das Spiel Posen empfängt, wenn die Tastatur angefahren wird und „Spieleingabe blockieren“ aktiviert ist",
|
||||
"LANGUAGE": "Sprache",
|
||||
"REQUIRES_RESTART": "Erfordert Neustart",
|
||||
"GRID_OPACITY": "Bodenraster-Undurchsichtigkeit",
|
||||
"GRID_OPACITY_HELP": "Undurchsichtigkeit des Bodenrasters, wenn der Skybox aktiviert ist",
|
||||
"BROWSE_ONLINE_CATALOG": "Online-Katalog durchsuchen...",
|
||||
"BROWSE_SKYMAPS": "Skymaps durchsuchen",
|
||||
"COLOR_KEYING": "Farbschlüsselung",
|
||||
"NO_SKYMAPS_FOUND": "Keine Skymaps gefunden",
|
||||
"SELECT_VARIANT": "Variante auswählen",
|
||||
"SHOW_WELCOME_SCREEN": "Begrüßungsbildschirm anzeigen",
|
||||
"SKYBOX": "Skybox",
|
||||
"SKYMAP_ALREADY_DOWNLOADED": "Diese Skymap wurde bereits heruntergeladen. Wählen Sie die gewünschte Aktion aus.",
|
||||
"WATCH_VIEW_ANGLE": "Betrachtungswinkel der Watch",
|
||||
"WATCH_VIEW_ANGLE_HELP": "Steuerung, wie die Watch ausgeblendet wird",
|
||||
"BINDINGS": {
|
||||
"COMP": {
|
||||
"CLICK": "Klicken",
|
||||
"FORCE": "Kraft",
|
||||
"TOUCH": "Berührung",
|
||||
"VALUE": "Wert",
|
||||
"PROXIMITY": "Nähe",
|
||||
"X_AXIS": "X-Achse",
|
||||
"Y_AXIS": "Y-Achse"
|
||||
},
|
||||
"TYPE": {
|
||||
"BUMPER": "Bumper",
|
||||
"DPAD_UP": "D-Pad oben",
|
||||
"DPAD_DOWN": "D-Pad Runter",
|
||||
"DPAD_LEFT": "D-Pad Links",
|
||||
"DPAD_RIGHT": "D-Pad Rechts",
|
||||
"JOYSTICK": "Joystick",
|
||||
"MENU": "Menü",
|
||||
"SHOULDER": "Schulter",
|
||||
"SQUEEZE": "Greifen",
|
||||
"SYSTEM": "System",
|
||||
"THUMBREST": "Daumenuflage",
|
||||
"THUMBSTICK": "Thumbstick",
|
||||
"TRACKPAD": "Trackpad",
|
||||
"TRIGGER": "Trigger",
|
||||
"VIEW": "Ansehen"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "Beliebig",
|
||||
"DOUBLE": "Doppeltippen",
|
||||
"TRIPLE": "Dreifach-Tippen",
|
||||
"TYPE": "Anzahl der Taps"
|
||||
},
|
||||
"ACTION": {
|
||||
"CLICK": "Klick*",
|
||||
"GRAB": "Greifen*",
|
||||
"ALT_CLICK": "Benutzerdefiniertes Shell-Exec (alt_click in Konfiguration festlegen)",
|
||||
"SHOW_HIDE": "Anzeigen, ausblenden, neuzentrieren*",
|
||||
"TOGGLE_DASHBOARD": "Dashboard umschalten",
|
||||
"SPACE_DRAG": "Playspace-Drag",
|
||||
"SPACE_ROTATE": "Playspace rotieren",
|
||||
"SPACE_RESET": "Playspace zurücksetzen",
|
||||
"CLICK_MODIFIER_RIGHT": "Rechtsklick-Modifikator",
|
||||
"CLICK_MODIFIER_MIDDLE": "Mittlere Maustaste-Modifier",
|
||||
"MOVE_MOUSE": "Maus bewegen (falls standardmäßig deaktiviert)",
|
||||
"SCROLL": "Scrollen*"
|
||||
},
|
||||
"LEFT": "Links",
|
||||
"RIGHT": "Rechts",
|
||||
"COMPONENT": "Auslösetyp",
|
||||
"SUBPATH": "Betätigungskontrolle",
|
||||
"THRESHOLD": "Aktivieren, wenn oberer Wert überschritten\nDeaktivieren, wenn unterer Wert unterschritten"
|
||||
},
|
||||
"ENABLED": "Aktiviert",
|
||||
"INPUT_EMULATION_METHOD": "Methode zur Eingabeemulation",
|
||||
"INPUT_EMULATION_METHOD_HELP": "Versuchen Sie dies zu ändern, falls Maus- oder\nTastatureingaben nicht registriert werden.",
|
||||
"INPUT_PROFILES": "Eingabesteuerungen ändern",
|
||||
"INPUT_PROFILES_HELP": "OpenXR-Controller-Eingabebindungen",
|
||||
"NOT_SUPPORTED": "Nicht unterstützt",
|
||||
"ENABLE_WATCH": "Watch aktivieren",
|
||||
"SPACE_DRAG": "Space-drag",
|
||||
"SPACE_GRAVITY_DAMPING": "Dämpfung",
|
||||
"SPACE_GRAVITY_DAMPING_HELP": "Künstlicher Widerstand, um die Bewegung zu verlangsamen. 0,1 - hoher Widerstand, 1,0 - kein Widerstand",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH": "Wurfstärke",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Intensitätsmultiplikator der Schwerkraft-Abstoßungskraft nach dem Space-drag.\n0.0 - gar keine Bewegung, 2.0 - doppelte Intensität",
|
||||
"SPACE_GRAVITY_GRAVITY": "Gravitation",
|
||||
"SPACE_GRAVITY_GRAVITY_HELP": "Betrag der Abwärtskraft. 0.0 - keine Schwerkraft",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION": "Bodenreibung",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "Das Ausmaß der Reibung, das Sie verlangsamt, wenn Sie den Boden berühren.\n0.0 - keine Reibung (wie auf Eis), 1.0 - raue Oberfläche",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT": "Bodenhöhe",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "Die Y-Position, an der sich der Boden befindet. Die Schwerkraft wird gestoppt, wenn Sie diese Höhe erreichen.",
|
||||
"SAVE": "Speichern",
|
||||
"CANCEL": "Abbrechen"
|
||||
},
|
||||
"HELLO": "Hallo!",
|
||||
"AUDIO": {
|
||||
|
|
@ -98,7 +196,6 @@
|
|||
"ACTIONS": {
|
||||
"RECENTER_PLAYSPACE": "Playspace neu zentrieren"
|
||||
},
|
||||
"LIST_OF_PROCESSES": "Prozessliste",
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "Auflösung"
|
||||
},
|
||||
|
|
@ -107,19 +204,12 @@
|
|||
"HIDE": "Verbergen",
|
||||
"REMOVE": "Entfernen",
|
||||
"SHOW": "Anzeigen",
|
||||
"PROCESS_LIST": {
|
||||
"NO_PROCESSES_FOUND": "Keine Prozesse gefunden",
|
||||
"LOCATED_ON": "auf",
|
||||
"TERMINATE_PROCESS_NAMED_X": "Prozess \"{PROCESS_NAME}\" beenden"
|
||||
},
|
||||
"FAILED_TO_LAUNCH_APPLICATION": "Fehler beim Starten der Anwendung:",
|
||||
"NO_WINDOWS_FOUND": "Keine Fenster gefunden",
|
||||
"WINDOW_OPTIONS": "Fensteroptionen",
|
||||
"APPLICATION_STARTED": "Anwendung gestartet",
|
||||
"LIST_OF_WINDOWS": "Fensterliste",
|
||||
"CLOSE_WINDOW": "Fenster schließen",
|
||||
"GAME_LIST": {
|
||||
"NO_GAMES_FOUND": "Keine Spiele gefunden"
|
||||
"NO_GAMES_FOUND": "Keine Spiele gefunden",
|
||||
"RUNNING_GAMES_LIST": "Liste der laufenden Spiele"
|
||||
},
|
||||
"TERMINATE_PROCESS": "Prozess beenden",
|
||||
"GAME_LAUNCHED": "Spiel gestartet",
|
||||
|
|
@ -149,5 +239,23 @@
|
|||
"AUTOSTART": "Automatisch beim Start ausführen",
|
||||
"LAUNCH": "Starten"
|
||||
},
|
||||
"DISPLAY_BRIGHTNESS": "Bildschirmhelligkeit"
|
||||
"DISPLAY_BRIGHTNESS": "Bildschirmhelligkeit",
|
||||
"PROCESS_LIST": "Prozessliste",
|
||||
"REFRESH": "Aktualisieren",
|
||||
"PROCESS": {
|
||||
"STOP": "Stopp",
|
||||
"FORCE_KILL": "Erzwinge Beenden"
|
||||
},
|
||||
"DEBUG_INFO": "Debug-Informationen",
|
||||
"CREATION_DATE": "Erstellungsdatum",
|
||||
"DOWNLOADER": "Downloader",
|
||||
"DOWNLOAD_AGAIN": "Erneut herunterladen",
|
||||
"DOWNLOADING_FILE": "Datei wird heruntergeladen...",
|
||||
"GETTING_STARTED": "Erste Schritte",
|
||||
"MODIFICATION_DATE": "Änderungsdatum",
|
||||
"LOADING": "Laden...",
|
||||
"APPLY": "Anwenden",
|
||||
"RELOAD_FROM_DISK": "Von Festplatte neu laden",
|
||||
"TARGET_PATH": "Zielpfad",
|
||||
"VERSION": "Version"
|
||||
}
|
||||
|
|
@ -31,12 +31,71 @@
|
|||
"APP_SETTINGS": {
|
||||
"ALLOW_SLIDING": "Stick interaction during grab",
|
||||
"ANIMATION_SPEED": "UI Animation speed",
|
||||
"AUTOSTART_APPS": "Apps to run on startup",
|
||||
"BLOCK_GAME_INPUT": "Block game input",
|
||||
"BLOCK_GAME_INPUT_HELP": "Blocks all input when an overlay is hovered",
|
||||
"BLOCK_GAME_INPUT_IGNORE_WATCH": "Ignore watch when blocking input",
|
||||
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "Do not block input when watch is hovered",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Block poses when interacting with keyboard",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blocks the game from receiving poses when the keyboard is hovered and 'Block game input' is enabled",
|
||||
"BINDINGS": {
|
||||
"COMP": {
|
||||
"CLICK": "Click",
|
||||
"FORCE": "Force",
|
||||
"TOUCH": "Touch",
|
||||
"VALUE": "Value",
|
||||
"PROXIMITY": "Proximity",
|
||||
"X_AXIS": "X axis",
|
||||
"Y_AXIS": "Y axis"
|
||||
},
|
||||
"TYPE": {
|
||||
"BUMPER": "Bumper",
|
||||
"DPAD_UP": "D-pad Up",
|
||||
"DPAD_DOWN": "D-pad Down",
|
||||
"DPAD_LEFT": "D-pad Left",
|
||||
"DPAD_RIGHT": "D-pad Right",
|
||||
"JOYSTICK": "Joystick",
|
||||
"MENU": "Menu",
|
||||
"SHOULDER": "Shoulder",
|
||||
"SQUEEZE": "Grip",
|
||||
"SYSTEM": "System",
|
||||
"THUMBREST": "Thumbrest",
|
||||
"THUMBSTICK": "Thumbstick",
|
||||
"TRACKPAD": "Trackpad",
|
||||
"TRIGGER": "Trigger",
|
||||
"VIEW": "View"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "Any",
|
||||
"DOUBLE": "Double-tap",
|
||||
"TRIPLE": "Triple-tap",
|
||||
"TYPE": "Tap count"
|
||||
},
|
||||
"ACTION": {
|
||||
"CLICK": "Click*",
|
||||
"GRAB": "Grab*",
|
||||
"ALT_CLICK": "Custom shell exec (set alt_click in config)",
|
||||
"SHOW_HIDE": "Show, hide, recenter*",
|
||||
"TOGGLE_DASHBOARD": "Toggle dashboard",
|
||||
"SPACE_DRAG": "Playspace drag",
|
||||
"SPACE_ROTATE": "Playspace rotate",
|
||||
"SPACE_RESET": "Playspace reset",
|
||||
"CLICK_MODIFIER_RIGHT": "Right-click modifier",
|
||||
"CLICK_MODIFIER_MIDDLE": "Middle-click modifier",
|
||||
"MOVE_MOUSE": "Move mouse (if off by default)",
|
||||
"SCROLL": "Scroll*"
|
||||
},
|
||||
"LEFT": "Left",
|
||||
"RIGHT": "Right",
|
||||
"COMPONENT": "Actuation type",
|
||||
"SUBPATH": "Actuating control",
|
||||
"THRESHOLD": "Activate when above upper value\nDeactivate when below lower value"
|
||||
},
|
||||
"BROWSE_ONLINE_CATALOG": "Browse online catalog...",
|
||||
"BROWSE_SKYMAPS": "Browse skymaps",
|
||||
"CAPTURE_METHOD": "Wayland screen capture",
|
||||
"CAPTURE_METHOD_HELP": "Try changing this if you are\nexperiencing black or glitchy screens",
|
||||
"COLOR_KEYING": "Color keying",
|
||||
"CLEAR_PIPEWIRE_TOKENS": "Clear PipeWire tokens",
|
||||
"CLEAR_PIPEWIRE_TOKENS_HELP": "Prompt for screen selection on next start",
|
||||
"CLEAR_SAVED_STATE": "Clear saved state",
|
||||
|
|
@ -49,15 +108,23 @@
|
|||
"DELETE_ALL_CONFIGS_HELP": "Remove all configuration files from conf.d",
|
||||
"DOUBLE_CURSOR_FIX": "Double cursor fix",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Enable this if you see 2 cursors",
|
||||
"ENABLED": "Enabled",
|
||||
"FEATURES": "Features",
|
||||
"FOCUS_FOLLOWS_MOUSE_MODE": "Mouse move on trigger touch",
|
||||
"HANDSFREE_POINTER": "Handsfree mode",
|
||||
"HANDSFREE_POINTER_HELP": "Input to use when motion\ncontrollers are unavailable.\nLeft pinch is grab, right is click.",
|
||||
"HIDE_GRAB_HELP": "Hide grab help",
|
||||
"HIDE_USERNAME": "Hide username",
|
||||
"INPUT_EMULATION_METHOD": "Input emulation method",
|
||||
"INPUT_EMULATION_METHOD_HELP": "Try change this in case mouse or\nkeyboard input does not register.",
|
||||
"INPUT_PROFILES": "Change Input Bindings",
|
||||
"INPUT_PROFILES_HELP": "OpenXR controller input bindings",
|
||||
"INVERT_SCROLL_DIRECTION_X": "Invert horizontal scroll direction",
|
||||
"INVERT_SCROLL_DIRECTION_Y": "Invert vertical scroll direction",
|
||||
"KEYBOARD_MIDDLE_CLICK": "Keyboard middle click",
|
||||
"KEYBOARD_MIDDLE_CLICK_HELP": "Modifier to use when typing\nwith purple laser",
|
||||
"KEYBOARD_SOUND_ENABLED": "Keyboard sounds",
|
||||
"LANGUAGE": "Language",
|
||||
"LEFT_HANDED_MOUSE": "Left-handed mouse",
|
||||
"LEFT_HANDED_MOUSE_HELP": "Use this if mouse buttons are swapped",
|
||||
"LONG_PRESS_DURATION": "Long press duration",
|
||||
|
|
@ -65,39 +132,73 @@
|
|||
"MISC": "Miscellaneous",
|
||||
"NOTIFICATIONS_ENABLED": "Enable notifications",
|
||||
"NOTIFICATIONS_SOUND_ENABLED": "Notification sounds",
|
||||
"NOT_SUPPORTED": "Not supported",
|
||||
"NO_SKYMAPS_FOUND": "No skymaps found",
|
||||
"OPAQUE_BACKGROUND": "Opaque background",
|
||||
"OPTION": {
|
||||
"AUTO": "Automatic",
|
||||
"AUTO_HELP": "ScreenCopy GPU if supported,\notherwise PipeWire GPU.",
|
||||
"EYE_ONLY": "Eye only",
|
||||
"EYE_PINCH": "Eye + pinch",
|
||||
"HMD_ONLY": "HMD only",
|
||||
"HMD_PINCH": "HMD + pinch",
|
||||
"NONE": "None",
|
||||
"NONE_INPUT_HELP": "Do not emulate mouse and keyboard.\nWill not be able to interact with screens.",
|
||||
"PIPEWIRE_HELP": "Fast GPU capture,\nstandard on all desktops.",
|
||||
"PW_FALLBACK_HELP": "Slow method with high CPU usage.\nTry in case PipeWire GPU doesn't work",
|
||||
"SCREENCOPY_GPU_HELP": "Fast, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway",
|
||||
"SCREENCOPY_HELP": "Slow, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway"
|
||||
"SCREENCOPY_HELP": "Slow, no screen share popups.\nWorks on: Hyprland, Niri, River, Sway",
|
||||
"UINPUT": "Device emulation",
|
||||
"UINPUT_HELP": "Uses the uinput module to emulate a device.\nYour user must be in the input group.\nKnown to work well on most desktops.",
|
||||
"WL_VIRTUAL": "Wayland virtual input",
|
||||
"WL_VIRTUAL_HELP": "Send events to the Wayland compositor using\nzwlr_virtual_pointer and zwp_virtual_keyboard.\nOnly works reliably on some desktops.\nDoes NOT work on KDE, GNOME or COSMIC."
|
||||
},
|
||||
"POINTER_LERP_FACTOR": "Pointer smoothing",
|
||||
"REQUIRES_RESTART": "Requires restart",
|
||||
"RESET_PLAYSPACE": "Reset playspace",
|
||||
"RESET_PLAYSPACE_HELP": "Clear the stage space offset.",
|
||||
"RESTART_SOFTWARE": "Restart software",
|
||||
"RESTART_SOFTWARE_HELP": "Apply settings that require a restart",
|
||||
"ROUND_MULTIPLIER": "UI Edge roundness",
|
||||
"SCREEN_RENDER_DOWN": "Render screen at lower resolution",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Helps with aliasing on high-res screens",
|
||||
"SCROLL_SPEED": "Scroll speed",
|
||||
"SELECT_VARIANT": "Select variant",
|
||||
"ENABLE_WATCH": "Enable watch",
|
||||
"SETS_ON_WATCH": "Sets on watch",
|
||||
"SHOW_WELCOME_SCREEN": "Show welcome screen",
|
||||
"SHOW_WELCOME_SCREEN_HELP": "Show welcome screen on next start",
|
||||
"SKYBOX": "Skybox",
|
||||
"SKYMAP_ALREADY_DOWNLOADED": "This skymap is already downloaded. Select desired action.",
|
||||
"SPACE_DRAG": "Space drag",
|
||||
"SPACE_DRAG_MULTIPLIER": "Space drag multiplier",
|
||||
"SPACE_DRAG_UNLOCKED": "Allow space drag on all axes",
|
||||
"SPACE_GRAVITY_DAMPING": "Damping",
|
||||
"SPACE_GRAVITY_DAMPING_HELP": "Artificial drag to slow down movement. 0.1 - high drag, 1.0 - no drag",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH": "Fling strength",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Intensity multiplier of gravitational launch force after space-drag.\n0.0 - no movement at all, 2.0 - double intensity",
|
||||
"SPACE_GRAVITY_GRAVITY": "Gravity",
|
||||
"SPACE_GRAVITY_GRAVITY_HELP": "Amount of downwards force. 0.0 - no gravity",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION": "Ground friction",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "Amount of friction slowing you down if you're touching the ground.\n0.0 - no friction (just like on ice), 1.0 - rough surface",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT": "Floor height",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "The Y position where the floor is. Gravity stops when you reach this height.",
|
||||
"SPACE_ROTATE_UNLOCKED": "Allow space rotate on all axes",
|
||||
"TROUBLESHOOTING": "Troubleshooting",
|
||||
"UI_GRADIENT_INTENSITY": "UI Gradient intensity",
|
||||
"UPRIGHT_SCREEN_FIX": "Upright screen fix",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Fixes upright screens on some desktops",
|
||||
"USE_PASSTHROUGH": "Enable passthrough",
|
||||
"USE_PASSTHROUGH_HELP": "Allow passthrough if the XR runtime supports it",
|
||||
"USE_SKYBOX": "Enable skybox",
|
||||
"USE_SKYBOX_HELP": "Show a skybox if there's no scene app or passthrough",
|
||||
"XR_CLICK_SENSITIVITY": "XR click sensitivity",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Analog trigger sensitivity",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE": "XR release sensitivity",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Must be lower than click",
|
||||
"WATCH_VIEW_ANGLE": "Watch view angles",
|
||||
"WATCH_VIEW_ANGLE_HELP": "Control how the watch fades away",
|
||||
"GRID_OPACITY": "Floor grid opacity",
|
||||
"GRID_OPACITY_HELP": "Opacity of the floor grid when the skybox is enabled",
|
||||
"XWAYLAND_BY_DEFAULT": "Run apps in Compatibility mode by default",
|
||||
"AUTOSTART_APPS": "Apps to run on startup"
|
||||
"SAVE": "Save",
|
||||
"CANCEL": "Cancel"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Application launcher",
|
||||
"APPLICATION_STARTED": "Application started",
|
||||
|
|
@ -117,36 +218,45 @@
|
|||
"VOLUME": "Volume"
|
||||
},
|
||||
"CLOSE_WINDOW": "Close window",
|
||||
"CREATION_DATE": "Creation date",
|
||||
"DEBUG_INFO": "Debug info",
|
||||
"DISPLAY_BRIGHTNESS": "Display brightness",
|
||||
"DOWNLOADER": "Downloader",
|
||||
"DOWNLOAD_AGAIN": "Download again",
|
||||
"DOWNLOADING_FILE": "Downloading file...",
|
||||
"FAILED_TO_LAUNCH_APPLICATION": "Failed to launch a application:",
|
||||
"GAME_LAUNCHED": "Game launched",
|
||||
"GAME_LIST": {
|
||||
"NO_GAMES_FOUND": "No games found"
|
||||
"NO_GAMES_FOUND": "No games found",
|
||||
"RUNNING_GAMES_LIST": "List of running games"
|
||||
},
|
||||
"GAMES": "Games",
|
||||
"GENERAL_SETTINGS": "General settings",
|
||||
"GETTING_STARTED": "Getting started",
|
||||
"HEIGHT": "Height",
|
||||
"HELLO": "Hello!",
|
||||
"HELLO_USER": "Hello, {USER}!",
|
||||
"HIDE": "Hide",
|
||||
"HOME_SCREEN": "Home",
|
||||
"LIST_OF_PROCESSES": "Process list",
|
||||
"LIST_OF_WINDOWS": "Window list",
|
||||
"MODIFICATION_DATE": "Modification date",
|
||||
"MONADO_RUNTIME": "Monado runtime",
|
||||
"NO_WINDOWS_FOUND": "No windows found",
|
||||
"LOADING": "Loading...",
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "Resolution"
|
||||
},
|
||||
"PROCESS_LIST": {
|
||||
"LOCATED_ON": "on",
|
||||
"NO_PROCESSES_FOUND": "No processes found",
|
||||
"TERMINATE_PROCESS_NAMED_X": "Terminate process \"{PROCESS_NAME}\""
|
||||
"PROCESS": {
|
||||
"FORCE_KILL": "Force-kill",
|
||||
"STOP": "Stop"
|
||||
},
|
||||
"PROCESSES": "Processes",
|
||||
"PROCESS_LIST": "Process list",
|
||||
"REFRESH": "Refresh",
|
||||
"REMOVE": "Remove",
|
||||
"APPLY": "Apply",
|
||||
"RELOAD_FROM_DISK": "Reload from disk",
|
||||
"SETTINGS": "Settings",
|
||||
"SHOW": "Show",
|
||||
"TARGET_PATH": "Target path",
|
||||
"TERMINATE_PROCESS": "Terminate process",
|
||||
"WIDTH": "Width",
|
||||
"WINDOW_OPTIONS": "Window options"
|
||||
"VERSION": "Version",
|
||||
"WIDTH": "Width"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,12 @@
|
|||
"APPLICATIONS": "Aplicaciones",
|
||||
"GAMES": "Juegos",
|
||||
"SETTINGS": "Ajustes",
|
||||
"PROCESSES": "Procesos",
|
||||
"HELLO_USER": "¡Hola, {USER}!",
|
||||
"GENERAL_SETTINGS": "Ajustes generales",
|
||||
"APPLICATION_LAUNCHER": "Lanzador de aplicaciones",
|
||||
"APP_SETTINGS": {
|
||||
"HIDE_USERNAME": "Ocultar nombre de usuario",
|
||||
"OPAQUE_BACKGROUND": "Fondo opaco",
|
||||
"WLX": {},
|
||||
"LOOK_AND_FEEL": "Apariencia y estilo",
|
||||
"HIDE_GRAB_HELP": "Ocultar ayuda para agarrar",
|
||||
"ANIMATION_SPEED": "Velocidad de animación de la IU",
|
||||
|
|
@ -37,8 +35,6 @@
|
|||
"SCROLL_SPEED": "Velocidad de desplazamiento",
|
||||
"LONG_PRESS_DURATION": "Duración de la pulsación larga",
|
||||
"POINTER_LERP_FACTOR": "Suavizado del puntero",
|
||||
"XR_CLICK_SENSITIVITY": "Sensibilidad del clic XR",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE": "Sensibilidad de liberación de OpenXR",
|
||||
"CLICK_FREEZE_TIME_MS": "Tiempo de congelación al hacer clic (ms)",
|
||||
"MISC": "Miscelánea",
|
||||
"XWAYLAND_BY_DEFAULT": "Ejecutar aplicaciones en modo de compatibilidad por defecto",
|
||||
|
|
@ -47,8 +43,6 @@
|
|||
"SCREEN_RENDER_DOWN": "Renderizar pantalla a menor resolución",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Corrige pantallas en posición vertical en algunos escritorios",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Habilita esto si ves 2 cursores",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Sensibilidad del gatillo analógico",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Debe ser inferior a 'click'",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "Ayuda con la precisión de los dobles clics",
|
||||
"LEFT_HANDED_MOUSE_HELP": "Utilice esto si los botones del ratón están intercambiados",
|
||||
"BLOCK_GAME_INPUT_HELP": "Bloquea toda la entrada cuando se pasa el cursor sobre un overlay",
|
||||
|
|
@ -76,9 +70,113 @@
|
|||
"PIPEWIRE_HELP": "Captura de GPU rápida,\nestándar en todos los escritorios.",
|
||||
"PW_FALLBACK_HELP": "Método lento con alto uso de CPU.\nPruébalo si PipeWire GPU no funciona",
|
||||
"SCREENCOPY_GPU_HELP": "Rápido, sin ventanas emergentes de uso compartido de pantalla.\nFunciona en: Hyprland, Niri, River, Sway",
|
||||
"SCREENCOPY_HELP": "Lento, sin ventanas emergentes de uso compartido de pantalla.\nFunciona en: Hyprland, Niri, River, Sway"
|
||||
"SCREENCOPY_HELP": "Lento, sin ventanas emergentes de uso compartido de pantalla.\nFunciona en: Hyprland, Niri, River, Sway",
|
||||
"NONE": "Ninguno",
|
||||
"HMD_PINCH": "HMD + pellizco",
|
||||
"EYE_PINCH": "Ojo + pellizco",
|
||||
"EYE_ONLY": "Solo ojo",
|
||||
"HMD_ONLY": "Solo HMD",
|
||||
"NONE_INPUT_HELP": "No emular ratón y teclado.\nNo podrá interactuar con las pantallas.",
|
||||
"UINPUT": "Emulación de dispositivo",
|
||||
"UINPUT_HELP": "Utiliza el módulo uinput para emular un dispositivo.\nSu usuario debe estar en el grupo input.\nSe sabe que funciona bien en la mayoría de los escritorios.",
|
||||
"WL_VIRTUAL": "Entrada virtual de Wayland",
|
||||
"WL_VIRTUAL_HELP": "Enviar eventos al compositor de Wayland usando\nzwlr_virtual_pointer y zwp_virtual_keyboard.\nSolo funciona de forma fiable en algunos escritorios.\nNO funciona en KDE, GNOME o COSMIC."
|
||||
},
|
||||
"AUTOSTART_APPS": "Aplicaciones a ejecutar al inicio"
|
||||
"AUTOSTART_APPS": "Aplicaciones a ejecutar al inicio",
|
||||
"HANDSFREE_POINTER": "Modo manos libres",
|
||||
"HANDSFREE_POINTER_HELP": "Entrada a utilizar cuando no\nestén disponibles los mandos de movimiento.\nPellizco con la izquierda para agarrar, con la derecha para hacer clic.",
|
||||
"UI_GRADIENT_INTENSITY": "Intensidad del degradado de la IU",
|
||||
"RESET_PLAYSPACE": "Restablecer espacio de juego",
|
||||
"RESET_PLAYSPACE_HELP": "Borrar el desplazamiento del espacio de juego.",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Bloquear poses al interactuar con el teclado",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Bloquea que el juego reciba poses cuando el teclado está sobre él y 'Bloquear entrada del juego' está habilitado",
|
||||
"LANGUAGE": "Idioma",
|
||||
"REQUIRES_RESTART": "Requiere reinicio",
|
||||
"GRID_OPACITY": "Opacidad de la cuadrícula del suelo",
|
||||
"GRID_OPACITY_HELP": "Opacidad de la cuadrícula del suelo cuando el skybox está habilitado",
|
||||
"BROWSE_ONLINE_CATALOG": "Explorar catálogo en línea...",
|
||||
"BROWSE_SKYMAPS": "Explorar skymaps",
|
||||
"COLOR_KEYING": "Clave de color",
|
||||
"NO_SKYMAPS_FOUND": "No se encontraron skymaps",
|
||||
"SELECT_VARIANT": "Seleccionar variante",
|
||||
"SHOW_WELCOME_SCREEN": "Mostrar pantalla de bienvenida",
|
||||
"SKYBOX": "Skybox",
|
||||
"SKYMAP_ALREADY_DOWNLOADED": "Esta skymap ya ha sido descargada. Selecciona la acción deseada.",
|
||||
"WATCH_VIEW_ANGLE": "Ángulos de visión del Watch",
|
||||
"WATCH_VIEW_ANGLE_HELP": "Controla cómo se desvanece el Watch",
|
||||
"BINDINGS": {
|
||||
"COMP": {
|
||||
"CLICK": "Click",
|
||||
"FORCE": "Fuerza",
|
||||
"TOUCH": "Tocar",
|
||||
"VALUE": "Valor",
|
||||
"PROXIMITY": "Proximidad",
|
||||
"X_AXIS": "Eje X",
|
||||
"Y_AXIS": "Eje Y"
|
||||
},
|
||||
"TYPE": {
|
||||
"BUMPER": "Bumper",
|
||||
"DPAD_UP": "D-pad arriba",
|
||||
"DPAD_DOWN": "D-pad hacia abajo",
|
||||
"DPAD_LEFT": "D-pad izquierda",
|
||||
"DPAD_RIGHT": "D-pad derecha",
|
||||
"JOYSTICK": "Joystick",
|
||||
"MENU": "Menú",
|
||||
"SHOULDER": "Hombro",
|
||||
"SQUEEZE": "Agarre",
|
||||
"SYSTEM": "Sistema",
|
||||
"THUMBREST": "Thumbrest",
|
||||
"THUMBSTICK": "Stick analógico",
|
||||
"TRACKPAD": "Trackpad",
|
||||
"TRIGGER": "Gatillo",
|
||||
"VIEW": "Ver"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "Cualquiera",
|
||||
"DOUBLE": "Doble toque",
|
||||
"TRIPLE": "Triple toque",
|
||||
"TYPE": "Número de toques"
|
||||
},
|
||||
"ACTION": {
|
||||
"CLICK": "Clic*",
|
||||
"GRAB": "Agarrar*",
|
||||
"ALT_CLICK": "Ejecución de shell personalizada (establecer alt_click en la configuración)",
|
||||
"SHOW_HIDE": "Mostrar, ocultar, recentrar*",
|
||||
"TOGGLE_DASHBOARD": "Alternar dashboard",
|
||||
"SPACE_DRAG": "Arrastre del playspace",
|
||||
"SPACE_ROTATE": "Rotar playspace",
|
||||
"SPACE_RESET": "Reinicio del Playspace",
|
||||
"CLICK_MODIFIER_RIGHT": "Modificador de clic derecho",
|
||||
"CLICK_MODIFIER_MIDDLE": "Modificador de clic central",
|
||||
"MOVE_MOUSE": "Mover ratón (si está desactivado por defecto)",
|
||||
"SCROLL": "Desplazamiento*"
|
||||
},
|
||||
"LEFT": "Izquierda",
|
||||
"RIGHT": "Derecha",
|
||||
"COMPONENT": "Tipo de actuación",
|
||||
"SUBPATH": "Control de actuación",
|
||||
"THRESHOLD": "Activar cuando supere el valor superior\nDesactivar cuando sea inferior al valor inferior"
|
||||
},
|
||||
"ENABLED": "Activado",
|
||||
"INPUT_EMULATION_METHOD": "Método de emulación de entrada",
|
||||
"INPUT_EMULATION_METHOD_HELP": "Prueba a cambiar esto en caso de que la entrada del\nratón o el teclado no se registre.",
|
||||
"INPUT_PROFILES": "Cambiar la configuración de entrada",
|
||||
"INPUT_PROFILES_HELP": "Vinculaciones de entrada del controlador OpenXR",
|
||||
"NOT_SUPPORTED": "No compatible",
|
||||
"ENABLE_WATCH": "Activar watch",
|
||||
"SPACE_DRAG": "Space drag",
|
||||
"SPACE_GRAVITY_DAMPING": "Amortiguación",
|
||||
"SPACE_GRAVITY_DAMPING_HELP": "Resistencia artificial para ralentizar el movimiento. 0.1 - alta resistencia, 1.0 - sin resistencia",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH": "Fuerza de lanzamiento",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Multiplicador de intensidad de la fuerza de lanzamiento gravitacional tras el space-drag.\n0.0 - sin movimiento alguno, 2.0 - doble intensidad",
|
||||
"SPACE_GRAVITY_GRAVITY": "Gravedad",
|
||||
"SPACE_GRAVITY_GRAVITY_HELP": "Cantidad de fuerza hacia abajo. 0.0 - sin gravedad",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION": "Fricción del suelo",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "Cantidad de fricción que te ralentiza si estás tocando el suelo.\n0.0 - sin fricción (como si fuera hielo), 1.0 - superficie rugosa",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT": "Altura del suelo",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "La posición Y donde se encuentra el suelo. La gravedad se detiene cuando alcanzas esta altura.",
|
||||
"SAVE": "Guardar",
|
||||
"CANCEL": "Cancelar"
|
||||
},
|
||||
"HELLO": "¡Hola!",
|
||||
"AUDIO": {
|
||||
|
|
@ -98,7 +196,6 @@
|
|||
"ACTIONS": {
|
||||
"RECENTER_PLAYSPACE": "Re-centrar espacio de juego"
|
||||
},
|
||||
"LIST_OF_PROCESSES": "Lista de procesos",
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "Resolución"
|
||||
},
|
||||
|
|
@ -107,19 +204,12 @@
|
|||
"HIDE": "Ocultar",
|
||||
"REMOVE": "Eliminar",
|
||||
"SHOW": "Mostrar",
|
||||
"PROCESS_LIST": {
|
||||
"NO_PROCESSES_FOUND": "No se encontraron procesos",
|
||||
"LOCATED_ON": "en",
|
||||
"TERMINATE_PROCESS_NAMED_X": "Terminar proceso \"{PROCESS_NAME}\""
|
||||
},
|
||||
"FAILED_TO_LAUNCH_APPLICATION": "No se pudo iniciar la aplicación:",
|
||||
"NO_WINDOWS_FOUND": "No se encontraron ventanas",
|
||||
"WINDOW_OPTIONS": "Opciones de ventana",
|
||||
"APPLICATION_STARTED": "Aplicación iniciada",
|
||||
"LIST_OF_WINDOWS": "Lista de ventanas",
|
||||
"CLOSE_WINDOW": "Cerrar ventana",
|
||||
"GAME_LIST": {
|
||||
"NO_GAMES_FOUND": "No se encontraron juegos"
|
||||
"NO_GAMES_FOUND": "No se encontraron juegos",
|
||||
"RUNNING_GAMES_LIST": "Lista de juegos en ejecución"
|
||||
},
|
||||
"TERMINATE_PROCESS": "Finalizar proceso",
|
||||
"GAME_LAUNCHED": "Juego lanzado",
|
||||
|
|
@ -149,5 +239,23 @@
|
|||
"AUTOSTART": "Ejecutar automáticamente al inicio",
|
||||
"LAUNCH": "Iniciar"
|
||||
},
|
||||
"DISPLAY_BRIGHTNESS": "Brillo de la pantalla"
|
||||
"DISPLAY_BRIGHTNESS": "Brillo de la pantalla",
|
||||
"PROCESS_LIST": "Lista de procesos",
|
||||
"REFRESH": "Actualizar",
|
||||
"PROCESS": {
|
||||
"STOP": "Detener",
|
||||
"FORCE_KILL": "Forzar cierre"
|
||||
},
|
||||
"DEBUG_INFO": "Información de depuración",
|
||||
"CREATION_DATE": "Fecha de creación",
|
||||
"DOWNLOADER": "Descargador",
|
||||
"DOWNLOAD_AGAIN": "Descargar de nuevo",
|
||||
"DOWNLOADING_FILE": "Descargando archivo...",
|
||||
"GETTING_STARTED": "Primeros pasos",
|
||||
"MODIFICATION_DATE": "Fecha de modificación",
|
||||
"LOADING": "Cargando...",
|
||||
"APPLY": "Aplicar",
|
||||
"RELOAD_FROM_DISK": "Recargar desde el disco",
|
||||
"TARGET_PATH": "Ruta de destino",
|
||||
"VERSION": "Versión"
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
{
|
||||
"ACTIONS": {
|
||||
"RECENTER_PLAYSPACE": "Recentra lo spazio di gioco"
|
||||
},
|
||||
"APP_LAUNCHER": {
|
||||
"ASPECT": {
|
||||
"SEMI_TALL": "Semi-alto",
|
||||
"SEMI_WIDE": "Semi-ampio",
|
||||
"SQUARE": "Quadrato",
|
||||
"TALL": "Alto",
|
||||
"WIDE": "Ampio"
|
||||
},
|
||||
"ASPECT_TITLE": "Proporzioni",
|
||||
"AUTOSTART": "Avvia automaticamente all'avvio",
|
||||
"LAUNCH": "Avvia",
|
||||
"MODE": {
|
||||
"CAGE": "Modalità compatibilità (Cage)",
|
||||
"NATIVE": "Modalità nativa"
|
||||
},
|
||||
"POS": {
|
||||
"ANCHORED": "Ancorato",
|
||||
"ANCHORED_HELP": "Rimane fermo rispetto al marcatore centrale.",
|
||||
"FLOATING": "Fluttuante",
|
||||
"FLOATING_HELP": "Si muove in modo indipendente, si recentra quando viene mostrato.",
|
||||
"STATIC": "Statico",
|
||||
"STATIC_HELP": "Non fa parte di alcun set. Non recentra."
|
||||
},
|
||||
"POS_TITLE": "Posizionamento",
|
||||
"RES_TITLE": "Risoluzione"
|
||||
},
|
||||
"APP_SETTINGS": {
|
||||
"ALLOW_SLIDING": "Interazione tramite stick durante l'afferrare",
|
||||
"ANIMATION_SPEED": "Velocità dell'animazione dell'interfaccia utente",
|
||||
"BLOCK_GAME_INPUT": "Blocca l'input di gioco",
|
||||
"BLOCK_GAME_INPUT_HELP": "Blocca tutti gli input quando il cursore è sopra un overlay",
|
||||
"BLOCK_GAME_INPUT_IGNORE_WATCH": "Ignora il Watch quando si blocca l'input",
|
||||
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "Non bloccare l'input quando il watch è evidenziato",
|
||||
"CAPTURE_METHOD": "Acquisizione dello schermo Wayland",
|
||||
"CAPTURE_METHOD_HELP": "Prova a modificare questa impostazione se riscontri schermate nere o con artefatti.",
|
||||
"CLEAR_PIPEWIRE_TOKENS": "Cancella i token PipeWire",
|
||||
"CLEAR_PIPEWIRE_TOKENS_HELP": "Richiedi la selezione dello schermo all'avvio successivo",
|
||||
"CLEAR_SAVED_STATE": "Cancella stato salvato",
|
||||
"CLEAR_SAVED_STATE_HELP": "Ripristina set e posizioni degli overlay",
|
||||
"CLICK_FREEZE_TIME_MS": "Tempo di congelamento del click (ms)",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "Aiuta con la precisione dei doppi clic",
|
||||
"CLOCK_12H": "Orologio a 12 ore",
|
||||
"CONTROLS": "Controlli",
|
||||
"DELETE_ALL_CONFIGS": "Elimina configurazione",
|
||||
"DELETE_ALL_CONFIGS_HELP": "Rimuovi tutti i file di configurazione da conf.d",
|
||||
"DOUBLE_CURSOR_FIX": "Correzione doppio cursore",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Abilita questa opzione se vedi 2 cursori",
|
||||
"FEATURES": "Funzionalità",
|
||||
"FOCUS_FOLLOWS_MOUSE_MODE": "Movimento del mouse al tocco del grilletto",
|
||||
"HIDE_GRAB_HELP": "Nascondi l'aiuto per l'afferrare",
|
||||
"HIDE_USERNAME": "Nascondi nome utente",
|
||||
"INVERT_SCROLL_DIRECTION_X": "Inverti direzione dello scorrimento orizzontale",
|
||||
"INVERT_SCROLL_DIRECTION_Y": "Inverti direzione dello scorrimento verticale",
|
||||
"KEYBOARD_MIDDLE_CLICK": "Click centrale del tasto",
|
||||
"KEYBOARD_MIDDLE_CLICK_HELP": "Modificatore da usare durante la digitazione\ncon laser viola",
|
||||
"KEYBOARD_SOUND_ENABLED": "Suoni della tastiera",
|
||||
"LEFT_HANDED_MOUSE": "Mouse per mancini",
|
||||
"LEFT_HANDED_MOUSE_HELP": "Usalo se i pulsanti del mouse sono invertiti",
|
||||
"LONG_PRESS_DURATION": "Durata pressione prolungata",
|
||||
"LOOK_AND_FEEL": "Aspetto",
|
||||
"MISC": "Varie",
|
||||
"NOTIFICATIONS_ENABLED": "Abilita notifiche",
|
||||
"NOTIFICATIONS_SOUND_ENABLED": "Suoni di notifica",
|
||||
"OPAQUE_BACKGROUND": "Sfondo opaco",
|
||||
"OPTION": {
|
||||
"AUTO": "Automatico",
|
||||
"AUTO_HELP": "Copia dello schermo tramite GPU se supportata,\naltrimenti tramite GPU PipeWire.",
|
||||
"PIPEWIRE_HELP": "Acquisizione GPU veloce,\nstandard su tutti i desktop.",
|
||||
"PW_FALLBACK_HELP": "Metodo lento con elevato utilizzo della CPU.\nProva in caso PipeWire GPU non funzioni",
|
||||
"SCREENCOPY_GPU_HELP": "Veloce, senza popup di condivisione schermo.\nFunziona su: Hyprland, Niri, River, Sway",
|
||||
"SCREENCOPY_HELP": "Lento, nessuna finestra pop-up per la condivisione dello schermo.\nFunziona su: Hyprland, Niri, River, Sway",
|
||||
"NONE": "Nessuno",
|
||||
"HMD_PINCH": "HMD + pizzico",
|
||||
"EYE_PINCH": "Occhio + pizzico",
|
||||
"EYE_ONLY": "Solo occhio",
|
||||
"HMD_ONLY": "Solo HMD",
|
||||
"NONE_INPUT_HELP": "Non emulare mouse e tastiera.\nNon sarà possibile interagire con gli schermi.",
|
||||
"UINPUT": "Emulazione dispositivo",
|
||||
"UINPUT_HELP": "Utilizza il modulo uinput per emulare un dispositivo.\nL'utente deve far parte del gruppo input.\nRisultato ottimale su quasi tutti i desktop.",
|
||||
"WL_VIRTUAL": "Input virtuale Wayland",
|
||||
"WL_VIRTUAL_HELP": "Invia eventi al compositor Wayland utilizzando\nzwlr_virtual_pointer e zwp_virtual_keyboard.\nFunziona in modo affidabile solo su alcuni desktop.\nNON funziona su KDE, GNOME o COSMIC."
|
||||
},
|
||||
"POINTER_LERP_FACTOR": "Smussamento puntatore",
|
||||
"RESTART_SOFTWARE": "Riavvia il software",
|
||||
"RESTART_SOFTWARE_HELP": "Applica impostazioni che richiedono un riavvio",
|
||||
"ROUND_MULTIPLIER": "Arrotondamento bordi UI",
|
||||
"SCREEN_RENDER_DOWN": "Rendering dello schermo a risoluzione inferiore",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Aiuta a ridurre l'aliasing su schermi ad alta risoluzione",
|
||||
"SCROLL_SPEED": "Velocità di scorrimento",
|
||||
"SETS_ON_WATCH": "Set sul Watch",
|
||||
"SPACE_DRAG_MULTIPLIER": "Moltiplicatore space-drag",
|
||||
"SPACE_DRAG_UNLOCKED": "Consenti lo space-drag su tutti gli assi",
|
||||
"SPACE_ROTATE_UNLOCKED": "Consenti la rotazione dello spazio su tutti gli assi",
|
||||
"TROUBLESHOOTING": "Risoluzione dei problemi",
|
||||
"UPRIGHT_SCREEN_FIX": "Correzione schermo verticale",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Corregge schermi verticali su alcuni desktop",
|
||||
"USE_PASSTHROUGH": "Abilita passthrough",
|
||||
"USE_PASSTHROUGH_HELP": "Consenti il passthrough se supportato dal runtime XR",
|
||||
"USE_SKYBOX": "Abilita skybox",
|
||||
"USE_SKYBOX_HELP": "Mostra uno skybox se non c'è un'app di scena o passthrough",
|
||||
"XWAYLAND_BY_DEFAULT": "Esegui le app in modalità Compatibilità per impostazione predefinita",
|
||||
"AUTOSTART_APPS": "App da avviare all'avvio",
|
||||
"HANDSFREE_POINTER": "Modalità a mani libere",
|
||||
"HANDSFREE_POINTER_HELP": "Input da usare quando i\ncontroller di movimento non sono disponibili.\nPizzico sinistro per afferrare, destro per cliccare.",
|
||||
"UI_GRADIENT_INTENSITY": "Intensità gradiente dell'interfaccia utente",
|
||||
"RESET_PLAYSPACE": "Ripristina playspace",
|
||||
"RESET_PLAYSPACE_HELP": "Cancella l'offset dello spazio di gioco.",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Blocca le pose durante l'interazione con la tastiera",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Impedisce al gioco di ricevere pose quando la tastiera è evidenziata e 'Blocca input di gioco' è abilitato",
|
||||
"LANGUAGE": "Lingua",
|
||||
"REQUIRES_RESTART": "Richiede riavvio",
|
||||
"GRID_OPACITY": "Opacità della griglia del pavimento",
|
||||
"GRID_OPACITY_HELP": "Opacità della griglia del pavimento quando lo skybox è abilitato",
|
||||
"BROWSE_ONLINE_CATALOG": "Sfoglia catalogo online...",
|
||||
"BROWSE_SKYMAPS": "Sfoglia skymap",
|
||||
"COLOR_KEYING": "Keying del colore",
|
||||
"NO_SKYMAPS_FOUND": "Nessuna skymap trovata",
|
||||
"SELECT_VARIANT": "Seleziona variante",
|
||||
"SHOW_WELCOME_SCREEN": "Mostra schermata di benvenuto",
|
||||
"SKYBOX": "Skybox",
|
||||
"SKYMAP_ALREADY_DOWNLOADED": "Questa skymap è già stata scaricata. Seleziona l'azione desiderata.",
|
||||
"WATCH_VIEW_ANGLE": "Angoli di visualizzazione Watch",
|
||||
"WATCH_VIEW_ANGLE_HELP": "Controlla come l'orologio sfuma",
|
||||
"BINDINGS": {
|
||||
"COMP": {
|
||||
"CLICK": "Clic",
|
||||
"FORCE": "Forza",
|
||||
"TOUCH": "Tocco",
|
||||
"VALUE": "Valore",
|
||||
"PROXIMITY": "Prossimità",
|
||||
"X_AXIS": "Asse X",
|
||||
"Y_AXIS": "Asse Y"
|
||||
},
|
||||
"TYPE": {
|
||||
"BUMPER": "Bumper",
|
||||
"DPAD_UP": "D-pad su",
|
||||
"DPAD_DOWN": "D-pad Giù",
|
||||
"DPAD_LEFT": "D-pad Sinistra",
|
||||
"DPAD_RIGHT": "D-pad Destra",
|
||||
"JOYSTICK": "Joystick",
|
||||
"MENU": "Menu",
|
||||
"SHOULDER": "Spalla",
|
||||
"SQUEEZE": "Grip",
|
||||
"SYSTEM": "Sistema",
|
||||
"THUMBREST": "Appoggio del pollice",
|
||||
"THUMBSTICK": "Thumbstick",
|
||||
"TRACKPAD": "Trackpad",
|
||||
"TRIGGER": "Grilletto",
|
||||
"VIEW": "Visualizza"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "Qualsiasi",
|
||||
"DOUBLE": "Doppio tocco",
|
||||
"TRIPLE": "Triplo tocco",
|
||||
"TYPE": "Numero di tocchi"
|
||||
},
|
||||
"ACTION": {
|
||||
"CLICK": "Click*",
|
||||
"GRAB": "Afferra*",
|
||||
"ALT_CLICK": "Esecuzione shell personalizzata (imposta alt_click nella configurazione)",
|
||||
"SHOW_HIDE": "Mostra, nascondi, recentra*",
|
||||
"TOGGLE_DASHBOARD": "Attiva/disattiva dashboard",
|
||||
"SPACE_DRAG": "Trascinamento playspace",
|
||||
"SPACE_ROTATE": "Rotazione playspace",
|
||||
"SPACE_RESET": "Reset playspace",
|
||||
"CLICK_MODIFIER_RIGHT": "Modificatore click destro",
|
||||
"CLICK_MODIFIER_MIDDLE": "Modificatore click centrale",
|
||||
"MOVE_MOUSE": "Muovi mouse (se disattivato di default)",
|
||||
"SCROLL": "Scorrimento*"
|
||||
},
|
||||
"LEFT": "Sinistra",
|
||||
"RIGHT": "Destra",
|
||||
"COMPONENT": "Tipo di attivazione",
|
||||
"SUBPATH": "Controllo di attivazione",
|
||||
"THRESHOLD": "Attiva quando sopra il valore superiore\nDisattiva quando sotto il valore inferiore"
|
||||
},
|
||||
"ENABLED": "Abilitato",
|
||||
"INPUT_EMULATION_METHOD": "Metodo di emulazione input",
|
||||
"INPUT_EMULATION_METHOD_HELP": "Prova a cambiare questa impostazione nel caso in cui l'input del mouse o \ndella tastiera non venga registrato.",
|
||||
"INPUT_PROFILES": "Cambia i binding di input",
|
||||
"INPUT_PROFILES_HELP": "Binding di input del controller OpenXR",
|
||||
"NOT_SUPPORTED": "Non supportato",
|
||||
"ENABLE_WATCH": "Abilita watch",
|
||||
"SPACE_DRAG": "Space drag",
|
||||
"SPACE_GRAVITY_DAMPING": "Smorzamento",
|
||||
"SPACE_GRAVITY_DAMPING_HELP": "Resistenza artificiale per rallentare il movimento. 0.1 - alta resistenza, 1.0 - nessuna resistenza",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH": "Forza del lancio",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Moltiplicatore dell'intensità della forza di lancio gravitazionale dopo lo space-drag.\n0.0 - nessun movimento, 2.0 - intensità doppia",
|
||||
"SPACE_GRAVITY_GRAVITY": "Gravità",
|
||||
"SPACE_GRAVITY_GRAVITY_HELP": "Quantità di forza verso il basso. 0.0 - nessuna gravità",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION": "Attrito del terreno",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "Quantità di attrito che ti rallenta se tocchi il suolo.\n0.0 - nessuna frizione (proprio come sul ghiaccio), 1.0 - superficie ruvida",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT": "Altezza del pavimento",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "La posizione Y in cui si trova il pavimento. La gravità si ferma quando raggiungi questa altezza.",
|
||||
"SAVE": "Salva",
|
||||
"CANCEL": "Annulla"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Lanciatore applicazioni",
|
||||
"APPLICATION_STARTED": "Applicazione avviata",
|
||||
"APPLICATIONS": "Applicazioni",
|
||||
"AUDIO": {
|
||||
"AUTO_SWITCH_TO_VR_AUDIO": "Passa automaticamente all'audio VR",
|
||||
"CARDS": "Schede",
|
||||
"FAILED_TO_SWITCH_MICROPHONE": "Impossibile cambiare microfono",
|
||||
"MICROPHONE_SET_SUCCESSFULLY": "Microfono impostato con successo",
|
||||
"MICROPHONES": "Microfoni",
|
||||
"NO_VR_MICROPHONE_SWITCH_MANUALLY": "Nessun microfono VR trovato. Attivalo manualmente.",
|
||||
"NO_VR_SPEAKERS_FOUND_SWITCH_MANUALLY": "Nessun altoparlante VR trovato. Selezionali manualmente.",
|
||||
"SELECT_AUDIO_CARD_PROFILE": "Seleziona profilo scheda audio",
|
||||
"SETTINGS": "Impostazioni audio",
|
||||
"SPEAKERS": "Altoparlanti",
|
||||
"SPEAKERS_SET_SUCCESSFULLY": "Altoparlanti impostati correttamente",
|
||||
"VOLUME": "Volume"
|
||||
},
|
||||
"CLOSE_WINDOW": "Chiudi finestra",
|
||||
"DISPLAY_BRIGHTNESS": "Luminosità display",
|
||||
"FAILED_TO_LAUNCH_APPLICATION": "Impossibile avviare l'applicazione:",
|
||||
"GAME_LAUNCHED": "Gioco lanciato",
|
||||
"GAME_LIST": {
|
||||
"NO_GAMES_FOUND": "Nessun gioco trovato",
|
||||
"RUNNING_GAMES_LIST": "Lista dei giochi in esecuzione"
|
||||
},
|
||||
"GAMES": "Giochi",
|
||||
"GENERAL_SETTINGS": "Impostazioni generali",
|
||||
"HEIGHT": "Altezza",
|
||||
"HELLO": "Ciao!",
|
||||
"HELLO_USER": "Ciao, {USER}!",
|
||||
"HIDE": "Nascondi",
|
||||
"HOME_SCREEN": "Home",
|
||||
"MONADO_RUNTIME": "Runtime Monado",
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "Risoluzione"
|
||||
},
|
||||
"REMOVE": "Rimuovi",
|
||||
"SETTINGS": "Impostazioni",
|
||||
"SHOW": "Mostra",
|
||||
"TERMINATE_PROCESS": "Termina processo",
|
||||
"WIDTH": "Larghezza",
|
||||
"PROCESS_LIST": "Elenco processi",
|
||||
"REFRESH": "Aggiorna",
|
||||
"PROCESS": {
|
||||
"STOP": "Interrompi",
|
||||
"FORCE_KILL": "Uccidi forzatamente"
|
||||
},
|
||||
"DEBUG_INFO": "Informazioni di debug",
|
||||
"CREATION_DATE": "Data di creazione",
|
||||
"DOWNLOADER": "Downloader",
|
||||
"DOWNLOAD_AGAIN": "Scarica di nuovo",
|
||||
"DOWNLOADING_FILE": "Download del file in corso...",
|
||||
"GETTING_STARTED": "Inizio rapido",
|
||||
"MODIFICATION_DATE": "Data di modifica",
|
||||
"LOADING": "Caricamento...",
|
||||
"APPLY": "Applica",
|
||||
"RELOAD_FROM_DISK": "Ricarica da disco",
|
||||
"TARGET_PATH": "Percorso di destinazione",
|
||||
"VERSION": "Versione"
|
||||
}
|
||||
|
|
@ -4,14 +4,12 @@
|
|||
"APPLICATIONS": "アプリ",
|
||||
"GAMES": "ゲーム",
|
||||
"SETTINGS": "設定",
|
||||
"PROCESSES": "プロセス",
|
||||
"HELLO_USER": "こんにちは、{USER}!",
|
||||
"GENERAL_SETTINGS": "全般設定",
|
||||
"APPLICATION_LAUNCHER": "アプリケーションランチャー",
|
||||
"APP_SETTINGS": {
|
||||
"HIDE_USERNAME": "ユーザー名を非表示",
|
||||
"OPAQUE_BACKGROUND": "不透明な背景",
|
||||
"WLX": {},
|
||||
"LOOK_AND_FEEL": "外観",
|
||||
"HIDE_GRAB_HELP": "グリップ動作中にのヘルプを非表示",
|
||||
"ANIMATION_SPEED": "UIアニメーション速度",
|
||||
|
|
@ -37,8 +35,6 @@
|
|||
"SCROLL_SPEED": "スクロール速度",
|
||||
"LONG_PRESS_DURATION": "長押し時間",
|
||||
"POINTER_LERP_FACTOR": "ポインターのスムージング",
|
||||
"XR_CLICK_SENSITIVITY": "XRクリック感度",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE": "XRリリース感度",
|
||||
"CLICK_FREEZE_TIME_MS": "クリックで一時停止時間 (ms)",
|
||||
"MISC": "その他",
|
||||
"XWAYLAND_BY_DEFAULT": "アプリ実行のデフォルトは互換モード",
|
||||
|
|
@ -47,8 +43,6 @@
|
|||
"SCREEN_RENDER_DOWN": "画面の解像度を縮小",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "一部のデスクトップで縦向きの画面を修正",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "2つのカーソルが表示される場合は、これを有効にします",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "アナログトリガの感度",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "クリックより低くする必要があります",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "ダブルクリックの精度向上に役立ちます",
|
||||
"LEFT_HANDED_MOUSE_HELP": "マウスボタンが入れ替わっている場合に有効にします",
|
||||
"BLOCK_GAME_INPUT_HELP": "オーバーレイ上にマウスカーソルがあるときに入力をブロックします",
|
||||
|
|
@ -76,9 +70,113 @@
|
|||
"PIPEWIRE_HELP": "GPU高速キャプチャ。\nすべてのデスクトップで標準です。",
|
||||
"PW_FALLBACK_HELP": "CPU使用量が多い低速な方法です。\nPipeWire GPUが動作しない場合に試してください。",
|
||||
"SCREENCOPY_GPU_HELP": "高速で、スクリーン共有ポップアップはありません。\n動作する環境: Hyprland, Niri, River, Sway",
|
||||
"SCREENCOPY_HELP": "遅延あり、画面共有ポップアップなし。\n動作する環境: Hyprland, Niri, River, Sway"
|
||||
"SCREENCOPY_HELP": "遅延あり、画面共有ポップアップなし。\n動作する環境: Hyprland, Niri, River, Sway",
|
||||
"NONE": "なし",
|
||||
"HMD_PINCH": "HMD + ピンチ",
|
||||
"EYE_PINCH": "つまんで目を合わせる",
|
||||
"EYE_ONLY": "視野のみ",
|
||||
"HMD_ONLY": "HMDのみ",
|
||||
"NONE_INPUT_HELP": "マウスとキーボードをエミュレートしません。\nディスプレイを操作できなくなります。",
|
||||
"UINPUT": "デバイス・エミュレーション",
|
||||
"UINPUT_HELP": "uinput モジュールを使用してデバイスをエミュレートします。\nユーザーが input グループに属している必要があります。\nほとんどのデスクトップ環境で正常に動作することが確認されています。",
|
||||
"WL_VIRTUAL": "Wayland 仮想入力",
|
||||
"WL_VIRTUAL_HELP": "zwlr_virtual_pointer および zwp_virtual_keyboard を使用して、Wayland コンポジタにイベントを送信します。\n一部のデスクトップ環境でのみ、安定して動作します。\nKDE、GNOME、または COSMIC では動作しません。"
|
||||
},
|
||||
"AUTOSTART_APPS": "起動時に実行するアプリ"
|
||||
"AUTOSTART_APPS": "起動時に実行するアプリ",
|
||||
"HANDSFREE_POINTER": "ハンズフリーモード",
|
||||
"HANDSFREE_POINTER_HELP": "モーションコントローラーが利用できない場合の入力方法。\n左手のピンチは掴み、右手のピンチはクリックです。",
|
||||
"UI_GRADIENT_INTENSITY": "UIグラデーションの強さ",
|
||||
"RESET_PLAYSPACE": "プレイエリアをリセット",
|
||||
"RESET_PLAYSPACE_HELP": "プレイエリアのオフセットをクリアします。",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION": "キーボード操作時のポーズをブロック",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "キーボードがホバーされ、「ゲーム入力をブロック」が有効になっている場合、ゲームがポーズを受信することをブロックします",
|
||||
"LANGUAGE": "言語",
|
||||
"REQUIRES_RESTART": "再起動が必要です",
|
||||
"GRID_OPACITY": "フロアグリッドの不透明度",
|
||||
"GRID_OPACITY_HELP": "スカイボックスが有効なときの床グリッドの不透明度",
|
||||
"BROWSE_ONLINE_CATALOG": "オンラインカタログを閲覧...",
|
||||
"BROWSE_SKYMAPS": "Skymapを閲覧",
|
||||
"COLOR_KEYING": "カラーキーイング",
|
||||
"NO_SKYMAPS_FOUND": "スカイマップが見つかりません",
|
||||
"SELECT_VARIANT": "バリアントを選択",
|
||||
"SHOW_WELCOME_SCREEN": "ウェルカムスクリーンを表示する",
|
||||
"SKYBOX": "スカイボックス",
|
||||
"SKYMAP_ALREADY_DOWNLOADED": "このスカイマップは既にダウンロードされています。希望のアクションを選択してください。",
|
||||
"WATCH_VIEW_ANGLE": "Watchの表示角度",
|
||||
"WATCH_VIEW_ANGLE_HELP": "ウォッチのフェードアウト具合を調整する",
|
||||
"BINDINGS": {
|
||||
"COMP": {
|
||||
"CLICK": "クリック",
|
||||
"FORCE": "Force",
|
||||
"TOUCH": "タッチ",
|
||||
"VALUE": "値",
|
||||
"PROXIMITY": "近接度",
|
||||
"X_AXIS": "X軸",
|
||||
"Y_AXIS": "Y軸"
|
||||
},
|
||||
"TYPE": {
|
||||
"BUMPER": "バンパー",
|
||||
"DPAD_UP": "Dパッド上",
|
||||
"DPAD_DOWN": "Dパッド 下",
|
||||
"DPAD_LEFT": "Dパッド左",
|
||||
"DPAD_RIGHT": "Dパッド右",
|
||||
"JOYSTICK": "ジョイスティック",
|
||||
"MENU": "メニュー",
|
||||
"SHOULDER": "ショルダー",
|
||||
"SQUEEZE": "グリップ",
|
||||
"SYSTEM": "システム",
|
||||
"THUMBREST": "サムレスト",
|
||||
"THUMBSTICK": "サムスティック",
|
||||
"TRACKPAD": "トラックパッド",
|
||||
"TRIGGER": "トリガー",
|
||||
"VIEW": "表示"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "任意",
|
||||
"DOUBLE": "ダブルタップ",
|
||||
"TRIPLE": "トリプルタップ",
|
||||
"TYPE": "タップ回数"
|
||||
},
|
||||
"ACTION": {
|
||||
"CLICK": "クリック*",
|
||||
"GRAB": "掴む*",
|
||||
"ALT_CLICK": "カスタムシェル実行 (configでalt_clickを設定)",
|
||||
"SHOW_HIDE": "表示・非表示、再中心化*",
|
||||
"TOGGLE_DASHBOARD": "ダッシュボードの切り替え",
|
||||
"SPACE_DRAG": "Playspaceドラッグ",
|
||||
"SPACE_ROTATE": "Playspace 回転",
|
||||
"SPACE_RESET": "Playspace リセット",
|
||||
"CLICK_MODIFIER_RIGHT": "右クリック修飾キー",
|
||||
"CLICK_MODIFIER_MIDDLE": "中クリック修飾キー",
|
||||
"MOVE_MOUSE": "マウスを移動 (デフォルトでオフの場合)",
|
||||
"SCROLL": "スクロール*"
|
||||
},
|
||||
"LEFT": "左",
|
||||
"RIGHT": "右",
|
||||
"COMPONENT": "作動タイプ",
|
||||
"SUBPATH": "アクチュエーション制御",
|
||||
"THRESHOLD": "上限値を超えたときに有効化\n下限値を下回ったときに無効化"
|
||||
},
|
||||
"ENABLED": "有効",
|
||||
"INPUT_EMULATION_METHOD": "入力エミュレーション方法",
|
||||
"INPUT_EMULATION_METHOD_HELP": "マウスやキーボードの入力が\n認識されない場合は、ここを変更してみてください。",
|
||||
"INPUT_PROFILES": "入力バインドの変更",
|
||||
"INPUT_PROFILES_HELP": "OpenXRコントローラーの入力バインディング",
|
||||
"NOT_SUPPORTED": "未対応",
|
||||
"ENABLE_WATCH": "Watchを有効にする",
|
||||
"SPACE_DRAG": "Space drag",
|
||||
"SPACE_GRAVITY_DAMPING": "減衰",
|
||||
"SPACE_GRAVITY_DAMPING_HELP": "動きを減速させるための人工的な抵抗です。0.1 - 強い抵抗、1.0 - 抵抗なし",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH": "スリングの強さ",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Space-drag 後の重力による打ち出し強度の倍率です。\n0.0 - 全く動きません、2.0 - 強度が2倍になります",
|
||||
"SPACE_GRAVITY_GRAVITY": "重力",
|
||||
"SPACE_GRAVITY_GRAVITY_HELP": "下向きの力の強さ。0.0 - 重力なし",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION": "地面の摩擦",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "地面に触れている際に、移動を遅らせる摩擦の強さです。\n0.0 - 摩擦なし(氷の上のような状態)、1.0 - 粗い表面",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT": "床の高さ",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "床のY座標です。この高さに達すると重力が停止します。",
|
||||
"SAVE": "保存",
|
||||
"CANCEL": "キャンセル"
|
||||
},
|
||||
"HELLO": "こんにちは!",
|
||||
"AUDIO": {
|
||||
|
|
@ -98,7 +196,6 @@
|
|||
"ACTIONS": {
|
||||
"RECENTER_PLAYSPACE": "プレイスペースを再中央"
|
||||
},
|
||||
"LIST_OF_PROCESSES": "プロセスのリスト",
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "解像度"
|
||||
},
|
||||
|
|
@ -107,19 +204,12 @@
|
|||
"HIDE": "隠す",
|
||||
"REMOVE": "削除",
|
||||
"SHOW": "表示",
|
||||
"PROCESS_LIST": {
|
||||
"NO_PROCESSES_FOUND": "プロセスが見つかりませんでした",
|
||||
"LOCATED_ON": "に",
|
||||
"TERMINATE_PROCESS_NAMED_X": "プロセス \"{PROCESS_NAME}\" を終了します"
|
||||
},
|
||||
"FAILED_TO_LAUNCH_APPLICATION": "アプリケーションの起動に失敗しました:",
|
||||
"NO_WINDOWS_FOUND": "ウィンドウが見つかりませんでした",
|
||||
"WINDOW_OPTIONS": "ウィンドウオプション",
|
||||
"APPLICATION_STARTED": "アプリケーションが起動しました",
|
||||
"LIST_OF_WINDOWS": "ウィンドウ一覧",
|
||||
"CLOSE_WINDOW": "ウィンドウを閉じる",
|
||||
"GAME_LIST": {
|
||||
"NO_GAMES_FOUND": "ゲームが見つかりませんでした"
|
||||
"NO_GAMES_FOUND": "ゲームが見つかりませんでした",
|
||||
"RUNNING_GAMES_LIST": "実行中のゲーム一覧"
|
||||
},
|
||||
"TERMINATE_PROCESS": "プロセスを終了する",
|
||||
"GAME_LAUNCHED": "ゲームが起動しました",
|
||||
|
|
@ -149,5 +239,23 @@
|
|||
"AUTOSTART": "起動時に自動実行",
|
||||
"LAUNCH": "起動"
|
||||
},
|
||||
"DISPLAY_BRIGHTNESS": "ディスプレイの明るさ"
|
||||
"DISPLAY_BRIGHTNESS": "ディスプレイの明るさ",
|
||||
"PROCESS_LIST": "プロセスリスト",
|
||||
"REFRESH": "更新",
|
||||
"PROCESS": {
|
||||
"STOP": "停止",
|
||||
"FORCE_KILL": "強制終了"
|
||||
},
|
||||
"DEBUG_INFO": "デバッグ情報",
|
||||
"CREATION_DATE": "作成日",
|
||||
"DOWNLOADER": "ダウンローダー",
|
||||
"DOWNLOAD_AGAIN": "再ダウンロード",
|
||||
"DOWNLOADING_FILE": "ファイルをダウンロード中...",
|
||||
"GETTING_STARTED": "はじめに",
|
||||
"MODIFICATION_DATE": "更新日",
|
||||
"LOADING": "読み込み中...",
|
||||
"APPLY": "適用",
|
||||
"RELOAD_FROM_DISK": "ディスクからリロード",
|
||||
"TARGET_PATH": "ターゲットパス",
|
||||
"VERSION": "バージョン"
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@
|
|||
"APP_SETTINGS": {
|
||||
"HIDE_USERNAME": "Ukryj nazwę użytkownika",
|
||||
"OPAQUE_BACKGROUND": "Nieprzezroczyste tło",
|
||||
"WLX": {},
|
||||
"LOOK_AND_FEEL": "Wygląd i działanie",
|
||||
"HIDE_GRAB_HELP": "Ukryj pomoc dotyczącą chwytania",
|
||||
"ANIMATION_SPEED": "Prędkość animacji UI",
|
||||
|
|
@ -31,18 +30,13 @@
|
|||
"SCROLL_SPEED": "Prędkość przewijania",
|
||||
"LONG_PRESS_DURATION": "Czas długiego przytrzymania",
|
||||
"POINTER_LERP_FACTOR": "Wygładzanie wskaźnika",
|
||||
"XR_CLICK_SENSITIVITY": "Czułość kliknięć XR",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE": "Czułość zwalniania XR",
|
||||
"CLICK_FREEZE_TIME_MS": "Czas zamrożenia po kliknięciu (ms)",
|
||||
"MISC": "Różne",
|
||||
"XWAYLAND_BY_DEFAULT": "Uruchamiaj aplikacje domyślnie w trybie kompatybilności",
|
||||
"UPRIGHT_SCREEN_FIX": "Naprawa pozycji ekranu",
|
||||
"DOUBLE_CURSOR_FIX": "Naprawa podwójnego kursora",
|
||||
"SCREEN_RENDER_DOWN": "Renderuj ekran w niższej rozdzielczości",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "Naprawia pionowe ekrany na niektórych komputerach",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "Włącz to, jeśli widzisz 2 kursory",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Czułość analogowego spustu",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Musi być niższa niż kliknięcie",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "Pomaga w precyzji podwójnego kliknięcia",
|
||||
"LEFT_HANDED_MOUSE_HELP": "Użyj tego, jeśli przyciski myszy są zamienione",
|
||||
"BLOCK_GAME_INPUT_HELP": "Blokuje wszystkie dane wejściowe, gdy kursor najedzie na nakładkę",
|
||||
|
|
@ -50,12 +44,13 @@
|
|||
"USE_SKYBOX_HELP": "Wyświetlaj niebo, jeśli nie ma aplikacji sceny lub passthrough",
|
||||
"USE_PASSTHROUGH_HELP": "Pozwól na passthrough, jeśli runtime XR to obsługuje",
|
||||
"SCREEN_RENDER_DOWN_HELP": "Pomaga redukować aliasing na ekranach o wysokiej rozdzielczości",
|
||||
"ENABLE_WATCH": "Włącz zegarek",
|
||||
"SETS_ON_WATCH": "Lista zestawów na zegarku",
|
||||
"TROUBLESHOOTING": "Rozwiązywanie problemów",
|
||||
"CLEAR_SAVED_STATE": "Wyczyść zapisany stan",
|
||||
"CLEAR_PIPEWIRE_TOKENS": "Wyczyść tokeny PipeWire",
|
||||
"DELETE_ALL_CONFIGS": "Wyczyść konfigurację",
|
||||
"RESTART_SOFTWARE": "Uruchom ponownie oprogramowanie",
|
||||
"RESTART_SOFTWARE": "Restartuj WayVR",
|
||||
"CLEAR_SAVED_STATE_HELP": "Zresetuj zestawy i pozycje nakładek",
|
||||
"CLEAR_PIPEWIRE_TOKENS_HELP": "Zapytaj o wybór ekranu przy następnym uruchomieniu",
|
||||
"DELETE_ALL_CONFIGS_HELP": "Usuń wszystkie pliki konfiguracyjne z katalogu conf.d",
|
||||
|
|
@ -70,9 +65,113 @@
|
|||
"PIPEWIRE_HELP": "Szybkie przechwytywanie GPU,\nstandard na wszystkich komputerach.",
|
||||
"PW_FALLBACK_HELP": "Powolna metoda z wysokim użyciem procesora.\nWypróbuj w przypadku, gdy PipeWire GPU nie działa",
|
||||
"SCREENCOPY_GPU_HELP": "Szybkie działanie, brak wyskakujących okien z informacją o udostępnianiu ekranu.\nDziała na: Hyprland, Niri, River, Sway",
|
||||
"SCREENCOPY_HELP": "Wolne, bez wyskakujących okienek udostępniania ekranu.\nDziała na: Hyprland, Niri, River, Sway"
|
||||
"SCREENCOPY_HELP": "Wolne, bez wyskakujących okienek udostępniania ekranu.\nDziała na: Hyprland, Niri, River, Sway",
|
||||
"NONE": "Brak",
|
||||
"HMD_PINCH": "HMD + ściśnięcie placami",
|
||||
"EYE_PINCH": "Ściśnięcie palcami + oko",
|
||||
"EYE_ONLY": "Tylko oko",
|
||||
"HMD_ONLY": "Tylko HMD",
|
||||
"NONE_INPUT_HELP": "Nie emuluj myszy ani klawiatury.\nBrak możliwości interakcji z ekranami.",
|
||||
"UINPUT": "Emulacja urządzenia",
|
||||
"UINPUT_HELP": "Używa modułu uinput do emulowania urządzenia.\nTwoje konto użytkownika musi należeć do grupy input.\nWiadomo, że działa dobrze na większości komputerów stacjonarnych.",
|
||||
"WL_VIRTUAL": "Wirtualne wejście Wayland",
|
||||
"WL_VIRTUAL_HELP": "Wysyłaj wejście myszki/klawiatury do kompozytora Wayland za pomocą\nzwlr_virtual_pointer i zwp_virtual_keyboard.\nDziała niezawodnie tylko na niektórych pulpitach.\nNIE działa na KDE, GNOME ani COSMIC."
|
||||
},
|
||||
"AUTOSTART_APPS": "Aplikacje do uruchomienia przy starcie"
|
||||
"AUTOSTART_APPS": "Aplikacje auto-start",
|
||||
"HANDSFREE_POINTER": "Tryb bez użycia rąk",
|
||||
"HANDSFREE_POINTER_HELP": "Wejście do użycia, gdy kontrolery ruchu\nsą niedostępne. Lewy szczyptak to chwyt,\nprawy to kliknięcie.",
|
||||
"UI_GRADIENT_INTENSITY": "Intensywność gradientu UI",
|
||||
"RESET_PLAYSPACE": "Zresetuj przestrzeń gry",
|
||||
"RESET_PLAYSPACE_HELP": "Wyczyść przesunięcie przestrzeni gry.",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION": "Blokuj pozy podczas interakcji z klawiaturą",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blokuje odbieranie póz przez grę, gdy kursor myszy znajduje się nad klawiaturą i włączona jest opcja 'Blokuj dane wejściowe z gry'",
|
||||
"LANGUAGE": "Język",
|
||||
"REQUIRES_RESTART": "Wymaga restartu",
|
||||
"MISC": "Różne",
|
||||
"GRID_OPACITY": "Przezroczystość siatki podłogowej",
|
||||
"GRID_OPACITY_HELP": "Przezroczystość siatki podłogowej, gdy włączony jest skybox",
|
||||
"BROWSE_ONLINE_CATALOG": "Przeglądaj katalog online...",
|
||||
"BROWSE_SKYMAPS": "Przeglądaj skymaps",
|
||||
"COLOR_KEYING": "Kluczowanie kolorem",
|
||||
"NO_SKYMAPS_FOUND": "Nie znaleziono skymap",
|
||||
"SELECT_VARIANT": "Wybierz wariant",
|
||||
"SHOW_WELCOME_SCREEN": "Pokaż ekran powitalny",
|
||||
"SKYBOX": "Skymap",
|
||||
"SKYMAP_ALREADY_DOWNLOADED": "Ta skymapa została już pobrana. Wybierz żądaną akcję.",
|
||||
"WATCH_VIEW_ANGLE": "Kąty widzenia Watch",
|
||||
"WATCH_VIEW_ANGLE_HELP": "Kontroluj, jak zegarek zanika",
|
||||
"BINDINGS": {
|
||||
"COMP": {
|
||||
"CLICK": "Kliknięcie",
|
||||
"FORCE": "Siła",
|
||||
"TOUCH": "Dotyk",
|
||||
"VALUE": "Wartość",
|
||||
"PROXIMITY": "Bliskość",
|
||||
"X_AXIS": "Oś X",
|
||||
"Y_AXIS": "Oś Y"
|
||||
},
|
||||
"TYPE": {
|
||||
"BUMPER": "Bumper",
|
||||
"DPAD_UP": "D-pad w górę",
|
||||
"DPAD_DOWN": "D-pad w dół",
|
||||
"DPAD_LEFT": "D-pad w lewo",
|
||||
"DPAD_RIGHT": "D-pad w prawo",
|
||||
"JOYSTICK": "Joystick",
|
||||
"MENU": "Menu",
|
||||
"SHOULDER": "Boczny przycisk",
|
||||
"SQUEEZE": "Chwyt",
|
||||
"SYSTEM": "System",
|
||||
"THUMBREST": "Thumbrest",
|
||||
"THUMBSTICK": "Thumbstick",
|
||||
"TRACKPAD": "Trackpad",
|
||||
"TRIGGER": "Spust",
|
||||
"VIEW": "Widok"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "Dowolny",
|
||||
"DOUBLE": "Podwójne kliknięcie",
|
||||
"TRIPLE": "Potrójne kliknięcie",
|
||||
"TYPE": "Liczba kliknięć"
|
||||
},
|
||||
"ACTION": {
|
||||
"CLICK": "Kliknięcie*",
|
||||
"GRAB": "Chwyć*",
|
||||
"ALT_CLICK": "Własne polecenie shell exec (ustaw alt_click w konfiguracji)",
|
||||
"SHOW_HIDE": "Pokaż, ukryj, wycentruj ponownie*",
|
||||
"TOGGLE_DASHBOARD": "Przełącz dashboard",
|
||||
"SPACE_DRAG": "Przesuwanie Playspace",
|
||||
"SPACE_ROTATE": "Obrót Playspace",
|
||||
"SPACE_RESET": "Resetowanie playspace",
|
||||
"CLICK_MODIFIER_RIGHT": "Modyfikator prawego kliknięcia",
|
||||
"CLICK_MODIFIER_MIDDLE": "Modyfikator środkowego kliknięcia",
|
||||
"MOVE_MOUSE": "Ruszaj myszą (jeśli domyślnie wyłączone)",
|
||||
"SCROLL": "Przewijanie*"
|
||||
},
|
||||
"LEFT": "Lewy",
|
||||
"RIGHT": "Prawy",
|
||||
"COMPONENT": "Typ aktywacji",
|
||||
"SUBPATH": "Sterowanie aktywacją",
|
||||
"THRESHOLD": "Aktywuj po przekroczeniu górnej wartości\nDezaktywuj po spadku poniżej dolnej wartości"
|
||||
},
|
||||
"ENABLED": "Włączone",
|
||||
"INPUT_EMULATION_METHOD": "Metoda emulacji wejścia",
|
||||
"INPUT_EMULATION_METHOD_HELP": "Spróbuj zmienić tę opcję w przypadku, gdy wejście myszy lub\nklawiatury nie jest rejestrowane.",
|
||||
"INPUT_PROFILES": "Zmień klawiszologię",
|
||||
"INPUT_PROFILES_HELP": "Przypisania przycisków kontrolera OpenXR",
|
||||
"NOT_SUPPORTED": "Nieobsługiwane",
|
||||
"SPACE_DRAG": "Space-drag",
|
||||
"SPACE_GRAVITY_DAMPING": "Spowalnianie",
|
||||
"SPACE_GRAVITY_DAMPING_HELP": "Sztuczne spowalnianie mające na celu zatrzymywanie ruchu po pewnym czasie. 0.1 - wysokie spowolnienie, 1.0 - brak spowolnienia",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH": "Siła wyrzutu",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Mnożnik intensywności siły grawitacyjnego wyrzutu po użyciu funkcji space-drag.\n0.0 - brak ruchu, 2.0 - podwójna intensywność",
|
||||
"SPACE_GRAVITY_GRAVITY": "Grawitacja",
|
||||
"SPACE_GRAVITY_GRAVITY_HELP": "Wielkość siły działającej w dół. 0.0 - brak grawitacji",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION": "Tarcie podłoża",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "Moc tarcia spowalniającego Cię podczas kontaktu z podłożem.\n0.0 - brak tarcia (jak na lodzie), 1.0 - chropowata powierzchnia",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT": "Wysokość podłogi",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "Pozycja Y, w której znajduje się podłoga. Grawitacja przestaje działać po osiągnięciu tej wysokości.",
|
||||
"SAVE": "Zapisz",
|
||||
"CANCEL": "Anuluj"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
|
||||
"APPLICATIONS": "Aplikacje",
|
||||
|
|
@ -97,7 +196,6 @@
|
|||
"HELLO_USER": "Witaj, {USER}!",
|
||||
"HIDE": "Ukryj",
|
||||
"HOME_SCREEN": "Ekran główny",
|
||||
"LIST_OF_PROCESSES": "Lista procesów",
|
||||
"MONADO_RUNTIME": "Środowisko Monado",
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "Rozdzielczość"
|
||||
|
|
@ -106,20 +204,12 @@
|
|||
"SETTINGS": "Ustawienia",
|
||||
"SHOW": "Pokaż",
|
||||
"WIDTH": "Szerokość",
|
||||
"PROCESSES": "Procesy",
|
||||
"PROCESS_LIST": {
|
||||
"NO_PROCESSES_FOUND": "Nie znaleziono procesów",
|
||||
"LOCATED_ON": "na",
|
||||
"TERMINATE_PROCESS_NAMED_X": "Zakończ proces \"{PROCESS_NAME}\""
|
||||
},
|
||||
"FAILED_TO_LAUNCH_APPLICATION": "Nie udało się uruchomić aplikacji:",
|
||||
"NO_WINDOWS_FOUND": "Nie znaleziono okien",
|
||||
"WINDOW_OPTIONS": "Opcje okna",
|
||||
"APPLICATION_STARTED": "Aplikacja uruchomiona",
|
||||
"LIST_OF_WINDOWS": "Lista okien",
|
||||
"CLOSE_WINDOW": "Zamknij okno",
|
||||
"GAME_LIST": {
|
||||
"NO_GAMES_FOUND": "Nie znaleziono gier"
|
||||
"NO_GAMES_FOUND": "Nie znaleziono gier",
|
||||
"RUNNING_GAMES_LIST": "Lista uruchomionych gier"
|
||||
},
|
||||
"TERMINATE_PROCESS": "Zakończ proces",
|
||||
"GAME_LAUNCHED": "Gra uruchomiona",
|
||||
|
|
@ -149,5 +239,23 @@
|
|||
"AUTOSTART": "Uruchom automatycznie przy starcie",
|
||||
"LAUNCH": "Uruchom"
|
||||
},
|
||||
"DISPLAY_BRIGHTNESS": "Jasność wyświetlacza"
|
||||
"DISPLAY_BRIGHTNESS": "Jasność wyświetlacza",
|
||||
"PROCESS_LIST": "Lista procesów",
|
||||
"REFRESH": "Odśwież",
|
||||
"PROCESS": {
|
||||
"STOP": "Zatrzymaj",
|
||||
"FORCE_KILL": "Wymuś zakończenie"
|
||||
},
|
||||
"DEBUG_INFO": "Informacje debugowania",
|
||||
"CREATION_DATE": "Data utworzenia",
|
||||
"DOWNLOADER": "Pobieranie",
|
||||
"DOWNLOAD_AGAIN": "Pobierz ponownie",
|
||||
"DOWNLOADING_FILE": "Pobieranie pliku...",
|
||||
"GETTING_STARTED": "Rozpoczęcie",
|
||||
"MODIFICATION_DATE": "Data modyfikacji",
|
||||
"LOADING": "Ładowanie...",
|
||||
"APPLY": "Zastosuj",
|
||||
"RELOAD_FROM_DISK": "Przeładuj z dysku",
|
||||
"TARGET_PATH": "Ścieżka docelowa",
|
||||
"VERSION": "Wersja"
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
{
|
||||
"ACTIONS": {
|
||||
"RECENTER_PLAYSPACE": "重置游玩区中心"
|
||||
},
|
||||
"APP_LAUNCHER": {
|
||||
"ASPECT": {
|
||||
"SEMI_TALL": "略高",
|
||||
"SEMI_WIDE": "略宽",
|
||||
"SQUARE": "正方形",
|
||||
"TALL": "高",
|
||||
"WIDE": "宽"
|
||||
},
|
||||
"ASPECT_TITLE": "比例",
|
||||
"AUTOSTART": "启动时自动运行",
|
||||
"LAUNCH": "启动",
|
||||
"MODE": {
|
||||
"CAGE": "兼容模式 (Cage)",
|
||||
"NATIVE": "原生模式"
|
||||
},
|
||||
"POS": {
|
||||
"ANCHORED": "锚定",
|
||||
"ANCHORED_HELP": "相对于中心标记保持固定。",
|
||||
"FLOATING": "悬浮",
|
||||
"FLOATING_HELP": "独立移动,显示时自动重置中心。",
|
||||
"STATIC": "静态",
|
||||
"STATIC_HELP": "不属于任何集合。不会重置中心。"
|
||||
},
|
||||
"POS_TITLE": "定位",
|
||||
"RES_TITLE": "分辨率"
|
||||
},
|
||||
"APP_SETTINGS": {
|
||||
"ALLOW_SLIDING": "抓取时允许摇杆交互",
|
||||
"ANIMATION_SPEED": "UI 动画速度",
|
||||
"BLOCK_GAME_INPUT": "屏蔽游戏输入",
|
||||
"BLOCK_GAME_INPUT_HELP": "悬停在覆盖层上时屏蔽所有输入",
|
||||
"BLOCK_GAME_INPUT_IGNORE_WATCH": "屏蔽输入时忽略手表",
|
||||
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "悬停在手表上时不屏蔽输入",
|
||||
"CAPTURE_METHOD": "Wayland 屏幕采集",
|
||||
"CAPTURE_METHOD_HELP": "如果您遇到黑屏或花屏,请尝试更改此项",
|
||||
"CLEAR_PIPEWIRE_TOKENS": "清除 PipeWire 令牌",
|
||||
"CLEAR_PIPEWIRE_TOKENS_HELP": "下次启动时提示选择屏幕",
|
||||
"CLEAR_SAVED_STATE": "清除保存的状态",
|
||||
"CLEAR_SAVED_STATE_HELP": "重置集合与覆盖层位置",
|
||||
"CLICK_FREEZE_TIME_MS": "点击冻结时间 (毫秒)",
|
||||
"CLICK_FREEZE_TIME_MS_HELP": "有助于提高双击精度",
|
||||
"CLOCK_12H": "12 小时制时钟",
|
||||
"CONTROLS": "控制",
|
||||
"DELETE_ALL_CONFIGS": "擦除配置",
|
||||
"DELETE_ALL_CONFIGS_HELP": "从 conf.d 中删除所有配置文件",
|
||||
"DOUBLE_CURSOR_FIX": "双光标修复",
|
||||
"DOUBLE_CURSOR_FIX_HELP": "如果您看到两个光标,请启用此项",
|
||||
"FEATURES": "功能",
|
||||
"FOCUS_FOLLOWS_MOUSE_MODE": "触摸扳机时移动鼠标",
|
||||
"HIDE_GRAB_HELP": "隐藏抓取帮助",
|
||||
"HIDE_USERNAME": "隐藏用户名",
|
||||
"INVERT_SCROLL_DIRECTION_X": "反转水平滚动方向",
|
||||
"INVERT_SCROLL_DIRECTION_Y": "反转垂直滚动方向",
|
||||
"KEYBOARD_MIDDLE_CLICK": "键盘中键点击",
|
||||
"KEYBOARD_MIDDLE_CLICK_HELP": "使用紫色激光打字时的修饰键",
|
||||
"KEYBOARD_SOUND_ENABLED": "键盘音效",
|
||||
"LEFT_HANDED_MOUSE": "左手鼠标",
|
||||
"LEFT_HANDED_MOUSE_HELP": "如果鼠标按钮反置,请使用此项",
|
||||
"LONG_PRESS_DURATION": "长按持续时间",
|
||||
"LOOK_AND_FEEL": "外观与体验",
|
||||
"MISC": "杂项",
|
||||
"NOTIFICATIONS_ENABLED": "启用通知",
|
||||
"NOTIFICATIONS_SOUND_ENABLED": "通知音效",
|
||||
"OPAQUE_BACKGROUND": "不透明背景",
|
||||
"OPTION": {
|
||||
"AUTO": "自动",
|
||||
"AUTO_HELP": "如果支持,则使用 ScreenCopy GPU,\n否则使用 PipeWire GPU。",
|
||||
"PIPEWIRE_HELP": "快速 GPU 采集,\n所有桌面环境的标准方式。",
|
||||
"PW_FALLBACK_HELP": "高 CPU 占用的慢速方法。\n在 PipeWire GPU 不起作用时尝试。",
|
||||
"SCREENCOPY_GPU_HELP": "快速,无屏幕共享弹窗。\n支持:Hyprland, Niri, River, Sway",
|
||||
"SCREENCOPY_HELP": "慢速,无屏幕共享弹窗。\n支持:Hyprland, Niri, River, Sway",
|
||||
"NONE": "无",
|
||||
"HMD_PINCH": "HMD + 捏合",
|
||||
"EYE_PINCH": "眼睛 + 捏合",
|
||||
"EYE_ONLY": "仅眼球",
|
||||
"HMD_ONLY": "仅限头显",
|
||||
"NONE_INPUT_HELP": "不模拟鼠标和键盘。\n将无法与屏幕进行交互。",
|
||||
"UINPUT": "设备模拟",
|
||||
"UINPUT_HELP": "使用 uinput 模块来模拟设备。\n您的用户必须处于 input 用户组中。\n已知在大多数桌面上运行良好。",
|
||||
"WL_VIRTUAL": "Wayland 虚拟输入",
|
||||
"WL_VIRTUAL_HELP": "使用 zwlr_virtual_pointer 和 zwp_virtual_keyboard 向 Wayland 合成器发送事件。\n仅在部分桌面环境下能可靠工作。\n在 KDE、GNOME 或 COSMIC 上无法工作。"
|
||||
},
|
||||
"POINTER_LERP_FACTOR": "指针平滑",
|
||||
"RESTART_SOFTWARE": "重启软件",
|
||||
"RESTART_SOFTWARE_HELP": "应用需要重启的设置",
|
||||
"ROUND_MULTIPLIER": "UI 边缘圆角",
|
||||
"SCREEN_RENDER_DOWN": "以较低分辨率渲染屏幕",
|
||||
"SCREEN_RENDER_DOWN_HELP": "有助于解决高分辨率屏幕的锯齿问题",
|
||||
"SCROLL_SPEED": "滚动速度",
|
||||
"SETS_ON_WATCH": "在手表上显示集合",
|
||||
"SPACE_DRAG_MULTIPLIER": "空间拖拽倍率",
|
||||
"SPACE_DRAG_UNLOCKED": "允许在所有轴上进行空间拖拽",
|
||||
"SPACE_ROTATE_UNLOCKED": "允许在所有轴上进行空间旋转",
|
||||
"TROUBLESHOOTING": "故障排除",
|
||||
"UPRIGHT_SCREEN_FIX": "垂直屏幕修复",
|
||||
"UPRIGHT_SCREEN_FIX_HELP": "修复某些桌面上的垂直屏幕问题",
|
||||
"USE_PASSTHROUGH": "启用穿透",
|
||||
"USE_PASSTHROUGH_HELP": "如果 XR 运行时支持,则允许穿透",
|
||||
"USE_SKYBOX": "启用天空盒",
|
||||
"USE_SKYBOX_HELP": "如果没有场景应用或穿透,则显示天空盒",
|
||||
"XWAYLAND_BY_DEFAULT": "默认以兼容模式运行应用",
|
||||
"AUTOSTART_APPS": "开机启动应用",
|
||||
"HANDSFREE_POINTER": "免提模式",
|
||||
"HANDSFREE_POINTER_HELP": "当运动控制器不可用时使用的输入。\n左手捏合为抓取,右手为点击。",
|
||||
"UI_GRADIENT_INTENSITY": "UI 渐变强度",
|
||||
"RESET_PLAYSPACE": "重置游戏空间",
|
||||
"RESET_PLAYSPACE_HELP": "清除舞台空间偏移。",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION": "与键盘交互时阻止姿势",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "当键盘悬停且启用“阻止游戏输入”时,阻止游戏接收姿势",
|
||||
"LANGUAGE": "语言",
|
||||
"REQUIRES_RESTART": "需要重启",
|
||||
"GRID_OPACITY": "地面网格不透明度",
|
||||
"GRID_OPACITY_HELP": "启用天空盒时地板网格的不透明度",
|
||||
"BROWSE_ONLINE_CATALOG": "浏览在线目录...",
|
||||
"BROWSE_SKYMAPS": "浏览 Skymaps",
|
||||
"COLOR_KEYING": "颜色键控",
|
||||
"NO_SKYMAPS_FOUND": "未找到 Skymaps",
|
||||
"SELECT_VARIANT": "选择变体",
|
||||
"SHOW_WELCOME_SCREEN": "显示欢迎屏幕",
|
||||
"SKYBOX": "Skybox",
|
||||
"SKYMAP_ALREADY_DOWNLOADED": "此 Skymap 已下载。请选择所需操作。",
|
||||
"WATCH_VIEW_ANGLE": "Watch 视角角度",
|
||||
"WATCH_VIEW_ANGLE_HELP": "控制表盘的淡出方式",
|
||||
"BINDINGS": {
|
||||
"COMP": {
|
||||
"CLICK": "点击",
|
||||
"FORCE": "力度",
|
||||
"TOUCH": "触摸",
|
||||
"VALUE": "值",
|
||||
"PROXIMITY": "临近度",
|
||||
"X_AXIS": "X 轴",
|
||||
"Y_AXIS": "Y 轴"
|
||||
},
|
||||
"TYPE": {
|
||||
"BUMPER": "侧键",
|
||||
"DPAD_UP": "方向键上",
|
||||
"DPAD_DOWN": "方向键下",
|
||||
"DPAD_LEFT": "方向键左",
|
||||
"DPAD_RIGHT": "方向键右",
|
||||
"JOYSTICK": "摇杆",
|
||||
"MENU": "菜单",
|
||||
"SHOULDER": "肩键",
|
||||
"SQUEEZE": "抓取",
|
||||
"SYSTEM": "系统",
|
||||
"THUMBREST": "拇指托",
|
||||
"THUMBSTICK": "摇杆",
|
||||
"TRACKPAD": "触控板",
|
||||
"TRIGGER": "扳机键",
|
||||
"VIEW": "视图"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "任意",
|
||||
"DOUBLE": "双击",
|
||||
"TRIPLE": "三击",
|
||||
"TYPE": "点击次数"
|
||||
},
|
||||
"ACTION": {
|
||||
"CLICK": "点击*",
|
||||
"GRAB": "抓取*",
|
||||
"ALT_CLICK": "自定义 Shell 执行 (在配置中设置 alt_click)",
|
||||
"SHOW_HIDE": "显示、隐藏、重新中心化*",
|
||||
"TOGGLE_DASHBOARD": "切换控制面板",
|
||||
"SPACE_DRAG": "Playspace 拖拽",
|
||||
"SPACE_ROTATE": "Playspace 旋转",
|
||||
"SPACE_RESET": "Playspace 重置",
|
||||
"CLICK_MODIFIER_RIGHT": "右键修饰键",
|
||||
"CLICK_MODIFIER_MIDDLE": "中键修饰键",
|
||||
"MOVE_MOUSE": "移动鼠标 (如果默认关闭)",
|
||||
"SCROLL": "滚动*"
|
||||
},
|
||||
"LEFT": "左侧",
|
||||
"RIGHT": "右",
|
||||
"COMPONENT": "触发类型",
|
||||
"SUBPATH": "动作控制",
|
||||
"THRESHOLD": "高于上限值时激活\n低于下限值时停用"
|
||||
},
|
||||
"ENABLED": "已启用",
|
||||
"INPUT_EMULATION_METHOD": "输入仿真方法",
|
||||
"INPUT_EMULATION_METHOD_HELP": "如果鼠标或键盘输入未被识别,请尝试更改此设置。",
|
||||
"INPUT_PROFILES": "更改输入绑定",
|
||||
"INPUT_PROFILES_HELP": "OpenXR 控制器输入绑定",
|
||||
"NOT_SUPPORTED": "不支持",
|
||||
"ENABLE_WATCH": "启用手表",
|
||||
"SPACE_DRAG": "空间拖拽",
|
||||
"SPACE_GRAVITY_DAMPING": "阻尼",
|
||||
"SPACE_GRAVITY_DAMPING_HELP": "用于减缓移动速度的人造阻力。0.1 - 高阻力,1.0 - 无阻力",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH": "投掷力度",
|
||||
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Space-drag 后的重力发射力强度倍数。\n0.0 - 完全没有位移,2.0 - 双倍强度",
|
||||
"SPACE_GRAVITY_GRAVITY": "重力",
|
||||
"SPACE_GRAVITY_GRAVITY_HELP": "向下作用的力的大小。0.0 - 无重力",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION": "地面摩擦力",
|
||||
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "如果你接触地面时,减慢你移动速度的摩擦力大小。\n0.0 - 无摩擦(就像在冰面上一样),1.0 - 粗糙表面",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT": "地面高度",
|
||||
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "地面所在 Y 轴位置。达到该高度时重力停止。",
|
||||
"SAVE": "保存",
|
||||
"CANCEL": "取消"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "应用启动器",
|
||||
"APPLICATION_STARTED": "应用已启动",
|
||||
"APPLICATIONS": "应用",
|
||||
"AUDIO": {
|
||||
"AUTO_SWITCH_TO_VR_AUDIO": "自动切换到 VR 音频",
|
||||
"CARDS": "声卡",
|
||||
"FAILED_TO_SWITCH_MICROPHONE": "切换麦克风失败",
|
||||
"MICROPHONE_SET_SUCCESSFULLY": "麦克风设置成功",
|
||||
"MICROPHONES": "麦克风",
|
||||
"NO_VR_MICROPHONE_SWITCH_MANUALLY": "未找到 VR 麦克风。请手动切换。",
|
||||
"NO_VR_SPEAKERS_FOUND_SWITCH_MANUALLY": "未找到 VR 扬声器。请手动切换。",
|
||||
"SELECT_AUDIO_CARD_PROFILE": "选择声卡配置",
|
||||
"SETTINGS": "音频设置",
|
||||
"SPEAKERS": "扬声器",
|
||||
"SPEAKERS_SET_SUCCESSFULLY": "扬声器设置成功",
|
||||
"VOLUME": "音量"
|
||||
},
|
||||
"CLOSE_WINDOW": "关闭窗口",
|
||||
"DISPLAY_BRIGHTNESS": "显示亮度",
|
||||
"FAILED_TO_LAUNCH_APPLICATION": "启动应用失败:",
|
||||
"GAME_LAUNCHED": "游戏已启动",
|
||||
"GAME_LIST": {
|
||||
"NO_GAMES_FOUND": "未找到游戏",
|
||||
"RUNNING_GAMES_LIST": "正在运行的游戏列表"
|
||||
},
|
||||
"GAMES": "游戏",
|
||||
"GENERAL_SETTINGS": "通用设置",
|
||||
"HEIGHT": "高度",
|
||||
"HELLO": "你好!",
|
||||
"HELLO_USER": "你好,{USER}!",
|
||||
"HIDE": "隐藏",
|
||||
"HOME_SCREEN": "主页",
|
||||
"MONADO_RUNTIME": "Monado 运行时",
|
||||
"POPUP_ADD_DISPLAY": {
|
||||
"RESOLUTION": "分辨率"
|
||||
},
|
||||
"REMOVE": "移除",
|
||||
"SETTINGS": "设置",
|
||||
"SHOW": "显示",
|
||||
"TERMINATE_PROCESS": "终止进程",
|
||||
"WIDTH": "宽度",
|
||||
"PROCESS_LIST": "进程列表",
|
||||
"REFRESH": "刷新",
|
||||
"PROCESS": {
|
||||
"STOP": "停止",
|
||||
"FORCE_KILL": "强制关闭"
|
||||
},
|
||||
"DEBUG_INFO": "调试信息",
|
||||
"CREATION_DATE": "创建日期",
|
||||
"DOWNLOADER": "下载器",
|
||||
"DOWNLOAD_AGAIN": "重新下载",
|
||||
"DOWNLOADING_FILE": "正在下载文件...",
|
||||
"GETTING_STARTED": "入门指南",
|
||||
"MODIFICATION_DATE": "修改日期",
|
||||
"LOADING": "正在加载...",
|
||||
"APPLY": "应用",
|
||||
"RELOAD_FROM_DISK": "从磁盘重新加载",
|
||||
"TARGET_PATH": "目标路径",
|
||||
"VERSION": "版本"
|
||||
}
|
||||
|
|
@ -5,41 +5,52 @@ use glam::Vec2;
|
|||
use wgui::{
|
||||
assets::{AssetPath, AssetProvider},
|
||||
components::button::ComponentButton,
|
||||
event::StyleSetRequest,
|
||||
font_config::WguiFontConfig,
|
||||
globals::WguiGlobals,
|
||||
i18n::Translation,
|
||||
layout::{Layout, LayoutParams, LayoutUpdateParams, LayoutUpdateResult, WidgetID},
|
||||
layout::{Layout, LayoutParams, LayoutTask, LayoutUpdateParams, LayoutUpdateResult, WidgetID},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
renderer_vk::text::custom_glyph::CustomGlyphData,
|
||||
taffy::{self},
|
||||
task::Tasks,
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle},
|
||||
theme::WguiTheme,
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite},
|
||||
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
|
||||
};
|
||||
use wlx_common::{audio, dash_interface::BoxDashInterface, timestep::Timestep};
|
||||
use wlx_common::{
|
||||
async_executor::AsyncExecutor,
|
||||
audio,
|
||||
dash_interface::{BoxDashInterface, RecenterMode},
|
||||
locale::WayVRLangProvider,
|
||||
timestep::{self, Timestep},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
assets,
|
||||
tab::{
|
||||
apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, processes::TabProcesses, settings::TabSettings,
|
||||
Tab, TabType,
|
||||
Tab, TabType, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, settings::TabSettings,
|
||||
welcome::TabWelcome,
|
||||
},
|
||||
util::{
|
||||
popup_manager::{MountPopupParams, PopupManager, PopupManagerParams},
|
||||
popup_manager::{MountPopupOnceParams, PopupManager, PopupManagerParams},
|
||||
toast_manager::ToastManager,
|
||||
various::AsyncExecutor,
|
||||
},
|
||||
views,
|
||||
};
|
||||
|
||||
pub struct FrontendWidgets {
|
||||
pub id_label_time: WidgetID,
|
||||
pub id_rect_content: WidgetID,
|
||||
id_label_time: WidgetID,
|
||||
id_rect_content: WidgetID,
|
||||
id_sprite_titlebar_icon: WidgetID,
|
||||
id_label_titlebar_title: WidgetID,
|
||||
}
|
||||
|
||||
pub type FrontendTasks = Tasks<FrontendTask>;
|
||||
|
||||
pub struct Frontend<T> {
|
||||
pub layout: Layout,
|
||||
globals: WguiGlobals,
|
||||
pub globals: WguiGlobals,
|
||||
|
||||
pub interface: BoxDashInterface<T>,
|
||||
|
||||
|
|
@ -77,9 +88,11 @@ pub struct FrontendUpdateResult {
|
|||
pub sounds_to_play: Vec<SoundType>,
|
||||
}
|
||||
|
||||
pub struct InitParams<T> {
|
||||
pub struct InitParams<'a, T> {
|
||||
pub interface: BoxDashInterface<T>,
|
||||
pub lang_provider: &'a WayVRLangProvider,
|
||||
pub has_monado: bool,
|
||||
pub theme: Rc<WguiTheme>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -93,7 +106,7 @@ pub enum FrontendTask {
|
|||
SetTab(TabType),
|
||||
RefreshClock,
|
||||
RefreshBackground,
|
||||
MountPopup(MountPopupParams),
|
||||
MountPopupOnce(MountPopupOnceParams),
|
||||
RefreshPopupManager,
|
||||
ShowAudioSettings,
|
||||
UpdateAudioSettingsView,
|
||||
|
|
@ -104,7 +117,7 @@ pub enum FrontendTask {
|
|||
}
|
||||
|
||||
impl<T: 'static> Frontend<T> {
|
||||
pub fn new(params: InitParams<T>, data: &mut T) -> anyhow::Result<Frontend<T>> {
|
||||
pub fn new(params: InitParams<T>) -> anyhow::Result<Frontend<T>> {
|
||||
let mut assets = Box::new(assets::Asset {});
|
||||
|
||||
let font_binary_bold = assets.load_from_path_gzip("Quicksand-Bold.ttf.gz")?;
|
||||
|
|
@ -113,7 +126,7 @@ impl<T: 'static> Frontend<T> {
|
|||
|
||||
let globals = WguiGlobals::new(
|
||||
assets,
|
||||
wgui::globals::Defaults::default(),
|
||||
params.lang_provider,
|
||||
&WguiFontConfig {
|
||||
binaries: vec![&font_binary_regular, &font_binary_bold, &font_binary_light],
|
||||
family_name_sans_serif: "Quicksand",
|
||||
|
|
@ -129,7 +142,10 @@ impl<T: 'static> Frontend<T> {
|
|||
path: AssetPath::BuiltIn("gui/dashboard.xml"),
|
||||
extra: Default::default(),
|
||||
},
|
||||
&LayoutParams { resize_to_parent: true },
|
||||
LayoutParams {
|
||||
resize_to_parent: true,
|
||||
theme: params.theme,
|
||||
},
|
||||
)?;
|
||||
|
||||
let id_popup_manager = state.get_widget_id("popup_manager")?;
|
||||
|
|
@ -144,6 +160,8 @@ impl<T: 'static> Frontend<T> {
|
|||
|
||||
let id_label_time = state.get_widget_id("label_time")?;
|
||||
let id_rect_content = state.get_widget_id("rect_content")?;
|
||||
let id_sprite_titlebar_icon = state.get_widget_id("sprite_titlebar_icon")?;
|
||||
let id_label_titlebar_title = state.get_widget_id("label_titlebar_title")?;
|
||||
|
||||
let timestep = Timestep::new(60.0);
|
||||
|
||||
|
|
@ -157,6 +175,8 @@ impl<T: 'static> Frontend<T> {
|
|||
widgets: FrontendWidgets {
|
||||
id_label_time,
|
||||
id_rect_content,
|
||||
id_sprite_titlebar_icon,
|
||||
id_label_titlebar_title,
|
||||
},
|
||||
timestep,
|
||||
interface: params.interface,
|
||||
|
|
@ -169,8 +189,8 @@ impl<T: 'static> Frontend<T> {
|
|||
};
|
||||
|
||||
// init some things first
|
||||
frontend.update_background(data)?;
|
||||
frontend.update_time(data)?;
|
||||
frontend.tasks.push(FrontendTask::RefreshBackground);
|
||||
frontend.tasks.push(FrontendTask::RefreshClock);
|
||||
|
||||
Frontend::register_widgets(&mut frontend)?;
|
||||
|
||||
|
|
@ -183,10 +203,19 @@ impl<T: 'static> Frontend<T> {
|
|||
|
||||
fn play_sound(&mut self, audio_system: &mut audio::AudioSystem, sound_type: SoundType) -> anyhow::Result<()> {
|
||||
let mut assets = self.globals.assets_builtin();
|
||||
let sample = audio::AudioSample::from_mp3(&assets.load_from_path(match sound_type {
|
||||
|
||||
let path = match sound_type {
|
||||
SoundType::Startup => "sound/startup.mp3",
|
||||
SoundType::Launch => "sound/app_start.mp3",
|
||||
})?)?;
|
||||
};
|
||||
|
||||
// try loading a custom sound; if one doesn't exist (or it failed to load), use the built-in asset
|
||||
let sound_bytes = match audio::AudioSample::try_bytes_from_config(path) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(_) => assets.load_from_path(path)?.into(),
|
||||
};
|
||||
|
||||
let sample = audio::AudioSample::from_mp3(&sound_bytes)?;
|
||||
audio_system.play_sample(&sample);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -198,8 +227,10 @@ impl<T: 'static> Frontend<T> {
|
|||
self.process_task(&mut params, task)?;
|
||||
}
|
||||
|
||||
let time_ms = timestep::get_micros() / 1000;
|
||||
|
||||
if let Some(mut tab) = self.current_tab.take() {
|
||||
tab.update(self, params.data)?;
|
||||
tab.update(self, time_ms as u32, params.data)?;
|
||||
|
||||
self.current_tab = Some(tab);
|
||||
}
|
||||
|
|
@ -237,7 +268,7 @@ impl<T: 'static> Frontend<T> {
|
|||
{
|
||||
// always 30 times per second
|
||||
while self.timestep.on_tick() {
|
||||
self.toast_manager.tick(&self.globals, &mut self.layout)?;
|
||||
self.toast_manager.tick(&mut self.layout)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,13 +284,12 @@ impl<T: 'static> Frontend<T> {
|
|||
}
|
||||
|
||||
fn update_time(&mut self, data: &mut T) -> anyhow::Result<()> {
|
||||
let mut c = self.layout.start_common();
|
||||
let mut common = c.common();
|
||||
|
||||
{
|
||||
let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(self.widgets.id_label_time) else {
|
||||
anyhow::bail!("");
|
||||
};
|
||||
let mut common = self.layout.common();
|
||||
let mut label = common
|
||||
.state
|
||||
.widgets
|
||||
.cast_as::<WidgetLabel>(self.widgets.id_label_time)?;
|
||||
|
||||
let now = chrono::Local::now();
|
||||
let hours = now.hour();
|
||||
|
|
@ -276,31 +306,26 @@ impl<T: 'static> Frontend<T> {
|
|||
label.set_text(&mut common, Translation::from_raw_text(&text));
|
||||
}
|
||||
|
||||
c.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mount_popup(&mut self, params: MountPopupParams, data: &mut T) -> anyhow::Result<()> {
|
||||
fn mount_popup_once(&mut self, params: MountPopupOnceParams, data: &mut T) -> anyhow::Result<()> {
|
||||
let config = self.interface.general_config(data);
|
||||
|
||||
self.popup_manager.mount_popup(
|
||||
self.globals.clone(),
|
||||
&mut self.layout,
|
||||
self.tasks.clone(),
|
||||
params,
|
||||
config,
|
||||
)?;
|
||||
self
|
||||
.popup_manager
|
||||
.mount_popup_once(&self.globals, &mut self.layout, &self.tasks, params, config)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn refresh_popup_manager(&mut self) -> anyhow::Result<()> {
|
||||
let mut c = self.layout.start_common();
|
||||
self.popup_manager.refresh(c.common().alterables);
|
||||
c.finish()?;
|
||||
self.popup_manager.refresh(&mut self.layout.alterables);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_background(&mut self, data: &mut T) -> anyhow::Result<()> {
|
||||
self.layout.mark_redraw();
|
||||
|
||||
let Some(mut rect) = self
|
||||
.layout
|
||||
.state
|
||||
|
|
@ -327,7 +352,7 @@ impl<T: 'static> Frontend<T> {
|
|||
FrontendTask::SetTab(tab_type) => self.set_tab(params.data, tab_type)?,
|
||||
FrontendTask::RefreshClock => self.update_time(params.data)?,
|
||||
FrontendTask::RefreshBackground => self.update_background(params.data)?,
|
||||
FrontendTask::MountPopup(popup_params) => self.mount_popup(popup_params, params.data)?,
|
||||
FrontendTask::MountPopupOnce(popup_params) => self.mount_popup_once(popup_params, params.data)?,
|
||||
FrontendTask::RefreshPopupManager => self.refresh_popup_manager()?,
|
||||
FrontendTask::ShowAudioSettings => self.action_show_audio_settings()?,
|
||||
FrontendTask::UpdateAudioSettingsView => self.action_update_audio_settings()?,
|
||||
|
|
@ -339,17 +364,59 @@ impl<T: 'static> Frontend<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn set_tab_title(&mut self, translation: &str, icon: &str) -> anyhow::Result<()> {
|
||||
let mut common = self.layout.common();
|
||||
|
||||
{
|
||||
let mut label = common
|
||||
.state
|
||||
.widgets
|
||||
.cast_as::<WidgetLabel>(self.widgets.id_label_titlebar_title)?;
|
||||
label.set_text(&mut common, Translation::from_translation_key(translation));
|
||||
}
|
||||
|
||||
{
|
||||
let mut sprite = common
|
||||
.state
|
||||
.widgets
|
||||
.cast_as::<WidgetSprite>(self.widgets.id_sprite_titlebar_icon)?;
|
||||
sprite.set_content(
|
||||
common.alterables,
|
||||
Some(CustomGlyphData::from_assets(&self.globals, AssetPath::BuiltIn(icon))?),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_tab(&mut self, data: &mut T, tab_type: TabType) -> anyhow::Result<()> {
|
||||
log::info!("Setting tab to {tab_type:?}");
|
||||
let widget_content = self.state.fetch_widget(&self.layout.state, "content")?;
|
||||
self.layout.remove_children(widget_content.id);
|
||||
|
||||
let padding = tab_type.get_preferred_padding();
|
||||
self.layout.tasks.push(LayoutTask::SetWidgetStyle(
|
||||
widget_content.id,
|
||||
StyleSetRequest::Padding(taffy::Rect::length(padding)),
|
||||
));
|
||||
|
||||
let (tab_translation, icon_path) = match tab_type {
|
||||
TabType::Welcome => ("GETTING_STARTED", "dashboard/welcome.svg"),
|
||||
TabType::Home => ("HOME_SCREEN", "dashboard/home.svg"),
|
||||
TabType::Apps => ("APPLICATIONS", "dashboard/apps.svg"),
|
||||
TabType::Games => ("GAMES", "dashboard/games.svg"),
|
||||
TabType::Monado => ("MONADO_RUNTIME", "dashboard/monado.svg"),
|
||||
TabType::Settings => ("SETTINGS", "dashboard/settings.svg"),
|
||||
};
|
||||
|
||||
self.set_tab_title(tab_translation, icon_path)?;
|
||||
|
||||
let tab: Box<dyn Tab<T>> = match tab_type {
|
||||
TabType::Welcome => Box::new(TabWelcome::new(self, widget_content.id, data)?),
|
||||
TabType::Home => Box::new(TabHome::new(self, widget_content.id, data)?),
|
||||
TabType::Apps => Box::new(TabApps::new(self, widget_content.id, data)?),
|
||||
TabType::Games => Box::new(TabGames::new(self, widget_content.id)?),
|
||||
TabType::Monado => Box::new(TabMonado::new(self, widget_content.id)?),
|
||||
TabType::Processes => Box::new(TabProcesses::new(self, widget_content.id)?),
|
||||
TabType::Settings => Box::new(TabSettings::new(self, widget_content.id, data)?),
|
||||
};
|
||||
|
||||
|
|
@ -393,12 +460,6 @@ impl<T: 'static> Frontend<T> {
|
|||
FrontendTask::SetTab(TabType::Monado),
|
||||
);
|
||||
|
||||
// "Processes" side button
|
||||
// self.tasks.handle_button(
|
||||
// &self.state.fetch_component_as::<ComponentButton>("btn_side_processes")?,
|
||||
// FrontendTask::SetTab(TabType::Processes),
|
||||
// );
|
||||
|
||||
// "Settings" side button
|
||||
self.tasks.handle_button(
|
||||
&self.state.fetch_component_as::<ComponentButton>("btn_side_settings")?,
|
||||
|
|
@ -426,7 +487,6 @@ impl<T: 'static> Frontend<T> {
|
|||
|
||||
fn action_show_audio_settings(&mut self) -> anyhow::Result<()> {
|
||||
self.window_audio_settings.open(&mut WguiWindowParams {
|
||||
globals: &self.globals,
|
||||
position: Vec2::new(64.0, 64.0),
|
||||
layout: &mut self.layout,
|
||||
extra: WguiWindowParamsExtra {
|
||||
|
|
@ -466,7 +526,7 @@ impl<T: 'static> Frontend<T> {
|
|||
}
|
||||
|
||||
fn action_recenter_playspace(&mut self, data: &mut T) -> anyhow::Result<()> {
|
||||
self.interface.recenter_playspace(data)?;
|
||||
self.interface.recenter_playspace(data, RecenterMode::Recenter)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +1,22 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, VecDeque},
|
||||
marker::PhantomData,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use std::{cell::RefCell, collections::VecDeque, marker::PhantomData, rc::Rc};
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
components::button::{ButtonClickCallback, ComponentButton},
|
||||
globals::WguiGlobals,
|
||||
i18n::Translation,
|
||||
layout::{WidgetID, WidgetPair},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
task::Tasks,
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
|
||||
};
|
||||
use wlx_common::desktop_finder::DesktopEntry;
|
||||
|
||||
use crate::{
|
||||
frontend::{Frontend, FrontendTask, FrontendTasks},
|
||||
frontend::{Frontend, FrontendTasks},
|
||||
tab::{Tab, TabType},
|
||||
util::popup_manager::{MountPopupParams, PopupHandle},
|
||||
views::{self, app_launcher},
|
||||
util::popup_manager::PopupHolder,
|
||||
views::{self},
|
||||
};
|
||||
|
||||
enum Task {
|
||||
CloseLauncher,
|
||||
}
|
||||
|
||||
struct State {
|
||||
view_launcher: Option<(PopupHandle, views::app_launcher::View)>,
|
||||
view_launcher: PopupHolder<views::app_launcher::View>,
|
||||
}
|
||||
|
||||
pub struct TabApps<T> {
|
||||
|
|
@ -37,7 +25,6 @@ pub struct TabApps<T> {
|
|||
|
||||
state: Rc<RefCell<State>>,
|
||||
app_list: AppList,
|
||||
tasks: Tasks<Task>,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
|
|
@ -46,22 +33,14 @@ impl<T> Tab<T> for TabApps<T> {
|
|||
TabType::Apps
|
||||
}
|
||||
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, data: &mut T) -> anyhow::Result<()> {
|
||||
let mut state = self.state.borrow_mut();
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, _time_ms: u32, data: &mut T) -> anyhow::Result<()> {
|
||||
let state = self.state.borrow_mut();
|
||||
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::CloseLauncher => state.view_launcher = None,
|
||||
}
|
||||
}
|
||||
self.app_list.tick(frontend, &self.state, &mut self.parser_state)?;
|
||||
|
||||
self
|
||||
.app_list
|
||||
.tick(frontend, &self.state, &self.tasks, &mut self.parser_state)?;
|
||||
|
||||
if let Some((_, launcher)) = &mut state.view_launcher {
|
||||
launcher.update(&mut frontend.interface, data)?;
|
||||
}
|
||||
state
|
||||
.view_launcher
|
||||
.with_view_res(|view| view.update(&mut frontend.interface, data))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -79,40 +58,14 @@ fn on_app_click(
|
|||
globals: WguiGlobals,
|
||||
entry: DesktopEntry,
|
||||
state: Rc<RefCell<State>>,
|
||||
tasks: Tasks<Task>,
|
||||
) -> ButtonClickCallback {
|
||||
Box::new(move |_common, _evt| {
|
||||
frontend_tasks.push(FrontendTask::MountPopup(MountPopupParams {
|
||||
title: Translation::from_raw_text(&entry.app_name),
|
||||
on_content: {
|
||||
// this is awful
|
||||
let state = state.clone();
|
||||
let entry = entry.clone();
|
||||
let globals = globals.clone();
|
||||
let frontend_tasks = frontend_tasks.clone();
|
||||
let tasks = tasks.clone();
|
||||
|
||||
Rc::new(move |data| {
|
||||
let on_launched = {
|
||||
let tasks = tasks.clone();
|
||||
Box::new(move || tasks.push(Task::CloseLauncher))
|
||||
};
|
||||
|
||||
let view = app_launcher::View::new(app_launcher::Params {
|
||||
entry: entry.clone(),
|
||||
globals: &globals,
|
||||
layout: data.layout,
|
||||
parent_id: data.id_content,
|
||||
frontend_tasks: &frontend_tasks,
|
||||
config: data.config,
|
||||
on_launched,
|
||||
})?;
|
||||
|
||||
state.borrow_mut().view_launcher = Some((data.handle, view));
|
||||
Ok(())
|
||||
})
|
||||
},
|
||||
}));
|
||||
Rc::new(move |_common, _evt| {
|
||||
views::app_launcher::mount_popup(
|
||||
frontend_tasks.clone(),
|
||||
globals.clone(),
|
||||
entry.clone(),
|
||||
state.borrow_mut().view_launcher.clone(),
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -128,8 +81,9 @@ fn doc_params(globals: WguiGlobals) -> ParseDocumentParams<'static> {
|
|||
impl<T> TabApps<T> {
|
||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID, data: &mut T) -> anyhow::Result<Self> {
|
||||
let globals = frontend.layout.state.globals.clone();
|
||||
let tasks = Tasks::new();
|
||||
let state = Rc::new(RefCell::new(State { view_launcher: None }));
|
||||
let state = Rc::new(RefCell::new(State {
|
||||
view_launcher: Default::default(),
|
||||
}));
|
||||
|
||||
let parser_state = wgui::parser::parse_from_assets(&doc_params(globals.clone()), &mut frontend.layout, parent_id)?;
|
||||
let app_list_parent = parser_state.fetch_widget(&frontend.layout.state, "app_list_parent")?;
|
||||
|
|
@ -157,7 +111,6 @@ impl<T> TabApps<T> {
|
|||
app_list,
|
||||
parser_state,
|
||||
state,
|
||||
tasks,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
|
@ -283,10 +236,10 @@ impl AppList {
|
|||
let category_name = get_category_name(entry);
|
||||
if category_name != self.prev_category_name {
|
||||
self.prev_category_name = String::from(category_name);
|
||||
let mut params = HashMap::<Rc<str>, Rc<str>>::new();
|
||||
params.insert("text".into(), category_name.into());
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("text", category_name);
|
||||
|
||||
parser_state.parse_template(
|
||||
parser_state.realize_template(
|
||||
doc_params,
|
||||
"CategoryText",
|
||||
&mut frontend.layout,
|
||||
|
|
@ -296,11 +249,11 @@ impl AppList {
|
|||
}
|
||||
|
||||
{
|
||||
let mut params = HashMap::new();
|
||||
let mut params = TemplateParams::new();
|
||||
|
||||
// entry icon
|
||||
params.insert(
|
||||
"src_ext".into(),
|
||||
params.insert_rc(
|
||||
"src_ext",
|
||||
entry
|
||||
.icon_path
|
||||
.as_ref()
|
||||
|
|
@ -309,16 +262,16 @@ impl AppList {
|
|||
|
||||
// entry fallback (question mark) icon
|
||||
params.insert(
|
||||
"src".into(),
|
||||
"src",
|
||||
if entry.icon_path.is_none() {
|
||||
"dashboard/terminal.svg".into()
|
||||
"dashboard/terminal.svg"
|
||||
} else {
|
||||
"".into()
|
||||
""
|
||||
},
|
||||
);
|
||||
params.insert("name".into(), entry.app_name.clone());
|
||||
params.insert("name", &entry.app_name);
|
||||
|
||||
let data = parser_state.parse_template(
|
||||
let data = parser_state.realize_template(
|
||||
doc_params,
|
||||
"AppEntry",
|
||||
&mut frontend.layout,
|
||||
|
|
@ -334,11 +287,10 @@ impl AppList {
|
|||
&mut self,
|
||||
frontend: &mut Frontend<T>,
|
||||
state: &Rc<RefCell<State>>,
|
||||
tasks: &Tasks<Task>,
|
||||
parser_state: &mut ParserState,
|
||||
) -> anyhow::Result<()> {
|
||||
// load 4 entries for a single frame at most
|
||||
for _ in 0..4 {
|
||||
// load 30 entries for a single frame at most
|
||||
for _ in 0..30 {
|
||||
if let Some(entry) = self.entries_to_mount.pop_front() {
|
||||
let globals = frontend.layout.state.globals.clone();
|
||||
let button = self.mount_entry(frontend, parser_state, &doc_params(globals.clone()), &entry)?;
|
||||
|
|
@ -348,7 +300,6 @@ impl AppList {
|
|||
globals.clone(),
|
||||
entry.clone(),
|
||||
state.clone(),
|
||||
tasks.clone(),
|
||||
));
|
||||
} else {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ use wgui::{
|
|||
use crate::{
|
||||
frontend::Frontend,
|
||||
tab::{Tab, TabType},
|
||||
views::game_list,
|
||||
util::steam_utils::SteamUtils,
|
||||
views::{ViewTrait, ViewUpdateParams, game_list, running_games_list},
|
||||
};
|
||||
|
||||
pub struct TabGames<T> {
|
||||
|
|
@ -17,6 +18,7 @@ pub struct TabGames<T> {
|
|||
pub state: ParserState,
|
||||
|
||||
view_game_list: game_list::View,
|
||||
view_running_games_list: running_games_list::View,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
|
|
@ -25,17 +27,32 @@ impl<T> Tab<T> for TabGames<T> {
|
|||
TabType::Games
|
||||
}
|
||||
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, _data: &mut T) -> anyhow::Result<()> {
|
||||
self.view_game_list.update(&mut frontend.layout, &frontend.executor)?;
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, time_ms: u32, data: &mut T) -> anyhow::Result<()> {
|
||||
let mut config_change_kind = None;
|
||||
|
||||
self.view_game_list.update(&mut ViewUpdateParams {
|
||||
layout: &mut frontend.layout,
|
||||
executor: &frontend.executor,
|
||||
general_config: frontend.interface.general_config(data),
|
||||
config_change_kind: &mut config_change_kind,
|
||||
})?;
|
||||
|
||||
if let Some(kind) = config_change_kind {
|
||||
frontend.interface.config_changed(data, kind);
|
||||
}
|
||||
|
||||
self.view_running_games_list.update(&mut frontend.layout, time_ms)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TabGames<T> {
|
||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID) -> anyhow::Result<Self> {
|
||||
let globals = frontend.layout.state.globals.clone();
|
||||
|
||||
let state = wgui::parser::parse_from_assets(
|
||||
&ParseDocumentParams {
|
||||
globals: frontend.layout.state.globals.clone(),
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/games.xml"),
|
||||
extra: Default::default(),
|
||||
},
|
||||
|
|
@ -44,18 +61,31 @@ impl<T> TabGames<T> {
|
|||
)?;
|
||||
|
||||
let game_list_parent = state.get_widget_id("game_list_parent")?;
|
||||
let id_running_games_list_parent = state.get_widget_id("running_games_list_parent")?;
|
||||
|
||||
let mut steam_utils = SteamUtils::new()?;
|
||||
|
||||
let view_game_list = game_list::View::new(game_list::Params {
|
||||
executor: frontend.executor.clone(),
|
||||
frontend_tasks: frontend.tasks.clone(),
|
||||
globals: frontend.layout.state.globals.clone(),
|
||||
globals: globals.clone(),
|
||||
layout: &mut frontend.layout,
|
||||
parent_id: game_list_parent,
|
||||
steam_utils: &steam_utils,
|
||||
})?;
|
||||
|
||||
let view_running_games_list = running_games_list::View::new(running_games_list::Params {
|
||||
globals: globals.clone(),
|
||||
layout: &mut frontend.layout,
|
||||
parent_id: id_running_games_list_parent,
|
||||
steam_utils: &mut steam_utils,
|
||||
frontend_tasks: frontend.tasks.clone(),
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
view_game_list,
|
||||
view_running_games_list,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,22 +59,25 @@ impl<T> TabHome<T> {
|
|||
parent_id,
|
||||
)?;
|
||||
|
||||
let mut c = frontend.layout.start_common();
|
||||
let widget_label = state.fetch_widget(&c.layout.state, "label_hello")?.widget;
|
||||
configure_label_hello(&mut c.common(), widget_label, frontend.interface.general_config(data));
|
||||
let widget_label = state.fetch_widget(&frontend.layout.state, "label_hello")?.widget;
|
||||
configure_label_hello(
|
||||
&mut frontend.layout.common(),
|
||||
widget_label,
|
||||
frontend.interface.general_config(data),
|
||||
);
|
||||
|
||||
let btn_apps = state.fetch_component_as::<ComponentButton>("btn_apps")?;
|
||||
let btn_games = state.fetch_component_as::<ComponentButton>("btn_games")?;
|
||||
let btn_monado = state.fetch_component_as::<ComponentButton>("btn_monado")?;
|
||||
//let btn_processes = state.fetch_component_as::<ComponentButton>("btn_processes")?;
|
||||
let btn_settings = state.fetch_component_as::<ComponentButton>("btn_settings")?;
|
||||
let btn_welcome_screen = state.fetch_component_as::<ComponentButton>("btn_welcome_screen")?;
|
||||
|
||||
let tasks = &mut frontend.tasks;
|
||||
tasks.handle_button(&btn_apps, FrontendTask::SetTab(TabType::Apps));
|
||||
tasks.handle_button(&btn_games, FrontendTask::SetTab(TabType::Games));
|
||||
tasks.handle_button(&btn_monado, FrontendTask::SetTab(TabType::Monado));
|
||||
//tasks.handle_button(&btn_processes, FrontendTask::SetTab(TabType::Processes));
|
||||
tasks.handle_button(&btn_settings, FrontendTask::SetTab(TabType::Settings));
|
||||
tasks.handle_button(&btn_welcome_screen, FrontendTask::SetTab(TabType::Welcome));
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ pub mod apps;
|
|||
pub mod games;
|
||||
pub mod home;
|
||||
pub mod monado;
|
||||
pub mod processes;
|
||||
pub mod settings;
|
||||
pub mod welcome;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TabType {
|
||||
|
|
@ -13,15 +13,24 @@ pub enum TabType {
|
|||
Apps,
|
||||
Games,
|
||||
Monado,
|
||||
Processes,
|
||||
Settings,
|
||||
Welcome,
|
||||
}
|
||||
|
||||
impl TabType {
|
||||
pub fn get_preferred_padding(&self) -> f32 {
|
||||
match self {
|
||||
TabType::Welcome => 0.0,
|
||||
_ => 16.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Tab<T> {
|
||||
#[allow(dead_code)]
|
||||
fn get_type(&self) -> TabType;
|
||||
|
||||
fn update(&mut self, _: &mut Frontend<T>, _: &mut T) -> anyhow::Result<()> {
|
||||
fn update(&mut self, _frontend: &mut Frontend<T>, _time_ms: u32, _user_data: &mut T) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,24 +2,133 @@ use std::{collections::HashMap, marker::PhantomData, rc::Rc};
|
|||
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
components::{checkbox::ComponentCheckbox, slider::ComponentSlider},
|
||||
components::{
|
||||
bar_graph::{ComponentBarGraph, ValueCell},
|
||||
button::ComponentButton,
|
||||
checkbox::ComponentCheckbox,
|
||||
color_selector::{ColorSelectorChangedCallback, ComponentColorSelector},
|
||||
slider::{ComponentSlider, SliderValueChangedCallback},
|
||||
tabs::ComponentTabs,
|
||||
},
|
||||
drawing::Color,
|
||||
globals::WguiGlobals,
|
||||
layout::WidgetID,
|
||||
parser::{self, Fetchable, ParseDocumentParams, ParserState},
|
||||
layout::{Layout, WidgetID},
|
||||
parser::{self, Fetchable, ParseDocumentParams, ParserState, TemplateParams},
|
||||
task::Tasks,
|
||||
};
|
||||
use wlx_common::dash_interface;
|
||||
use wlx_common::{
|
||||
config::GeneralConfig,
|
||||
dash_interface::{self, ConfigChangeKind, MonadoDumpSessionFrame},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
frontend::Frontend,
|
||||
tab::{Tab, TabType},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone)]
|
||||
enum TabNameEnum {
|
||||
GeneralSettings,
|
||||
ProcessList,
|
||||
DebugTimings,
|
||||
}
|
||||
|
||||
impl TabNameEnum {
|
||||
fn from_string(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"general_settings" => Some(TabNameEnum::GeneralSettings),
|
||||
"process_list" => Some(TabNameEnum::ProcessList),
|
||||
"debug_timings" => Some(TabNameEnum::DebugTimings),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Task {
|
||||
Refresh,
|
||||
FocusClient(String),
|
||||
SetBrightness(f32),
|
||||
SetTab(TabNameEnum),
|
||||
|
||||
// `ProcessList` tab
|
||||
ProcessListRefresh,
|
||||
ProcessListFocusClient(String),
|
||||
|
||||
// `DebugTimings` tab
|
||||
DebugTimingsRefreshSessionList,
|
||||
DebugTimingsSetSessionId(i64),
|
||||
|
||||
GeneralSettingsChromaUpdate,
|
||||
}
|
||||
|
||||
struct SubtabProcessList {
|
||||
id_list_parent: WidgetID,
|
||||
state: ParserState,
|
||||
cells: Vec<parser::ParserData>,
|
||||
}
|
||||
|
||||
struct SubtabGeneralSettings {
|
||||
#[allow(dead_code)]
|
||||
state: ParserState,
|
||||
|
||||
slider_keying_curve: Rc<ComponentSlider>,
|
||||
slider_keying_despill: Rc<ComponentSlider>,
|
||||
slider_keying_hue_range: Rc<ComponentSlider>,
|
||||
slider_keying_saturation_range: Rc<ComponentSlider>,
|
||||
slider_keying_value_range: Rc<ComponentSlider>,
|
||||
cs_keying: Rc<ComponentColorSelector>,
|
||||
}
|
||||
|
||||
struct DebugGraph {
|
||||
graph: Rc<ComponentBarGraph>,
|
||||
}
|
||||
|
||||
struct DebugSessionList {
|
||||
#[allow(dead_code)]
|
||||
buttons: Vec<Rc<ComponentButton>>,
|
||||
}
|
||||
|
||||
struct TimingsSession {
|
||||
resolved_name: Option<String>,
|
||||
last_frame: MonadoDumpSessionFrame,
|
||||
}
|
||||
|
||||
struct Graphs {
|
||||
predicted_display_time: DebugGraph,
|
||||
predicted_frame_time: DebugGraph,
|
||||
predicted_wake_up_time: DebugGraph,
|
||||
predicted_gpu_done_time: DebugGraph,
|
||||
predicted_display_period: DebugGraph,
|
||||
display_time: DebugGraph,
|
||||
when_predicted: DebugGraph,
|
||||
when_wait_woke: DebugGraph,
|
||||
when_begin: DebugGraph,
|
||||
when_delivered: DebugGraph,
|
||||
when_gpu_done: DebugGraph,
|
||||
}
|
||||
|
||||
type SessionsMap = HashMap<i64 /* session id */, TimingsSession>;
|
||||
|
||||
struct SubtabDebugTimings {
|
||||
#[allow(dead_code)]
|
||||
state: ParserState,
|
||||
|
||||
graphs: Option<Graphs>,
|
||||
session_list: DebugSessionList,
|
||||
selected_session_id: Option<i64>,
|
||||
|
||||
id_sessions_list_parent: WidgetID,
|
||||
id_timings_parent: WidgetID,
|
||||
|
||||
sessions: SessionsMap,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum Subtab {
|
||||
Empty,
|
||||
GeneralSettings(SubtabGeneralSettings),
|
||||
ProcessList(SubtabProcessList),
|
||||
DebugTimings(SubtabDebugTimings),
|
||||
}
|
||||
|
||||
pub struct TabMonado<T> {
|
||||
|
|
@ -29,10 +138,8 @@ pub struct TabMonado<T> {
|
|||
|
||||
marker: PhantomData<T>,
|
||||
|
||||
globals: WguiGlobals,
|
||||
id_list_parent: WidgetID,
|
||||
|
||||
cells: Vec<parser::ParserData>,
|
||||
id_content: WidgetID,
|
||||
subtab: Subtab,
|
||||
|
||||
ticks: u32,
|
||||
}
|
||||
|
|
@ -42,18 +149,75 @@ impl<T> Tab<T> for TabMonado<T> {
|
|||
TabType::Games
|
||||
}
|
||||
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, data: &mut T) -> anyhow::Result<()> {
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, _time_ms: u32, data: &mut T) -> anyhow::Result<()> {
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::Refresh => self.refresh(frontend, data)?,
|
||||
Task::FocusClient(name) => self.focus_client(frontend, data, name)?,
|
||||
Task::ProcessListRefresh => {
|
||||
if let Subtab::ProcessList(process_list) = &mut self.subtab {
|
||||
process_list.refresh(frontend, data, &self.tasks)?;
|
||||
}
|
||||
}
|
||||
Task::ProcessListFocusClient(client_name) => {
|
||||
if let Subtab::ProcessList(process_list) = &mut self.subtab {
|
||||
process_list.focus_client(frontend, data, client_name, &self.tasks)?;
|
||||
}
|
||||
}
|
||||
Task::DebugTimingsRefreshSessionList => {
|
||||
if let Subtab::DebugTimings(tab) = &mut self.subtab {
|
||||
tab.refresh_session_list(&mut frontend.layout, &self.tasks)?;
|
||||
}
|
||||
}
|
||||
Task::DebugTimingsSetSessionId(session_id) => {
|
||||
if let Subtab::DebugTimings(tab) = &mut self.subtab {
|
||||
tab.set_session_id(&mut frontend.layout, session_id)?;
|
||||
}
|
||||
}
|
||||
Task::GeneralSettingsChromaUpdate => {
|
||||
if let Subtab::GeneralSettings(tab) = &mut self.subtab {
|
||||
tab.chroma_update(frontend.interface.general_config(data));
|
||||
frontend
|
||||
.interface
|
||||
.config_changed(data, ConfigChangeKind::EnvironmentBlend);
|
||||
}
|
||||
}
|
||||
Task::SetBrightness(brightness) => self.set_brightness(frontend, data, brightness),
|
||||
Task::SetTab(tab) => {
|
||||
frontend.layout.remove_children(self.id_content);
|
||||
match tab {
|
||||
TabNameEnum::GeneralSettings => {
|
||||
self.subtab = Subtab::GeneralSettings(SubtabGeneralSettings::new(
|
||||
self.id_content,
|
||||
frontend,
|
||||
data,
|
||||
&self.tasks,
|
||||
)?)
|
||||
}
|
||||
TabNameEnum::ProcessList => {
|
||||
self.tasks.push(Task::ProcessListRefresh);
|
||||
self.subtab = Subtab::ProcessList(SubtabProcessList::new(self.id_content, frontend)?)
|
||||
}
|
||||
TabNameEnum::DebugTimings => {
|
||||
self.subtab = Subtab::DebugTimings(SubtabDebugTimings::new(self.id_content, frontend, &self.tasks)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match &mut self.subtab {
|
||||
Subtab::Empty => {}
|
||||
Subtab::GeneralSettings(_) => {}
|
||||
Subtab::ProcessList(_) => {
|
||||
// every few seconds
|
||||
if self.ticks.is_multiple_of(500) {
|
||||
self.tasks.push(Task::Refresh);
|
||||
if let Subtab::ProcessList(_) = &self.subtab
|
||||
&& self.ticks.is_multiple_of(500)
|
||||
{
|
||||
self.tasks.push(Task::ProcessListRefresh);
|
||||
}
|
||||
}
|
||||
Subtab::DebugTimings(timings) => {
|
||||
timings.update(&self.tasks, data, frontend)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.ticks += 1;
|
||||
|
|
@ -62,7 +226,7 @@ impl<T> Tab<T> for TabMonado<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn doc_params(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
|
||||
fn doc_params_monado(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
|
||||
ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/monado.xml"),
|
||||
|
|
@ -70,6 +234,30 @@ fn doc_params(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn doc_params_tab_process_list(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
|
||||
ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/monado_tab_process_list.xml"),
|
||||
extra: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_params_tab_general_settings(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
|
||||
ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/monado_tab_general_settings.xml"),
|
||||
extra: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_params_tab_debug_timings(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
|
||||
ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/monado_tab_debug_timings.xml"),
|
||||
extra: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn yesno(n: bool) -> &'static str {
|
||||
match n {
|
||||
true => "yes",
|
||||
|
|
@ -77,61 +265,421 @@ fn yesno(n: bool) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> TabMonado<T> {
|
||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID) -> anyhow::Result<Self> {
|
||||
let globals = frontend.layout.state.globals.clone();
|
||||
let state = wgui::parser::parse_from_assets(&doc_params(&globals), &mut frontend.layout, parent_id)?;
|
||||
const SLIDER_MULTIPLIER: f32 = 100.0;
|
||||
|
||||
let id_list_parent = state.get_widget_id("list_parent")?;
|
||||
impl SubtabGeneralSettings {
|
||||
fn new<T>(
|
||||
parent_id: WidgetID,
|
||||
frontend: &mut Frontend<T>,
|
||||
data: &mut T,
|
||||
tasks: &Tasks<Task>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let state = wgui::parser::parse_from_assets(
|
||||
&doc_params_tab_general_settings(&frontend.globals),
|
||||
&mut frontend.layout,
|
||||
parent_id,
|
||||
)?;
|
||||
|
||||
let tasks = Tasks::<Task>::new();
|
||||
// get brightness
|
||||
let slider_brightness = state.fetch_component_as::<ComponentSlider>("slider_brightness")?;
|
||||
if let Some(brightness) = frontend.interface.monado_brightness_get(data) {
|
||||
slider_brightness.set_value_primary(&mut frontend.layout.common(), brightness * 100.0);
|
||||
|
||||
tasks.push(Task::Refresh);
|
||||
slider_brightness.on_value_changed({
|
||||
let tasks = tasks.clone();
|
||||
Box::new(move |_common, e| {
|
||||
tasks.push(Task::SetBrightness(e.value / 100.0));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
let config = frontend.interface.general_config(data);
|
||||
|
||||
let cs_keying = state.fetch_component_as::<ComponentColorSelector>("cs_keying")?;
|
||||
let slider_keying_despill = state.fetch_component_as::<ComponentSlider>("slider_keying_despill")?;
|
||||
let slider_keying_curve = state.fetch_component_as::<ComponentSlider>("slider_keying_curve")?;
|
||||
let slider_keying_hue_range = state.fetch_component_as::<ComponentSlider>("slider_keying_hue_range")?;
|
||||
let slider_keying_saturation_range =
|
||||
state.fetch_component_as::<ComponentSlider>("slider_keying_saturation_range")?;
|
||||
let slider_keying_value_range = state.fetch_component_as::<ComponentSlider>("slider_keying_value_range")?;
|
||||
|
||||
{
|
||||
let mut common = frontend.layout.common();
|
||||
|
||||
// set initial values
|
||||
let (rgb, range_h, range_s, range_v) = config.chroma_key_params.get_rgb_and_hsv_ranges();
|
||||
slider_keying_curve.set_value_primary(&mut common, config.chroma_key_params.curve * SLIDER_MULTIPLIER);
|
||||
slider_keying_despill.set_value_primary(&mut common, config.chroma_key_params.despill * SLIDER_MULTIPLIER);
|
||||
slider_keying_hue_range.set_value_primary(&mut common, range_h * SLIDER_MULTIPLIER);
|
||||
slider_keying_saturation_range.set_value_primary(&mut common, range_s * SLIDER_MULTIPLIER);
|
||||
slider_keying_value_range.set_value_primary(&mut common, range_v * SLIDER_MULTIPLIER);
|
||||
cs_keying.set_color(&mut common, rgb);
|
||||
|
||||
// prepare callbacks
|
||||
fn get_slider_callback(tasks: &Tasks<Task>) -> SliderValueChangedCallback {
|
||||
Box::new({
|
||||
let tasks = tasks.clone();
|
||||
move |_, _| {
|
||||
tasks.push(Task::GeneralSettingsChromaUpdate);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_color_selector_callback(tasks: &Tasks<Task>) -> ColorSelectorChangedCallback {
|
||||
Box::new({
|
||||
let tasks = tasks.clone();
|
||||
move |_, _| {
|
||||
tasks.push(Task::GeneralSettingsChromaUpdate);
|
||||
}
|
||||
})
|
||||
}
|
||||
slider_keying_curve.on_value_changed(get_slider_callback(tasks));
|
||||
slider_keying_despill.on_value_changed(get_slider_callback(tasks));
|
||||
slider_keying_hue_range.on_value_changed(get_slider_callback(tasks));
|
||||
slider_keying_saturation_range.on_value_changed(get_slider_callback(tasks));
|
||||
slider_keying_value_range.on_value_changed(get_slider_callback(tasks));
|
||||
cs_keying.on_changed(get_color_selector_callback(tasks));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
marker: PhantomData,
|
||||
slider_keying_curve,
|
||||
slider_keying_despill,
|
||||
slider_keying_hue_range,
|
||||
slider_keying_saturation_range,
|
||||
slider_keying_value_range,
|
||||
cs_keying,
|
||||
})
|
||||
}
|
||||
|
||||
fn chroma_update(&mut self, config: &mut GeneralConfig) {
|
||||
let val_curve = self.slider_keying_curve.get_value_primary();
|
||||
let val_despill = self.slider_keying_despill.get_value_primary();
|
||||
let val_range_h = self.slider_keying_hue_range.get_value_primary();
|
||||
let val_range_s = self.slider_keying_saturation_range.get_value_primary();
|
||||
let val_range_v = self.slider_keying_value_range.get_value_primary();
|
||||
let val_rgb = self.cs_keying.get_color();
|
||||
|
||||
config.chroma_key_params.despill = val_despill / SLIDER_MULTIPLIER;
|
||||
config.chroma_key_params.curve = val_curve / SLIDER_MULTIPLIER;
|
||||
config.chroma_key_params.update_hsv_range_from_rgb(
|
||||
val_rgb,
|
||||
val_range_h / SLIDER_MULTIPLIER,
|
||||
val_range_s / SLIDER_MULTIPLIER,
|
||||
val_range_v / SLIDER_MULTIPLIER,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn mount_sessions_list(
|
||||
state: &mut ParserState,
|
||||
layout: &mut Layout,
|
||||
tasks: &Tasks<Task>,
|
||||
id_parent: WidgetID,
|
||||
sessions: &SessionsMap,
|
||||
) -> anyhow::Result<DebugSessionList> {
|
||||
let mut buttons = Vec::new();
|
||||
let globals = layout.state.globals.clone();
|
||||
layout.remove_children(id_parent);
|
||||
|
||||
for (session_id, session) in sessions {
|
||||
let mut params = TemplateParams::new();
|
||||
|
||||
params.insert_rc(
|
||||
"text",
|
||||
format!(
|
||||
"{} (ID {})",
|
||||
session.resolved_name.as_ref().map_or("Unknown", |s| s.as_str()),
|
||||
session_id,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
|
||||
let data = state.realize_template(
|
||||
&doc_params_tab_debug_timings(&globals),
|
||||
"SessionButton",
|
||||
layout,
|
||||
id_parent,
|
||||
params,
|
||||
)?;
|
||||
|
||||
let button = data.fetch_component_as::<ComponentButton>("button")?;
|
||||
|
||||
button.on_click({
|
||||
let tasks = tasks.clone();
|
||||
let session_id = *session_id;
|
||||
Rc::new(move |_, _| {
|
||||
tasks.push(Task::DebugTimingsSetSessionId(session_id));
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
buttons.push(button);
|
||||
}
|
||||
|
||||
Ok(DebugSessionList { buttons })
|
||||
}
|
||||
|
||||
fn mount_graph(
|
||||
state: &mut ParserState,
|
||||
layout: &mut Layout,
|
||||
id_parent: WidgetID,
|
||||
name: &'static str,
|
||||
limits: (f32, f32),
|
||||
) -> anyhow::Result<DebugGraph> {
|
||||
let globals = layout.state.globals.clone();
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("name", name);
|
||||
params.insert_rc("limit_min", limits.0.to_string().into());
|
||||
params.insert_rc("limit_max", limits.1.to_string().into());
|
||||
|
||||
let data = state.realize_template(
|
||||
&doc_params_tab_debug_timings(&globals),
|
||||
"DebugGraph",
|
||||
layout,
|
||||
id_parent,
|
||||
params,
|
||||
)?;
|
||||
|
||||
let graph = data.fetch_component_as::<ComponentBarGraph>("graph")?;
|
||||
Ok(DebugGraph { graph })
|
||||
}
|
||||
|
||||
fn ns_to_ms(ns: i64) -> f32 {
|
||||
(ns / 1000) as f32 / 1000.0
|
||||
}
|
||||
|
||||
impl SubtabDebugTimings {
|
||||
fn new<T>(parent_id: WidgetID, frontend: &mut Frontend<T>, tasks: &Tasks<Task>) -> anyhow::Result<Self> {
|
||||
let mut state = wgui::parser::parse_from_assets(
|
||||
&doc_params_tab_debug_timings(&frontend.globals),
|
||||
&mut frontend.layout,
|
||||
parent_id,
|
||||
)?;
|
||||
|
||||
let id_timings_parent = state.get_widget_id("timings_parent")?;
|
||||
let id_sessions_list_parent = state.get_widget_id("session_list_parent")?;
|
||||
|
||||
let sessions = Default::default();
|
||||
|
||||
let session_list = mount_sessions_list(
|
||||
&mut state,
|
||||
&mut frontend.layout,
|
||||
tasks,
|
||||
globals,
|
||||
id_sessions_list_parent,
|
||||
&sessions,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
graphs: None,
|
||||
session_list,
|
||||
id_sessions_list_parent,
|
||||
id_timings_parent,
|
||||
sessions,
|
||||
selected_session_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn set_session_id(&mut self, layout: &mut Layout, session_id: i64) -> anyhow::Result<()> {
|
||||
layout.remove_children(self.id_timings_parent);
|
||||
|
||||
let mut graph = |name: &'static str, limits: (f32, f32)| -> anyhow::Result<DebugGraph> {
|
||||
mount_graph(&mut self.state, layout, self.id_timings_parent, name, limits)
|
||||
};
|
||||
|
||||
// populate graphs
|
||||
self.graphs = Some(Graphs {
|
||||
predicted_display_time: graph("Predicted display time", (0.0, 30.0))?,
|
||||
predicted_frame_time: graph("Predicted frame time", (0.0, 30.0))?,
|
||||
predicted_wake_up_time: graph("Predicted wake-up time", (0.0, 30.0))?,
|
||||
predicted_gpu_done_time: graph("Predicted GPU done time", (0.0, 30.0))?,
|
||||
predicted_display_period: graph("Predicted display period", (0.0, 30.0))?,
|
||||
display_time: graph("Display time", (0.0, 30.0))?,
|
||||
when_predicted: graph("When predicted", (0.0, 30.0))?,
|
||||
when_wait_woke: graph("When wait woke", (0.0, 30.0))?,
|
||||
when_begin: graph("When begin", (0.0, 30.0))?,
|
||||
when_delivered: graph("When delivered", (0.0, 30.0))?,
|
||||
when_gpu_done: graph("When GPU done", (0.0, 30.0))?,
|
||||
});
|
||||
|
||||
self.selected_session_id = Some(session_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn refresh_session_list(&mut self, layout: &mut Layout, tasks: &Tasks<Task>) -> anyhow::Result<()> {
|
||||
self.session_list = mount_sessions_list(
|
||||
&mut self.state,
|
||||
layout,
|
||||
tasks,
|
||||
self.id_sessions_list_parent,
|
||||
&self.sessions,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update<T>(&mut self, tasks: &Tasks<Task>, data: &mut T, frontend: &mut Frontend<T>) -> anyhow::Result<()> {
|
||||
if !frontend.interface.monado_metrics_set_enabled(data, true) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let frames = frontend.interface.monado_metrics_dump_session_frames(data);
|
||||
if frames.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let col_green = Color::new(0.0, 1.0, 0.0, 1.0);
|
||||
|
||||
for frame in frames {
|
||||
//log::info!("{:?}", frame);
|
||||
|
||||
match self.sessions.get_mut(&frame.session_id) {
|
||||
Some(session) => {
|
||||
if let Some(graphs) = &mut self.graphs
|
||||
&& let Some(selected_session_id) = self.selected_session_id
|
||||
&& selected_session_id == frame.session_id
|
||||
{
|
||||
let predicted_display_time = ns_to_ms(session.last_frame.predicted_display_time_ns as i64);
|
||||
let predicted_frame_time = ns_to_ms(frame.predicted_frame_time_ns as i64);
|
||||
let predicted_wake_up_time =
|
||||
ns_to_ms(frame.predicted_wake_up_time_ns as i64 - session.last_frame.predicted_wake_up_time_ns as i64);
|
||||
let predicted_gpu_done_time =
|
||||
ns_to_ms(frame.predicted_gpu_done_time_ns as i64 - session.last_frame.predicted_gpu_done_time_ns as i64);
|
||||
let predicted_display_period = ns_to_ms(session.last_frame.predicted_display_period_ns as i64); // 6.944 ms for 144Hz
|
||||
let display_time = ns_to_ms(frame.display_time_ns as i64 - session.last_frame.display_time_ns as i64);
|
||||
let when_predicted = ns_to_ms(frame.when_predicted_ns as i64 - session.last_frame.when_predicted_ns as i64);
|
||||
let when_wait_woke = ns_to_ms(frame.when_wait_woke_ns as i64 - session.last_frame.when_wait_woke_ns as i64);
|
||||
let when_begin = ns_to_ms(frame.when_begin_ns as i64 - session.last_frame.when_begin_ns as i64);
|
||||
let when_delivered = ns_to_ms(frame.when_delivered_ns as i64 - session.last_frame.when_delivered_ns as i64);
|
||||
let when_gpu_done = ns_to_ms(frame.when_gpu_done_ns as i64 - session.last_frame.when_gpu_done_ns as i64);
|
||||
|
||||
graphs.predicted_display_time.graph.push_value(ValueCell {
|
||||
value: predicted_display_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.predicted_frame_time.graph.push_value(ValueCell {
|
||||
value: predicted_frame_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.predicted_wake_up_time.graph.push_value(ValueCell {
|
||||
value: predicted_wake_up_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.predicted_gpu_done_time.graph.push_value(ValueCell {
|
||||
value: predicted_gpu_done_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.predicted_display_period.graph.push_value(ValueCell {
|
||||
value: predicted_display_period,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.display_time.graph.push_value(ValueCell {
|
||||
value: display_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.when_predicted.graph.push_value(ValueCell {
|
||||
value: when_predicted,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.when_wait_woke.graph.push_value(ValueCell {
|
||||
value: when_wait_woke,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.when_begin.graph.push_value(ValueCell {
|
||||
value: when_begin,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.when_delivered.graph.push_value(ValueCell {
|
||||
value: when_delivered,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
graphs.when_gpu_done.graph.push_value(ValueCell {
|
||||
value: when_gpu_done,
|
||||
color: col_green,
|
||||
});
|
||||
}
|
||||
|
||||
session.last_frame = frame;
|
||||
}
|
||||
None => {
|
||||
self.sessions.insert(
|
||||
frame.session_id,
|
||||
TimingsSession {
|
||||
last_frame: frame,
|
||||
resolved_name: None, /* TODO! find client ID from session ID */
|
||||
},
|
||||
);
|
||||
tasks.push(Task::DebugTimingsRefreshSessionList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frontend.layout.mark_redraw();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SubtabProcessList {
|
||||
fn new<T>(parent_id: WidgetID, frontend: &mut Frontend<T>) -> anyhow::Result<Self> {
|
||||
let state = wgui::parser::parse_from_assets(
|
||||
&doc_params_tab_process_list(&frontend.globals),
|
||||
&mut frontend.layout,
|
||||
parent_id,
|
||||
)?;
|
||||
let id_list_parent = state.get_widget_id("list_parent")?;
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
id_list_parent,
|
||||
ticks: 0,
|
||||
cells: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn mount_client(&mut self, frontend: &mut Frontend<T>, client: &dash_interface::MonadoClient) -> anyhow::Result<()> {
|
||||
let mut par = HashMap::<Rc<str>, Rc<str>>::new();
|
||||
par.insert(
|
||||
"checked".into(),
|
||||
if client.is_primary {
|
||||
Rc::from("1")
|
||||
} else {
|
||||
Rc::from("0")
|
||||
},
|
||||
);
|
||||
par.insert("name".into(), client.name.clone().into());
|
||||
par.insert("flag_active".into(), yesno(client.is_active).into());
|
||||
par.insert("flag_focused".into(), yesno(client.is_focused).into());
|
||||
par.insert("flag_io_active".into(), yesno(client.is_io_active).into());
|
||||
par.insert("flag_overlay".into(), yesno(client.is_overlay).into());
|
||||
par.insert("flag_primary".into(), yesno(client.is_primary).into());
|
||||
par.insert("flag_visible".into(), yesno(client.is_visible).into());
|
||||
fn mount_client(
|
||||
&mut self,
|
||||
layout: &mut Layout,
|
||||
client: &dash_interface::MonadoClient,
|
||||
tasks: &Tasks<Task>,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut par = TemplateParams::new();
|
||||
par.insert("checked", if client.is_primary { "1" } else { "0" });
|
||||
par.insert_rc("name", format!("{} (Client ID: {})", client.name, client.id).into());
|
||||
par.insert("flag_active", yesno(client.is_active));
|
||||
par.insert("flag_focused", yesno(client.is_focused));
|
||||
par.insert("flag_io_active", yesno(client.is_io_active));
|
||||
par.insert("flag_overlay", yesno(client.is_overlay));
|
||||
par.insert("flag_primary", yesno(client.is_primary));
|
||||
par.insert("flag_visible", yesno(client.is_visible));
|
||||
|
||||
let state_cell = self.state.parse_template(
|
||||
&doc_params(&self.globals),
|
||||
let globals = layout.state.globals.clone();
|
||||
|
||||
let state_cell = self.state.realize_template(
|
||||
&doc_params_tab_process_list(&globals),
|
||||
"Cell",
|
||||
&mut frontend.layout,
|
||||
layout,
|
||||
self.id_list_parent,
|
||||
par,
|
||||
)?;
|
||||
|
||||
let checkbox = state_cell.fetch_component_as::<ComponentCheckbox>("checkbox")?;
|
||||
checkbox.on_toggle({
|
||||
let tasks = self.tasks.clone();
|
||||
let tasks = tasks.clone();
|
||||
let client_name = client.name.clone();
|
||||
Box::new(move |_common, e| {
|
||||
if e.checked {
|
||||
tasks.push(Task::FocusClient(client_name.clone()));
|
||||
tasks.push(Task::ProcessListFocusClient(client_name.clone()));
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
|
@ -142,41 +690,63 @@ impl<T> TabMonado<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn refresh(&mut self, frontend: &mut Frontend<T>, data: &mut T) -> anyhow::Result<()> {
|
||||
fn focus_client<T>(
|
||||
&mut self,
|
||||
frontend: &mut Frontend<T>,
|
||||
data: &mut T,
|
||||
name: String,
|
||||
tasks: &Tasks<Task>,
|
||||
) -> anyhow::Result<()> {
|
||||
frontend.interface.monado_client_focus(data, &name)?;
|
||||
tasks.push(Task::ProcessListRefresh);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn refresh<T>(&mut self, frontend: &mut Frontend<T>, data: &mut T, tasks: &Tasks<Task>) -> anyhow::Result<()> {
|
||||
log::debug!("refreshing monado client list");
|
||||
|
||||
let clients = frontend.interface.monado_client_list(data)?;
|
||||
let clients = frontend.interface.monado_client_list(data, true)?;
|
||||
|
||||
frontend.layout.remove_children(self.id_list_parent);
|
||||
self.cells.clear();
|
||||
|
||||
for client in clients {
|
||||
self.mount_client(frontend, &client)?;
|
||||
self.mount_client(&mut frontend.layout, &client, tasks)?;
|
||||
}
|
||||
|
||||
// get brightness
|
||||
let slider_brightness = self.state.fetch_component_as::<ComponentSlider>("slider_brightness")?;
|
||||
if let Some(brightness) = frontend.interface.monado_brightness_get(data) {
|
||||
let mut c = frontend.layout.start_common();
|
||||
slider_brightness.set_value(&mut c.common(), brightness * 100.0);
|
||||
c.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
slider_brightness.on_value_changed({
|
||||
let tasks = self.tasks.clone();
|
||||
Box::new(move |_common, e| {
|
||||
tasks.push(Task::SetBrightness(e.value / 100.0));
|
||||
impl<T> TabMonado<T> {
|
||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID) -> anyhow::Result<Self> {
|
||||
let globals = frontend.layout.state.globals.clone();
|
||||
let state = wgui::parser::parse_from_assets(&doc_params_monado(&globals), &mut frontend.layout, parent_id)?;
|
||||
let id_content = state.get_widget_id("content")?;
|
||||
let tabs = state.fetch_component_as::<ComponentTabs>("tabs")?;
|
||||
|
||||
let tasks = Tasks::<Task>::new();
|
||||
|
||||
tabs.on_select({
|
||||
let tasks = tasks.clone();
|
||||
Rc::new(move |_common, evt| {
|
||||
if let Some(tab) = TabNameEnum::from_string(&evt.name) {
|
||||
tasks.push(Task::SetTab(tab));
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
tasks.push(Task::SetTab(TabNameEnum::ProcessList));
|
||||
|
||||
fn focus_client(&mut self, frontend: &mut Frontend<T>, data: &mut T, name: String) -> anyhow::Result<()> {
|
||||
frontend.interface.monado_client_focus(data, &name)?;
|
||||
self.tasks.push(Task::Refresh);
|
||||
Ok(())
|
||||
Ok(Self {
|
||||
state,
|
||||
marker: PhantomData,
|
||||
tasks,
|
||||
id_content,
|
||||
ticks: 0,
|
||||
subtab: Subtab::Empty,
|
||||
})
|
||||
}
|
||||
|
||||
fn set_brightness(&mut self, frontend: &mut Frontend<T>, data: &mut T, brightness: f32) {
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
layout::WidgetID,
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
frontend::Frontend,
|
||||
tab::{Tab, TabType},
|
||||
views::{process_list, window_list},
|
||||
};
|
||||
|
||||
pub struct TabProcesses<T> {
|
||||
#[allow(dead_code)]
|
||||
pub state: ParserState,
|
||||
|
||||
view_window_list: window_list::View,
|
||||
view_process_list: process_list::View,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Tab<T> for TabProcesses<T> {
|
||||
fn get_type(&self) -> TabType {
|
||||
TabType::Games
|
||||
}
|
||||
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, data: &mut T) -> anyhow::Result<()> {
|
||||
self
|
||||
.view_window_list
|
||||
.update(&mut frontend.layout, &mut frontend.interface, data)?;
|
||||
self
|
||||
.view_process_list
|
||||
.update(&mut frontend.layout, &mut frontend.interface, data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TabProcesses<T> {
|
||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID) -> anyhow::Result<Self> {
|
||||
let globals = frontend.layout.state.globals.clone();
|
||||
let state = wgui::parser::parse_from_assets(
|
||||
&ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/processes.xml"),
|
||||
extra: Default::default(),
|
||||
},
|
||||
&mut frontend.layout,
|
||||
parent_id,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
view_window_list: window_list::View::new(window_list::Params {
|
||||
layout: &mut frontend.layout,
|
||||
parent_id: state.get_widget_id("window_list_parent")?,
|
||||
globals: globals.clone(),
|
||||
frontend_tasks: frontend.tasks.clone(),
|
||||
on_click: None,
|
||||
})?,
|
||||
view_process_list: process_list::View::new(process_list::Params {
|
||||
layout: &mut frontend.layout,
|
||||
parent_id: state.get_widget_id("process_list_parent")?,
|
||||
globals,
|
||||
})?,
|
||||
state,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,736 +0,0 @@
|
|||
use std::{collections::HashMap, marker::PhantomData, rc::Rc, str::FromStr};
|
||||
|
||||
use glam::Vec2;
|
||||
use strum::{AsRefStr, EnumProperty, EnumString, VariantArray};
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
components::{button::ComponentButton, checkbox::ComponentCheckbox, slider::ComponentSlider},
|
||||
event::{CallbackDataCommon, EventAlterables},
|
||||
i18n::Translation,
|
||||
layout::{Layout, WidgetID},
|
||||
log::LogErr,
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
task::Tasks,
|
||||
widget::label::WidgetLabel,
|
||||
windowing::context_menu::{self, Blueprint, ContextMenu, TickResult},
|
||||
};
|
||||
use wlx_common::{config::GeneralConfig, config_io::ConfigRoot};
|
||||
|
||||
use crate::{
|
||||
frontend::{Frontend, FrontendTask},
|
||||
tab::{Tab, TabType},
|
||||
};
|
||||
|
||||
enum Task {
|
||||
UpdateBool(SettingType, bool),
|
||||
UpdateFloat(SettingType, f32),
|
||||
UpdateInt(SettingType, i32),
|
||||
OpenContextMenu(Vec2, Vec<context_menu::Cell>),
|
||||
ClearPipewireTokens,
|
||||
ClearSavedState,
|
||||
DeleteAllConfigs,
|
||||
RestartSoftware,
|
||||
RemoveAutostartApp(Rc<str>),
|
||||
}
|
||||
|
||||
pub struct TabSettings<T> {
|
||||
pub state: ParserState,
|
||||
|
||||
app_button_ids: Vec<Rc<str>>,
|
||||
context_menu: ContextMenu,
|
||||
|
||||
tasks: Tasks<Task>,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Tab<T> for TabSettings<T> {
|
||||
fn get_type(&self) -> TabType {
|
||||
TabType::Settings
|
||||
}
|
||||
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, data: &mut T) -> anyhow::Result<()> {
|
||||
let config = frontend.interface.general_config(data);
|
||||
let mut changed = false;
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::UpdateBool(setting, n) => {
|
||||
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||
*setting.mut_bool(config) = n;
|
||||
changed = true;
|
||||
}
|
||||
Task::UpdateFloat(setting, n) => {
|
||||
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||
*setting.mut_f32(config) = n;
|
||||
changed = true;
|
||||
}
|
||||
Task::UpdateInt(setting, n) => {
|
||||
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||
*setting.mut_i32(config) = n;
|
||||
changed = true;
|
||||
}
|
||||
Task::ClearPipewireTokens => {
|
||||
let _ = std::fs::remove_file(ConfigRoot::Generic.get_conf_d_path().join("pw_tokens.yaml"))
|
||||
.log_err("Could not remove pw_tokens.yaml");
|
||||
}
|
||||
Task::ClearSavedState => {
|
||||
let _ = std::fs::remove_file(ConfigRoot::Generic.get_conf_d_path().join("zz-saved-state.json5"))
|
||||
.log_err("Could not remove zz-saved-state.json5");
|
||||
}
|
||||
Task::DeleteAllConfigs => {
|
||||
let path = ConfigRoot::Generic.get_conf_d_path();
|
||||
std::fs::remove_dir_all(&path)?;
|
||||
std::fs::create_dir(&path)?;
|
||||
}
|
||||
Task::RestartSoftware => {
|
||||
frontend.interface.restart(data);
|
||||
return Ok(());
|
||||
}
|
||||
Task::OpenContextMenu(position, cells) => {
|
||||
self.context_menu.open(context_menu::OpenParams {
|
||||
on_custom_attribs: None,
|
||||
position,
|
||||
blueprint: Blueprint::Cells(cells),
|
||||
});
|
||||
}
|
||||
Task::RemoveAutostartApp(button_id) => {
|
||||
if let (Some(idx), Ok(widget)) = (
|
||||
self.app_button_ids.iter().position(|x| button_id.eq(x)),
|
||||
self.state.get_widget_id(&format!("{button_id}_root")),
|
||||
) {
|
||||
self.app_button_ids.remove(idx);
|
||||
config.autostart_apps.remove(idx);
|
||||
frontend.layout.remove_widget(widget);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dropdown handling
|
||||
if let TickResult::Action(name) = self.context_menu.tick(&mut frontend.layout, &mut self.state)? {
|
||||
if let (Some(setting), Some(id), Some(value), Some(text), Some(translated)) = {
|
||||
let mut s = name.splitn(5, ';');
|
||||
(s.next(), s.next(), s.next(), s.next(), s.next())
|
||||
} {
|
||||
let mut label = self
|
||||
.state
|
||||
.fetch_widget_as::<WidgetLabel>(&frontend.layout.state, &format!("{id}_value"))?;
|
||||
|
||||
let mut alterables = EventAlterables::default();
|
||||
let mut common = CallbackDataCommon {
|
||||
alterables: &mut alterables,
|
||||
state: &frontend.layout.state,
|
||||
};
|
||||
|
||||
let translation = Translation {
|
||||
text: text.into(),
|
||||
translated: translated == "1",
|
||||
};
|
||||
|
||||
label.set_text(&mut common, translation);
|
||||
|
||||
let setting = SettingType::from_str(setting).expect("Invalid Enum string");
|
||||
setting.set_enum(config, value);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify overlays of the change
|
||||
if changed {
|
||||
frontend.interface.config_changed(data);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Clone, Copy, AsRefStr, EnumString)]
|
||||
enum SettingType {
|
||||
AnimationSpeed,
|
||||
RoundMultiplier,
|
||||
InvertScrollDirectionX,
|
||||
InvertScrollDirectionY,
|
||||
ScrollSpeed,
|
||||
LongPressDuration,
|
||||
NotificationsEnabled,
|
||||
NotificationsSoundEnabled,
|
||||
KeyboardSoundEnabled,
|
||||
UprightScreenFix,
|
||||
DoubleCursorFix,
|
||||
SetsOnWatch,
|
||||
HideGrabHelp,
|
||||
XrClickSensitivity,
|
||||
XrClickSensitivityRelease,
|
||||
AllowSliding,
|
||||
ClickFreezeTimeMs,
|
||||
FocusFollowsMouseMode,
|
||||
LeftHandedMouse,
|
||||
BlockGameInput,
|
||||
BlockGameInputIgnoreWatch,
|
||||
SpaceDragMultiplier,
|
||||
UseSkybox,
|
||||
UsePassthrough,
|
||||
ScreenRenderDown,
|
||||
PointerLerpFactor,
|
||||
SpaceDragUnlocked,
|
||||
SpaceRotateUnlocked,
|
||||
Clock12h,
|
||||
HideUsername,
|
||||
OpaqueBackground,
|
||||
XwaylandByDefault,
|
||||
CaptureMethod,
|
||||
KeyboardMiddleClick,
|
||||
}
|
||||
|
||||
impl SettingType {
|
||||
pub fn mut_bool<'a>(self, config: &'a mut GeneralConfig) -> &'a mut bool {
|
||||
match self {
|
||||
Self::InvertScrollDirectionX => &mut config.invert_scroll_direction_x,
|
||||
Self::InvertScrollDirectionY => &mut config.invert_scroll_direction_y,
|
||||
Self::NotificationsEnabled => &mut config.notifications_enabled,
|
||||
Self::NotificationsSoundEnabled => &mut config.notifications_sound_enabled,
|
||||
Self::KeyboardSoundEnabled => &mut config.keyboard_sound_enabled,
|
||||
Self::UprightScreenFix => &mut config.upright_screen_fix,
|
||||
Self::DoubleCursorFix => &mut config.double_cursor_fix,
|
||||
Self::SetsOnWatch => &mut config.sets_on_watch,
|
||||
Self::HideGrabHelp => &mut config.hide_grab_help,
|
||||
Self::AllowSliding => &mut config.allow_sliding,
|
||||
Self::FocusFollowsMouseMode => &mut config.focus_follows_mouse_mode,
|
||||
Self::LeftHandedMouse => &mut config.left_handed_mouse,
|
||||
Self::BlockGameInput => &mut config.block_game_input,
|
||||
Self::BlockGameInputIgnoreWatch => &mut config.block_game_input_ignore_watch,
|
||||
Self::UseSkybox => &mut config.use_skybox,
|
||||
Self::UsePassthrough => &mut config.use_passthrough,
|
||||
Self::ScreenRenderDown => &mut config.screen_render_down,
|
||||
Self::SpaceDragUnlocked => &mut config.space_drag_unlocked,
|
||||
Self::SpaceRotateUnlocked => &mut config.space_rotate_unlocked,
|
||||
Self::Clock12h => &mut config.clock_12h,
|
||||
Self::HideUsername => &mut config.hide_username,
|
||||
Self::OpaqueBackground => &mut config.opaque_background,
|
||||
Self::XwaylandByDefault => &mut config.xwayland_by_default,
|
||||
_ => panic!("Requested bool for non-bool SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mut_f32<'a>(self, config: &'a mut GeneralConfig) -> &'a mut f32 {
|
||||
match self {
|
||||
Self::AnimationSpeed => &mut config.animation_speed,
|
||||
Self::RoundMultiplier => &mut config.round_multiplier,
|
||||
Self::ScrollSpeed => &mut config.scroll_speed,
|
||||
Self::LongPressDuration => &mut config.long_press_duration,
|
||||
Self::XrClickSensitivity => &mut config.xr_click_sensitivity,
|
||||
Self::XrClickSensitivityRelease => &mut config.xr_click_sensitivity_release,
|
||||
Self::SpaceDragMultiplier => &mut config.space_drag_multiplier,
|
||||
Self::PointerLerpFactor => &mut config.pointer_lerp_factor,
|
||||
_ => panic!("Requested f32 for non-f32 SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mut_i32<'a>(self, config: &'a mut GeneralConfig) -> &'a mut i32 {
|
||||
match self {
|
||||
Self::ClickFreezeTimeMs => &mut config.click_freeze_time_ms,
|
||||
_ => panic!("Requested i32 for non-i32 SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_enum<'a>(self, config: &'a mut GeneralConfig, value: &str) {
|
||||
match self {
|
||||
Self::CaptureMethod => {
|
||||
config.capture_method = wlx_common::config::CaptureMethod::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
Self::KeyboardMiddleClick => {
|
||||
config.keyboard_middle_click_mode =
|
||||
wlx_common::config::AltModifier::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
_ => panic!("Requested enum for non-enum SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_enum_title<'a>(self, config: &'a mut GeneralConfig) -> Translation {
|
||||
match self {
|
||||
Self::CaptureMethod => Self::get_enum_title_inner(config.capture_method),
|
||||
Self::KeyboardMiddleClick => Self::get_enum_title_inner(config.keyboard_middle_click_mode),
|
||||
_ => panic!("Requested enum for non-enum SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_enum_title_inner<E>(value: E) -> Translation
|
||||
where
|
||||
E: EnumProperty + AsRef<str>,
|
||||
{
|
||||
value
|
||||
.get_str("Translation")
|
||||
.map(|x| Translation::from_translation_key(x))
|
||||
.or_else(|| value.get_str("Text").map(|x| Translation::from_raw_text(x)))
|
||||
.unwrap_or_else(|| Translation::from_raw_text(value.as_ref()))
|
||||
}
|
||||
|
||||
fn get_enum_tooltip_inner<E>(value: E) -> Option<Translation>
|
||||
where
|
||||
E: EnumProperty + AsRef<str>,
|
||||
{
|
||||
value.get_str("Tooltip").map(|x| Translation::from_translation_key(x))
|
||||
}
|
||||
|
||||
/// Ok is translation, Err is raw text
|
||||
fn get_translation(self) -> Result<&'static str, &'static str> {
|
||||
match self {
|
||||
Self::AnimationSpeed => Ok("APP_SETTINGS.ANIMATION_SPEED"),
|
||||
Self::RoundMultiplier => Ok("APP_SETTINGS.ROUND_MULTIPLIER"),
|
||||
Self::InvertScrollDirectionX => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_X"),
|
||||
Self::InvertScrollDirectionY => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_Y"),
|
||||
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
|
||||
Self::LongPressDuration => Ok("APP_SETTINGS.LONG_PRESS_DURATION"),
|
||||
Self::NotificationsEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_ENABLED"),
|
||||
Self::NotificationsSoundEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED"),
|
||||
Self::KeyboardSoundEnabled => Ok("APP_SETTINGS.KEYBOARD_SOUND_ENABLED"),
|
||||
Self::UprightScreenFix => Ok("APP_SETTINGS.UPRIGHT_SCREEN_FIX"),
|
||||
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
||||
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
|
||||
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
||||
Self::XrClickSensitivity => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY"),
|
||||
Self::XrClickSensitivityRelease => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE"),
|
||||
Self::AllowSliding => Ok("APP_SETTINGS.ALLOW_SLIDING"),
|
||||
Self::ClickFreezeTimeMs => Ok("APP_SETTINGS.CLICK_FREEZE_TIME_MS"),
|
||||
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
|
||||
Self::LeftHandedMouse => Ok("APP_SETTINGS.LEFT_HANDED_MOUSE"),
|
||||
Self::BlockGameInput => Ok("APP_SETTINGS.BLOCK_GAME_INPUT"),
|
||||
Self::BlockGameInputIgnoreWatch => Ok("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH"),
|
||||
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
|
||||
Self::UseSkybox => Ok("APP_SETTINGS.USE_SKYBOX"),
|
||||
Self::UsePassthrough => Ok("APP_SETTINGS.USE_PASSTHROUGH"),
|
||||
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
|
||||
Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"),
|
||||
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),
|
||||
Self::SpaceRotateUnlocked => Ok("APP_SETTINGS.SPACE_ROTATE_UNLOCKED"),
|
||||
Self::Clock12h => Ok("APP_SETTINGS.CLOCK_12H"),
|
||||
Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"),
|
||||
Self::OpaqueBackground => Ok("APP_SETTINGS.OPAQUE_BACKGROUND"),
|
||||
Self::XwaylandByDefault => Ok("APP_SETTINGS.XWAYLAND_BY_DEFAULT"),
|
||||
Self::CaptureMethod => Ok("APP_SETTINGS.CAPTURE_METHOD"),
|
||||
Self::KeyboardMiddleClick => Ok("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_tooltip(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::UprightScreenFix => Some("APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP"),
|
||||
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
||||
Self::XrClickSensitivity => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_HELP"),
|
||||
Self::XrClickSensitivityRelease => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE_HELP"),
|
||||
Self::FocusFollowsMouseMode => Some("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE_HELP"),
|
||||
Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"),
|
||||
Self::BlockGameInput => Some("APP_SETTINGS.BLOCK_GAME_INPUT_HELP"),
|
||||
Self::BlockGameInputIgnoreWatch => Some("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH_HELP"),
|
||||
Self::UseSkybox => Some("APP_SETTINGS.USE_SKYBOX_HELP"),
|
||||
Self::UsePassthrough => Some("APP_SETTINGS.USE_PASSTHROUGH_HELP"),
|
||||
Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"),
|
||||
Self::CaptureMethod => Some("APP_SETTINGS.CAPTURE_METHOD_HELP"),
|
||||
Self::KeyboardMiddleClick => Some("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK_HELP"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: incorporate this
|
||||
fn requires_restart(self) -> bool {
|
||||
match self {
|
||||
Self::AnimationSpeed
|
||||
| Self::RoundMultiplier
|
||||
| Self::UprightScreenFix
|
||||
| Self::DoubleCursorFix
|
||||
| Self::SetsOnWatch
|
||||
| Self::UseSkybox
|
||||
| Self::UsePassthrough
|
||||
| Self::ScreenRenderDown => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_frontend_task(self) -> Option<FrontendTask> {
|
||||
match self {
|
||||
Self::Clock12h => Some(FrontendTask::RefreshClock),
|
||||
Self::OpaqueBackground => Some(FrontendTask::RefreshBackground),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! category {
|
||||
($pe:expr, $root:expr, $translation:expr, $icon:expr) => {{
|
||||
let id = $pe.idx.to_string();
|
||||
$pe.idx += 1;
|
||||
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("translation"), Rc::from($translation));
|
||||
params.insert(Rc::from("icon"), Rc::from($icon));
|
||||
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||
|
||||
$pe
|
||||
.parser_state
|
||||
.instantiate_template($pe.doc_params, "SettingsGroupBox", $pe.layout, $root, params)?;
|
||||
|
||||
$pe.parser_state.get_widget_id(&id)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! checkbox {
|
||||
($mp:expr, $root:expr, $setting:expr) => {
|
||||
let id = $mp.idx.to_string();
|
||||
$mp.idx += 1;
|
||||
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||
|
||||
match $setting.get_translation() {
|
||||
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
|
||||
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = $setting.get_tooltip() {
|
||||
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||
}
|
||||
|
||||
let checked = if *$setting.mut_bool($mp.config) { "1" } else { "0" };
|
||||
params.insert(Rc::from("checked"), Rc::from(checked));
|
||||
|
||||
$mp
|
||||
.parser_state
|
||||
.instantiate_template($mp.doc_params, "CheckBoxSetting", $mp.layout, $root, params)?;
|
||||
|
||||
let checkbox = $mp.parser_state.fetch_component_as::<ComponentCheckbox>(&id)?;
|
||||
checkbox.on_toggle(Box::new({
|
||||
let tasks = $mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
tasks.push(Task::UpdateBool($setting, e.checked));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! slider_f32 {
|
||||
($mp:expr, $root:expr, $setting:expr, $min:expr, $max:expr, $step:expr) => {
|
||||
let id = $mp.idx.to_string();
|
||||
$mp.idx += 1;
|
||||
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||
|
||||
match $setting.get_translation() {
|
||||
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
|
||||
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = $setting.get_tooltip() {
|
||||
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||
}
|
||||
|
||||
let value = $setting.mut_f32($mp.config).to_string();
|
||||
params.insert(Rc::from("value"), Rc::from(value));
|
||||
params.insert(Rc::from("min"), Rc::from($min.to_string()));
|
||||
params.insert(Rc::from("max"), Rc::from($max.to_string()));
|
||||
params.insert(Rc::from("step"), Rc::from($step.to_string()));
|
||||
|
||||
$mp
|
||||
.parser_state
|
||||
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, $root, params)?;
|
||||
|
||||
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||
slider.on_value_changed(Box::new({
|
||||
let tasks = $mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
tasks.push(Task::UpdateFloat($setting, e.value));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! slider_i32 {
|
||||
($mp:expr, $root:expr, $setting:expr, $min:expr, $max:expr, $step:expr) => {
|
||||
let id = $mp.idx.to_string();
|
||||
$mp.idx += 1;
|
||||
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||
|
||||
match $setting.get_translation() {
|
||||
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
|
||||
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = $setting.get_tooltip() {
|
||||
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||
}
|
||||
|
||||
let value = $setting.mut_i32($mp.config).to_string();
|
||||
params.insert(Rc::from("value"), Rc::from(value));
|
||||
params.insert(Rc::from("min"), Rc::from($min.to_string()));
|
||||
params.insert(Rc::from("max"), Rc::from($max.to_string()));
|
||||
params.insert(Rc::from("step"), Rc::from($step.to_string()));
|
||||
|
||||
$mp
|
||||
.parser_state
|
||||
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, $root, params)?;
|
||||
|
||||
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||
slider.on_value_changed(Box::new({
|
||||
let tasks = $mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
tasks.push(Task::UpdateInt($setting, e.value as i32));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! dropdown {
|
||||
($mp:expr, $root:expr, $setting:expr, $options:expr) => {
|
||||
let id = $mp.idx.to_string();
|
||||
$mp.idx += 1;
|
||||
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||
|
||||
match $setting.get_translation() {
|
||||
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
|
||||
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = $setting.get_tooltip() {
|
||||
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||
}
|
||||
|
||||
$mp
|
||||
.parser_state
|
||||
.instantiate_template($mp.doc_params, "DropdownButton", $mp.layout, $root, params)?;
|
||||
|
||||
let setting_str = $setting.as_ref();
|
||||
let title = $setting.get_enum_title($mp.config);
|
||||
|
||||
{
|
||||
let mut label = $mp
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&$mp.layout.state, &format!("{id}_value"))?;
|
||||
label.set_text_simple(&mut $mp.layout.state.globals.get(), title);
|
||||
}
|
||||
|
||||
let btn = $mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Box::new({
|
||||
let tasks = $mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
tasks.push(Task::OpenContextMenu(
|
||||
e.mouse_pos_absolute.unwrap_or_default(),
|
||||
$options
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
if item.get_bool("Hidden").unwrap_or(false) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = item.as_ref();
|
||||
let title = SettingType::get_enum_title_inner(*item);
|
||||
let tooltip = SettingType::get_enum_tooltip_inner(*item);
|
||||
|
||||
let text = &title.text;
|
||||
let translated = if title.translated { "1" } else { "0" };
|
||||
|
||||
Some(context_menu::Cell {
|
||||
action_name: Some(format!("{setting_str};{id};{value};{text};{translated}").into()),
|
||||
title,
|
||||
tooltip,
|
||||
attribs: vec![],
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! danger_button {
|
||||
($mp:expr, $root:expr, $translation:expr, $icon:expr, $task:expr) => {
|
||||
let id = $mp.idx.to_string();
|
||||
$mp.idx += 1;
|
||||
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||
params.insert(Rc::from("translation"), Rc::from($translation));
|
||||
params.insert(Rc::from("icon"), Rc::from($icon));
|
||||
|
||||
$mp
|
||||
.parser_state
|
||||
.instantiate_template($mp.doc_params, "DangerButton", $mp.layout, $root, params)?;
|
||||
|
||||
let btn = $mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Box::new({
|
||||
let tasks = $mp.tasks.clone();
|
||||
move |_common, _e| {
|
||||
tasks.push($task);
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! autostart_app {
|
||||
($mp:expr, $root:expr, $text:expr, $ids:expr) => {
|
||||
let id = $mp.idx.to_string();
|
||||
$mp.idx += 1;
|
||||
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||
params.insert(Rc::from("text"), Rc::from($text.as_str()));
|
||||
|
||||
$mp
|
||||
.parser_state
|
||||
.instantiate_template($mp.doc_params, "AutostartApp", $mp.layout, $root, params)?;
|
||||
|
||||
let btn = $mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
let id: Rc<str> = Rc::from(id);
|
||||
|
||||
$ids.push(id.clone());
|
||||
|
||||
btn.on_click(Box::new({
|
||||
let tasks = $mp.tasks.clone();
|
||||
move |_common, _e| {
|
||||
tasks.push(Task::RemoveAutostartApp(id.clone()));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
struct MacroParams<'a> {
|
||||
layout: &'a mut Layout,
|
||||
parser_state: &'a mut ParserState,
|
||||
doc_params: &'a ParseDocumentParams<'a>,
|
||||
config: &'a mut GeneralConfig,
|
||||
tasks: Tasks<Task>,
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl<T> TabSettings<T> {
|
||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID, data: &mut T) -> anyhow::Result<Self> {
|
||||
let doc_params = ParseDocumentParams {
|
||||
globals: frontend.layout.state.globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/settings.xml"),
|
||||
extra: Default::default(),
|
||||
};
|
||||
let mut parser_state = wgui::parser::parse_from_assets(&doc_params, &mut frontend.layout, parent_id)?;
|
||||
|
||||
let root = parser_state.get_widget_id("settings_root")?;
|
||||
|
||||
let mut mp = MacroParams {
|
||||
layout: &mut frontend.layout,
|
||||
parser_state: &mut parser_state,
|
||||
doc_params: &doc_params,
|
||||
config: frontend.interface.general_config(data),
|
||||
tasks: Tasks::default(),
|
||||
idx: 9001,
|
||||
};
|
||||
|
||||
let c = category!(mp, root, "APP_SETTINGS.LOOK_AND_FEEL", "dashboard/palette.svg")?;
|
||||
checkbox!(mp, c, SettingType::OpaqueBackground);
|
||||
checkbox!(mp, c, SettingType::HideUsername);
|
||||
checkbox!(mp, c, SettingType::HideGrabHelp);
|
||||
slider_f32!(mp, c, SettingType::AnimationSpeed, 0.5, 5.0, 0.1); // min, max, step
|
||||
slider_f32!(mp, c, SettingType::RoundMultiplier, 0.5, 5.0, 0.1);
|
||||
checkbox!(mp, c, SettingType::SetsOnWatch);
|
||||
checkbox!(mp, c, SettingType::UseSkybox);
|
||||
checkbox!(mp, c, SettingType::UsePassthrough);
|
||||
checkbox!(mp, c, SettingType::Clock12h);
|
||||
|
||||
let c = category!(mp, root, "APP_SETTINGS.FEATURES", "dashboard/options.svg")?;
|
||||
checkbox!(mp, c, SettingType::NotificationsEnabled);
|
||||
checkbox!(mp, c, SettingType::NotificationsSoundEnabled);
|
||||
checkbox!(mp, c, SettingType::KeyboardSoundEnabled);
|
||||
checkbox!(mp, c, SettingType::SpaceDragUnlocked);
|
||||
checkbox!(mp, c, SettingType::SpaceRotateUnlocked);
|
||||
slider_f32!(mp, c, SettingType::SpaceDragMultiplier, -10.0, 10.0, 0.5);
|
||||
checkbox!(mp, c, SettingType::BlockGameInput);
|
||||
checkbox!(mp, c, SettingType::BlockGameInputIgnoreWatch);
|
||||
|
||||
let c = category!(mp, root, "APP_SETTINGS.CONTROLS", "dashboard/controller.svg")?;
|
||||
dropdown!(
|
||||
mp,
|
||||
c,
|
||||
SettingType::KeyboardMiddleClick,
|
||||
wlx_common::config::AltModifier::VARIANTS
|
||||
);
|
||||
checkbox!(mp, c, SettingType::FocusFollowsMouseMode);
|
||||
checkbox!(mp, c, SettingType::LeftHandedMouse);
|
||||
checkbox!(mp, c, SettingType::AllowSliding);
|
||||
checkbox!(mp, c, SettingType::InvertScrollDirectionX);
|
||||
checkbox!(mp, c, SettingType::InvertScrollDirectionY);
|
||||
slider_f32!(mp, c, SettingType::ScrollSpeed, 0.1, 5.0, 0.1);
|
||||
slider_f32!(mp, c, SettingType::LongPressDuration, 0.1, 2.0, 0.1);
|
||||
slider_f32!(mp, c, SettingType::PointerLerpFactor, 0.1, 1.0, 0.1);
|
||||
slider_f32!(mp, c, SettingType::XrClickSensitivity, 0.1, 1.0, 0.1);
|
||||
slider_f32!(mp, c, SettingType::XrClickSensitivityRelease, 0.1, 1.0, 0.1);
|
||||
slider_i32!(mp, c, SettingType::ClickFreezeTimeMs, 0, 500, 50);
|
||||
|
||||
let c = category!(mp, root, "APP_SETTINGS.MISC", "dashboard/blocks.svg")?;
|
||||
dropdown!(
|
||||
mp,
|
||||
c,
|
||||
SettingType::CaptureMethod,
|
||||
wlx_common::config::CaptureMethod::VARIANTS
|
||||
);
|
||||
checkbox!(mp, c, SettingType::XwaylandByDefault);
|
||||
checkbox!(mp, c, SettingType::UprightScreenFix);
|
||||
checkbox!(mp, c, SettingType::DoubleCursorFix);
|
||||
checkbox!(mp, c, SettingType::ScreenRenderDown);
|
||||
|
||||
let mut app_button_ids = vec![];
|
||||
|
||||
if !mp.config.autostart_apps.is_empty() {
|
||||
let c = category!(mp, root, "APP_SETTINGS.AUTOSTART_APPS", "dashboard/apps.svg")?;
|
||||
|
||||
for app in &mp.config.autostart_apps {
|
||||
autostart_app!(mp, c, app.name, app_button_ids);
|
||||
}
|
||||
}
|
||||
|
||||
let c = category!(mp, root, "APP_SETTINGS.TROUBLESHOOTING", "dashboard/cpu.svg")?;
|
||||
danger_button!(
|
||||
mp,
|
||||
c,
|
||||
"APP_SETTINGS.CLEAR_PIPEWIRE_TOKENS",
|
||||
"dashboard/display.svg",
|
||||
Task::ClearPipewireTokens
|
||||
);
|
||||
danger_button!(
|
||||
mp,
|
||||
c,
|
||||
"APP_SETTINGS.CLEAR_SAVED_STATE",
|
||||
"dashboard/binary.svg",
|
||||
Task::ClearSavedState
|
||||
);
|
||||
danger_button!(
|
||||
mp,
|
||||
c,
|
||||
"APP_SETTINGS.DELETE_ALL_CONFIGS",
|
||||
"dashboard/circle.svg",
|
||||
Task::DeleteAllConfigs
|
||||
);
|
||||
danger_button!(
|
||||
mp,
|
||||
c,
|
||||
"APP_SETTINGS.RESTART_SOFTWARE",
|
||||
"dashboard/refresh.svg",
|
||||
Task::RestartSoftware
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
app_button_ids,
|
||||
tasks: mp.tasks,
|
||||
state: parser_state,
|
||||
marker: PhantomData,
|
||||
context_menu: ContextMenu::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,377 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart};
|
||||
use wgui::{
|
||||
components::{
|
||||
button::{ButtonClickEvent, ComponentButton},
|
||||
checkbox::ComponentCheckbox,
|
||||
slider::ComponentSlider,
|
||||
},
|
||||
layout::{Layout, WidgetID},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
|
||||
task::Tasks,
|
||||
widget::label::WidgetLabel,
|
||||
windowing::context_menu,
|
||||
};
|
||||
use wlx_common::config::GeneralConfig;
|
||||
|
||||
pub fn options_category(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
translation: &str,
|
||||
icon: &str,
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("translation", translation);
|
||||
params.insert("icon", icon);
|
||||
params.insert("id", &id);
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "SettingsGroupBox", mp.layout, parent, params)?;
|
||||
|
||||
mp.parser_state.get_widget_id(&id)
|
||||
}
|
||||
|
||||
pub fn options_checkbox(mp: &mut MacroParams, parent: WidgetID, setting: SettingType) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
|
||||
match setting.get_translation() {
|
||||
Ok(translation) => params.insert("translation", translation),
|
||||
Err(raw_text) => params.insert("text", raw_text),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = setting.get_tooltip() {
|
||||
params.insert("tooltip", tooltip);
|
||||
}
|
||||
|
||||
let checked = if *setting.mut_bool(mp.config) { "1" } else { "0" };
|
||||
params.insert("checked", checked);
|
||||
|
||||
let id_cell = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "CheckBoxSetting", mp.layout, id_cell, params)?;
|
||||
|
||||
if setting.requires_restart() {
|
||||
mount_requires_restart(mp.layout, id_cell)?;
|
||||
}
|
||||
|
||||
let checkbox = mp.parser_state.fetch_component_as::<ComponentCheckbox>(&id)?;
|
||||
checkbox.on_toggle(Box::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
tasks.push(Task::UpdateBool(setting, e.checked));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn options_slider_f32(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
setting: SettingType,
|
||||
min: f32,
|
||||
max: f32,
|
||||
step: f32,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
|
||||
match setting.get_translation() {
|
||||
Ok(translation) => params.insert("translation", translation),
|
||||
Err(raw_text) => params.insert("text", raw_text),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = setting.get_tooltip() {
|
||||
params.insert("tooltip", tooltip);
|
||||
}
|
||||
|
||||
let value = setting.mut_f32(mp.config).to_string();
|
||||
params.insert_rc("value", value.into());
|
||||
params.insert_rc("min", min.to_string().into());
|
||||
params.insert_rc("max", max.to_string().into());
|
||||
params.insert_rc("step", step.to_string().into());
|
||||
|
||||
let id_cell = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "SliderSetting", mp.layout, id_cell, params)?;
|
||||
|
||||
if setting.requires_restart() {
|
||||
mount_requires_restart(mp.layout, id_cell)?;
|
||||
}
|
||||
|
||||
let slider = mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||
slider.on_value_changed(Box::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
tasks.push(Task::UpdateFloat(setting, e.value));
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn options_range_f32(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
setting: SettingType,
|
||||
setting2: SettingType,
|
||||
min: f32,
|
||||
max: f32,
|
||||
step: f32,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
|
||||
match setting.get_translation() {
|
||||
Ok(translation) => params.insert("translation", translation),
|
||||
Err(raw_text) => params.insert("text", raw_text),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = setting.get_tooltip() {
|
||||
params.insert("tooltip", tooltip);
|
||||
}
|
||||
|
||||
let value = setting.mut_f32(mp.config).to_string();
|
||||
let value2 = setting2.mut_f32(mp.config).to_string();
|
||||
params.insert_rc("value", value.into());
|
||||
params.insert_rc("value2", value2.into());
|
||||
params.insert_rc("min", min.to_string().into());
|
||||
params.insert_rc("max", max.to_string().into());
|
||||
params.insert_rc("step", step.to_string().into());
|
||||
|
||||
let id_cell = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "RangeSetting", mp.layout, id_cell, params)?;
|
||||
|
||||
if setting.requires_restart() {
|
||||
mount_requires_restart(mp.layout, id_cell)?;
|
||||
}
|
||||
|
||||
let slider = mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||
slider.on_value_changed(Box::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
if matches!(e.index, wgui::components::slider::ValueIndex::Primary) {
|
||||
tasks.push(Task::UpdateFloat(setting, e.value));
|
||||
} else {
|
||||
tasks.push(Task::UpdateFloat(setting2, e.value));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn options_slider_i32(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
setting: SettingType,
|
||||
min: i32,
|
||||
max: i32,
|
||||
step: i32,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
|
||||
match setting.get_translation() {
|
||||
Ok(translation) => params.insert("translation", translation),
|
||||
Err(raw_text) => params.insert("text", raw_text),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = setting.get_tooltip() {
|
||||
params.insert("tooltip", tooltip);
|
||||
}
|
||||
|
||||
let id_cell = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
let value = setting.mut_i32(mp.config).to_string();
|
||||
params.insert_rc("value", value.into());
|
||||
params.insert_rc("min", min.to_string().into());
|
||||
params.insert_rc("max", max.to_string().into());
|
||||
params.insert_rc("step", step.to_string().into());
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "SliderSetting", mp.layout, id_cell, params)?;
|
||||
|
||||
if setting.requires_restart() {
|
||||
mount_requires_restart(mp.layout, id_cell)?;
|
||||
}
|
||||
|
||||
let slider = mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||
slider.on_value_changed(Box::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, e| {
|
||||
tasks.push(Task::UpdateInt(setting, e.value as i32));
|
||||
}
|
||||
}));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn options_dropdown<EnumType>(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
setting: &'static SettingType,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
EnumType: strum::VariantArray + strum::EnumProperty + std::convert::AsRef<str> + Copy + 'static,
|
||||
{
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
|
||||
match setting.get_translation() {
|
||||
Ok(translation) => params.insert("translation", translation),
|
||||
Err(raw_text) => params.insert("text", raw_text),
|
||||
};
|
||||
|
||||
if let Some(tooltip) = setting.get_tooltip() {
|
||||
params.insert("tooltip", tooltip);
|
||||
}
|
||||
|
||||
let id_cell = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, id_cell, params)?;
|
||||
|
||||
if setting.requires_restart() {
|
||||
mount_requires_restart(mp.layout, id_cell)?;
|
||||
}
|
||||
|
||||
let setting_str = setting.as_ref();
|
||||
let title = setting.get_enum_title(mp.config);
|
||||
|
||||
{
|
||||
let mut label = mp
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&mp.layout.state, &format!("{id}_value"))?;
|
||||
label.set_text_simple(&mut mp.layout.state.globals.get(), title);
|
||||
}
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Rc::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, e: ButtonClickEvent| {
|
||||
tasks.push(Task::OpenContextMenu(
|
||||
e.mouse_pos_absolute.unwrap_or_default(),
|
||||
EnumType::VARIANTS
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
if item.get_bool("Hidden").unwrap_or(false) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = item.as_ref();
|
||||
let title = SettingType::get_enum_title_inner(*item);
|
||||
let tooltip = SettingType::get_enum_tooltip_inner(*item);
|
||||
|
||||
let text = &title.text;
|
||||
let translated = if title.translated { "1" } else { "0" };
|
||||
|
||||
Some(context_menu::Cell {
|
||||
action_name: Some(format!("{setting_str};{id};{value};{text};{translated}").into()),
|
||||
title,
|
||||
tooltip,
|
||||
attribs: vec![],
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn options_danger_button(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
translation: &str,
|
||||
icon: &str,
|
||||
task: Task,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
params.insert("translation", translation);
|
||||
params.insert("icon", icon);
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "DangerButton", mp.layout, parent, params)?;
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Rc::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, _e| {
|
||||
tasks.push(task.clone());
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn options_autostart_app(
|
||||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
text: &str,
|
||||
ids: &mut Vec<Rc<str>>,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
params.insert("text", text);
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "AutostartApp", mp.layout, parent, params)?;
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
let id: Rc<str> = Rc::from(id);
|
||||
|
||||
ids.push(id.clone());
|
||||
|
||||
btn.on_click(Rc::new({
|
||||
let tasks = mp.tasks.clone();
|
||||
move |_common, _e| {
|
||||
tasks.push(Task::RemoveAutostartApp(id.clone()));
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct MacroParams<'a> {
|
||||
pub layout: &'a mut Layout,
|
||||
pub parser_state: &'a mut ParserState,
|
||||
pub doc_params: &'a ParseDocumentParams<'a>,
|
||||
pub config: &'a mut GeneralConfig,
|
||||
pub tasks: Tasks<settings::Task>,
|
||||
pub idx: usize,
|
||||
}
|
||||
|
|
@ -0,0 +1,699 @@
|
|||
use glam::Vec2;
|
||||
use std::{marker::PhantomData, rc::Rc, str::FromStr};
|
||||
use strum::{AsRefStr, EnumProperty, EnumString};
|
||||
use wgui::{
|
||||
assets::AssetPath,
|
||||
components::tabs::ComponentTabs,
|
||||
drawing,
|
||||
event::StyleSetRequest,
|
||||
globals::WguiGlobals,
|
||||
i18n::Translation,
|
||||
layout::{Layout, WidgetID},
|
||||
log::LogErr,
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
renderer_vk::text::{FontWeight, TextStyle},
|
||||
taffy::{self, prelude::length},
|
||||
task::Tasks,
|
||||
widget::{
|
||||
div::WidgetDiv,
|
||||
label::{WidgetLabel, WidgetLabelParams},
|
||||
},
|
||||
windowing::context_menu::{self, Blueprint, ContextMenu, TickResult},
|
||||
};
|
||||
use wlx_common::{
|
||||
config::GeneralConfig,
|
||||
config_io::ConfigRoot,
|
||||
dash_interface::{ConfigChangeKind, InterfaceFeats, RecenterMode},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
frontend::{Frontend, FrontendTask, FrontendTasks},
|
||||
tab::{Tab, TabType, settings::macros::MacroParams},
|
||||
views::ViewUpdateParams,
|
||||
};
|
||||
|
||||
mod macros;
|
||||
mod tab_autostart_apps;
|
||||
mod tab_controls;
|
||||
mod tab_features;
|
||||
mod tab_look_and_feel;
|
||||
mod tab_misc;
|
||||
mod tab_skybox;
|
||||
mod tab_space_drag;
|
||||
mod tab_troubleshooting;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum TabNameEnum {
|
||||
AutostartApps,
|
||||
Controls,
|
||||
Features,
|
||||
LookAndFeel,
|
||||
Misc,
|
||||
Skybox,
|
||||
SpaceDrag,
|
||||
Troubleshooting,
|
||||
}
|
||||
|
||||
impl TabNameEnum {
|
||||
fn from_string(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"autostart_apps" => Some(TabNameEnum::AutostartApps),
|
||||
"controls" => Some(TabNameEnum::Controls),
|
||||
"features" => Some(TabNameEnum::Features),
|
||||
"look_and_feel" => Some(TabNameEnum::LookAndFeel),
|
||||
"misc" => Some(TabNameEnum::Misc),
|
||||
"skybox" => Some(TabNameEnum::Skybox),
|
||||
"space_drag" => Some(TabNameEnum::SpaceDrag),
|
||||
"troubleshooting" => Some(TabNameEnum::Troubleshooting),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Task {
|
||||
ClearPipewireTokens,
|
||||
ClearSavedState,
|
||||
DeleteAllConfigs,
|
||||
OpenContextMenu(Vec2, Vec<context_menu::Cell>),
|
||||
RemoveAutostartApp(Rc<str>),
|
||||
ResetPlayspace,
|
||||
RestartSoftware,
|
||||
SetTab(TabNameEnum),
|
||||
SettingUpdated(SettingType),
|
||||
ShowWelcomeScreen,
|
||||
UpdateBool(SettingType, bool),
|
||||
UpdateFloat(SettingType, f32),
|
||||
UpdateInt(SettingType, i32),
|
||||
}
|
||||
|
||||
struct SettingsMountParams<'a> {
|
||||
mp: &'a mut MacroParams<'a>,
|
||||
frontend_tasks: &'a FrontendTasks,
|
||||
id_parent: WidgetID,
|
||||
feats: InterfaceFeats,
|
||||
}
|
||||
|
||||
struct SettingUpdatedParams<'a> {
|
||||
layout: &'a mut Layout,
|
||||
config: &'a GeneralConfig,
|
||||
setting_type: SettingType,
|
||||
}
|
||||
|
||||
trait SettingsTab {
|
||||
fn update(&mut self, _par: &mut ViewUpdateParams) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setting_updated(&mut self, _sup: &mut SettingUpdatedParams) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TabSettings<T> {
|
||||
pub state: ParserState,
|
||||
|
||||
app_button_ids: Vec<Rc<str>>,
|
||||
context_menu: ContextMenu,
|
||||
|
||||
current_tab: Option<Box<dyn SettingsTab>>,
|
||||
|
||||
tasks: Tasks<Task>,
|
||||
marker: PhantomData<T>,
|
||||
frontend_tasks: FrontendTasks,
|
||||
}
|
||||
|
||||
impl<T> Tab<T> for TabSettings<T> {
|
||||
fn get_type(&self) -> TabType {
|
||||
TabType::Settings
|
||||
}
|
||||
|
||||
fn update(&mut self, frontend: &mut Frontend<T>, _time_ms: u32, data: &mut T) -> anyhow::Result<()> {
|
||||
if let Some(tab) = &mut self.current_tab {
|
||||
let mut config_change_kind = None;
|
||||
|
||||
tab.update(&mut ViewUpdateParams {
|
||||
layout: &mut frontend.layout,
|
||||
executor: &frontend.executor,
|
||||
general_config: frontend.interface.general_config(data),
|
||||
config_change_kind: &mut config_change_kind,
|
||||
})?;
|
||||
|
||||
if let Some(kind) = config_change_kind {
|
||||
frontend.interface.config_changed(data, kind);
|
||||
}
|
||||
}
|
||||
|
||||
let mut changed = None;
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::SetTab(tab) => {
|
||||
self.set_tab(frontend, data, tab)?;
|
||||
}
|
||||
Task::ShowWelcomeScreen => {
|
||||
self.frontend_tasks.push(FrontendTask::SetTab(TabType::Welcome));
|
||||
}
|
||||
Task::UpdateBool(setting, n) => {
|
||||
self.tasks.push(Task::SettingUpdated(setting));
|
||||
if let Some(task) = setting.get_frontend_task() {
|
||||
frontend.tasks.push(task)
|
||||
}
|
||||
let config = frontend.interface.general_config(data);
|
||||
*setting.mut_bool(config) = n;
|
||||
changed = Some(setting.change_kind());
|
||||
}
|
||||
Task::UpdateFloat(setting, n) => {
|
||||
self.tasks.push(Task::SettingUpdated(setting));
|
||||
if let Some(task) = setting.get_frontend_task() {
|
||||
frontend.tasks.push(task)
|
||||
}
|
||||
let config = frontend.interface.general_config(data);
|
||||
*setting.mut_f32(config) = n;
|
||||
changed = Some(setting.change_kind());
|
||||
}
|
||||
Task::UpdateInt(setting, n) => {
|
||||
self.tasks.push(Task::SettingUpdated(setting));
|
||||
if let Some(task) = setting.get_frontend_task() {
|
||||
frontend.tasks.push(task)
|
||||
}
|
||||
let config = frontend.interface.general_config(data);
|
||||
*setting.mut_i32(config) = n;
|
||||
changed = Some(setting.change_kind());
|
||||
}
|
||||
Task::ClearPipewireTokens => {
|
||||
let _ = std::fs::remove_file(ConfigRoot::Generic.get_conf_d_path().join("pw_tokens.yaml"))
|
||||
.log_err("Could not remove pw_tokens.yaml");
|
||||
}
|
||||
Task::ClearSavedState => {
|
||||
let _ = std::fs::remove_file(ConfigRoot::Generic.get_conf_d_path().join("zz-saved-state.json5"))
|
||||
.log_err("Could not remove zz-saved-state.json5");
|
||||
}
|
||||
Task::DeleteAllConfigs => {
|
||||
let path = ConfigRoot::Generic.get_conf_d_path();
|
||||
std::fs::remove_dir_all(&path)?;
|
||||
std::fs::create_dir(&path)?;
|
||||
}
|
||||
Task::ResetPlayspace => {
|
||||
frontend.interface.recenter_playspace(data, RecenterMode::Reset)?;
|
||||
return Ok(());
|
||||
}
|
||||
Task::RestartSoftware => {
|
||||
frontend.interface.restart(data);
|
||||
return Ok(());
|
||||
}
|
||||
Task::OpenContextMenu(position, cells) => {
|
||||
self.context_menu.open(context_menu::OpenParams {
|
||||
on_custom_attribs: None,
|
||||
position,
|
||||
blueprint: Blueprint::Cells(cells),
|
||||
});
|
||||
}
|
||||
Task::RemoveAutostartApp(button_id) => {
|
||||
if let (Some(idx), Ok(widget)) = (
|
||||
self.app_button_ids.iter().position(|x| button_id.eq(x)),
|
||||
self.state.get_widget_id(&format!("{button_id}_root")),
|
||||
) {
|
||||
self.app_button_ids.remove(idx);
|
||||
let config = frontend.interface.general_config(data);
|
||||
config.autostart_apps.remove(idx);
|
||||
frontend.layout.remove_widget(widget);
|
||||
changed = Some(ConfigChangeKind::OverlayConfig);
|
||||
}
|
||||
}
|
||||
Task::SettingUpdated(setting) => {
|
||||
if let Some(tab) = &mut self.current_tab {
|
||||
tab.setting_updated(&mut SettingUpdatedParams {
|
||||
layout: &mut frontend.layout,
|
||||
config: frontend.interface.general_config(data),
|
||||
setting_type: setting,
|
||||
})?;
|
||||
}
|
||||
match setting {
|
||||
SettingType::UiAnimationSpeed | SettingType::UiGradientIntensity | SettingType::UiRoundMultiplier => {
|
||||
// todo: currently, wayvr restart is required to apply these changes (WguiTheme is Rc)
|
||||
}
|
||||
_ => { /* do nothing */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dropdown handling
|
||||
if let TickResult::Action(name) = self.context_menu.tick(&mut frontend.layout, &mut self.state)?
|
||||
&& let (Some(setting), Some(id), Some(value), Some(text), Some(translated)) = {
|
||||
let mut s = name.splitn(5, ';');
|
||||
(s.next(), s.next(), s.next(), s.next(), s.next())
|
||||
} {
|
||||
let mut common = frontend.layout.common();
|
||||
let mut label = self
|
||||
.state
|
||||
.fetch_widget_as::<WidgetLabel>(common.state, &format!("{id}_value"))?;
|
||||
|
||||
let translation = Translation {
|
||||
text: text.into(),
|
||||
translated: translated == "1",
|
||||
};
|
||||
|
||||
label.set_text(&mut common, translation);
|
||||
|
||||
let setting = SettingType::from_str(setting).expect("Invalid Enum string");
|
||||
let config = frontend.interface.general_config(data);
|
||||
setting.set_enum(config, value);
|
||||
changed = Some(ConfigChangeKind::OverlayConfig);
|
||||
}
|
||||
|
||||
// Notify overlays of the change
|
||||
if let Some(changed) = changed {
|
||||
frontend.interface.config_changed(data, changed);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Sorted alphabetically
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, AsRefStr, EnumString)]
|
||||
enum SettingType {
|
||||
AllowSliding,
|
||||
BlockGameInput,
|
||||
BlockGameInputIgnoreWatch,
|
||||
BlockPosesOnKbdInteraction,
|
||||
CaptureMethod,
|
||||
ClickFreezeTimeMs,
|
||||
Clock12h,
|
||||
DoubleCursorFix,
|
||||
FocusFollowsMouseMode,
|
||||
GridOpacity,
|
||||
HandsfreePointer,
|
||||
HideGrabHelp,
|
||||
HideUsername,
|
||||
InputEmulationMethod,
|
||||
InvertScrollDirectionX,
|
||||
InvertScrollDirectionY,
|
||||
KeyboardMiddleClick,
|
||||
KeyboardSoundEnabled,
|
||||
Language,
|
||||
LeftHandedMouse,
|
||||
LongPressDuration,
|
||||
NotificationsEnabled,
|
||||
NotificationsSoundEnabled,
|
||||
OpaqueBackground,
|
||||
PointerLerpFactor,
|
||||
ScreenRenderDown,
|
||||
ScrollSpeed,
|
||||
EnableWatch,
|
||||
SetsOnWatch,
|
||||
SpaceDragMultiplier,
|
||||
SpaceDragUnlocked,
|
||||
SpaceGravityDamping,
|
||||
SpaceGravityEnabled,
|
||||
SpaceGravityFlingStrength,
|
||||
SpaceGravityGravity,
|
||||
SpaceGravityGroundFriction,
|
||||
SpaceGravityFloorHeight,
|
||||
SpaceRotateUnlocked,
|
||||
UiAnimationSpeed,
|
||||
UiGradientIntensity,
|
||||
UiRoundMultiplier,
|
||||
UprightScreenFix,
|
||||
UsePassthrough,
|
||||
UseSkybox,
|
||||
WatchViewAngleMax,
|
||||
WatchViewAngleMin,
|
||||
XwaylandByDefault,
|
||||
}
|
||||
|
||||
impl SettingType {
|
||||
pub fn change_kind(self) -> ConfigChangeKind {
|
||||
match self {
|
||||
Self::UseSkybox | Self::UsePassthrough => ConfigChangeKind::EnvironmentBlend,
|
||||
_ => ConfigChangeKind::OverlayConfig,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mut_bool(self, config: &mut GeneralConfig) -> &mut bool {
|
||||
match self {
|
||||
Self::AllowSliding => &mut config.allow_sliding,
|
||||
Self::BlockGameInput => &mut config.block_game_input,
|
||||
Self::BlockGameInputIgnoreWatch => &mut config.block_game_input_ignore_watch,
|
||||
Self::BlockPosesOnKbdInteraction => &mut config.block_poses_on_kbd_interaction,
|
||||
Self::Clock12h => &mut config.clock_12h,
|
||||
Self::DoubleCursorFix => &mut config.double_cursor_fix,
|
||||
Self::EnableWatch => &mut config.enable_watch,
|
||||
Self::FocusFollowsMouseMode => &mut config.focus_follows_mouse_mode,
|
||||
Self::HideGrabHelp => &mut config.hide_grab_help,
|
||||
Self::HideUsername => &mut config.hide_username,
|
||||
Self::InvertScrollDirectionX => &mut config.invert_scroll_direction_x,
|
||||
Self::InvertScrollDirectionY => &mut config.invert_scroll_direction_y,
|
||||
Self::KeyboardSoundEnabled => &mut config.keyboard_sound_enabled,
|
||||
Self::LeftHandedMouse => &mut config.left_handed_mouse,
|
||||
Self::NotificationsEnabled => &mut config.notifications_enabled,
|
||||
Self::NotificationsSoundEnabled => &mut config.notifications_sound_enabled,
|
||||
Self::OpaqueBackground => &mut config.opaque_background,
|
||||
Self::ScreenRenderDown => &mut config.screen_render_down,
|
||||
Self::SetsOnWatch => &mut config.sets_on_watch,
|
||||
Self::SpaceDragUnlocked => &mut config.space_drag_unlocked,
|
||||
Self::SpaceGravityEnabled => &mut config.space_gravity_enabled,
|
||||
Self::SpaceRotateUnlocked => &mut config.space_rotate_unlocked,
|
||||
Self::UprightScreenFix => &mut config.upright_screen_fix,
|
||||
Self::UsePassthrough => &mut config.use_passthrough,
|
||||
Self::UseSkybox => &mut config.use_skybox,
|
||||
Self::XwaylandByDefault => &mut config.xwayland_by_default,
|
||||
_ => panic!("Requested bool for non-bool SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mut_f32(self, config: &mut GeneralConfig) -> &mut f32 {
|
||||
match self {
|
||||
Self::GridOpacity => &mut config.grid_opacity,
|
||||
Self::LongPressDuration => &mut config.long_press_duration,
|
||||
Self::PointerLerpFactor => &mut config.pointer_lerp_factor,
|
||||
Self::ScrollSpeed => &mut config.scroll_speed,
|
||||
Self::SpaceDragMultiplier => &mut config.space_drag_multiplier,
|
||||
Self::SpaceGravityDamping => &mut config.space_gravity_damping,
|
||||
Self::SpaceGravityFlingStrength => &mut config.space_gravity_fling_strength,
|
||||
Self::SpaceGravityGravity => &mut config.space_gravity_gravity,
|
||||
Self::SpaceGravityGroundFriction => &mut config.space_gravity_ground_friction,
|
||||
Self::SpaceGravityFloorHeight => &mut config.space_gravity_floor_height,
|
||||
Self::UiAnimationSpeed => &mut config.ui_animation_speed,
|
||||
Self::UiGradientIntensity => &mut config.ui_gradient_intensity,
|
||||
Self::UiRoundMultiplier => &mut config.ui_round_multiplier,
|
||||
Self::WatchViewAngleMax => &mut config.watch_view_angle_max,
|
||||
Self::WatchViewAngleMin => &mut config.watch_view_angle_min,
|
||||
_ => panic!("Requested f32 for non-f32 SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mut_i32(self, config: &mut GeneralConfig) -> &mut i32 {
|
||||
match self {
|
||||
Self::ClickFreezeTimeMs => &mut config.click_freeze_time_ms,
|
||||
_ => panic!("Requested i32 for non-i32 SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_enum(self, config: &mut GeneralConfig, value: &str) {
|
||||
match self {
|
||||
Self::CaptureMethod => {
|
||||
config.capture_method = wlx_common::config::CaptureMethod::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
Self::InputEmulationMethod => {
|
||||
config.input_emulation_method =
|
||||
wlx_common::config::InputEmulationMethod::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
Self::KeyboardMiddleClick => {
|
||||
config.keyboard_middle_click_mode =
|
||||
wlx_common::config::AltModifier::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
Self::HandsfreePointer => {
|
||||
config.handsfree_pointer = wlx_common::config::HandsfreePointer::from_str(value).expect("Invalid enum value!")
|
||||
}
|
||||
Self::Language => {
|
||||
config.language = Some(wlx_common::locale::Language::from_str(value).expect("Invalid enum value!"))
|
||||
}
|
||||
_ => panic!("Requested enum for non-enum SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_enum_title(self, config: &mut GeneralConfig) -> Translation {
|
||||
match self {
|
||||
Self::CaptureMethod => Self::get_enum_title_inner(config.capture_method),
|
||||
Self::InputEmulationMethod => Self::get_enum_title_inner(config.input_emulation_method),
|
||||
Self::KeyboardMiddleClick => Self::get_enum_title_inner(config.keyboard_middle_click_mode),
|
||||
Self::HandsfreePointer => Self::get_enum_title_inner(config.handsfree_pointer),
|
||||
Self::Language => match &config.language {
|
||||
Some(lang) => Self::get_enum_title_inner(*lang),
|
||||
None => Translation::from_translation_key("APP_SETTINGS.OPTION.AUTO"),
|
||||
},
|
||||
_ => panic!("Requested enum for non-enum SettingType"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_enum_title_inner<E>(value: E) -> Translation
|
||||
where
|
||||
E: EnumProperty + AsRef<str>,
|
||||
{
|
||||
value
|
||||
.get_str("Translation")
|
||||
.map(Translation::from_translation_key)
|
||||
.or_else(|| value.get_str("Text").map(Translation::from_raw_text))
|
||||
.unwrap_or_else(|| Translation::from_raw_text(value.as_ref()))
|
||||
}
|
||||
|
||||
fn get_enum_tooltip_inner<E>(value: E) -> Option<Translation>
|
||||
where
|
||||
E: EnumProperty + AsRef<str>,
|
||||
{
|
||||
value.get_str("Tooltip").map(Translation::from_translation_key)
|
||||
}
|
||||
|
||||
/// Ok is translation, Err is raw text
|
||||
/// `match` sorted alphabetically
|
||||
fn get_translation(self) -> Result<&'static str, &'static str> {
|
||||
match self {
|
||||
Self::AllowSliding => Ok("APP_SETTINGS.ALLOW_SLIDING"),
|
||||
Self::BlockGameInput => Ok("APP_SETTINGS.BLOCK_GAME_INPUT"),
|
||||
Self::BlockGameInputIgnoreWatch => Ok("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH"),
|
||||
Self::BlockPosesOnKbdInteraction => Ok("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION"),
|
||||
Self::CaptureMethod => Ok("APP_SETTINGS.CAPTURE_METHOD"),
|
||||
Self::ClickFreezeTimeMs => Ok("APP_SETTINGS.CLICK_FREEZE_TIME_MS"),
|
||||
Self::Clock12h => Ok("APP_SETTINGS.CLOCK_12H"),
|
||||
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
||||
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
|
||||
Self::GridOpacity => Ok("APP_SETTINGS.GRID_OPACITY"),
|
||||
Self::HandsfreePointer => Ok("APP_SETTINGS.HANDSFREE_POINTER"),
|
||||
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
||||
Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"),
|
||||
Self::InputEmulationMethod => Ok("APP_SETTINGS.INPUT_EMULATION_METHOD"),
|
||||
Self::InvertScrollDirectionX => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_X"),
|
||||
Self::InvertScrollDirectionY => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_Y"),
|
||||
Self::KeyboardMiddleClick => Ok("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK"),
|
||||
Self::KeyboardSoundEnabled => Ok("APP_SETTINGS.KEYBOARD_SOUND_ENABLED"),
|
||||
Self::Language => Ok("APP_SETTINGS.LANGUAGE"),
|
||||
Self::LeftHandedMouse => Ok("APP_SETTINGS.LEFT_HANDED_MOUSE"),
|
||||
Self::LongPressDuration => Ok("APP_SETTINGS.LONG_PRESS_DURATION"),
|
||||
Self::NotificationsEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_ENABLED"),
|
||||
Self::NotificationsSoundEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED"),
|
||||
Self::OpaqueBackground => Ok("APP_SETTINGS.OPAQUE_BACKGROUND"),
|
||||
Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"),
|
||||
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
|
||||
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
|
||||
Self::EnableWatch => Ok("APP_SETTINGS.ENABLE_WATCH"),
|
||||
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
|
||||
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
|
||||
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),
|
||||
Self::SpaceGravityDamping => Ok("APP_SETTINGS.SPACE_GRAVITY_DAMPING"),
|
||||
Self::SpaceGravityEnabled => Ok("APP_SETTINGS.ENABLED"),
|
||||
Self::SpaceGravityFlingStrength => Ok("APP_SETTINGS.SPACE_GRAVITY_FLING_STRENGTH"),
|
||||
Self::SpaceGravityGravity => Ok("APP_SETTINGS.SPACE_GRAVITY_GRAVITY"),
|
||||
Self::SpaceGravityGroundFriction => Ok("APP_SETTINGS.SPACE_GRAVITY_GROUND_FRICTION"),
|
||||
Self::SpaceGravityFloorHeight => Ok("APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT"),
|
||||
Self::SpaceRotateUnlocked => Ok("APP_SETTINGS.SPACE_ROTATE_UNLOCKED"),
|
||||
Self::UiAnimationSpeed => Ok("APP_SETTINGS.ANIMATION_SPEED"),
|
||||
Self::UiGradientIntensity => Ok("APP_SETTINGS.UI_GRADIENT_INTENSITY"),
|
||||
Self::UiRoundMultiplier => Ok("APP_SETTINGS.ROUND_MULTIPLIER"),
|
||||
Self::UprightScreenFix => Ok("APP_SETTINGS.UPRIGHT_SCREEN_FIX"),
|
||||
Self::UsePassthrough => Ok("APP_SETTINGS.USE_PASSTHROUGH"),
|
||||
Self::UseSkybox => Ok("APP_SETTINGS.USE_SKYBOX"),
|
||||
Self::WatchViewAngleMax => Ok("APP_SETTINGS.WATCH_VIEW_ANGLE"),
|
||||
Self::WatchViewAngleMin => Ok("APP_SETTINGS.WATCH_VIEW_ANGLE"),
|
||||
Self::XwaylandByDefault => Ok("APP_SETTINGS.XWAYLAND_BY_DEFAULT"),
|
||||
}
|
||||
}
|
||||
|
||||
/// `match` sorted alphabetically
|
||||
fn get_tooltip(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::BlockGameInput => Some("APP_SETTINGS.BLOCK_GAME_INPUT_HELP"),
|
||||
Self::BlockGameInputIgnoreWatch => Some("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH_HELP"),
|
||||
Self::BlockPosesOnKbdInteraction => Some("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION_HELP"),
|
||||
Self::CaptureMethod => Some("APP_SETTINGS.CAPTURE_METHOD_HELP"),
|
||||
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
||||
Self::GridOpacity => Some("APP_SETTINGS.GRID_OPACITY_HELP"),
|
||||
Self::HandsfreePointer => Some("APP_SETTINGS.HANDSFREE_POINTER_HELP"),
|
||||
Self::InputEmulationMethod => Some("APP_SETTINGS.INPUT_EMULATION_METHOD_HELP"),
|
||||
Self::KeyboardMiddleClick => Some("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK_HELP"),
|
||||
Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"),
|
||||
Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"),
|
||||
Self::SpaceGravityDamping => Some("APP_SETTINGS.SPACE_GRAVITY_DAMPING_HELP"),
|
||||
Self::SpaceGravityFlingStrength => Some("APP_SETTINGS.SPACE_GRAVITY_FLING_STRENGTH_HELP"),
|
||||
Self::SpaceGravityFloorHeight => Some("APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT_HELP"),
|
||||
Self::SpaceGravityGravity => Some("APP_SETTINGS.SPACE_GRAVITY_GRAVITY_HELP"),
|
||||
Self::SpaceGravityGroundFriction => Some("APP_SETTINGS.SPACE_GRAVITY_GROUND_FRICTION_HELP"),
|
||||
Self::UprightScreenFix => Some("APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP"),
|
||||
Self::UsePassthrough => Some("APP_SETTINGS.USE_PASSTHROUGH_HELP"),
|
||||
Self::UseSkybox => Some("APP_SETTINGS.USE_SKYBOX_HELP"),
|
||||
Self::WatchViewAngleMax => Some("APP_SETTINGS.WATCH_VIEW_ANGLE_HELP"),
|
||||
Self::WatchViewAngleMin => Some("APP_SETTINGS.WATCH_VIEW_ANGLE_HELP"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn requires_restart(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::UiAnimationSpeed
|
||||
| Self::UiRoundMultiplier
|
||||
| Self::UiGradientIntensity
|
||||
| Self::UprightScreenFix
|
||||
| Self::DoubleCursorFix
|
||||
| Self::Language
|
||||
| Self::CaptureMethod
|
||||
| Self::InputEmulationMethod
|
||||
)
|
||||
}
|
||||
|
||||
fn get_frontend_task(self) -> Option<FrontendTask> {
|
||||
match self {
|
||||
Self::Clock12h => Some(FrontendTask::RefreshClock),
|
||||
Self::OpaqueBackground => Some(FrontendTask::RefreshBackground),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creates a simple div with horizontal, centered flow
|
||||
pub fn horiz_cell(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<WidgetID> {
|
||||
let (pair, _) = layout.add_child(
|
||||
parent,
|
||||
WidgetDiv::create(),
|
||||
taffy::Style {
|
||||
flex_direction: taffy::FlexDirection::Row,
|
||||
align_items: Some(taffy::AlignItems::Center),
|
||||
gap: length(8.0),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(pair.id)
|
||||
}
|
||||
|
||||
fn mount_requires_restart(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<()> {
|
||||
let content = Translation::from_translation_key("APP_SETTINGS.REQUIRES_RESTART");
|
||||
let label = WidgetLabel::create(
|
||||
&mut layout.state,
|
||||
WidgetLabelParams {
|
||||
content,
|
||||
style: TextStyle {
|
||||
wrap: false,
|
||||
color: Some(drawing::Color::new(1.0, 0.5, 0.5, 1.0)),
|
||||
weight: Some(FontWeight::Bold),
|
||||
size: Some(10.0),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
layout.add_child(parent, label, Default::default())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn doc_params(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
|
||||
ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/settings.xml"),
|
||||
extra: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TabSettings<T> {
|
||||
fn set_tab(&mut self, frontend: &mut Frontend<T>, data: &mut T, name: TabNameEnum) -> anyhow::Result<()> {
|
||||
let root = self.state.get_widget_id("settings_root")?;
|
||||
frontend.layout.remove_children(root);
|
||||
let globals = frontend.layout.state.globals.clone();
|
||||
self.current_tab = None;
|
||||
|
||||
let feats = frontend.interface.get_feats(data);
|
||||
|
||||
let mut mp = MacroParams {
|
||||
layout: &mut frontend.layout,
|
||||
parser_state: &mut self.state,
|
||||
doc_params: &doc_params(&globals),
|
||||
config: frontend.interface.general_config(data),
|
||||
tasks: self.tasks.clone(),
|
||||
idx: 9001,
|
||||
};
|
||||
|
||||
let settings_mount_params = SettingsMountParams {
|
||||
mp: &mut mp,
|
||||
id_parent: root,
|
||||
frontend_tasks: &self.frontend_tasks,
|
||||
feats,
|
||||
};
|
||||
|
||||
match name {
|
||||
TabNameEnum::LookAndFeel => {
|
||||
self.current_tab = Some(Box::new(tab_look_and_feel::State::mount(settings_mount_params)?));
|
||||
}
|
||||
TabNameEnum::Features => {
|
||||
self.current_tab = Some(Box::new(tab_features::State::mount(settings_mount_params)?));
|
||||
}
|
||||
TabNameEnum::SpaceDrag => {
|
||||
self.current_tab = Some(Box::new(tab_space_drag::State::mount(settings_mount_params)?));
|
||||
}
|
||||
TabNameEnum::Controls => {
|
||||
self.current_tab = Some(Box::new(tab_controls::State::mount(settings_mount_params)?));
|
||||
}
|
||||
TabNameEnum::Misc => {
|
||||
self.current_tab = Some(Box::new(tab_misc::State::mount(settings_mount_params)?));
|
||||
}
|
||||
TabNameEnum::AutostartApps => {
|
||||
self.current_tab = Some(Box::new(tab_autostart_apps::State::mount(
|
||||
settings_mount_params,
|
||||
&mut self.app_button_ids,
|
||||
)?));
|
||||
}
|
||||
TabNameEnum::Troubleshooting => {
|
||||
self.current_tab = Some(Box::new(tab_troubleshooting::State::mount(settings_mount_params)?));
|
||||
}
|
||||
TabNameEnum::Skybox => {
|
||||
self.current_tab = Some(Box::new(tab_skybox::State::mount(settings_mount_params)?));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID, data: &mut T) -> anyhow::Result<Self> {
|
||||
let doc_params = ParseDocumentParams {
|
||||
globals: frontend.layout.state.globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/tab/settings.xml"),
|
||||
extra: Default::default(),
|
||||
};
|
||||
|
||||
let parser_state = wgui::parser::parse_from_assets(&doc_params, &mut frontend.layout, parent_id)?;
|
||||
let tasks = Tasks::default();
|
||||
let tabs = parser_state.fetch_component_as::<ComponentTabs>("tabs")?;
|
||||
|
||||
if !frontend.interface.get_feats(data).openxr {
|
||||
let skybox_btn = tabs.get_tab_button("skybox").unwrap();
|
||||
frontend
|
||||
.layout
|
||||
.common()
|
||||
.alterables
|
||||
.set_style(skybox_btn.get_rect(), StyleSetRequest::Display(taffy::Display::None));
|
||||
}
|
||||
|
||||
tabs.on_select({
|
||||
let tasks = tasks.clone();
|
||||
Rc::new(move |_common, evt| {
|
||||
if let Some(tab) = TabNameEnum::from_string(&evt.name) {
|
||||
tasks.push(Task::SetTab(tab));
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
tasks.push(Task::SetTab(TabNameEnum::LookAndFeel));
|
||||
|
||||
Ok(Self {
|
||||
app_button_ids: Vec::new(),
|
||||
tasks,
|
||||
state: parser_state,
|
||||
marker: PhantomData,
|
||||
context_menu: ContextMenu::default(),
|
||||
current_tab: None,
|
||||
frontend_tasks: frontend.tasks.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::tab::settings::{
|
||||
SettingsMountParams, SettingsTab,
|
||||
macros::{options_autostart_app, options_category},
|
||||
};
|
||||
|
||||
pub struct State {}
|
||||
|
||||
impl SettingsTab for State {}
|
||||
|
||||
impl State {
|
||||
pub fn mount(par: SettingsMountParams, app_button_ids: &mut Vec<Rc<str>>) -> anyhow::Result<State> {
|
||||
*app_button_ids = Vec::new();
|
||||
|
||||
if !par.mp.config.autostart_apps.is_empty() {
|
||||
let c = options_category(
|
||||
par.mp,
|
||||
par.id_parent,
|
||||
"APP_SETTINGS.AUTOSTART_APPS",
|
||||
"dashboard/apps.svg",
|
||||
)?;
|
||||
|
||||
// todo: prevent clone
|
||||
let autostart_apps = par.mp.config.autostart_apps.clone();
|
||||
for app in autostart_apps {
|
||||
options_autostart_app(par.mp, c, &app.name, app_button_ids)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(State {})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
use std::rc::Rc;
|
||||
use wgui::parser::TemplateParams;
|
||||
use wgui::{
|
||||
components::button::ComponentButton, globals::WguiGlobals, layout::WidgetID, parser::Fetchable, task::Tasks,
|
||||
};
|
||||
|
||||
use crate::util::popup_manager::PopupHolder;
|
||||
|
||||
use crate::{
|
||||
frontend::FrontendTasks,
|
||||
tab::settings::{
|
||||
SettingType, SettingsMountParams, SettingsTab,
|
||||
macros::{options_category, options_checkbox, options_dropdown, options_slider_f32, options_slider_i32},
|
||||
},
|
||||
views::{ViewUpdateParams, input_profiles},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Task {
|
||||
OpenInputProfiles,
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
popup_input_profiles: PopupHolder<input_profiles::View>,
|
||||
frontend_tasks: FrontendTasks,
|
||||
globals: WguiGlobals,
|
||||
tasks: Tasks<Task>,
|
||||
}
|
||||
|
||||
impl SettingsTab for State {
|
||||
fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
|
||||
self.popup_input_profiles.update(par)?;
|
||||
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::OpenInputProfiles => {
|
||||
input_profiles::mount_popup(
|
||||
self.frontend_tasks.clone(),
|
||||
self.globals.clone(),
|
||||
self.popup_input_profiles.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn create_input_profiles_button(
|
||||
mp: &mut crate::tab::settings::macros::MacroParams,
|
||||
parent: WidgetID,
|
||||
tasks: Tasks<Task>,
|
||||
_popup: &PopupHolder<input_profiles::View>,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
mp.idx += 1;
|
||||
|
||||
let mut params = TemplateParams::new();
|
||||
params.insert("id", &id);
|
||||
params.insert("translation", "APP_SETTINGS.INPUT_PROFILES");
|
||||
params.insert("icon", "dashboard/controller.svg");
|
||||
|
||||
mp.parser_state
|
||||
.instantiate_template(mp.doc_params, "ButtonText", mp.layout, parent, params)?;
|
||||
|
||||
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
|
||||
btn.on_click(Rc::new({
|
||||
let tasks = tasks.clone();
|
||||
move |_common, _e| {
|
||||
tasks.push(Task::OpenInputProfiles);
|
||||
Ok(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn mount(par: SettingsMountParams) -> anyhow::Result<State> {
|
||||
let tasks = Tasks::<Task>::new();
|
||||
let popup = PopupHolder::<input_profiles::View>::default();
|
||||
|
||||
let c = options_category(
|
||||
par.mp,
|
||||
par.id_parent,
|
||||
"APP_SETTINGS.CONTROLS",
|
||||
"dashboard/controller.svg",
|
||||
)?;
|
||||
if par.feats.openxr {
|
||||
create_input_profiles_button(par.mp, c, tasks.clone(), &popup)?;
|
||||
}
|
||||
options_dropdown::<wlx_common::config::AltModifier>(par.mp, c, &SettingType::KeyboardMiddleClick)?;
|
||||
options_dropdown::<wlx_common::config::HandsfreePointer>(par.mp, c, &SettingType::HandsfreePointer)?;
|
||||
options_checkbox(par.mp, c, SettingType::FocusFollowsMouseMode)?;
|
||||
options_checkbox(par.mp, c, SettingType::LeftHandedMouse)?;
|
||||
options_checkbox(par.mp, c, SettingType::AllowSliding)?;
|
||||
options_checkbox(par.mp, c, SettingType::InvertScrollDirectionX)?;
|
||||
options_checkbox(par.mp, c, SettingType::InvertScrollDirectionY)?;
|
||||
options_slider_f32(par.mp, c, SettingType::ScrollSpeed, 0.1, 5.0, 0.1)?;
|
||||
options_slider_f32(par.mp, c, SettingType::LongPressDuration, 0.1, 2.0, 0.1)?;
|
||||
|
||||
if par.feats.openxr {
|
||||
options_slider_f32(par.mp, c, SettingType::PointerLerpFactor, 0.1, 1.0, 0.1)?;
|
||||
}
|
||||
|
||||
options_slider_i32(par.mp, c, SettingType::ClickFreezeTimeMs, 0, 500, 50)?;
|
||||
|
||||
Ok(State {
|
||||
popup_input_profiles: popup,
|
||||
frontend_tasks: par.frontend_tasks.clone(),
|
||||
globals: par.mp.doc_params.globals.clone(),
|
||||
tasks,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
use crate::tab::settings::{
|
||||
SettingType, SettingsMountParams, SettingsTab,
|
||||
macros::{options_category, options_checkbox, options_range_f32},
|
||||
};
|
||||
|
||||
pub struct State {}
|
||||
|
||||
impl SettingsTab for State {}
|
||||
|
||||
impl State {
|
||||
pub fn mount(par: SettingsMountParams) -> anyhow::Result<State> {
|
||||
let c = options_category(par.mp, par.id_parent, "APP_SETTINGS.FEATURES", "dashboard/options.svg")?;
|
||||
options_checkbox(par.mp, c, SettingType::NotificationsEnabled)?;
|
||||
options_checkbox(par.mp, c, SettingType::NotificationsSoundEnabled)?;
|
||||
options_checkbox(par.mp, c, SettingType::KeyboardSoundEnabled)?;
|
||||
if !par.feats.openxr || par.feats.monado {
|
||||
// monado or openvr
|
||||
options_checkbox(par.mp, c, SettingType::BlockGameInput)?;
|
||||
options_checkbox(par.mp, c, SettingType::BlockGameInputIgnoreWatch)?;
|
||||
}
|
||||
if par.feats.monado {
|
||||
// monado-only
|
||||
options_checkbox(par.mp, c, SettingType::BlockPosesOnKbdInteraction)?;
|
||||
}
|
||||
|
||||
options_range_f32(
|
||||
par.mp,
|
||||
c,
|
||||
SettingType::WatchViewAngleMin,
|
||||
SettingType::WatchViewAngleMax,
|
||||
0.1,
|
||||
1.0,
|
||||
0.1,
|
||||
)?;
|
||||
Ok(State {})
|
||||
}
|
||||
}
|
||||