mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Invalidate full map
This commit is contained in:
@@ -166,12 +166,14 @@ class Compositor:
|
||||
|
||||
def __init__(self) -> None:
|
||||
# A mapping of Widget on to its "render location" (absolute position / depth)
|
||||
self.map: CompositorMap = {}
|
||||
self._full_map: CompositorMap | None = None
|
||||
|
||||
self._full_map: CompositorMap = {}
|
||||
self._full_map_invalidated = True
|
||||
self._visible_map: CompositorMap | None = None
|
||||
self._layers: list[tuple[Widget, MapGeometry]] | None = None
|
||||
|
||||
# All widgets considered in the arrangement
|
||||
# Note this may be a superset of self.map.keys() as some widgets may be invisible for various reasons
|
||||
# Note this may be a superset of self.full_map.keys() as some widgets may be invisible for various reasons
|
||||
self.widgets: set[Widget] = set()
|
||||
|
||||
# Mapping of visible widgets on to their region, and clip region
|
||||
@@ -248,12 +250,12 @@ class Compositor:
|
||||
self._layers = None
|
||||
self._layers_visible = None
|
||||
self._visible_widgets = None
|
||||
self._full_map = None
|
||||
self._visible_map = None
|
||||
self.root = parent
|
||||
self.size = size
|
||||
|
||||
# Keep a copy of the old map because we're going to compare it with the update
|
||||
old_map = self.map
|
||||
old_map = self._full_map
|
||||
old_widgets = old_map.keys()
|
||||
|
||||
map, widgets = self._arrange_root(parent, size)
|
||||
@@ -261,7 +263,6 @@ class Compositor:
|
||||
new_widgets = map.keys()
|
||||
|
||||
# Replace map and widgets
|
||||
self.map = map
|
||||
self._full_map = map
|
||||
self.widgets = widgets
|
||||
|
||||
@@ -316,19 +317,22 @@ class Compositor:
|
||||
self._layers = None
|
||||
self._layers_visible = None
|
||||
self._visible_widgets = None
|
||||
self._full_map = None
|
||||
self._full_map_invalidated = True
|
||||
self.root = parent
|
||||
self.size = size
|
||||
|
||||
# Keep a copy of the old map because we're going to compare it with the update
|
||||
old_map = self.map
|
||||
old_map = (
|
||||
self._visible_map if self._visible_map is not None else self._full_map or {}
|
||||
)
|
||||
map, widgets = self._arrange_root(parent, size, visible_only=True)
|
||||
|
||||
exposed_widgets = map.keys() - old_map.keys()
|
||||
# Replace map and widgets
|
||||
self.map = map
|
||||
self._visible_map = map
|
||||
self.widgets = widgets
|
||||
|
||||
exposed_widgets = map.keys() - old_map.keys()
|
||||
|
||||
# Contains widgets + geometry for every widget that changed (added, removed, or updated)
|
||||
changes = map.items() ^ old_map.items()
|
||||
|
||||
@@ -350,11 +354,15 @@ class Compositor:
|
||||
@property
|
||||
def full_map(self) -> CompositorMap:
|
||||
"""Lazily built compositor map that covers all widgets."""
|
||||
if self.root is None or not self.map:
|
||||
|
||||
if self.root is None:
|
||||
return {}
|
||||
if self._full_map is None:
|
||||
if self._full_map_invalidated:
|
||||
self._full_map_invalidated = False
|
||||
map, widgets = self._arrange_root(self.root, self.size, visible_only=False)
|
||||
self._full_map = map
|
||||
self._visible_widgets = None
|
||||
self._visible_map = None
|
||||
|
||||
return self._full_map
|
||||
|
||||
@@ -365,7 +373,13 @@ class Compositor:
|
||||
Returns:
|
||||
Visible widget mapping.
|
||||
"""
|
||||
|
||||
if self._visible_widgets is None:
|
||||
map = (
|
||||
self._visible_map
|
||||
if self._visible_map is not None
|
||||
else (self._full_map or {})
|
||||
)
|
||||
screen = self.size.region
|
||||
in_screen = screen.overlaps
|
||||
overlaps = Region.overlaps
|
||||
@@ -373,7 +387,7 @@ class Compositor:
|
||||
# Widgets and regions in render order
|
||||
visible_widgets = [
|
||||
(order, widget, region, clip)
|
||||
for widget, (region, order, clip, _, _, _) in self.map.items()
|
||||
for widget, (region, order, clip, _, _, _) in map.items()
|
||||
if in_screen(region) and overlaps(clip, region)
|
||||
]
|
||||
visible_widgets.sort(key=itemgetter(0), reverse=True)
|
||||
@@ -556,9 +570,10 @@ class Compositor:
|
||||
@property
|
||||
def layers(self) -> list[tuple[Widget, MapGeometry]]:
|
||||
"""Get widgets and geometry in layer order."""
|
||||
map = self._visible_map if self._visible_map is not None else self._full_map
|
||||
if self._layers is None:
|
||||
self._layers = sorted(
|
||||
self.map.items(), key=lambda item: item[1].order, reverse=True
|
||||
map.items(), key=lambda item: item[1].order, reverse=True
|
||||
)
|
||||
return self._layers
|
||||
|
||||
@@ -585,12 +600,14 @@ class Compositor:
|
||||
def get_offset(self, widget: Widget) -> Offset:
|
||||
"""Get the offset of a widget."""
|
||||
try:
|
||||
return self.map[widget].region.offset
|
||||
if self._visible_map is not None:
|
||||
try:
|
||||
return self._visible_map[widget].region.offset
|
||||
except KeyError:
|
||||
pass
|
||||
return self.full_map[widget].region.offset
|
||||
except KeyError:
|
||||
try:
|
||||
return self.full_map[widget].region.offset
|
||||
except KeyError:
|
||||
raise errors.NoWidget("Widget is not in layout")
|
||||
raise errors.NoWidget("Widget is not in layout")
|
||||
|
||||
def get_widget_at(self, x: int, y: int) -> tuple[Widget, Region]:
|
||||
"""Get the widget under a given coordinate.
|
||||
@@ -672,15 +689,17 @@ class Compositor:
|
||||
Widget's composition information.
|
||||
|
||||
"""
|
||||
if self.root is None or not self.map:
|
||||
if self.root is None:
|
||||
raise errors.NoWidget("Widget is not in layout")
|
||||
try:
|
||||
region = self.map[widget]
|
||||
if self._visible_map is not None:
|
||||
try:
|
||||
return self._visible_map[widget]
|
||||
except KeyError:
|
||||
pass
|
||||
region = self.full_map[widget]
|
||||
except KeyError:
|
||||
try:
|
||||
return self.full_map[widget]
|
||||
except KeyError:
|
||||
raise errors.NoWidget("Widget is not in layout")
|
||||
raise errors.NoWidget("Widget is not in layout")
|
||||
else:
|
||||
return region
|
||||
|
||||
@@ -728,9 +747,6 @@ class Compositor:
|
||||
# up to this point.
|
||||
_rich_traceback_guard = True
|
||||
|
||||
if not self.map:
|
||||
return
|
||||
|
||||
_Region = Region
|
||||
|
||||
visible_widgets = self.visible_widgets
|
||||
@@ -864,7 +880,6 @@ class Compositor:
|
||||
widget: Widget to update.
|
||||
|
||||
"""
|
||||
self._full_map = None
|
||||
regions: list[Region] = []
|
||||
add_region = regions.append
|
||||
get_widget = self.visible_widgets.__getitem__
|
||||
|
||||
@@ -425,12 +425,12 @@ class Screen(Widget):
|
||||
self._compositor.update_widgets(self._dirty_widgets)
|
||||
self.update_timer.pause()
|
||||
ResizeEvent = events.Resize
|
||||
|
||||
try:
|
||||
if scroll:
|
||||
exposed_widgets = self._compositor.reflow_visible(self, size)
|
||||
if exposed_widgets:
|
||||
layers = self._compositor.layers
|
||||
|
||||
for widget, (
|
||||
region,
|
||||
_order,
|
||||
@@ -441,19 +441,14 @@ class Screen(Widget):
|
||||
) in layers:
|
||||
if widget in exposed_widgets:
|
||||
if widget._size_updated(
|
||||
region.size,
|
||||
virtual_size,
|
||||
container_size,
|
||||
layout=False,
|
||||
region.size, virtual_size, container_size, layout=False
|
||||
):
|
||||
widget.post_message_no_wait(
|
||||
ResizeEvent(
|
||||
self,
|
||||
region.size,
|
||||
virtual_size,
|
||||
container_size,
|
||||
self, region.size, virtual_size, container_size
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
hidden, shown, resized = self._compositor.reflow(self, size)
|
||||
Hide = events.Hide
|
||||
|
||||
@@ -150,4 +150,4 @@ class Placeholder(Widget):
|
||||
"""Update the placeholder "size" variant with the new placeholder size."""
|
||||
self._renderables["size"] = self._SIZE_RENDER_TEMPLATE.format(*event.size)
|
||||
if self.variant == "size":
|
||||
self.refresh(layout=False)
|
||||
self.refresh()
|
||||
|
||||
Reference in New Issue
Block a user