forked from genewildish/Mainline
Major changes: - Pipeline architecture with capability-based dependency resolution - Effects plugin system with performance monitoring - Display abstraction with multiple backends (terminal, null, websocket) - Camera system for viewport scrolling - Sensor framework for real-time input - Command-and-control system via ntfy - WebSocket display backend for browser clients - Comprehensive test suite and documentation Issue #48: ADR for preset scripting language included This commit consolidates 110 individual commits into a single feature integration that can be reviewed and tested before further refinement.
123 lines
3.2 KiB
Python
123 lines
3.2 KiB
Python
"""
|
|
Replay display backend - plays back recorded frames.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
|
|
class ReplayDisplay:
|
|
"""Replay display - plays back recorded frames.
|
|
|
|
This display reads frames from a recording (list of frame data)
|
|
and yields them sequentially, useful for testing and demo purposes.
|
|
"""
|
|
|
|
width: int = 80
|
|
height: int = 24
|
|
|
|
def __init__(self):
|
|
self._frames: list[dict[str, Any]] = []
|
|
self._current_frame = 0
|
|
self._playback_index = 0
|
|
self._loop = False
|
|
|
|
def init(self, width: int, height: int, reuse: bool = False) -> None:
|
|
"""Initialize display with dimensions.
|
|
|
|
Args:
|
|
width: Terminal width in characters
|
|
height: Terminal height in rows
|
|
reuse: Ignored for ReplayDisplay
|
|
"""
|
|
self.width = width
|
|
self.height = height
|
|
|
|
def set_frames(self, frames: list[dict[str, Any]]) -> None:
|
|
"""Set frames to replay.
|
|
|
|
Args:
|
|
frames: List of frame dicts with 'buffer', 'width', 'height'
|
|
"""
|
|
self._frames = frames
|
|
self._current_frame = 0
|
|
self._playback_index = 0
|
|
|
|
def set_loop(self, loop: bool) -> None:
|
|
"""Set loop playback mode.
|
|
|
|
Args:
|
|
loop: True to loop, False to stop at end
|
|
"""
|
|
self._loop = loop
|
|
|
|
def show(self, buffer: list[str], border: bool = False) -> None:
|
|
"""Display a frame (ignored in replay mode).
|
|
|
|
Args:
|
|
buffer: Buffer to display (ignored)
|
|
border: Border flag (ignored)
|
|
"""
|
|
pass
|
|
|
|
def get_next_frame(self) -> list[str] | None:
|
|
"""Get the next frame in the recording.
|
|
|
|
Returns:
|
|
Buffer list of strings, or None if playback is done
|
|
"""
|
|
if not self._frames:
|
|
return None
|
|
|
|
if self._playback_index >= len(self._frames):
|
|
if self._loop:
|
|
self._playback_index = 0
|
|
else:
|
|
return None
|
|
|
|
frame = self._frames[self._playback_index]
|
|
self._playback_index += 1
|
|
return frame.get("buffer")
|
|
|
|
def reset(self) -> None:
|
|
"""Reset playback to the beginning."""
|
|
self._playback_index = 0
|
|
|
|
def seek(self, index: int) -> None:
|
|
"""Seek to a specific frame.
|
|
|
|
Args:
|
|
index: Frame index to seek to
|
|
"""
|
|
if 0 <= index < len(self._frames):
|
|
self._playback_index = index
|
|
|
|
def is_finished(self) -> bool:
|
|
"""Check if playback is finished.
|
|
|
|
Returns:
|
|
True if at end of frames and not looping
|
|
"""
|
|
return not self._loop and self._playback_index >= len(self._frames)
|
|
|
|
def clear(self) -> None:
|
|
pass
|
|
|
|
def cleanup(self) -> None:
|
|
pass
|
|
|
|
def get_dimensions(self) -> tuple[int, int]:
|
|
"""Get current dimensions.
|
|
|
|
Returns:
|
|
(width, height) in character cells
|
|
"""
|
|
return (self.width, self.height)
|
|
|
|
def is_quit_requested(self) -> bool:
|
|
"""Check if quit was requested (optional protocol method)."""
|
|
return False
|
|
|
|
def clear_quit_request(self) -> None:
|
|
"""Clear quit request (optional protocol method)."""
|
|
pass
|