mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 01:00:13 +02:00
93 lines
4.0 KiB
Markdown
93 lines
4.0 KiB
Markdown
# Window curvature
|
||
|
||
`dashboard.windowCurvature.*`, module `window-curvature` ([options](../README.md#options)).
|
||
|
||
A [SteamVR dashboard patch](ui-patches.md#steamvr-dashboard-patches).
|
||
|
||
## Problem
|
||
|
||
SteamVR dashboard windows are either curved (fixed radius) or flat, and
|
||
world windows start flat.
|
||
|
||
## What you get
|
||
|
||
The "Toggle Curvature" row of a window's three-dot menu becomes a control
|
||
showing the window's value; the same control in the bottom bar (see
|
||
[window control bar](window-control-bar.md)) works without the value, with
|
||
haptic steps.
|
||
|
||
- **click:** curved → flat, flat → stock (1);
|
||
- **drag up/down** with the laser: curvature from 0 (flat) to `max`,
|
||
relative to stock (2 = half the radius), rounded to `step`, with a detent
|
||
of `detentPixels` of drag at each of `detentPoints` (no values skipped),
|
||
and haptics (`haptics`) for detents, edges and steps. Drag distance:
|
||
`dragPixelsPerUnit` in the menu, `barDragPixelsPerUnit` on the bar button,
|
||
after `dragThresholdPixels`.
|
||
|
||
A window without its own value is shown at `initial` once curved in the
|
||
world or on a hand, at 1 in the dashboard or theater. Values are kept per
|
||
window until SteamVR restarts.
|
||
|
||
## Configuration
|
||
|
||
```nix
|
||
steamFrame.dashboard.windowCurvature = {
|
||
enable = true;
|
||
# initial = 1.0; max = 3.0; step = 0.05;
|
||
# detentPoints = [ 0 1.0 ]; detentPixels = 24;
|
||
# dragPixelsPerUnit = 60; # full range in one drag (see below)
|
||
};
|
||
```
|
||
|
||
## Limitations
|
||
|
||
- Laser only; with gamepad navigation the row is the stock toggle.
|
||
- No thumbstick scrolling (SteamVR sends no wheel events to the menu).
|
||
- The laser stops at the menu's edge (~190 px above the row): with the
|
||
default 120 px per 1.0, 0 → 1 fits into one drag, 0 → 3 takes two. Lower
|
||
`dragPixelsPerUnit` (≤ 60) for the full range in one drag.
|
||
|
||
## How it works
|
||
|
||
Stock curvature: the frame renders a transform `frame:<id>:curvature-origin`
|
||
at `z = DashboardStore.curvatureDistance` when curved, else 1000; its panels
|
||
reference it as `curvature-origin-id` and vrcompositor bends them onto a
|
||
cylinder around it (curvature = 1/radius). Those MobX properties are
|
||
non-configurable, so the patch hooks the mailbox `SendMessage`
|
||
([shared hooks](ui-patches.md#shared-method-hooks), shared with
|
||
[dashboard windows](dashboard-windows.md)) and rewrites the origin's z in
|
||
outgoing scene graphs to stock / value. On/off stays the stock toggle state,
|
||
so stock toggle and wheel always agree.
|
||
|
||
Values are kept per window (key: first overlay key) in
|
||
`window.__sfuiWindowCurvatureState`, across re-patch and unpatch, not across
|
||
a dashboard reload. The bar button uses the coordinates SteamVR keeps
|
||
sending past the pressed panel's edge while the trigger is held; the bar
|
||
panel is never resized.
|
||
|
||
Debugging: `window.__sfuiWindowCurvature.dump()` (`.log` recent events).
|
||
|
||
### Contract for other patches
|
||
|
||
For patches handling presses on the curvature controls (e.g. the window
|
||
control bar's long press); the curvature patch owns press-and-drag on them:
|
||
|
||
- Every element the patch drives has class `sfui-curv-ctl`.
|
||
- When a press becomes a drag (`dragThresholdPixels` vertical from where the
|
||
press started), a bubbling `CustomEvent` `sfui-curv-dragstart` (detail
|
||
`{ frameID, where: 'menu' | 'bar' }`) is dispatched on the element, and
|
||
`sfui-curv-dragend` when that drag ends (release or `cancelPress()`).
|
||
- `window.__sfuiWindowCurvature.scalePressDragThreshold(factor)` sets the
|
||
current press's drag threshold to `factor` × `dragThresholdPixels`, still
|
||
measured from the press start; returns whether it applied (a press that
|
||
is not yet a drag). The next press starts at 1×.
|
||
- `window.__sfuiWindowCurvature.cancelPress()` ends the current press
|
||
without its click (a drag keeps its value); returns whether a press was
|
||
active.
|
||
|
||
A patch with its own gesture lets `mousemove` through while undecided,
|
||
drops its gesture on `sfui-curv-dragstart`, may raise the threshold while
|
||
its gesture is under way, and calls `cancelPress()` when it takes the press
|
||
over. Neither side reads the other's thresholds or restores the other's
|
||
state.
|