key lines

This commit is contained in:
Will McGugan
2021-11-24 21:26:27 +00:00
parent eedb339908
commit 09544e172f
16 changed files with 177 additions and 114 deletions

View File

@@ -1,5 +1,5 @@
from textual.app import App from textual.app import App
from textual.widgets import Placeholder from textual.widget import Widget
class BasicApp(App): class BasicApp(App):
@@ -9,35 +9,51 @@ class BasicApp(App):
App > DockView { App > DockView {
layout: dock; layout: dock;
docks: sidebar=left/1 widgets=top; docks: side=left/1 header=top footer=bottom;
layers: base panels; layers: base panels;
} }
#sidebar { #sidebar {
dock-group: sidebar; text: bold #09312e on #3CAEA3;
width: 40; /* dock-group: header; */
width: 30;
height: 1fr;
layer: panels; layer: panels;
border-right: vkey #09312e;
} }
#widget1 { #header {
text: on blue; text: on #173f5f;
dock-group: widgets; dock-group: header;
height: 1fr; height: 3;
border: hkey white;
} }
#widget2 { #footer {
text: on red; dock-group: header;
dock-group: widgets; height: 3;
height: 1fr; border-top: hkey #0f2b41;
text: #3a3009 on #f6d55c;
} }
#content {
dock-group: header;
text: on #20639B;
}
""" """
async def on_mount(self) -> None: async def on_mount(self) -> None:
"""Build layout here.""" """Build layout here."""
await self.view.mount( await self.view.mount(
sidebar=Placeholder(), widget1=Placeholder(), widget2=Placeholder() header=Widget(),
content=Widget(),
footer=Widget(),
sidebar=Widget(),
) )
self.panic(self.view.styles)
BasicApp.run(log="textual.log") BasicApp.run(log="textual.log")

View File

@@ -17,6 +17,8 @@ BORDER_STYLES: dict[str, tuple[str, str, str]] = {
"heavy": ("┏━┓", "┃ ┃", "┗━┛"), "heavy": ("┏━┓", "┃ ┃", "┗━┛"),
"inner": ("▗▄▖", "▐ ▌", "▝▀▘"), "inner": ("▗▄▖", "▐ ▌", "▝▀▘"),
"outer": ("▛▀▜", "▌ ▐", "▙▄▟"), "outer": ("▛▀▜", "▌ ▐", "▙▄▟"),
"hkey": ("▔▔▔", " ", "▁▁▁"),
"vkey": ("▏ ▕", "▏ ▕", "▏ ▕"),
} }
@@ -98,9 +100,9 @@ class Border:
render_options = options.update_dimensions(width, height) render_options = options.update_dimensions(width, height)
lines = console.render_lines(self.renderable, render_options) lines = console.render_lines(self.renderable, render_options)
if len(lines) <= 2: # if len(lines) <= 2:
yield SegmentLines(lines, new_lines=True) # yield SegmentLines(lines, new_lines=True)
return # return
if self.outline: if self.outline:
self._crop_renderable(lines, options.max_width) self._crop_renderable(lines, options.max_width)

View File

