mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 06:15:09 +00:00
feat(scroll): show which scroll speeds are smooth on this panel (#710)
* feat(scroll): show which scroll speeds are smooth on this panel The Vegas Scroll Speed slider now says what the panel will do with the chosen speed and offers the nearest smooth ones to click. Backed by scroll_config.speed_advice() and GET /api/v3/config/scroll-speed-advice, which uses the refresh the display measured rather than the cap. Also stops the default 50 px/s snapping to a stepped 48 px/s (2px every 5 refreshes, 24fps) on a 120Hz panel: the low-fps penalty in solve_crisp() now loses to 60 or 40 px/s. 100Hz panels are unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(scroll): hint threw before its timer variables existed; count 25-30fps as stepped The Vegas speed hint called refreshScrollSpeedHint() before the let declarations it uses, so it never rendered (found on ledpi). And the solver's low-fps penalty stopped at 25fps, which let a measured 125.7Hz panel keep a 25.1fps 2px-every-5-refreshes scroll. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * test: add the scroll-speed-advice route to the /api/v3 URL map snapshot Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
4ddc3a3620
commit
16b566e14f
@@ -13,6 +13,7 @@ from src.common.scroll_config import ( # noqa: E402
|
||||
MAX_PIXELS_PER_FRAME,
|
||||
crisp_ladder,
|
||||
solve_crisp,
|
||||
speed_advice,
|
||||
MAX_PIXELS_PER_SECOND,
|
||||
MIN_PIXELS_PER_SECOND,
|
||||
ScrollSettings,
|
||||
@@ -465,3 +466,41 @@ class TestFrameHoldIsReportedNotApplied:
|
||||
display_manager=dm)
|
||||
assert dm.calls == [], "configure() must not apply the hold itself"
|
||||
assert settings.frame_hold == 4, "but it must report what to apply"
|
||||
|
||||
|
||||
class TestSpeedAdvice:
|
||||
def test_default_speed_on_a_120hz_panel_is_not_left_stepped(self):
|
||||
"""50 px/s used to snap to 48 (2px every 5 refreshes, 24fps)."""
|
||||
got = solve_crisp(50, 120)
|
||||
assert got.steppiness == "smooth"
|
||||
assert got.pixels_per_frame == 1
|
||||
|
||||
def test_unchanged_choices_on_a_100hz_panel(self):
|
||||
assert solve_crisp(50, 100).pixels_per_second == pytest.approx(50.0)
|
||||
assert solve_crisp(60, 100).pixels_per_second == pytest.approx(66.667, abs=0.01)
|
||||
|
||||
def test_smooth_exact_speed_needs_no_alternatives(self):
|
||||
advice = speed_advice(60, 120)
|
||||
assert advice["exact"] and advice["smooth"]
|
||||
assert advice["alternatives"] == []
|
||||
|
||||
def test_off_ladder_speed_offers_the_nearest_smooth_ones(self):
|
||||
advice = speed_advice(50, 120, 10, 200)
|
||||
assert advice["applied"]["steppiness"] == "smooth"
|
||||
offered = [a["pixels_per_second"] for a in advice["alternatives"]]
|
||||
assert offered == [40.0, 60.0]
|
||||
assert all(a["steppiness"] == "smooth" for a in advice["alternatives"])
|
||||
|
||||
def test_alternatives_stay_inside_the_requested_range(self):
|
||||
advice = speed_advice(50, 120, 45, 200)
|
||||
assert all(45 <= a["pixels_per_second"] <= 200 for a in advice["alternatives"])
|
||||
|
||||
def test_a_whole_number_near_the_panels_speed_counts_as_exact(self):
|
||||
"""The UI sends 63 for a 62.9 px/s panel."""
|
||||
assert speed_advice(63, 125.74)["exact"]
|
||||
|
||||
def test_a_measured_rate_does_not_let_a_stepped_speed_through(self):
|
||||
"""125.74Hz: 50.3px/s is 2px every 5 refreshes at 25.1fps."""
|
||||
got = solve_crisp(50, 125.74)
|
||||
assert got.steppiness == "smooth"
|
||||
assert got.pixels_per_frame == 1
|
||||
|
||||
Reference in New Issue
Block a user