mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 05:00:24 +02:00
window-curvature: drag detents, muted hover haptics, longer drag per step
- Snap points are detents in drag distance (snapPixels, default 24): the value holds at the point, then continues, so no value is skipped. `snap` is removed in favour of `snapPixels`. - The dashboard's own hover haptics are muted during a drag, so only the value's ticks and detents are felt. - Longer drag per step by default: 120 px per 1.0 in the menu, 60 on the bar button (step stays 0.05).
This commit is contained in:
1 parent
772681a771
commit
2feb3d405d
3 files changed
+89
-45
No files matched your search
@@ -214,13 +214,13 @@ without it.
|
|||||||
| `steamFrame.dashboard.windowCurvature.default` | number | `1.0` | Curvature of curved world/hand windows without own value (1 = stock, 0 = flat). |
|
| `steamFrame.dashboard.windowCurvature.default` | number | `1.0` | Curvature of curved world/hand windows without own value (1 = stock, 0 = flat). |
|
||||||
| `steamFrame.dashboard.windowCurvature.max` | number | `3.0` | Largest curvature. |
|
| `steamFrame.dashboard.windowCurvature.max` | number | `3.0` | Largest curvature. |
|
||||||
| `steamFrame.dashboard.windowCurvature.step` | number | `0.05` | Rounding step while dragging. |
|
| `steamFrame.dashboard.windowCurvature.step` | number | `0.05` | Rounding step while dragging. |
|
||||||
| `steamFrame.dashboard.windowCurvature.snap` | number | `0.15` | Snap distance around snap points; `0`: none. |
|
| `steamFrame.dashboard.windowCurvature.snapPixels` | unsigned int (px) | `24` | Detent at each snap point in drag pixels: the value holds there, then continues (nothing skipped); `0`: none. |
|
||||||
| `steamFrame.dashboard.windowCurvature.snapPoints` | list of numbers | `[ 0 1.0 ]` | Snap points (flat, stock). |
|
| `steamFrame.dashboard.windowCurvature.snapPoints` | list of numbers | `[ 0 1.0 ]` | Snap points (flat, stock). |
|
||||||
| `steamFrame.dashboard.windowCurvature.dragThreshold` | unsigned int (px) | `8` | Vertical travel before a press becomes a drag. |
|
| `steamFrame.dashboard.windowCurvature.dragThreshold` | unsigned int (px) | `8` | Vertical travel before a press becomes a drag. |
|
||||||
| `steamFrame.dashboard.windowCurvature.dragPixelsPerUnit` | number (px) | `60` | Drag distance per 1.0 in the menu. |
|
| `steamFrame.dashboard.windowCurvature.dragPixelsPerUnit` | number (px) | `120` | Drag distance per 1.0 in the menu (6 px per 0.05 step). |
|
||||||
| `steamFrame.dashboard.windowCurvature.barDragPixelsPerUnit` | number (px) | `30` | Drag distance per 1.0 on the bar button. |
|
| `steamFrame.dashboard.windowCurvature.barDragPixelsPerUnit` | number (px) | `60` | Drag distance per 1.0 on the bar button. |
|
||||||
| `steamFrame.dashboard.windowCurvature.barDragRoom` | unsigned int (px) | `160` | Room added above/below the bar while dragging; `0`: none. |
|
| `steamFrame.dashboard.windowCurvature.barDragRoom` | unsigned int (px) | `160` | Room added above/below the bar while dragging; `0`: none. |
|
||||||
| `steamFrame.dashboard.windowCurvature.haptics` | bool | `true` | Controller haptics while dragging. |
|
| `steamFrame.dashboard.windowCurvature.haptics` | bool | `true` | Controller haptics while dragging (steps, detents, edges); the dashboard's hover clicks are muted during a drag. |
|
||||||
| `steamFrame.dashboard.frameControls.enable` | bool | `false` | Move window controls between bar and three-dot menu, see [Window control bar](#window-control-bar-dashboardframecontrols). |
|
| `steamFrame.dashboard.frameControls.enable` | bool | `false` | Move window controls between bar and three-dot menu, see [Window control bar](#window-control-bar-dashboardframecontrols). |
|
||||||
| `steamFrame.dashboard.frameControls.longPressMs` | int, 300-10000 (ms) | `1500` | Long-press duration. |
|
| `steamFrame.dashboard.frameControls.longPressMs` | int, 300-10000 (ms) | `1500` | Long-press duration. |
|
||||||
| `steamFrame.dashboard.frameControls.inBar` | list of control names | `[ ]` | Controls that start in the bar: `keyboard`, `float`, `dashboard`, `theater`, `dockLeft`, `dockRight`, `close`, `curvature`, `"icon:<n>"`. |
|
| `steamFrame.dashboard.frameControls.inBar` | list of control names | `[ ]` | Controls that start in the bar: `keyboard`, `float`, `dashboard`, `theater`, `dockLeft`, `dockRight`, `close`, `curvature`, `"icon:<n>"`. |
|
||||||
@@ -599,8 +599,9 @@ without the value, with haptic steps.
|
|||||||
|
|
||||||
- **click:** curved → flat, flat → stock (1);
|
- **click:** curved → flat, flat → stock (1);
|
||||||
- **drag up/down** with the laser: curvature from 0 (flat) to `max`,
|
- **drag up/down** with the laser: curvature from 0 (flat) to `max`,
|
||||||
relative to stock (2 = half the radius), snapping near `snapPoints`, with
|
relative to stock (2 = half the radius), with a detent of `snapPixels` of
|
||||||
haptics for snaps, edges and steps.
|
drag at each of `snapPoints` (no values skipped), and haptics for snaps,
|
||||||
|
edges and steps.
|
||||||
|
|
||||||
A window without its own value is shown at `default` once curved in the
|
A window without its own value is shown at `default` once curved in the
|
||||||
world or on a hand, at 1 in the dashboard or theater. Values are kept per
|
world or on a hand, at 1 in the dashboard or theater. Values are kept per
|
||||||
@@ -611,8 +612,9 @@ window until SteamVR restarts. Debugging: `window.__sfuiWindowCurvature.dump()`
|
|||||||
|
|
||||||
- Laser only; with gamepad navigation the row is the stock toggle.
|
- Laser only; with gamepad navigation the row is the stock toggle.
|
||||||
- No thumbstick scrolling (SteamVR sends no wheel events to the menu).
|
- No thumbstick scrolling (SteamVR sends no wheel events to the menu).
|
||||||
- The laser stops at the menu's edge, so `dragPixelsPerUnit` × `max` should
|
- The laser stops at the menu's edge (~190 px above the row): with the
|
||||||
stay below ~190 px to reach `max` in one drag.
|
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.
|
||||||
|
|
||||||
**For patch authors** (other patches handling presses on these controls):
|
**For patch authors** (other patches handling presses on these controls):
|
||||||
every element the patch drives has class `sfui-curv-ctl`; when a press
|
every element the patch drives has class `sfui-curv-ctl`; when a press
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ let
|
|||||||
inherit default description;
|
inherit default description;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [ ./steam-ui-patches.nix ./steamvr-debugger.nix ];
|
imports = [
|
||||||
|
./steam-ui-patches.nix ./steamvr-debugger.nix
|
||||||
|
(lib.mkRemovedOptionModule [ "steamFrame" "dashboard" "windowCurvature" "snap" ]
|
||||||
|
"Snapping is a detent in drag pixels now: use steamFrame.dashboard.windowCurvature.snapPixels.")
|
||||||
|
];
|
||||||
|
|
||||||
options.steamFrame.dashboard.windowCurvature = {
|
options.steamFrame.dashboard.windowCurvature = {
|
||||||
enable = lib.mkEnableOption ''
|
enable = lib.mkEnableOption ''
|
||||||
@@ -28,13 +32,19 @@ in {
|
|||||||
'';
|
'';
|
||||||
max = value 3.0 "Largest curvature the control goes to (relative to the stock curve).";
|
max = value 3.0 "Largest curvature the control goes to (relative to the stock curve).";
|
||||||
step = value 0.05 "Step the value is rounded to while dragging.";
|
step = value 0.05 "Step the value is rounded to while dragging.";
|
||||||
snap = value 0.15 ''
|
snapPixels = mkOption {
|
||||||
Snap distance around snap points while dragging; 0 = no snapping.
|
type = types.ints.unsigned;
|
||||||
|
default = 24;
|
||||||
|
description = ''
|
||||||
|
Detent at each snap point, in pixels of drag: the value holds at the
|
||||||
|
point for this much travel, then continues from it (no values are
|
||||||
|
skipped). 0 = no detent.
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
snapPoints = mkOption {
|
snapPoints = mkOption {
|
||||||
type = types.listOf types.number;
|
type = types.listOf types.number;
|
||||||
default = [ 0 1.0 ];
|
default = [ 0 1.0 ];
|
||||||
description = "Values the drag snaps to (0 = flat, 1 = stock curve).";
|
description = "Values with a detent while dragging (0 = flat, 1 = stock curve).";
|
||||||
};
|
};
|
||||||
dragThreshold = mkOption {
|
dragThreshold = mkOption {
|
||||||
type = types.ints.unsigned;
|
type = types.ints.unsigned;
|
||||||
@@ -43,11 +53,12 @@ in {
|
|||||||
Vertical laser travel (menu px) that turns a press into a drag.
|
Vertical laser travel (menu px) that turns a press into a drag.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
dragPixelsPerUnit = value 60 ''
|
dragPixelsPerUnit = value 120 ''
|
||||||
Menu pixels per 1.0 of curvature. The laser stops at the menu's edge
|
Menu pixels per 1.0 of curvature (6 px per 0.05 step). The laser stops
|
||||||
(~190 px above the row), so 0 to `max` should fit.
|
at the menu's edge (~190 px above the row): with the default, 0 to 1
|
||||||
|
fits into one drag, the full range to `max` = 3 takes two.
|
||||||
'';
|
'';
|
||||||
barDragPixelsPerUnit = value 30 ''
|
barDragPixelsPerUnit = value 60 ''
|
||||||
Bar pixels per 1.0 of curvature on the bottom-bar button.
|
Bar pixels per 1.0 of curvature on the bottom-bar button.
|
||||||
'';
|
'';
|
||||||
barDragRoom = mkOption {
|
barDragRoom = mkOption {
|
||||||
@@ -62,7 +73,7 @@ in {
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = ''
|
description = ''
|
||||||
Controller haptics while dragging (snap points, 0/`max` edges, steps).
|
Controller haptics while dragging (steps, detents, 0/`max` edges); the dashboard's own hover clicks are muted during a drag.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -78,8 +89,8 @@ in {
|
|||||||
message = "steamFrame.dashboard.windowCurvature.default must be within 0 .. max (${builtins.toJSON cfg.max}), got ${builtins.toJSON cfg.default}.";
|
message = "steamFrame.dashboard.windowCurvature.default must be within 0 .. max (${builtins.toJSON cfg.max}), got ${builtins.toJSON cfg.default}.";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assertion = cfg.snap >= 0 && lib.all (p: p >= 0 && p <= cfg.max) cfg.snapPoints;
|
assertion = lib.all (p: p >= 0 && p <= cfg.max) cfg.snapPoints;
|
||||||
message = "steamFrame.dashboard.windowCurvature: snap must be >= 0 and snapPoints within 0 .. max (${builtins.toJSON cfg.max}).";
|
message = "steamFrame.dashboard.windowCurvature: snapPoints must be within 0 .. max (${builtins.toJSON cfg.max}).";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assertion = cfg.dragPixelsPerUnit > 0 && cfg.barDragPixelsPerUnit > 0;
|
assertion = cfg.dragPixelsPerUnit > 0 && cfg.barDragPixelsPerUnit > 0;
|
||||||
@@ -94,7 +105,7 @@ in {
|
|||||||
patch = mkPatch {
|
patch = mkPatch {
|
||||||
name = "window-curvature";
|
name = "window-curvature";
|
||||||
src = ./window-curvature/patch.js;
|
src = ./window-curvature/patch.js;
|
||||||
opts = removeAttrs cfg [ "enable" ];
|
opts = removeAttrs cfg [ "enable" "snap" ];
|
||||||
};
|
};
|
||||||
unpatch = ./window-curvature/unpatch.js;
|
unpatch = ./window-curvature/unpatch.js;
|
||||||
} ];
|
} ];
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
// window-curvature: adjustable curvature per SteamVR dashboard window. The
|
// window-curvature: adjustable curvature per SteamVR dashboard window. The
|
||||||
// stock "Toggle Curvature" control becomes a wheel: in the More Options menu
|
// stock "Toggle Curvature" control becomes a wheel: in the More Options menu
|
||||||
// row (value shown on the right) and, if the control is in the bottom bar
|
// row (value shown on the right) and, if the control is in the bottom bar
|
||||||
// (e.g. via frame-controls), on that bar button (no value; steps and snap
|
// (e.g. via frame-controls), on that bar button (no value; steps and
|
||||||
// points are felt as haptics). Click toggles (curved -> flat, flat -> stock
|
// detents are felt as haptics). Click toggles (curved -> flat, flat -> stock
|
||||||
// curve); dragging up/down with the laser sets the curvature live.
|
// curve); dragging up/down with the laser sets the curvature live.
|
||||||
//
|
//
|
||||||
// Target: SteamVR dashboard (vrwebhelper, DevTools 127.0.0.1:8087, title
|
// Target: SteamVR dashboard (vrwebhelper, DevTools 127.0.0.1:8087, title
|
||||||
// "systemui"). mkPatch patch (see lib/default.nix); opts: { default, max,
|
// "systemui"). mkPatch patch (see lib/default.nix); opts: { default, max,
|
||||||
// step, snap, snapPoints, dragThreshold, dragPixelsPerUnit,
|
// step, snapPixels, snapPoints, dragThreshold, dragPixelsPerUnit,
|
||||||
// barDragPixelsPerUnit, barDragRoom, haptics }.
|
// barDragPixelsPerUnit, barDragRoom, haptics }.
|
||||||
//
|
//
|
||||||
// Stock curvature (frame.curvature, systemui's `curvature` component):
|
// Stock curvature (frame.curvature, systemui's `curvature` component):
|
||||||
@@ -36,9 +36,14 @@
|
|||||||
// origin is compensated in outgoing scene graphs so the bar stays put in VR.
|
// origin is compensated in outgoing scene graphs so the bar stays put in VR.
|
||||||
// Laser events still mapped with the old layout are detected and shifted.
|
// Laser events still mapped with the old layout are detected and shifted.
|
||||||
//
|
//
|
||||||
|
// Dragging: value = start value + drag distance / px per unit, rounded to
|
||||||
|
// step. Snap points are detents in drag distance: the value holds there for
|
||||||
|
// opts.snapPixels of travel, then continues, so no value is skipped.
|
||||||
|
//
|
||||||
// Haptics (opts.haptics): VROverlay.TriggerOverlayHapticEffect with stock
|
// Haptics (opts.haptics): VROverlay.TriggerOverlayHapticEffect with stock
|
||||||
// EOverlayHapticEffect values: SlidingEdge at 0/max, Snap at snap points,
|
// EOverlayHapticEffect values: SlidingEdge at 0/max, Snap at snap points,
|
||||||
// Sliding otherwise (at most every 30 ms).
|
// Sliding per step (at most every 30 ms). During a drag the dashboard's own
|
||||||
|
// haptics (hover clicks on buttons the laser passes) are muted.
|
||||||
//
|
//
|
||||||
// Contract with other patches (e.g. frame-controls' long press); this patch
|
// Contract with other patches (e.g. frame-controls' long press); this patch
|
||||||
// owns press-and-drag on its controls:
|
// owns press-and-drag on its controls:
|
||||||
@@ -56,19 +61,20 @@
|
|||||||
// thresholds or restores the other's state.
|
// thresholds or restores the other's state.
|
||||||
//
|
//
|
||||||
// Debugging: window.__sfuiWindowCurvature: dump(), hits (rewrite/haptic
|
// Debugging: window.__sfuiWindowCurvature: dump(), hits (rewrite/haptic
|
||||||
// counters), log, setValue(frameID, v), controls(), cancelPress().
|
// counters), log, setValue(frameID, v), controls(), cancelPress(),
|
||||||
|
// dragValue(v0, dy, ppu, cur).
|
||||||
((find, sigs, opts, hooks) => {
|
((find, sigs, opts, hooks) => {
|
||||||
const NAME = 'window-curvature';
|
const NAME = 'window-curvature';
|
||||||
const VERSION = 11;
|
const VERSION = 16;
|
||||||
const FLAT = 999; // origin distances >= this are "flat"
|
const FLAT = 999; // origin distances >= this are "flat"
|
||||||
const ICON_OFF = 40, ICON_ON = 39; // Toggle Curvature action icons (sigs.curvatureAction)
|
const ICON_OFF = 40, ICON_ON = 39; // Toggle Curvature action icons (sigs.curvatureAction)
|
||||||
const HAPTIC = { Snap: 3, Sliding: 4, SlidingEdge: 5 }; // EOverlayHapticEffect (sigs.hapticEffects)
|
const HAPTIC = { Snap: 3, Sliding: 4, SlidingEdge: 5 }; // EOverlayHapticEffect (sigs.hapticEffects)
|
||||||
|
|
||||||
const o = {
|
const o = {
|
||||||
default: 1, max: 3, step: 0.05, snap: 0.15, snapPoints: [0, 1], dragThreshold: 8, dragPixelsPerUnit: 60,
|
default: 1, max: 3, step: 0.05, snapPixels: 24, snapPoints: [0, 1], dragThreshold: 8, dragPixelsPerUnit: 120,
|
||||||
barDragPixelsPerUnit: 30, barDragRoom: 160, haptics: true, ...opts,
|
barDragPixelsPerUnit: 60, barDragRoom: 160, haptics: true, ...opts,
|
||||||
};
|
};
|
||||||
if (!(o.max > 0 && o.step > 0 && o.step <= o.max && o.default >= 0 && o.default <= o.max && o.snap >= 0 &&
|
if (!(o.max > 0 && o.step > 0 && o.step <= o.max && o.default >= 0 && o.default <= o.max && o.snapPixels >= 0 &&
|
||||||
Array.isArray(o.snapPoints) && o.snapPoints.every((p) => p >= 0 && p <= o.max) &&
|
Array.isArray(o.snapPoints) && o.snapPoints.every((p) => p >= 0 && p <= o.max) &&
|
||||||
o.dragThreshold >= 0 && o.dragPixelsPerUnit > 0 && o.barDragPixelsPerUnit > 0 &&
|
o.dragThreshold >= 0 && o.dragPixelsPerUnit > 0 && o.barDragPixelsPerUnit > 0 &&
|
||||||
Number.isInteger(o.barDragRoom) && o.barDragRoom >= 0 && typeof o.haptics === 'boolean'))
|
Number.isInteger(o.barDragRoom) && o.barDragRoom >= 0 && typeof o.haptics === 'boolean'))
|
||||||
@@ -119,27 +125,49 @@
|
|||||||
const curved = (f) => !!curvatureOf(f)?.shouldCurve;
|
const curved = (f) => !!curvatureOf(f)?.shouldCurve;
|
||||||
const shown = (f) => (curved(f) ? strength(f) : 0);
|
const shown = (f) => (curved(f) ? strength(f) : 0);
|
||||||
|
|
||||||
// Value for a drag position (target: unrounded value under the pointer),
|
// Value for a drag of dy px (up = positive) from v0 at ppu px per unit, or
|
||||||
// or null to keep the current one: within +-snap of a snap point the value
|
// null to keep cur. Snap points are detents in drag distance: reaching one
|
||||||
// is that point, else target rounded to step; a change of less than 0.6
|
// (or starting on it) holds the value there for snapPixels of travel, then
|
||||||
// steps away from cur is ignored (laser jitter at a step boundary).
|
// it continues from the point, so no values are skipped. Off a snap point
|
||||||
const dragValue = (target, cur) => {
|
// the value is rounded to step; a change of less than 0.6 steps away from
|
||||||
const snapped = o.snapPoints.find((p) => Math.abs(target - p) <= o.snap);
|
// cur is ignored (laser jitter at a step boundary).
|
||||||
const v = clamp(snapped ?? round(target));
|
const dragValue = (v0, dy, ppu, cur) => {
|
||||||
if (v === cur || (snapped === undefined && Math.abs(target - cur) < o.step * 0.6)) return null;
|
const dir = Math.sign(dy);
|
||||||
return v;
|
let v = v0, rest = Math.abs(dy), held = null;
|
||||||
|
const points = o.snapPoints.filter((p) => (dir > 0 ? p >= v0 : p <= v0)).sort((a, b) => dir * (a - b));
|
||||||
|
for (const p of points) {
|
||||||
|
const dist = Math.abs(p - v) * ppu;
|
||||||
|
if (rest <= dist) break;
|
||||||
|
rest -= dist; v = p;
|
||||||
|
if (rest <= o.snapPixels) { held = p; rest = 0; break; }
|
||||||
|
rest -= o.snapPixels;
|
||||||
|
}
|
||||||
|
const target = held ?? v + dir * rest / ppu;
|
||||||
|
const nv = clamp(held ?? round(target));
|
||||||
|
if (nv === cur || (held === null && Math.abs(target - cur) < o.step * 0.6)) return null;
|
||||||
|
return nv;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---- haptics -------------------------------------------------------------------------
|
// ---- haptics -------------------------------------------------------------------------
|
||||||
let lastHaptic = -Infinity;
|
// While a drag runs, the dashboard's own haptics (a click whenever the laser
|
||||||
const haptic = (effect) => {
|
// enters a button, e.g. menu rows the drag passes over) are muted, so only
|
||||||
if (!o.haptics) return;
|
// the value's ticks and detents are felt. The stock function is wrapped
|
||||||
|
// once (restored by teardown); our ticks call the original.
|
||||||
|
let lastHaptic = -Infinity, muteStock = false;
|
||||||
const ov = window.VRHTML?.VROverlay;
|
const ov = window.VRHTML?.VROverlay;
|
||||||
if (typeof ov?.TriggerOverlayHapticEffect !== 'function' || typeof ov.ThisOverlayHandle !== 'function') return;
|
const stockHaptic = typeof ov?.TriggerOverlayHapticEffect === 'function'
|
||||||
|
? (ov.TriggerOverlayHapticEffect.__sfuiCurvOrig ?? ov.TriggerOverlayHapticEffect) : null;
|
||||||
|
if (stockHaptic) {
|
||||||
|
const wrapped = function (...a) { if (!muteStock) return stockHaptic.apply(this, a); };
|
||||||
|
wrapped.__sfuiCurvOrig = stockHaptic;
|
||||||
|
ov.TriggerOverlayHapticEffect = wrapped;
|
||||||
|
}
|
||||||
|
const haptic = (effect) => {
|
||||||
|
if (!o.haptics || !stockHaptic || typeof ov.ThisOverlayHandle !== 'function') return;
|
||||||
const now = performance.now();
|
const now = performance.now();
|
||||||
if (effect === HAPTIC.Sliding && now - lastHaptic < 30) return;
|
if (effect === HAPTIC.Sliding && now - lastHaptic < 30) return;
|
||||||
lastHaptic = now;
|
lastHaptic = now;
|
||||||
try { ov.TriggerOverlayHapticEffect(ov.ThisOverlayHandle(), effect); hits.haptics++; } catch (e) { log('haptic failed', String(e)); }
|
try { stockHaptic.call(ov, ov.ThisOverlayHandle(), effect); hits.haptics++; } catch (e) { log('haptic failed', String(e)); }
|
||||||
};
|
};
|
||||||
const hapticFor = (v) => haptic(v <= 0 || v >= o.max ? HAPTIC.SlidingEdge
|
const hapticFor = (v) => haptic(v <= 0 || v >= o.max ? HAPTIC.SlidingEdge
|
||||||
: o.snapPoints.includes(v) ? HAPTIC.Snap : HAPTIC.Sliding);
|
: o.snapPoints.includes(v) ? HAPTIC.Snap : HAPTIC.Sliding);
|
||||||
@@ -378,6 +406,7 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; }
|
|||||||
if (!p.moved) {
|
if (!p.moved) {
|
||||||
if (Math.abs(y - p.y0) < o.dragThreshold) return;
|
if (Math.abs(y - p.y0) < o.dragThreshold) return;
|
||||||
p.moved = true;
|
p.moved = true;
|
||||||
|
muteStock = true;
|
||||||
p.c.el?.classList.add('sfui-dragging');
|
p.c.el?.classList.add('sfui-dragging');
|
||||||
log('drag', { frame: p.c.fid, where: p.c.where });
|
log('drag', { frame: p.c.fid, where: p.c.where });
|
||||||
emit(p.c, 'sfui-curv-dragstart');
|
emit(p.c, 'sfui-curv-dragstart');
|
||||||
@@ -387,7 +416,7 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; }
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ppu = p.c.where === 'bar' ? o.barDragPixelsPerUnit : o.dragPixelsPerUnit;
|
const ppu = p.c.where === 'bar' ? o.barDragPixelsPerUnit : o.dragPixelsPerUnit;
|
||||||
const v = dragValue(p.v0 + (p.y0 - y) / ppu, shown(f));
|
const v = dragValue(p.v0, p.y0 - y, ppu, shown(f));
|
||||||
if (v === null) return;
|
if (v === null) return;
|
||||||
setValue(f, v, 'drag');
|
setValue(f, v, 'drag');
|
||||||
hapticFor(v);
|
hapticFor(v);
|
||||||
@@ -398,6 +427,7 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; }
|
|||||||
// Ends the press; `release` of a press that never moved is a click.
|
// Ends the press; `release` of a press that never moved is a click.
|
||||||
function endPress(why) {
|
function endPress(why) {
|
||||||
const p = press;
|
const p = press;
|
||||||
|
muteStock = false;
|
||||||
if (!p) return false;
|
if (!p) return false;
|
||||||
press = null;
|
press = null;
|
||||||
window.removeEventListener('mousemove', onMove, true);
|
window.removeEventListener('mousemove', onMove, true);
|
||||||
@@ -526,6 +556,7 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; }
|
|||||||
|
|
||||||
const teardown = () => {
|
const teardown = () => {
|
||||||
endPress('teardown');
|
endPress('teardown');
|
||||||
|
if (stockHaptic && ov.TriggerOverlayHapticEffect?.__sfuiCurvOrig === stockHaptic) ov.TriggerOverlayHapticEffect = stockHaptic;
|
||||||
for (const d of disposers.splice(0)) d();
|
for (const d of disposers.splice(0)) d();
|
||||||
clearTimeout(syncTimer); clearTimeout(resendTimer);
|
clearTimeout(syncTimer); clearTimeout(resendTimer);
|
||||||
for (const key of [...controls.keys()]) removeControl(key);
|
for (const key of [...controls.keys()]) removeControl(key);
|
||||||
@@ -560,6 +591,6 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; }
|
|||||||
log('patched', { version: VERSION, opts: o });
|
log('patched', { version: VERSION, opts: o });
|
||||||
resend();
|
resend();
|
||||||
queueSync();
|
queueSync();
|
||||||
return `patched (default ${o.default}, max ${o.max}, step ${o.step}, snap ±${o.snap} at ${o.snapPoints.join('/')}, ` +
|
return `patched (default ${o.default}, max ${o.max}, step ${o.step}, snap ${o.snapPixels} px at ${o.snapPoints.join('/')}, ` +
|
||||||
`haptics ${o.haptics ? 'on' : 'off'})`;
|
`haptics ${o.haptics ? 'on' : 'off'})`;
|
||||||
})
|
})
|
||||||
Reference in new issue
Block a user