step 6: add animation and high rate update stress tests

This commit is contained in:
2026-07-02 15:06:10 +02:00
parent 1a476bc91d
commit f4716e0d19
9 changed files with 352 additions and 21 deletions

View File

@@ -25,6 +25,17 @@ def get_gauge_debug_state(tag: Tag) -> dict[str, Any]:
"config_revision": state.config_revision,
"animation_active": state.animation_state.active,
"smoothing_active": state.smoothing_state.active,
"animation": {
"start_value": state.animation_state.start_value,
"target_value": state.animation_state.target_value,
"started_at": state.animation_state.started_at,
"duration": state.animation_state.duration,
"active": state.animation_state.active,
},
"smoothing": {
"value": state.smoothing_state.value,
"active": state.smoothing_state.active,
},
}
if state.renderer is not None:
debug["renderer"] = state.renderer.debug_state()

View File

@@ -31,9 +31,16 @@ from .scales import (
)
from .sizing import effective_size, square_gauge_rect, update_measured_size
from .smoothing import advance_smoothing
from .state import DirtyFlags, GaugeState, animation_config, size_state_for_gauge, update_state_size
from .state import (
DirtyFlags,
GaugeState,
animation_config,
size_state_for_gauge,
smoothing_config,
update_state_size,
)
from .themes import GaugeStyle
from .types import SmoothingConfig, StatusState, Tag
from .types import StatusState, Tag
Rect = tuple[float, float, float, float]
@@ -97,7 +104,7 @@ class GaugeRenderer:
if state.animation_state.active:
state.displayed_value, active = advance_animation(state.animation_state, config, now)
state.animation_state.active = active
smoothing = _smoothing_config(state)
smoothing = smoothing_config(state.config)
if not state.animation_state.active and smoothing is not None and smoothing.enabled:
state.displayed_value, _ = advance_smoothing(
state.smoothing_state, state.clamped_value, smoothing
@@ -640,13 +647,6 @@ def render_attached_gauge(state: GaugeState) -> None:
state.renderer.render()
def _smoothing_config(state: GaugeState) -> SmoothingConfig | None:
smoothing = state.config.smoothing
if isinstance(smoothing, bool):
return SmoothingConfig(enabled=smoothing)
return smoothing
def _drawlist_tag(state: GaugeState) -> Tag:
return cast(Tag, state.drawlist_tag)

View File

@@ -3,6 +3,7 @@
from __future__ import annotations
import math
import time
from dataclasses import dataclass, field, replace
from enum import IntFlag, auto
from typing import Any
@@ -144,6 +145,13 @@ def animation_config(config: GaugeConfig) -> AnimationConfig | None:
return animation
def smoothing_config(config: GaugeConfig) -> SmoothingConfig | None:
smoothing = config.smoothing
if isinstance(smoothing, bool):
return SmoothingConfig(enabled=smoothing)
return smoothing
def clamp_runtime_value(value: GaugeValue, config: GaugeConfig) -> tuple[float | None, bool]:
numeric = coerce_numeric_value(value)
if numeric is None:
@@ -203,8 +211,9 @@ def get_gauge_state(tag: Tag) -> GaugeState:
raise GaugeNotFoundError(msg) from exc
def set_runtime_value(tag: Tag, value: GaugeValue, *, now: float = 0.0) -> None:
def set_runtime_value(tag: Tag, value: GaugeValue, *, now: float | None = None) -> None:
state = get_gauge_state(tag)
now = time.monotonic() if now is None else now
clamped, invalid = clamp_runtime_value(value, state.config)
state.target_value = value
state.clamped_value = clamped
@@ -215,8 +224,15 @@ def set_runtime_value(tag: Tag, value: GaugeValue, *, now: float = 0.0) -> None:
state.displayed_value, clamped, animation_config(state.config), now
)
if not state.animation_state.active:
state.displayed_value = clamped
state.smoothing_state.value = clamped
smoothing = smoothing_config(state.config)
if smoothing is not None and smoothing.enabled and clamped is not None and not invalid:
if state.smoothing_state.value is None:
state.smoothing_state.value = state.previous_displayed_value
state.smoothing_state.active = state.smoothing_state.value != clamped
else:
state.displayed_value = clamped
state.smoothing_state.value = clamped
state.smoothing_state.active = False
state.dirty |= DirtyFlags.VALUE | DirtyFlags.DYNAMIC | DirtyFlags.TEXT
render_runtime_gauge(state)