from datetime import datetime from typing import Callable, Iterable from textual._segment_tools import line_pad from textual.app import App, ComposeResult, RenderResult from textual.color import Color from textual.css.styles import StylesBase from textual.geometry import Size, Spacing from textual.screen import Screen from textual.strip import Strip from textual.widgets import Digits from rich.console import Console, ConsoleOptions from rich.segment import Segment from rich.style import Style from rich.text import Text from textual._styles_cache import StylesCache, make_blank class TransparentBlank: def __rich_console__( self, console: Console, options: ConsoleOptions ) -> RenderResult: width = options.max_width height = options.height or options.max_height self._style = Style() segment = Segment(" " * width) line = Segment.line() for _ in range(height): yield segment yield line class TransparentStyleCache(StylesCache): def render_line( self, styles: StylesBase, y: int, size: Size, content_size: Size, padding: Spacing, base_background: Color, background: Color, render_content_line: Callable[[int], Strip], console: Console, border_title: tuple[Text, Color, Color, Style] | None, border_subtitle: tuple[Text, Color, Color, Style] | None, opacity: float, ) -> Strip: gutter = styles.gutter width, _ = size content_width, content_height = content_size _, pad_right, _, pad_left = padding line: Iterable[Segment] content_y = y - gutter.top if content_y < content_height: line = render_content_line(y - gutter.top) line = line.adjust_cell_length(content_width) else: line = [make_blank(content_width)] line = line_pad(line, pad_left, pad_right, Style()) strip = Strip(line, width) return strip class TransparentScreen(Screen): def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self._styles_cache = TransparentStyleCache() class ClockApp(App): CSS = """ App { background: transparent; } Screen { align: center middle; &:inline { border: none; height: 50vh; Digits { color: $success; } } background: transparent; } #clock { width: auto; } """ def get_default_screen(self) -> Screen: return TransparentScreen(id="_default") def compose(self) -> ComposeResult: yield Digits("", id="clock") def on_ready(self) -> None: self.update_clock() self.set_interval(1, self.update_clock) def update_clock(self) -> None: clock = datetime.now().time() self.query_one(Digits).update(f"{clock:%T}") def render(self) -> RenderResult: return TransparentBlank() if __name__ == "__main__": app = ClockApp() app.run(inline=True)