mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
layout refactor
This commit is contained in:
@@ -45,7 +45,7 @@ class UpdateMessage(Message):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
sender: MessagePump,
|
sender: MessagePump,
|
||||||
widget: WidgetBase,
|
widget: Widget,
|
||||||
offset_x: int = 0,
|
offset_x: int = 0,
|
||||||
offset_y: int = 0,
|
offset_y: int = 0,
|
||||||
):
|
):
|
||||||
@@ -76,15 +76,15 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
self._default = default
|
self._default = default
|
||||||
self.validator = validator
|
self.validator = validator
|
||||||
|
|
||||||
def __set_name__(self, owner: "WidgetBase", name: str) -> None:
|
def __set_name__(self, owner: "Widget", name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.internal_name = f"__{name}"
|
self.internal_name = f"__{name}"
|
||||||
setattr(owner, self.internal_name, self._default)
|
setattr(owner, self.internal_name, self._default)
|
||||||
|
|
||||||
def __get__(self, obj: "WidgetBase", obj_type: type[object]) -> ReactiveType:
|
def __get__(self, obj: "Widget", obj_type: type[object]) -> ReactiveType:
|
||||||
return getattr(obj, self.internal_name)
|
return getattr(obj, self.internal_name)
|
||||||
|
|
||||||
def __set__(self, obj: "WidgetBase", value: ReactiveType) -> None:
|
def __set__(self, obj: "Widget", value: ReactiveType) -> None:
|
||||||
if getattr(obj, self.internal_name) != value:
|
if getattr(obj, self.internal_name) != value:
|
||||||
|
|
||||||
current_value = getattr(obj, self.internal_name, None)
|
current_value = getattr(obj, self.internal_name, None)
|
||||||
@@ -104,7 +104,7 @@ class Reactive(Generic[ReactiveType]):
|
|||||||
|
|
||||||
|
|
||||||
@rich.repr.auto
|
@rich.repr.auto
|
||||||
class WidgetBase(MessagePump):
|
class Widget(MessagePump):
|
||||||
_id: ClassVar[int] = 0
|
_id: ClassVar[int] = 0
|
||||||
_counts: ClassVar[dict[str, int]] = {}
|
_counts: ClassVar[dict[str, int]] = {}
|
||||||
can_focus: bool = False
|
can_focus: bool = False
|
||||||
@@ -114,8 +114,8 @@ class WidgetBase(MessagePump):
|
|||||||
Widget._counts.setdefault(class_name, 0)
|
Widget._counts.setdefault(class_name, 0)
|
||||||
Widget._counts[class_name] += 1
|
Widget._counts[class_name] += 1
|
||||||
_count = self._counts[class_name]
|
_count = self._counts[class_name]
|
||||||
self.id: WidgetID = cast(WidgetID, WidgetBase._id)
|
self.id: WidgetID = cast(WidgetID, Widget._id)
|
||||||
WidgetBase._id += 1
|
Widget._id += 1
|
||||||
|
|
||||||
self.name = name or f"{class_name}#{_count}"
|
self.name = name or f"{class_name}#{_count}"
|
||||||
|
|
||||||
@@ -173,7 +173,6 @@ class WidgetBase(MessagePump):
|
|||||||
self.post_message_no_wait(events.Null(self))
|
self.post_message_no_wait(events.Null(self))
|
||||||
|
|
||||||
def check_repaint(self) -> bool:
|
def check_repaint(self) -> bool:
|
||||||
return True
|
|
||||||
return self._repaint_required
|
return self._repaint_required
|
||||||
|
|
||||||
async def forward_event(self, event: events.Event) -> None:
|
async def forward_event(self, event: events.Event) -> None:
|
||||||
@@ -188,29 +187,6 @@ class WidgetBase(MessagePump):
|
|||||||
"""Instructs parent to repaint this widget."""
|
"""Instructs parent to repaint this widget."""
|
||||||
await self.emit(UpdateMessage(self, self))
|
await self.emit(UpdateMessage(self, self))
|
||||||
|
|
||||||
def render_update(self, x: int, y: int) -> Iterable[Segment]:
|
|
||||||
"""Render an update to a portion of the screen.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
x (int): X offset from origin.
|
|
||||||
y (int): Y offset form origin.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Iterable[Segment]: Partial update.
|
|
||||||
"""
|
|
||||||
return
|
|
||||||
|
|
||||||
width, height = self.size
|
|
||||||
lines = self.console.render_lines(
|
|
||||||
self.render(), self.console.options.update_dimensions(width, height)
|
|
||||||
)
|
|
||||||
|
|
||||||
new_line = Segment.line()
|
|
||||||
for last, line in loop_last(lines):
|
|
||||||
yield from line
|
|
||||||
if not last:
|
|
||||||
yield new_line
|
|
||||||
|
|
||||||
def render(self) -> RenderableType:
|
def render(self) -> RenderableType:
|
||||||
"""Get renderable for widget.
|
"""Get renderable for widget.
|
||||||
|
|
||||||
@@ -241,31 +217,6 @@ class WidgetBase(MessagePump):
|
|||||||
if self.check_repaint():
|
if self.check_repaint():
|
||||||
await self.repaint()
|
await self.repaint()
|
||||||
|
|
||||||
|
|
||||||
class Widget(WidgetBase):
|
|
||||||
def __init__(self, name: str | None = None) -> None:
|
|
||||||
super().__init__(name)
|
|
||||||
self._line_cache: LineCache | None = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def line_cache(self) -> LineCache:
|
|
||||||
|
|
||||||
if self._line_cache is None:
|
|
||||||
width, height = self.size
|
|
||||||
try:
|
|
||||||
renderable = self.render()
|
|
||||||
except Exception:
|
|
||||||
log.exception("error in render")
|
|
||||||
raise
|
|
||||||
self._line_cache = LineCache.from_renderable(
|
|
||||||
self.console, renderable, width, height
|
|
||||||
)
|
|
||||||
assert self._line_cache is not None
|
|
||||||
return self._line_cache
|
|
||||||
|
|
||||||
# def __rich__(self) -> LineCache:
|
|
||||||
# return self.line_cache
|
|
||||||
|
|
||||||
async def focus(self) -> None:
|
async def focus(self) -> None:
|
||||||
await self.app.set_focus(self)
|
await self.app.set_focus(self)
|
||||||
|
|
||||||
@@ -273,19 +224,9 @@ class Widget(WidgetBase):
|
|||||||
await self.app.capture_mouse(self if capture else None)
|
await self.app.capture_mouse(self if capture else None)
|
||||||
|
|
||||||
def get_style_at(self, x: int, y: int) -> Style:
|
def get_style_at(self, x: int, y: int) -> Style:
|
||||||
|
return
|
||||||
return self.line_cache.get_style_at(x, y)
|
return self.line_cache.get_style_at(x, y)
|
||||||
|
|
||||||
def render(self) -> RenderableType:
|
|
||||||
raise NotImplementedError
|
|
||||||
# return self.line_cache
|
|
||||||
|
|
||||||
def require_repaint(self) -> None:
|
|
||||||
self._line_cache = None
|
|
||||||
super().require_repaint()
|
|
||||||
|
|
||||||
def check_repaint(self) -> bool:
|
|
||||||
return self._line_cache is None or self.line_cache.dirty
|
|
||||||
|
|
||||||
def render_update(self, x: int, y: int) -> Iterable[Segment]:
|
def render_update(self, x: int, y: int) -> Iterable[Segment]:
|
||||||
"""Render an update to a portion of the screen.
|
"""Render an update to a portion of the screen.
|
||||||
|
|
||||||
@@ -299,16 +240,16 @@ class Widget(WidgetBase):
|
|||||||
width, height = self.size
|
width, height = self.size
|
||||||
yield from self.line_cache.render(x, y, width, height)
|
yield from self.line_cache.render(x, y, width, height)
|
||||||
|
|
||||||
async def on_mouse_move(self, event: events.MouseMove) -> None:
|
# async def on_mouse_move(self, event: events.MouseMove) -> None:
|
||||||
style_under_cursor = self.get_style_at(event.x, event.y)
|
# style_under_cursor = self.get_style_at(event.x, event.y)
|
||||||
if style_under_cursor:
|
# if style_under_cursor:
|
||||||
log.debug("%r", style_under_cursor)
|
# log.debug("%r", style_under_cursor)
|
||||||
|
|
||||||
async def on_mouse_up(self, event: events.MouseUp) -> None:
|
# async def on_mouse_up(self, event: events.MouseUp) -> None:
|
||||||
style = self.get_style_at(event.x, event.y)
|
# style = self.get_style_at(event.x, event.y)
|
||||||
if "@click" in style.meta:
|
# if "@click" in style.meta:
|
||||||
log.debug(style._link_id)
|
# log.debug(style._link_id)
|
||||||
await self.app.action(style.meta["@click"], default_namespace=self)
|
# await self.app.action(style.meta["@click"], default_namespace=self)
|
||||||
|
|
||||||
|
|
||||||
class StaticWidget(Widget):
|
class StaticWidget(Widget):
|
||||||
|
|||||||
Reference in New Issue
Block a user