diff --git a/src/textual/_arrange.py b/src/textual/_arrange.py index 2bf706e0f..102c17844 100644 --- a/src/textual/_arrange.py +++ b/src/textual/_arrange.py @@ -50,7 +50,7 @@ def arrange( get_dock = attrgetter("styles.dock") styles = widget.styles - for widgets in dock_layers.values(): + for index, widgets in enumerate(dock_layers.values()): layout_widgets, dock_widgets = partition(get_dock, widgets) diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index 75dc2a51f..689e5b93c 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -388,16 +388,16 @@ class Compositor: spatial_map.total_region.grow(spacing) ) - placements = spatial_map.get_placements( - child_region.reset_offset.translate(widget.scroll_offset) - ) - widgets.update(arranged_widgets) # An offset added to all placements placement_offset = container_region.offset + layout_offset placement_scroll_offset = placement_offset - widget.scroll_offset + placements = spatial_map.get_placements( + (child_region.size.region).translate(widget.scroll_offset) + ) + _layers = widget.layers layers_to_index = { layer_name: index for index, layer_name in enumerate(_layers) diff --git a/src/textual/_spatial_map.py b/src/textual/_spatial_map.py index eb2685554..8f5d9879e 100644 --- a/src/textual/_spatial_map.py +++ b/src/textual/_spatial_map.py @@ -8,6 +8,7 @@ from typing import Iterable, Sequence from ._layout import WidgetPlacement from .geometry import Region, Spacing from ._partition import partition +from ._profile import timer class SpatialMap: @@ -27,8 +28,8 @@ class SpatialMap: self, placements: Sequence[WidgetPlacement], *, - block_width: int = 80, - block_height: int = 80, + block_width: int = 40, + block_height: int = 20, ) -> None: self._placements = placements self._total_region = Region() @@ -39,8 +40,6 @@ class SpatialMap: self.placement_map = self._build_placements(placements) - print("SPATIAL", len(placements)) - def __iter__(self) -> Iterable[WidgetPlacement]: yield from self._placements @@ -92,17 +91,24 @@ class SpatialMap: Returns: Iterable[WidgetPlacement]: A super-set of Widget placements that may be in the screen. """ + return [ + placement + for placement in self._placements + if screen_region.overlaps(placement.region) + ] x1, y1, width, height = screen_region x2 = x1 + width y2 = y1 + height block_width = self._block_width block_height = self._block_height - placements: set[WidgetPlacement] = set(self._fixed) + placements: set[WidgetPlacement] = set() extend_placements = placements.update map = self.placement_map map_get = map.get + overlaps_screen = screen_region.overlaps + for coord in product( range(x1 // block_width, x2 // block_width + 1), range(y1 // block_height, y2 // block_height + 1), @@ -111,4 +117,13 @@ class SpatialMap: if block_placements is not None: extend_placements(block_placements) - return list(placements) + _placements = [ + placement + for placement in self._placements + if placement in placements and not placement.fixed + ] + + visible_placements = self._fixed + [ + placement for placement in _placements if overlaps_screen(placement.region) + ] + return visible_placements diff --git a/src/textual/widget.py b/src/textual/widget.py index 292b670ba..275320558 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -759,14 +759,12 @@ class Widget(DOMNode): def watch_scroll_x(self, new_value: float) -> None: if self.show_horizontal_scrollbar: self.horizontal_scrollbar.position = int(new_value) - self.horizontal_scrollbar.refresh() - self.refresh(layout=True) + self.refresh(layout=True, repaint=False) def watch_scroll_y(self, new_value: float) -> None: if self.show_vertical_scrollbar: self.vertical_scrollbar.position = int(new_value) - self.vertical_scrollbar.refresh() - self.refresh(layout=True) + self.refresh(layout=True, repaint=False) def validate_scroll_x(self, value: float) -> float: return clamp(value, 0, self.max_scroll_x) @@ -2134,12 +2132,12 @@ class Widget(DOMNode): layout (bool, optional): Also layout widgets in the view. Defaults to False. """ - if layout: + if layout and not self._layout_required: self._layout_required = True if isinstance(self._parent, Widget): self._parent._clear_arrangement_cache() - if repaint: + if repaint and not self._repaint_required: self._set_dirty(*regions) self._content_width_cache = (None, 0) self._content_height_cache = (None, 0)