pyqt_reactive.animation

Animation and visual effects system.

Game-engine inspired flash animation system with O(1) per-window performance for visual feedback on value changes.

class pyqt_reactive.animation.FlashConfig(base_color_rgb: Tuple[int, int, int] = (255, 255, 255), flash_alpha: int = 255, fade_in_s: float = 0.2, hold_s: float = 0.05, fade_out_s: float = 0.6, frame_ms: int | None = None, use_opengl: bool = False, target_fps: int | None = None, max_fps: int | None = 60)[source]

Flash animation tuning knobs with automatic screen refresh rate detection.

base_color_rgb: Tuple[int, int, int] = (255, 255, 255)
flash_alpha: int = 255
fade_in_s: float = 0.2
hold_s: float = 0.05
fade_out_s: float = 0.6
frame_ms: int | None = None
use_opengl: bool = False
target_fps: int | None = None
max_fps: int | None = 60
__post_init__()[source]

Calculate frame_ms from target_fps or auto-detect screen refresh rate.

__init__(base_color_rgb: Tuple[int, int, int] = (255, 255, 255), flash_alpha: int = 255, fade_in_s: float = 0.2, hold_s: float = 0.05, fade_out_s: float = 0.6, frame_ms: int | None = None, use_opengl: bool = False, target_fps: int | None = None, max_fps: int | None = 60) None
pyqt_reactive.animation.get_flash_config() FlashConfig[source]

Return singleton flash config.

pyqt_reactive.animation.FlashMixin

alias of VisualUpdateMixin

class pyqt_reactive.animation.WindowFlashOverlay(window: QWidget)[source]

Transparent overlay that renders ALL flash effects for an entire window.

TRUE GAME ENGINE ARCHITECTURE: - ONE instance per top-level window (QMainWindow/QDialog) - Renders ALL element types (groupboxes, tree items, list items) in ONE paintEvent - Elements register via FlashElement with geometry callbacks - Scales O(1) per window regardless of element count or type

VIEWPORT CULLING: Elements outside visible scroll areas return None from their geometry callback and are skipped.

classmethod get_for_window(widget: QWidget) WindowFlashOverlay | None[source]

Get or create the overlay for a top-level window (factory method).

Automatically chooses between OpenGL and QPainter based on config and availability.

Returns None if: - Widget is not yet in a proper window hierarchy - Widget has been deleted (RuntimeError from Qt C++ layer)

classmethod cleanup_window(window: QWidget) None[source]

Remove overlay for a window (call when window closes).

__init__(window: QWidget)[source]
register_element(element: FlashElement) None[source]

Register a flashable element. Multiple elements can share the same key.

CRITICAL: Deduplicate based on (key, source_id) to prevent duplicate registrations while allowing multiple element types (tree item + groupbox) for the same key.

unregister_element(key: str) None[source]

Unregister all elements for a key.

eventFilter(obj, event)[source]

Catch scroll/resize/layout events to invalidate geometry cache.

invalidate_cache()[source]

Public method to invalidate geometry cache.

Call this when programmatically scrolling (e.g., scroll_to_section via tree item click).

classmethod invalidate_cache_for_widget(widget: QWidget) None[source]

Invalidate geometry cache for the overlay covering a widget’s window.

Convenience method for programmatic scroll/resize operations.

resizeEvent(event) None[source]

Resize to cover entire window.

is_element_in_viewport(key: str) bool[source]

Check if any element for this key is visible (for viewport culling).

get_visible_keys() Set[str][source]

Get set of keys for elements currently visible in viewport.

get_visible_keys_for(keys: Set[str]) Set[str][source]

Get visible keys from a specific subset (avoids scanning all elements).

PERFORMANCE FIX: Use cached geometry instead of recalculating every frame. This eliminates expensive coordinate transformations during animation.

paintEvent(event) None[source]

GAME ENGINE: Render ALL flash effects in ONE paint call.

