mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
* compound example * update bit switch * prevent * no css * compound widget example * more diagrams * more diagrams * diagrams * words * words * remove sender * removed priority post * timer fix * test fixes * drop async version of post_message * extended docs * fix no app * Added control properties * changelog * changelog * changelog * fix for stopping timers * changelog * docs update * last byte example * new section * update of byte03 * updae to docs * Added compound examples * Rewording * Use set sender * don't need this * hyphens * Update docs/guide/widgets.md Co-authored-by: Dave Pearson <davep@davep.org> * Update docs/guide/widgets.md Co-authored-by: Dave Pearson <davep@davep.org> * Update docs/guide/widgets.md Co-authored-by: Dave Pearson <davep@davep.org> * Update docs/guide/widgets.md Co-authored-by: Dave Pearson <davep@davep.org> * Update docs/guide/widgets.md Co-authored-by: Dave Pearson <davep@davep.org> * Update docs/guide/widgets.md Co-authored-by: Dave Pearson <davep@davep.org> * Update docs/guide/widgets.md Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * Update docs/guide/widgets.md Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * Update docs/guide/widgets.md Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * Update docs/guide/widgets.md Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * parenthesis * stack diagram --------- Co-authored-by: Dave Pearson <davep@davep.org> Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>
131 lines
3.4 KiB
Python
131 lines
3.4 KiB
Python
from __future__ import annotations
|
|
|
|
from textual.app import App, ComposeResult
|
|
from textual.containers import Container
|
|
from textual.geometry import clamp
|
|
from textual.messages import Message
|
|
from textual.reactive import reactive
|
|
from textual.widget import Widget
|
|
from textual.widgets import Input, Label, Switch
|
|
|
|
|
|
class BitSwitch(Widget):
|
|
"""A Switch with a numeric label above it."""
|
|
|
|
DEFAULT_CSS = """
|
|
BitSwitch {
|
|
layout: vertical;
|
|
width: auto;
|
|
height: auto;
|
|
}
|
|
BitSwitch > Label {
|
|
text-align: center;
|
|
width: 1fr;
|
|
}
|
|
"""
|
|
|
|
class BitChanged(Message):
|
|
"""Sent when the 'bit' changes."""
|
|
|
|
def __init__(self, bit: int, value: bool) -> None:
|
|
super().__init__()
|
|
self.bit = bit
|
|
self.value = value
|
|
|
|
value = reactive(0)
|
|
|
|
def __init__(self, bit: int) -> None:
|
|
self.bit = bit
|
|
super().__init__()
|
|
|
|
def compose(self) -> ComposeResult:
|
|
yield Label(str(self.bit))
|
|
yield Switch()
|
|
|
|
def watch_value(self, value: bool) -> None: # (1)!
|
|
"""When the value changes we want to set the switch accordingly."""
|
|
self.query_one(Switch).value = value
|
|
|
|
def on_switch_changed(self, event: Switch.Changed) -> None:
|
|
"""When the switch changes, notify the parent via a message."""
|
|
event.stop()
|
|
self.value = event.value
|
|
self.post_message(self.BitChanged(self.bit, event.value))
|
|
|
|
|
|
class ByteInput(Widget):
|
|
"""A compound widget with 8 switches."""
|
|
|
|
DEFAULT_CSS = """
|
|
ByteInput {
|
|
width: auto;
|
|
height: auto;
|
|
border: blank;
|
|
layout: horizontal;
|
|
}
|
|
ByteInput:focus-within {
|
|
border: heavy $secondary;
|
|
}
|
|
"""
|
|
|
|
def compose(self) -> ComposeResult:
|
|
for bit in reversed(range(8)):
|
|
yield BitSwitch(bit)
|
|
|
|
|
|
class ByteEditor(Widget):
|
|
DEFAULT_CSS = """
|
|
ByteEditor > Container {
|
|
height: 1fr;
|
|
align: center middle;
|
|
}
|
|
ByteEditor > Container.top {
|
|
background: $boost;
|
|
}
|
|
ByteEditor Input {
|
|
width: 16;
|
|
}
|
|
"""
|
|
|
|
value = reactive(0)
|
|
|
|
def validate_value(self, value: int) -> int: # (2)!
|
|
"""Ensure value is between 0 and 255."""
|
|
return clamp(value, 0, 255)
|
|
|
|
def compose(self) -> ComposeResult:
|
|
with Container(classes="top"):
|
|
yield Input(placeholder="byte")
|
|
with Container():
|
|
yield ByteInput()
|
|
|
|
def on_bit_switch_bit_changed(self, event: BitSwitch.BitChanged) -> None:
|
|
"""When a switch changes, update the value."""
|
|
value = 0
|
|
for switch in self.query(BitSwitch):
|
|
value |= switch.value << switch.bit
|
|
self.query_one(Input).value = str(value)
|
|
|
|
def on_input_changed(self, event: Input.Changed) -> None: # (3)!
|
|
"""When the text changes, set the value of the byte."""
|
|
try:
|
|
self.value = int(event.value or "0")
|
|
except ValueError:
|
|
pass
|
|
|
|
def watch_value(self, value: int) -> None: # (4)!
|
|
"""When self.value changes, update switches."""
|
|
for switch in self.query(BitSwitch):
|
|
with switch.prevent(BitSwitch.BitChanged): # (5)!
|
|
switch.value = bool(value & (1 << switch.bit)) # (6)!
|
|
|
|
|
|
class ByteInputApp(App):
|
|
def compose(self) -> ComposeResult:
|
|
yield ByteEditor()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app = ByteInputApp()
|
|
app.run()
|