@@ -305,7 +305,6 @@ class App(DOMNode):
self.stylesheet.read(self.css_file) self.stylesheet.read(self.css_file)
if self.css is not None: if self.css is not None:
self.stylesheet.parse(self.css, path=f"<{self.__class__.__name__}>") self.stylesheet.parse(self.css, path=f"<{self.__class__.__name__}>")
print(self.stylesheet.css)
except StylesheetParseError as error: except StylesheetParseError as error:
self.panic(error) self.panic(error)
self._print_error_renderables() self._print_error_renderables()
@@ -322,16 +321,14 @@ class App(DOMNode):
# Wait for the load event to be processed, so we don't go in to application mode beforehand # Wait for the load event to be processed, so we don't go in to application mode beforehand
await load_event.wait() await load_event.wait()
await self.post_message(events.Mount(sender=self))
view = DockView()
await self.mount(self, view)
await self.push_view(view)
driver = self._driver = self.driver_class(self.console, self) driver = self._driver = self.driver_class(self.console, self)
driver.start_application_mode() driver.start_application_mode()
try: try:
mount_event = events.Mount(sender=self)
await self.dispatch_message(mount_event)
await mount_event.wait()
self.title = self._title self.title = self._title
self.refresh() self.refresh()
await self.animator.start() await self.animator.start()
@@ -339,8 +336,6 @@ class App(DOMNode):
log("PROCESS END") log("PROCESS END")
await self.animator.stop() await self.animator.stop()
await self.close_all() await self.close_all()
except Exception:
self.panic()
finally: finally:
driver.stop_application_mode() driver.stop_application_mode()
except: except:
@@ -376,13 +371,20 @@ class App(DOMNode):
name_widgets: Iterable[tuple[str | None, Widget]] name_widgets: Iterable[tuple[str | None, Widget]]
name_widgets = [*((None, widget) for widget in anon_widgets), *widgets.items()] name_widgets = [*((None, widget) for widget in anon_widgets), *widgets.items()]
apply_stylesheet = self.stylesheet.apply apply_stylesheet = self.stylesheet.apply
widget_events = []
for widget_id, widget in name_widgets: for widget_id, widget in name_widgets:
if widget not in self.registry: if widget not in self.registry:
if widget_id is not None: if widget_id is not None:
widget.id = widget_id widget.id = widget_id
self._register(parent, widget) self._register(parent, widget)
apply_stylesheet(widget) apply_stylesheet(widget)
widget.post_message_no_wait(events.Mount(sender=parent)) mount_event = events.Mount(sender=parent)
widget_events.append((widget, mount_event))
# await widget.post_message(mount_event)
# await mount_event.wait()
for widget, event in widget_events:
widget.post_message_no_wait(event)
# await event.wait()
def is_mounted(self, widget: Widget) -> bool: def is_mounted(self, widget: Widget) -> bool:
return widget in self.registry return widget in self.registry
@@ -471,7 +473,13 @@ class App(DOMNode):
async def on_event(self, event: events.Event) -> None: async def on_event(self, event: events.Event) -> None:
# Handle input events that haven't been forwarded # Handle input events that haven't been forwarded
# If the event has been forwaded it may have bubbled up back to the App # If the event has been forwaded it may have bubbled up back to the App
if isinstance(event, events.InputEvent) and not event.is_forwarded: if isinstance(event, events.Mount):
view = DockView()
await self.mount(self, view)
await self.push_view(view)
await super().on_event(event)
elif isinstance(event, events.InputEvent) and not event.is_forwarded:
if isinstance(event, events.MouseEvent): if isinstance(event, events.MouseEvent):
# Record current mouse position on App # Record current mouse position on App
self.mouse_position = Offset(event.x, event.y) self.mouse_position = Offset(event.x, event.y)

View File