CARMACK OPTIMIZATION: Cache ALL geometry and QRegion objects. Recompute ONLY on scroll/resize events. During smooth animation: ZERO coordinate transformations, ZERO QRegion operations.

class pyqt_reactive.animation.OverlayGeometryCache(valid: bool = False, scroll_clip_rects: List[QRect] = <factory>, element_rects: Dict[str, ~typing.List[~typing.Tuple[~PyQt6.QtCore.QRect, float] | None]]=<factory>, element_regions: Dict[str, ~typing.List[~PyQt6.QtGui.QPainterPath | None]]=<factory>)[source]

Unified cache for all overlay geometry calculations.

FIX 3: Single cache object with single invalidation point. Replaces separate scroll_area + element caches.

valid: bool = False
scroll_clip_rects: List[QRect]
element_rects: Dict[str, List[Tuple[QRect, float] | None]]
element_regions: Dict[str, List[QPainterPath | None]]
invalidate()[source]

Invalidate entire cache - called on scroll/resize.

__init__(valid: bool = False, scroll_clip_rects: List[QRect] = <factory>, element_rects: Dict[str, ~typing.List[~typing.Tuple[~PyQt6.QtCore.QRect, float] | None]]=<factory>, element_regions: Dict[str, ~typing.List[~PyQt6.QtGui.QPainterPath | None]]=<factory>) None
pyqt_reactive.animation.get_flash_color(opacity: float = 1.0, config: FlashConfig | None = None, base_color: QColor | None = None) QColor[source]

Get the shared flash QColor with optional opacity (0.0-1.0).

pyqt_reactive.animation.get_flash_color_from_palette(scope_id: str, alpha: int = 255, use_parent_scope: bool = True) QColor[source]

Get flash color from circular palette based on scope_id.

Parameters:
  • scope_id – Scope identifier (e.g., “plate::config_field”)

  • alpha – Alpha channel (0-255)

  • use_parent_scope – If True, hash only parent scope (plate path) so all elements in same plate get same color. If False, hash full scope_id.

Returns:

QColor from pre-computed WCAG-compliant palette

class pyqt_reactive.animation.FlashElement(key: str, get_rect_in_window: Callable[[QWidget], QRect | None], get_child_rects: Callable[[QWidget], List[Tuple[QRect, bool]]] | None = None, needs_scroll_clipping: bool = True, source_id: str | None = None, corner_radius: float = 0.0, skip_overlay_paint: bool = False, delegate_widget: QWidget | None = None, get_model_index: Callable[[], Any] | None = None)[source]

Abstract representation of a flashable UI element.

Provides a geometry callback that returns the element’s rect in window coords. Works for ANY element type: groupboxes, tree items, list items, etc.

key: str
get_rect_in_window: Callable[[QWidget], QRect | None]
get_child_rects: Callable[[QWidget], List[Tuple[QRect, bool]]] | None = None
needs_scroll_clipping: bool = True
source_id: str | None = None
corner_radius: float = 0.0
skip_overlay_paint: bool = False
delegate_widget: QWidget | None = None
get_model_index: Callable[[], Any] | None = None
__init__(key: str, get_rect_in_window: Callable[[QWidget], QRect | None], get_child_rects: Callable[[QWidget], List[Tuple[QRect, bool]]] | None = None, needs_scroll_clipping: bool = True, source_id: str | None = None, corner_radius: float = 0.0, skip_overlay_paint: bool = False, delegate_widget: QWidget | None = None, get_model_index: Callable[[], Any] | None = None) None
pyqt_reactive.animation.get_widget_corner_radius(widget: QWidget) float[source]

Extract corner radius from widget’s stylesheet, with caching.

Searches the widget and its ancestors for border-radius in stylesheets. Returns 0 if no border-radius found (sharp corners).

Modules

flash_config

Declarative configuration for flash animations.

flash_mixin

Unified visual update mixin for PyQt widgets.