From 71c78bd73369fc2d62d3c84d307d46267f4bbedb Mon Sep 17 00:00:00 2001 From: Pierre Kisters <1524059+lhns@users.noreply.github.com> Date: Mon, 28 Sep 2026 03:36:38 +0200 Subject: [PATCH] Dashboard options: windows.*, detent names, positive number types - dashboard.windowMaxScale / windowDistance -> dashboard.windows.maxScale / distance - windowCurvature: default -> initial, snapPixels/snapPoints -> detentPixels/detentPoints, dragThreshold -> dragThresholdPixels (also the patch's option keys; window-curvature VERSION 19); removed `snap` now points to detentPixels - types.numbers.positive/nonnegative instead of number + range assertions (step <= max, initial/detentPoints <= max and distance min <= max stay) - frame-controls patch accepts longPressMs from 300, like the option (VERSION 2) - "SteamVR dashboard patch" in descriptions, which fit into 80 columns Old names keep working with a rename warning. --- modules/dashboard-windows.nix | 67 +++++++++++++------------- modules/firefox.nix | 3 +- modules/frame-controls.nix | 9 ++-- modules/frame-controls/patch.js | 4 +- modules/steam-close-button.nix | 4 +- modules/steamvr-debugger.nix | 9 ++-- modules/window-curvature.nix | 79 ++++++++++++++++++------------- modules/window-curvature/patch.js | 46 +++++++++--------- 8 files changed, 121 insertions(+), 100 deletions(-) diff --git a/modules/dashboard-windows.nix b/modules/dashboard-windows.nix index 6e26c1b..d9a20ba 100644 --- a/modules/dashboard-windows.nix +++ b/modules/dashboard-windows.nix @@ -1,10 +1,10 @@ -# Resize and grab-distance limits of SteamVR dashboard windows. Dashboard patch -# (dashboard-windows/patch.js; "systemui" on 127.0.0.1:8087), registered only -# when an option is set; enables steamvr-debugger.nix (one SteamVR restart the -# first time). Unsetting all options reverts to stock. +# Resize and grab-distance limits of SteamVR dashboard windows. SteamVR +# dashboard patch (dashboard-windows/patch.js; "systemui" on 127.0.0.1:8087), +# registered only when an option is set; enables steamvr-debugger.nix (one +# SteamVR restart the first time). Unsetting all options reverts to stock. { config, lib, pkgs, ... }: let - cfg = config.steamFrame.dashboard; + cfg = config.steamFrame.dashboard.windows; inherit (lib) mkOption types; inherit (import ./lib { inherit pkgs; }) mkPatch; @@ -17,7 +17,7 @@ let rangeOption = kind: what: { min = mkOption { - type = types.nullOr types.number; + type = types.nullOr types.numbers.positive; default = null; description = '' Closest distance (m) ${what} can be pulled in to while grabbed; null = @@ -25,7 +25,7 @@ let ''; }; max = mkOption { - type = types.nullOr types.number; + type = types.nullOr types.numbers.positive; default = null; example = stockDistance.${kind}.max * 2; description = '' @@ -36,43 +36,49 @@ let }; effective = kind: { - min = if cfg.windowDistance.${kind}.min != null then cfg.windowDistance.${kind}.min else stockDistance.${kind}.min; - max = if cfg.windowDistance.${kind}.max != null then cfg.windowDistance.${kind}.max else stockDistance.${kind}.max; + min = if cfg.distance.${kind}.min != null then cfg.distance.${kind}.min else stockDistance.${kind}.min; + max = if cfg.distance.${kind}.max != null then cfg.distance.${kind}.max else stockDistance.${kind}.max; }; - distanceSet = lib.any (r: r.min != null || r.max != null) (lib.attrValues cfg.windowDistance); - enabled = cfg.windowMaxScale != null || distanceSet; -in { - imports = [ ./steam-ui-patches.nix ./steamvr-debugger.nix ]; + distanceSet = lib.any (r: r.min != null || r.max != null) (lib.attrValues cfg.distance); + enabled = cfg.maxScale != null || distanceSet; - options.steamFrame.dashboard = { - windowMaxScale = mkOption { - type = types.nullOr types.number; + old = [ "steamFrame" "dashboard" ]; + new = [ "steamFrame" "dashboard" "windows" ]; +in { + imports = [ + ./steam-ui-patches.nix ./steamvr-debugger.nix + (lib.mkRenamedOptionModule (old ++ [ "windowMaxScale" ]) (new ++ [ "maxScale" ])) + ] ++ lib.concatMap (kind: map (bound: + lib.mkRenamedOptionModule + (old ++ [ "windowDistance" kind bound ]) (new ++ [ "distance" kind bound ])) + [ "min" "max" ]) (lib.attrNames stockDistance); + + options.steamFrame.dashboard.windows = { + maxScale = mkOption { + type = types.nullOr types.numbers.positive; default = null; example = 4.0; description = '' Largest resize factor of SteamVR dashboard windows, relative to their default size; null = stock (2). The theater screen starts 2.8x larger, - so its limit is 2.8x this. Dashboard patch, applied immediately. + so its limit is 2.8x this. SteamVR dashboard patch, applied + immediately. ''; }; - windowDistance = { - world = rangeOption "world" "windows placed in the world (not attached to the dashboard)"; + distance = { + world = rangeOption "world" + "windows placed in the world (not attached to the dashboard)"; theater = rangeOption "theater" "the theater-mode screen"; dashboard = rangeOption "dashboard" "the dashboard itself"; }; }; config = lib.mkIf enabled { - assertions = - [ { - assertion = cfg.windowMaxScale == null || cfg.windowMaxScale > 0; - message = "steamFrame.dashboard.windowMaxScale must be positive."; - } ] - ++ map (kind: let r = effective kind; in { - assertion = r.min > 0 && r.max >= r.min; - message = "steamFrame.dashboard.windowDistance.${kind}: need 0 < min <= max (stock values fill in unset ones), got ${toString r.min}-${toString r.max}."; - }) (lib.attrNames stockDistance); + assertions = map (kind: let r = effective kind; in { + assertion = r.max >= r.min; + message = "steamFrame.dashboard.windows.distance.${kind}: need min <= max (stock values fill in unset ones), got ${toString r.min}-${toString r.max}."; + }) (lib.attrNames stockDistance); steamFrame.uiPatches.patches = [ { name = "dashboard-windows"; @@ -81,10 +87,7 @@ in { patch = mkPatch { name = "dashboard-windows"; src = ./dashboard-windows/patch.js; - opts = { - maxScale = cfg.windowMaxScale; - distance = cfg.windowDistance; - }; + opts = { inherit (cfg) maxScale distance; }; }; unpatch = ./dashboard-windows/unpatch.js; } ]; diff --git a/modules/firefox.nix b/modules/firefox.nix index ebe75e3..7b4e4b1 100644 --- a/modules/firefox.nix +++ b/modules/firefox.nix @@ -34,7 +34,8 @@ let in { options.steamFrame.firefox = { enable = lib.mkEnableOption '' - the Firefox Flatpak (org.mozilla.firefox) launcher with Steam Frame fixes''; + the Firefox Flatpak (org.mozilla.firefox) launcher with Steam Frame + fixes''; vrFullscreenFix = lib.mkOption { type = lib.types.bool; default = true; diff --git a/modules/frame-controls.nix b/modules/frame-controls.nix index 075c33a..6a42a62 100644 --- a/modules/frame-controls.nix +++ b/modules/frame-controls.nix @@ -1,7 +1,8 @@ # Move window controls between a dashboard window's bottom bar and its -# three-dot menu (long press). Dashboard patch (frame-controls/patch.js; -# "systemui" on 127.0.0.1:8087), registered only when enabled; enables -# steamvr-debugger.nix (one SteamVR restart the first time). +# three-dot menu (long press). SteamVR dashboard patch +# (frame-controls/patch.js; "systemui" on 127.0.0.1:8087), registered only +# when enabled; enables steamvr-debugger.nix (one SteamVR restart the first +# time). { config, lib, pkgs, ... }: let cfg = config.steamFrame.dashboard.frameControls; @@ -25,7 +26,7 @@ in { moving SteamVR dashboard window controls between the bottom bar and the three-dot menu: long press an icon or menu row for a "Show in bar" popup. Applies to that control in all windows, kept across SteamVR - restarts. Dashboard patch; off restores stock (next switch)''; + restarts. SteamVR dashboard patch; off restores stock (next switch)''; longPressMs = mkOption { type = types.ints.between 300 10000; default = 1500; diff --git a/modules/frame-controls/patch.js b/modules/frame-controls/patch.js index d5be84f..3412630 100644 --- a/modules/frame-controls/patch.js +++ b/modules/frame-controls/patch.js @@ -59,7 +59,7 @@ // setPlacement(name or "icon:N", 'bar' | 'menu' | null), reset(). ((find, sigs, opts) => { const NAME = 'frame-controls'; - const VERSION = 1; + const VERSION = 2; const T_SPACER = 1, T_ACTION = 2; const LS_KEY = 'sfui.frameControls.v1'; // Action icon enums (sigs.controls anchors them): names for the options. @@ -70,7 +70,7 @@ const TOOLTIP_OFFSET = '0 0.15 0.06'; // stock tooltip / menu offset (y 0.15, z 0.05), in front const o = { inBar: [], inMenu: [], longPressMs: 1500, floatInTheater: false, ...opts }; - if (!(o.longPressMs >= 200)) return `invalid options ${JSON.stringify(opts)}`; + if (!(o.longPressMs >= 300)) return `invalid options ${JSON.stringify(opts)}`; const toKey = (x) => (typeof x === 'number' ? `icon:${x}` : NAMES[x] != null ? `icon:${NAMES[x]}` : /^icon:\d+$/.test(x) ? x : null); const optMap = {}; // key -> 'bar' | 'menu' from the options for (const [list, where] of [[o.inBar, 'bar'], [o.inMenu, 'menu']]) { diff --git a/modules/steam-close-button.nix b/modules/steam-close-button.nix index ed7d6b1..eccd720 100644 --- a/modules/steam-close-button.nix +++ b/modules/steam-close-button.nix @@ -1,4 +1,4 @@ -# Close (X) button on the dashboard's Steam window. Dashboard patch +# Close (X) button on the dashboard's Steam window. SteamVR dashboard patch # (steam-close-button/patch.js; "systemui" on 127.0.0.1:8087), registered only # when enabled; enables steamvr-debugger.nix (one SteamVR restart the first time). { config, lib, pkgs, ... }: @@ -11,7 +11,7 @@ in { options.steamFrame.dashboard.steamCloseButton.enable = lib.mkEnableOption '' a Close (X) button on the dashboard's Steam window. It hides Steam (previous window or just the bar) until shown explicitly, e.g. via the - Steam tab. Dashboard patch; off removes it (next switch)''; + Steam tab. SteamVR dashboard patch; off removes it (next switch)''; config = lib.mkIf cfg.enable { steamFrame.uiPatches.patches = [ { diff --git a/modules/steamvr-debugger.nix b/modules/steamvr-debugger.nix index 1281e6e..20491e4 100644 --- a/modules/steamvr-debugger.nix +++ b/modules/steamvr-debugger.nix @@ -58,11 +58,14 @@ in { options.steamFrame.steamvrDebugger.enable = lib.mkOption { type = lib.types.bool; default = false; - defaultText = lib.literalMD "on automatically when a dashboard patch (a `steamFrame.uiPatches.patches` entry on port 8087) is enabled"; + defaultText = lib.literalMD '' + on automatically when a SteamVR dashboard patch (a + `steamFrame.uiPatches.patches` entry on port 8087) is enabled + ''; description = '' SteamVR's web helper debugger (dashboard DevTools on 127.0.0.1:8087, - VRWebHelper/DebuggerEnabled in steamvr.vrsettings), needed by dashboard - patches, which turn it on automatically. Takes effect after one SteamVR + VRWebHelper/DebuggerEnabled in steamvr.vrsettings), needed by SteamVR + dashboard patches, which turn it on automatically. Takes effect after one SteamVR restart; off resets the key at the next start. Developer Mode also forwards the port to the LAN (0.0.0.0:8088). ''; diff --git a/modules/window-curvature.nix b/modules/window-curvature.nix index 6915a53..8c69fe1 100644 --- a/modules/window-curvature.nix +++ b/modules/window-curvature.nix @@ -1,4 +1,4 @@ -# Adjustable curvature per dashboard window. Dashboard patch +# Adjustable curvature per dashboard window. SteamVR dashboard patch # (window-curvature/patch.js; "systemui" on 127.0.0.1:8087), registered only # when enabled; enables steamvr-debugger.nix (one SteamVR restart the first time). { config, lib, pkgs, ... }: @@ -7,17 +7,23 @@ let inherit (lib) mkOption types; inherit (import ./lib { inherit pkgs; }) mkPatch; - value = default: description: mkOption { - type = types.number; - inherit default description; + path = [ "steamFrame" "dashboard" "windowCurvature" ]; + rename = from: to: lib.mkRenamedOptionModule (path ++ [ from ]) (path ++ [ to ]); + + number = type: default: description: mkOption { + inherit type default description; }; in { imports = [ ./steam-ui-patches.nix ./steamvr-debugger.nix - (lib.mkRemovedOptionModule [ "steamFrame" "dashboard" "windowCurvature" "barDragRoom" ] + (lib.mkRemovedOptionModule (path ++ [ "barDragRoom" ]) "Not needed: SteamVR keeps sending the bar's coordinates past its edge during a drag.") - (lib.mkRemovedOptionModule [ "steamFrame" "dashboard" "windowCurvature" "snap" ] - "Snapping is a detent in drag pixels now: use steamFrame.dashboard.windowCurvature.snapPixels.") + (lib.mkRemovedOptionModule (path ++ [ "snap" ]) + "Snapping is a detent in drag pixels now: use steamFrame.dashboard.windowCurvature.detentPixels.") + (rename "default" "initial") + (rename "snapPixels" "detentPixels") + (rename "snapPoints" "detentPoints") + (rename "dragThreshold" "dragThresholdPixels") ]; options.steamFrame.dashboard.windowCurvature = { @@ -26,48 +32,56 @@ in { Curvature" menu row (shows the value) or bar button: click toggles curved/flat, drag up/down sets it live. Values are relative to the stock curve (1 = stock, 2 = half the radius, 0 = flat), kept per window until - SteamVR restarts. Dashboard patch; off restores stock (next switch)''; - default = value 1.0 '' + SteamVR restarts. SteamVR dashboard patch; off restores stock (next + switch)''; + initial = number types.numbers.nonnegative 1.0 '' Curvature a world/hand window (stock: flat) gets when first curved. Dashboard and theater windows start at 1, keeping the docked Steam window concentric with the bar. ''; - 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."; - snapPixels = mkOption { + max = number types.numbers.positive 3.0 '' + Largest curvature the control goes to (relative to the stock curve). + ''; + step = number types.numbers.positive 0.05 '' + Step the value is rounded to while dragging. + ''; + detentPixels = mkOption { 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. + Width of the detent at each of `detentPoints`, 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 { - type = types.listOf types.number; + detentPoints = mkOption { + type = types.listOf types.numbers.nonnegative; default = [ 0 1.0 ]; - description = "Values with a detent while dragging (0 = flat, 1 = stock curve)."; + description = '' + Values with a detent while dragging (0 = flat, 1 = stock curve). + ''; }; - dragThreshold = mkOption { + dragThresholdPixels = mkOption { type = types.ints.unsigned; default = 8; description = '' Vertical laser travel (menu px) that turns a press into a drag. ''; }; - dragPixelsPerUnit = value 120 '' + dragPixelsPerUnit = number types.numbers.positive 120 '' Menu pixels per 1.0 of curvature (6 px per 0.05 step). The laser stops 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 60 '' + barDragPixelsPerUnit = number types.numbers.positive 60 '' Bar pixels per 1.0 of curvature on the bottom-bar button. ''; haptics = mkOption { type = types.bool; default = true; description = '' - Controller haptics while dragging (steps, detents, 0/`max` edges); the dashboard's own hover clicks are muted during a drag. + Controller haptics while dragging (steps, detents, 0/`max` edges); + the dashboard's own hover clicks are muted during a drag. ''; }; }; @@ -75,20 +89,16 @@ in { config = lib.mkIf cfg.enable { assertions = [ { - assertion = cfg.max > 0 && cfg.step > 0 && cfg.step <= cfg.max; - message = "steamFrame.dashboard.windowCurvature: need max > 0 and 0 < step <= max, got max ${builtins.toJSON cfg.max}, step ${builtins.toJSON cfg.step}."; + assertion = cfg.step <= cfg.max; + message = "steamFrame.dashboard.windowCurvature: need step <= max, got max ${builtins.toJSON cfg.max}, step ${builtins.toJSON cfg.step}."; } { - assertion = cfg.default >= 0 && cfg.default <= cfg.max; - message = "steamFrame.dashboard.windowCurvature.default must be within 0 .. max (${builtins.toJSON cfg.max}), got ${builtins.toJSON cfg.default}."; + assertion = cfg.initial <= cfg.max; + message = "steamFrame.dashboard.windowCurvature.initial must be within 0 .. max (${builtins.toJSON cfg.max}), got ${builtins.toJSON cfg.initial}."; } { - assertion = lib.all (p: p >= 0 && p <= cfg.max) cfg.snapPoints; - message = "steamFrame.dashboard.windowCurvature: snapPoints must be within 0 .. max (${builtins.toJSON cfg.max})."; - } - { - assertion = cfg.dragPixelsPerUnit > 0 && cfg.barDragPixelsPerUnit > 0; - message = "steamFrame.dashboard.windowCurvature: dragPixelsPerUnit and barDragPixelsPerUnit must be positive."; + assertion = lib.all (p: p <= cfg.max) cfg.detentPoints; + message = "steamFrame.dashboard.windowCurvature: detentPoints must be within 0 .. max (${builtins.toJSON cfg.max})."; } ]; @@ -99,7 +109,10 @@ in { patch = mkPatch { name = "window-curvature"; src = ./window-curvature/patch.js; - opts = removeAttrs cfg [ "enable" "snap" "barDragRoom" ]; + opts = { + inherit (cfg) initial max step detentPixels detentPoints + dragThresholdPixels dragPixelsPerUnit barDragPixelsPerUnit haptics; + }; }; unpatch = ./window-curvature/unpatch.js; } ]; diff --git a/modules/window-curvature/patch.js b/modules/window-curvature/patch.js index 8714f76..c30af04 100644 --- a/modules/window-curvature/patch.js +++ b/modules/window-curvature/patch.js @@ -6,8 +6,8 @@ // curve); dragging up/down with the laser sets the curvature live. // // Target: SteamVR dashboard (vrwebhelper, DevTools 127.0.0.1:8087, title -// "systemui"). mkPatch patch (see lib/default.nix); opts: { default, max, -// step, snapPixels, snapPoints, dragThreshold, dragPixelsPerUnit, +// "systemui"). mkPatch patch (see lib/default.nix); opts: { initial, max, +// step, detentPixels, detentPoints, dragThresholdPixels, dragPixelsPerUnit, // barDragPixelsPerUnit, haptics }. // // Stock curvature (frame.curvature, systemui's `curvature` component): @@ -26,7 +26,7 @@ // Values per window (key: first overlay key) in // window.__sfuiWindowCurvatureState (schema 1: { values, log }); kept across // re-patch and unpatch, not across a dashboard reload. Without a stored value: -// opts.default in the world or on a hand, 1 when docked in the dashboard or +// opts.initial in the world or on a hand, 1 when docked in the dashboard or // theater (so the Steam window stays concentric with the dashboard bar). // // Bar button: the bar panel (#legacy-frame-controls-) is one button @@ -36,18 +36,18 @@ // origin reach the compositor at different times). // // 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. +// step. Detent points hold in drag distance: the value stays there for +// opts.detentPixels of travel, then continues, so no value is skipped. // // 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 detent points, // 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 // owns press-and-drag on its controls: // - Every element it drives has the class `sfui-curv-ctl`. -// - When a press becomes a drag (opts.dragThreshold px vertical) it +// - When a press becomes a drag (opts.dragThresholdPixels px vertical) it // dispatches a bubbling CustomEvent `sfui-curv-dragstart` on the element // (detail { frameID, where: 'menu' | 'bar' }); when that drag ends // (release or cancelPress), `sfui-curv-dragend`. @@ -64,18 +64,18 @@ // dragValue(v0, dy, ppu, cur). ((find, sigs, opts, hooks) => { const NAME = 'window-curvature'; - const VERSION = 18; + const VERSION = 19; const FLAT = 999; // origin distances >= this are "flat" 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 o = { - default: 1, max: 3, step: 0.05, snapPixels: 24, snapPoints: [0, 1], dragThreshold: 8, dragPixelsPerUnit: 120, + initial: 1, max: 3, step: 0.05, detentPixels: 24, detentPoints: [0, 1], dragThresholdPixels: 8, dragPixelsPerUnit: 120, barDragPixelsPerUnit: 60, haptics: true, ...opts, }; - 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) && - o.dragThreshold >= 0 && o.dragPixelsPerUnit > 0 && o.barDragPixelsPerUnit > 0 && + if (!(o.max > 0 && o.step > 0 && o.step <= o.max && o.initial >= 0 && o.initial <= o.max && o.detentPixels >= 0 && + Array.isArray(o.detentPoints) && o.detentPoints.every((p) => p >= 0 && p <= o.max) && + o.dragThresholdPixels >= 0 && o.dragPixelsPerUnit > 0 && o.barDragPixelsPerUnit > 0 && typeof o.haptics === 'boolean')) return `invalid options ${JSON.stringify(opts)}`; const id = JSON.stringify([VERSION, o]); @@ -120,26 +120,26 @@ const keyOf = (f) => f.associatedSummonOverlayKeys?.[0] ?? `frame:${f.frameID}`; const dockOf = (f) => f.docking?.visualDockLocation ?? f.docking?.dockLocation; const strength = (f) => S.values[keyOf(f)] ?? - ([DOCK.LeftHand, DOCK.RightHand, DOCK.World].includes(dockOf(f)) ? o.default : 1); + ([DOCK.LeftHand, DOCK.RightHand, DOCK.World].includes(dockOf(f)) ? o.initial : 1); const curved = (f) => !!curvatureOf(f)?.shouldCurve; const shown = (f) => (curved(f) ? strength(f) : 0); // Value for a drag of dy px (up = positive) from v0 at ppu px per unit, or - // null to keep cur. Snap points are detents in drag distance: reaching one - // (or starting on it) holds the value there for snapPixels of travel, then - // it continues from the point, so no values are skipped. Off a snap point + // null to keep cur. Detent points hold in drag distance: reaching one + // (or starting on it) holds the value there for detentPixels of travel, + // then it continues from the point, so no values are skipped. Off a point // the value is rounded to step; a change of less than 0.6 steps away from // cur is ignored (laser jitter at a step boundary). const dragValue = (v0, dy, ppu, cur) => { const dir = Math.sign(dy); 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)); + const points = o.detentPoints.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; + if (rest <= o.detentPixels) { held = p; rest = 0; break; } + rest -= o.detentPixels; } const target = held ?? v + dir * rest / ppu; const nv = clamp(held ?? round(target)); @@ -169,7 +169,7 @@ 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 - : o.snapPoints.includes(v) ? HAPTIC.Snap : HAPTIC.Sliding); + : o.detentPoints.includes(v) ? HAPTIC.Snap : HAPTIC.Sliding); // ---- scene graph --------------------------------------------------------------------- // Origin node ids may carry a "::" (sub-scene); match the suffix. @@ -338,7 +338,7 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; } // Presses/clicks are stopped at the element so React (root listener) never // runs the stock onClick; a press that never became a drag is a click on // mouseup. Drag is vertical and relative (the cylinder bends horizontally, - // so y barely moves as curvature changes); after dragThreshold px it + // so y barely moves as curvature changes); after dragThresholdPixels px it // re-bases (no jump). One press at a time, window capture listeners. const stop = (e) => e.stopPropagation(); const STOPPED = ['click', 'dblclick', 'mouseup', 'pointerdown', 'pointerup', 'contextmenu']; @@ -359,7 +359,7 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; } const y = e.clientY; p.last = y; if (!p.moved) { - if (Math.abs(y - p.y0) < o.dragThreshold) return; + if (Math.abs(y - p.y0) < o.dragThresholdPixels) return; p.moved = true; muteStock = true; p.c.el?.classList.add('sfui-dragging'); @@ -543,6 +543,6 @@ ${ROW}:last-child > .sfui-curv-ind { margin-bottom: -14px; } log('patched', { version: VERSION, opts: o }); resend(); queueSync(); - return `patched (default ${o.default}, max ${o.max}, step ${o.step}, snap ${o.snapPixels} px at ${o.snapPoints.join('/')}, ` + + return `patched (initial ${o.initial}, max ${o.max}, step ${o.step}, detent ${o.detentPixels} px at ${o.detentPoints.join('/')}, ` + `haptics ${o.haptics ? 'on' : 'off'})`; })