@@ -6,7 +6,7 @@ import rich.repr
from rich.color import Color from rich.color import Color
from rich.style import Style from rich.style import Style
from .scalar import Scalar, ScalarParseError from .scalar import get_symbols, UNIT_SYMBOL, Unit, Scalar, ScalarParseError
from ..geometry import Offset, Spacing, SpacingDimensions from ..geometry import Offset, Spacing, SpacingDimensions
from .constants import NULL_SPACING, VALID_EDGE from .constants import NULL_SPACING, VALID_EDGE
from .errors import StyleTypeError, StyleValueError from .errors import StyleTypeError, StyleValueError
@@ -14,15 +14,16 @@ from ._error_tools import friendly_list
if TYPE_CHECKING: if TYPE_CHECKING:
from .styles import Styles from .styles import Styles
from .styles import DockSpecification from .styles import DockGroup
class ScalarProperty: class ScalarProperty:
def __init__(self, units: set[str]) -> None: def __init__(self, units: set[Unit] | None = None) -> None:
self.units = units self.units: set[Unit] = units or {*UNIT_SYMBOL}
super().__init__() super().__init__()
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: Styles, name: str) -> None:
self.name = name
self.internal_name = f"_rule_{name}" self.internal_name = f"_rule_{name}"
def __get__( def __get__(
@@ -38,7 +39,7 @@ class ScalarProperty:
if value is None: if value is None:
new_value = None new_value = None
elif isinstance(value, float): elif isinstance(value, float):
new_value = Scalar(value, "") new_value = Scalar(value, Unit.CELLS)
elif isinstance(value, Scalar): elif isinstance(value, Scalar):
new_value = value new_value = value
elif isinstance(value, str): elif isinstance(value, str):
@@ -49,7 +50,9 @@ class ScalarProperty:
else: else:
raise StyleValueError("expected float, Scalar, or None") raise StyleValueError("expected float, Scalar, or None")
if new_value is not None and new_value.unit not in self.units: if new_value is not None and new_value.unit not in self.units:
raise StyleValueError(f"units must be one of {friendly_list(self.units)}") raise StyleValueError(
f"{self.name} units must be one of {friendly_list(get_symbols(self.units))}"
)
setattr(obj, self.internal_name, new_value) setattr(obj, self.internal_name, new_value)
return value return value
@@ -224,12 +227,12 @@ class SpacingProperty:
class DocksProperty: class DocksProperty:
def __get__( def __get__(
self, obj: Styles, objtype: type[Styles] | None = None self, obj: Styles, objtype: type[Styles] | None = None
) -> tuple[DockSpecification, ...]: ) -> tuple[DockGroup, ...]:
return obj._rule_docks or () return obj._rule_docks or ()
def __set__( def __set__(
self, obj: Styles, docks: Iterable[DockSpecification] | None self, obj: Styles, docks: Iterable[DockGroup] | None
) -> Iterable[DockSpecification] | None: ) -> Iterable[DockGroup] | None:
if docks is None: if docks is None:
obj._rule_docks = None obj._rule_docks = None
else: else:

View File

@@ -12,7 +12,7 @@ from ._error_tools import friendly_list
from ..geometry import Offset, Spacing, SpacingDimensions from ..geometry import Offset, Spacing, SpacingDimensions
from .model import Declaration from .model import Declaration
from .scalar import Scalar from .scalar import Scalar
from .styles import DockSpecification, Styles from .styles import DockGroup, Styles
from .types import Edge, Display, Visibility from .types import Edge, Display, Visibility
from .tokenize import Token from .tokenize import Token
@@ -138,7 +138,7 @@ class StylesBuilder:
style_tokens: list[str] = [] style_tokens: list[str] = []
append = style_tokens.append append = style_tokens.append
for token in tokens: for token in tokens:
_, _, location, token_name, value = token token_name, value, _, _, _ = token
if token_name == "token": if token_name == "token":
if value in VALID_BORDER: if value in VALID_BORDER:
border_type = value border_type = value
@@ -157,7 +157,7 @@ class StylesBuilder:
def _process_border(self, edge: str, name: str, tokens: list[Token]) -> None: def _process_border(self, edge: str, name: str, tokens: list[Token]) -> None:
border = self._parse_border("border", tokens) border = self._parse_border("border", tokens)
setattr(self.styles, f"_border_{edge}", border) setattr(self.styles, f"_rule_border_{edge}", border)
def process_border(self, name: str, tokens: list[Token]) -> None: def process_border(self, name: str, tokens: list[Token]) -> None:
border = self._parse_border("border", tokens) border = self._parse_border("border", tokens)
@@ -179,7 +179,7 @@ class StylesBuilder:
def _process_outline(self, edge: str, name: str, tokens: list[Token]) -> None: def _process_outline(self, edge: str, name: str, tokens: list[Token]) -> None:
border = self._parse_border("outline", tokens) border = self._parse_border("outline", tokens)
setattr(self.styles, f"_outline_{edge}", border) setattr(self.styles, f"_rule_outline_{edge}", border)
def process_outline(self, name: str, tokens: list[Token]) -> None: def process_outline(self, name: str, tokens: list[Token]) -> None:
border = self._parse_border("outline", tokens) border = self._parse_border("outline", tokens)
@@ -289,7 +289,7 @@ class StylesBuilder:
self.styles._rule_dock_group = tokens[0].value if tokens else "" self.styles._rule_dock_group = tokens[0].value if tokens else ""
def process_docks(self, name: str, tokens: list[Token]) -> None: def process_docks(self, name: str, tokens: list[Token]) -> None:
docks: list[DockSpecification] = [] docks: list[DockGroup] = []
for token in tokens: for token in tokens:
if token.name == "key_value": if token.name == "key_value":
key, edge_name = token.value.split("=") key, edge_name = token.value.split("=")
@@ -308,7 +308,7 @@ class StylesBuilder:
token, token,
f"edge must be one of 'top', 'right', 'bottom', or 'left'; found {edge_name!r}", f"edge must be one of 'top', 'right', 'bottom', or 'left'; found {edge_name!r}",
) )
docks.append(DockSpecification(key.strip(), cast(Edge, edge_name), z)) docks.append(DockGroup(key.strip(), cast(Edge, edge_name), z))
elif token.name == "bar": elif token.name == "bar":
pass pass
else: else:

View File

