from __future__ import annotations from rich.console import Console, ConsoleOptions, RenderResult from rich.measure import Measurement from rich.segment import Segment from rich.style import Style, StyleType DIGITS = " 0123456789+-^x:ABCDEF$£€()" DIGITS3X3_BOLD = """\ ┏━┓ ┃ ┃ ┗━┛ ╺┓ ┃ ╺┻╸ ╺━┓ ┏━┛ ┗━╸ ╺━┓ ━┫ ╺━┛ ╻ ╻ ┗━┫ ╹ ┏━╸ ┗━┓ ╺━┛ ┏━╸ ┣━┓ ┗━┛ ╺━┓ ┃ ╹ ┏━┓ ┣━┫ ┗━┛ ┏━┓ ┗━┫ ╺━┛ ╺╋╸ ╺━╸ ^ × : ╭─╮ ├─┤ ╵ ╵ ┌─╮ ├─┤ └─╯ ╭─╮ │ ╰─╯ ┌─╮ │ │ └─╯ ╭─╴ ├─ ╰─╴ ╭─╴ ├─ ╵ ╭╫╮ ╰╫╮ ╰╫╯ ╭─╮ ╪═ ┷━╸ ╭─╮ ╪═ ╰─╯ ╭╴ │ ╰╴ ╶╮ │ ╶╯ """.splitlines() DIGITS3X3 = """\ ╭─╮ │ │ ╰─╯ ╶╮ │ ╶┴╴ ╶─╮ ┌─┘ ╰─╴ ╶─╮ ─┤ ╶─╯ ╷ ╷ ╰─┤ ╵ ╭─╴ ╰─╮ ╶─╯ ╭─╴ ├─╮ ╰─╯ ╶─┐ │ ╵ ╭─╮ ├─┤ ╰─╯ ╭─╮ ╰─┤ ╶─╯ ╶┼╴ ╶─╴ ^ × : ╭─╮ ├─┤ ╵ ╵ ┌─╮ ├─┤ └─╯ ╭─╮ │ ╰─╯ ┌─╮ │ │ └─╯ ╭─╴ ├─ ╰─╴ ╭─╴ ├─ ╵ ╭╫╮ ╰╫╮ ╰╫╯ ╭─╮ ╪═ ┷━╸ ╭─╮ ╪═ ╰─╯ ╭╴ │ ╰╴ ╶╮ │ ╶╯ """.splitlines() class Digits: """Renders a 3X3 unicode 'font' for numerical values. Args: text: Text to display. style: Style to apply to the digits. """ REPLACEMENTS = str.maketrans({".": "•"}) def __init__(self, text: str, style: StyleType = "") -> None: self._text = text self._style = style def __rich_console__( self, console: Console, options: ConsoleOptions ) -> RenderResult: style = console.get_style(self._style) yield from self.render(style) def render(self, style: Style) -> RenderResult: """Render with the given style Args: style: Rich Style. Returns: Result of render. """ digit_pieces: list[list[str]] = [[], [], []] row1 = digit_pieces[0].append row2 = digit_pieces[1].append row3 = digit_pieces[2].append if style.bold: digits = DIGITS3X3_BOLD else: digits = DIGITS3X3 for character in self._text.translate(self.REPLACEMENTS): try: position = DIGITS.index(character) * 3 except ValueError: row1(" ") row2(" ") row3(character) else: row1(digits[position].ljust(3)) row2(digits[position + 1].ljust(3)) row3(digits[position + 2].ljust(3)) new_line = Segment.line() for line in digit_pieces: yield Segment("".join(line), style + Style(meta={"offset": (0, 0)})) yield new_line @classmethod def get_width(cls, text: str) -> int: """Calculate the width without rendering. Args: text: Text which may be displayed in the `Digits` widget. Returns: width of the text (in cells). """ width = sum(3 if character in DIGITS else 1 for character in text) return width def __rich_measure__( self, console: Console, options: ConsoleOptions ) -> Measurement: width = self.get_width(self._text) return Measurement(width, width)