Favorite menu cleanup

This commit is contained in:
firestarsdog
2026-09-27 22:45:20 -04:00
parent 7b4643208e
commit b1e7a5c46e
3 changed files with 93 additions and 8 deletions
@@ -70,11 +70,13 @@ class FavoriteRadialMenu:
def __init__(self, params: Any, params_memory: Any,
option_provider: Callable[[], Iterable[dict[str, Any]]], *,
clock: Callable[[], float] = time.monotonic):
clock: Callable[[], float] = time.monotonic,
cache_render_texture: Callable[..., Any] | None = None):
self._params = params
self._params_memory = params_memory
self._option_provider = option_provider
self._clock = clock
self._cache_render_texture = cache_render_texture
self._state = self.STATE_COLLAPSED
self._selected_slot: int | None = None
@@ -723,11 +725,48 @@ class FavoriteRadialMenu:
x0 = self._rect.x
y0 = self._rect.y + self._rect.height
is_pressed = self._corner_press is not None
size = 150.0 * scale
texture_size = max(1, int(round(size)))
texture_scale = texture_size / 150.0
# Cache the hint's two appearances instead of rebuilding the mesh every frame.
cache = self._cache_render_texture
texture = None
if cache is not None:
variant = "pressed" if is_pressed else "idle"
texture = cache(
f"favorite-corner-hint:{texture_size}:{variant}",
texture_size,
texture_size,
lambda: FavoriteRadialMenu._draw_corner_hint_geometry(
texture_scale, is_pressed, 0.0, float(texture_size),
),
)
if texture is not None:
rl.begin_blend_mode(rl.BlendMode.BLEND_ALPHA_PREMULTIPLY)
try:
rl.draw_texture_pro(
texture,
rl.Rectangle(0, 0, texture_size, -texture_size),
rl.Rectangle(x0, y0 - size, size, size),
rl.Vector2(0, 0),
0.0,
rl.WHITE,
)
finally:
rl.end_blend_mode()
return
self._draw_corner_hint_geometry(scale, is_pressed, x0, y0)
@classmethod
def _draw_corner_hint_geometry(cls, scale: float, is_pressed: bool,
x0: float, y0: float) -> None:
size = 150.0 * scale
steps = 48
# 1. Precompute edge vertices to minimize per-frame allocations
# Build the gradient mesh once for this cached appearance.
v_origin = rl.Vector2(x0, y0)
inv_steps = 1.0 / steps
pts_top = [rl.Vector2(x0, y0 - size * (k * inv_steps)) for k in range(steps + 1)]
@@ -747,7 +786,7 @@ class FavoriteRadialMenu:
purple_a = int(purple_max_alpha * ((1.0 - t_mid) ** 1.75))
for col in (rl.Color(8, 6, 18, base_a) if base_a > 0 else None,
self._sample_aether_color(t_mid, purple_a) if purple_a > 0 else None):
cls._sample_aether_color(t_mid, purple_a) if purple_a > 0 else None):
if col is None:
continue
if i == 0:
@@ -757,8 +796,8 @@ class FavoriteRadialMenu:
rl.draw_triangle(v_tb, v_ra, v_rb, col)
# 3. Ultra-Polished Frosted-Glass Vector Arrow (Nestled deep in purple corner)
center = self.corner_center(self._rect)
cx, cy = center.x, center.y
inset = (cls.CORNER_HINT_RING_RADIUS + cls.CORNER_HINT_EDGE_MARGIN) * scale
cx, cy = x0 + inset, y0 - inset
tip = rl.Vector2(cx + 15.0 * scale, cy - 15.0 * scale)
tail = rl.Vector2(cx - 15.0 * scale, cy + 15.0 * scale)
@@ -52,6 +52,7 @@ class StarPilotOnroadView(AugmentedRoadView):
ui_state.ui_params,
ui_state.params_memory,
self._favorite_slot_options,
cache_render_texture=gui_app.cached_render_texture,
)
self._favorite_input_consumed = False
@@ -77,14 +77,15 @@ def _open_picker(menu, rect, slot_index=0):
assert menu.state == FavoriteRadialMenu.STATE_PICKER
def _menu(clock, options=None):
def _menu(clock, options=None, cache_render_texture=None):
params = FakeParams()
memory = FakeParams()
options = options or [
{"key": "FeatureToggle", "label": "Feature Toggle", "description": "The primary test setting.", "section": "Testing"},
{"key": "OtherToggle", "label": "Other Toggle", "description": "Another test setting.", "section": "Testing"},
]
return FavoriteRadialMenu(params, memory, lambda: options, clock=lambda: clock[0]), params, memory
return FavoriteRadialMenu(params, memory, lambda: options, clock=lambda: clock[0],
cache_render_texture=cache_render_texture), params, memory
def test_radial_menu_opens_from_corner_tap_and_arranges_three_slots_on_an_arc():
@@ -116,6 +117,50 @@ def test_corner_hint_keeps_visible_ring_near_content_corner():
assert menu._contains(menu._corner_touch_zone_for(rect), center)
def test_corner_hint_caches_idle_and_pressed_art(monkeypatch):
clock = [0.0]
cached = {}
requests = []
geometry = []
draws = []
blend_modes = []
def cache(key, width, height, render):
requests.append((key, width, height, render))
return cached.get(key)
menu, _params, _memory = _menu(clock, cache_render_texture=cache)
menu._rect = rl.Rectangle(0, 0, 2160, 1080)
monkeypatch.setattr(FavoriteRadialMenu, "_draw_corner_hint_geometry",
staticmethod(lambda *args: geometry.append(args)))
monkeypatch.setattr(rl, "draw_texture_pro", lambda *args: draws.append(args))
monkeypatch.setattr(rl, "begin_blend_mode", blend_modes.append)
monkeypatch.setattr(rl, "end_blend_mode", lambda: None)
menu._draw_corner_hint()
idle_key, width, height, render_idle = requests[-1]
assert idle_key == "favorite-corner-hint:150:idle"
assert (width, height) == (150, 150)
assert geometry == [(1.0, False, 0, 1080)] # Original drawing remains the cache-miss fallback.
render_idle()
assert geometry[-1] == (1.0, False, 0.0, 150.0) # Cached art is drawn in local texture coordinates.
texture = object()
cached[idle_key] = texture
menu._draw_corner_hint()
assert len(geometry) == 2
assert draws[-1][0] is texture
destination = draws[-1][2]
assert (destination.x, destination.y, destination.width, destination.height) == (0, 930, 150, 150)
assert blend_modes == [rl.BlendMode.BLEND_ALPHA_PREMULTIPLY]
menu._corner_press = object()
menu._draw_corner_hint()
assert requests[-1][0] == "favorite-corner-hint:150:pressed"
assert geometry[-1] == (1.0, True, 0, 1080)
def test_radial_menu_opens_from_diagonal_inward_swipe_and_auto_collapses_after_six_seconds():
clock = [0.0]
menu, _params, _memory = _menu(clock)