@@ -10,13 +10,15 @@ from ..geometry import Spacing
VALID_VISIBILITY: Final = {"visible", "hidden"} VALID_VISIBILITY: Final = {"visible", "hidden"}
VALID_DISPLAY: Final = {"block", "none"} VALID_DISPLAY: Final = {"block", "none"}
VALID_BORDER: Final = { VALID_BORDER: Final = {
"rounded", "none" "round",
"solid", "solid",
"double", "double",
"dashed", "dashed",
"heavy", "heavy",
"inner", "inner",
"outer", "outer",
"hkey",
"vkey",
} }
VALID_EDGE: Final = {"top", "right", "bottom", "left"} VALID_EDGE: Final = {"top", "right", "bottom", "left"}
VALID_LAYOUT: Final = {"dock", "vertical", "grid"} VALID_LAYOUT: Final = {"dock", "vertical", "grid"}

View File

@@ -1,10 +1,46 @@
from __future__ import annotations from __future__ import annotations
from enum import Enum, unique
import re import re
from typing import NamedTuple from typing import Iterable, NamedTuple
_MATCH_SCALAR = re.compile(r"^(\d+\.?\d*)(fr|%)?$").match @unique
class Unit(Enum):
CELLS = 1
FRACTION = 2
PERCENT = 3
WIDTH = 4
HEIGHT = 5
VIEW_WIDTH = 6
VIEW_HEIGHT = 7
UNIT_SYMBOL = {
Unit.CELLS: "",
Unit.FRACTION: "fr",
Unit.PERCENT: "%",
Unit.WIDTH: "w",
Unit.HEIGHT: "h",
Unit.VIEW_WIDTH: "vw",
Unit.VIEW_HEIGHT: "vh",
}
SYMBOL_UNIT = {v: k for k, v in UNIT_SYMBOL.items()}
_MATCH_SCALAR = re.compile(r"^(\d+\.?\d*)(fr|%|w|h|vw|vh)?$").match
def get_symbols(units: Iterable[Unit]) -> list[str]:
"""Get symbols for an iterable of units.
Args:
units (Iterable[Unit]): A number of units.
Returns:
list[str]: List of symbols.
"""
return [UNIT_SYMBOL[unit] for unit in units]
class ScalarParseError(Exception): class ScalarParseError(Exception):
@@ -15,36 +51,25 @@ class Scalar(NamedTuple):
"""A numeric value and a unit.""" """A numeric value and a unit."""
value: float value: float
unit: str unit: Unit
def __str__(self) -> str: def __str__(self) -> str:
value, unit = self value, _unit = self
return f"{int(value) if value.is_integer() else value}{unit}" return f"{int(value) if value.is_integer() else value}{self.symbol}"
@property @property
def cells(self) -> int | None: def cells(self) -> int | None:
value, unit = self value, unit = self
if unit: return int(value) if unit == Unit.CELLS else None
return None
else:
return int(value)
@property @property
def fraction(self) -> int | None: def fraction(self) -> int | None:
value, unit = self value, unit = self
if unit == "fr": return int(value) if unit == Unit.FRACTION else None
return int(value)
else:
return None
def resolve_size(self, total: int, total_fraction: int) -> int: @property
value, unit = self def symbol(self) -> str:
if unit == "": return UNIT_SYMBOL[self.unit]
return int(value)
elif unit == "%":
return int(total * value / 100.0)
else: # if unit == "fr":
return int((value / total_fraction) * total)
@classmethod @classmethod
def parse(cls, token: str) -> Scalar: def parse(cls, token: str) -> Scalar:
@@ -62,11 +87,14 @@ class Scalar(NamedTuple):
match = _MATCH_SCALAR(token) match = _MATCH_SCALAR(token)
if match is None: if match is None:
raise ScalarParseError(f"{token!r} is not a valid scalar") raise ScalarParseError(f"{token!r} is not a valid scalar")
value, unit = match.groups() value, unit_name = match.groups()
scalar = cls(float(value), unit or "") scalar = cls(float(value), SYMBOL_UNIT[unit_name or ""])
return scalar return scalar
if __name__ == "__main__": if __name__ == "__main__":
print(Scalar.parse("3.14")) print(Scalar.parse("3.14fr"))
s = Scalar.parse("23")
print(repr(s))
print(repr(s.cells))

View File

