Skip to content

Commit

Permalink
fix LedDisplay component to avoid breaking when content overflows
Browse files Browse the repository at this point in the history
  • Loading branch information
eliasdorneles committed Jul 22, 2023
1 parent 1dfe02e commit 2374072
Showing 1 changed file with 173 additions and 14 deletions.
187 changes: 173 additions & 14 deletions src/textual/widgets/_led_display.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from textual.app import ComposeResult
from textual.reactive import reactive
from textual.widget import Widget
from textual.widgets import Static
from textual.containers import Horizontal, Vertical


_character_map: dict[str, str] = {}
Expand All @@ -10,7 +13,7 @@
"0"
] = """
┏━┓
┗━┛
"""

Expand Down Expand Up @@ -120,13 +123,20 @@
┗━╸
"""

_character_map["D"] = _character_map["0"]
_character_map[
"D"
] = """
┏━╮
┃ ┃
┗━╯
"""


_character_map[
"E"
] = """
┏━╸
┣━
┣━
┗━╸
"""

Expand Down Expand Up @@ -202,7 +212,13 @@
╹ ╹
"""

_character_map["O"] = _character_map["0"]
_character_map[
"O"
] = """
╭━╮
┃ ┃
╰━╯
"""

_character_map[
"P"
Expand Down Expand Up @@ -372,28 +388,171 @@
__
"""

_character_map[
":"
] = """
_
"""

_character_map[
";"
] = """
_
"""

_character_map[
"("
] = """
__╸
_┃_
__╸
"""

_character_map[
")"
] = """
_╺_
__┃
_╺_
"""

_character_map[
"["
] = """
_┏╸
_┃_
_┗╸
"""

_character_map[
"]"
] = """
╺┓
_┃
╺┛
"""

_character_map[
"{"
] = """
_┏╸
_┫_
_┗╸
"""

_character_map[
"}"
] = """
╺┓
_┣
╺┛
"""

_character_map[
"<"
] = """
__╸
_╸_
__╸
"""

_character_map[
">"
] = """
╺__
_╺_
╺__
"""

_character_map[
"@"
] = """
╭━╮
╹╹┛
╰━_
"""

_character_map[
"#"
] = """
╋╋
╋╋
___
"""


# here we strip spaces and replace underscores with spaces
_character_map = {k: v.strip() for k, v in _character_map.items()}


def render_digits(digits: str) -> str:
"""Render a string of digits as 7-segment LED-like characters."""
lines = [""] * 3
for digit in digits:
for i, line in enumerate(_character_map[digit].splitlines()):
lines[i] += line.replace("_", " ")
return "\n".join(lines)
def render_single_digit(digit: str):
return _character_map[digit].replace("_", " ")


class SingleDigitDisplay(Static):
digit = reactive(" ", layout=True)

DEFAULT_CSS = """
SingleDigitDisplay {
height: 3;
max-width: 3;
}
"""

def __init__(self, initial_value=" ", **kwargs):
super().__init__(**kwargs)
self.digit = initial_value

def watch_digit(self, digit: str) -> None:
"""Called when the digit attribute changes."""
if len(digit) > 1:
raise ValueError(f"Expected a single character, got {len(digit)}")
self.update(render_single_digit(digit.upper()))


class LedDisplay(Static):
class LedDisplay(Widget):
"""A widget to display characters using 7-segment LED-like format."""

digits = reactive("", layout=True)

DEFAULT_CSS = """
LedDisplay {
layout: horizontal;
height: 5;
}
"""

def __init__(self, initial_value="", **kwargs):
super().__init__(**kwargs)
self._displays = [SingleDigitDisplay(d) for d in initial_value]
self.digits = initial_value
self.previous_digits = initial_value

def compose(self) -> ComposeResult:
for led_display in self._displays:
yield led_display

def watch_digits(self, digits: str) -> None:
"""Called when the time attribute changes."""
self.update(render_digits(digits.upper()))
"""
Called when the digits attribute changes.
Here we update the display widgets to match the number of digits.
"""
diff_digits_len = len(digits) - len(self._displays)
if diff_digits_len > 0:
# add new displays
start = len(self._displays)
for i in range(diff_digits_len):
new_widget = SingleDigitDisplay(digits[start + i])
self._displays.append(new_widget)
self.mount(new_widget)
elif diff_digits_len < 0:
# remove displays
for display in self._displays[diff_digits_len:]:
display.remove()
self._displays.remove(display)
for i, d in enumerate(self.digits):
self._displays[i].digit = d

0 comments on commit 2374072

Please sign in to comment.