From f703addc996a6de111105c3c8e9ac662449649f0 Mon Sep 17 00:00:00 2001 From: salt-die <53280662+salt-die@users.noreply.github.com> Date: Fri, 6 Oct 2023 06:05:27 -0500 Subject: [PATCH] Add a `render_mode` option for `App`. --- examples/basic/spinners.py | 2 +- nurses_2/app.py | 18 ++++++++++++++++++ nurses_2/widgets/_root.py | 22 ++++++++++++++-------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/examples/basic/spinners.py b/examples/basic/spinners.py index fb0d1e56..69a28aa6 100644 --- a/examples/basic/spinners.py +++ b/examples/basic/spinners.py @@ -55,4 +55,4 @@ async def on_start(self): if __name__ == "__main__": - SpinnersApp(title="Spinners").run() + SpinnersApp(title="Spinners", render_mode="painter").run() diff --git a/nurses_2/app.py b/nurses_2/app.py index 12af8902..8e8e1564 100644 --- a/nurses_2/app.py +++ b/nurses_2/app.py @@ -10,6 +10,7 @@ from pathlib import Path from time import monotonic from types import ModuleType +from typing import Literal from .colors import BLACK_ON_BLACK, DEFAULT_COLOR_THEME, ColorPair, ColorTheme from .io import ( @@ -54,6 +55,10 @@ class App(ABC): the asciicast format -- doing so will corrupt the recording. redirect_stderr : Path | None, default: None If provided, stderr is written to this path. + render_mode : Literal["regions", "painter"], default: "regions" + Determines how the widget tree is rendered. "painter" fully paints every widget + back-to-front. "regions" only paints the visible portion of each widget. + "painter" may be more efficient for a large number of non-overlapping widgets. Attributes ---------- @@ -106,6 +111,7 @@ def __init__( color_theme: ColorTheme = DEFAULT_COLOR_THEME, asciicast_path: Path | None = None, redirect_stderr: Path | None = None, + render_mode: Literal["regions", "painter"] = "regions", ): self.root = None @@ -117,6 +123,7 @@ def __init__( self.color_theme = color_theme self.asciicast_path = asciicast_path self.redirect_stderr = redirect_stderr + self.render_mode = render_mode @property def color_theme(self) -> ColorTheme: @@ -151,6 +158,16 @@ def background_color_pair(self, background_color_pair: str): if self.root is not None: self.root.background_color_pair = background_color_pair + @property + def render_mode(self) -> Literal["regions", "painter"]: + return self._render_mode + + @render_mode.setter + def render_mode(self, render_mode: Literal["regions", "painter"]): + self._render_mode = render_mode + if self.root is not None: + self.root.render_mode = render_mode + @abstractmethod async def on_start(self): """ @@ -216,6 +233,7 @@ async def _run_async(self): self.root = root = _Root( background_char=self.background_char, background_color_pair=self.background_color_pair, + render_mode=self.render_mode, size=env_out.get_size(), ) diff --git a/nurses_2/widgets/_root.py b/nurses_2/widgets/_root.py index f71acc81..83ad1f78 100644 --- a/nurses_2/widgets/_root.py +++ b/nurses_2/widgets/_root.py @@ -1,12 +1,12 @@ """ Root widget. """ +from typing import Literal + import numpy as np from .widget import ColorPair, Point, Region, Size, Widget, style_char -USE_PAINTERS = True - class _Root(Widget): """ @@ -16,11 +16,16 @@ class _Root(Widget): """ def __init__( - self, background_char: str, background_color_pair: ColorPair, size: Size + self, + background_char: str, + background_color_pair: ColorPair, + render_mode: Literal["regions", "painter"], + size: Size, ): self.children = [] self.background_char = background_char self.background_color_pair = background_color_pair + self.render_mode = render_mode self._size = size self.on_size() @@ -93,11 +98,12 @@ def render(self): else Region() ) - for child in self.walk_reverse(): - if child.is_enabled: - child.region &= self.region - if child.is_visible and not child.is_transparent: - self.region -= child.region + if self.render_mode == "regions": + for child in self.walk_reverse(): + if child.is_enabled: + child.region &= self.region + if child.is_visible and not child.is_transparent: + self.region -= child.region self.canvas, self._last_canvas = self._last_canvas, self.canvas self.colors, self._last_colors = self._last_colors, self.colors