@@ -43,7 +43,7 @@ else:
from typing_extensions import Literal from typing_extensions import Literal
class DockSpecification(NamedTuple): class DockGroup(NamedTuple):
name: str name: str
edge: Edge edge: Edge
z: int z: int
@@ -83,7 +83,7 @@ class Styles:
_rule_layout: str | None = None _rule_layout: str | None = None
_rule_dock_group: str | None = None _rule_dock_group: str | None = None
_rule_docks: tuple[DockSpecification, ...] | None = None _rule_docks: tuple[DockGroup, ...] | None = None
_rule_layers: tuple[str, ...] | None = None _rule_layers: tuple[str, ...] | None = None
_rule_layer: str | None = None _rule_layer: str | None = None
@@ -115,10 +115,10 @@ class Styles:
outline_bottom = BoxProperty() outline_bottom = BoxProperty()
outline_left = BoxProperty() outline_left = BoxProperty()
width = ScalarProperty({"", "fr"}) width = ScalarProperty()
height = ScalarProperty({"", "fr"}) height = ScalarProperty()
min_width = ScalarProperty({"", "fr"}) min_width = ScalarProperty()
min_height = ScalarProperty({"", "fr"}) min_height = ScalarProperty()
dock_group = DockGroupProperty() dock_group = DockGroupProperty()
docks = DocksProperty() docks = DocksProperty()
@@ -251,8 +251,8 @@ class Styles:
append_declaration( append_declaration(
"docks", "docks",
" ".join( " ".join(
(f"{key}={value}/{z}" if z else f"{key}={value}") (f"{name}={edge}/{z}" if z else f"{name}={edge}")
for key, value, z in self._rule_docks for name, edge, z in self._rule_docks
), ),
) )
if self._rule_layers is not None: if self._rule_layers is not None:

View File

@@ -134,7 +134,6 @@ class Stylesheet:
for name, specificity_rules in rule_attributes.items() for name, specificity_rules in rule_attributes.items()
] ]
node.styles.apply_rules(node_rules) node.styles.apply_rules(node_rules)
log(node, node_rules)
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -46,7 +46,7 @@ expect_declaration_content = Expect(
comment_start=r"\/\*", comment_start=r"\/\*",
percentage=r"\d+\%", percentage=r"\d+\%",
scalar=r"\d+\.?\d*(?:fr|%)?", scalar=r"\d+\.?\d*(?:fr|%)?",
color=r"\#[0-9a-f]{6}|color\([0-9]{1,3}\)|rgb\(\d{1,3}\,\s?\d{1,3}\,\s?\d{1,3}\)", color=r"\#[0-9a-fA-F]{6}|color\([0-9]{1,3}\)|rgb\(\d{1,3}\,\s?\d{1,3}\,\s?\d{1,3}\)",
key_value=r"[a-zA-Z_-][a-zA-Z0-9_-]*=[0-9a-zA-Z_\-\/]+", key_value=r"[a-zA-Z_-][a-zA-Z0-9_-]*=[0-9a-zA-Z_\-\/]+",
token="[a-zA-Z_-]+", token="[a-zA-Z_-]+",
string=r"\".*?\"", string=r"\".*?\"",

View File

@@ -67,7 +67,6 @@ class DockLayout(Layout):
self, view: View, size: Size, scroll: Offset self, view: View, size: Size, scroll: Offset
) -> Iterable[WidgetPlacement]: ) -> Iterable[WidgetPlacement]:
map: LayoutMap = LayoutMap(size)
width, height = size width, height = size
layout_region = Region(0, 0, width, height) layout_region = Region(0, 0, width, height)
layers: dict[int, Region] = defaultdict(lambda: layout_region) layers: dict[int, Region] = defaultdict(lambda: layout_region)
@@ -170,5 +169,3 @@ class DockLayout(Layout):
region = Region(x, y, width - total, height) region = Region(x, y, width - total, height)
layers[z] = region layers[z] = region
return map

View File

@@ -52,6 +52,9 @@ class Message:
cls.bubble = bubble cls.bubble = bubble
cls.verbosity = verbosity cls.verbosity = verbosity
def set_done(self) -> None:
self._done_event.set()
@property @property
def _done_event(self) -> Event: def _done_event(self) -> Event:
if self.__done_event is None: if self.__done_event is None:

View File

