forked from genewildish/Mainline
The old engine/pipeline/core.py file was removed as part of the Sideline/Mainline split. All imports that referenced engine.pipeline.core have been updated to use engine.pipeline which re-exports from sideline.pipeline.core. This ensures consistency and avoids duplicate DataType enum instances.
109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
"""Adapter wrapping Display as a Stage."""
|
|
|
|
from typing import Any
|
|
|
|
from engine.pipeline import PipelineContext, Stage
|
|
|
|
|
|
class DisplayStage(Stage):
|
|
"""Adapter wrapping Display as a Stage."""
|
|
|
|
def __init__(self, display, name: str = "terminal", positioning: str = "mixed"):
|
|
self._display = display
|
|
self.name = name
|
|
self.category = "display"
|
|
self.optional = False
|
|
self._initialized = False
|
|
self._init_width = 80
|
|
self._init_height = 24
|
|
self._positioning = positioning
|
|
|
|
def save_state(self) -> dict[str, Any]:
|
|
"""Save display state for restoration after pipeline rebuild.
|
|
|
|
Returns:
|
|
Dictionary containing display state that can be restored
|
|
"""
|
|
return {
|
|
"initialized": self._initialized,
|
|
"init_width": self._init_width,
|
|
"init_height": self._init_height,
|
|
"width": getattr(self._display, "width", 80),
|
|
"height": getattr(self._display, "height", 24),
|
|
}
|
|
|
|
def restore_state(self, state: dict[str, Any]) -> None:
|
|
"""Restore display state from saved state.
|
|
|
|
Args:
|
|
state: Dictionary containing display state from save_state()
|
|
"""
|
|
self._initialized = state.get("initialized", False)
|
|
self._init_width = state.get("init_width", 80)
|
|
self._init_height = state.get("init_height", 24)
|
|
|
|
# Restore display dimensions if the display supports it
|
|
if hasattr(self._display, "width"):
|
|
self._display.width = state.get("width", 80)
|
|
if hasattr(self._display, "height"):
|
|
self._display.height = state.get("height", 24)
|
|
|
|
@property
|
|
def capabilities(self) -> set[str]:
|
|
return {"display.output"}
|
|
|
|
@property
|
|
def dependencies(self) -> set[str]:
|
|
# Display needs rendered content and camera transformation
|
|
return {"render.output", "camera"}
|
|
|
|
@property
|
|
def inlet_types(self) -> set:
|
|
from engine.pipeline import DataType
|
|
|
|
return {DataType.TEXT_BUFFER} # Display consumes rendered text
|
|
|
|
@property
|
|
def outlet_types(self) -> set:
|
|
from engine.pipeline import DataType
|
|
|
|
return {DataType.NONE} # Display is a terminal stage (no output)
|
|
|
|
def init(self, ctx: PipelineContext) -> bool:
|
|
w = ctx.params.viewport_width if ctx.params else 80
|
|
h = ctx.params.viewport_height if ctx.params else 24
|
|
|
|
# Try to reuse display if already initialized
|
|
reuse = self._initialized
|
|
result = self._display.init(w, h, reuse=reuse)
|
|
|
|
# Update initialization state
|
|
if result is not False:
|
|
self._initialized = True
|
|
self._init_width = w
|
|
self._init_height = h
|
|
|
|
return result is not False
|
|
|
|
def process(self, data: Any, ctx: PipelineContext) -> Any:
|
|
"""Output data to display."""
|
|
if data is not None:
|
|
# Check if positioning mode is specified in context params
|
|
positioning = self._positioning
|
|
if ctx and ctx.params and hasattr(ctx.params, "positioning"):
|
|
positioning = ctx.params.positioning
|
|
|
|
# Pass positioning to display if supported
|
|
if (
|
|
hasattr(self._display, "show")
|
|
and "positioning" in self._display.show.__code__.co_varnames
|
|
):
|
|
self._display.show(data, positioning=positioning)
|
|
else:
|
|
# Fallback for displays that don't support positioning parameter
|
|
self._display.show(data)
|
|
return data
|
|
|
|
def cleanup(self) -> None:
|
|
self._display.cleanup()
|