diff --git a/docs/examples/widgets/digit_display.py b/docs/examples/widgets/digit_display.py index e135782bea2..c2d95e08e11 100644 --- a/docs/examples/widgets/digit_display.py +++ b/docs/examples/widgets/digit_display.py @@ -1,5 +1,5 @@ from textual.app import App, ComposeResult -from textual.widgets import Static +from textual.widgets import Label from textual.widgets import DigitDisplay @@ -7,15 +7,15 @@ class MyApp(App): BINDINGS = [] def compose(self) -> ComposeResult: - yield Static("Digits: 0123456789") + yield Label("Digits: 0123456789") yield DigitDisplay("0123456789") - punctuation=" .+,XYZ^*/-=" - yield Static("Punctuation: " + punctuation) + punctuation = " .+,XYZ^*/-=" + yield Label("Punctuation: " + punctuation) yield DigitDisplay(punctuation) equation = "x = y^2 + 3.14159*y + 10" - yield Static("Equation: " + equation) + yield Label("Equation: " + equation) yield DigitDisplay(equation) diff --git a/docs/widgets/digit_display.md b/docs/widgets/digit_display.md index e451aee1465..594e6cee54f 100644 --- a/docs/widgets/digit_display.md +++ b/docs/widgets/digit_display.md @@ -7,7 +7,10 @@ A widget to display digits and basic arithmetic operators using Unicode blocks. ## Examples -=== "Static example" + +### Static display example + +=== "Screenshot" ```{.textual path="docs/examples/widgets/digit_display.py"} ``` @@ -18,9 +21,12 @@ A widget to display digits and basic arithmetic operators using Unicode blocks. --8<-- "docs/examples/widgets/digit_display.py" ``` -=== "Reacting to an input" - ```{.textual path="docs/examples/widgets/digit_display_reacting.py"} +### Reacting to an input + +=== "Screenshot" + + ```{.textual path="docs/examples/widgets/digit_display_reacting.py" press="1,2,3"} ``` === "digit_display_reacting.py" @@ -31,16 +37,16 @@ A widget to display digits and basic arithmetic operators using Unicode blocks. ## Reactive attributes -| Name | Type | Default | Description | -| ------ | ------ | ------- | ---------------------------------------------- | -| `digits` | `str` | `""` | Use this to update the digits to be displayed. | +| Name | Type | Default | Description | +| ------ | ------ | ------- | ---------------------------------------------- | +| `digits` | `str` | `""` | Use this to update the digits to be displayed. | ## Read-only attributes -| Name | Type | Description | -| ------ | ------ | ----------------------------------------- | -| `supported_digits` | `frozenset[str]` | Contains the list of supported digits/characters. +| Name | Type | Description | +| ------ | ------ | ----------------------------------------- | +| `supported_digits` | `frozenset[str]` | Contains the list of supported digits/characters. | ## Messages diff --git a/src/textual/widgets/_digit_display.py b/src/textual/widgets/_digit_display.py index fdbb8d9215d..c58769af294 100644 --- a/src/textual/widgets/_digit_display.py +++ b/src/textual/widgets/_digit_display.py @@ -199,6 +199,7 @@ class _SingleDigitDisplay(Static): digit = reactive(" ", layout=True) + """The digit to display.""" DEFAULT_CSS = """ _SingleDigitDisplay { @@ -212,10 +213,17 @@ 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.""" + def validate_digit(self, digit: str) -> str: + """Sanitize and validate the digit input.""" if len(digit) > 1: raise ValueError(f"Expected a single character, got {len(digit)}") + digit = digit.upper() + if digit not in _character_map: + raise ValueError(f"Unsupported character: {digit}") + return digit + + def _watch_digit(self, digit: str) -> None: + """Called when the digit attribute changes and passes validation.""" self.update(_character_map[digit.upper()]) @@ -223,8 +231,10 @@ class DigitDisplay(Widget): """A widget to display digits and basic arithmetic operators using Unicode blocks.""" digits = reactive("", layout=True) + """The digits to display.""" supported_digits = frozenset(_character_map.keys()) + """The digits and characters supported by this widget.""" DEFAULT_CSS = """ DigitDisplay { @@ -242,27 +252,17 @@ def compose(self) -> ComposeResult: for widget in self._displays: yield widget - def _add_digit_widget(self, digit: str) -> None: - new_widget = _SingleDigitDisplay(digit) - self._displays.append(new_widget) - self.mount(new_widget) - - def watch_digits(self, digits: str) -> None: + def _watch_digits(self, digits: str) -> None: """ Called when the digits attribute changes. Here we update the display widgets to match the input digits. """ - diff_digits_len = len(digits) - len(self._displays) - # Here we add or remove widgets to match the number of digits - if diff_digits_len > 0: - start = len(self._displays) - for i in range(diff_digits_len): - self._add_digit_widget(digits[start + i]) - elif diff_digits_len < 0: - for display in self._displays[diff_digits_len:]: - self._displays.remove(display) - display.remove() + while len(self._displays) < len(digits): + self._displays.append(_SingleDigitDisplay(digits[len(self._displays)])) + self.mount(self._displays[-1]) + while len(self._displays) > len(digits): + self._displays.pop().remove() # At this point, the number of widgets matches the number of digits, and we can # update the contents of the widgets that might need it diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 92ecbea4dbc..1611004818a 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -13742,131 +13742,131 @@ font-weight: 700; } - .terminal-1756784214-matrix { + .terminal-4012950226-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1756784214-title { + .terminal-4012950226-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1756784214-r1 { fill: #e1e1e1 } - .terminal-1756784214-r2 { fill: #c5c8c6 } + .terminal-4012950226-r1 { fill: #e1e1e1 } + .terminal-4012950226-r2 { fill: #c5c8c6 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - MyApp + MyApp - + - - Digits: 0123456789 - ┏━┓ ┓ ╺━┓╺━┓╻ ╻┏━╸┏━╸╺━┓┏━┓┏━┓ - ┃╱┃ ┃ ┏━┛ ━┫┗━┫┗━┓┣━┓  ╹┣━┫┗━┫ - ┗━┛╺┻╸┗━╸╺━┛  ╹╺━┛┗━┛ ╹ ┗━┛╺━┛ - Punctuation:  .+,XYZ^*/-= - ╻ ╻╻ ╻╺━┓ ╻   ╻ - ╺╋╸ ╋  ┳  ▞ ▝ ▘ ✱  ▞ ╺━╸╺━  -  • ▞╹ ╹ ╹ ┗━╸╹  ╺━  - Equation: x = y^2 + 3.14159*y + 10 - ╻ ╻╻ ╻ ╻ ╺━┓╺━┓ ┓ ╻ ╻ ┓ ┏━╸┏━┓╻ ╻ ┓ ┏━┓ -  ╋ ╺━  ┳ ▝ ▘┏━┛╺╋╸ ━┫ ┃ ┗━┫ ┃ ┗━┓┗━┫ ✱  ┳ ╺╋╸ ┃ ┃╱┃ - ╹ ╹╺━  ╹ ┗━╸╺━┛ •╺┻╸  ╹╺┻╸╺━┛╺━┛ ╹ ╺┻╸┗━┛ - - - - - - - - - - - + + Digits: 0123456789 + ┏━┓ ┓ ╺━┓╺━┓╻ ╻┏━╸┏━╸╺━┓┏━┓┏━┓ + ┃╱┃ ┃ ┏━┛ ━┫┗━┫┗━┓┣━┓  ╹┣━┫┗━┫ + ┗━┛╺┻╸┗━╸╺━┛  ╹╺━┛┗━┛ ╹ ┗━┛╺━┛ + Punctuation:  .+,XYZ^*/-= + ╻ ╻╻ ╻╺━┓ ╻   ╻ + ╺╋╸ ╋  ┳  ▞ ▝ ▘ ✱  ▞ ╺━╸╺━  +  • ▞╹ ╹ ╹ ┗━╸╹  ╺━  + Equation: x = y^2 + 3.14159*y + 10 + ╻ ╻╻ ╻ ╻ ╺━┓╺━┓ ┓ ╻ ╻ ┓ ┏━╸┏━┓╻ ╻ ┓ ┏━┓ +  ╋ ╺━  ┳ ▝ ▘┏━┛╺╋╸ ━┫ ┃ ┗━┫ ┃ ┗━┓┗━┫ ✱  ┳ ╺╋╸ ┃ ┃╱┃ + ╹ ╹╺━  ╹ ┗━╸╺━┛ •╺┻╸  ╹╺┻╸╺━┛╺━┛ ╹ ╺┻╸┗━┛ + + + + + + + + + + +