fix for simple case

This commit is contained in:
Will McGugan
2022-05-26 11:15:44 +01:00
parent 153567d3b1
commit 5c10f944ed
9 changed files with 56 additions and 50 deletions

View File

@@ -3,10 +3,6 @@ from textual.app import App
class ExampleApp(App):
CSS = """
"""
COLORS = [
"white",
"maroon",
@@ -22,15 +18,12 @@ class ExampleApp(App):
def on_mount(self):
self.styles.background = "darkblue"
self.bind("t", "tree")
def on_key(self, event):
if event.key.isdigit():
self.styles.background = self.COLORS[int(event.key)]
self.bell()
def action_tree(self):
self.log(self.tree)
app = ExampleApp()
app.run()

View File

@@ -5,7 +5,7 @@ from textual.widget import Widget
class WidthApp(App):
CSS = """
Widget {
background: blue;
background: blue 50%;
width: 50%;
}
"""

View File

@@ -12,7 +12,7 @@ TEXT = Text.from_markup(lorem)
class TextWidget(Widget):
def render(self, style):
def render(self):
return TEXT

View File

@@ -221,7 +221,7 @@ class Compositor:
# Keep a copy of the old map because we're going to compare it with the update
old_map = self.map.copy()
old_widgets = old_map.keys()
map, widgets = self._arrange_root(parent)
map, widgets = self._arrange_root(parent, size)
# parent.log(map)
@@ -246,17 +246,16 @@ class Compositor:
resized_widgets = {
widget
for widget, (region, *_) in map.items()
if widget in old_widgets and widget.size != region.size
if widget in old_widgets and old_map[widget].region.size != region.size
}
# Gets pairs of tuples of (Widget, MapGeometry) which have changed
# i.e. if something is moved / deleted / added
screen = size.region
if screen not in self._dirty_regions:
crop_screen = screen.intersection
changes: set[tuple[Widget, MapGeometry]] = (
self.map.items() ^ old_map.items()
)
changes = map.items() ^ old_map.items()
self._dirty_regions.update(
[
crop_screen(map_geometry.visible_region)
@@ -270,7 +269,9 @@ class Compositor:
resized=resized_widgets,
)
def _arrange_root(self, root: Widget) -> tuple[CompositorMap, set[Widget]]:
def _arrange_root(
self, root: Widget, size: Size
) -> tuple[CompositorMap, set[Widget]]:
"""Arrange a widgets children based on its layout attribute.
Args:
@@ -282,7 +283,7 @@ class Compositor:
"""
ORIGIN = Offset(0, 0)
size = root.size
map: CompositorMap = {}
widgets: set[Widget] = set()
get_order = attrgetter("order")

View File

@@ -526,7 +526,7 @@ class App(Generic[ReturnType], DOMNode):
self.screen.refresh(layout=True)
def render(self) -> RenderableType:
return Blank("red")
return Blank()
def query(self, selector: str | None = None) -> DOMQuery:
"""Get a DOM query in the current screen.
@@ -737,6 +737,7 @@ class App(Generic[ReturnType], DOMNode):
driver = self._driver = self.driver_class(self.console, self)
driver.start_application_mode()
with redirect_stdout(StdoutRedirector(self.devtools, self._log_file)): # type: ignore
try:
mount_event = events.Mount(sender=self)
await self.dispatch_message(mount_event)
@@ -745,8 +746,6 @@ class App(Generic[ReturnType], DOMNode):
self.stylesheet.update(self)
self.refresh()
await self.animator.start()
with redirect_stdout(StdoutRedirector(self.devtools, self._log_file)): # type: ignore
await self._ready()
await super().process_messages()
await self.animator.stop()
@@ -872,7 +871,11 @@ class App(Generic[ReturnType], DOMNode):
await self.close_messages()
def refresh(self, *, repaint: bool = True, layout: bool = False) -> None:
self._display(self.screen._compositor)
self.screen.refresh(repaint=repaint, layout=layout)
# self._display(self.screen._compositor.render())
def _paint(self):
self._display(self.screen._compositor.render())
def refresh_css(self, animate: bool = True) -> None:
"""Refresh CSS.
@@ -1052,11 +1055,11 @@ class App(Generic[ReturnType], DOMNode):
async def handle_update(self, message: messages.Update) -> None:
message.stop()
self.app.refresh()
self._paint()
async def handle_layout(self, message: messages.Layout) -> None:
message.stop()
self.app.refresh()
self._paint()
async def on_key(self, event: events.Key) -> None:
if event.key == "tab":
@@ -1071,6 +1074,9 @@ class App(Generic[ReturnType], DOMNode):
await self.close_messages()
async def on_resize(self, event: events.Resize) -> None:
event.stop()
self.screen._screen_resized(event.size)
await self.screen.post_message(event)
async def action_press(self, key: str) -> None:

View File

@@ -476,7 +476,6 @@ class Styles(StylesBase):
return self._rules.get(rule, default)
def refresh(self, *, layout: bool = False) -> None:
print(self, self.node, "REFRESH", layout)
if self.node is not None:
self.node.refresh(layout=layout)

View File

@@ -11,12 +11,12 @@ class Blank:
"""Draw solid background color."""
def __init__(self, color: Color | str = "transparent") -> None:
background = (
color.rich_color
if isinstance(color, Color)
else Color.parse(color).rich_color
background = color if isinstance(color, Color) else Color.parse(color)
self._style = (
Style()
if background.is_transparent
else Style.from_color(None, background.rich_color)
)
self._style = Style.from_color(None, background)
def __rich_console__(
self, console: Console, options: ConsoleOptions

View File

@@ -9,9 +9,11 @@ from rich.style import Style
from . import events, messages, errors
from .geometry import Offset, Region
from .color import Color
from .geometry import Offset, Region, Size
from ._compositor import Compositor, MapGeometry
from .reactive import Reactive
from .renderables.blank import Blank
from .widget import Widget
if sys.version_info >= (3, 8):
@@ -31,10 +33,6 @@ class Screen(Widget):
Screen {
layout: vertical;
overflow-y: auto;
/*
background: $surface;
color: $text-surface;
*/
}
"""
@@ -45,11 +43,15 @@ class Screen(Widget):
self._compositor = Compositor()
self._dirty_widgets: set[Widget] = set()
@property
def is_transparent(self) -> bool:
return False
def watch_dark(self, dark: bool) -> None:
pass
def render(self) -> RenderableType:
return self.app.render()
return Blank()
def get_offset(self, widget: Widget) -> Offset:
"""Get the absolute offset of a given Widget.
@@ -114,15 +116,16 @@ class Screen(Widget):
self._dirty_widgets.clear()
self._update_timer.pause()
def _refresh_layout(self) -> None:
def _refresh_layout(self, size: Size | None = None, full: bool = False) -> None:
"""Refresh the layout (can change size and positions of widgets)."""
if not self.size:
size = self.size if size is None else size
if not size:
return
# This paint the entire screen, so replaces the batched dirty widgets
self._compositor.update_widgets(self._dirty_widgets)
self._update_timer.pause()
try:
hidden, shown, resized = self._compositor.reflow(self, self.size)
hidden, shown, resized = self._compositor.reflow(self, size)
Hide = events.Hide
Show = events.Show
@@ -131,6 +134,7 @@ class Screen(Widget):
for widget in shown:
widget.post_message_no_wait(Show(self))
# We want to send a resize event to widgets that were just added or change since last layout
send_resize = shown | resized
for (
@@ -151,7 +155,7 @@ class Screen(Widget):
self.app.on_exception(error)
return
display_update = self._compositor.render()
display_update = self._compositor.render(full=full)
if display_update is not None:
self.app._display(display_update)
@@ -172,9 +176,13 @@ class Screen(Widget):
UPDATE_PERIOD, self._on_update, name="screen_update", pause=True
)
def _screen_resized(self, size: Size):
self._refresh_layout(size, full=True)
async def on_resize(self, event: events.Resize) -> None:
self.size_updated(event.size, event.virtual_size, event.container_size)
event.stop()
# self._size = event.size
# self._refresh_layout(event.size, full=True)
async def _on_mouse_move(self, event: events.MouseMove) -> None:
try:

View File

@@ -769,7 +769,6 @@ class Widget(DOMNode):
self._size = size
self._virtual_size = virtual_size
self._container_size = container_size
if self.is_container:
self._refresh_scrollbars()
width, height = self.container_size