@@ -225,14 +225,11 @@ class MessagePump:
async def dispatch_message(self, message: Message) -> bool | None: async def dispatch_message(self, message: Message) -> bool | None:
_rich_traceback_guard = True _rich_traceback_guard = True
try: if isinstance(message, events.Event):
if isinstance(message, events.Event): if not isinstance(message, events.Null):
if not isinstance(message, events.Null): await self.on_event(message)
await self.on_event(message) else:
else: return await self.on_message(message)
return await self.on_message(message)
finally:
message._done_event.set()
return False return False
def _get_dispatch_methods( def _get_dispatch_methods(
@@ -248,9 +245,12 @@ class MessagePump:
async def on_event(self, event: events.Event) -> None: async def on_event(self, event: events.Event) -> None:
_rich_traceback_guard = True _rich_traceback_guard = True
for method in self._get_dispatch_methods(f"on_{event.name}", event): try:
log(event, ">>>", self, verbosity=event.verbosity) for method in self._get_dispatch_methods(f"on_{event.name}", event):
await invoke(method, event) log(event, ">>>", self, verbosity=event.verbosity)
await invoke(method, event)
finally:
event.set_done()
if event.bubble and self._parent and not event._stop_propagation: if event.bubble and self._parent and not event._stop_propagation:
if event.sender == self._parent: if event.sender == self._parent:
@@ -264,9 +264,12 @@ class MessagePump:
method_name = f"handle_{message.name}" method_name = f"handle_{message.name}"
method = getattr(self, method_name, None) method = getattr(self, method_name, None)
if method is not None: try:
log(message, ">>>", self, verbosity=message.verbosity) if method is not None:
await invoke(method, message) log(message, ">>>", self, verbosity=message.verbosity)
await invoke(method, message)
finally:
message.set_done()
if message.bubble and self._parent and not message._stop_propagation: if message.bubble and self._parent and not message._stop_propagation:
if message.sender == self._parent: if message.sender == self._parent:

View File

@@ -118,6 +118,7 @@ class View(Widget):
if cached_size == size and cached_scroll == scroll: if cached_size == size and cached_scroll == scroll:
return arrangement return arrangement
arrangement = list(self._layout.arrange(self, size, scroll)) arrangement = list(self._layout.arrange(self, size, scroll))
self.log(arrangement)
self._cached_arrangement = (size, scroll, arrangement) self._cached_arrangement = (size, scroll, arrangement)
return arrangement return arrangement

View File

@@ -19,7 +19,7 @@ from rich.padding import Padding
from rich.pretty import Pretty from rich.pretty import Pretty
from rich.style import Style from rich.style import Style
from rich.styled import Styled from rich.styled import Styled
from rich.text import TextType from rich.text import Text, TextType
from . import events from . import events
from . import errors from . import errors
@@ -135,24 +135,28 @@ class Widget(DOMNode):
Returns: Returns:
RenderableType: A new renderable. RenderableType: A new renderable.
""" """
renderable = Styled(self.render(), self.styles.text)
renderable = self.render()
styles = self.styles
if self.padding is not None: if self.padding is not None:
renderable = Padding(renderable, self.padding) renderable = Padding(renderable, self.padding)
if self.border not in ("", "none"):
_border_style = self.console.get_style(self.border_style) if styles.has_border:
renderable = Border( renderable = Border(renderable, styles.border)
renderable,
( # _border_style = self.console.get_style(self.border_style)
("heavy", _border_style), # renderable = Border(
("heavy", _border_style), # renderable,
("heavy", _border_style), # (
("heavy", _border_style), # ("heavy", _border_style),
), # ("heavy", _border_style),
) # ("heavy", _border_style),
# ("heavy", _border_style),
# ),
# )
if self.margin is not None: if self.margin is not None:
renderable = Padding(renderable, self.margin) renderable = Padding(renderable, self.margin)
if self.style: renderable = Styled(renderable, styles.text)
renderable = Styled(renderable, self.style)
return renderable return renderable
@property @property
@@ -269,9 +273,7 @@ class Widget(DOMNode):
Returns: Returns:
RenderableType: Any renderable RenderableType: Any renderable
""" """
return Panel( return Align.center(Text(f"#{self.id}"), vertical="middle")
Align.center(Pretty(self), vertical="middle"), title=self.__class__.__name__
)
async def action(self, action: str, *params) -> None: async def action(self, action: str, *params) -> None:
await self.app.action(action, self) await self.app.action(action, self)

View File

@@ -10,7 +10,6 @@ import rich.repr
from logging import getLogger from logging import getLogger
from .. import events from .. import events
from ..geometry import Offset
from ..widget import Reactive, Widget from ..widget import Reactive, Widget
log = getLogger("rich") log = getLogger("rich")