Compare commits

..
Author SHA1 Message Date
galister 89eb2e04f5 add spirv-headers to ci 2026-10-28 06:00:02 +09:00
galister 12253a5e20 bump whisper-rs 2026-10-28 05:53:43 +09:00
galister 9e116988ac wvr_server: process matching tweaks 2026-10-28 05:26:14 +09:00
Aleksander 466960d32a Add contribution instructions regarding LLM usage policy [skip ci] 2026-10-27 12:13:34 +09:00
Aleksander abafddefd8 add Swedish translation strings 2026-10-24 23:31:49 +02:00
Jonatan Nyberg 9b1fc2774a Add Swedish template to the translation tool (#701) 2026-10-24 22:48:43 +02:00
galister c539ff6a90 XSHM & PipeWire CPU capture fixes (#698) 2026-10-23 21:13:08 +09:00
galister f94c0c4ace desktop_finder rework (#697)
* desktop_finder rework

* fix args for wayvrctl process-launch
2026-10-23 19:29:25 +09:00
Aleksander 5f4c97794c wayvr: prevent alpha from going NaN again 2026-10-22 18:04:40 +02:00
Aleksander d9288a877c dash-frontend: refactoring: deduplicate dropdown code 2026-10-21 19:57:14 +02:00
galister dff4b0067a thumbstick axes fix 2026-10-21 14:29:48 +09:00
oo8dev adf852971f dash-frontend: whisper GPU device selector (Closes #680) (#692) 2026-10-18 17:19:10 +02:00
Aleksander 074d2de7aa wgui: bugfix: layout is recomputed every frame (tick/render loop) (Closes #690) 2026-10-18 12:37:49 +02:00
diffy e8d9a35714 openxr: pivot unlocked space rotate on the hand (#689)
* openxr: pivot unlocked space rotate on the hand

* openxr: don't start space drag during space rotate
2026-10-18 16:53:05 +09:00
diffy 36f9fab5c6 apply ui_gradient_intensity to theme (#688) 2026-10-17 13:16:03 +09:00
diffy 058792fc8e wlx-capture: destroy dmabuf params after create_immed (#687) 2026-10-17 13:15:48 +09:00
Dandrid ef934e0b02 chore: Swap away from using deprecated associated constants (#686) 2026-10-17 13:05:56 +09:00
galister c42e992a62 support both systemctl and loginctl 2026-10-15 13:20:31 +09:00
galister 41d7a0b3d2 try fix appimage with multi-desktop files 2026-10-14 13:22:25 +09:00
galister 471e4be946 show toast when starting hidden 2026-10-14 13:02:22 +09:00
galister 26afa57fe3 include headless desktop entry 2026-10-14 12:51:33 +09:00
galister d120617abe openvr: hide set & dash when showing bindings 2026-10-14 12:39:49 +09:00
galister 351b24533c openvr: button to open bindings 2026-10-14 12:09:52 +09:00
galister 09ed96542f openvr: fix space drag interrupting itself 2026-10-14 11:44:36 +09:00
oo8devandgalister 9b89622ff9 Power options, context menu icons (#681)
* dash-frontend: Power options (Closes #640), Context menu: refactor: positioning

* dash-frontend: Power options

* systemctl → loginctl

Co-authored-by: galister <22305755+galister@users.noreply.github.com>

---------

Co-authored-by: galister <22305755+galister@users.noreply.github.com>
2026-10-13 14:06:47 +09:00
galister 346c6391ef translations 2026-10-11 22:14:17 +09:00
galister e850c2c8b6 toast expiry tweaks 2026-10-11 22:14:17 +09:00
galister 5360697828 frame controller trigger thresholds 2026-10-11 17:51:59 +09:00
galister 3a869e3c35 openvr: hide at startup until steamvr dashboard is closed 2026-10-11 17:51:59 +09:00
galister b3ac55474f show toast if steamvr dashboard shown at startup 2026-10-11 17:51:59 +09:00
galister a4986a3d9f toast: extend_display_time 2026-10-11 17:51:59 +09:00
galister f3f7d97ed6 toast queue, priority toasts 2026-10-11 17:51:59 +09:00
Aleksander 10857739a4 dash-frontend: make WiVRn microphone show up, add volume control support for microphones with mono channel 2026-10-10 18:19:57 +02:00
Aleksander 42e9deb54c wgui: Layout: Fix content_size regression (Closes #679) 2026-10-09 09:29:20 +02:00
Aleksander d6515b3c2a dash-frontend: Tweak home screen buttons, minor logic fix 2026-10-08 22:44:23 +02:00
Aleksander a101c79892 wgui: Fix context menus leaving renderable content bounadry (Closes #668) 2026-10-08 22:25:33 +02:00
galister 82565e975f prevent alpha from going NaN 2026-10-05 14:15:00 +09:00
Aleksander 959f66b271 graphics: change dmabuf log level 2026-10-04 18:45:18 +02:00
oo8dev 745728d90d dash-frontend: diagnostics: list gpus and capabilities (vram info) (#674) 2026-10-03 13:14:58 +02:00
hypevhs 68944184de Embed update information within AppImages (#672)
Let linuxdeploy embed Update Information into each AppImage, allowing
for external apps (Gear Lever, Shelly, AppImageUpdate) to easily
download WayVR updates.

This also requires that a corresponding .zsync file be attached to each
release, for efficient transfer of updated AppImages.

See this section in the AppImage spec:

https://github.com/AppImage/AppImageSpec/blob/master/draft.md#update-information
2026-10-03 11:45:41 +09:00
galister 4590371a4c openvr: add generic_hmd to actions 2026-09-30 12:49:13 +09:00
galister d1255e5f71 openvr: fix eye tracking 2026-09-30 12:47:46 +09:00
galister 537f2f5397 openvr: fix missing toggle dash bind 2026-09-30 12:27:12 +09:00
galister 77730432b1 openvr: frame bindings 2026-09-30 12:22:43 +09:00
galister fd3e9069e4 openvr eye tracking 2026-09-30 06:19:07 +09:00
galister 2226d95834 update ovr_overlay 2026-09-30 05:35:09 +09:00
galister a0d36d7257 openvr: handsfree pointer 2026-09-30 05:13:24 +09:00
galister 38382275ec Revert "headless appimages for frame"
This reverts commit 0a158c102c.
2026-09-30 04:34:42 +09:00
galister 5517c3a809 focus picker to override controller input 2026-09-30 04:09:02 +09:00
galister f0d96802ba wvr_server: fix resize on windows using wl_viewporter 2026-09-30 00:18:19 +09:00
galister 3f43003a0b client-side decorations 2026-09-29 23:24:48 +09:00
galister 28842d6d69 wvr_server: drag and drop support (#669) 2026-09-29 18:58:51 +09:00
Dimo 573bd5da53 Ignore invisible overlays during raycast (#665) 2026-09-29 18:42:13 +09:00
galister da3b19a495 sets_on_watch by default 2026-09-29 13:34:50 +09:00
galister ad0d1aa8a2 fmt 2026-09-29 11:58:54 +09:00
galister b85976bdf0 toasts stay while you look! 2026-09-29 11:58:26 +09:00
galister 2ea97e88bb bump key repeat delay 2026-09-29 03:07:19 +09:00
galister b7b93131c9 [skip-ci] Update readme 2026-09-29 02:56:09 +09:00
galister e7c07c7789 update readme 2026-09-29 02:05:13 +09:00
galister 0a158c102c headless appimages for frame 2026-09-29 02:02:53 +09:00
galister 11a5c8305b rework WGfx to work with ash instead of vulkano 2026-09-29 01:50:42 +09:00
galister d5f0306aab Revert "check vkGetMemoryFdPropertiesKHR on dmabuf import, allow only SAMPLED drm formats"
This reverts commit 6d6e7033ac.
2026-09-29 01:50:42 +09:00
galister 6d6e7033ac check vkGetMemoryFdPropertiesKHR on dmabuf import, allow only SAMPLED drm formats 2026-09-27 21:55:14 +09:00
galister 16bc4383b5 openxr: binding chords support, update frame controller as per 2026-09-27 19:58:19 +09:00
galister 0e6526836e add option for --no-audio 2026-09-27 16:37:19 +09:00
galister 2e8d1589f5 oxr bindings: scroll is actually Vec2; tweak frame_controller 2026-09-26 22:29:24 +09:00
galister 54713b95f4 lax precision on IPD logs 2026-09-26 14:37:32 +09:00
galister 6f761a99dc log available extensions 2026-09-26 14:37:21 +09:00
galister c87bcee358 build aarch64 appimage 2026-09-25 14:59:50 +09:00
oo8dev 0eab390702 dash-frontend: Diagnostics tab (#661)
* dash-frontend: diagnostics

* wgui: support booleans, Button: `adjust_children` tag

* dash-frontend: diagnostics: add tooltips
2026-09-20 11:32:17 +02:00
Aleksander 9dcdf852c7 dash-frontend: audio settings: bugfix: panic after trying to open a non-existent asset path in the card profile selector 2026-09-19 18:51:43 +02:00
galister b3261dbe4f fmt 2026-09-19 12:10:42 +09:00
galister 329a89ca08 setting: Middle-click modifier grabs individual overlays 2026-09-19 11:54:07 +09:00
galister c284162068 fmt 2026-09-18 01:37:22 +09:00
galister f2beabd39a XR_MNDX_composition_layer_alpha_blend_system_ui 2026-09-18 01:37:12 +09:00
galister 126120e52e fmt 2026-09-12 16:55:10 +09:00
galister e986c3591e debug logs for input_capture 2026-09-12 16:55:10 +09:00
galister a0f096b9dc wayvrctl: add window-attrib 2026-09-12 16:55:10 +09:00
galister 7b95f01ff4 wayvrctl: rework window-set-visible 2026-09-12 16:55:10 +09:00
galister d9cc73be8b wayvrctl: rework window-list 2026-09-12 16:55:10 +09:00
galister 548ea36a84 wayvrctl windows-state: add get/set for global 2026-09-12 16:55:10 +09:00
galister d4a5d4c81f wayvrctl: window-state subcommand 2026-09-12 16:55:10 +09:00
galister 443bc01361 missing translations 2026-09-12 16:54:52 +09:00
galister 9b9d1b9f8a avoid using vulkano's approximative gamma correction 2026-09-12 13:35:09 +09:00
oo8dev 40811f219e Add various animations, UI fixes (#651)
* wgui: Animation system refactoring (seconds instead of ticks), dash-frontend: pop-up slide effects

* dash-frontend: audio_settings UI fixes

* wgui: do not swipe in non-scrollable axis, dash-frontend: skymap list xml fixes

* wayvr: notification animations, wgui: animation system refactoring
2026-09-06 16:50:39 +02:00
Aleksander a244c90d05 wgui: Bugfix: Can't click on a scrollable widget with both hands pointing at the overlay 2026-09-06 13:41:24 +02:00
Aleksander f0a1b82db5 dash-frontend: Bugfix: Bindings menu mount failure due to wrong svg path 2026-09-05 19:02:33 +02:00
Mahonzu b45c68cb59 Fix Vive controllers vibrating on touch 2026-09-03 01:57:17 +09:00
Aleksander 234c4a4021 wgui: do not pass AttribPairs with empty values further, dash-frontend: xml refactor, use template children in various places, remove unused files 2026-09-03 00:35:43 +09:00
Aleksander 10e54728fa wgui: Add <CHILDREN/> support in templates (Closes #550) 2026-09-03 00:35:43 +09:00
Aleksander e4daef209b Changes (wgui):
- All new layout xml files now are required to include this metadata
at the top, if they want to be parsed in the new layout v2 behavior:
```xml
<layout version="2">
    <!-- rest of the markup -->
</layout>
```

- Add path expansion using '@' for widget resources and includes
The '@' character is always expanded to the assets root directory
(builtin/internal), or the root xml directory (external).
Paths directing to the built-in resources like:
    `edit/mouse.svg`
are now required to be written as:
    `@/edit/mouse.svg`,
For example:
    ```xml
        <sprite src_builtin="@/edit/mouse.svg" />
    ```

- All paths without '/' at the start are now treated as relative
to the currently parsing XML (paths like `/usr/share/icons/...`
are still accessible)

- Add support for relative paths for widgets instantiated from
templates

- Rename `<theme>` to `<vars>`

Changes (dash-frontend):

- Adapt and refactor XML files

Changes (wayvr):

- Adapt and refactor XML files
2026-09-03 00:35:43 +09:00
galister d318831ecc issue template 2026-08-30 01:24:49 +09:00
galister 48be76c443 update bug report template to discourage AI-generated issues 2026-08-30 01:23:57 +09:00
galister 9d3546b0c4 fix passthru overlay burn-in after edit mode 2026-08-28 10:17:34 +09:00
Aleksander 6163328769 wayvr: fix space rotate quaternion/matrix feedback drift (Closes #636) 2026-08-27 21:35:23 +02:00
galister e79440d03d openvr: only should_render if initialized 2026-08-28 01:50:49 +09:00
galister e0f09d63c2 fix dirty handling in passthru overlay 2026-08-28 01:50:49 +09:00
galister 69dbf331c8 block input to xr-hotas even though headless 2026-08-22 21:33:51 +09:00
oo8dev 5079f31c40 wayvr: Whisper panel: Microphone feedback & processing progress (#631) 2026-08-16 14:58:17 +02:00
GK-Gaming 3c2d0d07f5 Fix x11 pipewire screencast (#609) 2026-08-16 20:40:27 +09:00
oo8dev a50ad00fb0 dash-frontend: Runtime statistics tab, head rotation count (Closes #222) (#627) 2026-08-16 11:12:17 +02:00
305 changed files with 16000 additions and 5744 deletions

No files matched your search

+3 -1
View File
@@ -9,7 +9,9 @@ assignees: ''
## Description
<!--
If this is a regression, please mention which version was working previously.
*** Do NOT use AI to generate a bug report! ***
Simply write down what's wrong and maybe provide screenshots or a video.
If this has worked before, please mention which version was last working.
-->
## System Info
+17 -4
View File
@@ -1,6 +1,7 @@
name: Build AppImage
on:
workflow_dispatch:
push:
branches:
- 'main'
@@ -12,10 +13,17 @@ env:
CARGO_TERM_COLOR: always
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
jobs:
build_appimage:
runs-on: ubuntu-24.04
strategy:
matrix:
include:
- runner: ubuntu-24.04
arch: x86_64
- runner: ubuntu-24.04-arm
arch: aarch64
runs-on: ${{ matrix.runner }}
defaults:
run:
working-directory: ./wayvr
@@ -38,5 +46,10 @@ jobs:
- name: Upload AppImage
uses: actions/upload-artifact@v4
with:
name: WayVR-${{ github.ref_name }}-x86_64.AppImage
path: ./wayvr/WayVR-x86_64.AppImage
name: WayVR-${{ github.ref_name }}-${{ matrix.arch }}.AppImage
path: ./wayvr/WayVR-${{ matrix.arch }}.AppImage
- name: Upload AppImage zsync
uses: actions/upload-artifact@v4
with:
name: WayVR-${{ github.ref_name }}-${{ matrix.arch }}.AppImage.zsync
path: ./wayvr/WayVR-${{ matrix.arch }}.AppImage.zsync
+10
View File
@@ -83,6 +83,16 @@ jobs:
asset_name: WayVR-${{ github.ref_name }}-x86_64.AppImage
asset_content_type: application/octet-stream
- name: Upload AppImage zsync
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-x86_64.AppImage.zsync
asset_name: WayVR-${{ github.ref_name }}-x86_64.AppImage.zsync
asset_content_type: application/octet-stream
- name: Upload vendor tarball
uses: actions/upload-release-asset@v1
env:
@@ -1,6 +1,7 @@
#!/bin/sh
set -eu
sudo apt install \
sudo apt-get install -y \
xwayland \
libxcb1-dev \
libxcb-cursor-dev \
@@ -11,7 +12,7 @@ git clone https://github.com/Supreeeme/xwayland-satellite.git
cd xwayland-satellite
cargo build --release
chmod +x ../target/release/xwayland-satellite
chmod +x target/release/xwayland-satellite
cd ..
cp xwayland-satellite/target/release/xwayland-satellite ${APPDIR}/usr/bin
cp xwayland-satellite/target/release/xwayland-satellite "${APPDIR}/usr/bin"
@@ -1,4 +1,6 @@
#!/bin/sh
set -eu
cargo build --release
chmod +x ../target/release/wayvr
cp ../target/release/wayvr ${APPDIR}/usr/bin
cp ../target/release/wayvr "${APPDIR}/usr/bin"
+34 -3
View File
@@ -1,4 +1,35 @@
#!/bin/sh
export VERSION=$GITHUB_REF_NAME
./linuxdeploy-x86_64.AppImage -dwayvr.desktop -iwayvr.png --appdir=${APPDIR} --output appimage --exclude-library '*libpipewire*'
mv WayVR-$VERSION-x86_64.AppImage WayVR-x86_64.AppImage
set -eu
case "$(uname -m)" in
x86_64|amd64)
APPIMAGE_ARCH=x86_64
;;
aarch64|arm64)
APPIMAGE_ARCH=aarch64
;;
*)
echo "Unsupported architecture: $(uname -m)" >&2
exit 1
;;
esac
LINUXDEPLOY="linuxdeploy-${APPIMAGE_ARCH}.AppImage"
VERSION="${GITHUB_REF_NAME:-dev}"
export VERSION
export LDAI_UPDATE_INFORMATION="gh-releases-zsync|wayvr-org|wayvr|latest|WayVR-*-${APPIMAGE_ARCH}.AppImage.zsync"
echo "Packaging AppImage for ${APPIMAGE_ARCH}"
# linuxdeploy doesn't like multiple -d's being passed
install -Dm 0644 wayvr-headless.desktop "${APPDIR}/usr/share/applications/wayvr-headless.desktop"
"./${LINUXDEPLOY}" \
-dwayvr.desktop \
-iwayvr.png \
--appdir="${APPDIR}" \
--output appimage \
--exclude-library '*libpipewire*'
mv "WayVR-${VERSION}-${APPIMAGE_ARCH}.AppImage" "WayVR-${APPIMAGE_ARCH}.AppImage"
mv "WayVR-${VERSION}-${APPIMAGE_ARCH}.AppImage.zsync" "WayVR-${APPIMAGE_ARCH}.AppImage.zsync"
@@ -1,17 +1,39 @@
#!/bin/sh
set -eu
case "$(uname -m)" in
x86_64|amd64)
APPIMAGE_ARCH=x86_64
;;
aarch64|arm64)
APPIMAGE_ARCH=aarch64
;;
*)
echo "Unsupported architecture: $(uname -m)" >&2
exit 1
;;
esac
LINUXDEPLOY="linuxdeploy-${APPIMAGE_ARCH}.AppImage"
echo "Preparing AppImage environment for ${APPIMAGE_ARCH}"
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 \
dav1d libdav1d-dev libvulkan-dev glslc vulkan-tools libudev-dev libudev1 libinput-dev libinput10
libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1t64 libwayland-dev libegl-dev libxcb-glx0 libxcb-glx0-dev \
dav1d libdav1d-dev libvulkan-dev glslc vulkan-tools libudev-dev libudev1 libinput-dev libinput10 spirv-headers
rustup update
if [ "$APPDIR" != "" ]; then
test -f linuxdeploy-x86_64.AppImage || wget -q "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
chmod +x linuxdeploy-x86_64.AppImage
if [ -n "${APPDIR:-}" ]; then
if [ ! -f "$LINUXDEPLOY" ]; then
wget -q "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/${LINUXDEPLOY}"
fi
chmod +x "$LINUXDEPLOY"
test -d ${APPDIR} && rm -rf ${APPDIR}
mkdir -p ${APPDIR}/usr/bin
if [ -d "$APPDIR" ]; then
rm -rf "$APPDIR"
fi
mkdir -p "$APPDIR/usr/bin"
fi
+46
View File
@@ -0,0 +1,46 @@
# Contributing
Contributions are warmly welcome. Before you start, please read the entire document carefully.
## AI Policy
Do not use LLMs to generate substantial pieces of code. You need to fully understand every line of code you change. No exceptions.
Commits, issues and pull requests must be made by humans. Co-authoring by AI is not allowed.
Looking to create an issue on the project, such as a feature request or bug report? Focus on writing what you know for sure in simple terms. We'll figure it out from there.
Usage of Gen-AI for visuals and audio is prohibited.
The only exception is LLM-translated strings generated by the scripts/translator tool.
## Basics
Before committing, make sure to format your Rust code by running:
```
cargo fmt
```
You should also check for any compiler warnings too:
```
cargo check
```
or even better:
```
cargo clippy
```
## Large contributions
If you want to submit a relatively big pull requests, it's highly advisable to create a separate issue request for it. That way we can discuss the approach and sort out the details first.
## Adding translations
Look at `scripts/translator/run.sh` for more information.
## Licensing
WayVR is developed and published under [GPL-3 License](https://www.gnu.org/licenses/gpl-3.0.en.html).
Generated
+137 -148
View File
@@ -689,6 +689,12 @@ dependencies = [
"wyz",
]
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -729,6 +735,17 @@ dependencies = [
"piper",
]
[[package]]
name = "bstr"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f"
dependencies = [
"memchr",
"regex-automata",
"serde_core",
]
[[package]]
name = "built"
version = "0.8.1"
@@ -1250,15 +1267,6 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
@@ -1410,6 +1418,7 @@ dependencies = [
"rust-embed",
"serde",
"serde_json",
"shell-words",
"smol",
"strum",
"ureq",
@@ -1735,7 +1744,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -1930,6 +1939,21 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
name = "freedesktop-desktop-entry"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42a69ad6111a2b572cb41e0f3542d546386e841013cee7c45d705b61a15a87dd"
dependencies = [
"bstr",
"gettext-rs",
"log",
"memchr",
"thiserror 2.0.18",
"unicase",
"xdg 3.0.0",
]
[[package]]
name = "fs_extra"
version = "1.3.0"
@@ -2109,6 +2133,26 @@ dependencies = [
"rand_core 0.10.1",
]
[[package]]
name = "gettext-rs"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9df5e3fa8c077b15fdfa8ce130e2bc73d663b8aaa6d51b71421b8659980b1d80"
dependencies = [
"gettext-sys",
"locale_config",
]
[[package]]
name = "gettext-sys"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4caa7e4460b196107cc1bb2629488e8b6dbb7f34f6683ea6753c4ac22f590785"
dependencies = [
"cc",
"temp-dir",
]
[[package]]
name = "gif"
version = "0.14.2"
@@ -2878,6 +2922,19 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "locale_config"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
dependencies = [
"lazy_static",
"objc",
"objc-foundation",
"regex",
"winapi",
]
[[package]]
name = "lock_api"
version = "0.4.14"
@@ -2939,6 +2996,15 @@ dependencies = [
"libc",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "matchers"
version = "0.2.0"
@@ -3149,7 +3215,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@@ -3230,6 +3296,26 @@ dependencies = [
"syn 2.0.118",
]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc-sys"
version = "0.3.5"
@@ -3268,7 +3354,7 @@ dependencies = [
"objc2-core-data",
"objc2-core-image",
"objc2-foundation 0.2.2",
"objc2-quartz-core 0.2.2",
"objc2-quartz-core",
]
[[package]]
@@ -3377,7 +3463,7 @@ dependencies = [
"block2 0.5.1",
"objc2 0.5.2",
"objc2-foundation 0.2.2",
"objc2-metal 0.2.2",
"objc2-metal",
]
[[package]]
@@ -3458,17 +3544,6 @@ dependencies = [
"objc2-foundation 0.2.2",
]
[[package]]
name = "objc2-metal"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
dependencies = [
"bitflags 2.13.0",
"objc2 0.6.4",
"objc2-foundation 0.3.2",
]
[[package]]
name = "objc2-open-directory"
version = "0.3.2"
@@ -3490,20 +3565,7 @@ dependencies = [
"block2 0.5.1",
"objc2 0.5.2",
"objc2-foundation 0.2.2",
"objc2-metal 0.2.2",
]
[[package]]
name = "objc2-quartz-core"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
dependencies = [
"bitflags 2.13.0",
"objc2 0.6.4",
"objc2-core-foundation",
"objc2-foundation 0.3.2",
"objc2-metal 0.3.2",
"objc2-metal",
]
[[package]]
@@ -3531,7 +3593,7 @@ dependencies = [
"objc2-core-location",
"objc2-foundation 0.2.2",
"objc2-link-presentation",
"objc2-quartz-core 0.2.2",
"objc2-quartz-core",
"objc2-symbols",
"objc2-uniform-type-identifiers",
"objc2-user-notifications",
@@ -3561,6 +3623,15 @@ dependencies = [
"objc2-foundation 0.2.2",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]]
name = "object"
version = "0.37.3"
@@ -3651,7 +3722,7 @@ dependencies = [
[[package]]
name = "ovr_overlay"
version = "0.0.0"
source = "git+https://github.com/galister/ovr_overlay_oyasumi?rev=e477bd2a9e04293ea68c1e7529ef2cb131f32acc#e477bd2a9e04293ea68c1e7529ef2cb131f32acc"
source = "git+https://github.com/galister/ovr_overlay_oyasumi?rev=3b7d24cee24aa2b1ad7dffc5d5c8568508049bdd#3b7d24cee24aa2b1ad7dffc5d5c8568508049bdd"
dependencies = [
"byteorder",
"derive_more",
@@ -3666,7 +3737,7 @@ dependencies = [
[[package]]
name = "ovr_overlay_sys"
version = "0.0.0"
source = "git+https://github.com/galister/ovr_overlay_oyasumi?rev=e477bd2a9e04293ea68c1e7529ef2cb131f32acc#e477bd2a9e04293ea68c1e7529ef2cb131f32acc"
source = "git+https://github.com/galister/ovr_overlay_oyasumi?rev=3b7d24cee24aa2b1ad7dffc5d5c8568508049bdd#3b7d24cee24aa2b1ad7dffc5d5c8568508049bdd"
dependencies = [
"autocxx",
"autocxx-build",
@@ -4054,7 +4125,7 @@ version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
dependencies = [
"heck 0.5.0",
"heck 0.4.1",
"itertools 0.14.0",
"log",
"multimap",
@@ -4357,18 +4428,6 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "raw-window-metal"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135"
dependencies = [
"objc2 0.6.4",
"objc2-core-foundation",
"objc2-foundation 0.3.2",
"objc2-quartz-core 0.3.2",
]
[[package]]
name = "rayon"
version = "1.12.0"
@@ -4667,7 +4726,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.12.1",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -4714,8 +4773,7 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "rxscreen"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afbab13f83503a8272b7150d487494992cf6c59c299dcaf5d8ffac75bad9fc96"
source = "git+https://github.com/galister/rxscreen.git?rev=7197e1de6622b65859e6f2060b5750185e0dad2a#7197e1de6622b65859e6f2060b5750185e0dad2a"
dependencies = [
"libc",
]
@@ -5026,12 +5084,6 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "slabbin"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9db491c0d4152a069911a0fbdaca959691bf0b9d7110d98a7ed1c8e59b79ab30"
[[package]]
name = "slice-of-array"
version = "0.3.2"
@@ -5394,6 +5446,12 @@ version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
[[package]]
name = "temp-dir"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83176759e9416cf81ee66cb6508dbfe9c96f20b8b56265a39917551c23c70964"
[[package]]
name = "tempfile"
version = "3.27.0"
@@ -5401,10 +5459,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
"getrandom 0.4.3",
"getrandom 0.3.4",
"once_cell",
"rustix 1.1.4",
"windows-sys 0.61.2",
"windows-sys 0.52.0",
]
[[package]]
@@ -5739,13 +5797,17 @@ dependencies = [
"rust-embed",
"tracing-subscriber",
"ureq",
"vulkano",
"vulkano-shaders",
"wgui",
"winit",
"wlx-common",
]
[[package]]
name = "unicase"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
[[package]]
name = "unicode-bidi"
version = "0.3.18"
@@ -5905,70 +5967,6 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "vk-parse"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3859da4d7b98bec73e68fb65815d47a263819c415c90eed42b80440a02cbce8c"
dependencies = [
"xml-rs",
]
[[package]]
name = "vulkano"
version = "0.35.2"
source = "git+https://github.com/galister/vulkano.git?rev=cf7f92867928a56ce16b376037c1120f2b167678#cf7f92867928a56ce16b376037c1120f2b167678"
dependencies = [
"ash",
"bytemuck",
"crossbeam-queue",
"foldhash 0.1.5",
"half",
"heck 0.4.1",
"indexmap 2.14.0",
"libloading 0.8.9",
"nom 7.1.3",
"once_cell",
"parking_lot",
"proc-macro2",
"quote",
"raw-window-handle",
"raw-window-metal",
"serde",
"serde_json",
"slabbin",
"smallvec",
"thread_local",
"vk-parse",
"vulkano-macros",
]
[[package]]
name = "vulkano-macros"
version = "0.35.0"
source = "git+https://github.com/galister/vulkano.git?rev=cf7f92867928a56ce16b376037c1120f2b167678#cf7f92867928a56ce16b376037c1120f2b167678"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.118",
]
[[package]]
name = "vulkano-shaders"
version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bf501461be7cef2893c0e62c50945add9763cc482051d29053f6157089d5ea9"
dependencies = [
"foldhash 0.1.5",
"heck 0.4.1",
"proc-macro2",
"quote",
"shaderc",
"syn 2.0.118",
"vulkano",
]
[[package]]
name = "walkdir"
version = "2.5.0"
@@ -6211,7 +6209,6 @@ name = "wayvr"
version = "26.8.0"
dependencies = [
"anyhow",
"ash",
"bytes",
"calloop 0.14.4",
"calloop-wayland-source 0.4.1",
@@ -6249,6 +6246,7 @@ dependencies = [
"serde_json",
"serde_json5",
"serde_yaml",
"shaderc",
"signal-hook",
"slotmap",
"smallvec",
@@ -6261,8 +6259,6 @@ dependencies = [
"tracing",
"tracing-subscriber",
"uuid",
"vulkano",
"vulkano-shaders",
"wayland-client",
"wayland-protocols",
"wayland-protocols-misc",
@@ -6349,6 +6345,7 @@ name = "wgui"
version = "0.1.0"
dependencies = [
"anyhow",
"ash",
"bytes",
"cosmic-text",
"dav1d-sys",
@@ -6360,25 +6357,24 @@ dependencies = [
"lru",
"ouroboros",
"parking_lot",
"raw-window-handle",
"regex",
"resvg",
"roxmltree 0.21.1",
"rust-embed",
"rustc-hash",
"serde_json",
"shaderc",
"slotmap",
"smallvec",
"strum",
"taffy",
"vulkano",
"vulkano-shaders",
]
[[package]]
name = "whisper-rs"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2088172d00f936c348d6a72f488dc2660ab3f507263a195df308a3c2383229f6"
source = "git+https://github.com/wayvr-org/whisper-rs.git?rev=2d908ec36cd41521a28f7f5fb5dc95499fd40051#2d908ec36cd41521a28f7f5fb5dc95499fd40051"
dependencies = [
"libc",
"whisper-rs-sys",
@@ -6387,8 +6383,7 @@ dependencies = [
[[package]]
name = "whisper-rs-sys"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6986c0fe081241d391f09b9a071fbcbb59720c3563628c3c829057cf69f2a56f"
source = "git+https://github.com/wayvr-org/whisper-rs.git?rev=2d908ec36cd41521a28f7f5fb5dc95499fd40051#2d908ec36cd41521a28f7f5fb5dc95499fd40051"
dependencies = [
"bindgen",
"cfg-if",
@@ -6425,7 +6420,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.48.0",
]
[[package]]
@@ -6857,6 +6852,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"freedesktop-desktop-entry",
"glam",
"glob",
"identicons-svg",
@@ -6864,7 +6860,6 @@ dependencies = [
"idmap-derive",
"log",
"rodio",
"rust-ini",
"serde",
"serde_json",
"serde_json5",
@@ -6982,12 +6977,6 @@ dependencies = [
"bytemuck",
]
[[package]]
name = "xml-rs"
version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
[[package]]
name = "xmlparser"
version = "0.13.6"
+1 -14
View File
@@ -32,32 +32,19 @@ rust-embed = "8.9.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.145"
serde_json5 = "0.2.1"
shell-words = "1.1.1"
slotmap = "1.1.1"
smallvec = "1.15.2"
smol = "2.0.2"
strum = { version = "0.27.2", features = ["derive"] }
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
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" }
wayland-protocols = { version = "0.32" }
wayland-protocols-misc = { version = "0.3.12" }
winit = "0.30.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
+15 -1
View File
@@ -37,7 +37,7 @@ There are multiple ways to install WayVR:
**Note:** If you are using Monado or WiVRn, no additional setup steps are required for Flatpak Steam compatibility—most people use WayVR seamlessly with Monado/WiVRn.
### SteamVR via Steam Flatpak
### SteamVR (PC) via Steam Flatpak
For users specifically running **SteamVR via Steam Flatpak**, follow these steps:
@@ -50,6 +50,20 @@ For users specifically running **SteamVR via Steam Flatpak**, follow these steps
1. Start SteamVR.
1. `flatpak run --command='/path/to/squashfs-root/AppRun' com.valvesoftware.Steam`
### Installing on Steam Frame
Steam Frame support is experimental. Please report issues.
It's possible to install and run WayVR on the Steam Frame in headless mode. You will not have access to your KDE desktop, but you will be able to run applications in 3D space around you.
Steps to install on Steam Frame:
1. Grab the latest aarch64 AppImage
- For nightly AppImages go [here](https://github.com/wayvr-org/wayvr/actions/workflows/build-appimage.yml) and select the topmost list item a ✅️
- The downloads will be on the bottom of the page (GitHub login required).
1. Install the AppImage using GearLever
1. (Recommended) In Frame's SteamVR settings, set overlay quality to High.
1. Start WayVR from the taskbar (same place where you'd start Destkop)
## First Start
**When the screen share pop-up appears, check your notifications or the terminal and select the screens in the order it requests.**
+1
View File
@@ -19,6 +19,7 @@ log.workspace = true
rust-embed.workspace = true
serde = { workspace = true, features = ["rc"] }
serde_json.workspace = true
shell-words.workspace = true
smol = { workspace = true }
strum.workspace = true
uuid.workspace = true
@@ -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="M2 21v-2h20v2zm1-3v-7h3v7zm5 0V6h3v12zm5 0V9h3v9zm5 0V3h3v15z"/></svg>

After

Width:  |  Height:  |  Size: 297 B

+1
View File
@@ -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 13.4l-4.9 4.9q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7l4.9-4.9l-4.9-4.9q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l4.9 4.9l4.9-4.9q.275-.275.7-.275t.7.275t.275.7t-.275.7L13.4 12l4.9 4.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275z"/></svg>

After

Width:  |  Height:  |  Size: 468 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="M9 22q-.825 0-1.412-.587T7 20v-3H4q-.825 0-1.412-.587T2 15v-2h6.45l1.7 2.55q.125.2.35.325t.475.125q.325 0 .6-.2t.375-.5l1.35-4.05l.85 1.3q.15.2.375.325T15 13h7v2q0 .825-.588 1.413T20 17h-3v3q0 .825-.587 1.413T15 22zm1.7-9.25l-.875-1.3q-.125-.2-.35-.325T9 11H2V9q0-.825.588-1.412T4 7h3V4q0-.825.588-1.412T9 2h6q.825 0 1.413.588T17 4v3h3q.825 0 1.413.588T22 9v2h-6.475l-1.7-2.55q-.125-.2-.35-.325T13 8q-.325 0-.587.2t-.363.5z"/></svg>

After

Width:  |  Height:  |  Size: 660 B

+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="32"
height="32"
viewBox="0 0 24 24"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs id="defs1" />
<path fill="currentColor" d="m 10,12 c 0,-1.104569 0.895431,-2 2,-2 1.104569,0 2,0.895431 2,2 0,1.104569 -0.895431,2 -2,2 -1.104569,0 -2,-0.895431 -2,-2" id="path1" />
</svg>

After

Width:  |  Height:  |  Size: 422 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Lucide by Lucide Contributors - https://github.com/lucide-icons/lucide/blob/main/LICENSE --><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M2 17h18a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2H2m0 16V3m5 14v3a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1v-3"/><circle cx="16" cy="11" r="2"/><circle cx="8" cy="11" r="2"/></g></svg>

After

Width:  |  Height:  |  Size: 462 B

+1
View File
@@ -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="M17 10q-.825 0-1.412-.575T15 8V4q0-.85.588-1.425T17 2q.85 0 1.425.575T19 4v4q0 .85-.575 1.425T17 10M5 22q-.825 0-1.412-.587T3 20V4q0-.825.588-1.412T5 2h8v2H5v16h11v-2h2v2q0 .825-.587 1.413T16 22zm2-4v-2h7v2zm0-3v-2h5v2zm11 1h-2v-2.6q-1.925-.35-3.213-1.862T11.5 8h2q0 1.45 1.025 2.475T17 11.5q1.475 0 2.488-1.025T20.5 8h2q0 2.025-1.275 3.538T18 13.4z"/></svg>

After

Width:  |  Height:  |  Size: 585 B

+24 -11
View File
@@ -1,10 +1,20 @@
<layout>
<theme>
<layout version="2">
<vars>
<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>
</vars>
<blueprint name="context_menu_power_options">
<context_menu>
<cell translation="APP_SETTINGS.RESTART_WAYVR" action="restart" sprite_src_builtin="@/dashboard/refresh.svg"/>
<cell translation="APP_SETTINGS.CLOSE_WAYVR" action="close" sprite_src_builtin="@/dashboard/close.svg"/>
<separator/>
<cell translation="POWER_OPTIONS.SUSPEND" action="suspend" sprite_src_builtin="@/dashboard/sleep.svg"/>
<cell translation="POWER_OPTIONS.SHUTDOWN" action="shutdown" sprite_src_builtin="@/dashboard/power.svg"/>
</context_menu>
</blueprint>
<template name="SideButton">
<Button
@@ -41,12 +51,12 @@
align_items="center"
gap="4"
>
<SideButton id="btn_side_home" src_builtin="dashboard/wayvr_dashboard_mono.svg" tooltip="HOME_SCREEN" tooltip_side="right" />
<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_home" src_builtin="@/dashboard/wayvr_dashboard_mono.svg" tooltip="HOME_SCREEN" tooltip_side="right" />
<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" />
<rectangle height="2" color="outline" width="~side_sprite_size" />
<SideButton id="btn_side_settings" src_builtin="dashboard/settings.svg" tooltip="SETTINGS" tooltip_side="right" />
<SideButton id="btn_side_settings" src_builtin="@/dashboard/settings.svg" tooltip="SETTINGS" tooltip_side="right" />
</rectangle>
</div>
<!-- REST -->
@@ -69,7 +79,7 @@
<!-- Close button -->
<Button position="absolute" id="btn_close" color="background_contrast" border_color="background_contrast" round="100%" width="~top_size" height="~top_size" tooltip="CLOSE_WINDOW" tooltip_side="left"
hover_color="danger" hover_border_color="danger(rgb-mult-0.5)" >
<sprite src_builtin="dashboard/close.svg" width="32" height="32" />
<sprite src_builtin="@/dashboard/close.svg" width="32" height="32" />
</Button>
</div>
@@ -136,11 +146,14 @@
<!-- Left bottom side -->
<div margin_left="8">
<Button id="btn_power" color="background(transparent)" border_color="background(transparent)" tooltip="POWER_OPTIONS.TITLE" tooltip_side="top">
<sprite src_builtin="@/dashboard/power.svg" width="24" height="24" margin="8" />
</Button>
<Button id="btn_audio" color="background(transparent)" border_color="background(transparent)" tooltip="AUDIO.VOLUME" tooltip_side="top">
<sprite src_builtin="dashboard/volume.svg" width="24" height="24" margin="8" />
<sprite src_builtin="@/dashboard/volume.svg" width="24" height="24" margin="8" />
</Button>
<Button id="btn_recenter" color="background(transparent)" border_color="background(transparent)" tooltip="ACTIONS.RECENTER_PLAYSPACE" tooltip_side="top">
<sprite src_builtin="dashboard/recenter.svg" width="24" height="24" margin="8" />
<sprite src_builtin="@/dashboard/recenter.svg" width="24" height="24" margin="8" />
</Button>
</div>
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<macro name="dropdown_button"
flex_direction="row"
border="2"
@@ -17,7 +17,7 @@
<div padding_top="4" padding_bottom="4">
<rectangle width="2" height="100%" color="outline" />
</div>
<sprite margin_left="-4" width="30" height="30" src_builtin="dashboard/down.svg" />
<sprite margin_left="-4" width="30" height="30" src_builtin="@/dashboard/down.svg" />
</div>
</Button>
</template>
+9 -2
View File
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<macro name="group_box"
flex_direction="column"
align_items="baseline"
@@ -7,7 +7,14 @@
border_color="outline"
padding="12"
gap="8"
round="8" />
round="8"/>
<!-- id -->
<template name="GroupBox">
<rectangle macro="group_box" id="rect">
<CHILDREN/>
</rectangle>
</template>
<!-- src_builtin, text, translation -->
<template name="GroupBoxTitle">
+3 -3
View File
@@ -1,8 +1,8 @@
<layout>
<layout version="2">
<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" color="on_background"/>
<sprite id="sprite_loading" src_builtin="@/dashboard/loading.svg" width="32" height="32" color="on_background"/>
<label translation="LOADING" weight="bold"/>
</div>
</div>
@@ -10,7 +10,7 @@
<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" color="on_background"/>
<sprite id="sprite_loading" src_builtin="@/dashboard/loading.svg" width="32" height="32" color="on_background"/>
</div>
</template>
</layout>
+1 -1
View File
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<macro name="home_button" round="8" hover_color="primary" hover_border_color="on_primary" />
<template name="MenuButton">
+1 -1
View File
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<template name="Separator">
<rectangle width="100%" min_height="2" color="outline" />
</template>
+8 -8
View File
@@ -1,5 +1,5 @@
<layout>
<include src="../t_group_box.xml" />
<layout version="2">
<include src="@/gui/t_group_box.xml" />
<!-- tooltip, src, src_ext, name -->
<template name="AppEntry">
@@ -28,26 +28,26 @@
<!--
<div gap="4" align_items="center">
<Button width="48" height="38">
<sprite src_builtin="dashboard/alphabetical.svg" width="24" height="24" />
<sprite src_builtin="@/dashboard/alphabetical.svg" width="24" height="24" />
</Button>
<Button width="48" height="38">
<sprite src_builtin="dashboard/category_search.svg" width="24" height="24" />
<sprite src_builtin="@/dashboard/category_search.svg" width="24" height="24" />
</Button>
<sprite src_builtin="dashboard/search.svg" width="24" height="24" />
<sprite src_builtin="@/dashboard/search.svg" width="24" height="24" />
<rectangle flex_grow="1" height="100%" color="#1d2e51" border_color="#294774" border="2" round="4" align_items="center" padding_left="12">
<label text="Search" color="#FFFFFF88" weight="bold" />
</rectangle>
</div>
-->
<rectangle macro="group_box">
<GroupBox>
<div align_items="center" gap="8">
<sprite src_builtin="dashboard/heart_plus.svg" color="primary" min_width="24" min_height="24"/>
<sprite src_builtin="@/dashboard/heart_plus.svg" color="primary" min_width="24" min_height="24"/>
<label translation="PINNED_APPS"/>
</div>
<div id="pinned_apps_parent" flex_direction="row" flex_wrap="wrap" gap="4">
<!-- filled-in at runtime -->
</div>
</rectangle>
</GroupBox>
<div
id="app_list_parent"
flex_direction="row"
+8 -8
View File
@@ -1,16 +1,16 @@
<layout>
<include src="../t_separator.xml" />
<layout version="2">
<include src="@/gui/t_separator.xml" />
<template name="TierCell">
<div gap="8" align_items="center">
<sprite width="28" height="28" src_builtin="dashboard/medal.svg" color="${color}"/>
<sprite width="28" height="28" src_builtin="@/dashboard/medal.svg" color="${color}"/>
<label text="${text}" weight="bold" size="18" color="${color}" shadow="shadow"/>
</div>
</template>
<template name="SupporterCell">
<rectangle padding="8" color="background(transparent)" round="8" border="2" border_color="outline" gap="8" align_items="center" flex_direction="row" >
<sprite width="24" height="24" src_builtin="dashboard/person.svg"/>
<sprite width="24" height="24" src_builtin="@/dashboard/person.svg"/>
<label text="${username}" weight="bold"/>
</rectangle>
</template>
@@ -32,14 +32,14 @@
<elements>
<div flex_direction="row" width="100%" min_height="100%" gap="16">
<div macro="half">
<sprite color="#FFAAAA" src_builtin="dashboard/donate.svg" min_width="48" min_height="48"/>
<sprite color="#FFAAAA" src_builtin="@/dashboard/donate.svg" min_width="48" min_height="48"/>
<div gap="16" align_items="center" width="100%">
<label align="justified" wrap="1" size="15" translation="DONATE.DESCRIPTION" color="on_background"/>
</div>
<div flex_direction="column" gap="8" align_items="center">
<Button id="btn_donate" tooltip="DONATE.BUTTON_TOOLTIP" align_self="baseline">
<image src_builtin="dashboard/opencollective_logo.svg" width="200" height="32" margin="8" margin_left="16" margin_right="16"/>
<image src_builtin="@/dashboard/opencollective_logo.svg" width="200" height="32" margin="8" margin_left="16" margin_right="16"/>
</Button>
<label text="opencollective.com/wayvr-org"/>
</div>
@@ -47,8 +47,8 @@
<label weight="bold" size="20" translation="DONATE.THANK_YOU_WAYVR" color="on_background"/>
<div gap="32">
<Avatar icon="dashboard/avatars/galister.png" nickname="galister"/>
<Avatar icon="dashboard/avatars/oo8dev.png" nickname="oo8dev"/>
<Avatar icon="@/dashboard/avatars/galister.png" nickname="galister"/>
<Avatar icon="@/dashboard/avatars/oo8dev.png" nickname="oo8dev"/>
</div>
</div>
<!-- vertical separator -->
+2 -2
View File
@@ -1,6 +1,6 @@
<layout>
<layout version="2">
<elements>
<div id="running_games_list_parent" align_self="center" />
<div id="game_list_parent" align_items="center" flex_direction="column" gap="8" />
</elements>
</layout>
</layout>
+25 -18
View File
@@ -1,5 +1,20 @@
<layout>
<include src="../t_menu_button.xml" />
<layout version="2">
<include src="@/gui/t_menu_button.xml" />
<template name="MiscButton">
<Button
id="${id}" macro="home_button"
min_width="64" height="36"
padding_left="8" padding_right="8">
<div gap="8"
align_items="center"
justify_content="center"
flex_direction="row">
<sprite src_builtin="${icon}" width="24" height="24" />
<label weight="bold" size="18" text="${text}" translation="${translation}" />
</div>
</Button>
</template>
<elements>
<div
@@ -9,7 +24,7 @@
flex_grow="1"
gap="8"
>
<image src_builtin="dashboard/splash.png" width="300" height="89" />
<image src_builtin="@/dashboard/splash.png" width="300" height="89" />
<!-- supporters -->
<Button
@@ -26,24 +41,16 @@
<!-- main button list -->
<div flex_direction="row" gap="8" margin_top="32">
<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_settings" icon="dashboard/settings.svg" translation="SETTINGS" />
<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_settings" icon="@/dashboard/settings.svg" translation="SETTINGS" />
</div>
<div gap="8">
<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>
<Button id="btn_website" macro="home_button" tooltip_str="wayvr.org">
<sprite src_builtin="dashboard/globe.svg" width="32" height="32" margin="16" />
</Button>
<Button id="btn_donate" macro="home_button" tooltip="DONATE.SUPPORT_US">
<sprite src_builtin="dashboard/opencollective.svg" width="32" height="32" margin="16" />
</Button>
<MiscButton id="btn_welcome_screen" icon="@/dashboard/welcome.svg" translation="APP_SETTINGS.TUTORIAL"/>
<MiscButton id="btn_website" icon="@/dashboard/globe.svg" text="wayvr.org"/>
<MiscButton id="btn_donate" icon="@/dashboard/opencollective.svg" translation="DONATE.SUPPORT_US"/>
</div>
</div>
</elements>
+4 -4
View File
@@ -1,10 +1,10 @@
<layout>
<layout version="2">
<elements>
<div gap="4">
<Tabs id="tabs">
<Tab name="process_list" translation="PROCESS_LIST" sprite_src_builtin="dashboard/cpu.svg" />
<Tab name="general_settings" translation="GENERAL_SETTINGS" sprite_src_builtin="dashboard/settings.svg" />
<Tab name="debug_timings" translation="DEBUG_INFO" sprite_src_builtin="dashboard/not_a_bug.svg" />
<Tab name="process_list" translation="PROCESS_LIST" sprite_src_builtin="@/dashboard/cpu.svg" />
<Tab name="general_settings" translation="GENERAL_SETTINGS" sprite_src_builtin="@/dashboard/settings.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 -->
@@ -1,5 +1,5 @@
<layout>
<include src="../t_group_box.xml" />
<layout version="2">
<include src="@/gui/t_group_box.xml" />
<!-- name, limit_min, limit_max -->
<template name="DebugGraph">
@@ -15,13 +15,13 @@
</template>
<elements>
<rectangle macro="group_box">
<GroupBoxTitle src_builtin="dashboard/apps.svg" text="Sessions" />
<GroupBox>
<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" />
<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>
</GroupBox>
</elements>
</layout>
</layout>
@@ -1,56 +1,57 @@
<layout>
<include src="../t_group_box.xml" />
<layout version="2">
<include src="@/gui/t_group_box.xml" />
<macro name="slider" width="100%" height="24"/>
<template name="CKRow">
<div gap="8" width="~s_width">
<CHILDREN/>
</div>
</template>
<theme>
<!-- title, id -->
<template name="CKSlider">
<div gap="8" flex_direction="column" width="100%">
<label text="${title}"/>
<Slider id="${id}" min_value="0" max_value="100" width="100%" height="24"/>
</div>
</template>
<!-- title, id -->
<template name="CKColSel">
<div gap="8" flex_direction="column" width="100%">
<label text="${title}"/>
<ColorSelector id="cs_keying" height="24" width="100%"/>
</div>
</template>
<vars>
<var key="s_width" value="500"/>
</theme>
</vars>
<elements>
<div flex_direction="column" gap="8">
<rectangle macro="group_box">
<GroupBoxTitle src_builtin="dashboard/settings.svg" translation="GENERAL_SETTINGS" />
<!-- headset brightness -->
<GroupBox>
<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>
</GroupBox>
<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>
<!-- color keying -->
<GroupBox>
<GroupBoxTitle src_builtin="@/dashboard/settings.svg" translation="APP_SETTINGS.COLOR_KEYING" />
<CKRow>
<CKColSel title="Color" id="cs_keying"/>
<CKSlider title="Despill" id="slider_keying_despill"/>
<CKSlider title="Curve (0 = disabled)" id="slider_keying_curve"/>
</CKRow>
<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>
<CKRow>
<CKSlider title="Hue range" id="slider_keying_hue_range"/>
<CKSlider title="Saturation range" id="slider_keying_saturation_range"/>
<CKSlider title="Value range" id="slider_keying_value_range"/>
</CKRow>
</GroupBox>
</div>
</elements>
</layout>
@@ -1,5 +1,5 @@
<layout>
<include src="../t_group_box.xml" />
<layout version="2">
<include src="@/gui/t_group_box.xml" />
<!-- key: str, value: str -->
<template name="BoolFlag">
@@ -11,7 +11,7 @@
<!-- name, checked, flag_* -->
<template name="Cell">
<rectangle macro="group_box">
<GroupBox>
<CheckBox id="checkbox" text="${name}" checked="${checked}" />
<div flex_direction="row" gap="8" flex_wrap="wrap">
<BoolFlag key="Active:" value="${flag_active}" />
@@ -21,15 +21,15 @@
<BoolFlag key="Primary:" value="${flag_primary}" />
<BoolFlag key="Visible:" value="${flag_visible}" />
</div>
</rectangle>
</GroupBox>
</template>
<elements>
<rectangle macro="group_box">
<GroupBoxTitle src_builtin="dashboard/cpu.svg" translation="PROCESS_LIST" />
<GroupBox>
<GroupBoxTitle src_builtin="@/dashboard/cpu.svg" translation="PROCESS_LIST" />
<div id="list_parent" flex_direction="column" gap="8">
<!-- filled at runtime -->
</div>
</rectangle>
</GroupBox>
</elements>
</layout>
</layout>
+42 -12
View File
@@ -1,6 +1,6 @@
<layout>
<include src="../t_group_box.xml" />
<include src="../t_dropdown_button.xml" />
<layout version="2">
<include src="@/gui/t_group_box.xml" />
<include src="@/gui/t_dropdown_button.xml" />
<template name="SettingsGroupBox">
<rectangle macro="group_box" id="${id}" flex_grow="1">
@@ -31,6 +31,34 @@
<RadioBox text="${text}" translation="${translation}" value="${value}" tooltip="${tooltip}" />
</template>
<!-- title, sprite, color, tooltip_str -->
<template name="DiagnosticsRow">
<div align_items="center">
<label text="${title}" weight="bold" min_width="140"/>
<Button tooltip_str="${tooltip_str}" color="background(transparent)">
<sprite width="24" height="24" color="${color}" src_builtin="${sprite}" parent_color="ignore"/>
</Button>
</div>
</template>
<!-- name, info -->
<template name="DiagnosticsDrmCard">
<GroupBox>
<div gap="8">
<sprite width="24" height="24" src_builtin="@/dashboard/gpu.svg"/>
<label text="${name}"/>
</div>
<label text="${info}"/>
</GroupBox>
</template>
<template name="StatRow">
<div flex_direction="row" justify_content="space_between" align_items="center" gap="12" width="100%">
<label weight="bold" translation="${translation}" />
<label id="${id}" weight="bold" />
</div>
</template>
<template name="ButtonText">
<Button id="${id}" height="32" tooltip="${translation}_HELP" padding="4" gap="8">
<sprite src_builtin="${icon}" height="24" width="24" />
@@ -49,7 +77,7 @@
<div id="${id}_root" flex_direction="row">
<Button id="${id}" color="#AA3333" height="24" padding="4" margin_top="-2" margin_bottom="-2"
hover_color="danger" hover_border_color="danger(rgb-mult-0.5)" >
<sprite src_builtin="dashboard/close.svg" height="20" width="20" />
<sprite src_builtin="@/dashboard/close.svg" height="20" width="20" />
</Button>
<div padding_left="8">
<label align="left" text="${text}" weight="bold" overflow="hidden" />
@@ -62,14 +90,16 @@
<elements>
<div gap="4">
<Tabs id="tabs">
<Tab macro="tab_style" name="look_and_feel" translation="APP_SETTINGS.LOOK_AND_FEEL" sprite_src_builtin="dashboard/palette.svg" />
<Tab macro="tab_style" name="skybox" translation="APP_SETTINGS.SKYBOX" sprite_src_builtin="dashboard/globe.svg" />
<Tab macro="tab_style" name="features" translation="APP_SETTINGS.FEATURES" sprite_src_builtin="dashboard/options.svg" />
<Tab macro="tab_style" name="controls" translation="APP_SETTINGS.CONTROLS" sprite_src_builtin="dashboard/controller.svg" />
<Tab macro="tab_style" name="space_drag" translation="APP_SETTINGS.SPACE_DRAG" sprite_src_builtin="dashboard/drag.svg" />
<Tab macro="tab_style" name="misc" translation="APP_SETTINGS.MISC" sprite_src_builtin="dashboard/blocks.svg" />
<Tab macro="tab_style" name="autostart_apps" translation="APP_SETTINGS.AUTOSTART_APPS" sprite_src_builtin="dashboard/apps.svg" />
<Tab macro="tab_style" name="troubleshooting" translation="APP_SETTINGS.TROUBLESHOOTING" sprite_src_builtin="dashboard/cpu.svg" />
<Tab macro="tab_style" name="look_and_feel" translation="APP_SETTINGS.LOOK_AND_FEEL" sprite_src_builtin="@/dashboard/palette.svg" />
<Tab macro="tab_style" name="skybox" translation="APP_SETTINGS.SKYBOX" sprite_src_builtin="@/dashboard/globe.svg" />
<Tab macro="tab_style" name="features" translation="APP_SETTINGS.FEATURES" sprite_src_builtin="@/dashboard/options.svg" />
<Tab macro="tab_style" name="controls" translation="APP_SETTINGS.CONTROLS" sprite_src_builtin="@/dashboard/controller.svg" />
<Tab macro="tab_style" name="space_drag" translation="APP_SETTINGS.SPACE_DRAG" sprite_src_builtin="@/dashboard/drag.svg" />
<Tab macro="tab_style" name="misc" translation="APP_SETTINGS.MISC" sprite_src_builtin="@/dashboard/blocks.svg" />
<Tab macro="tab_style" name="autostart_apps" translation="APP_SETTINGS.AUTOSTART_APPS" sprite_src_builtin="@/dashboard/apps.svg" />
<Tab macro="tab_style" name="statistics" translation="APP_SETTINGS.STATISTICS" sprite_src_builtin="@/dashboard/barchart.svg" />
<Tab macro="tab_style" name="diagnostics" translation="APP_SETTINGS.DIAGNOSTICS.TITLE" sprite_src_builtin="@/dashboard/diagnostics.svg" />
<Tab macro="tab_style" 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 -->
@@ -1,14 +1,14 @@
<layout>
<include src="../t_group_box.xml" />
<layout version="2">
<include src="@/gui/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" />
<GroupBox>
<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>
</GroupBox>
</elements>
</layout>
+3 -3
View File
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<template name="Pip">
<rectangle id="pip" width="8" height="8" round="100%" color="${COLOR}"/>
</template>
@@ -12,11 +12,11 @@
<!-- 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" />
<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" />
<Button id="btn_next" width="32" height="32" round="100%" sprite_src_builtin="@/dashboard/arrow_right.svg" />
</div>
</div>
</div>
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<!-- 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">
@@ -19,4 +19,13 @@
<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"/>
<!-- src_builtin, aspect_ratio -->
<template name="WelcomeVideo">
<Video macro="video_overlay_component" src_builtin="${src_builtin}" aspect_ratio="${aspect_ratio}">
<div macro="video_overlay_content">
<CHILDREN/>
</div>
</Video>
</template>
</layout>
@@ -1,6 +1,6 @@
<layout>
<layout version="2">
<elements>
<image src_builtin="dashboard/splash.png" min_width="336" min_height="100" />
<image src_builtin="@/dashboard/splash.png" min_width="336" min_height="100" />
<rectangle color="#FFFFFF11" width="100%" height="2"/>
@@ -10,12 +10,12 @@
<label size="20" translation="WELCOME.GUIDE_INTRO"/>
<div gap="4" align_items="center" margin_top="8">
<sprite min_width="16" min_height="16" src_builtin="dashboard/info.svg" color="on_background"/>
<sprite min_width="16" min_height="16" src_builtin="@/dashboard/info.svg" color="on_background"/>
<label wrap="1" size="14" translation="WELCOME.REPOSITION_THIS_WINDOW_BY_GRABBING"/>
</div>
<div gap="4" align_items="center">
<sprite min_width="16" min_height="16" src_builtin="dashboard/info.svg" color="on_background"/>
<sprite min_width="16" min_height="16" src_builtin="@/dashboard/info.svg" color="on_background"/>
<label wrap="1" size="14" translation="WELCOME.LAST_PAGE_INFO"/>
</div>
@@ -1,15 +1,14 @@
<layout>
<layout version="2">
<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" translation="WELCOME.WATCH"/>
<div position="relative" align_self="end" padding="16">
<TextDesc translation="WELCOME.LOOK_AT_LEFT_WRIST"/>
</div>
<WelcomeVideo src_builtin="@/video/onboarding_watch.ivf" aspect_ratio="1.0">
<PageTitle icon="@/dashboard/watch.svg" translation="WELCOME.WATCH"/>
<div position="relative" align_self="end" padding="16">
<TextDesc translation="WELCOME.LOOK_AT_LEFT_WRIST"/>
</div>
</Video>
</WelcomeVideo>
</elements>
</layout>
@@ -1,14 +1,12 @@
<layout>
<layout version="2">
<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" translation="WELCOME.WORKING_SET"/>
<div position="relative" align_self="end" padding="16">
<TextDesc translation="WELCOME.DOUBLE_PRESS_TO_TOGGLE"/>
</div>
<WelcomeVideo src_builtin="@/video/onboarding_double_press.ivf">
<PageTitle icon="@/dashboard/panorama.svg" translation="WELCOME.WORKING_SET"/>
<div position="relative" align_self="end" padding="16">
<TextDesc translation="WELCOME.DOUBLE_PRESS_TO_TOGGLE"/>
</div>
</Video>
</WelcomeVideo>
</elements>
</layout>
+11 -13
View File
@@ -1,19 +1,17 @@
<layout>
<layout version="2">
<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" translation="WELCOME.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="outline" border="2" >
<label size="12" weight="bold" color="#00FFFF" translation="WELCOME.REGULAR_MODE_BLUE_LASER"/>
<label size="12" weight="bold" color="#FFAA00" translation="WELCOME.RIGHT_CLICK_MODE_ORANGE_LASER"/>
<label size="12" weight="bold" color="#FF88FF" translation="WELCOME.MIDDLE_CLICK_MODE_PURPLE_LASER"/>
</rectangle>
<label wrap="1" size="18" width="450" weight="bold" color="#ffffff" shadow="#000000" translation="WELCOME.LASER_FUNCTIONALITY"/>
</div>
<WelcomeVideo src_builtin="@/video/onboarding_laser_colors.ivf">
<PageTitle icon="@/dashboard/click.svg" translation="WELCOME.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="outline" border="2" >
<label size="12" weight="bold" color="#00FFFF" translation="WELCOME.REGULAR_MODE_BLUE_LASER"/>
<label size="12" weight="bold" color="#FFAA00" translation="WELCOME.RIGHT_CLICK_MODE_ORANGE_LASER"/>
<label size="12" weight="bold" color="#FF88FF" translation="WELCOME.MIDDLE_CLICK_MODE_PURPLE_LASER"/>
</rectangle>
<label wrap="1" size="18" width="450" weight="bold" color="#ffffff" shadow="#000000" translation="WELCOME.LASER_FUNCTIONALITY"/>
</div>
</Video>
</WelcomeVideo>
</elements>
</layout>
+10 -12
View File
@@ -1,20 +1,18 @@
<layout>
<layout version="2">
<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" translation="WELCOME.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" translation="WELCOME.GRAB_ONE_HAND"/>
<label shadow="#000000" size="14" weight="bold" wrap="1" color="#ccaaff" translation="WELCOME.GRAB_BOTH_HANDS"/>
<div align_items="center" gap="8">
<sprite src_builtin="dashboard/info.svg" min_width="48" min_height="48" max_width="48" max_height="48" color="#ffff00"/>
<label shadow="#000000" size="16" weight="bold" wrap="1" color="#ffff00" translation="WELCOME.CENTER_MARKER"/>
</div>
<WelcomeVideo src_builtin="@/video/onboarding_center_marker.ivf" aspect_ratio="1.33333">
<PageTitle icon="@/dashboard/panorama.svg" translation="WELCOME.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" translation="WELCOME.GRAB_ONE_HAND"/>
<label shadow="#000000" size="14" weight="bold" wrap="1" color="#ccaaff" translation="WELCOME.GRAB_BOTH_HANDS"/>
<div align_items="center" gap="8">
<sprite src_builtin="@/dashboard/info.svg" min_width="48" min_height="48" max_width="48" max_height="48" color="#ffff00"/>
<label shadow="#000000" size="16" weight="bold" wrap="1" color="#ffff00" translation="WELCOME.CENTER_MARKER"/>
</div>
</div>
</Video>
</WelcomeVideo>
</elements>
</layout>
@@ -1,9 +1,9 @@
<layout>
<layout version="2">
<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"/>
<image src_builtin="@/dashboard/check_3d.png" width="256" height="256"/>
<div flex_direction="column" gap="16" max_width="480">
<TextDescBig translation="WELCOME.ALL_SET" color="tertiary"/>
@@ -12,14 +12,14 @@
<label size="16" wrap="1" translation="WELCOME.BASICS"/>
<label size="16" wrap="1" translation="WELCOME.FEATURES_DOCUMENTATION"/>
<Button id="btn_wayvr_org" align_self="baseline" min_height="32">
<sprite src_builtin="dashboard/globe.svg" width="24" height="24" margin="8"/>
<sprite src_builtin="@/dashboard/globe.svg" width="24" height="24" margin="8"/>
<label size="18" weight="bold" text="wayvr.org" margin_right="8" />
</Button>
<rectangle color="#FFFFFF33" width="100%" min_height="2"/>
<Button id="btn_home_screen" min_height="48" >
<sprite src_builtin="dashboard/check.svg" width="32" height="32" margin="8"/>
<sprite src_builtin="@/dashboard/check.svg" width="32" height="32" margin="8"/>
<label color="on_background" size="20" weight="bold" translation="WELCOME.FINISH_TUTORIAL" margin_right="8" />
</Button>
</div>
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<template name="Subtext">
<div flex_direction="row" gap="8" max_width="100%">
<label weight="bold" text="${title}" wrap="1" />
@@ -10,8 +10,8 @@
<sprite src_ext="${path}" width="96" height="96" />
</template>
<include src="../t_separator.xml" />
<include src="../t_group_box.xml" />
<include src="@/gui/t_separator.xml" />
<include src="@/gui/t_group_box.xml" />
<elements>
<div flex_direction="row" gap="16" flex_grow="1">
@@ -45,15 +45,15 @@
<CheckBox id="cb_autostart" translation="APP_LAUNCHER.AUTOSTART" align_self="baseline"/>
<div flex_direction="row" align_items="end" justify_content="center" gap="8" margin_top="8">
<Button id="btn_unpin" color="danger" padding_left="8" padding_right="8" round="8" min_height="40">
<sprite src_builtin="dashboard/heart_minus.svg" width="32" height="32" />
<sprite src_builtin="@/dashboard/heart_minus.svg" width="32" height="32" />
<label translation="REMOVE_FROM_FAVOURITES" weight="bold" size="17" />
</Button>
<Button id="btn_pin" color="secondary" padding_left="8" padding_right="8" round="8" min_height="40" tooltip="ADD_TO_FAVOURITES_HINT">
<sprite src_builtin="dashboard/heart_plus.svg" width="32" height="32" />
<sprite src_builtin="@/dashboard/heart_plus.svg" width="32" height="32" />
<label translation="ADD_TO_FAVOURITES" weight="bold" size="17" />
</Button>
<Button id="btn_launch" color="primary" padding_left="8" padding_right="8" round="8" min_width="200" min_height="40">
<sprite src_builtin="dashboard/play.svg" width="32" height="32" />
<sprite src_builtin="@/dashboard/play.svg" width="32" height="32" />
<label translation="APP_LAUNCHER.LAUNCH" weight="bold" size="17" />
</Button>
</div>
@@ -1,35 +1,35 @@
<layout>
<include src_builtin="../t_group_box.xml" />
<layout version="2">
<include src_builtin="@/gui/t_group_box.xml" />
<!-- device_name, device_icon -->
<template name="DeviceSlider">
<rectangle macro="group_box">
<GroupBox id="rect">
<div width="100%" align_items="center" justify_content="center" gap="8">
<sprite src_builtin="${device_icon}" width="16" height="16" color="on_background" />
<sprite src_builtin="${device_icon}" width="24" height="24" color="on_background" />
<label text="${device_name}" margin_right="8" size="12" weight="bold" color="on_background" />
</div>
<div width="100%" align_items="center">
<CheckBox id="checkbox" />
<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" />
<CheckBox id="checkbox" tooltip="AUDIO.SWITCH_TO_THIS_DEVICE" />
<Slider id="slider" flex_grow="1" height="16" min_value="0" max_value="150" margin_left="8" margin_right="8" />
<Button sprite_src_builtin="${volume_icon}" id="btn_mute" width="32" height="32" />
</div>
</rectangle>
</GroupBox>
</template>
<!-- card_name, profile_name -->
<template name="Card">
<rectangle macro="group_box">
<GroupBox>
<div width="100%" align_items="center" justify_content="center">
<label text="${card_name}" size="12" weight="bold" color="on_background" />
</div>
<Button id="btn_card" text="${profile_name}" width="100%" height="32" />
</rectangle>
</GroupBox>
</template>
<template name="SelectAudioProfileText">
<div align_items="center" gap="8">
<Button width="48" height="32" id="btn_back">
<sprite src_builtin="dashboard/back.svg" width="24" height="24" color="on_background" />
<sprite src_builtin="@/dashboard/back.svg" width="24" height="24" color="on_background" />
</Button>
<label translation="AUDIO.SELECT_AUDIO_CARD_PROFILE" size="14" weight="bold" />
</div>
@@ -47,24 +47,33 @@
<elements>
<div flex_direction="column" gap="4">
<div id="devices" flex_direction="column" gap="4" max_height="400" overflow_y="scroll">
<!--
this div shouldn't be technically needed, but there's a bug in
the newest taffy version (or we're doing something wrong),
causing the scrollbar to show up, even if it's not overflowing.
OVERFLOW_START_THRESHOLD_UNITS is already set to 3, but it's not
sufficient enough in this case?? (margin_bottom="4" fixes that).
-->
<div width="100%" flex_direction="column" max_height="400" overflow_y="scroll">
<div id="devices" width="100%" flex_direction="column" gap="4" margin_bottom="4">
</div>
</div>
<!-- bottom buttons -->
<div flex_direction="row" gap="4">
<Button
id="btn_auto"
sprite_src_builtin="dashboard/magic_wand.svg"
sprite_src_builtin="@/dashboard/magic_wand.svg"
min_width="32"
tooltip="AUDIO.AUTO_SWITCH_TO_VR_AUDIO"
color="primary"
sprite_color="on_primary"
tooltip_side="right" />
<BottomButton id="btn_sinks" src_builtin="dashboard/volume.svg" translation="AUDIO.SPEAKERS" />
<BottomButton id="btn_sources" src_builtin="dashboard/microphone.svg" translation="AUDIO.MICROPHONES" />
<BottomButton id="btn_cards" src_builtin="dashboard/cpu.svg" translation="AUDIO.CARDS" />
<BottomButton id="btn_sinks" src_builtin="@/dashboard/volume.svg" translation="AUDIO.SPEAKERS" />
<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>
+6 -6
View File
@@ -1,8 +1,8 @@
<layout>
<include src="../t_group_box.xml" />
<layout version="2">
<include src="@/gui/t_group_box.xml" />
<!-- used at runtime [!!!] -->
<include src="../t_dropdown_button.xml" />
<include src="@/gui/t_dropdown_button.xml" />
<!-- id, min, max, step, value, value2, tooltip -->
<template name="ThresholdSlider">
@@ -14,7 +14,7 @@
<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" color="on_background"/>
<sprite src_builtin="@/dashboard/controller.svg" width="24" height="24" color="on_background"/>
<label translation="${translation}" color="primary" weight="bold" size="14" />
</div>
<!-- filled-in at runtime -->
@@ -27,8 +27,8 @@
<div id="list_parent" flex_direction="column" gap="6" width="100%"></div>
</div>
<rectangle color="background_contrast" 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" />
<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>
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<template name="ColorPaletteButton">
<Button id="${id}" width="350" flex_direction="column" justify_content="space_around" tooltip="${tooltip}" tooltip_side="bottom"
color="${background}" hover_color="${background_variant}" border_color="${outline}" hover_border_color="${highlight}" padding="16" margin="4" >
@@ -20,7 +20,7 @@
</template>
<elements>
<div flex_direction="column" gap="8" width="100%" align_items="center">
<div flex_direction="column" gap="8" width="100%" align_items="center" overflow_y="scroll">
<div id="list_parent" flex_grow="1" flex_wrap="wrap" flex_direction="row" gap="4" width="100%" justify_content="center"></div>
</div>
</elements>
+5 -2
View File
@@ -1,6 +1,9 @@
<layout>
<layout version="2">
<template name="DialogBoxButton">
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="${icon}"/>
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="${icon}"
text_size="16"
padding_left="16" padding_right="16"
padding_top="8" padding_bottom="8"/>
</template>
<elements>
@@ -1,8 +1,8 @@
<layout>
<include src="../t_separator.xml"/>
<layout version="2">
<include src="@/gui/t_separator.xml"/>
<template name="btn_close">
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="dashboard/check.svg"/>
<Button id="btn" translation="CLOSE_WINDOW" align_self="start" sprite_src_builtin="@/dashboard/check.svg"/>
</template>
<elements>
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<elements>
<div flex_direction="row" gap="16" align_items="center">
<div id="cover_art_parent" />
@@ -10,7 +10,7 @@
</div>
<label id="label_description" wrap="1" text="No description available" />
<Button id="btn_launch" align_self="baseline" color="primary" border_color="primary(rgb-mult-0.5)" padding_top="4" padding_bottom="4" round="8" padding_right="12" min_width="200" min_height="40">
<sprite src_builtin="dashboard/play.svg" width="32" height="32" />
<sprite src_builtin="@/dashboard/play.svg" width="32" height="32" />
<label text="Launch" weight="bold" size="17" />
</Button>
</div>
+4 -4
View File
@@ -1,12 +1,12 @@
<layout>
<layout version="2">
<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" />
<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" />
<Button id="btn_next" sprite_src_builtin="@/dashboard/arrow_right.svg" width="32" height="32" />
</div>
</elements>
</layout>
</layout>
@@ -1,8 +1,8 @@
<layout>
<layout version="2">
<!-- 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" />
<sprite margin_left="8" src_builtin="@/dashboard/controller.svg" min_width="24" min_height="24" />
<label text="${text}" weight="bold"/>
</Button>
</template>
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<elements>
<div
consume_mouse_events="1"
@@ -20,10 +20,10 @@
<rectangle position="absolute" width="100%" height="3" round="4" color="highlight(opacity-0.1)" />
<!-- Top bar contents -->
<div gap="16" align_items="center">
<div gap="16" align_items="center" id="top_bar_contents">
<!-- Back button -->
<Button id="but_back" width="48" height="48" color="on_background_contrast(transparent)" border_color="on_background_contrast(transparent)">
<sprite src_builtin="dashboard/back.svg" width="24" height="24" color="on_background_contrast" />
<sprite src_builtin="@/dashboard/back.svg" width="24" height="24" color="on_background_contrast" />
</Button>
<!-- Title -->
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<!--
parameters:
@@ -12,7 +12,7 @@
<Button id="button" sprite_src_builtin="${sprite}" text="${text}"/>
</template>
<include src="../t_separator.xml"/>
<include src="@/gui/t_separator.xml"/>
<elements>
<div gap="8" flex_direction="column" min_width="100%" overflow_y="scroll">
@@ -1,7 +1,9 @@
<layout>
<layout version="2">
<elements>
<div id="list" gap="8" flex_wrap="wrap" align_self="baseline">
<!-- filled-in at runtime -->
<div flex_direction="column" overflow_y="scroll">
<div id="list" gap="8" flex_direction="row" flex_wrap="wrap">
<!-- filled-in at runtime -->
</div>
</div>
</elements>
</layout>
@@ -1,20 +1,20 @@
<layout>
<include src="../t_group_box.xml" />
<layout version="2">
<include src="@/gui/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" />
<GroupBox>
<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>
</GroupBox>
</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" />
<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>
</layout>
@@ -1,11 +1,11 @@
<layout>
<layout version="2">
<elements>
<div flex_direction="column" gap="8" width="100%" align_items="center">
<div flex_direction="column" gap="8" width="100%" >
<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"/>
<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 id="list_parent" gap="8" flex_direction="row" flex_wrap="wrap" overflow_y="scroll" justify_content="center"/>
</div>
</elements>
</layout>
@@ -1,4 +1,4 @@
<layout>
<layout version="2">
<!--
ids:
@@ -15,9 +15,12 @@
flex_direction="column"
gap="4"
width="256"
max_width="450"
height="200"
align_items="center"
flex_grow="1"
align_self="start">
<image id="image_preview" width="100%" height="128" round="6">
<image id="image_preview" width="100%" aspect_ratio="2.0" 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>
@@ -34,7 +37,7 @@
-->
<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" color="#FFFFFF" shadow="#000000" shadow_x="2" shadow_y="2"/>
<label text="${text}" weight="bold" size="12" color="#FFFFFF" shadow="#000000" shadow_x="2" shadow_y="2" parent_color="ignore"/>
</rectangle>
</template>
</layout>
@@ -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="row" flex_wrap="wrap" flex_grow="1" />
</rectangle>
</elements>
</layout>
@@ -1,16 +0,0 @@
<layout>
<include src="../t_group_box.xml" />
<elements>
<div gap="16" flex_direction="column" width="100%" justify_self="center" align_items="center" justify_content="center">
<rectangle macro="group_box" align_items="center">
<div id="window_parent" />
<div gap="8">
<Button id="btn_show_hide" text="showhide" sprite_src_builtin="dashboard/eye.svg" />
<Button id="btn_close" translation="CLOSE_WINDOW" sprite_src_builtin="dashboard/remove_circle.svg" />
<Button id="btn_kill" translation="TERMINATE_PROCESS" sprite_src_builtin="dashboard/remove_circle.svg" />
</div>
</rectangle>
</div>
</elements>
</layout>
+43 -8
View File
@@ -97,7 +97,10 @@
"RIGHT": "Rechts",
"COMPONENT": "Aktivierungsart",
"SUBPATH": "Bedienelement",
"THRESHOLD": "Aktivieren bei Überschreiten des oberen Wertes\nDeaktivieren bei Unterschreiten des unteren Wertes"
"THRESHOLD": "Aktivieren bei Überschreiten des oberen Wertes\nDeaktivieren bei Unterschreiten des unteren Wertes",
"CHORD": "Chord",
"CHORD_ADD_INPUT": "Chord-Input hinzufügen",
"CHORD_INPUT_HAND": "Eingabehand"
},
"BROWSE_ONLINE_CATALOG": "Online-Katalog durchsuchen...",
"BROWSE_SKYMAPS": "Skymaps durchsuchen",
@@ -194,8 +197,6 @@
"SAVE_PLAYSPACE_CENTER_HELP": "Nutze aktuellen Playspace für die Playspace-Reset-Belegung.",
"RESET_PLAYSPACE_CENTER": "Playspace-Zentrum zurücksetzen",
"RESET_PLAYSPACE_CENTER_HELP": "Vorheriges Playspace-Zentrum zurücksetzen.",
"RESTART_SOFTWARE": "Software neu starten",
"RESTART_SOFTWARE_HELP": "Einstellungen übernehmen, die einen Neustart erfordern",
"ROUND_MULTIPLIER": "Abrundung der UI-Kanten",
"SCREEN_RENDER_DOWN": "Bildschirm mit niedrigerer Auflösung rendern",
"SCREEN_RENDER_DOWN_HELP": "Hilft gegen Treppeneffekte bei hochauflösenden Bildschirmen",
@@ -205,7 +206,6 @@
"SNAP_ANGLE_DEG_HELP": "Gegriffene Fenster rasten auf der Nick- und Rollachse in diesem Winkel ein.",
"ENABLE_WATCH": "Handgelenk-Uhr aktivieren",
"SETS_ON_WATCH": "Sets auf Handgelenk-Uhr",
"SHOW_WELCOME_SCREEN": "Willkommensbildschirm anzeigen",
"SKYBOX": "Skymap",
"SKYMAP_ALREADY_DOWNLOADED": "Diese Skymap ist bereits heruntergeladen. Wähle eine Aktion aus.",
"SPACE_DRAG": "Playspace",
@@ -243,7 +243,29 @@
"GRID_OPACITY_HELP": "Deckkraft des Bodengitters, wenn die Skymap aktiviert ist",
"XWAYLAND_BY_DEFAULT": "Apps standardmäßig im Kompatibilitätsmodus starten",
"SAVE": "Speichern",
"CANCEL": "Abbrechen"
"CANCEL": "Abbrechen",
"STATISTICS": "Statistiken",
"ROTATIONS": "HMD-Rotationen",
"SESSION_TIME": "Sitzungszeit",
"LENS_SEPARATION_MM": "Linsenabstand (mm)",
"MIDDLE_GRABS_SINGLE": "Mittelklick-Modifier greift einzeln",
"MIDDLE_GRABS_SINGLE_HELP": "Greifen mit dem Mittelklick-Modifier (lila Laser) \ngreift einzelne Overlays statt des gesamten Sets",
"DIAGNOSTICS_REASON": {
"PACTL": "Erforderlich für Lautsprecher-/Mikrofonsteuerung und das Wechseln der Soundkarte",
"CAGE": "Empfohlen bei Inkompatibilitäten mit einigen X11-Anwendungen (Kompatibilitätsmodus)",
"XWAYLAND_SATELLITE": "Empfohlen, wenn X11 (Xwayland) Anwendungen im nativen Modus ausgeführt werden sollen",
"XDG_OPEN": "Erforderlich zum Öffnen von URLs oder Steam-Spielen"
},
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "CPU-zugänglicher VRAM: {NUM} MiB",
"TITLE": "Diagnose",
"ENABLE_REBAR": "Aktiviere resizable bar in den BIOS-Einstellungen für optimale VR-Performance"
},
"TUTORIAL": "Tutorial",
"RESTART_WAYVR": "WayVR neu starten",
"CLOSE_WAYVR": "WayVR schließen",
"SPEECH_TO_TEXT": "Sprache zu Text",
"WHISPER_GPU_SELECT": "GPU auswählen"
},
"APPLICATION_LAUNCHER": "Programmstarter",
"APPLICATION_STARTED": "Anwendung gestartet",
@@ -260,7 +282,8 @@
"SETTINGS": "Audio-Einstellungen",
"SPEAKERS": "Lautsprecher",
"SPEAKERS_SET_SUCCESSFULLY": "Lautsprecher erfolgreich eingestellt",
"VOLUME": "Lautstärke"
"VOLUME": "Lautstärke",
"SWITCH_TO_THIS_DEVICE": "Zu diesem Gerät wechseln"
},
"CLOSE_WINDOW": "Fenster schließen",
"CREATION_DATE": "Erstellungsdatum",
@@ -345,5 +368,17 @@
"ADD_TO_FAVOURITES": "Zu angehefteten Anwendungen hinzufügen",
"ADD_TO_FAVOURITES_HINT": "Voreinstellung speichern und an die App-Schublade anheften",
"REMOVE_FROM_FAVOURITES": "Aus angehefteten Anwendungen entfernen",
"EMPTY": "Leer"
}
"EMPTY": "Leer",
"INSTALLED": "Installiert",
"NOT_INSTALLED": "Nicht installiert",
"POWER_OPTIONS": {
"TITLE": "Energieoptionen",
"SHUTDOWN": "Herunterfahren",
"SUSPEND": "Ruhezustand",
"SHUTDOWN_ARE_YOU_SURE": "Bist du sicher, dass du den Computer ausschalten willst?",
"NOT_SUPPORTED": "Energieoptionen erfordern systemd oder elogind.",
"SUSPEND_ARE_YOU_SURE": "Bist du sicher, dass du den Computer in den Ruhezustand versetzen willst?"
},
"YES": "Ja",
"NO": "Nein"
}
+33 -3
View File
@@ -74,6 +74,9 @@ APP_SETTINGS.BINDINGS.ACTION.MOVE_MOUSE,Move mouse (if off by default),Label for
APP_SETTINGS.BINDINGS.ACTION.SCROLL,Scroll*,Label for the scroll action row. Maps controller input to scrolling. Leave the '*' at the end.
APP_SETTINGS.BINDINGS.LEFT,Left,Label in the bindings editor. Refers to the left controller/hand configuration.
APP_SETTINGS.BINDINGS.RIGHT,Right,Label in the bindings editor. Refers to the right controller/hand configuration.
APP_SETTINGS.BINDINGS.CHORD,Chord,Label for a group of controller inputs that must all be active together. As in Input Chord
APP_SETTINGS.BINDINGS.CHORD_ADD_INPUT,Add chord input,"Button in the controller bindings editor that adds another physical input to a chord. ""Chord"" was previously translated as ""${APP_SETTINGS.BINDINGS.CHORD}""."
APP_SETTINGS.BINDINGS.CHORD_INPUT_HAND,Input hand,"Selector for the hand to which we will be binding the input action to."
APP_SETTINGS.BINDINGS.COMPONENT,Actuation type,"Tooltip for the component dropdown in the bindings editor. Asks user to select what type of actuation (click, touch, axis, etc.)."
APP_SETTINGS.BINDINGS.SUBPATH,Actuating control,Tooltip for the subpath dropdown in the bindings editor. Asks user to select which controller button/stick/trackpad to bind.
APP_SETTINGS.BINDINGS.THRESHOLD,"Activate when above upper value
@@ -119,6 +122,13 @@ controllers are unavailable.
Left pinch is grab, right is click.",Tooltip for the handsfree mode dropdown.
APP_SETTINGS.HANDSFREE_ALT_TAB,App switcher aim,Dropdown/setting in Settings > Features tab. Controls how the alt-tab app switcher is aimed.
APP_SETTINGS.HANDSFREE_ALT_TAB_HELP,"Hold Super+X, aim at the desired window, then release to switch focus.",Tooltip explaining the handsfree alt-tab behavior.
APP_SETTINGS.DIAGNOSTICS.CPU_ACCESSIBLE_VRAM,"CPU-accessible VRAM: {NUM} MiB","Amount of VRAM accessible by the CPU. For example: 256/4096"
APP_SETTINGS.DIAGNOSTICS.TITLE,"Diagnostics","Tab name for the hardware/software check panel"
APP_SETTINGS.DIAGNOSTICS.ENABLE_REBAR,"Enable Resizable BAR in the BIOS settings for optimal VR performance","Info shown if resizable bar is disabled in the BIOS. Leave [resizable bar] translation as-is."
APP_SETTINGS.DIAGNOSTICS_REASON.PACTL,"Required for speaker/microphone control and audio card switching","Reason for why the given software is recommended"
APP_SETTINGS.DIAGNOSTICS_REASON.CAGE,"Recommended in case if there's an incompatibility with some X11 applications (Compatibility mode)","Reason for why the given software is required or recommended"
APP_SETTINGS.DIAGNOSTICS_REASON.XWAYLAND_SATELLITE,"Recommended in case if you want to run X11 (Xwayland) applications in native mode","Reason for why the given software is required or recommended"
APP_SETTINGS.DIAGNOSTICS_REASON.XDG_OPEN,"Required for opening URLs or Steam games","Reason for why the given software is required or recommended"
APP_SETTINGS.HIDE_GRAB_HELP,Hide grab help,Checkbox label in Settings > Look & Feel tab. Hides the grab help overlay/text.
APP_SETTINGS.HIDE_USERNAME,Hide username,Checkbox label in Settings > Look & Feel tab. Hides the user's username from the UI.
APP_SETTINGS.INPUT_EMULATION_METHOD,Input emulation method,"Dropdown label in Settings > Miscellaneous tab. Selects how WayVR emulates mouse/keyboard input (uinput, Wayland virtual, none)."
@@ -132,6 +142,7 @@ APP_SETTINGS.INPUT_PROFILES,Change Input Bindings,Button label in Settings > Con
APP_SETTINGS.INPUT_PROFILES_HELP,OpenXR controller input bindings,Tooltip for the Change Input Bindings button.
APP_SETTINGS.INVERT_SCROLL_DIRECTION_X,Invert horizontal scroll direction,Checkbox label in Settings > Features tab. Inverts the horizontal scroll direction.
APP_SETTINGS.INVERT_SCROLL_DIRECTION_Y,Invert vertical scroll direction,Checkbox label in Settings > Features tab. Inverts the vertical scroll direction.
APP_SETTINGS.LENS_SEPARATION_MM,Lens separation (mm),"Distance between lens, in milimeters."
APP_SETTINGS.KEYBOARD_MIDDLE_CLICK,Keyboard middle click,Dropdown label in Settings > Features tab. Selects the modifier key used for middle-click when typing with the laser pointer.
APP_SETTINGS.KEYBOARD_MIDDLE_CLICK_HELP,"Modifier to use when typing
with purple laser",Tooltip for the keyboard middle-click setting.
@@ -142,6 +153,9 @@ APP_SETTINGS.LEFT_HANDED_MOUSE_HELP,Use this if mouse buttons are swapped,Toolti
APP_SETTINGS.LONG_PRESS_DURATION,Long press duration,Setting in Settings > Features tab. Controls how long a press must be held to register as a long press.
APP_SETTINGS.LOOK_AND_FEEL,Look & Feel,"Category header in Settings. Groups visual/customization settings like language, opacity, animation speed, color palettes."
APP_SETTINGS.MISC,Miscellaneous,"Category header in Settings. Groups troubleshooting and system-level settings like capture method, input emulation, xwayland."
APP_SETTINGS.MIDDLE_GRABS_SINGLE,"Middle-click modifier grabs individual","Checkbox label in Settings > Controls tab. When enabled, grabbing with the middle modifier will always grab individual objects, never the entire set of objects. ""Middle-click modifier"" was previously translated as ""${APP_SETTINGS.BINDINGS.ACTION.CLICK_MODIFIER_MIDDLE}"""
APP_SETTINGS.MIDDLE_GRABS_SINGLE_HELP,"Grabbing with the middle-click modifier (purple laser)
will grab individual overlays, not the entire set","Tooltip for the middle modifier grabs single overlays checkbox. ""Middle-click modifier"" was previously translated as ""${APP_SETTINGS.BINDINGS.ACTION.CLICK_MODIFIER_MIDDLE}"""
APP_SETTINGS.NOTIFICATIONS_ENABLED,Enable notifications,Checkbox label in Settings > Features tab. Enables or disables system notifications within WayVR.
APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED,Notification sounds,Checkbox label in Settings > Features tab. Enables or disables sound effects for notifications.
APP_SETTINGS.NOT_SUPPORTED,Not supported,Label shown in the space drag/physics settings when a feature (like gravity) is not supported by the current backend.
@@ -194,8 +208,8 @@ APP_SETTINGS.SAVE_PLAYSPACE_CENTER,Save playspace center,"Button in Settings > S
APP_SETTINGS.SAVE_PLAYSPACE_CENTER_HELP,Use current playspace for reset playspace binding.,"Tooltip for the Save playspace center button. ""Playspace"" was previously translated as ""${DEFINITIONS.PLAYSPACE}""."
APP_SETTINGS.RESET_PLAYSPACE_CENTER,Reset playspace center,"Button in Settings > Space Drag tab. Clears the previously saved playspace center. ""Playspace"" was previously translated as ""${DEFINITIONS.PLAYSPACE}""."
APP_SETTINGS.RESET_PLAYSPACE_CENTER_HELP,Clear previously set playspace center.,"Tooltip for the Reset playspace center button. ""Playspace"" was previously translated as ""${DEFINITIONS.PLAYSPACE}""."
APP_SETTINGS.RESTART_SOFTWARE,Restart software,Button in Settings > Troubleshooting tab. Restarts the WayVR software to apply settings that require a restart.
APP_SETTINGS.RESTART_SOFTWARE_HELP,Apply settings that require a restart,Tooltip for the Restart software button.
APP_SETTINGS.RESTART_WAYVR,Restart WayVR,Button in Settings which restarts WayVR
APP_SETTINGS.CLOSE_WAYVR,Close WayVR,Button in Settings which closes WayVR
APP_SETTINGS.ROUND_MULTIPLIER,UI Edge roundness,Slider in Settings > Look & Feel tab. Controls how rounded the corners of UI elements appear (range 0.1-5.0).
APP_SETTINGS.SCREEN_RENDER_DOWN,Render screen at lower resolution,Checkbox in Settings > Miscellaneous tab. Renders the captured desktop screen at a lower resolution to improve performance or reduce aliasing.
APP_SETTINGS.SCREEN_RENDER_DOWN_HELP,Helps with aliasing on high-res screens,Tooltip for the lower-resolution screen render setting.
@@ -205,7 +219,6 @@ APP_SETTINGS.SNAP_ANGLE_DEG,Window pitch & roll snap angle,Slider in Settings >
APP_SETTINGS.SNAP_ANGLE_DEG_HELP,Grabbed windows snap to this angle on pitch and roll axis.,Tooltip for the snap angle setting.
APP_SETTINGS.ENABLE_WATCH,Enable watch,"Checkbox in Settings > Look & Feel tab. Enables the wrist watch UI element. ""Watch"" was previously translated as ""${DEFINITIONS.WATCH}""."
APP_SETTINGS.SETS_ON_WATCH,Sets on watch,"Checkbox in Settings > Look & Feel tab. Shows overlay sets on the wrist watch display. ""Watch"" was previously translated as ""${DEFINITIONS.WATCH}"". ""Set"" was previously translated as ""${DEFINITIONS.SET}""."
APP_SETTINGS.SHOW_WELCOME_SCREEN,Show welcome screen,Checkbox in Settings > Features tab. Controls whether the welcome/tutorial screen is shown on first launch.
APP_SETTINGS.SKYBOX,Skymap,"Category header in Settings > Skymap tab. Groups skymap-related settings. ""Skymap"" was previously translated as ""${DEFINITIONS.SKYMAP}""."
APP_SETTINGS.SKYMAP_ALREADY_DOWNLOADED,This skymap is already downloaded. Select desired action.,"Message shown in a dialog when attempting to download a skymap that is already present locally. ""Skymap"" was previously translated as ""${DEFINITIONS.SKYMAP}""."
APP_SETTINGS.SPACE_DRAG,Playspace,"Category header in Settings. Groups playspace drag/physics settings including reset buttons and gravity. ""Playspace"" was previously translated as ""${DEFINITIONS.PLAYSPACE}""."
@@ -225,6 +238,9 @@ APP_SETTINGS.SPACE_GRAVITY_GROUND_FRICTION_HELP,"Amount of friction slowing you
APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT,Floor height,Setting in the space gravity physics panel. The Y position where the virtual floor is.
APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT_HELP,The Y position where the floor is. Gravity stops when you reach this height.,Tooltip for the floor height setting.
APP_SETTINGS.SPACE_ROTATE_UNLOCKED,Allow space rotate on all axes,"Checkbox in Settings > Space Drag tab. Unlocks space rotate to work on all axes. ""Space"" in this context refers to ""Playspace"" which was translated as ""${DEFINITIONS.PLAYSPACE}""."
APP_SETTINGS.ROTATIONS,HMD rotations,Number of full 360-degree rotations of the HMD since startup. Shown in Settings > Statistics.
APP_SETTINGS.SESSION_TIME,Session time,Time since WayVR started. Shown in Settings > Statistics.
APP_SETTINGS.STATISTICS,Statistics,Category header in Settings.
APP_SETTINGS.TROUBLESHOOTING,Troubleshooting,"Category header in Settings. Groups diagnostic/reset actions like clearing tokens, wiping config, and restarting."
APP_SETTINGS.UI_GRADIENT_INTENSITY,UI Gradient intensity,Slider in Settings > Look & Feel tab. Controls the intensity of gradient effects on the UI (range 0.0-1.0).
APP_SETTINGS.UPRIGHT_SCREEN_FIX,Upright screen fix,Checkbox in Settings > Miscellaneous tab. Fixes upright screen orientation on some desktop environments.
@@ -243,6 +259,9 @@ APP_SETTINGS.WHISPER_MODEL,Speech-to-text model,Dropdown label in Settings > Fea
APP_SETTINGS.WHISPER_MODEL_HELP,"Whisper model to use.
Larger models produce more accurate
results, but consume more VRAM.",Tooltip for the speech-to-text model dropdown.
APP_SETTINGS.SPEECH_TO_TEXT,"Speech to text","Category header in Settings"
APP_SETTINGS.WHISPER_GPU_SELECT,"Select GPU","A list of GPUs the user can select from"
APP_SETTINGS.TUTORIAL,Tutorial,Tooltip for tutorial button in the main screen.
APP_SETTINGS.GRID_OPACITY,Floor grid opacity,Slider in Settings > Skybox tab. Controls the opacity of the floor grid when skybox is enabled.
APP_SETTINGS.GRID_OPACITY_HELP,Opacity of the floor grid when the skymap is enabled,"Tooltip for the floor grid opacity slider. ""Skymap"" was previously translated as ""${DEFINITIONS.SKYMAP}""."
APP_SETTINGS.XWAYLAND_BY_DEFAULT,Run apps in Compatibility mode by default,Checkbox in Settings > Miscellaneous tab. Launches apps in Cage/compatibility mode by default.
@@ -251,6 +270,7 @@ APP_SETTINGS.CANCEL,Cancel,Button label in the controller bindings editor popup
APPLICATION_LAUNCHER,Application launcher,App launcher configuration popup title - appears as the label for the app launch/options dialog.
APPLICATION_STARTED,Application started,Toast notification shown after a successful app launch.
APPLICATIONS,Applications,Tab label in the dashboard sidebar for the Apps tab.
AUDIO.SWITCH_TO_THIS_DEVICE,Switch to this device,Button in the audio settings dialog
AUDIO.AUTO_SWITCH_TO_VR_AUDIO,Auto-switch to VR audio,Tooltip on the auto-switch audio button in the audio settings popup.
AUDIO.CARDS,Cards,Button label in the audio settings popup for selecting audio card profiles.
AUDIO.FAILED_TO_SWITCH_MICROPHONE,Failed to switch microphone,Error toast shown when switching to a VR microphone fails.
@@ -318,6 +338,12 @@ MODIFICATION_DATE,Modification date,Column label in the remote skymap downloader
MONADO_RUNTIME,Monado runtime,Tab label in the dashboard sidebar for the Monado runtime tab.
LOADING,Loading...,Label in the loading spinner template used across the UI.
POPUP_ADD_DISPLAY.RESOLUTION,Resolution,Label for the resolution field in the add display popup.
POWER_OPTIONS.TITLE,"Power options","A button which allows the user to perform a specific power action"
POWER_OPTIONS.SHUTDOWN,"Shut down","One of the power options: shuts down the computer"
POWER_OPTIONS.SUSPEND,"Suspend","One of the power options: suspends the computer"
POWER_OPTIONS.NOT_SUPPORTED,"Power options require systemd or elogind.","Notification to the user that power options (shutdown and suspend) are not available. 'systemd' and 'elogind' are package names and should not be translated."
POWER_OPTIONS.SHUTDOWN_ARE_YOU_SURE,"Are you sure you want to turn off your computer?","Question dialog box before shutting down the computer"
POWER_OPTIONS.SUSPEND_ARE_YOU_SURE,"Are you sure you want to put your computer to sleep?","Question dialog box before putting the computer in sleep mode"
PROCESS.FORCE_KILL,Force-kill,Tooltip on the kill button in the running games list.
PROCESS.STOP,Stop,Tooltip on the stop button in the running games list.
PROCESS_LIST,Process list,Tab name and group box title in the Monado runtime process list section.
@@ -337,3 +363,7 @@ ADD_TO_FAVOURITES,Add to pinned apps,"Label on the pin button in the app launche
ADD_TO_FAVOURITES_HINT,Save preset and pin it to the app drawer,"Tooltip on the add to favourites button in the app launcher popup. ""Pinned apps"" was previously translated as ""${PINNED_APPS}""."
REMOVE_FROM_FAVOURITES,Remove from pinned apps,"Label on the unpin section in the app launcher popup. ""Pinned apps"" was previously translated as ""${PINNED_APPS}""."
EMPTY,Empty,Label shown in the pinned apps section when there are no pinned apps.
INSTALLED,"Installed","Installation flag (installed/not installed)"
NOT_INSTALLED,"Not installed","Installation flag (installed/not installed)"
YES,"Yes","Just a simple 'Yes' message, button in the dialog box"
NO,"No","Just a simple 'No' message, button in the dialog box"
1 DEFINITIONS.ANCHORED Anchored A movement option that makes this window move together with the rest of the workspace. Emphasize the "moving together" part as opposed to "not moving at all".
74 APP_SETTINGS.BINDINGS.ACTION.SCROLL Scroll* Label for the scroll action row. Maps controller input to scrolling. Leave the '*' at the end.
75 APP_SETTINGS.BINDINGS.LEFT Left Label in the bindings editor. Refers to the left controller/hand configuration.
76 APP_SETTINGS.BINDINGS.RIGHT Right Label in the bindings editor. Refers to the right controller/hand configuration.
77 APP_SETTINGS.BINDINGS.CHORD Chord Label for a group of controller inputs that must all be active together. As in Input Chord
78 APP_SETTINGS.BINDINGS.CHORD_ADD_INPUT Add chord input Button in the controller bindings editor that adds another physical input to a chord. "Chord" was previously translated as "${APP_SETTINGS.BINDINGS.CHORD}".
79 APP_SETTINGS.BINDINGS.CHORD_INPUT_HAND Input hand Selector for the hand to which we will be binding the input action to.
80 APP_SETTINGS.BINDINGS.COMPONENT Actuation type Tooltip for the component dropdown in the bindings editor. Asks user to select what type of actuation (click, touch, axis, etc.).
81 APP_SETTINGS.BINDINGS.SUBPATH Actuating control Tooltip for the subpath dropdown in the bindings editor. Asks user to select which controller button/stick/trackpad to bind.
82 APP_SETTINGS.BINDINGS.THRESHOLD Activate when above upper value Deactivate when below lower value Tooltip for the threshold slider in the bindings editor. Explains the two-value threshold range for analog inputs.
122 APP_SETTINGS.INPUT_EMULATION_METHOD APP_SETTINGS.DIAGNOSTICS.ENABLE_REBAR Input emulation method Enable Resizable BAR in the BIOS settings for optimal VR performance Dropdown label in Settings > Miscellaneous tab. Selects how WayVR emulates mouse/keyboard input (uinput, Wayland virtual, none). Info shown if resizable bar is disabled in the BIOS. Leave [resizable bar] translation as-is.
123 APP_SETTINGS.INPUT_EMULATION_METHOD_HELP APP_SETTINGS.DIAGNOSTICS_REASON.PACTL Try change this in case mouse or keyboard input does not register. Required for speaker/microphone control and audio card switching Tooltip for the input emulation method dropdown. Reason for why the given software is recommended
124 APP_SETTINGS.INPUT_CAPTURE_METHOD APP_SETTINGS.DIAGNOSTICS_REASON.CAGE Input capture method Recommended in case if there's an incompatibility with some X11 applications (Compatibility mode) Dropdown label in Settings > Miscellaneous tab. Selects how physical input devices are captured for use inside WayVR. Reason for why the given software is required or recommended
125 APP_SETTINGS.DIAGNOSTICS_REASON.XWAYLAND_SATELLITE Recommended in case if you want to run X11 (Xwayland) applications in native mode Reason for why the given software is required or recommended
126 APP_SETTINGS.DIAGNOSTICS_REASON.XDG_OPEN Required for opening URLs or Steam games Reason for why the given software is required or recommended
127 APP_SETTINGS.HIDE_GRAB_HELP Hide grab help Checkbox label in Settings > Look & Feel tab. Hides the grab help overlay/text.
128 APP_SETTINGS.HIDE_USERNAME Hide username Checkbox label in Settings > Look & Feel tab. Hides the user's username from the UI.
129 APP_SETTINGS.INPUT_EMULATION_METHOD Input emulation method Dropdown label in Settings > Miscellaneous tab. Selects how WayVR emulates mouse/keyboard input (uinput, Wayland virtual, none).
130 APP_SETTINGS.INPUT_EMULATION_METHOD_HELP Try change this in case mouse or keyboard input does not register. Tooltip for the input emulation method dropdown.
131 APP_SETTINGS.INPUT_CAPTURE_METHOD Input capture method Dropdown label in Settings > Miscellaneous tab. Selects how physical input devices are captured for use inside WayVR.
132 APP_SETTINGS.INPUT_CAPTURE_METHOD_HELP Allows using physical peripherial inside WayVR. Super+Z: Switch input between WayVR and real desktop Super+X: Switch between WayVR apps Tooltip explaining the input capture method setting.
133 APP_SETTINGS.INPUT_PROFILES Change Input Bindings Button label in Settings > Controls tab. Opens the controller bindings editor popup.
134 APP_SETTINGS.INPUT_PROFILES_HELP OpenXR controller input bindings Tooltip for the Change Input Bindings button.
142 APP_SETTINGS.LEFT_HANDED_MOUSE_HELP APP_SETTINGS.LEFT_HANDED_MOUSE Use this if mouse buttons are swapped Left-handed mouse Tooltip for the left-handed mouse checkbox. Checkbox label in Settings > Features tab. Swaps mouse buttons for left-handed users.
143 APP_SETTINGS.LONG_PRESS_DURATION APP_SETTINGS.LEFT_HANDED_MOUSE_HELP Long press duration Use this if mouse buttons are swapped Setting in Settings > Features tab. Controls how long a press must be held to register as a long press. Tooltip for the left-handed mouse checkbox.
144 APP_SETTINGS.LOOK_AND_FEEL APP_SETTINGS.LONG_PRESS_DURATION Look & Feel Long press duration Category header in Settings. Groups visual/customization settings like language, opacity, animation speed, color palettes. Setting in Settings > Features tab. Controls how long a press must be held to register as a long press.
145 APP_SETTINGS.LOOK_AND_FEEL Look & Feel Category header in Settings. Groups visual/customization settings like language, opacity, animation speed, color palettes.
146 APP_SETTINGS.MISC Miscellaneous Category header in Settings. Groups troubleshooting and system-level settings like capture method, input emulation, xwayland.
147 APP_SETTINGS.NOTIFICATIONS_ENABLED APP_SETTINGS.MIDDLE_GRABS_SINGLE Enable notifications Middle-click modifier grabs individual Checkbox label in Settings > Features tab. Enables or disables system notifications within WayVR. Checkbox label in Settings > Controls tab. When enabled, grabbing with the middle modifier will always grab individual objects, never the entire set of objects. "Middle-click modifier" was previously translated as "${APP_SETTINGS.BINDINGS.ACTION.CLICK_MODIFIER_MIDDLE}"
148 APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED APP_SETTINGS.MIDDLE_GRABS_SINGLE_HELP Notification sounds Grabbing with the middle-click modifier (purple laser) will grab individual overlays, not the entire set Checkbox label in Settings > Features tab. Enables or disables sound effects for notifications. Tooltip for the middle modifier grabs single overlays checkbox. "Middle-click modifier" was previously translated as "${APP_SETTINGS.BINDINGS.ACTION.CLICK_MODIFIER_MIDDLE}"
153 APP_SETTINGS.OPTION.FLOATING_HELP APP_SETTINGS.OPAQUE_BACKGROUND Moves independently, recenters. Easy to misplace; not recommended. Opaque background Tooltip for the Floating positioning option. Checkbox label in Settings > Look & Feel tab. Makes overlay backgrounds fully opaque (no transparency).
154 APP_SETTINGS.OPTION.STATIC_HELP APP_SETTINGS.OPTION.ANCHORED_HELP Stays in place relative to world. Moves with center marker. Recommended. Tooltip for the Static positioning option. Tooltip for the Anchored positioning option.
155 APP_SETTINGS.OPTION.AUTO APP_SETTINGS.OPTION.FLOATING_HELP Automatic Moves independently, recenters. Easy to misplace; not recommended. Dropdown option for screen capture method. Uses ScreenCopy GPU if supported, otherwise PipeWire GPU. Tooltip for the Floating positioning option.
156 APP_SETTINGS.OPTION.STATIC_HELP Stays in place relative to world. Tooltip for the Static positioning option.
157 APP_SETTINGS.OPTION.AUTO Automatic Dropdown option for screen capture method. Uses ScreenCopy GPU if supported, otherwise PipeWire GPU.
158 APP_SETTINGS.OPTION.AUTO_HELP ScreenCopy GPU if supported, otherwise PipeWire GPU. Tooltip for the Automatic capture method option.
159 APP_SETTINGS.OPTION.AUTO_HELP APP_SETTINGS.OPTION.EYE_ONLY ScreenCopy GPU if supported, otherwise PipeWire GPU. Eye laser Tooltip for the Automatic capture method option. Dropdown option for handsfree pointer mode. Uses only eye-tracking laser (no pinch).
160 APP_SETTINGS.OPTION.EYE_ONLY APP_SETTINGS.OPTION.EYE_PINCH Eye laser Eye + pinch Dropdown option for handsfree pointer mode. Uses only eye-tracking laser (no pinch). Dropdown option for handsfree pointer mode. Uses eye-tracking for aiming and pinch for click.
161 APP_SETTINGS.OPTION.EYE_PINCH APP_SETTINGS.OPTION.HMD_ONLY Eye + pinch HMD laser Dropdown option for handsfree pointer mode. Uses eye-tracking for aiming and pinch for click. Dropdown option for handsfree pointer/alt-tab mode. Uses only the HMD forward laser.
208 APP_SETTINGS.SPACE_GRAVITY_FLING_STRENGTH_HELP APP_SETTINGS.SPACE_GRAVITY_GRAVITY_HELP Intensity multiplier of gravitational launch force after space-drag. 0.0 - no movement at all, 2.0 - double intensity Amount of downwards force. 0.0 - no gravity Tooltip for the fling strength setting. "Space" in this context refers to "Playspace" which was translated as "${DEFINITIONS.PLAYSPACE}". Tooltip for the gravity setting.
209 APP_SETTINGS.SPACE_GRAVITY_GRAVITY APP_SETTINGS.SPACE_GRAVITY_GROUND_FRICTION Gravity Ground friction Setting in the space gravity physics panel. Amount of downward force (0.0 = no gravity). Setting in the space gravity physics panel. Friction when touching the ground (0.0 = ice-like, 1.0 = rough).
210 APP_SETTINGS.SPACE_GRAVITY_GRAVITY_HELP APP_SETTINGS.SPACE_GRAVITY_GROUND_FRICTION_HELP Amount of downwards force. 0.0 - no gravity Amount of friction slowing you down if you're touching the ground. 0.0 - no friction (just like on ice), 1.0 - rough surface Tooltip for the gravity setting. Tooltip for the ground friction setting.
211 APP_SETTINGS.SPACE_GRAVITY_GROUND_FRICTION APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT Ground friction Floor height Setting in the space gravity physics panel. Friction when touching the ground (0.0 = ice-like, 1.0 = rough). Setting in the space gravity physics panel. The Y position where the virtual floor is.
212 APP_SETTINGS.SPACE_GRAVITY_GROUND_FRICTION_HELP APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT_HELP Amount of friction slowing you down if you're touching the ground. 0.0 - no friction (just like on ice), 1.0 - rough surface The Y position where the floor is. Gravity stops when you reach this height. Tooltip for the ground friction setting. Tooltip for the floor height setting.
213 APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT APP_SETTINGS.SPACE_ROTATE_UNLOCKED Floor height Allow space rotate on all axes Setting in the space gravity physics panel. The Y position where the virtual floor is. Checkbox in Settings > Space Drag tab. Unlocks space rotate to work on all axes. "Space" in this context refers to "Playspace" which was translated as "${DEFINITIONS.PLAYSPACE}".
214 APP_SETTINGS.SPACE_GRAVITY_FLOOR_HEIGHT_HELP APP_SETTINGS.ROTATIONS The Y position where the floor is. Gravity stops when you reach this height. HMD rotations Tooltip for the floor height setting. Number of full 360-degree rotations of the HMD since startup. Shown in Settings > Statistics.
215 APP_SETTINGS.SPACE_ROTATE_UNLOCKED APP_SETTINGS.SESSION_TIME Allow space rotate on all axes Session time Checkbox in Settings > Space Drag tab. Unlocks space rotate to work on all axes. "Space" in this context refers to "Playspace" which was translated as "${DEFINITIONS.PLAYSPACE}". Time since WayVR started. Shown in Settings > Statistics.
219 APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP APP_SETTINGS.UPRIGHT_SCREEN_FIX Fixes upright screens on some desktops Upright screen fix Tooltip for the upright screen fix checkbox. Checkbox in Settings > Miscellaneous tab. Fixes upright screen orientation on some desktop environments.
220 APP_SETTINGS.USE_PASSTHROUGH APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP Enable passthrough Fixes upright screens on some desktops Checkbox in Settings > Skybox tab. Allows camera passthrough mode if the XR runtime supports it. Tooltip for the upright screen fix checkbox.
221 APP_SETTINGS.USE_PASSTHROUGH_HELP APP_SETTINGS.USE_PASSTHROUGH Allow passthrough if the XR runtime supports it Enable passthrough Tooltip for the passthrough checkbox. Checkbox in Settings > Skybox tab. Allows camera passthrough mode if the XR runtime supports it.
APP_SETTINGS.USE_SKYBOX Show skymap Checkbox in Settings > Skybox tab. Shows a skybox when there's no scene app or passthrough active. "Skymap" was previously translated as "${DEFINITIONS.SKYMAP}".
222 APP_SETTINGS.USE_SKYBOX_HELP APP_SETTINGS.USE_PASSTHROUGH_HELP Show a skymap if there's no scene app or passthrough Allow passthrough if the XR runtime supports it Tooltip for the enable skybox checkbox. "Skymap" was previously translated as "${DEFINITIONS.SKYMAP}". Tooltip for the passthrough checkbox.
223 APP_SETTINGS.WATCH_VIEW_ANGLE APP_SETTINGS.USE_SKYBOX Watch view angles Show skymap Setting in Settings > Look & Feel tab. Controls the view angles at which the wrist watch fades in/out. "Watch" was previously translated as "${DEFINITIONS.WATCH}". Checkbox in Settings > Skybox tab. Shows a skybox when there's no scene app or passthrough active. "Skymap" was previously translated as "${DEFINITIONS.SKYMAP}".
224 APP_SETTINGS.WATCH_VIEW_ANGLE_HELP APP_SETTINGS.USE_SKYBOX_HELP Control how the watch fades away Show a skymap if there's no scene app or passthrough Tooltip for the watch view angles setting. "Watch" was previously translated as "${DEFINITIONS.WATCH}". Tooltip for the enable skybox checkbox. "Skymap" was previously translated as "${DEFINITIONS.SKYMAP}".
238 AUDIO.CARDS APP_SETTINGS.CANCEL Cards Cancel Button label in the audio settings popup for selecting audio card profiles. Button label in the controller bindings editor popup and in whisper model dialogs. Cancels/dismisses the dialog without saving.
239 AUDIO.FAILED_TO_SWITCH_MICROPHONE APPLICATION_LAUNCHER Failed to switch microphone Application launcher Error toast shown when switching to a VR microphone fails. App launcher configuration popup title - appears as the label for the app launch/options dialog.
240 AUDIO.MICROPHONE_SET_SUCCESSFULLY APPLICATION_STARTED Microphone set successfully Application started Toast notification after successfully switching the microphone. Toast notification shown after a successful app launch.
241 APPLICATIONS Applications Tab label in the dashboard sidebar for the Apps tab.
242 AUDIO.SWITCH_TO_THIS_DEVICE Switch to this device Button in the audio settings dialog
243 AUDIO.AUTO_SWITCH_TO_VR_AUDIO Auto-switch to VR audio Tooltip on the auto-switch audio button in the audio settings popup.
244 AUDIO.MICROPHONES AUDIO.CARDS Microphones Cards Button label in the audio settings popup for selecting microphone sources. Button label in the audio settings popup for selecting audio card profiles.
245 AUDIO.NO_VR_MICROPHONE_SWITCH_MANUALLY AUDIO.FAILED_TO_SWITCH_MICROPHONE No VR microphone found. Switch it manually. Failed to switch microphone Toast shown when no VR microphone is detected and manual switching is needed. Error toast shown when switching to a VR microphone fails.
246 AUDIO.NO_VR_SPEAKERS_FOUND_SWITCH_MANUALLY AUDIO.MICROPHONE_SET_SUCCESSFULLY No VR speakers found. Switch them manually. Microphone set successfully Toast shown when no VR speakers are detected after auto-switch. Toast notification after successfully switching the microphone.
259 DONATE.BUTTON_TOOLTIP DONATE.SUPPORT_US Donate via Open Collective Support us Tooltip on the donate button on the donate tab. Button tooltip on the home screen donate button.
260 DONATE.CURRENT_SUPPORTERS DONATE.DESCRIPTION Current Supporters We're a small team of 2 developers building WayVR in our free time. If you enjoy using this software, please consider supporting us - every donation helps us keep going. Section header on the donate tab listing supporters. Description text on the donate tab explaining the project.
261 DONATE.BROUGHT_TO_YOU_VARIANTS_OFTEN DONATE.THANK_YOU_WAYVR Supported by {USER}|Special thanks to {USER}|Sponsored by {USER}|Backed by {USER}|Driven by community members like {USER}|Made possible by {USER}|Sustained by {USER}|Contributed by {USER}|Funded by {USER} Thank you from the WayVR Team! This text will show up a random person from donations page - line below this string will display the supporter user. There are many variants of it. Thank you message displayed on the donate tab.
262 DONATE.BUTTON_TOOLTIP Donate via Open Collective Tooltip on the donate button on the donate tab.
263 DONATE.CURRENT_SUPPORTERS Current Supporters Section header on the donate tab listing supporters.
264 DONATE.BROUGHT_TO_YOU_VARIANTS_OFTEN Supported by {USER}|Special thanks to {USER}|Sponsored by {USER}|Backed by {USER}|Driven by community members like {USER}|Made possible by {USER}|Sustained by {USER}|Contributed by {USER}|Funded by {USER} This text will show up a random person from donations page - line below this string will display the supporter user. There are many variants of it.
265 DONATE.BROUGHT_TO_YOU_VARIANTS_RARE Coffee provided by {USER}|Fuelled by {USER}|Shoutout to {USER}!|Keeping us going: {USER}|Helping us grow: {USER}|Keeping the servers running: {USER}|With gratitude to {USER}|Powered by {USER}|Supported by friends like {USER} This text will show up a random person from donations page - line below this string will display the supporter user. There are many variants of it (rare versions).
266 DONATE.BROUGHT_TO_YOU_VARIANTS_VERY_RARE Supported by legends like {USER}|Caffeine supplied by {USER}|A true legend: {USER}|Our hero of the day: {USER}|An absolute superstar: {USER}|Paying for the electricity bill: {USER}|The savior of our sanity: {USER}|Leading the way: {USER}|Caffeine-to-code converter provided by {USER}|Keeping the production stable: {USER}|The one and only: {USER}|Passing dmabuf buffers: {USER} This text will show up a random person from donations page - line below this string will display the supporter user. There are many variants of it (rare versions).
267 DOWNLOAD Download Button in the Whisper model download dialog to confirm downloading a model.
270 WELCOME.BASICS These basics will allow you to start using WayVR with ease. Description text on the final welcome page under the You are all set heading.
271 WELCOME.CENTER_MARKER Center marker is what will appear in front of you when recentering. Place overlays around it! Description of the center marker on the moving your set tutorial page. "Overlay" was previously translated as "${DEFINITIONS.OVERLAY}".
272 WELCOME.DOUBLE_PRESS_TO_TOGGLE Double-press B (on Index) or Y (on Meta) to show, recenter or hide your set. Try it now. Instruction text on the working set tutorial page explaining the double-press gesture. "Set" was previously translated as "${DEFINITIONS.SET}".
273 WELCOME.FEATURES_DOCUMENTATION There are many other features worth customizing. For more information, check the documentation at Text on the final welcome page linking to documentation.
274 WELCOME.FEATURES_DOCUMENTATION WELCOME.FINISH_TUTORIAL There are many other features worth customizing. For more information, check the documentation at Finish tutorial Text on the final welcome page linking to documentation. Button text on the final welcome page to complete the tutorial.
275 WELCOME.FINISH_TUTORIAL WELCOME.GRAB_BOTH_HANDS Finish tutorial Grab it with both hands if you want to move a specific overlay in your set. Button text on the final welcome page to complete the tutorial. Instruction text on the moving your set tutorial page for two-hand grab.
276 WELCOME.GRAB_BOTH_HANDS WELCOME.GRAB_ONE_HAND Grab it with both hands if you want to move a specific overlay in your set. Grab it with one hand to move your set. Instruction text on the moving your set tutorial page for two-hand grab. Instruction text on the moving your set tutorial page for one-hand grab.
338 NO No Just a simple 'No' message, button in the dialog box
339
340
341
342
343
344
345
346
347
348
349
363
364
365
366
367
368
369
+41 -6
View File
@@ -95,6 +95,9 @@
},
"LEFT": "Left",
"RIGHT": "Right",
"CHORD": "Chord",
"CHORD_ADD_INPUT": "Add chord input",
"CHORD_INPUT_HAND": "Input hand",
"COMPONENT": "Actuation type",
"SUBPATH": "Actuating control",
"THRESHOLD": "Activate when above upper value\nDeactivate when below lower value"
@@ -136,6 +139,17 @@
"HANDSFREE_POINTER_HELP": "Input to use when motion\ncontrollers are unavailable.\nLeft pinch is grab, right is click.",
"HANDSFREE_ALT_TAB": "App switcher aim",
"HANDSFREE_ALT_TAB_HELP": "Hold Super+X, aim at the desired window, then release to switch focus.",
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "CPU-accessible VRAM: {NUM} MiB",
"TITLE": "Diagnostics",
"ENABLE_REBAR": "Enable Resizable BAR in the BIOS settings for optimal VR performance"
},
"DIAGNOSTICS_REASON": {
"PACTL": "Required for speaker/microphone control and audio card switching",
"CAGE": "Recommended in case if there's an incompatibility with some X11 applications (Compatibility mode)",
"XWAYLAND_SATELLITE": "Recommended in case if you want to run X11 (Xwayland) applications in native mode",
"XDG_OPEN": "Required for opening URLs or Steam games"
},
"HIDE_GRAB_HELP": "Hide grab help",
"HIDE_USERNAME": "Hide username",
"INPUT_EMULATION_METHOD": "Input emulation method",
@@ -146,6 +160,7 @@
"INPUT_PROFILES_HELP": "OpenXR controller input bindings",
"INVERT_SCROLL_DIRECTION_X": "Invert horizontal scroll direction",
"INVERT_SCROLL_DIRECTION_Y": "Invert vertical scroll direction",
"LENS_SEPARATION_MM": "Lens separation (mm)",
"KEYBOARD_MIDDLE_CLICK": "Keyboard middle click",
"KEYBOARD_MIDDLE_CLICK_HELP": "Modifier to use when typing\nwith purple laser",
"KEYBOARD_SOUND_ENABLED": "Keyboard sounds",
@@ -155,6 +170,8 @@
"LONG_PRESS_DURATION": "Long press duration",
"LOOK_AND_FEEL": "Look & Feel",
"MISC": "Miscellaneous",
"MIDDLE_GRABS_SINGLE": "Middle-click modifier grabs individual",
"MIDDLE_GRABS_SINGLE_HELP": "Grabbing with the middle-click modifier (purple laser)\nwill grab individual overlays, not the entire set",
"NOTIFICATIONS_ENABLED": "Enable notifications",
"NOTIFICATIONS_SOUND_ENABLED": "Notification sounds",
"NOT_SUPPORTED": "Not supported",
@@ -194,8 +211,8 @@
"SAVE_PLAYSPACE_CENTER_HELP": "Use current playspace for reset playspace binding.",
"RESET_PLAYSPACE_CENTER": "Reset playspace center",
"RESET_PLAYSPACE_CENTER_HELP": "Clear previously set playspace center.",
"RESTART_SOFTWARE": "Restart software",
"RESTART_SOFTWARE_HELP": "Apply settings that require a restart",
"RESTART_WAYVR": "Restart WayVR",
"CLOSE_WAYVR": "Close WayVR",
"ROUND_MULTIPLIER": "UI Edge roundness",
"SCREEN_RENDER_DOWN": "Render screen at lower resolution",
"SCREEN_RENDER_DOWN_HELP": "Helps with aliasing on high-res screens",
@@ -205,7 +222,6 @@
"SNAP_ANGLE_DEG_HELP": "Grabbed windows snap to this angle on pitch and roll axis.",
"ENABLE_WATCH": "Enable watch",
"SETS_ON_WATCH": "Sets on watch",
"SHOW_WELCOME_SCREEN": "Show welcome screen",
"SKYBOX": "Skymap",
"SKYMAP_ALREADY_DOWNLOADED": "This skymap is already downloaded. Select desired action.",
"SPACE_DRAG": "Playspace",
@@ -223,6 +239,9 @@
"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",
"ROTATIONS": "HMD rotations",
"SESSION_TIME": "Session time",
"STATISTICS": "Statistics",
"TROUBLESHOOTING": "Troubleshooting",
"UI_GRADIENT_INTENSITY": "UI Gradient intensity",
"UPRIGHT_SCREEN_FIX": "Upright screen fix",
@@ -239,6 +258,9 @@
},
"WHISPER_MODEL": "Speech-to-text model",
"WHISPER_MODEL_HELP": "Whisper model to use.\nLarger models produce more accurate\nresults, but consume more VRAM.",
"SPEECH_TO_TEXT": "Speech to text",
"WHISPER_GPU_SELECT": "Select GPU",
"TUTORIAL": "Tutorial",
"GRID_OPACITY": "Floor grid opacity",
"GRID_OPACITY_HELP": "Opacity of the floor grid when the skymap is enabled",
"XWAYLAND_BY_DEFAULT": "Run apps in Compatibility mode by default",
@@ -249,6 +271,7 @@
"APPLICATION_STARTED": "Application started",
"APPLICATIONS": "Applications",
"AUDIO": {
"SWITCH_TO_THIS_DEVICE": "Switch to this device",
"AUTO_SWITCH_TO_VR_AUDIO": "Auto-switch to VR audio",
"CARDS": "Cards",
"FAILED_TO_SWITCH_MICROPHONE": "Failed to switch microphone",
@@ -274,7 +297,7 @@
"CURRENT_SUPPORTERS": "Current Supporters",
"BROUGHT_TO_YOU_VARIANTS_OFTEN": "Supported by {USER}|Special thanks to {USER}|Sponsored by {USER}|Backed by {USER}|Driven by community members like {USER}|Made possible by {USER}|Sustained by {USER}|Contributed by {USER}|Funded by {USER}",
"BROUGHT_TO_YOU_VARIANTS_RARE": "Coffee provided by {USER}|Fuelled by {USER}|Shoutout to {USER}!|Keeping us going: {USER}|Helping us grow: {USER}|Keeping the servers running: {USER}|With gratitude to {USER}|Powered by {USER}|Supported by friends like {USER}",
"BROUGHT_TO_YOU_VARIANTS_VERY_RARE": "Supported by legends like {USER}|Caffeine supplied by {USER}|A true legend: {USER}|Our hero of the day: {USER}|An absolute superstar: {USER}|Paying for the electricity bill: {USER}|Leading the way: {USER}|Caffeine-to-code converter provided by {USER}|Keeping the production stable: {USER}|The one and only: {USER}|Passing dmabuf buffers: {USER}"
"BROUGHT_TO_YOU_VARIANTS_VERY_RARE": "Supported by legends like {USER}|Caffeine supplied by {USER}|A true legend: {USER}|Our hero of the day: {USER}|An absolute superstar: {USER}|Paying for the electricity bill: {USER}|The savior of our sanity: {USER}|Leading the way: {USER}|Caffeine-to-code converter provided by {USER}|Keeping the production stable: {USER}|The one and only: {USER}|Passing dmabuf buffers: {USER}"
},
"DOWNLOAD": "Download",
"DOWNLOADER": "Downloader",
@@ -325,6 +348,14 @@
"POPUP_ADD_DISPLAY": {
"RESOLUTION": "Resolution"
},
"POWER_OPTIONS": {
"TITLE": "Power options",
"SHUTDOWN": "Shut down",
"SUSPEND": "Suspend",
"NOT_SUPPORTED": "Power options require systemd or elogind.",
"SHUTDOWN_ARE_YOU_SURE": "Are you sure you want to turn off your computer?",
"SUSPEND_ARE_YOU_SURE": "Are you sure you want to put your computer to sleep?"
},
"PROCESS": {
"FORCE_KILL": "Force-kill",
"STOP": "Stop"
@@ -345,5 +376,9 @@
"ADD_TO_FAVOURITES": "Add to pinned apps",
"ADD_TO_FAVOURITES_HINT": "Save preset and pin it to the app drawer",
"REMOVE_FROM_FAVOURITES": "Remove from pinned apps",
"EMPTY": "Empty"
}
"EMPTY": "Empty",
"INSTALLED": "Installed",
"NOT_INSTALLED": "Not installed",
"YES": "Yes",
"NO": "No"
}
+43 -8
View File
@@ -97,7 +97,10 @@
"RIGHT": "Derecha",
"COMPONENT": "Tipo de accionamiento",
"SUBPATH": "Control a accionar",
"THRESHOLD": "Activar al superar el valor superior\nDesactivar al caer bajo el valor inferior"
"THRESHOLD": "Activar al superar el valor superior\nDesactivar al caer bajo el valor inferior",
"CHORD": "Acorde",
"CHORD_ADD_INPUT": "Añadir entrada al acorde",
"CHORD_INPUT_HAND": "Mano de entrada"
},
"BROWSE_ONLINE_CATALOG": "Explorar catálogo en línea...",
"BROWSE_SKYMAPS": "Explorar skymaps",
@@ -194,8 +197,6 @@
"SAVE_PLAYSPACE_CENTER_HELP": "Usa el espacio de juego actual para el comando de reiniciar espacio de juego.",
"RESET_PLAYSPACE_CENTER": "Reiniciar centro del espacio de juego",
"RESET_PLAYSPACE_CENTER_HELP": "Restablece el centro del espacio de juego definido previamente.",
"RESTART_SOFTWARE": "Reiniciar software",
"RESTART_SOFTWARE_HELP": "Aplicar ajustes que requieren reiniciar",
"ROUND_MULTIPLIER": "Redondeo de bordes de la UI",
"SCREEN_RENDER_DOWN": "Renderizar pantalla a resolución menor",
"SCREEN_RENDER_DOWN_HELP": "Ayuda con el aliasing en pantallas de alta resolución",
@@ -205,7 +206,6 @@
"SNAP_ANGLE_DEG_HELP": "Las ventanas agarradas se ajustan a este ángulo en los ejes de cabeceo y balanceo.",
"ENABLE_WATCH": "Habilitar reloj",
"SETS_ON_WATCH": "Sets en el reloj",
"SHOW_WELCOME_SCREEN": "Mostrar pantalla de bienvenida",
"SKYBOX": "Skymap",
"SKYMAP_ALREADY_DOWNLOADED": "Este skymap ya está descargado. Selecciona la acción deseada.",
"SPACE_DRAG": "Espacio de juego",
@@ -243,7 +243,29 @@
"GRID_OPACITY_HELP": "Opacidad de la rejilla del suelo cuando el skymap está activado",
"XWAYLAND_BY_DEFAULT": "Ejecutar apps en modo de compatibilidad por defecto",
"SAVE": "Guardar",
"CANCEL": "Cancelar"
"CANCEL": "Cancelar",
"STATISTICS": "Estadísticas",
"ROTATIONS": "Rotaciones del HMD",
"SESSION_TIME": "Tiempo de sesión",
"LENS_SEPARATION_MM": "Separación de lentes (mm)",
"MIDDLE_GRABS_SINGLE": "El modificador de clic central agarra objetos individuales",
"MIDDLE_GRABS_SINGLE_HELP": "Al agarrar con el modificador de clic central (láser púrpura),\nse agarrarán overlays individuales y no el set completo",
"DIAGNOSTICS_REASON": {
"PACTL": "Necesario para el control de altavoces/micrófono y el cambio de tarjeta de audio",
"CAGE": "Recomendado en caso de incompatibilidad con algunas aplicaciones X11 (Modo de compatibilidad)",
"XWAYLAND_SATELLITE": "Recomendado si quieres ejecutar aplicaciones X11 (Xwayland) en modo nativo",
"XDG_OPEN": "Necesario para abrir URLs o juegos de Steam"
},
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "VRAM accesible por CPU: {NUM} MiB",
"TITLE": "Diagnósticos",
"ENABLE_REBAR": "Activa [resizable bar] en la configuración de la BIOS para un rendimiento óptimo de VR"
},
"TUTORIAL": "Tutorial",
"RESTART_WAYVR": "Reiniciar WayVR",
"CLOSE_WAYVR": "Cerrar WayVR",
"SPEECH_TO_TEXT": "Dictado por voz",
"WHISPER_GPU_SELECT": "Seleccionar GPU"
},
"APPLICATION_LAUNCHER": "Lanzador de aplicaciones",
"APPLICATION_STARTED": "Aplicación iniciada",
@@ -260,7 +282,8 @@
"SETTINGS": "Ajustes de audio",
"SPEAKERS": "Altavoces",
"SPEAKERS_SET_SUCCESSFULLY": "Altavoces configurados correctamente",
"VOLUME": "Volumen"
"VOLUME": "Volumen",
"SWITCH_TO_THIS_DEVICE": "Cambiar a este dispositivo"
},
"CLOSE_WINDOW": "Cerrar ventana",
"CREATION_DATE": "Fecha de creación",
@@ -345,5 +368,17 @@
"ADD_TO_FAVOURITES": "Añadir a aplicaciones fijadas",
"ADD_TO_FAVOURITES_HINT": "Guardar ajuste y fijarlo al cajón de aplicaciones",
"REMOVE_FROM_FAVOURITES": "Quitar de aplicaciones fijadas",
"EMPTY": "Vacío"
}
"EMPTY": "Vacío",
"INSTALLED": "Instalado",
"NOT_INSTALLED": "No instalado",
"POWER_OPTIONS": {
"TITLE": "Opciones de energía",
"SHUTDOWN": "Apagar",
"SUSPEND": "Suspender",
"SHUTDOWN_ARE_YOU_SURE": "¿Seguro que quieres apagar el ordenador?",
"NOT_SUPPORTED": "Las opciones de energía requieren systemd o elogind.",
"SUSPEND_ARE_YOU_SURE": "¿Estás seguro de que quieres suspender el equipo?"
},
"YES": "Sí",
"NO": "No"
}
+43 -8
View File
@@ -97,7 +97,10 @@
"RIGHT": "Destro",
"COMPONENT": "Tipo di attuazione",
"SUBPATH": "Comando di attivazione",
"THRESHOLD": "Attiva sopra il valore superiore\nDisattiva sotto il valore inferiore"
"THRESHOLD": "Attiva sopra il valore superiore\nDisattiva sotto il valore inferiore",
"CHORD": "Combinazione",
"CHORD_ADD_INPUT": "Aggiungi input combinazione",
"CHORD_INPUT_HAND": "Mano di input"
},
"BROWSE_ONLINE_CATALOG": "Sfoglia catalogo online...",
"BROWSE_SKYMAPS": "Sfoglia skymap",
@@ -194,8 +197,6 @@
"SAVE_PLAYSPACE_CENTER_HELP": "Usa il playspace corrente per il comando di reset del playspace.",
"RESET_PLAYSPACE_CENTER": "Resetta centro playspace",
"RESET_PLAYSPACE_CENTER_HELP": "Rimuovi il centro del playspace impostato precedentemente.",
"RESTART_SOFTWARE": "Riavvia software",
"RESTART_SOFTWARE_HELP": "Applica le impostazioni che richiedono il riavvio",
"ROUND_MULTIPLIER": "Arrotondamento bordi UI",
"SCREEN_RENDER_DOWN": "Rendering schermo a risoluzione inferiore",
"SCREEN_RENDER_DOWN_HELP": "Riduce l'effetto aliasing sugli schermi ad alta risoluzione",
@@ -205,7 +206,6 @@
"SNAP_ANGLE_DEG_HELP": "Le finestre afferrate si allineano a questo angolo sugli assi di beccheggio e rollio.",
"ENABLE_WATCH": "Attiva orologio",
"SETS_ON_WATCH": "Set sull'orologio",
"SHOW_WELCOME_SCREEN": "Mostra schermata di benvenuto",
"SKYBOX": "Skymap",
"SKYMAP_ALREADY_DOWNLOADED": "Questo skymap è già stato scaricato. Seleziona l'azione desiderata.",
"SPACE_DRAG": "Playspace",
@@ -243,7 +243,29 @@
"GRID_OPACITY_HELP": "Opacità della griglia del pavimento quando lo skymap è attivo",
"XWAYLAND_BY_DEFAULT": "Avvia le app in modalità compatibilità per impostazione predefinita",
"SAVE": "Salva",
"CANCEL": "Annulla"
"CANCEL": "Annulla",
"STATISTICS": "Statistiche",
"ROTATIONS": "Rotazioni HMD",
"SESSION_TIME": "Tempo sessione",
"LENS_SEPARATION_MM": "Distanza lenti (mm)",
"MIDDLE_GRABS_SINGLE": "Il modificatore click centrale afferra singoli oggetti",
"MIDDLE_GRABS_SINGLE_HELP": "Afferrando con il modificatore click centrale (laser viola),\nsi afferrano i singoli overlay e non l'intero set",
"DIAGNOSTICS_REASON": {
"PACTL": "Necessario per il controllo di altoparlanti/microfono e il cambio della scheda audio",
"CAGE": "Consigliato in caso di incompatibilità con alcune applicazioni X11 (Modalità compatibilità)",
"XWAYLAND_SATELLITE": "Consigliato per eseguire applicazioni X11 (Xwayland) in modalità nativa",
"XDG_OPEN": "Necessario per aprire URL o giochi Steam"
},
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "VRAM accessibile dalla CPU: {NUM} MiB",
"TITLE": "Diagnostica",
"ENABLE_REBAR": "Abilita Resizable BAR nelle impostazioni del BIOS per prestazioni VR ottimali"
},
"TUTORIAL": "Tutorial",
"RESTART_WAYVR": "Riavvia WayVR",
"CLOSE_WAYVR": "Chiudi WayVR",
"SPEECH_TO_TEXT": "Speech-to-text",
"WHISPER_GPU_SELECT": "Seleziona GPU"
},
"APPLICATION_LAUNCHER": "Avvio applicazioni",
"APPLICATION_STARTED": "Applicazione avviata",
@@ -260,7 +282,8 @@
"SETTINGS": "Impostazioni audio",
"SPEAKERS": "Altoparlanti",
"SPEAKERS_SET_SUCCESSFULLY": "Altoparlanti impostati correttamente",
"VOLUME": "Volume"
"VOLUME": "Volume",
"SWITCH_TO_THIS_DEVICE": "Passa a questo dispositivo"
},
"CLOSE_WINDOW": "Chiudi finestra",
"CREATION_DATE": "Data di creazione",
@@ -345,5 +368,17 @@
"ADD_TO_FAVOURITES": "Aggiungi alle applicazioni fissate",
"ADD_TO_FAVOURITES_HINT": "Salva il preset e fissalo al cassetto delle app",
"REMOVE_FROM_FAVOURITES": "Rimuovi dalle app fissate",
"EMPTY": "Vuoto"
}
"EMPTY": "Vuoto",
"INSTALLED": "Installato",
"NOT_INSTALLED": "Non installato",
"POWER_OPTIONS": {
"TITLE": "Opzioni di alimentazione",
"SHUTDOWN": "Spegni",
"SUSPEND": "Sospendi",
"SHUTDOWN_ARE_YOU_SURE": "Sei sicuro di voler spegnere il computer?",
"NOT_SUPPORTED": "Le opzioni di alimentazione richiedono systemd o elogind.",
"SUSPEND_ARE_YOU_SURE": "Sei sicuro di voler mettere il computer in sospensione?"
},
"YES": "Sì",
"NO": "No"
}
+44 -9
View File
@@ -94,10 +94,13 @@
"SCROLL": "スクロール*"
},
"LEFT": "左手",
"RIGHT": "右",
"RIGHT": "右手",
"COMPONENT": "入力形式",
"SUBPATH": "操作ボタン",
"THRESHOLD": "上の値を超えると有効\n下の値を下回ると無効"
"THRESHOLD": "上の値を超えると有効\n下の値を下回ると無効",
"CHORD": "コード",
"CHORD_ADD_INPUT": "コード入力の追加",
"CHORD_INPUT_HAND": "入力側の手"
},
"BROWSE_ONLINE_CATALOG": "オンラインカタログを見る...",
"BROWSE_SKYMAPS": "スカイマップを選択",
@@ -194,8 +197,6 @@
"SAVE_PLAYSPACE_CENTER_HELP": "現在のプレイスペースを、プレイスペースリセットのバインディングに使用する。",
"RESET_PLAYSPACE_CENTER": "プレイスペースの中心をリセット",
"RESET_PLAYSPACE_CENTER_HELP": "設定済みのプレイスペースの中心点をリセットする。",
"RESTART_SOFTWARE": "ソフトウェアを再起動",
"RESTART_SOFTWARE_HELP": "再起動が必要な設定を適用する",
"ROUND_MULTIPLIER": "UIの角の丸み",
"SCREEN_RENDER_DOWN": "低解像度で画面をレンダリング",
"SCREEN_RENDER_DOWN_HELP": "高解像度ディスプレイでのジャギーを軽減する",
@@ -205,7 +206,6 @@
"SNAP_ANGLE_DEG_HELP": "掴んでいるウィンドウが、ピッチ軸とロール軸でこの角度にスナップします。",
"ENABLE_WATCH": "ウォッチを有効にする",
"SETS_ON_WATCH": "ウォッチにセットを表示",
"SHOW_WELCOME_SCREEN": "ウェルカムスクリーンを表示",
"SKYBOX": "スカイマップ",
"SKYMAP_ALREADY_DOWNLOADED": "このスカイマップはすでにダウンロード済みです。操作を選択してください。",
"SPACE_DRAG": "プレイスペース",
@@ -243,7 +243,29 @@
"GRID_OPACITY_HELP": "スカイマップ有効時のフロアグリッドの不透明度",
"XWAYLAND_BY_DEFAULT": "デフォルトで互換モードでアプリを起動",
"SAVE": "保存",
"CANCEL": "キャンセル"
"CANCEL": "キャンセル",
"STATISTICS": "統計",
"ROTATIONS": "HMD回転数",
"SESSION_TIME": "セッション時間",
"LENS_SEPARATION_MM": "レンズ間隔 (mm)",
"MIDDLE_GRABS_SINGLE": "中クリック修飾キーで個別に掴む",
"MIDDLE_GRABS_SINGLE_HELP": "中クリック修飾キー(紫色のレーザー)で掴むと、\nセット全体ではなく個別のオーバーレイを掴むことができる",
"DIAGNOSTICS_REASON": {
"PACTL": "スピーカー・マイクの制御およびオーディオカードの切り替えに必要",
"CAGE": "一部のX11アプリで互換性問題が発生する場合に推奨(互換モード)",
"XWAYLAND_SATELLITE": "X11 (Xwayland) アプリケーションをネイティブモードで動作させたい場合に推奨",
"XDG_OPEN": "URLやSteamゲームの起動に必要"
},
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "CPUアクセス可能VRAM: {NUM} MiB",
"TITLE": "診断",
"ENABLE_REBAR": "VRパフォーマンスを最適化するため、BIOS設定でresizable BARを有効にして下さい"
},
"TUTORIAL": "チュートリアル",
"RESTART_WAYVR": "WayVRを再起動",
"CLOSE_WAYVR": "WayVRを閉じる",
"SPEECH_TO_TEXT": "音声入力",
"WHISPER_GPU_SELECT": "GPUを選択"
},
"APPLICATION_LAUNCHER": "アプリランチャー",
"APPLICATION_STARTED": "アプリが起動しました",
@@ -260,7 +282,8 @@
"SETTINGS": "オーディオ設定",
"SPEAKERS": "スピーカー",
"SPEAKERS_SET_SUCCESSFULLY": "スピーカーを設定完了",
"VOLUME": "音量"
"VOLUME": "音量",
"SWITCH_TO_THIS_DEVICE": "このデバイスに切り替え"
},
"CLOSE_WINDOW": "ウィンドウを閉じる",
"CREATION_DATE": "作成日",
@@ -345,5 +368,17 @@
"ADD_TO_FAVOURITES": "固定済みアプリに追加",
"ADD_TO_FAVOURITES_HINT": "プリセットを保存し、アプリドロワーに固定する",
"REMOVE_FROM_FAVOURITES": "固定済みアプリから外す",
"EMPTY": "なし"
}
"EMPTY": "なし",
"INSTALLED": "インストール済み",
"NOT_INSTALLED": "未インストール",
"POWER_OPTIONS": {
"TITLE": "電源オプション",
"SHUTDOWN": "シャットダウン",
"SUSPEND": "サスペンド",
"SHUTDOWN_ARE_YOU_SURE": "コンピューターをシャットダウンしてもよろしいですか?",
"NOT_SUPPORTED": "電源オプションには systemd または elogind が必要です。",
"SUSPEND_ARE_YOU_SURE": "コンピューターをスリープ状態にしますか?"
},
"YES": "はい",
"NO": "いいえ"
}
+43 -8
View File
@@ -97,7 +97,10 @@
"RIGHT": "Prawy",
"COMPONENT": "Typ aktywacji",
"SUBPATH": "Aktywujący sterownik",
"THRESHOLD": "Aktywuj powyżej górnej wartości\nDeaktywuj poniżej dolnej wartości"
"THRESHOLD": "Aktywuj powyżej górnej wartości\nDeaktywuj poniżej dolnej wartości",
"CHORD": "Akord",
"CHORD_ADD_INPUT": "Dodaj wejście do akordu",
"CHORD_INPUT_HAND": "Ręka sterująca"
},
"BROWSE_ONLINE_CATALOG": "Przeglądaj katalog online...",
"BROWSE_SKYMAPS": "Przeglądaj skymapy",
@@ -194,8 +197,6 @@
"SAVE_PLAYSPACE_CENTER_HELP": "Użyj aktualnej przestrzeni gry dla przypisania resetowania przestrzeni.",
"RESET_PLAYSPACE_CENTER": "Zresetuj centrum przestrzeni gry",
"RESET_PLAYSPACE_CENTER_HELP": "Resetuj aktualny środek przestrzeni gry.",
"RESTART_SOFTWARE": "Uruchom ponownie program",
"RESTART_SOFTWARE_HELP": "Zastosuj ustawienia wymagające restartu",
"ROUND_MULTIPLIER": "Zaokrąglenie krawędzi UI",
"SCREEN_RENDER_DOWN": "Renderuj ekran w niższej rozdzielczości",
"SCREEN_RENDER_DOWN_HELP": "Pomaga zredukować aliasing na ekranach o wysokiej rozdzielczości",
@@ -205,7 +206,6 @@
"SNAP_ANGLE_DEG_HELP": "Chwycone okna przyciągają się do tego kąta na osi pochylenia i obrotu.",
"ENABLE_WATCH": "Włącz zegarek",
"SETS_ON_WATCH": "Zestawy na zegarku",
"SHOW_WELCOME_SCREEN": "Pokaż ekran powitalny",
"SKYBOX": "Skymap",
"SKYMAP_ALREADY_DOWNLOADED": "Ta skymapa jest już pobrana. Wybierz żądaną akcję.",
"SPACE_DRAG": "Przestrzeń gry",
@@ -243,7 +243,29 @@
"GRID_OPACITY_HELP": "Przezroczystość siatki podłogi przy włączonym Skymapie",
"XWAYLAND_BY_DEFAULT": "Uruchamiaj aplikacje domyślnie w trybie kompatybilności",
"SAVE": "Zapisz",
"CANCEL": "Anuluj"
"CANCEL": "Anuluj",
"STATISTICS": "Statystyki",
"ROTATIONS": "Obroty HMD",
"SESSION_TIME": "Czas sesji",
"LENS_SEPARATION_MM": "Rozstaw soczewek (mm)",
"MIDDLE_GRABS_SINGLE": "Modyfikator środkowego przycisku chwyta pojedyncze obiekty",
"MIDDLE_GRABS_SINGLE_HELP": "Chwytanie z modyfikatorem środkowego przycisku myszy (fioletowy laser)\npochwyci pojedyncze nakładki, a nie cały zestaw",
"DIAGNOSTICS_REASON": {
"PACTL": "Wymagane do sterowania głośnikami/mikrofonem i przełączania kart dźwiękowych",
"CAGE": "Zalecane w przypadku niekompatybilności z niektórymi aplikacjami X11 (tryb kompatybilności)",
"XWAYLAND_SATELLITE": "Zalecane, jeśli chcesz uruchamiać aplikacje X11 (Xwayland) w trybie natywnym",
"XDG_OPEN": "Wymagane do otwierania linków URL lub gier Steam"
},
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "VRAM dostępny dla CPU: {NUM} MiB",
"TITLE": "Diagnostyka",
"ENABLE_REBAR": "Włącz resizable BAR w ustawieniach BIOS, aby uzyskać optymalną wydajność VR"
},
"TUTORIAL": "Samouczek",
"RESTART_WAYVR": "Zrestartuj WayVR",
"CLOSE_WAYVR": "Zamknij WayVR",
"SPEECH_TO_TEXT": "Zamiana mowy na tekst",
"WHISPER_GPU_SELECT": "Wybierz GPU"
},
"APPLICATION_LAUNCHER": "Launcher aplikacji",
"APPLICATION_STARTED": "Uruchomiono aplikację",
@@ -260,7 +282,8 @@
"SETTINGS": "Ustawienia dźwięku",
"SPEAKERS": "Głośniki",
"SPEAKERS_SET_SUCCESSFULLY": "Głośniki ustawione pomyślnie",
"VOLUME": "Głośność"
"VOLUME": "Głośność",
"SWITCH_TO_THIS_DEVICE": "Przełącz na to urządzenie"
},
"CLOSE_WINDOW": "Zamknij okno",
"CREATION_DATE": "Data utworzenia",
@@ -345,5 +368,17 @@
"ADD_TO_FAVOURITES": "Przypnij aplikację",
"ADD_TO_FAVOURITES_HINT": "Zapisz preset i przypnij go do szuflady aplikacji",
"REMOVE_FROM_FAVOURITES": "Usuń z przypiętych aplikacji",
"EMPTY": "Puste"
}
"EMPTY": "Puste",
"INSTALLED": "Zainstalowano",
"NOT_INSTALLED": "Nie zainstalowano",
"POWER_OPTIONS": {
"TITLE": "Opcje zasilania",
"SHUTDOWN": "Wyłącz",
"SUSPEND": "Uśpij",
"SHUTDOWN_ARE_YOU_SURE": "Czy na pewno chcesz wyłączyć komputer?",
"NOT_SUPPORTED": "Opcje zasilania wymagają systemd lub elogind.",
"SUSPEND_ARE_YOU_SURE": "Czy na pewno chcesz uśpić komputer?"
},
"YES": "Tak",
"NO": "Nie"
}
+384
View File
@@ -0,0 +1,384 @@
{
"DEFINITIONS": {
"ANCHORED": "Förankrad",
"FLOATING": "Flytande",
"STATIC": "Stationär",
"SET": "Set",
"WATCH": "Klocka",
"DASHBOARD": "Kontrollpanel",
"EDIT_MODE": "Redigeringsläge",
"SETTINGS": "Inställningar",
"KEYBOARD": "Tangentbord",
"TASKBAR": "Uppgiftsfält",
"FEATURES": "Funktioner",
"OVERLAY": "Overlay",
"SKYMAP": "Skymap",
"PLAYSPACE": "Playspace",
"D_PAD": "D-pad"
},
"ACTIONS": {
"RECENTER_PLAYSPACE": "Centrera om playspace"
},
"APP_LAUNCHER": {
"ASPECT": {
"SEMI_TALL": "Halvhög",
"SEMI_WIDE": "Halvbredd",
"SQUARE": "Kvadratisk",
"TALL": "Hög",
"WIDE": "Bredbild"
},
"ASPECT_TITLE": "Bildförhållande",
"AUTOSTART": "Kör automatiskt vid start",
"LAUNCH": "Starta",
"MODE": {
"CAGE": "Kompatibilitetsläge (Cage)",
"NATIVE": "Nativt läge"
},
"RES_TITLE": "Upplösning"
},
"APP_SETTINGS": {
"ALLOW_SLIDING": "Stick-interaktion vid grepp",
"ANIMATION_SPEED": "Hastighet för UI-animationer",
"AUTOSTART_APPS": "Appar som ska köras vid start",
"BLOCK_GAME_INPUT": "Blockera spelindata",
"BLOCK_GAME_INPUT_HELP": "Blockerar all input när en overlay hovras över",
"BLOCK_GAME_INPUT_IGNORE_WATCH": "Ignorera klockan vid blockering av input",
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "Blockera inte inmatning när klockan är markerad",
"BLOCK_POSES_ON_KBD_INTERACTION": "Blockera poser vid interaktion med tangentbord",
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blockerar spelets mottagning av poser när tangentbordet hovras över och 'Blockera spel-input' är aktiverat",
"BINDINGS": {
"COMP": {
"CLICK": "Klick",
"FORCE": "Tryckkraft",
"TOUCH": "Beröring",
"VALUE": "Värde",
"PROXIMITY": "Närhet",
"X_AXIS": "X-axel",
"Y_AXIS": "Y-axel"
},
"TYPE": {
"BUMPER": "Bumper",
"DPAD_UP": "D-pad upp",
"DPAD_DOWN": "D-pad ned",
"DPAD_LEFT": "D-pad vänster",
"DPAD_RIGHT": "D-pad höger",
"JOYSTICK": "Joystick",
"MENU": "Meny",
"SHOULDER": "Axel",
"SQUEEZE": "Grepp",
"SYSTEM": "System",
"THUMBREST": "Tumstöd",
"THUMBSTICK": "Thumbstick",
"TRACKPAD": "Trackpad",
"TRIGGER": "Trigger",
"VIEW": "Visa"
},
"CLICK": {
"ANY": "Vilken som helst",
"DOUBLE": "Dubbelklicka",
"TRIPLE": "Trippelklick",
"TYPE": "Antal tryck"
},
"ACTION": {
"CLICK": "Klicka*",
"GRAB": "Greppa*",
"ALT_CLICK": "Anpassat shell-kommando (ställ in alt_click i config)",
"SHOW_HIDE": "Visa, dölj, centrera om*",
"TOGGLE_DASHBOARD": "Växla instrumentpanel",
"SPACE_DRAG": "Dra playspace",
"SPACE_ROTATE": "Rotera playspace",
"SPACE_RESET": "Återställ Playspace",
"CLICK_MODIFIER_RIGHT": "Högerklick-modifierare",
"CLICK_MODIFIER_MIDDLE": "Modifierare för mittklick",
"MOVE_MOUSE": "Flytta mus (om avstängd som standard)",
"SCROLL": "Scrolla*"
},
"LEFT": "Vänster",
"RIGHT": "Höger",
"CHORD": "Kombination",
"CHORD_ADD_INPUT": "Lägg till inmatning för kombination",
"CHORD_INPUT_HAND": "Inmatningshand",
"COMPONENT": "Aktiveringstyp",
"SUBPATH": "Aktiverande kontroll",
"THRESHOLD": "Aktivera vid övre värdet\nAvaktivera vid nedre värdet"
},
"BROWSE_ONLINE_CATALOG": "Bläddra i onlinekatalogen...",
"BROWSE_SKYMAPS": "Bläddra bland skymaps",
"CAPTURE_METHOD": "Metod för skärmavbildning",
"CAPTURE_METHOD_HELP": "Prova att ändra detta om du\nupplever svarta eller glitchiga skärmar",
"COLOR_KEYING": "Färgnyckelning",
"COLOR_PALETTE": "Färgpalett",
"COLOR_PALETTE_HELP": "Klicka för att bläddra bland färgpaletter.\nSe webbplatsen för att skapa egna!",
"COLOR_PALETTES": "Färgpaletter",
"COLOR_PALETTE_CURRENT": "Nuvarande aktivt tema.",
"COLOR_PALETTE_CUSTOM_URL": "Lägg till ett eget anpassat tema!",
"COLOR_PALETTE_CUSTOM_URL2": "Klicka för att öppna webbmanualen.",
"COLOR_PALETTE_ACTIVATE": "Klicka för att använda detta tema.",
"CLEAR_PIPEWIRE_TOKENS": "Rensa PipeWire-tokens",
"CLEAR_PIPEWIRE_TOKENS_HELP": "Fråga om skärmval vid nästa start",
"CLEAR_SAVED_STATE": "Återställ sparade inställningar",
"CLEAR_SAVED_STATE_HELP": "Återställ sets och overlay-positioner",
"CLICK_FREEZE_TIME_MS": "Klickfrysningstid (ms)",
"CLICK_FREEZE_TIME_MS_HELP": "Hjälper till med precision vid dubbelklick",
"CLOCK_12H": "12-timmarsklocka",
"CONTROLS": "Kontroller",
"DELETE_ALL_CONFIGS": "Rensa konfiguration",
"DELETE_ALL_CONFIGS_HELP": "Ta bort alla konfigurationsfiler från conf.d",
"DOUBLE_CURSOR_FIX": "Fix för dubbla markörer",
"DOUBLE_CURSOR_FIX_HELP": "Aktivera om du ser två markörer",
"DEFAULT_OVERLAY_SCALE": "Standardstorlek för overlay",
"DEFAULT_OVERLAY_SCALE_HELP": "Skapa nya overlays i den här skalan.",
"DEFAULT_CURVATURE": "Standardkurvatur för overlay",
"DEFAULT_OPACITY": "Standardopacitet för overlay",
"DEFAULT_POSITIONING": "Standardposition för overlay",
"OVERLAY_DEFAULTS_HELP": "Gäller endast nya overlays",
"ENABLED": "Aktiverad",
"FEATURES": "Funktioner",
"FOCUS_FOLLOWS_MOUSE_MODE": "Musrörelse vid trigger-tryck",
"HANDSFREE_POINTER": "Handsfree-läge",
"HANDSFREE_POINTER_HELP": "Inmatning som används när rörelsekontroller saknas.\nVänster nyp är greppa, höger är klicka.",
"HANDSFREE_ALT_TAB": "Sikte för app-växlare",
"HANDSFREE_ALT_TAB_HELP": "Håll in Super+X, sikta på önskat fönster och släpp sedan för att byta fokus.",
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "CPU-tillgängligt VRAM: {NUM} MiB",
"TITLE": "Diagnostik",
"ENABLE_REBAR": "Aktivera [resizable bar] i BIOS-inställningarna för optimal VR-prestanda"
},
"DIAGNOSTICS_REASON": {
"PACTL": "Krävs för kontroll av högtalare/mikrofon och byte av ljudkort",
"CAGE": "Rekommenderas vid inkompatibilitet med vissa X11-applikationer (kompatibilitetsläge)",
"XWAYLAND_SATELLITE": "Rekommenderas om du vill köra X11 (Xwayland)-applikationer i nativt läge",
"XDG_OPEN": "Krävs för att öppna URL:er eller Steam-spel"
},
"HIDE_GRAB_HELP": "Dölj grepphjälp",
"HIDE_USERNAME": "Dölj användarnamn",
"INPUT_EMULATION_METHOD": "Metod för inmatningssimulering",
"INPUT_EMULATION_METHOD_HELP": "Prova att ändra detta om mus- eller\ntangentbordindata inte registreras.",
"INPUT_CAPTURE_METHOD": "Metod för inmatningsfångst",
"INPUT_CAPTURE_METHOD_HELP": "Möjliggör användning av fysisk kringutrustning i WayVR.\n Super+Z: Växla input mellan WayVR och skrivbordet\n Super+X: Växla mellan WayVR-appar",
"INPUT_PROFILES": "Ändra styrinställningar",
"INPUT_PROFILES_HELP": "OpenXR-kontrollbindningar",
"INVERT_SCROLL_DIRECTION_X": "Invertera horisontell scrollriktning",
"INVERT_SCROLL_DIRECTION_Y": "Invertera vertikal rullningsriktning",
"LENS_SEPARATION_MM": "Linsavstånd (mm)",
"KEYBOARD_MIDDLE_CLICK": "Tangentbordets mittklick",
"KEYBOARD_MIDDLE_CLICK_HELP": "Modifier som används vid skrivning\nmed lila laser",
"KEYBOARD_SOUND_ENABLED": "Tangentbordsljud",
"LANGUAGE": "Språk",
"LEFT_HANDED_MOUSE": "Vänstermus",
"LEFT_HANDED_MOUSE_HELP": "Används om musknapparna är ombytta",
"LONG_PRESS_DURATION": "Långtryckstid",
"LOOK_AND_FEEL": "Utseende och känsla",
"MISC": "Övrigt",
"MIDDLE_GRABS_SINGLE": "Modifierare för mittklick greppar enskilda objekt",
"MIDDLE_GRABS_SINGLE_HELP": "Att greppa med modifieraren för mittklick (lila laser)\ngreppar enskilda overlays istället för hela setet",
"NOTIFICATIONS_ENABLED": "Aktivera aviseringar",
"NOTIFICATIONS_SOUND_ENABLED": "Ljud för aviseringar",
"NOT_SUPPORTED": "Ej stöds",
"NO_SKYMAPS_FOUND": "Inga skymaps hittades",
"OPAQUE_BACKGROUND": "Opak bakgrund",
"OPTION": {
"ANCHORED_HELP": "Följer centermarkören. Rekommenderas.",
"FLOATING_HELP": "Flyttas oberoende, centreras om.\nLätt att tappa bort; rekommenderas ej.",
"STATIC_HELP": "Håller sig på plats i förhållande till världen.",
"AUTO": "Automatisk",
"AUTO_HELP": "ScreenCopy GPU om det stöds,\nannars PipeWire GPU.",
"EYE_ONLY": "Ögonlaser",
"EYE_PINCH": "Öga + pinch",
"HMD_ONLY": "HMD-laser",
"HMD_PINCH": "HMD + pinch",
"NONE": "Ingen",
"NONE_INPUT_HELP": "Emulera inte mus och tangentbord.\nInteraktion med skärmar blir inte möjlig.",
"NONE_INPUT_CAPTURE_HELP": "Fånga inte mus och tangentbord.\nDu kommer inte att kunna använda fysisk mus\neller tangentbord i appar som startas i WayVR.",
"PIPEWIRE_HELP": "Snabb GPU-avbildning,\nstandard för alla skrivbord.",
"PW_FALLBACK_HELP": "Långsam metod med hög CPU-belastning.\nProva om PipeWire GPU inte fungerar",
"SCREENCOPY_GPU_HELP": "Snabb, inga popup-fönster för skärmdelning.\nFungerar på: Hyprland, Niri, River, Sway",
"SCREENCOPY_HELP": "Långsam, inga popup-fönster för skärmdelning.\nFungerar på: Hyprland, Niri, River, Sway",
"UINPUT": "Enhetsemulering",
"UINPUT_HELP": "Använder modulen uinput för att emulera en enhet.\nFungerar generellt bra på de flesta skrivbord.",
"EVDEV_HELP": "Ta kontroll över inmatningsenheter för exklusiv användning.\nAnvändaren måste tillhöra gruppen 'input'.",
"WL_VIRTUAL": "Wayland virtuell inmatning",
"WL_VIRTUAL_HELP": "Skickar händelser till Wayland-kompositorn via\nzwlr_virtual_pointer och zwp_virtual_keyboard.\nFungerar endast på vissa skrivbord.\nFungerar INTE på KDE, GNOME eller COSMIC."
},
"POINTER_ACCELERATION": "Musacceleration",
"POINTER_ACCELERATION_HELP": "På: Adaptiv musacceleration\nAv: Konstant hastighet",
"POINTER_LERP_FACTOR": "Utjämning av pekare",
"POINTER_SPEED": "Mushastighet",
"REQUIRES_RESTART": "Kräver omstart",
"RESET_PLAYSPACE": "Återställ playspace",
"RESET_PLAYSPACE_HELP": "Nollställ offset för playspace.",
"SAVE_PLAYSPACE_CENTER": "Spara playspace-center",
"SAVE_PLAYSPACE_CENTER_HELP": "Använd nuvarande playspace för bindningen \"återställ playspace\".",
"RESET_PLAYSPACE_CENTER": "Återställ playspace-center",
"RESET_PLAYSPACE_CENTER_HELP": "Rensa tidigare inställd mittpunkt för playspace.",
"RESTART_WAYVR": "Starta om WayVR",
"CLOSE_WAYVR": "Stäng WayVR",
"ROUND_MULTIPLIER": "UI-kanternas rundning",
"SCREEN_RENDER_DOWN": "Rendera skärm i lägre upplösning",
"SCREEN_RENDER_DOWN_HELP": "Hjälper mot aliasing på skärmar med hög upplösning",
"SCROLL_SPEED": "Scrollningshastighet",
"SELECT_VARIANT": "Välj variant",
"SNAP_ANGLE_DEG": "Snapvinkel för fönster (pitch & roll)",
"SNAP_ANGLE_DEG_HELP": "Greppade fönster snäpps till denna vinkel på pitch- och rollaxeln.",
"ENABLE_WATCH": "Aktivera klockan",
"SETS_ON_WATCH": "Set på klockan",
"SKYBOX": "Skymap",
"SKYMAP_ALREADY_DOWNLOADED": "Denna skymap är redan nedladdad. Välj åtgärd.",
"SPACE_DRAG": "Playspace",
"SPACE_DRAG_MULTIPLIER": "Multiplikator för space-drag",
"SPACE_DRAG_AFFECTS_WORLD": "Lämna overlays kvar vid flytt av playspace",
"SPACE_DRAG_UNLOCKED": "Tillåt space-drag på alla axlar",
"SPACE_GRAVITY_DAMPING": "Dämpning",
"SPACE_GRAVITY_DAMPING_HELP": "Artificiell dämpning för att sakta ner rörelser. 0,1 – hög dämpning, 1,0 – ingen dämpning",
"SPACE_GRAVITY_FLING_STRENGTH": "Kaststyrka",
"SPACE_GRAVITY_FLING_STRENGTH_HELP": "Intensitetsmultiplikator för gravitationskraften efter space-drag.\n0.0 - ingen rörelse alls, 2.0 - dubbel intensitet",
"SPACE_GRAVITY_GRAVITY": "Gravitation",
"SPACE_GRAVITY_GRAVITY_HELP": "Mängd nedåtgående kraft. 0.0 - ingen gravitation",
"SPACE_GRAVITY_GROUND_FRICTION": "Markfriktion",
"SPACE_GRAVITY_GROUND_FRICTION_HELP": "Mängden friktion som saktar ner dig när du rör vid marken.\n0.0 - ingen friktion (som på is), 1.0 - sträv yta",
"SPACE_GRAVITY_FLOOR_HEIGHT": "Golvhöjd",
"SPACE_GRAVITY_FLOOR_HEIGHT_HELP": "Y-positionen för golvet. Gravitationen upphör när denna höjd nås.",
"SPACE_ROTATE_UNLOCKED": "Tillåt rotation av playspace på alla axlar",
"ROTATIONS": "HMD-rotationer",
"SESSION_TIME": "Sessionstid",
"STATISTICS": "Statistik",
"TROUBLESHOOTING": "Felsökning",
"UI_GRADIENT_INTENSITY": "Intensitet för UI-gradient",
"UPRIGHT_SCREEN_FIX": "Fix för upprätt skärm",
"UPRIGHT_SCREEN_FIX_HELP": "Fixar upprätt ställda skärmar på vissa skrivbord",
"USE_PASSTHROUGH": "Aktivera passthrough",
"USE_PASSTHROUGH_HELP": "Tillåt passthrough om XR-runtime stöder det",
"USE_SKYBOX": "Visa skymap",
"USE_SKYBOX_HELP": "Visa en skymap om ingen scenapp eller passthrough används",
"WATCH_VIEW_ANGLE": "Klockans synvinklar",
"WATCH_VIEW_ANGLE_HELP": "Styr hur klockan tonas ut",
"WHISPER": {
"NEED_TO_DOWNLOAD_MODEL": "Den valda modellen måste laddas ner.\nVill du ladda ner den nu?",
"REMOVE_UNUSED_MODELS": "Du stänger av tal-till-text-funktionen.\nVill du ta bort nedladdade Whisper-modeller för att frigöra utrymme?"
},
"WHISPER_MODEL": "Tal-till-text-modell",
"WHISPER_MODEL_HELP": "Whisper-modell som ska användas.\nStörre modeller ger mer precisa\nresultat, men förbrukar mer VRAM.",
"SPEECH_TO_TEXT": "Tal till text",
"WHISPER_GPU_SELECT": "Välj GPU",
"TUTORIAL": "Handbok",
"GRID_OPACITY": "Golvgridens opacitet",
"GRID_OPACITY_HELP": "Opacitet för golvgridet när skymap är aktiverat",
"XWAYLAND_BY_DEFAULT": "Kör appar i kompatibilitetsläge som standard",
"SAVE": "Spara",
"CANCEL": "Avbryt"
},
"APPLICATION_LAUNCHER": "App-startare",
"APPLICATION_STARTED": "Applikationen startades",
"APPLICATIONS": "Applikationer",
"AUDIO": {
"SWITCH_TO_THIS_DEVICE": "Byt till den här enheten",
"AUTO_SWITCH_TO_VR_AUDIO": "Byt automatiskt till VR-ljud",
"CARDS": "Kort",
"FAILED_TO_SWITCH_MICROPHONE": "Kunde inte byta mikrofon",
"MICROPHONE_SET_SUCCESSFULLY": "Mikrofonen har ändrats",
"MICROPHONES": "Mikrofoner",
"NO_VR_MICROPHONE_SWITCH_MANUALLY": "Ingen VR-mikrofon hittades. Byt manuellt.",
"NO_VR_SPEAKERS_FOUND_SWITCH_MANUALLY": "Inga VR-högtalare hittades. Byt manuellt.",
"SELECT_AUDIO_CARD_PROFILE": "Välj ljudkortsprofil",
"SETTINGS": "Ljudinställningar",
"SPEAKERS": "Högtalare",
"SPEAKERS_SET_SUCCESSFULLY": "Högtalarna har ändrats",
"VOLUME": "Volym"
},
"CLOSE_WINDOW": "Stäng fönster",
"CREATION_DATE": "Skapad datum",
"DEBUG_INFO": "Debuginfo",
"DISPLAY_BRIGHTNESS": "Skärmljusstyrka",
"DONATE": {
"SUPPORT_US": "Stöd oss",
"DESCRIPTION": "Vi är ett litet team på två utvecklare som bygger WayVR på vår fritid. Om du gillar att använda programvaran, överväg att stötta oss – varje donation hjälper oss att fortsätta.",
"THANK_YOU_WAYVR": "Tack från WayVR-teamet!",
"BUTTON_TOOLTIP": "Donera via Open Collective",
"CURRENT_SUPPORTERS": "Nuvarande supportrar",
"BROUGHT_TO_YOU_VARIANTS_OFTEN": "Stöds av {USER}|Särskilt tack till {USER}|Sponsras av {USER}|Backas av {USER}|Drivs av community-medlemmar som {USER}|Möjliggjorts av {USER}|Upprätthålls av {USER}|Bidrag från {USER}|Finansierat av {USER}",
"BROUGHT_TO_YOU_VARIANTS_RARE": "Kaffe sponsrat av {USER}|Drivs av {USER}|Hälsningar till {USER}!|Håller oss igång: {USER}|Hjälper oss att växa: {USER}|Håller servrarna igång: {USER}|Med tacksamhet till {USER}|Drivs av {USER}|Stöds av vänner som {USER}",
"BROUGHT_TO_YOU_VARIANTS_VERY_RARE": "Stöttas av legender som {USER}|Koffein sponsrat av {USER}|En sann legend: {USER}|Dagens hjälte: {USER}|En total superstjärna: {USER}|Betalar elräkningen: {USER}|Räddaren av vårt förstånd: {USER}|Visar vägen: {USER}|Koffein-till-kod-omvandlare tillhandahållen av {USER}|Håller produktionen stabil: {USER}|Den ende och ende: {USER}|Skickar dmabuf-buffertar: {USER}"
},
"DOWNLOAD": "Ladda ner",
"DOWNLOADER": "Nedladdare",
"WELCOME": {
"ALL_SET": "Nu är du redo!",
"BASICS": "Dessa grunder gör att du enkelt kan börja använda WayVR.",
"CENTER_MARKER": "Centreringsmarkören visas framför dig vid omcentrering. Placera overlays runt den!",
"DOUBLE_PRESS_TO_TOGGLE": "Dubbeltryck B (på Index) eller Y (på Meta) för att visa, centrera om eller dölja ditt set. Prova nu.",
"FEATURES_DOCUMENTATION": "Det finns många andra funktioner värda att anpassa. För mer information, se dokumentationen på",
"FINISH_TUTORIAL": "Avsluta handledningen",
"GRAB_BOTH_HANDS": "Greppa med båda händerna om du vill flytta ett specifikt overlay i ditt set.",
"GRAB_ONE_HAND": "Greppa med en hand för att flytta ditt set.",
"GREETING": "Hej!",
"GUIDE_INTRO": "Låt oss guida dig genom dina första steg.",
"LASER_COLORS": "Laserfärger",
"LASER_FUNCTIONALITY": "Mycket av funktionaliteten i WayVR beror på vilken laserfärg som används för att interagera med ett UI-element. Du behöver inte trycka på knapparna, det räcker att röra vid dem!",
"LAST_PAGE_INFO": "Denna handledning slutar visas när du når den sista sidan.",
"LOOK_AT_LEFT_WRIST": "Titta på din vänstra handled. Det är din klocka.",
"MIDDLE_CLICK_MODE_PURPLE_LASER": "Mittenklick-läge: Lila laser",
"MOVING_YOUR_SET": "Flytta ditt set",
"NEXT_BUTTON": "Tryck på nästa-knappen nedan för att komma igång.",
"REGULAR_MODE_BLUE_LASER": "Vanligt läge: Blå laser",
"REPOSITION_THIS_WINDOW_BY_GRABBING": "Flytta det här fönstret med kontrollens grip-funktion.",
"RIGHT_CLICK_MODE_ORANGE_LASER": "Högerklicksläge: Orange laser",
"THANKS_FOR_INSTALLING": "Tack för att du installerade WayVR!",
"WATCH": "Klocka",
"WORKING_SET": "Aktivt Set"
},
"DOWNLOAD_AGAIN": "Ladda ner igen",
"DOWNLOADING_FILE": "Laddar ner fil...",
"FAILED_TO_LAUNCH_APPLICATION": "Kunde inte starta applikationen:",
"GAME_LAUNCHED": "Spelet har startats",
"GAME_LIST": {
"NO_GAMES_FOUND": "Inga spel hittades",
"RUNNING_GAMES_LIST": "Lista över körande spel"
},
"GAMES": "Spel",
"GENERAL_SETTINGS": "Allmänna inställningar",
"GETTING_STARTED": "Kom igång",
"HEIGHT": "Höjd",
"HELLO": "Hej!",
"HELLO_USER": "Hej, {USER}!",
"HIDE": "Dölj",
"HOME_SCREEN": "Hem",
"MODIFICATION_DATE": "Ändringsdatum",
"MONADO_RUNTIME": "Monado runtime",
"LOADING": "Laddar...",
"POPUP_ADD_DISPLAY": {
"RESOLUTION": "Upplösning"
},
"POWER_OPTIONS": {
"TITLE": "Strömalternativ",
"SHUTDOWN": "Stäng av",
"SUSPEND": "Viloläge",
"NOT_SUPPORTED": "Strömalternativ kräver systemd eller elogind.",
"SHUTDOWN_ARE_YOU_SURE": "Är du säker på att du vill stänga av datorn?",
"SUSPEND_ARE_YOU_SURE": "Är du säker på att du vill försätta datorn i viloläge?"
},
"PROCESS": {
"FORCE_KILL": "Tvinga avslut",
"STOP": "Stoppa"
},
"PROCESS_LIST": "Processlista",
"REFRESH": "Uppdatera",
"REMOVE": "Ta bort",
"APPLY": "Verkställ",
"RELOAD_FROM_DISK": "Ladda om från disk",
"SETTINGS": "Inställningar",
"SHOW": "Visa",
"TARGET_PATH": "Mål sökväg",
"TERMINATE_PROCESS": "Avsluta process",
"VERSION": "Version",
"WIDTH": "Bredd",
"PINNED_APPS": "Fästa applikationer",
"SAVED_TO_FAVOURITES": "Sparad i fästa applikationer",
"ADD_TO_FAVOURITES": "Lägg till i fästa applikationer",
"ADD_TO_FAVOURITES_HINT": "Spara förinställning och fäst den i app-menyn",
"REMOVE_FROM_FAVOURITES": "Ta bort från fästa applikationer",
"EMPTY": "Tomt",
"INSTALLED": "Installerad",
"NOT_INSTALLED": "Ej installerad",
"YES": "Ja",
"NO": "Nej"
}
+43 -8
View File
@@ -97,7 +97,10 @@
"RIGHT": "右侧",
"COMPONENT": "触发类型",
"SUBPATH": "激活控件",
"THRESHOLD": "高于上限值时激活\n低于下限值时取消激活"
"THRESHOLD": "高于上限值时激活\n低于下限值时取消激活",
"CHORD": "组合键",
"CHORD_ADD_INPUT": "添加组合键输入",
"CHORD_INPUT_HAND": "输入手"
},
"BROWSE_ONLINE_CATALOG": "浏览在线目录...",
"BROWSE_SKYMAPS": "浏览天空盒",
@@ -194,8 +197,6 @@
"SAVE_PLAYSPACE_CENTER_HELP": "将当前的活动空间设置为重置活动空间的绑定点。",
"RESET_PLAYSPACE_CENTER": "重置活动空间中心",
"RESET_PLAYSPACE_CENTER_HELP": "重置之前设置的活动空间中心。",
"RESTART_SOFTWARE": "重启软件",
"RESTART_SOFTWARE_HELP": "应用需要重启才能生效的设置",
"ROUND_MULTIPLIER": "UI 边缘圆角",
"SCREEN_RENDER_DOWN": "低分辨率渲染屏幕",
"SCREEN_RENDER_DOWN_HELP": "有助于减轻高分辨率屏幕上的锯齿现象",
@@ -205,7 +206,6 @@
"SNAP_ANGLE_DEG_HELP": "抓取窗口在俯仰轴和翻滚轴上按此角度对齐。",
"ENABLE_WATCH": "启用手表",
"SETS_ON_WATCH": "手表显示套装",
"SHOW_WELCOME_SCREEN": "显示欢迎界面",
"SKYBOX": "天空图",
"SKYMAP_ALREADY_DOWNLOADED": "此天空盒已下载。请选择操作。",
"SPACE_DRAG": "活动空间",
@@ -243,7 +243,29 @@
"GRID_OPACITY_HELP": "启用天空盒时地面网格的不透明度",
"XWAYLAND_BY_DEFAULT": "默认以兼容模式运行应用程序",
"SAVE": "保存",
"CANCEL": "取消"
"CANCEL": "取消",
"STATISTICS": "统计数据",
"ROTATIONS": "HMD 旋转次数",
"SESSION_TIME": "会话时间",
"LENS_SEPARATION_MM": "瞳距 (mm)",
"MIDDLE_GRABS_SINGLE": "中键点击修饰键抓取单个对象",
"MIDDLE_GRABS_SINGLE_HELP": "使用中键点击修饰键(紫色激光)抓取时\n将抓取单个叠加层,而非整个集合",
"DIAGNOSTICS_REASON": {
"PACTL": "用于扬声器/麦克风控制及声卡切换",
"CAGE": "若部分 X11 应用程序不兼容,建议开启(兼容模式)",
"XWAYLAND_SATELLITE": "如果你想以原生模式运行 X11 (Xwayland) 应用程序,建议开启此项",
"XDG_OPEN": "打开 URL 或 Steam 游戏所需"
},
"DIAGNOSTICS": {
"CPU_ACCESSIBLE_VRAM": "CPU 可访问 VRAM: {NUM} MiB",
"TITLE": "诊断",
"ENABLE_REBAR": "请在 BIOS 设置中启用 Resizable BAR 以获得最佳 VR 性能"
},
"TUTORIAL": "教程",
"RESTART_WAYVR": "重启 WayVR",
"CLOSE_WAYVR": "关闭 WayVR",
"SPEECH_TO_TEXT": "语音转文本",
"WHISPER_GPU_SELECT": "选择 GPU"
},
"APPLICATION_LAUNCHER": "应用启动器",
"APPLICATION_STARTED": "应用程序已启动",
@@ -260,7 +282,8 @@
"SETTINGS": "音频设置",
"SPEAKERS": "扬声器",
"SPEAKERS_SET_SUCCESSFULLY": "扬声器设置成功",
"VOLUME": "音量"
"VOLUME": "音量",
"SWITCH_TO_THIS_DEVICE": "切换至此设备"
},
"CLOSE_WINDOW": "关闭窗口",
"CREATION_DATE": "创建日期",
@@ -345,5 +368,17 @@
"ADD_TO_FAVOURITES": "添加到固定应用",
"ADD_TO_FAVOURITES_HINT": "保存预设并将其固定到应用抽屉",
"REMOVE_FROM_FAVOURITES": "从固定应用中移除",
"EMPTY": "暂无"
}
"EMPTY": "暂无",
"INSTALLED": "已安装",
"NOT_INSTALLED": "未安装",
"POWER_OPTIONS": {
"TITLE": "电源选项",
"SHUTDOWN": "关机",
"SUSPEND": "暂停",
"SHUTDOWN_ARE_YOU_SURE": "确定要关机吗?",
"NOT_SUPPORTED": "电源选项需要 systemd 或 elogind。",
"SUSPEND_ARE_YOU_SURE": "确定要让计算机进入睡眠状态吗?"
},
"YES": "确定",
"NO": "否"
}
+134 -15
View File
@@ -1,11 +1,11 @@
use std::{path::PathBuf, rc::Rc};
use std::{path::PathBuf, process::Command, rc::Rc};
use chrono::Timelike;
use glam::Vec2;
use strum::EnumCount;
use wgui::{
assets::{AssetPath, AssetProvider},
components::button::ComponentButton,
assets::{AssetPathRef, AssetProvider},
components::{ComponentTrait, button::ComponentButton},
event::{CallbackDataCommon, StyleSetRequest},
font_config::WguiFontConfig,
globals::WguiGlobals,
@@ -17,12 +17,15 @@ use wgui::{
task::Tasks,
theme::WguiTheme,
widget::{label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite},
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
windowing::{
context_menu::{self, ContextMenu},
window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
},
};
use wlx_common::{
async_executor::AsyncExecutor,
audio,
dash_interface::{BoxDashInterface, ConfigChangeKind, DashPlayspaceTask},
dash_interface::{BoxDashInterface, ConfigChangeKind, DashBackendTask, DashPlayspaceTask},
locale::WayVRLangProvider,
palette::load_palette,
timestep::{self, Timestep},
@@ -35,10 +38,11 @@ use crate::{
settings::TabSettings, welcome::TabWelcome,
},
util::{
popup_manager::{MountPopupOnceParams, PopupManager, PopupManagerParams},
is_exec_installed,
popup_manager::{MountPopupOnceParams, PopupHolder, PopupManager, PopupManagerParams},
toast_manager::ToastManager,
},
views,
views::{self, ViewUpdateParams},
};
pub struct FrontendWidgets {
@@ -74,9 +78,11 @@ pub struct Frontend<T> {
toast_manager: ToastManager,
timestep: Timestep,
sounds_to_play: Vec<SoundType>,
context_menu_power: ContextMenu,
window_audio_settings: WguiWindow,
view_audio_settings: Option<views::audio_settings::View>,
popup_dialog_box: PopupHolder<views::dialog_box::View>,
}
pub struct FrontendUpdateParams<'a, T> {
@@ -116,13 +122,16 @@ pub enum FrontendTask {
MountPopupOnce(MountPopupOnceParams),
RefreshPopupManager,
ShowAudioSettings,
ShowPowerSettings(WidgetID /* source widget */),
UpdateAudioSettingsView,
RecenterPlayspace,
PushToast(Translation),
PlaySound(SoundType),
OpenURL(Rc<str>),
RunCommand(String /* program */, Vec<String> /* args */),
HideDashboard,
MarkTutorialGraduated,
BackendTask(DashBackendTask),
}
impl<T: 'static> Frontend<T> {
@@ -151,7 +160,7 @@ impl<T: 'static> Frontend<T> {
let (layout, state) = wgui::parser::new_layout_from_assets(
&ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/dashboard.xml"),
path: AssetPathRef::BuiltIn("gui/dashboard.xml"),
extra: Default::default(),
},
LayoutParams {
@@ -202,9 +211,11 @@ impl<T: 'static> Frontend<T> {
popup_manager,
toast_manager,
window_audio_settings: WguiWindow::default(),
context_menu_power: Default::default(),
view_audio_settings: None,
executor: params.executor,
sounds_to_play: Vec::new(),
popup_dialog_box: Default::default(),
};
// init some things first
@@ -220,7 +231,7 @@ impl<T: 'static> Frontend<T> {
self.sounds_to_play.push(sound_type);
}
fn play_sound(&mut self, audio_system: &mut audio::AudioSystem, sound_type: SoundType) -> anyhow::Result<()> {
fn play_sound(&mut self, audio: &mut Box<dyn audio::AudioProvider>, sound_type: SoundType) -> anyhow::Result<()> {
let mut assets = self.globals.assets_builtin();
let path = match sound_type {
@@ -236,7 +247,7 @@ impl<T: 'static> Frontend<T> {
};
let sample = audio::AudioSample::from_mp3(&sound_bytes)?;
audio_system.play_sample(&sample);
audio.play_raw_sample(&sample);
Ok(())
}
@@ -264,24 +275,79 @@ impl<T: 'static> Frontend<T> {
pub fn process_update(
&mut self,
res: FrontendUpdateResult,
audio_system: &mut audio::AudioSystem,
audio_sample_player: &mut audio::SamplePlayer,
audio: &mut Box<dyn audio::AudioProvider>,
) -> anyhow::Result<()> {
for sound_type in res.sounds_to_play {
self.play_sound(audio_system, sound_type)?;
self.play_sound(audio, sound_type)?;
}
audio_sample_player.play_wgui_samples(audio_system, res.layout_result.sounds_to_play);
audio.play_wgui_samples(res.layout_result.sounds_to_play);
Ok(())
}
fn power_action_confirm(&mut self, power_action: PowerAction) {
let translation_key = match power_action {
PowerAction::Suspend => "POWER_OPTIONS.SUSPEND_ARE_YOU_SURE",
PowerAction::Poweroff => "POWER_OPTIONS.SHUTDOWN_ARE_YOU_SURE",
};
let tasks = self.tasks.clone();
views::dialog_box::mount_popup(
self.popup_dialog_box.clone(),
self.tasks.clone(),
views::dialog_box::Params {
globals: self.globals.clone(),
message: Translation::from_translation_key(translation_key),
entries: views::dialog_box::get_entries_yes_no(),
on_action_click: Box::new(move |action| {
if action == "yes" {
tasks.push(task_for_power_action(power_action));
}
}),
},
);
}
fn process_power_action(&mut self, action: &str, data: &mut T) {
match action {
"restart" => {
self.interface.restart(data);
}
"close" => {
self.interface.close(data);
}
"suspend" => {
self.power_action_confirm(PowerAction::Suspend);
}
"shutdown" => {
self.power_action_confirm(PowerAction::Poweroff);
}
_ => {
unreachable!()
}
}
}
fn tick(&mut self, params: FrontendUpdateParams<T>) -> anyhow::Result<FrontendUpdateResult> {
// fixme: timer events instead of this thing
if self.ticks.is_multiple_of(1000) {
self.update_time(params.data)?;
}
// TODO: refactor: simplify update function (no configs or T are required in most cases)
let mut config_change_kind = None;
self.popup_dialog_box.update(&mut ViewUpdateParams {
layout: &mut self.layout,
executor: &self.executor,
general_config: self.interface.general_config(params.data),
config_change_kind: &mut config_change_kind,
})?;
if let context_menu::TickResult::Action(action) = self.context_menu_power.tick(&mut self.layout, &mut self.state)? {
self.process_power_action(&action, params.data);
}
{
// always 30 times per second
while self.timestep.on_tick() {
@@ -372,13 +438,16 @@ impl<T: 'static> Frontend<T> {
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::ShowPowerSettings(pos) => self.action_show_power_settings(pos)?,
FrontendTask::UpdateAudioSettingsView => self.action_update_audio_settings()?,
FrontendTask::RecenterPlayspace => self.action_recenter_playspace(params.data)?,
FrontendTask::PushToast(content) => self.toast_manager.push(content),
FrontendTask::PlaySound(sound_type) => self.queue_play_sound(sound_type),
FrontendTask::HideDashboard => self.action_hide_dashboard(params.data),
FrontendTask::OpenURL(url) => self.action_open_url(url),
FrontendTask::RunCommand(program, args) => self.action_run_command(program, args),
FrontendTask::MarkTutorialGraduated => self.action_tutorial_graduated(params.data),
FrontendTask::BackendTask(task) => self.interface.backend_task(params.data, task)?,
};
Ok(())
}
@@ -401,7 +470,10 @@ impl<T: 'static> Frontend<T> {
.cast_as::<WidgetSprite>(self.widgets.id_sprite_titlebar_icon)?;
sprite.set_content(
common.alterables,
Some(CustomGlyphData::from_assets(&self.globals, AssetPath::BuiltIn(icon))?),
Some(CustomGlyphData::from_assets(
&self.globals,
AssetPathRef::BuiltIn(icon),
)?),
);
}
@@ -501,6 +573,11 @@ impl<T: 'static> Frontend<T> {
FrontendTask::ShowAudioSettings,
);
let btn_power = self.state.fetch_component_as::<ComponentButton>("btn_power")?;
self
.tasks
.handle_button(&btn_power, FrontendTask::ShowPowerSettings(btn_power.base().get_id()));
// "Recenter playspace" bottom bar button
self.tasks.handle_button(
&self.state.fetch_component_as::<ComponentButton>("btn_recenter")?,
@@ -510,6 +587,18 @@ impl<T: 'static> Frontend<T> {
Ok(())
}
fn action_show_power_settings(&mut self, source_id: WidgetID) -> anyhow::Result<()> {
self.context_menu_power.open(context_menu::OpenParams {
on_custom_attribs: None,
position: source_id.into(),
blueprint: context_menu::Blueprint::Template {
template_name: "context_menu_power_options".into(),
template_params: Default::default(),
},
});
Ok(())
}
fn action_show_audio_settings(&mut self) -> anyhow::Result<()> {
self.window_audio_settings.open(&mut WguiWindowParams {
position: Vec2::new(64.0, 64.0),
@@ -574,4 +663,34 @@ impl<T: 'static> Frontend<T> {
url
))));
}
fn action_run_command(&mut self, command: String, args: Vec<String>) {
if let Err(e) = Command::new(command).args(args).spawn() {
self
.tasks
.push(FrontendTask::PushToast(Translation::from_raw_text_string(format!(
"Failed to launch command: {e}"
))))
};
}
}
#[derive(Debug, Clone, Copy)]
pub enum PowerAction {
Suspend,
Poweroff,
}
pub fn task_for_power_action(action: PowerAction) -> FrontendTask {
for cmd in ["systemctl", "loginctl"] {
if is_exec_installed(cmd) {
let (command, args) = match action {
PowerAction::Suspend => (cmd.to_string(), vec!["suspend".to_string()]),
PowerAction::Poweroff => (cmd.to_string(), vec!["poweroff".to_string()]),
};
log::debug!("Command line for {action:?}: {command} {}", args.join(" "));
return FrontendTask::RunCommand(command, args);
}
}
FrontendTask::PushToast(Translation::from_translation_key("POWER_OPTIONS.NOT_SUPPORTED"))
}
+17 -14
View File
@@ -1,6 +1,6 @@
use std::{cell::RefCell, collections::VecDeque, marker::PhantomData, rc::Rc};
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::button::{ButtonClickCallback, ComponentButton},
globals::WguiGlobals,
i18n::Translation,
@@ -61,7 +61,7 @@ impl<T> Tab<T> for TabApps<T> {
}
}
fn find_entry_from_app_name<'a>(app_id: &str, entries: &'a [DesktopEntry]) -> Option<&'a DesktopEntry> {
fn find_entry_from_app_name<'a>(app_id: &str, entries: &'a [Rc<DesktopEntry>]) -> Option<&'a Rc<DesktopEntry>> {
entries.iter().find(|&entry| *entry.app_id == *app_id)
}
@@ -72,7 +72,7 @@ impl<T> TabApps<T> {
let mut stale_entries = Vec::<Rc<str>>::new();
let mut pinned_desktop_entries = Vec::<(PinnedApp, &DesktopEntry)>::new();
let mut pinned_desktop_entries = Vec::<(PinnedApp, Rc<DesktopEntry>)>::new();
// collect pinned desktop entries
{
@@ -83,7 +83,7 @@ impl<T> TabApps<T> {
continue;
};
pinned_desktop_entries.push((pinned_app.clone(), desktop_entry));
pinned_desktop_entries.push((pinned_app.clone(), desktop_entry.clone()));
}
// cleanup:
// remove non-existent app ids from pinned apps
@@ -119,7 +119,7 @@ impl<T> TabApps<T> {
&mut state.parser_state,
&doc_params(frontend.globals.clone()),
self.pinned_apps_parent,
desktop_entry,
desktop_entry.as_ref(),
Some(tooltip_string),
)?;
@@ -139,8 +139,8 @@ impl<T> TabApps<T> {
struct AppList {
//data: Vec<ParserData>,
all_entries: Vec<DesktopEntry>,
entries_to_mount: VecDeque<DesktopEntry>,
all_entries: Vec<Rc<DesktopEntry>>,
entries_to_mount: VecDeque<Rc<DesktopEntry>>,
list_parent: WidgetPair,
prev_category_name: String,
}
@@ -150,7 +150,7 @@ fn on_app_click(
frontend_tasks: FrontendTasks,
tasks: Tasks<Task>,
globals: WguiGlobals,
entry: DesktopEntry,
entry: Rc<DesktopEntry>,
state: Rc<RefCell<State>>,
pinned_app: Option<PinnedApp>,
) -> ButtonClickCallback {
@@ -170,7 +170,7 @@ fn on_app_click(
fn doc_params(globals: WguiGlobals) -> ParseDocumentParams<'static> {
ParseDocumentParams {
globals,
path: AssetPath::BuiltIn("gui/tab/apps.xml"),
path: AssetPathRef::BuiltIn("gui/tab/apps.xml"),
extra: Default::default(),
}
}
@@ -307,14 +307,17 @@ fn get_category_name_score(name: &str) -> u8 {
Scores::Unknown as u8
}
fn get_best_category_name(categories: &[Rc<str>]) -> Option<&Rc<str>> {
fn get_best_category_name<S>(categories: &[S]) -> Option<&str>
where
S: AsRef<str>,
{
let mut best_score: u8 = 0;
let mut best_category: Option<&Rc<str>> = None;
let mut best_category: Option<&str> = None;
for cat in categories {
let score = get_category_name_score(cat);
let score = get_category_name_score(cat.as_ref());
if score > best_score {
best_category = Some(cat);
best_category = Some(cat.as_ref());
best_score = score;
}
}
@@ -359,7 +362,7 @@ fn mount_entry<T>(
params.insert(
"src",
if entry.icon_path.is_none() {
"dashboard/terminal.svg"
"@/dashboard/terminal.svg"
} else {
""
},
+2 -2
View File
@@ -1,7 +1,7 @@
use std::{marker::PhantomData, rc::Rc};
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::button::ComponentButton,
globals::WguiGlobals,
layout::{Layout, WidgetID},
@@ -53,7 +53,7 @@ impl<T> Tab<T> for TabDonate<T> {
fn doc_params(globals: &WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/donate.xml"),
path: AssetPathRef::BuiltIn("gui/tab/donate.xml"),
extra: Default::default(),
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
use std::marker::PhantomData;
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
layout::WidgetID,
parser::{Fetchable, ParseDocumentParams, ParserState},
};
@@ -53,7 +53,7 @@ impl<T> TabGames<T> {
let state = wgui::parser::parse_from_assets(
&ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/games.xml"),
path: AssetPathRef::BuiltIn("gui/tab/games.xml"),
extra: Default::default(),
},
&mut frontend.layout,
+4 -4
View File
@@ -1,8 +1,8 @@
use std::{marker::PhantomData, rc::Rc};
use wgui::{
animation::{Animation, AnimationEasing},
assets::AssetPath,
animation::{Animation, AnimationDuration, AnimationEasing},
assets::AssetPathRef,
color::{WguiColor, WguiColorName, WguiNamedColor},
components::{ComponentTrait, button::ComponentButton},
event::CallbackDataCommon,
@@ -61,7 +61,7 @@ fn get_supporter_anim(
Animation::new_ex(
btn.base().get_id(),
1234,
480,
AnimationDuration::SecondsFixed(8.0),
AnimationEasing::Linear,
Box::new(move |common, data| {
let opacity_in = f32::clamp(data.pos * FADE_SPEED, 0.0, 1.0);
@@ -142,7 +142,7 @@ impl<T> TabHome<T> {
let state = wgui::parser::parse_from_assets(
&ParseDocumentParams {
globals: frontend.layout.state.globals.clone(),
path: AssetPath::BuiltIn("gui/tab/home.xml"),
path: AssetPathRef::BuiltIn("gui/tab/home.xml"),
extra: Default::default(),
},
&mut frontend.layout,
+5 -5
View File
@@ -1,7 +1,7 @@
use std::{collections::HashMap, marker::PhantomData, rc::Rc};
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::{
bar_graph::{ComponentBarGraph, ValueCell},
button::ComponentButton,
@@ -229,7 +229,7 @@ impl<T> Tab<T> for TabMonado<T> {
fn doc_params_monado(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/monado.xml"),
path: AssetPathRef::BuiltIn("gui/tab/monado.xml"),
extra: Default::default(),
}
}
@@ -237,7 +237,7 @@ fn doc_params_monado(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"),
path: AssetPathRef::BuiltIn("gui/tab/monado_tab_process_list.xml"),
extra: Default::default(),
}
}
@@ -245,7 +245,7 @@ fn doc_params_tab_process_list(globals: &'_ WguiGlobals) -> ParseDocumentParams<
fn doc_params_tab_general_settings(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/monado_tab_general_settings.xml"),
path: AssetPathRef::BuiltIn("gui/tab/monado_tab_general_settings.xml"),
extra: Default::default(),
}
}
@@ -253,7 +253,7 @@ fn doc_params_tab_general_settings(globals: &'_ WguiGlobals) -> ParseDocumentPar
fn doc_params_tab_debug_timings(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/monado_tab_debug_timings.xml"),
path: AssetPathRef::BuiltIn("gui/tab/monado_tab_debug_timings.xml"),
extra: Default::default(),
}
}
+114 -66
View File
@@ -1,16 +1,14 @@
use std::rc::Rc;
use crate::tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart};
use crate::{
tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart},
util::wgui_simple,
};
use wgui::{
components::{
button::{ButtonClickEvent, ComponentButton},
checkbox::ComponentCheckbox,
slider::ComponentSlider,
},
components::{button::ComponentButton, checkbox::ComponentCheckbox, slider::ComponentSlider},
layout::{Layout, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
task::Tasks,
widget::label::WidgetLabel,
windowing::context_menu,
};
use wlx_common::{DesktopBackend, XrBackend, config::GeneralConfig, dash_interface::InterfaceFeats};
@@ -35,6 +33,63 @@ pub fn options_category(
mp.parser_state.get_widget_id(&id)
}
pub fn options_stat_row(mp: &mut MacroParams, parent: WidgetID, translation: &str) -> anyhow::Result<WidgetID> {
let id = mp.idx.to_string();
mp.idx += 1;
let mut params = TemplateParams::new();
params.insert("id", &id);
params.insert("translation", translation);
mp.parser_state
.instantiate_template(mp.doc_params, "StatRow", mp.layout, parent, params)?;
mp.parser_state.get_widget_id(&id)
}
pub fn options_diagnostics_row(
mp: &mut MacroParams,
parent: WidgetID,
title: &str,
tooltip_str: &str,
checked: bool,
) -> anyhow::Result<()> {
let mut params = TemplateParams::new();
params.insert("title", title);
params.insert("tooltip_str", tooltip_str);
params.insert("color", if checked { "success" } else { "danger" });
params.insert(
"sprite",
if checked {
"@/dashboard/check.svg"
} else {
"@/dashboard/cross.svg"
},
);
mp.parser_state
.instantiate_template(mp.doc_params, "DiagnosticsRow", mp.layout, parent, params)?;
Ok(())
}
pub fn options_diagnostics_drm_card(
mp: &mut MacroParams,
parent: WidgetID,
name: &str,
info: &str,
) -> anyhow::Result<()> {
let mut params = TemplateParams::new();
params.insert("name", name);
params.insert("info", info);
mp.parser_state
.instantiate_template(mp.doc_params, "DiagnosticsDrmCard", mp.layout, parent, params)?;
Ok(())
}
pub fn options_checkbox(mp: &mut MacroParams, parent: WidgetID, setting: SettingType) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
@@ -240,7 +295,6 @@ where
mp.idx += 1;
let mut params = TemplateParams::new();
params.insert("id", &id);
match setting.get_translation() {
Ok(translation) => params.insert("translation", translation),
@@ -253,69 +307,63 @@ where
let id_cell = horiz_cell(mp.layout, parent)?;
mp.parser_state
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, id_cell, params)?;
let setting_str = setting.as_ref();
let title = setting.get_enum_title(mp.config);
let feats = mp.feats;
let cells = EnumType::VARIANTS
.iter()
.filter_map(|item| {
if item.get_bool("Hidden").unwrap_or(false) {
return None;
}
if item
.get_str("Backend")
.is_some_and(|x| XrBackend::try_from(x).unwrap() != feats.xr_backend)
{
return None;
}
if item
.get_str("Desktop")
.is_some_and(|x| DesktopBackend::try_from(x).unwrap() != feats.desktop_backend)
{
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" };
let action = format!("{setting_str};{id};{value};{text};{translated}");
Some(context_menu::Cell::Button(context_menu::Button {
action_name: Some(action.into()),
title,
tooltip,
..Default::default()
}))
})
.collect();
let tasks = mp.tasks.clone();
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
layout: mp.layout,
parser_state: mp.parser_state,
doc_params: mp.doc_params,
parent: id_cell,
id,
params,
current_text: title,
cells,
on_open: Box::new(move |pos, cells| tasks.push(Task::OpenContextMenu(pos, cells))),
})?;
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 feats = mp.feats;
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;
}
if item
.get_str("Backend")
.is_some_and(|x| XrBackend::try_from(x).unwrap() != feats.xr_backend)
{
return None;
}
if item
.get_str("Desktop")
.is_some_and(|x| DesktopBackend::try_from(x).unwrap() != feats.desktop_backend)
{
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(())
}
+53 -23
View File
@@ -1,8 +1,7 @@
use glam::Vec2;
use std::{marker::PhantomData, rc::Rc, str::FromStr};
use strum::{AsRefStr, EnumProperty, EnumString};
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
color::WguiColorName,
components::tabs::ComponentTabs,
event::StyleSetRequest,
@@ -23,7 +22,7 @@ use wgui::{
use wlx_common::{
config::GeneralConfig,
config_io::ConfigRoot,
dash_interface::{ConfigChangeKind, DashPlayspaceTask, InterfaceFeats},
dash_interface::{ConfigChangeKind, DashPlayspaceTask, HmdStats, InterfaceFeats},
};
use crate::{
@@ -35,11 +34,13 @@ use crate::{
mod macros;
mod tab_autostart_apps;
mod tab_controls;
mod tab_diagnostics;
mod tab_features;
mod tab_look_and_feel;
mod tab_misc;
mod tab_skybox;
mod tab_space_drag;
mod tab_statistics;
mod tab_troubleshooting;
#[derive(Clone)]
@@ -51,6 +52,8 @@ pub(crate) enum TabNameEnum {
Misc,
Skybox,
SpaceDrag,
Statistics,
Diagnostics,
Troubleshooting,
}
@@ -64,6 +67,8 @@ impl TabNameEnum {
"misc" => Some(TabNameEnum::Misc),
"skybox" => Some(TabNameEnum::Skybox),
"space_drag" => Some(TabNameEnum::SpaceDrag),
"statistics" => Some(TabNameEnum::Statistics),
"diagnostics" => Some(TabNameEnum::Diagnostics),
"troubleshooting" => Some(TabNameEnum::Troubleshooting),
_ => None,
}
@@ -75,11 +80,10 @@ pub(crate) enum Task {
ClearPipewireTokens,
ClearSavedState,
DeleteAllConfigs,
OpenContextMenu(Vec2, Vec<context_menu::Cell>),
OpenContextMenu(context_menu::Position, Vec<context_menu::Cell>),
RemoveAutostartApp(Rc<str>),
ResetPlayspace,
ResetPlayspaceCenter,
RestartSoftware,
SavePlayspaceCenter,
SetTab(TabNameEnum),
SettingUpdated(SettingType),
@@ -101,8 +105,12 @@ struct SettingUpdatedParams<'a> {
setting_type: SettingType,
}
struct UpdateExtra {
hmd_stats: HmdStats,
}
trait SettingsTab {
fn update(&mut self, _par: &mut ViewUpdateParams) -> anyhow::Result<()> {
fn update(&mut self, _par: &mut ViewUpdateParams, _extra: &UpdateExtra) -> anyhow::Result<()> {
Ok(())
}
@@ -133,6 +141,7 @@ pub struct TabSettings<T> {
tasks: Tasks<Task>,
marker: PhantomData<T>,
frontend_tasks: FrontendTasks,
feats: InterfaceFeats,
}
impl<T> Tab<T> for TabSettings<T> {
@@ -144,12 +153,17 @@ impl<T> Tab<T> for TabSettings<T> {
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,
})?;
let hmd_stats = frontend.interface.hmd_stats(data);
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,
},
&UpdateExtra { hmd_stats },
)?;
if let Some(kind) = config_change_kind {
frontend.interface.config_changed(data, kind);
@@ -216,10 +230,6 @@ impl<T> Tab<T> for TabSettings<T> {
frontend.interface.playspace_task(data, DashPlayspaceTask::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,
@@ -335,6 +345,7 @@ pub(crate) enum SettingType {
NotificationsEnabled,
NotificationsSoundEnabled,
OpaqueBackground,
MiddleGrabsSingle,
MouseAcceleration,
PointerLerpFactor,
MouseSpeed,
@@ -391,6 +402,7 @@ impl SettingType {
Self::NotificationsEnabled => &mut config.notifications_enabled,
Self::NotificationsSoundEnabled => &mut config.notifications_sound_enabled,
Self::OpaqueBackground => &mut config.opaque_background,
Self::MiddleGrabsSingle => &mut config.middle_grabs_single,
Self::MouseAcceleration => &mut config.wvr_mouse_acceleration,
Self::ScreenRenderDown => &mut config.screen_render_down,
Self::SetsOnWatch => &mut config.sets_on_watch,
@@ -541,6 +553,7 @@ impl SettingType {
Self::NotificationsEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_ENABLED"),
Self::NotificationsSoundEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED"),
Self::OpaqueBackground => Ok("APP_SETTINGS.OPAQUE_BACKGROUND"),
Self::MiddleGrabsSingle => Ok("APP_SETTINGS.MIDDLE_GRABS_SINGLE"),
Self::MouseSpeed => Ok("APP_SETTINGS.POINTER_SPEED"),
Self::MouseAcceleration => Ok("APP_SETTINGS.POINTER_ACCELERATION"),
Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"),
@@ -590,6 +603,7 @@ impl SettingType {
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::MiddleGrabsSingle => Some("APP_SETTINGS.MIDDLE_GRABS_SINGLE_HELP"),
Self::MouseAcceleration => Some("APP_SETTINGS.POINTER_ACCELERATION_HELP"),
Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"),
Self::SnapAngleDeg => Some("APP_SETTINGS.SNAP_ANGLE_DEG_HELP"),
@@ -675,7 +689,7 @@ fn mount_requires_restart(layout: &mut Layout, parent: WidgetID) -> anyhow::Resu
fn doc_params(globals: &'_ WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/settings.xml"),
path: AssetPathRef::BuiltIn("gui/tab/settings.xml"),
extra: Default::default(),
}
}
@@ -684,10 +698,14 @@ 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 globals = frontend.layout.state.globals.clone();
let feats = frontend.interface.get_feats(data);
let vulkan_devices = if matches!(name, TabNameEnum::Features) {
Some(frontend.interface.enumerate_vulkan_devices(data)?)
} else {
None
};
let mut mp = MacroParams {
layout: &mut frontend.layout,
@@ -696,14 +714,14 @@ impl<T> TabSettings<T> {
config: frontend.interface.general_config(data),
tasks: self.tasks.clone(),
idx: 9001,
feats,
feats: self.feats,
};
let settings_mount_params = SettingsMountParams {
mp: &mut mp,
id_parent: root,
frontend_tasks: &self.frontend_tasks,
feats,
feats: self.feats,
};
match name {
@@ -711,7 +729,10 @@ impl<T> TabSettings<T> {
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)?));
self.current_tab = Some(Box::new(tab_features::State::mount(
settings_mount_params,
vulkan_devices.unwrap(), /* safe */
)?));
}
TabNameEnum::SpaceDrag => {
self.current_tab = Some(Box::new(tab_space_drag::State::mount(settings_mount_params)?));
@@ -734,6 +755,12 @@ impl<T> TabSettings<T> {
TabNameEnum::Skybox => {
self.current_tab = Some(Box::new(tab_skybox::State::mount(settings_mount_params)?));
}
TabNameEnum::Statistics => {
self.current_tab = Some(Box::new(tab_statistics::State::mount(settings_mount_params)?));
}
TabNameEnum::Diagnostics => {
self.current_tab = Some(Box::new(tab_diagnostics::State::mount(settings_mount_params)?));
}
}
Ok(())
@@ -742,7 +769,7 @@ 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"),
path: AssetPathRef::BuiltIn("gui/tab/settings.xml"),
extra: Default::default(),
};
@@ -771,6 +798,8 @@ impl<T> TabSettings<T> {
tasks.push(Task::SetTab(TabNameEnum::LookAndFeel));
let feats = frontend.interface.get_feats(data);
Ok(Self {
app_button_ids: Vec::new(),
tasks,
@@ -779,6 +808,7 @@ impl<T> TabSettings<T> {
context_menu: ContextMenu::default(),
current_tab: None,
frontend_tasks: frontend.tasks.clone(),
feats,
})
}
}
@@ -18,7 +18,7 @@ impl State {
par.mp,
par.id_parent,
"APP_SETTINGS.AUTOSTART_APPS",
"dashboard/apps.svg",
"@/dashboard/apps.svg",
)?;
// todo: prevent clone
+28 -10
View File
@@ -3,8 +3,11 @@ use wgui::parser::TemplateParams;
use wgui::{
components::button::ComponentButton, globals::WguiGlobals, layout::WidgetID, parser::Fetchable, task::Tasks,
};
use wlx_common::XrBackend;
use wlx_common::dash_interface::DashBackendTask;
use crate::tab::settings::{horiz_cell, mount_requires_restart};
use crate::frontend::FrontendTask;
use crate::tab::settings::{UpdateExtra, horiz_cell, mount_requires_restart};
use crate::util::popup_manager::PopupHolder;
use crate::{
@@ -18,7 +21,8 @@ use crate::{
#[derive(Clone)]
enum Task {
OpenInputProfiles,
OpenInputProfilesDash,
OpenInputProfilesBackend,
}
pub struct State {
@@ -29,18 +33,28 @@ pub struct State {
}
impl SettingsTab for State {
fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
fn update(&mut self, par: &mut ViewUpdateParams, _extra: &UpdateExtra) -> anyhow::Result<()> {
self.popup_input_profiles.update(par)?;
for task in self.tasks.drain() {
match task {
Task::OpenInputProfiles => {
Task::OpenInputProfilesDash => {
input_profiles::mount_popup(
self.frontend_tasks.clone(),
self.globals.clone(),
self.popup_input_profiles.clone(),
);
}
Task::OpenInputProfilesBackend => {
self
.frontend_tasks
.push(FrontendTask::BackendTask(DashBackendTask::ShowBindingsUI));
// overlay sort order doesn't work on steamvr,
// so the dashboard would be drawn over the bindings UI
// while the bindings UI has input focus
self.frontend_tasks.push(FrontendTask::HideDashboard);
}
}
}
@@ -53,6 +67,7 @@ fn create_input_profiles_button(
parent: WidgetID,
tasks: Tasks<Task>,
_popup: &PopupHolder<input_profiles::View>,
xr_backend: XrBackend,
) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
@@ -62,7 +77,7 @@ fn create_input_profiles_button(
let mut params = TemplateParams::new();
params.insert("id", &id);
params.insert("translation", "APP_SETTINGS.INPUT_PROFILES");
params.insert("icon", "dashboard/controller.svg");
params.insert("icon", "@/dashboard/controller.svg");
mp.parser_state
.instantiate_template(mp.doc_params, "ButtonText", mp.layout, id_cell, params)?;
@@ -71,7 +86,11 @@ fn create_input_profiles_button(
btn.on_click(Rc::new({
let tasks = tasks.clone();
move |_common, _e| {
tasks.push(Task::OpenInputProfiles);
if xr_backend.is_open_vr() {
tasks.push(Task::OpenInputProfilesBackend);
} else {
tasks.push(Task::OpenInputProfilesDash);
}
Ok(())
}
}));
@@ -90,16 +109,15 @@ impl State {
par.mp,
par.id_parent,
"APP_SETTINGS.CONTROLS",
"dashboard/controller.svg",
"@/dashboard/controller.svg",
)?;
if par.feats.xr_backend.is_open_xr() {
create_input_profiles_button(par.mp, c, tasks.clone(), &popup)?;
}
create_input_profiles_button(par.mp, c, tasks.clone(), &popup, par.feats.xr_backend)?;
options_dropdown::<wlx_common::config::AltModifier>(par.mp, c, &SettingType::KeyboardMiddleClick)?;
options_dropdown::<wlx_common::config::HandsfreePointer>(par.mp, c, &SettingType::HandsfreePointer)?;
options_dropdown::<wlx_common::config::HandsfreeAltTab>(par.mp, c, &SettingType::HandsfreeAltTab)?;
options_checkbox(par.mp, c, SettingType::FocusFollowsMouseMode)?;
options_checkbox(par.mp, c, SettingType::LeftHandedMouse)?;
options_checkbox(par.mp, c, SettingType::MiddleGrabsSingle)?;
options_checkbox(par.mp, c, SettingType::AllowSliding)?;
options_checkbox(par.mp, c, SettingType::InvertScrollDirectionX)?;
options_checkbox(par.mp, c, SettingType::InvertScrollDirectionY)?;
@@ -0,0 +1,178 @@
use wgui::layout::WidgetID;
use crate::{
tab::settings::{
SettingsMountParams, SettingsTab,
macros::{MacroParams, options_category, options_diagnostics_drm_card, options_diagnostics_row},
},
util::is_exec_installed,
};
pub struct State {}
impl SettingsTab for State {}
#[derive(Default)]
struct LspciInfo {
// slot: String,
// class: String,
vendor: String,
device: String,
// s_vendor: String,
}
fn lspci_info(vendor: &str /* hex */, device: &str /* hex */) -> Option<LspciInfo> {
// example output for "lspci -vmmd 1002:747e":
//
// Slot: 0b:00.0
// Class: VGA compatible controller
// Vendor: Advanced Micro Devices, Inc. [AMD/ATI]
// Device: Navi 32 [Radeon RX 7700 XT / 7800 XT]
// SVendor: Sapphire Technology Limited
// SDevice: Device 475a
// Rev: c8
// ProgIf: 00
let mut cmd = std::process::Command::new("lspci");
cmd.arg("-vmmd");
cmd.arg(format!("{}:{}", vendor, device));
let res = cmd.output().ok()?;
if !res.status.success() {
return None;
}
let mut info = LspciInfo::default();
let stdout = str::from_utf8(&res.stdout).ok()?;
for line in stdout.lines() {
let Some((key, value)) = line.split_once(":") else {
continue;
};
if key == "Device" {
info.device = String::from(value.trim());
}
}
Some(info)
}
fn mount_installed_path(
mp: &mut MacroParams,
parent: WidgetID,
exec: &str,
reason_translation: Option<&str>,
) -> anyhow::Result<()> {
let title = if is_exec_installed(exec) {
"INSTALLED"
} else {
"NOT_INSTALLED"
};
let title_translated = mp.layout.state.globals.i18n().translate(title);
let tooltip = if let Some(reason) = reason_translation {
format!(
"{}\n{}",
title_translated,
mp.layout.state.globals.i18n().translate(reason)
)
} else {
title_translated.to_string()
};
options_diagnostics_row(mp, parent, exec, &tooltip, is_exec_installed(exec))?;
Ok(())
}
fn read_sysfs_param(device_path: &str, param: &str) -> anyhow::Result<String> {
let string = std::fs::read_to_string(format!("{}/{}", device_path, param))?;
Ok(string.trim().into())
}
fn read_sysfs_param_int(device_path: &str, param: &str) -> anyhow::Result<u64> {
Ok(read_sysfs_param(device_path, param)?.parse::<u64>()?)
}
fn mount_drm_card(mp: &mut MacroParams, parent: WidgetID, device_path: &str) -> anyhow::Result<()> {
let vendor = read_sysfs_param(device_path, "vendor")?;
let device = read_sysfs_param(device_path, "device")?;
let vram_total = read_sysfs_param_int(device_path, "mem_info_vram_total").ok();
let vis_vram_total = read_sysfs_param_int(device_path, "mem_info_vis_vram_total").ok();
let name = match lspci_info(&vendor, &device) {
Some(info) => {
format!("{} {}", info.vendor, info.device)
}
None => format!("{}:{}", vendor, device),
};
let info = if let Some(vram_total) = vram_total
&& let Some(vis_vram_total) = vis_vram_total
{
let mut s = mp.layout.state.globals.i18n().translate_and_replace(
"APP_SETTINGS.DIAGNOSTICS.CPU_ACCESSIBLE_VRAM",
(
"{NUM}",
&format!("{}/{}", vis_vram_total / 1024 / 1024, vram_total / 1024 / 1024),
),
);
if vis_vram_total != vram_total {
s += " [ALERT!]\nEnable Resizable BAR in the BIOS settings for optimal VR performance";
}
s
} else {
String::from("No info")
};
options_diagnostics_drm_card(mp, parent, &name, &info)?;
Ok(())
}
fn mount_drm_cards(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> {
for file in std::fs::read_dir("/sys/class/drm/")?.flatten() {
let file_name = file.file_name();
let Some(file_name) = file_name.to_str() else {
continue;
};
if !file_name.starts_with("renderD") {
continue;
}
if let Err(e) = mount_drm_card(mp, parent, &format!("/sys/class/drm/{}/device", file_name)) {
log::error!("failed to mount drm card: {}", e);
}
}
Ok(())
}
impl State {
pub fn mount(par: SettingsMountParams) -> anyhow::Result<Self> {
let c = options_category(
par.mp,
par.id_parent,
"APP_SETTINGS.DIAGNOSTICS.TITLE",
"@/dashboard/diagnostics.svg",
)?;
mount_installed_path(par.mp, c, "pactl", Some("APP_SETTINGS.DIAGNOSTICS_REASON.PACTL"))?;
mount_installed_path(par.mp, c, "cage", Some("APP_SETTINGS.DIAGNOSTICS_REASON.CAGE"))?;
mount_installed_path(
par.mp,
c,
"xwayland-satellite",
Some("APP_SETTINGS.DIAGNOSTICS_REASON.XWAYLAND_SATELLITE"),
)?;
mount_installed_path(par.mp, c, "xdg-open", Some("APP_SETTINGS.DIAGNOSTICS_REASON.XDG_OPEN"))?;
mount_installed_path(par.mp, c, "steam", None)?;
mount_drm_cards(par.mp, c)?;
Ok(State {})
}
}
+141 -80
View File
@@ -1,7 +1,6 @@
use std::rc::Rc;
use wgui::{
components::button::{ButtonClickEvent, ComponentButton},
globals::WguiGlobals,
i18n::Translation,
layout::WidgetID,
@@ -9,18 +8,19 @@ use wgui::{
parser::{Fetchable, TemplateParams},
task::Tasks,
widget::label::WidgetLabel,
windowing::context_menu::{self},
windowing::context_menu,
};
use wlx_common::{async_executor::AsyncExecutor, config::GeneralConfig, dash_interface::ConfigChangeKind};
use crate::{
frontend::FrontendTasks,
tab::settings::{
SettingType, SettingsMountParams, SettingsTab, TabNameEnum, Task as ParentTask, horiz_cell,
SettingType, SettingsMountParams, SettingsTab, TabNameEnum, Task as ParentTask, UpdateExtra, horiz_cell,
macros::{MacroParams, options_category, options_checkbox, options_range_f32},
},
util::{
popup_manager::PopupHolder,
wgui_simple,
whisper::{
WHISPER_MODELS, WhisperModel, whisper_any_models_downloaded, whisper_delete_all_models, whisper_model_from_name,
whisper_model_path,
@@ -50,7 +50,7 @@ pub struct State {
}
impl SettingsTab for State {
fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
fn update(&mut self, par: &mut ViewUpdateParams, _extra: &UpdateExtra) -> anyhow::Result<()> {
self.popup_download.update(par)?;
self.popup_dialog.update(par)?;
@@ -79,7 +79,7 @@ impl SettingsTab for State {
par.general_config.whisper_model = model.file_name.into();
par.config_change_kind.replace(ConfigChangeKind::Other);
// reload tab so that the downloaded checkmarks get populated
// reload tab so that the downloaded check marks get populated
self.parent_tasks.push(ParentTask::SetTab(TabNameEnum::Features));
}
}
@@ -104,49 +104,75 @@ impl SettingsTab for State {
layout: &mut wgui::layout::Layout,
state: &mut wgui::parser::ParserState,
) -> anyhow::Result<()> {
if let (Some(_), Some(id), Some(model_name)) = {
let mut s = action.splitn(3, ';');
(s.next(), s.next(), s.next())
} {
if !model_name.is_empty()
&& let Some(model) = whisper_model_from_name(model_name)
{
let mut common = layout.common();
let mut label = state.fetch_widget_as::<WidgetLabel>(common.state, &format!("{id}_value"))?;
label.set_text(&mut common, Translation::from_raw_text(model.display_name));
let (Some(_), Some(_type), Some(id), Some(value)) = ({
let mut s = action.splitn(4, ';');
(s.next(), s.next(), s.next(), s.next())
}) else {
debug_assert!(false);
return Ok(());
};
config.whisper_model = model.file_name.into();
if !whisper_model_path(model.file_name).exists() {
self.show_whisper_model_dialog_box_download(model)?;
match _type {
"whisper_model" => {
let model_name = value;
if !model_name.is_empty()
&& let Some(model) = whisper_model_from_name(model_name)
{
let mut common = layout.common();
let mut label = state.fetch_widget_as::<WidgetLabel>(common.state, &format!("{id}_value"))?;
label.set_text(&mut common, Translation::from_raw_text(model.display_name));
config.whisper_model = model.file_name.into();
if !whisper_model_path(model.file_name).exists() {
self.show_whisper_model_dialog_box_download(model)?;
} else {
change_kind.replace(ConfigChangeKind::Other);
}
} else {
config.whisper_model = "".into();
change_kind.replace(ConfigChangeKind::Other);
}
} else {
config.whisper_model = "".into();
change_kind.replace(ConfigChangeKind::Other);
// re-init the whole tab
if whisper_any_models_downloaded().unwrap_or_default() {
self.show_whisper_model_dialog_box_cleanup()?;
} else {
self.parent_tasks.push(ParentTask::SetTab(TabNameEnum::Features));
// re-init the whole tab
if whisper_any_models_downloaded().unwrap_or_default() {
self.show_whisper_model_dialog_box_cleanup()?;
} else {
self.parent_tasks.push(ParentTask::SetTab(TabNameEnum::Features));
}
}
}
}
"whisper_gpu" => {
let mut common = layout.common();
let mut label = state.fetch_widget_as::<WidgetLabel>(common.state, &format!("{id}_value"))?;
config.whisper_gpu = value.parse::<u32>().unwrap();
label.set_text(
&mut common,
Translation::from_raw_text_string(config.whisper_gpu.to_string()),
);
change_kind.replace(ConfigChangeKind::Other);
}
_ => unreachable!(),
};
Ok(())
}
}
impl State {
pub fn mount(par: SettingsMountParams) -> anyhow::Result<State> {
pub fn mount(par: SettingsMountParams, vulkan_devices: Vec<String>) -> anyhow::Result<State> {
let tasks = Tasks::<Task>::new();
let popup_download = PopupHolder::<views::download_file::View>::default();
let popup_dialog = PopupHolder::<views::dialog_box::View>::default();
let c = options_category(par.mp, par.id_parent, "APP_SETTINGS.FEATURES", "dashboard/options.svg")?;
let c = options_category(
par.mp,
par.id_parent,
"APP_SETTINGS.FEATURES",
"@/dashboard/options.svg",
)?;
if par.feats.whisper {
let c = options_category(par.mp, c, "APP_SETTINGS.SPEECH_TO_TEXT", "@/dashboard/stt.svg")?;
whisper_models_dropdown(par.mp, c)?;
whisper_gpu_select_dropdown(par.mp, c, vulkan_devices)?;
}
options_checkbox(par.mp, c, SettingType::NotificationsEnabled)?;
@@ -213,12 +239,12 @@ impl State {
entries: vec![
views::dialog_box::ButtonEntry {
content: Translation::from_translation_key("APP_SETTINGS.CANCEL"),
icon: "dashboard/close.svg",
icon: "@/dashboard/close.svg",
action: ACTION_CANCEL,
},
views::dialog_box::ButtonEntry {
content: Translation::from_translation_key("DOWNLOAD"),
icon: "dashboard/download.svg",
icon: "@/dashboard/download.svg",
action: ACTION_DOWNLOAD,
},
],
@@ -254,12 +280,12 @@ impl State {
entries: vec![
views::dialog_box::ButtonEntry {
content: Translation::from_translation_key("APP_SETTINGS.CANCEL"),
icon: "dashboard/close.svg",
icon: "@/dashboard/close.svg",
action: ACTION_CANCEL,
},
views::dialog_box::ButtonEntry {
content: Translation::from_translation_key("REMOVE"),
icon: "dashboard/trash.svg",
icon: "@/dashboard/trash.svg",
action: ACTION_REMOVE,
},
],
@@ -282,6 +308,48 @@ impl State {
}
}
fn whisper_gpu_select_dropdown(
mp: &mut MacroParams,
parent: WidgetID,
vulkan_devices: Vec<String>,
) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
let parent = horiz_cell(mp.layout, parent)?;
let mut params = TemplateParams::new();
params.insert("translation", "APP_SETTINGS.WHISPER_GPU_SELECT");
let current_text = Translation::from_raw_text_string(mp.config.whisper_gpu.to_string());
let cells = vulkan_devices
.iter()
.enumerate()
.filter(|(_, name)| !name.contains("llvmpipe"))
.map(|(idx, name)| {
context_menu::Cell::Button(context_menu::Button {
action_name: Some(format!(";whisper_gpu;{};{}", id, idx).into()),
title: Translation::from_raw_text_string(name.to_string()),
..Default::default()
})
})
.collect();
let tasks = mp.tasks.clone();
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
layout: mp.layout,
parser_state: mp.parser_state,
doc_params: mp.doc_params,
parent,
id,
params,
current_text,
cells,
on_open: Box::new(move |pos, cells| tasks.push(ParentTask::OpenContextMenu(pos, cells))),
})
}
fn whisper_models_dropdown(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
@@ -302,56 +370,49 @@ fn whisper_models_dropdown(mp: &mut MacroParams, parent: WidgetID) -> anyhow::Re
});
let mut params = TemplateParams::new();
params.insert("id", &id);
params.insert("translation", "APP_SETTINGS.WHISPER_MODEL");
params.insert("tooltip", "APP_SETTINGS.WHISPER_MODEL_HELP");
mp.parser_state
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, parent, params)?;
{
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(), current_translation);
}
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
btn.on_click(Rc::new({
let parent_tasks = mp.tasks.clone();
move |_common, e: ButtonClickEvent| {
let mut cells = WHISPER_MODELS
.iter()
.enumerate()
.map(|(idx, item)| context_menu::Cell {
action_name: Some(format!(";{id};{}", item.file_name).into()),
title: Translation::from_raw_text_string(format!(
"{}{}",
item.display_name,
if downloaded_models.contains(&idx) { " ✅" } else { "" }
)),
tooltip: None,
attribs: vec![],
let mut cells = WHISPER_MODELS
.iter()
.enumerate()
.map(|(idx, item)| {
if downloaded_models.contains(&idx) {
context_menu::Cell::Button(context_menu::Button {
action_name: Some(format!(";whisper_model;{id};{}", item.file_name).into()),
title: Translation::from_raw_text(item.display_name),
sprite_src_builtin: Some("@/dashboard/check.svg".into()),
..Default::default()
})
.collect::<Vec<_>>();
} else {
context_menu::Cell::Button(context_menu::Button {
action_name: Some(format!(";whisper_model;{id};{}", item.file_name).into()),
title: Translation::from_raw_text(item.display_name),
..Default::default()
})
}
})
.collect::<Vec<_>>();
cells.insert(
0,
context_menu::Cell {
action_name: Some(format!(";{id};").into()),
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
tooltip: None,
attribs: vec![],
},
);
cells.insert(
0,
context_menu::Cell::Button(context_menu::Button {
action_name: Some(format!(";whisper_model;{id};").into()),
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
..Default::default()
}),
);
parent_tasks.push(ParentTask::OpenContextMenu(
e.mouse_pos_absolute.unwrap_or_default(),
cells,
));
Ok(())
}
}));
Ok(())
let tasks = mp.tasks.clone();
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
layout: mp.layout,
parser_state: mp.parser_state,
doc_params: mp.doc_params,
parent,
id,
params,
current_text: current_translation,
cells,
on_open: Box::new(move |pos, cells| tasks.push(ParentTask::OpenContextMenu(pos, cells))),
})
}
@@ -11,7 +11,7 @@ use wgui::{
use crate::{
frontend::FrontendTasks,
tab::settings::{
SettingType, SettingsMountParams, SettingsTab, horiz_cell,
SettingType, SettingsMountParams, SettingsTab, UpdateExtra, horiz_cell,
macros::{options_category, options_checkbox, options_dropdown, options_slider_f32},
mount_requires_restart,
},
@@ -32,7 +32,7 @@ pub struct State {
}
impl SettingsTab for State {
fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
fn update(&mut self, par: &mut ViewUpdateParams, _extra: &UpdateExtra) -> anyhow::Result<()> {
self.popup_color_palettes.update(par)?;
for task in self.tasks.drain() {
@@ -60,7 +60,7 @@ impl State {
par.mp,
par.id_parent,
"APP_SETTINGS.LOOK_AND_FEEL",
"dashboard/palette.svg",
"@/dashboard/palette.svg",
)?;
create_color_palettes_button(par.mp, c, tasks.clone(), &popup)?;
options_dropdown::<wlx_common::locale::Language>(par.mp, c, &SettingType::Language)?;
@@ -100,7 +100,7 @@ fn create_color_palettes_button(
let mut params = TemplateParams::new();
params.insert("id", &id);
params.insert("translation", "APP_SETTINGS.COLOR_PALETTE");
params.insert("icon", "dashboard/palette.svg");
params.insert("icon", "@/dashboard/palette.svg");
mp.parser_state
.instantiate_template(mp.doc_params, "ButtonText", mp.layout, id_cell, params)?;
+1 -1
View File
@@ -9,7 +9,7 @@ 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.MISC", "dashboard/blocks.svg")?;
let c = options_category(par.mp, par.id_parent, "APP_SETTINGS.MISC", "@/dashboard/blocks.svg")?;
options_dropdown::<wlx_common::config::InputEmulationMethod>(par.mp, c, &SettingType::InputEmulationMethod)?;
options_dropdown::<wlx_common::config::InputCaptureMethod>(par.mp, c, &SettingType::InputCaptureMethod)?;
options_dropdown::<wlx_common::config::CaptureMethod>(par.mp, c, &SettingType::CaptureMethod)?;
+5 -5
View File
@@ -1,9 +1,9 @@
use wgui::{assets::AssetPath, i18n::Translation, layout::Layout, task::Tasks};
use wgui::{assets::AssetPathRef, i18n::Translation, layout::Layout, task::Tasks};
use crate::{
frontend::FrontendTasks,
tab::settings::{
SettingType, SettingsMountParams, SettingsTab,
SettingType, SettingsMountParams, SettingsTab, UpdateExtra,
macros::{options_category, options_checkbox, options_slider_f32},
},
util::{popup_manager::PopupHolder, wgui_simple},
@@ -22,7 +22,7 @@ pub struct State {
}
impl SettingsTab for State {
fn update(&mut self, par: &mut ViewUpdateParams) -> anyhow::Result<()> {
fn update(&mut self, par: &mut ViewUpdateParams, _extra: &UpdateExtra) -> anyhow::Result<()> {
self.popup_skymap_list.update(par)?;
for task in self.tasks.drain() {
@@ -37,7 +37,7 @@ impl SettingsTab for State {
impl State {
pub fn mount(par: SettingsMountParams) -> anyhow::Result<Self> {
let id_category = options_category(par.mp, par.id_parent, "APP_SETTINGS.SKYBOX", "dashboard/globe.svg")?;
let id_category = options_category(par.mp, par.id_parent, "APP_SETTINGS.SKYBOX", "@/dashboard/globe.svg")?;
options_checkbox(par.mp, id_category, SettingType::UseSkybox)?;
options_checkbox(par.mp, id_category, SettingType::UsePassthrough)?;
options_slider_f32(par.mp, id_category, SettingType::GridOpacity, 0.0, 1.0, 0.05)?;
@@ -49,7 +49,7 @@ impl State {
id_parent: id_category,
layout: par.mp.layout,
content: Translation::from_translation_key("APP_SETTINGS.BROWSE_SKYMAPS"),
icon_builtin: AssetPath::BuiltIn("dashboard/globe.svg"),
icon_builtin: AssetPathRef::BuiltIn("dashboard/globe.svg"),
on_click: tasks.get_button_click_callback(Task::ShowSkymapList),
})?;
@@ -1,5 +1,5 @@
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
i18n::Translation,
layout::{Layout, LayoutTask, WidgetID},
parser::{Fetchable, ParseDocumentParams},
@@ -36,14 +36,14 @@ 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.SPACE_DRAG", "dashboard/drag.svg")?;
let c = options_category(par.mp, par.id_parent, "APP_SETTINGS.SPACE_DRAG", "@/dashboard/drag.svg")?;
let globals = par.mp.layout.state.globals.clone();
let tab_state = wgui::parser::parse_from_assets(
&ParseDocumentParams {
globals,
path: AssetPath::BuiltIn("gui/tab/settings_tab_space_drag.xml"),
path: AssetPathRef::BuiltIn("gui/tab/settings_tab_space_drag.xml"),
extra: Default::default(),
},
par.mp.layout,
@@ -61,7 +61,7 @@ impl State {
par.mp,
c,
"APP_SETTINGS.RESET_PLAYSPACE",
"dashboard/refresh.svg",
"@/dashboard/refresh.svg",
super::Task::ResetPlayspace,
)?;
@@ -69,7 +69,7 @@ impl State {
par.mp,
c,
"APP_SETTINGS.SAVE_PLAYSPACE_CENTER",
"dashboard/recenter.svg",
"@/dashboard/recenter.svg",
super::Task::SavePlayspaceCenter,
)?;
@@ -77,7 +77,7 @@ impl State {
par.mp,
c,
"APP_SETTINGS.RESET_PLAYSPACE_CENTER",
"dashboard/trash.svg",
"@/dashboard/trash.svg",
super::Task::ResetPlayspaceCenter,
)?;
@@ -0,0 +1,102 @@
use crate::{
tab::settings::{
SettingsMountParams, SettingsTab, UpdateExtra,
macros::{options_category, options_stat_row},
},
views::ViewUpdateParams,
};
use std::f32::consts::TAU;
use wgui::{i18n::Translation, layout::WidgetID, widget::label::WidgetLabel};
pub struct State {
id_label_rotations: WidgetID,
id_label_session_time: WidgetID,
id_label_lens_separation: WidgetID,
last_rotations: f32,
last_session_time_ms: u64,
last_ipd: f32,
}
impl SettingsTab for State {
fn update(&mut self, par: &mut ViewUpdateParams, extra: &UpdateExtra) -> anyhow::Result<()> {
let hmd_stats = &extra.hmd_stats;
let mut common = par.layout.common();
// 1 - one rotation, 2 - two rotations
// accuracy up to 0.01 rotations
let rotations = (hmd_stats.rotations_rad / TAU * 100.0).round() / 100.0;
if rotations != self.last_rotations {
self.last_rotations = rotations;
let mut label = common.state.widgets.cast_as::<WidgetLabel>(self.id_label_rotations)?;
label.set_text(&mut common, Translation::from_raw_text_string(rotations.to_string()));
}
if hmd_stats.session_time_ms != self.last_session_time_ms {
self.last_session_time_ms = hmd_stats.session_time_ms;
let mut label = common
.state
.widgets
.cast_as::<WidgetLabel>(self.id_label_session_time)?;
label.set_text(
&mut common,
Translation::from_raw_text_string(format_duration(hmd_stats.session_time_ms)),
);
}
if hmd_stats.ipd != self.last_ipd {
self.last_ipd = hmd_stats.ipd;
let mut label = common
.state
.widgets
.cast_as::<WidgetLabel>(self.id_label_lens_separation)?;
label.set_text(
&mut common,
Translation::from_raw_text_string(format!("{:.2}", hmd_stats.ipd)),
);
}
Ok(())
}
}
fn format_duration(ms: u64) -> String {
let total_secs = ms / 1000;
let h = total_secs / 3600;
let m = (total_secs % 3600) / 60;
let s = total_secs % 60;
if h > 0 {
format!("{h}:{m:02}:{s:02}")
} else {
format!("{m}:{s:02}")
}
}
impl State {
pub fn mount(par: SettingsMountParams) -> anyhow::Result<State> {
let c = options_category(
par.mp,
par.id_parent,
"APP_SETTINGS.STATISTICS",
"@/dashboard/barchart.svg",
)?;
let id_label_rotations = options_stat_row(par.mp, c, "APP_SETTINGS.ROTATIONS")?;
let id_label_session_time = options_stat_row(par.mp, c, "APP_SETTINGS.SESSION_TIME")?;
let id_label_lens_separation = options_stat_row(par.mp, c, "APP_SETTINGS.LENS_SEPARATION_MM")?;
Ok(State {
id_label_rotations,
id_label_session_time,
id_label_lens_separation,
last_rotations: f32::MIN,
last_session_time_ms: u64::MAX,
last_ipd: f32::MIN,
})
}
}
@@ -13,36 +13,29 @@ impl State {
par.mp,
par.id_parent,
"APP_SETTINGS.TROUBLESHOOTING",
"dashboard/cpu.svg",
"@/dashboard/cpu.svg",
)?;
options_danger_button(
par.mp,
c,
"APP_SETTINGS.CLEAR_PIPEWIRE_TOKENS",
"dashboard/display.svg",
"@/dashboard/display.svg",
Task::ClearPipewireTokens,
)?;
options_danger_button(
par.mp,
c,
"APP_SETTINGS.CLEAR_SAVED_STATE",
"dashboard/binary.svg",
"@/dashboard/binary.svg",
Task::ClearSavedState,
)?;
options_danger_button(
par.mp,
c,
"APP_SETTINGS.DELETE_ALL_CONFIGS",
"dashboard/circle.svg",
"@/dashboard/circle.svg",
Task::DeleteAllConfigs,
)?;
options_danger_button(
par.mp,
c,
"APP_SETTINGS.RESTART_SOFTWARE",
"dashboard/refresh.svg",
Task::RestartSoftware,
)?;
Ok(State {})
}
}
+3 -3
View File
@@ -1,7 +1,7 @@
use std::{marker::PhantomData, rc::Rc};
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::button::ComponentButton,
globals::WguiGlobals,
layout::{Layout, WidgetID},
@@ -68,7 +68,7 @@ impl<T> Tab<T> for TabWelcome<T> {
fn doc_params(globals: &WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/tab/welcome.xml"),
path: AssetPathRef::BuiltIn("gui/tab/welcome.xml"),
extra: Default::default(),
}
}
@@ -135,7 +135,7 @@ impl<T> TabWelcome<T> {
let state = wgui::parser::parse_from_assets(
&ParseDocumentParams {
globals,
path: AssetPath::BuiltIn(&format!("gui/tab/welcome_page_{}.xml", self.current_page)),
path: AssetPathRef::BuiltIn(&format!("gui/tab/welcome_page_{}.xml", self.current_page)),
extra: Default::default(),
},
layout,
+13
View File
@@ -7,3 +7,16 @@ pub mod steam_utils;
pub mod toast_manager;
pub mod wgui_simple;
pub mod whisper;
// works good enough
pub fn is_exec_installed(exec: &str) -> bool {
let mut cmd = std::process::Command::new("sh");
cmd.arg("-c");
cmd.arg(format!("command -v {}", exec));
let Ok(res) = cmd.output() else {
return false;
};
res.status.success()
}
+10 -5
View File
@@ -81,7 +81,7 @@ impl BindingsDropdown for XrInputComponent {
pub struct ParsedOpenXrInputPath {
pub side: XrInputSide,
pub subpath: XrInputSubpathKind,
pub component: XrInputComponent,
pub component: Option<XrInputComponent>,
}
impl TryFrom<&str> for ParsedOpenXrInputPath {
@@ -101,13 +101,18 @@ impl TryFrom<&str> for ParsedOpenXrInputPath {
bail!("missing input prefix");
}
let (identifier, component) = rest.rsplit_once('/').context("missing identifier or component")?;
let (identifier, component) = match rest.rsplit_once('/') {
Some((ident, comp)) if !comp.is_empty() => {
let comp = XrInputComponent::try_from(comp).context("bad component")?;
(ident, Some(comp))
}
_ => (rest, None),
};
if identifier.is_empty() || component.is_empty() {
bail!("identifier or component empty");
if identifier.is_empty() {
bail!("identifier empty");
}
let component = XrInputComponent::try_from(component).context("bad component")?;
let subpath = XrInputSubpathKind::try_from(identifier).context("bad subpath")?;
Ok(Self {
+6 -1
View File
@@ -21,6 +21,9 @@ pub struct Volume {
#[serde(rename = "front-right")]
pub front_right: Option<VolumeChannel>,
#[serde(rename = "mono")]
pub mono: Option<VolumeChannel>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
@@ -207,7 +210,7 @@ pub fn list_sources() -> anyhow::Result<Vec<Source>> {
// exclude all monitor sources
sources.retain(|source| match &source.properties.device_class {
Some(c) => c != "monitor",
None => false,
None => true, /* unknown, pass it */
});
Ok(sources)
@@ -242,6 +245,8 @@ pub fn get_source_volume(source: &Source) -> anyhow::Result<f32> {
front_left
} else if let Some(aux0) = &source.volume.aux0 {
aux0
} else if let Some(mono) = &source.volume.mono {
mono
} else {
return Ok(0.0); // fail silently
}
+54 -12
View File
@@ -3,8 +3,10 @@ use std::{
rc::{Rc, Weak},
};
use glam::Vec2;
use wgui::{
assets::AssetPath,
animation::{Animation, AnimationDuration, AnimationEasing},
assets::AssetPathRef,
components::button::ComponentButton,
event::{EventAlterables, StyleSetRequest},
globals::WguiGlobals,
@@ -12,7 +14,7 @@ use wgui::{
layout::{Layout, LayoutTask, LayoutTasks, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState},
taffy::Rect,
widget::label::WidgetLabel,
widget::{WidgetObj, label::WidgetLabel},
};
use wlx_common::config::GeneralConfig;
@@ -251,6 +253,13 @@ impl State {
}
}
struct MountPopupPrepareResult {
popup_handle: PopupHandle,
id_content: WidgetID,
id_top_bar_contents: WidgetID,
id_popup_title: WidgetID,
}
impl PopupManager {
pub fn new(params: PopupManagerParams) -> Self {
Self {
@@ -273,16 +282,17 @@ impl PopupManager {
frontend_tasks: &FrontendTasks,
popup_title: &Translation,
popup_padding: PopupPadding,
) -> anyhow::Result<(PopupHandle, WidgetID /* content widget ID */)> {
) -> anyhow::Result<MountPopupPrepareResult> {
let doc_params = &ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/view/popup_window.xml"),
path: AssetPathRef::BuiltIn("gui/view/popup_window.xml"),
extra: Default::default(),
};
let state = wgui::parser::parse_from_assets(doc_params, layout, self.parent_id)?;
let id_root = state.get_widget_id("root")?;
let id_content = state.get_widget_id("content")?;
let id_top_bar_contents = state.get_widget_id("top_bar_contents")?;
let padding = match popup_padding {
PopupPadding::Normal => 16.0_f32,
@@ -294,10 +304,11 @@ impl PopupManager {
StyleSetRequest::Padding(Rect::length(padding)),
));
{
let id_popup_title = {
let mut label_title = state.fetch_widget_as::<WidgetLabel>(&layout.state, "popup_title")?;
label_title.set_text_simple(&mut globals.get(), popup_title.clone());
}
label_title.get_id()
};
let but_back = state.fetch_component_as::<ComponentButton>("but_back")?;
@@ -338,7 +349,13 @@ impl PopupManager {
});
frontend_tasks.push(FrontendTask::RefreshPopupManager);
Ok((popup_handle, id_content))
Ok(MountPopupPrepareResult {
popup_handle,
id_content,
id_top_bar_contents,
id_popup_title,
})
}
/// Mount a new popup on top of the existing popup stack.
@@ -356,18 +373,43 @@ impl PopupManager {
anyhow::bail!("mount_popup_once called more than once");
};
let (popup_handle, id_content) =
self.mount_popup_prepare(globals, layout, frontend_tasks, &params.title, params.extra.padding)?;
let res = self.mount_popup_prepare(globals, layout, frontend_tasks, &params.title, params.extra.padding)?;
// text fade-in
Animation::effect_label_fade_in(
res.id_popup_title,
AnimationDuration::Seconds(0.25),
AnimationEasing::OutQuad,
)
.submit_l(layout);
// top bar slide
Animation::effect_slide(
res.id_top_bar_contents,
AnimationDuration::Seconds(0.5),
AnimationEasing::OutQuint,
Vec2::new(10.0, 0.0),
)
.submit_l(layout);
// content slide
Animation::effect_slide(
res.id_content,
AnimationDuration::Seconds(0.5),
AnimationEasing::OutQuint,
Vec2::new(5.0, 0.0),
)
.submit_l(layout);
// mount user-set popup content
let closed_callback = on_content_func(PopupContentFuncData {
layout,
handle: popup_handle.clone(),
id_content,
handle: res.popup_handle.clone(),
id_content: res.id_content,
config,
})?;
popup_handle.state.borrow_mut().closed_callback = Some(closed_callback);
res.popup_handle.state.borrow_mut().closed_callback = Some(closed_callback);
Ok(())
}
+9 -6
View File
@@ -1,7 +1,7 @@
use glam::{Mat4, Vec3};
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
use wgui::{
animation::{Animation, AnimationEasing},
animation::{Animation, AnimationDuration, AnimationEasing},
color::{WguiColor, WguiColorName},
components::tooltip::{TOOLTIP_BORDER_COLOR, TOOLTIP_COLOR},
i18n::Translation,
@@ -45,7 +45,9 @@ impl Drop for MountedToast {
}
}
const TOAST_DURATION_TICKS: u32 = 150;
fn def_toast_duration() -> AnimationDuration {
AnimationDuration::Seconds(2.5)
}
impl ToastManager {
pub fn new() -> Self {
@@ -116,9 +118,9 @@ impl ToastManager {
let (label, _) = layout.add_child(rect.id, label, taffy::Style { ..Default::default() })?;
// show-up animation
layout.animations.add(Animation::new(
Animation::new(
rect.id,
(TOAST_DURATION_TICKS as f32 * layout.state.theme.animation_mult) as u32,
def_toast_duration(),
AnimationEasing::Linear,
Box::new(move |common, data| {
let pos_showup = AnimationEasing::OutQuint.interpolate((data.pos * 4.0).min(1.0));
@@ -143,7 +145,8 @@ impl ToastManager {
);
common.alterables.mark_redraw();
}),
));
)
.submit_l(layout);
state.toast = Some(MountedToast {
id_root: root.id,
@@ -165,7 +168,7 @@ impl ToastManager {
if state.timeout == 0 {
state.toast = None;
state.timeout = TOAST_DURATION_TICKS;
state.timeout = def_toast_duration().to_ticks(layout.state.ticks_per_second, layout.state.theme.animation_mult);
// mount next
if let Some(content) = state.queue.pop_front() {
self.mount_toast(layout, &mut state, content)?;
+57 -10
View File
@@ -1,12 +1,16 @@
use glam::{Mat4, Vec2};
use std::rc::Rc;
use wgui::{
animation::{Animation, AnimationEasing},
assets::AssetPath,
animation::{Animation, AnimationDuration, AnimationEasing},
assets::AssetPathRef,
color::WguiColorName,
components::{self, button::ButtonClickCallback},
components::{
self,
button::{ButtonClickCallback, ButtonClickEvent, ComponentButton},
},
i18n::Translation,
layout::{Layout, LayoutTask, WidgetID},
parser::{Fetchable, ParseDocumentParams},
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
renderer_vk::{
text::{FontWeight, TextStyle, custom_glyph::CustomGlyphData},
util::centered_matrix,
@@ -17,13 +21,14 @@ use wgui::{
label::{WidgetLabel, WidgetLabelParams},
sprite::{WidgetSprite, WidgetSpriteParams},
},
windowing::context_menu,
};
pub struct CreateButtonParams<'a> {
pub id_parent: WidgetID,
pub layout: &'a mut Layout,
pub content: Translation,
pub icon_builtin: AssetPath<'a>,
pub icon_builtin: AssetPathRef<'a>,
pub on_click: ButtonClickCallback,
}
@@ -84,7 +89,12 @@ pub fn create_label_error(layout: &mut Layout, parent: WidgetID, content: String
Ok(())
}
pub fn create_icon(layout: &mut Layout, id_parent: WidgetID, size: Vec2, path: AssetPath) -> anyhow::Result<WidgetID> {
pub fn create_icon(
layout: &mut Layout,
id_parent: WidgetID,
size: Vec2,
path: AssetPathRef,
) -> anyhow::Result<WidgetID> {
let widget_sprite = WidgetSprite::create(WidgetSpriteParams {
color: Some(WguiColorName::OnBackground.into()),
glyph_data: Some(CustomGlyphData::from_assets(&layout.state.globals, path)?),
@@ -119,7 +129,7 @@ pub struct CreateLoadingParams<'a> {
pub fn create_loading(par: CreateLoadingParams) -> anyhow::Result<WidgetID> {
let doc_params = ParseDocumentParams {
globals: par.layout.state.globals.clone(),
path: AssetPath::BuiltIn("gui/t_loading.xml"),
path: AssetPathRef::BuiltIn("gui/t_loading.xml"),
extra: Default::default(),
};
@@ -140,9 +150,9 @@ pub fn create_loading(par: CreateLoadingParams) -> anyhow::Result<WidgetID> {
let id_root = data.get_widget_id("root")?;
let id_sprite_loading = data.get_widget_id("sprite_loading")?;
par.layout.animations.add(Animation::new(
Animation::new(
id_sprite_loading,
60 * 30, /* spin it for 30 seconds at most */
AnimationDuration::SecondsFixed(120.0), /* spin it for 120 seconds at most */
AnimationEasing::Linear,
Box::new(move |common, data| {
// spin it
@@ -156,7 +166,44 @@ pub fn create_loading(par: CreateLoadingParams) -> anyhow::Result<WidgetID> {
}
common.alterables.mark_redraw();
}),
));
)
.submit_l(par.layout);
Ok(id_root)
}
pub struct MountDropdownParams<'a> {
pub layout: &'a mut Layout,
pub parser_state: &'a mut ParserState,
pub doc_params: &'a ParseDocumentParams<'a>,
pub parent: WidgetID,
pub id: String,
pub params: TemplateParams,
pub current_text: Translation,
pub cells: Vec<context_menu::Cell>,
pub on_open: Box<dyn Fn(context_menu::Position, Vec<context_menu::Cell>)>,
}
pub fn mount_dropdown(par: MountDropdownParams) -> anyhow::Result<()> {
let mut params = par.params;
params.insert("id", &par.id);
par
.parser_state
.instantiate_template(par.doc_params, "DropdownButton", par.layout, par.parent, params)?;
{
let mut label = par
.parser_state
.fetch_widget_as::<WidgetLabel>(&par.layout.state, &format!("{}_value", par.id))?;
label.set_text_simple(&mut par.layout.state.globals.get(), par.current_text);
}
let btn = par.parser_state.fetch_component_as::<ComponentButton>(&par.id)?;
btn.on_click(Rc::new(move |_common, e: ButtonClickEvent| {
(par.on_open)(e.mouse_pos_absolute.into(), par.cells.clone());
Ok(())
}));
Ok(())
}
+23 -21
View File
@@ -2,7 +2,7 @@ use std::{collections::HashMap, rc::Rc, str::FromStr};
use strum::VariantNames;
use wayvr_ipc::packet_client::{PositionMode, WvrProcessLaunchParams};
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::{
ComponentTrait, button::ComponentButton, checkbox::ComponentCheckbox, radio_group::ComponentRadioGroup,
},
@@ -53,7 +53,7 @@ struct LaunchParams<'a, T> {
pub struct View {
#[allow(dead_code)]
state: ParserState,
entry: DesktopEntry,
entry: Rc<DesktopEntry>,
tasks: Tasks<Task>,
frontend_tasks: FrontendTasks,
globals: WguiGlobals,
@@ -80,7 +80,7 @@ pub struct View {
pub struct Params<'a> {
pub globals: &'a WguiGlobals,
pub entry: DesktopEntry,
pub entry: Rc<DesktopEntry>,
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
pub config: &'a GeneralConfig,
@@ -100,7 +100,7 @@ impl View {
pub fn new(params: Params) -> anyhow::Result<Self> {
let doc_params = &ParseDocumentParams {
globals: params.globals.clone(),
path: AssetPath::BuiltIn("gui/view/app_launcher.xml"),
path: AssetPathRef::BuiltIn("gui/view/app_launcher.xml"),
extra: Default::default(),
};
@@ -119,10 +119,8 @@ impl View {
{
let mut label_exec = state.fetch_widget_as::<WidgetLabel>(&params.layout.state, "label_exec")?;
label_exec.set_text_simple(
&mut params.globals.get(),
Translation::from_raw_text_string(format!("{} {}", params.entry.exec_path, params.entry.exec_args)),
);
let command = shell_words::join(params.entry.exec_argv.iter().map(|x| x.as_ref()));
label_exec.set_text_simple(&mut params.globals.get(), Translation::from_raw_text_string(command));
}
let tasks = Tasks::new();
@@ -406,14 +404,19 @@ impl View {
env.push("ELECTRON_OZONE_PLATFORM_HINT=wayland".into());
}
let args = match params.compositor_mode {
AppCompositorMode::Cage => format!("-- {} {}", params.application.exec_path, params.application.exec_args),
AppCompositorMode::Native => params.application.exec_args.to_string(),
};
let exec = match params.compositor_mode {
AppCompositorMode::Cage => "cage".to_string(),
AppCompositorMode::Native => params.application.exec_path.to_string(),
let argv = match params.compositor_mode {
AppCompositorMode::Cage => ["cage", "--"]
.iter()
.copied()
.chain(params.application.exec_argv.iter().map(|x| x.as_ref()))
.map(|x| x.to_string())
.collect::<Vec<_>>(),
AppCompositorMode::Native => params
.application
.exec_argv
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>(),
};
let pos_mode = match params.pos_mode {
@@ -423,7 +426,7 @@ impl View {
};
let mut userdata = HashMap::new();
userdata.insert("desktop-entry".to_string(), serde_json::to_string(params.application)?);
userdata.insert("desktop-entry".into(), serde_json::to_string(params.application)?);
let resolution = Self::calculate_resolution(params.res_mode, params.orientation_mode);
@@ -432,12 +435,11 @@ impl View {
params.auto_start,
WvrProcessLaunchParams {
env,
exec,
argv,
name: params.application.app_name.to_string(),
args,
resolution,
pos_mode,
icon: params.application.icon_path.as_ref().map(|x| x.as_ref().to_string()),
icon: params.application.icon_path.as_deref().map(String::from),
userdata,
},
)?;
@@ -486,7 +488,7 @@ impl View {
pub fn mount_popup(
frontend_tasks: FrontendTasks,
globals: WguiGlobals,
entry: DesktopEntry,
entry: Rc<DesktopEntry>,
popup: PopupHolder<View>,
on_app_pins_changed: Box<dyn Fn()>,
pinned_app: Option<PinnedApp>,
+36 -29
View File
@@ -1,7 +1,7 @@
use std::rc::Rc;
use wgui::{
assets::AssetPath,
assets::{AssetPathRef, AssetPathSource},
color::{WguiColor, WguiColorName},
components::{
self,
@@ -12,9 +12,9 @@ use wgui::{
globals::WguiGlobals,
i18n::Translation,
layout::{Layout, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams, strip_path_as},
task::Tasks,
widget::ConstructEssentials,
widget::{ConstructEssentials, rectangle::WidgetRectangle},
};
use crate::{
@@ -100,7 +100,7 @@ struct ProfileDisplayName {
struct SelectorCell {
key: String,
display_text: String,
icon_path: &'static str,
icon_path_builtin: &'static str,
}
struct MultiSelectorParams<'a> {
@@ -124,7 +124,7 @@ fn mount_multi_selector(params: MultiSelectorParams) -> anyhow::Result<()> {
params.ess,
components::button::Params {
text: Some(Translation::from_raw_text(&cell.display_text)),
sprite_src: Some(AssetPath::BuiltIn(cell.icon_path)),
sprite_src: Some(strip_path_as(AssetPathSource::BuiltIn, cell.icon_path_builtin).unwrap()),
color,
..Default::default()
},
@@ -211,7 +211,7 @@ fn get_profile_display_name(profile_name: &str, card: &pactl_wrapper::Card) -> P
// fallback
return ProfileDisplayName {
name: profile_name.into(),
icon_path: "dashboard/binary.svg",
icon_path: "@/dashboard/binary.svg",
is_vr: false,
};
};
@@ -221,26 +221,26 @@ fn get_profile_display_name(profile_name: &str, card: &pactl_wrapper::Card) -> P
let prof = profile_name.to_lowercase();
if prof.contains("analog") {
out_icon_path = "dashboard/minijack.svg";
out_icon_path = "@/dashboard/minijack.svg";
} else if prof.contains("iec" /* digital */) {
out_icon_path = "dashboard/binary.svg";
out_icon_path = "@/dashboard/binary.svg";
} else if prof.contains("hdmi") {
out_icon_path = "dashboard/displayport.svg";
out_icon_path = "@/dashboard/displayport.svg";
} else if prof.contains("off") {
out_icon_path = "dashboard/sleep.svg";
out_icon_path = "@/dashboard/sleep.svg";
} else if prof.contains("input") {
out_icon_path = "dashboard/microphone.svg";
out_icon_path = "@/dashboard/microphone.svg";
} else {
out_icon_path = "dashboard/volume.svg"; // Default fallback
out_icon_path = "@/dashboard/volume.svg"; // Default fallback
}
// All ports are tied to this VR headset, assign all of them to the VR icon
if is_card_mentioning_hmd(card) {
if prof.contains("mic") {
// Probably microphone
out_icon_path = "dashboard/microphone.svg";
out_icon_path = "@/dashboard/microphone.svg";
} else {
out_icon_path = "dashboard/vr.svg";
out_icon_path = "@/dashboard/vr.svg";
}
}
@@ -266,11 +266,11 @@ fn get_profile_display_name(profile_name: &str, card: &pactl_wrapper::Card) -> P
if does_string_mention_hmd_sink(product_name) {
// VR icon
out_icon_path = "dashboard/vr.svg";
out_icon_path = "@/dashboard/vr.svg";
is_vr = true;
} else {
// Monitor icon
out_icon_path = "dashboard/displayport.svg";
out_icon_path = "@/dashboard/displayport.svg";
}
break;
@@ -291,7 +291,7 @@ fn get_profile_display_name(profile_name: &str, card: &pactl_wrapper::Card) -> P
fn doc_params(globals: &WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/view/audio_settings.xml"),
path: AssetPathRef::BuiltIn("gui/view/audio_settings.xml"),
extra: Default::default(),
}
}
@@ -402,7 +402,7 @@ struct MountDeviceSliderParams<'a> {
checked: bool,
muted: bool,
disp: Option<ProfileDisplayName>,
alt_desc: String,
device_desc: String,
}
fn push_popup_speakers_set_successfully(globals: &WguiGlobals, frontend_tasks: &FrontendTasks, name: &str) {
@@ -775,22 +775,22 @@ impl View {
par.insert("device_name", &disp.name);
par.insert("device_icon", disp.icon_path);
} else {
let icon_path = if params.alt_desc.contains("WiVRn") {
"dashboard/wivrn_head_symbolic.svg"
let icon_path = if params.device_desc.contains("WiVRn") {
"@/dashboard/wivrn_head_symbolic.svg"
} else {
"dashboard/binary.svg"
"@/dashboard/binary.svg"
};
par.insert("device_name", &params.alt_desc);
par.insert("device_name", &params.device_desc);
par.insert("device_icon", icon_path);
}
par.insert(
"volume_icon",
if params.muted {
"dashboard/volume_off.svg"
"@/dashboard/volume_off.svg"
} else {
"dashboard/volume.svg"
"@/dashboard/volume.svg"
},
);
@@ -802,6 +802,13 @@ impl View {
par,
)?;
if params.checked {
let rect = data.fetch_widget(&params.layout.state, "rect")?;
let mut rect = rect.widget.cast::<WidgetRectangle>()?;
rect.set_color(&mut params.layout.common(), WguiColorName::BackgroundVariant.into());
rect.set_border_color(&mut params.layout.common(), WguiColorName::Primary.into());
}
let mut common = params.layout.common();
let checkbox = data.fetch_component_as::<ComponentCheckbox>("checkbox")?;
let btn_mute = data.fetch_component_as::<ComponentButton>("btn_mute")?;
@@ -858,7 +865,7 @@ impl View {
false
};
let alt_desc = sink.description.clone();
let device_desc = sink.description.clone();
let muted = sink.mute;
let control = Rc::new(ControlSink::new(self.tasks.clone(), self.on_update.clone(), sink));
@@ -870,7 +877,7 @@ impl View {
self.mount_device_slider(MountDeviceSliderParams {
checked,
disp,
alt_desc,
device_desc,
layout,
control,
muted,
@@ -898,7 +905,7 @@ impl View {
false
};
let alt_desc = source.description.clone();
let device_desc = source.description.clone();
let muted = source.mute;
let control = Rc::new(ControlSource::new(self.tasks.clone(), self.on_update.clone(), source));
@@ -910,7 +917,7 @@ impl View {
self.mount_device_slider(MountDeviceSliderParams {
checked,
disp,
alt_desc,
device_desc,
layout,
control,
muted,
@@ -968,7 +975,7 @@ impl View {
cells.push(SelectorCell {
key: profile_name.clone(),
display_text: disp_name.name,
icon_path: disp_name.icon_path,
icon_path_builtin: disp_name.icon_path,
});
}
+684 -111
View File
@@ -2,23 +2,19 @@ use glam::Vec2;
use std::rc::Rc;
use strum::EnumProperty;
use wgui::{
assets::AssetPath,
components::{
button::{ButtonClickEvent, ComponentButton},
slider::ComponentSlider,
},
assets::AssetPathRef,
components::{button::ComponentButton, slider::ComponentSlider},
globals::WguiGlobals,
i18n::Translation,
layout::{Layout, WidgetID},
log::LogErr,
parser::{Fetchable, ParseDocumentParams, ParserState, TemplateParams},
task::Tasks,
widget::label::WidgetLabel,
windowing::context_menu::{self, TickResult},
};
use wlx_common::{
config_io,
openxr_actions::{OneOrMany, OpenXrInputAction, OpenXrInputProfile, load_xr_input_profiles},
openxr_actions::{OneOrMany, OpenXrInputAction, OpenXrInputChordMember, OpenXrInputProfile, load_xr_input_profiles},
openxr_bindings_schema::{
DEFAULT_BUTTON_THRESHOLDS, XrControllerProfile, XrInputComponent, XrInputSide, XrInputSubpathKind,
},
@@ -39,8 +35,11 @@ use crate::{
enum Task {
Save,
Cancel,
OpenContextMenu(glam::Vec2, Vec<context_menu::Cell>),
OpenContextMenu(context_menu::Position, Vec<context_menu::Cell>),
UpdateThreshold(Rc<str>, XrInputSide, usize, f32),
AddChordMember(Rc<str>, XrInputSide),
RemoveChordMember(Rc<str>, XrInputSide, usize),
UpdateChordThreshold(Rc<str>, XrInputSide, usize, usize, f32),
}
pub struct Params<'a> {
@@ -100,53 +99,114 @@ impl ViewTrait for View {
};
threshold[i] = val;
log::warn!("UpdateThreshold {action_name} {side:?} {threshold:?}");
}
Task::AddChordMember(action_name, output_side) => {
if let Some(member) = default_chord_member(self.controller_profile, output_side) {
let cur_profile = &mut self.profiles[self.cur_profile_idx];
let action_mut = get_action_mut(cur_profile, &action_name);
action_chord_mut(action_mut, output_side)
.get_or_insert_default()
.push(member);
self.refresh(par.layout)?;
}
}
Task::RemoveChordMember(action_name, output_side, member_idx) => {
let cur_profile = &mut self.profiles[self.cur_profile_idx];
let action_mut = get_action_mut(cur_profile, &action_name);
let chord = action_chord_mut(action_mut, output_side);
let chord_empty = if let Some(members) = chord.as_mut()
&& member_idx < members.len()
{
members.remove(member_idx);
members.is_empty()
} else {
false
};
if chord_empty {
*chord = None;
}
self.refresh(par.layout)?;
}
Task::UpdateChordThreshold(action_name, output_side, member_idx, i, val) => {
let cur_profile = &mut self.profiles[self.cur_profile_idx];
let action_mut = get_action_mut(cur_profile, &action_name);
if let Some(member) = action_chord_mut(action_mut, output_side)
.as_mut()
.and_then(|members| members.get_mut(member_idx))
{
let mut threshold = member.threshold().unwrap_or(DEFAULT_BUTTON_THRESHOLDS);
threshold[i] = val;
set_chord_member_threshold(member, threshold);
}
}
}
}
// Dropdown handling
if let TickResult::Action(name) = self.context_menu.tick(par.layout, &mut self.parser_state)?
&& let (Some(action), Some(action_name), Some(side), Some(value)) = {
let mut s = name.splitn(4, ';');
(s.next(), s.next(), s.next(), s.next())
} {
if let TickResult::Action(name) = self.context_menu.tick(par.layout, &mut self.parser_state)? {
let parts = name.split(';').collect::<Vec<_>>();
let cur_profile = &mut self.profiles[self.cur_profile_idx];
let action_mut = get_action_mut(cur_profile, action_name);
let side_mut = if side == "right" {
&mut action_mut.right
} else {
&mut action_mut.left
};
match action {
"clear" => {
*side_mut = None;
}
"subpath" => {
apply_subpath(side_mut, side, value, self.controller_profile);
}
"comp" => {
apply_comp(side_mut, side, value);
}
"click" => match value {
"triple" => {
action_mut.triple_click = Some(true);
action_mut.double_click = None;
match parts.as_slice() {
[action, action_name, side, value] => {
let action_mut = get_action_mut(cur_profile, action_name);
match *action {
"clear" => {
*action_binding_mut(action_mut, side) = None;
}
"subpath" => {
apply_subpath(
action_binding_mut(action_mut, side),
action_name,
side,
value,
self.controller_profile,
);
}
"comp" => {
apply_comp(action_binding_mut(action_mut, side), side, value);
}
"click" => apply_click_count(action_mut, value),
_ => log::warn!("Unknown action {action}"),
}
"double" => {
action_mut.triple_click = None;
action_mut.double_click = Some(true);
self.refresh(par.layout)?;
}
[kind, action_name, output_side, member_idx, value] => {
let (Ok(output_side), Ok(member_idx)) = (XrInputSide::try_from(*output_side), member_idx.parse::<usize>())
else {
return Ok(());
};
let action_mut = get_action_mut(cur_profile, action_name);
let Some(member) = action_chord_mut(action_mut, output_side)
.as_mut()
.and_then(|members| members.get_mut(member_idx))
else {
return Ok(());
};
match *kind {
"chord_hand" => {
if let Ok(side) = XrInputSide::try_from(*value) {
apply_chord_hand(member, side, self.controller_profile);
}
}
"chord_subpath" => {
if let Ok(subpath) = XrInputSubpathKind::try_from(*value) {
apply_chord_subpath(member, subpath, self.controller_profile);
}
}
"chord_comp" => {
if let Ok(component) = XrInputComponent::try_from(*value) {
apply_chord_component(member, component);
}
}
_ => log::warn!("Unknown chord action {kind}"),
}
_ => {
action_mut.triple_click = None;
action_mut.double_click = None;
}
},
_ => log::warn!("Unknown action {action}"),
self.refresh(par.layout)?;
}
_ => log::warn!("Malformed bindings context action: {name}"),
}
self.refresh(par.layout)?;
}
Ok(())
@@ -157,7 +217,7 @@ impl View {
pub fn new(params: Params) -> anyhow::Result<Self> {
let doc_params = &ParseDocumentParams {
globals: params.globals.clone(),
path: AssetPath::BuiltIn("gui/view/bindings.xml"),
path: AssetPathRef::BuiltIn("gui/view/bindings.xml"),
extra: Default::default(),
};
@@ -228,7 +288,7 @@ impl View {
parser_state: &mut self.parser_state,
doc_params: &ParseDocumentParams {
globals: self.globals.clone(),
path: AssetPath::BuiltIn("gui/view/bindings.xml"),
path: AssetPathRef::BuiltIn("gui/view/bindings.xml"),
extra: Default::default(),
},
layout,
@@ -413,6 +473,172 @@ fn input_controls_for_action(
},
)?;
if &*action != "scroll" {
if is_side_agnostic_action(action.as_ref()) {
chord_controls_for_output(
mp,
parent,
&action,
XrInputSide::Left,
current.left_chord.as_deref(),
click_type,
profile,
false,
)?;
} else {
for output_side in [XrInputSide::Left, XrInputSide::Right] {
if profile.find_userpath(output_side).is_none() {
continue;
}
let chord = if matches!(output_side, XrInputSide::Right) {
current.right_chord.as_deref()
} else {
current.left_chord.as_deref()
};
chord_controls_for_output(mp, parent, &action, output_side, chord, click_type, profile, true)?;
}
}
}
Ok(())
}
fn is_side_agnostic_action(action: &str) -> bool {
matches!(action, "show_hide" | "toggle_dashboard")
}
fn chord_controls_for_output(
mp: &mut MacroParams,
parent: WidgetID,
action: &Rc<str>,
output_side: XrInputSide,
members: Option<&[OpenXrInputChordMember]>,
click_type: ClickType,
profile: &XrControllerProfile,
show_output_side: bool,
) -> anyhow::Result<()> {
let header = horiz_cell(mp.layout, parent)?;
if show_output_side {
wgui_simple::create_icon(
mp.layout,
header,
Vec2::new(24.0, 24.0),
AssetPathRef::BuiltIn(&format!("dashboard/hand_{}.svg", output_side.as_ref())),
)?;
wgui_simple::create_label(mp.layout, header, side_translation(output_side))?;
}
wgui_simple::create_label(
mp.layout,
header,
Translation::from_translation_key("APP_SETTINGS.BINDINGS.CHORD"),
)?;
clicks_dropdown(mp, header, action.clone(), click_type)?;
let tasks = mp.tasks.clone();
let action_for_add = action.clone();
wgui_simple::create_button(wgui_simple::CreateButtonParams {
id_parent: header,
layout: mp.layout,
content: Translation::from_translation_key("APP_SETTINGS.BINDINGS.CHORD_ADD_INPUT"),
icon_builtin: AssetPathRef::BuiltIn("dashboard/add.svg"),
on_click: Rc::new(move |_common, _event| {
tasks.push(Task::AddChordMember(action_for_add.clone(), output_side));
Ok(())
}),
})?;
for (member_idx, member) in members.unwrap_or_default().iter().enumerate() {
chord_member_controls(mp, parent, action, output_side, member_idx, member, profile)?;
}
Ok(())
}
fn chord_member_controls(
mp: &mut MacroParams,
parent: WidgetID,
action: &Rc<str>,
output_side: XrInputSide,
member_idx: usize,
member: &OpenXrInputChordMember,
profile: &XrControllerProfile,
) -> anyhow::Result<()> {
let row = horiz_cell(mp.layout, parent)?;
let parsed = ParsedOpenXrInputPath::try_from(member.path())
.log_warn(member.path())
.ok();
let physical_side = parsed.as_ref().map(|x| x.side).unwrap_or(output_side);
chord_hand_dropdown(mp, row, action.clone(), output_side, member_idx, profile, physical_side)?;
let available_subpaths: Rc<[XrInputSubpathKind]> = profile
.find_userpath(physical_side)
.map(|user_path| {
user_path
.paths
.iter()
.filter(|x| !x.kind.get_bool("Hidden").unwrap_or_default())
.map(|x| x.kind)
.collect::<Vec<_>>()
.into()
})
.unwrap_or_default();
chord_subpath_dropdown(
mp,
row,
action.clone(),
output_side,
member_idx,
available_subpaths,
parsed.as_ref().map(|x| x.subpath),
)?;
let available_components: Rc<[XrInputComponent]> = parsed
.as_ref()
.and_then(|parsed| {
profile
.find_userpath(parsed.side)
.and_then(|user_path| user_path.find_subpath(parsed.subpath))
})
.map(|subpath| subpath.components)
.unwrap_or_default()
.into();
chord_component_dropdown(
mp,
row,
action.clone(),
output_side,
member_idx,
available_components,
parsed.and_then(|x| x.component),
)?;
let tasks = mp.tasks.clone();
let action_for_remove = action.clone();
wgui_simple::create_button(wgui_simple::CreateButtonParams {
id_parent: row,
layout: mp.layout,
content: Translation::from_raw_text(""),
icon_builtin: AssetPathRef::BuiltIn("dashboard/trash.svg"),
on_click: Rc::new(move |_common, _event| {
tasks.push(Task::RemoveChordMember(
action_for_remove.clone(),
output_side,
member_idx,
));
Ok(())
}),
})?;
// put threshold slider on its own row
if parsed.and_then(|x| x.component).is_some_and(|x| x.is_analog()) {
chord_threshold_slider(mp, parent, action.clone(), output_side, member_idx, member.threshold())?;
}
Ok(())
}
@@ -437,13 +663,6 @@ fn input_controls_for_hand(mp: &mut MacroParams, par: InputControlsForHandParams
let parent = horiz_cell(mp.layout, par.parent)?;
let available_components: Rc<[XrInputComponent]> = current
.as_ref()
.and_then(|par| user_path.find_subpath(par.subpath))
.map(|subp| subp.components)
.unwrap_or_default()
.into();
let available_subpaths: Rc<[XrInputSubpathKind]> = user_path
.paths
.iter()
@@ -460,23 +679,33 @@ fn input_controls_for_hand(mp: &mut MacroParams, par: InputControlsForHandParams
current.as_ref().map(|x| x.subpath),
)?;
if &**par.action == "scroll" {
clicks_dropdown(mp, parent, par.action.clone(), par.click_type)?;
return Ok(());
}
let available_components: Rc<[XrInputComponent]> = current
.as_ref()
.and_then(|par| user_path.find_subpath(par.subpath))
.map(|subp| subp.components)
.unwrap_or_default()
.into();
if !component_dropdown(
mp,
parent,
par.action.clone(),
par.side,
available_components,
current.as_ref().map(|x| x.component),
current.and_then(|x| x.component),
)? {
return Ok(());
}
clicks_dropdown(mp, parent, par.action.clone(), par.click_type)?;
if let Some(component) = current.as_ref().map(|x| x.component)
if let Some(component) = current.and_then(|x| x.component)
&& component.is_analog()
&& &**par.action != "scroll"
// hax
{
threshold_slider(mp, parent, par.action.clone(), par.side, par.threshold)?;
}
@@ -501,7 +730,7 @@ fn subpath_dropdown(
mp.layout,
parent,
Vec2::new(32.0, 32.0),
AssetPath::BuiltIn(&format!("dashboard/hand_{}.svg", side.as_ref())),
AssetPathRef::BuiltIn(&format!("dashboard/hand_{}.svg", side.as_ref())),
)?;
let current_text = current
@@ -552,6 +781,181 @@ fn clicks_dropdown(mp: &mut MacroParams, parent: WidgetID, action: Rc<str>, curr
Ok(())
}
fn side_translation(side: XrInputSide) -> Translation {
Translation::from_translation_key(match side {
XrInputSide::Left => "APP_SETTINGS.BINDINGS.LEFT",
XrInputSide::Right => "APP_SETTINGS.BINDINGS.RIGHT",
})
}
fn chord_hand_dropdown(
mp: &mut MacroParams,
parent: WidgetID,
action: Rc<str>,
output_side: XrInputSide,
member_idx: usize,
profile: &XrControllerProfile,
current: XrInputSide,
) -> anyhow::Result<()> {
let mut params = TemplateParams::new();
params.insert("tooltip", "APP_SETTINGS.BINDINGS.CHORD_INPUT_HAND");
params.insert("min_width", "100");
let cells = [XrInputSide::Left, XrInputSide::Right]
.into_iter()
.filter(|side| profile.find_userpath(*side).is_some())
.map(|side| {
context_menu::Cell::Button(context_menu::Button {
action_name: Some(
format!(
"chord_hand;{};{};{};{}",
action,
output_side.as_ref(),
member_idx,
side.as_ref()
)
.into(),
),
title: side_translation(side),
..Default::default()
})
})
.collect();
create_dropdown_with_cells(mp, parent, params, side_translation(current), cells)
}
fn chord_subpath_dropdown(
mp: &mut MacroParams,
parent: WidgetID,
action: Rc<str>,
output_side: XrInputSide,
member_idx: usize,
available: Rc<[XrInputSubpathKind]>,
current: Option<XrInputSubpathKind>,
) -> anyhow::Result<()> {
let mut params = TemplateParams::new();
params.insert("tooltip", "APP_SETTINGS.BINDINGS.SUBPATH");
params.insert("min_width", "100");
let current_text = current
.map(|subpath| subpath.translation())
.unwrap_or_else(|| Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"));
let cells = available
.iter()
.map(|subpath| {
context_menu::Cell::Button(context_menu::Button {
action_name: Some(
format!(
"chord_subpath;{};{};{};{}",
action,
output_side.as_ref(),
member_idx,
subpath.as_ref()
)
.into(),
),
title: subpath.translation(),
..Default::default()
})
})
.collect();
create_dropdown_with_cells(mp, parent, params, current_text, cells)
}
fn chord_component_dropdown(
mp: &mut MacroParams,
parent: WidgetID,
action: Rc<str>,
output_side: XrInputSide,
member_idx: usize,
available: Rc<[XrInputComponent]>,
current: Option<XrInputComponent>,
) -> anyhow::Result<bool> {
if available.is_empty() {
return Ok(false);
}
let mut params = TemplateParams::new();
params.insert("text", "・");
params.insert("tooltip", "APP_SETTINGS.BINDINGS.COMPONENT");
params.insert("min_width", "100");
let current_text = current
.map(|component| component.translation())
.unwrap_or_else(|| Translation::from_raw_text_rc(Default::default()));
let cells = available
.iter()
.map(|component| {
context_menu::Cell::Button(context_menu::Button {
action_name: Some(
format!(
"chord_comp;{};{};{};{}",
action,
output_side.as_ref(),
member_idx,
component.as_ref()
)
.into(),
),
title: component.translation(),
..Default::default()
})
})
.collect();
create_dropdown_with_cells(mp, parent, params, current_text, cells)?;
Ok(true)
}
fn chord_threshold_slider(
mp: &mut MacroParams,
parent: WidgetID,
action: Rc<str>,
output_side: XrInputSide,
member_idx: usize,
current: Option<[f32; 2]>,
) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
let current = current.unwrap_or(DEFAULT_BUTTON_THRESHOLDS);
let mut params = TemplateParams::new();
params.insert("id", &id);
params.insert("tooltip", "APP_SETTINGS.BINDINGS.THRESHOLD");
params.insert_str("value", format!("{:.2}", current[0]));
params.insert_str("value2", format!("{:.2}", current[1]));
params.insert("min", "0.0");
params.insert("max", "1.0");
params.insert("step", "0.1");
mp.parser_state
.instantiate_template(mp.doc_params, "ThresholdSlider", mp.layout, parent, 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| {
let threshold_idx = if matches!(e.index, wgui::components::slider::ValueIndex::Primary) {
0
} else {
1
};
tasks.push(Task::UpdateChordThreshold(
action.clone(),
output_side,
member_idx,
threshold_idx,
e.value,
));
}
}));
Ok(())
}
fn threshold_slider(
mp: &mut MacroParams,
parent: WidgetID,
@@ -594,67 +998,63 @@ fn threshold_slider(
fn create_dropdown<B: 'static + BindingsDropdown>(
mp: &mut MacroParams,
parent: WidgetID,
mut params: TemplateParams,
params: TemplateParams,
action: Rc<str>,
side: XrInputSide,
current_text: Translation,
available: Rc<[B]>,
) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
params.insert("id", &id);
let mut cells = available
.iter()
.map(|item| {
context_menu::Cell::Button(context_menu::Button {
action_name: Some(item.action_str(&action, side).into()),
title: item.translation(),
..Default::default()
})
})
.collect::<Vec<_>>();
mp.parser_state
.instantiate_template(mp.doc_params, "DropdownButton", mp.layout, parent, params)?;
{
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(), current_text);
if let Some(action_str) = B::clear_str(&action, side) {
cells.insert(
0,
context_menu::Cell::Button(context_menu::Button {
action_name: Some(action_str.into()),
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
..Default::default()
}),
);
}
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
btn.on_click(Rc::new({
let tasks = mp.tasks.clone();
let available = available.clone();
move |_common, e: ButtonClickEvent| {
let mut cells = available
.iter()
.map(|item| {
let title = item.translation();
create_dropdown_with_cells(mp, parent, params, current_text, cells)
}
context_menu::Cell {
action_name: Some(item.action_str(&action, side)),
title,
tooltip: None,
attribs: vec![],
}
})
.collect::<Vec<_>>();
if let Some(action_str) = B::clear_str(&action, side) {
cells.insert(
0,
context_menu::Cell {
action_name: Some(action_str),
title: Translation::from_translation_key("APP_SETTINGS.OPTION.NONE"),
tooltip: None,
attribs: vec![],
},
);
}
tasks.push(Task::OpenContextMenu(e.mouse_pos_absolute.unwrap_or_default(), cells));
Ok(())
}
}));
Ok(())
fn create_dropdown_with_cells(
mp: &mut MacroParams,
parent: WidgetID,
params: TemplateParams,
current_text: Translation,
cells: Vec<context_menu::Cell>,
) -> anyhow::Result<()> {
let id = mp.idx.to_string();
mp.idx += 1;
let tasks = mp.tasks.clone();
wgui_simple::mount_dropdown(wgui_simple::MountDropdownParams {
layout: mp.layout,
parser_state: mp.parser_state,
doc_params: mp.doc_params,
parent,
id,
params,
current_text,
cells,
on_open: Box::new(move |pos, cells| tasks.push(Task::OpenContextMenu(pos, cells))),
})
}
fn apply_subpath(
side_mut: &mut Option<OneOrMany<String>>,
action_name: &str,
side_str: &str,
subpath_str: &str,
profile: &XrControllerProfile,
@@ -665,6 +1065,12 @@ fn apply_subpath(
) else {
return;
};
if action_name == "scroll" {
*side_mut = Some(OneOrMany::One(format!("/user/hand/{side_str}/input/{subpath_str}")));
return;
}
let Some(subpath_obj) = profile.find_userpath(side).and_then(|p| p.find_subpath(subpath)) else {
return;
};
@@ -677,11 +1083,12 @@ fn apply_subpath(
return;
};
let mut parsed_compo = parsed.component;
if !subpath_obj.components.contains(&parsed_compo) {
parsed_compo = *subpath_obj.components.first().unwrap();
let parsed_compo = parsed.component.unwrap_or(*subpath_obj.components.first().unwrap());
if subpath_obj.components.contains(&parsed_compo) {
parsed_compo
} else {
*subpath_obj.components.first().unwrap()
}
parsed_compo
} else {
*subpath_obj.components.first().unwrap()
};
@@ -710,3 +1117,169 @@ fn apply_comp(side_mut: &mut Option<OneOrMany<String>>, side: &str, comp: &str)
*side_mut = Some(OneOrMany::One(format!("/user/hand/{side}/input/{subpath}/{comp}")));
}
fn action_chord_mut(
action: &mut OpenXrInputAction,
output_side: XrInputSide,
) -> &mut Option<Vec<OpenXrInputChordMember>> {
match output_side {
XrInputSide::Left => &mut action.left_chord,
XrInputSide::Right => &mut action.right_chord,
}
}
fn action_binding_mut<'a>(action: &'a mut OpenXrInputAction, side: &str) -> &'a mut Option<OneOrMany<String>> {
if side == "right" {
&mut action.right
} else {
&mut action.left
}
}
fn apply_click_count(action: &mut OpenXrInputAction, value: &str) {
match value {
"triple" => {
action.triple_click = Some(true);
action.double_click = None;
}
"double" => {
action.triple_click = None;
action.double_click = Some(true);
}
_ => {
action.triple_click = None;
action.double_click = None;
}
}
}
fn default_chord_member(profile: &XrControllerProfile, preferred_side: XrInputSide) -> Option<OpenXrInputChordMember> {
let other_side = match preferred_side {
XrInputSide::Left => XrInputSide::Right,
XrInputSide::Right => XrInputSide::Left,
};
for side in [preferred_side, other_side] {
let Some(user_path) = profile.find_userpath(side) else {
continue;
};
let Some(subpath) = user_path
.paths
.iter()
.find(|subpath| !subpath.kind.get_bool("Hidden").unwrap_or_default() && !subpath.components.is_empty())
else {
continue;
};
let component = *subpath.components.first()?;
return Some(OpenXrInputChordMember::Path(format!(
"/user/hand/{}/input/{}/{}",
side.as_ref(),
subpath.kind.as_ref(),
component.as_ref()
)));
}
None
}
fn set_chord_member_path(member: &mut OpenXrInputChordMember, path: String, component: XrInputComponent) {
let threshold = if component.is_analog() {
member.threshold()
} else {
None
};
*member = if threshold.is_some() {
OpenXrInputChordMember::Detailed { path, threshold }
} else {
OpenXrInputChordMember::Path(path)
};
}
fn set_chord_member_threshold(member: &mut OpenXrInputChordMember, threshold: [f32; 2]) {
*member = OpenXrInputChordMember::Detailed {
path: member.path().to_owned(),
threshold: Some(threshold),
};
}
fn apply_chord_hand(member: &mut OpenXrInputChordMember, side: XrInputSide, profile: &XrControllerProfile) {
let parsed = ParsedOpenXrInputPath::try_from(member.path()).ok();
let Some(user_path) = profile.find_userpath(side) else {
return;
};
let subpath = parsed
.and_then(|parsed| user_path.find_subpath(parsed.subpath))
.filter(|subpath| !subpath.kind.get_bool("Hidden").unwrap_or_default() && !subpath.components.is_empty())
.or_else(|| {
user_path
.paths
.iter()
.find(|subpath| !subpath.kind.get_bool("Hidden").unwrap_or_default() && !subpath.components.is_empty())
});
let Some(subpath) = subpath else {
return;
};
let component = parsed
.and_then(|parsed| parsed.component)
.filter(|component| subpath.components.contains(component))
.unwrap_or(subpath.components[0]);
let path = format!(
"/user/hand/{}/input/{}/{}",
side.as_ref(),
subpath.kind.as_ref(),
component.as_ref()
);
set_chord_member_path(member, path, component);
}
fn apply_chord_subpath(
member: &mut OpenXrInputChordMember,
subpath: XrInputSubpathKind,
profile: &XrControllerProfile,
) {
let Ok(parsed) = ParsedOpenXrInputPath::try_from(member.path()) else {
return;
};
let Some(subpath_obj) = profile
.find_userpath(parsed.side)
.and_then(|user_path| user_path.find_subpath(subpath))
else {
return;
};
let Some(first_component) = subpath_obj.components.first().copied() else {
return;
};
let component = if let Some(comp) = parsed.component {
if subpath_obj.components.contains(&comp) {
comp
} else {
first_component
}
} else {
first_component
};
let path = format!(
"/user/hand/{}/input/{}/{}",
parsed.side.as_ref(),
subpath.as_ref(),
component.as_ref()
);
set_chord_member_path(member, path, component);
}
fn apply_chord_component(member: &mut OpenXrInputChordMember, component: XrInputComponent) {
let Ok(parsed) = ParsedOpenXrInputPath::try_from(member.path()) else {
return;
};
let path = format!(
"/user/hand/{}/input/{}/{}",
parsed.side.as_ref(),
parsed.subpath.as_ref(),
component.as_ref()
);
set_chord_member_path(member, path, component);
}
+2 -2
View File
@@ -7,7 +7,7 @@ use crate::{
use std::{rc::Rc, sync::Arc};
use wgui::color::WguiColorName;
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::button::ComponentButton,
globals::WguiGlobals,
i18n::Translation,
@@ -93,7 +93,7 @@ impl View {
pub fn new(params: Params) -> anyhow::Result<Self> {
let doc_params = &ParseDocumentParams {
globals: params.globals.clone(),
path: AssetPath::BuiltIn("gui/view/color_palettes.xml"),
path: AssetPathRef::BuiltIn("gui/view/color_palettes.xml"),
extra: Default::default(),
};
+24 -5
View File
@@ -4,7 +4,7 @@ use crate::{
views::{ViewTrait, ViewUpdateParams},
};
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::button::ComponentButton,
globals::WguiGlobals,
i18n::Translation,
@@ -32,6 +32,21 @@ enum Task {
ActionClicked(&'static str),
}
pub fn get_entries_yes_no() -> Vec<ButtonEntry> {
vec![
ButtonEntry {
content: Translation::from_translation_key("YES"),
icon: "@/dashboard/check.svg",
action: "yes",
},
ButtonEntry {
content: Translation::from_translation_key("NO"),
icon: "@/dashboard/cancel.svg",
action: "no",
},
]
}
pub struct View {
tasks: Tasks<Task>,
@@ -45,13 +60,20 @@ pub struct View {
fn doc_params(globals: &WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/view/dialog_box.xml"),
path: AssetPathRef::BuiltIn("gui/view/dialog_box.xml"),
extra: Default::default(),
}
}
impl ViewTrait for View {
fn update(&mut self, _par: &mut ViewUpdateParams) -> anyhow::Result<()> {
self.tick();
Ok(())
}
}
impl View {
pub fn tick(&mut self) {
for task in self.tasks.drain() {
match task {
Task::ActionClicked(action) => {
@@ -65,11 +87,8 @@ impl ViewTrait for View {
}
}
}
Ok(())
}
}
impl View {
pub fn new(
layout: &mut Layout,
id_parent: WidgetID,
+4 -4
View File
@@ -10,7 +10,7 @@ use crate::{
use glam::Vec2;
use std::path::PathBuf;
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::button::ComponentButton,
globals::WguiGlobals,
i18n::Translation,
@@ -59,7 +59,7 @@ pub struct View {
fn doc_params(globals: &WguiGlobals) -> ParseDocumentParams<'_> {
ParseDocumentParams {
globals: globals.clone(),
path: AssetPath::BuiltIn("gui/view/download_file.xml"),
path: AssetPathRef::BuiltIn("gui/view/download_file.xml"),
extra: Default::default(),
}
}
@@ -92,7 +92,7 @@ impl ViewTrait for View {
par.layout,
self.id_loading_parent,
Vec2::splat(32.0),
AssetPath::BuiltIn("dashboard/check.svg"),
AssetPathRef::BuiltIn("dashboard/check.svg"),
)?;
// "Close window" button
@@ -114,7 +114,7 @@ impl ViewTrait for View {
par.layout,
self.id_loading_parent,
Vec2::splat(32.0),
AssetPath::BuiltIn("dashboard/error.svg"),
AssetPathRef::BuiltIn("dashboard/error.svg"),
)?;
}
Task::Close => {
+2 -2
View File
@@ -1,7 +1,7 @@
use std::rc::Rc;
use wgui::{
assets::AssetPath,
assets::AssetPathRef,
components::{
self,
button::ComponentButton,
@@ -311,7 +311,7 @@ impl ViewCommon {
fn get_placeholder_image(&mut self) -> anyhow::Result<&CustomGlyphData> {
if self.img_placeholder.is_none() {
let c = CustomGlyphData::from_assets(&self.globals, AssetPath::BuiltIn("dashboard/placeholder_cover.png"))?;
let c = CustomGlyphData::from_assets(&self.globals, AssetPathRef::BuiltIn("dashboard/placeholder_cover.png"))?;
self.img_placeholder = Some(c);
}
Loaded 100 of 305 files, more files were not shown because too many files have changed in this diff. Show more