event verbosity

This commit is contained in:
Will McGugan
2021-08-02 16:53:46 +01:00
parent 79e4a6003e
commit 3e7eb0e650
13 changed files with 52 additions and 102 deletions

View File

@@ -35,7 +35,7 @@ class GridTest(App):
area3=Placeholder(name="area3"),
area4=Placeholder(name="area4"),
)
await self.view.update_layout()
self.view.refresh(layout=True)
GridTest.run(title="Grid Test", log="textual.log")

View File

@@ -253,6 +253,7 @@ class App(MessagePump):
active_app.set(self)
driver = self._driver = self.driver_class(self.console, self)
log("---")
log(f"driver={self.driver_class}")
await self.dispatch_message(events.Load(sender=self))
@@ -332,7 +333,7 @@ class App(MessagePump):
driver.disable_input()
await self.close_messages()
def refresh(self) -> None:
def refresh(self, repaint: bool = True, layout: bool = False) -> None:
sync_available = os.environ.get("TERM_PROGRAM", "") != "Apple_Terminal"
if not self._closed:
console = self.console

View File

@@ -27,13 +27,13 @@ class Event(Message):
super().__init_subclass__(bubble=bubble, verbosity=verbosity)
class Null(Event):
class Null(Event, verbosity=3):
def can_replace(self, message: Message) -> bool:
return isinstance(message, Null)
@rich.repr.auto
class Callback(Event, bubble=False):
class Callback(Event, bubble=False, verbosity=3):
def __init__(
self, sender: MessageTarget, callback: Callable[[], Awaitable[None]]
) -> None:
@@ -88,7 +88,7 @@ class Action(Event, bubble=True):
yield "action", self.action
class Resize(Event):
class Resize(Event, verbosity=2):
"""Sent when the app or widget has been resized."""
__slots__ = ["size"]
@@ -360,7 +360,7 @@ class DoubleClick(MouseEvent):
@rich.repr.auto
class Timer(Event):
class Timer(Event, verbosity=3):
__slots__ = ["time", "count", "callback"]
def __init__(

View File

@@ -421,7 +421,6 @@ class Layout(ABC):
def update_widget(self, console: Console, widget: Widget) -> LayoutUpdate | None:
log("UPDATE", widget)
if widget not in self.regions:
return None
@@ -430,18 +429,7 @@ class Layout(ABC):
if not region.size:
return None
widget._clear_render_cache()
# if not region or not clip:
# return
# widget._clear_render_cache()
# widget.render_lines()
# new_lines = console.render_lines(
# widget, console.options.update_dimensions(region.width, region.height)
# )
# self.regions[widget] = (region, clip, new_lines)
widget.clear_render_cache()
update_region = region.intersection(clip)
update_lines = self.render(console, update_region).lines

View File

@@ -58,7 +58,7 @@ class LayoutMap:
sub_map = widget.layout.generate_map(
console, region.size, clip, widget.scroll
)
for widget, (sub_region, sub_order, sub_clip) in sub_map.items():
for sub_widget, (sub_region, sub_order, sub_clip) in sub_map.items():
sub_region += region.origin
sub_clip = sub_clip.intersection(clip)
self.add_widget(console, widget, sub_region, sub_order, sub_clip)
self.add_widget(console, sub_widget, sub_region, sub_order, sub_clip)

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
import asyncio
from asyncio import CancelledError
from asyncio import Queue, QueueEmpty, Task
import inspect
from typing import TYPE_CHECKING, Awaitable, Iterable, Callable
from weakref import WeakSet
@@ -24,6 +25,10 @@ class NoParent(Exception):
pass
class CallbackError(Exception):
pass
class MessagePumpClosed(Exception):
pass
@@ -301,4 +306,11 @@ class MessagePump:
event.prevent_default()
event.stop()
if event.callback is not None:
await event.callback()
try:
callback_result = event.callback()
if inspect.isawaitable(callback_result):
await callback_result
except Exception as error:
raise CallbackError(
f"unable to run callback {event.callback!r}; {error}"
)

View File

@@ -12,7 +12,7 @@ if TYPE_CHECKING:
@rich.repr.auto
class UpdateMessage(Message):
class UpdateMessage(Message, verbosity=3):
def __init__(
self,
sender: MessagePump,
@@ -30,6 +30,6 @@ class UpdateMessage(Message):
@rich.repr.auto
class LayoutMessage(Message):
class LayoutMessage(Message, verbosity=3):
def can_replace(self, message: Message) -> bool:
return isinstance(message, LayoutMessage)

View File

@@ -79,9 +79,9 @@ class Reactive(Generic[ReactiveType]):
self.check_watchers(obj, name, current_value)
if self.layout:
obj.require_layout()
obj.refresh(layout=True)
elif self.repaint:
obj.require_repaint()
obj.refresh()
@classmethod
def check_watchers(cls, obj: Reactable, name: str, old_value: Any) -> None:

View File

@@ -57,40 +57,6 @@ class View(Widget):
virtual_size: Reactive[Size] = Reactive(Size(0, 0))
# @property
# def virtual_size(self) -> Dimensions:
# return self.layout.map.size if self.layout.map else Dimensions(0, 0)
# virtual_width: Reactive[int | None] = Reactive(None)
# virtual_height: Reactive[int | None] = Reactive(None)
# @property
# def virtual_size(self) -> Dimensions:
# virtual_width = self.virtual_width
# virtual_height = self.virtual_height
# return Dimensions(
# (virtual_width if virtual_width is not None else self.size.width),
# (virtual_height if virtual_height is not None else self.size.height),
# )
# @virtual_size.setter
# def virtual_size(self, size: tuple[int, int]) -> None:
# width, height = size
# self.virtual_width = width
# self.virtual_height = height
# @property
# def offset(self) -> Point:
# return Point(self.offset_x, self.offset_y)
# @property
# def viewport(self) -> Region:
# virtual_width = self.virtual_width
# virtual_height = self.virtual_height
# width = virtual_width if virtual_width is not None else self.size.width
# height = virtual_height if virtual_height is not None else self.size.height
# return Region(self.offset_x, self.offset_y, width, height)
def __rich_console__(
self, console: Console, options: ConsoleOptions
) -> RenderResult:
@@ -109,7 +75,7 @@ class View(Widget):
@property
def is_root_view(self) -> bool:
return self._parent and self.parent is self.app
return bool(self._parent and self.parent is self.app)
def is_mounted(self, widget: Widget) -> bool:
return widget in self.widgets
@@ -159,16 +125,12 @@ class View(Widget):
return
width, height = self.console.size
# virtual_width, virtual_height = self.virtual_size
hidden, shown, resized = self.layout.reflow(
self.console, width, height, self.scroll
)
assert self.layout.map is not None
self.virtual_size = self.layout.map.virtual_size
# for widget, region in self.layout:
# widget._update_size(region.size)
# self.app.refresh()
# self.virtual_size = self.layout.map.virtual_size
self.log("VIRTUAL_SIZE", self, type(self.layout), self.virtual_size)
for widget in hidden:
widget.post_message_no_wait(events.Hide(self))

View File

@@ -40,8 +40,9 @@ class WindowView(View, layout=VerticalLayout):
await self.emit(VirtualSizeChange(self))
async def watch_virtual_size(self, size: Size) -> None:
self.log("VIRTUAL SIZE CHAGE")
await self.emit(VirtualSizeChange(self))
async def on_resize(self, event: events.Resize) -> None:
# self.layout.renders.pop(self.widget)
self.require_repaint()
# async def on_resize(self, event: events.Resize) -> None:
# # self.layout.renders.pop(self.widget)
# self.require_repaint()

View File

@@ -123,10 +123,6 @@ class Widget(MessagePump):
def _update_size(self, size: Size) -> None:
self._size = size
# if self._render_cache and self._render_cache.size != size:
# self.render_lines()
# self.require_repaint()
# self.size = size
def render_lines(self) -> RenderCache:
width, height = self.size
@@ -161,7 +157,7 @@ class Widget(MessagePump):
lines = self.render_cache.lines
return lines
def _clear_render_cache(self) -> None:
def clear_render_cache(self) -> None:
self.render_cache = None
def require_repaint(self) -> None:
@@ -199,17 +195,22 @@ class Widget(MessagePump):
async def forward_event(self, event: events.Event) -> None:
await self.post_message(event)
async def refresh(self) -> None:
"""Re-render the window and repaint it."""
self.require_repaint()
await self.repaint()
def refresh(self, repaint: bool = True, layout: bool = False) -> None:
"""Initiate a refresh of the widget.
async def repaint(self) -> None:
"""Instructs parent to repaint this widget."""
await self.emit(UpdateMessage(self, self))
This method sets an internal flag to perform a refresh, which will be done on the
next idle event. Only one refresh will be done even if this method is called multiple times.
async def update_layout(self) -> None:
await self.emit(LayoutMessage(self))
Args:
repaint (bool, optional): Repaint the widget (will call render() again). Defaults to True.
layout (bool, optional): Also layout widgets in the view. Defaults to False.
"""
if layout:
self._layout_required = True
elif repaint:
self.clear_render_cache()
self._repaint_required = True
self.post_message_no_wait(events.Null(self))
def render(self) -> RenderableType:
"""Get renderable for widget.
@@ -231,25 +232,17 @@ class Widget(MessagePump):
self.log(self, "IS NOT RUNNING")
return await super().post_message(message)
# async def on_event(self, event: events.Event) -> None:
# if isinstance(event, events.Resize):
# if self.size != event.size:
# # self.size = event.size
# self.require_repaint()
# await super().on_event(event)
async def on_resize(self, event: events.Resize) -> None:
self.log("RESIZE", self)
self.render_lines()
async def on_idle(self, event: events.Idle) -> None:
if self.check_layout():
self.reset_check_repaint()
self.reset_check_layout()
await self.update_layout()
await self.emit(LayoutMessage(self))
elif self.check_repaint():
self.reset_check_repaint()
await self.repaint()
await self.emit(UpdateMessage(self, self))
async def focus(self) -> None:
await self.app.set_focus(self)
@@ -276,10 +269,6 @@ class Widget(MessagePump):
if key_method is not None:
await key_method()
# async def on_repaint(self) -> None:
# if self._render_cache is None or self._render_cache.size != self.size:
# self._render_cache = self.render_lines()
async def on_mouse_down(self, event: events.MouseUp) -> None:
await self.broker_event("mouse.down", event)

View File

@@ -185,12 +185,9 @@ class ScrollView(View):
self.animate("y", self.target_y, speed=150, easing="out_cubic")
async def message_virtual_size_change(self, message: Message) -> None:
virtual_size = self.window.virtual_size
self.log("VIRTUAL_SIZE", self.size, virtual_size)
self.x = self.validate_x(self.x)
self.y = self.validate_y(self.y)
self.log(self.y)
self.vscroll.virtual_size = virtual_size.height
self.vscroll.window_size = self.size.height

View File

@@ -21,7 +21,7 @@ class Static(Widget):
self.padding = padding
def render(self) -> RenderableType:
self.log("RENDERING", self.renderable)
# self.log("RENDERING", self.renderable)
renderable = self.renderable
if self.padding:
renderable = Padding(renderable, self.padding)