mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
remove spatial map
This commit is contained in:
@@ -50,7 +50,7 @@ def arrange(
|
||||
get_dock = attrgetter("styles.dock")
|
||||
styles = widget.styles
|
||||
|
||||
for index, widgets in enumerate(dock_layers.values()):
|
||||
for widgets in dock_layers.values():
|
||||
|
||||
layout_widgets, dock_widgets = partition(get_dock, widgets)
|
||||
|
||||
|
||||
@@ -381,12 +381,9 @@ class Compositor:
|
||||
|
||||
if widget.is_container:
|
||||
# Arrange the layout
|
||||
spatial_map, arranged_widgets, spacing = widget._arrange(
|
||||
placements, arranged_widgets, spacing = widget._arrange(
|
||||
child_region.size
|
||||
)
|
||||
total_region = total_region.union(
|
||||
spatial_map.total_region.grow(spacing)
|
||||
)
|
||||
|
||||
widgets.update(arranged_widgets)
|
||||
|
||||
@@ -394,10 +391,6 @@ class Compositor:
|
||||
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)
|
||||
@@ -405,11 +398,16 @@ class Compositor:
|
||||
get_layer_index = layers_to_index.get
|
||||
|
||||
# Add all the widgets
|
||||
for sub_region, _, sub_widget, z, fixed in reversed(placements):
|
||||
for sub_region, margin, sub_widget, z, fixed in reversed(
|
||||
placements
|
||||
):
|
||||
# Combine regions with children to calculate the "virtual size"
|
||||
if fixed:
|
||||
widget_region = sub_region + placement_offset
|
||||
else:
|
||||
total_region = total_region.union(
|
||||
sub_region.grow(spacing + margin)
|
||||
)
|
||||
widget_region = sub_region + placement_scroll_offset
|
||||
|
||||
widget_order = order + (
|
||||
|
||||
@@ -8,10 +8,9 @@ from ._typing import TypeAlias
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .widget import Widget
|
||||
from ._spatial_map import SpatialMap
|
||||
|
||||
ArrangeResult: TypeAlias = "tuple[list[WidgetPlacement], set[Widget]]"
|
||||
DockArrangeResult: TypeAlias = "SpacialMap, set[Widget], Spacing]"
|
||||
DockArrangeResult: TypeAlias = "list[WidgetPlacement], set[Widget], Spacing]"
|
||||
|
||||
|
||||
class WidgetPlacement(NamedTuple):
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from itertools import product
|
||||
from operator import attrgetter
|
||||
from typing import Iterable, Sequence
|
||||
|
||||
from ._layout import WidgetPlacement
|
||||
from .geometry import Region, Spacing
|
||||
from ._partition import partition
|
||||
from ._profile import timer
|
||||
|
||||
|
||||
class SpatialMap:
|
||||
"""An object to return WidgetPlacements within a given region.
|
||||
|
||||
The widget area is split in to a regular grid of buckets. Each placement is assigned to
|
||||
any bucket it overlaps, which may be 1 or more buckets.
|
||||
|
||||
The `get_placements` function will calculate which buckets overlap the screen area, and combine
|
||||
the placements from those buckets. This generally means that widgets that aren't overlapping or
|
||||
near the screen area can be quickly discarded. The result will typically be a superset of visible
|
||||
placements, which can then be filtered normally.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
placements: Sequence[WidgetPlacement],
|
||||
*,
|
||||
block_width: int = 40,
|
||||
block_height: int = 20,
|
||||
) -> None:
|
||||
self._placements = placements
|
||||
self._total_region = Region()
|
||||
self._block_width = block_width
|
||||
self._block_height = block_height
|
||||
self._fixed: list[WidgetPlacement] = []
|
||||
self._map: defaultdict[tuple[int, int], list[WidgetPlacement]] | None = None
|
||||
|
||||
self.placement_map = self._build_placements(placements)
|
||||
|
||||
def __iter__(self) -> Iterable[WidgetPlacement]:
|
||||
yield from self._placements
|
||||
|
||||
def __reversed__(self) -> Iterable[WidgetPlacement]:
|
||||
yield from reversed(self._placements)
|
||||
|
||||
def _build_placements(
|
||||
self, placements: Iterable[WidgetPlacement]
|
||||
) -> defaultdict[tuple[int, int], list[WidgetPlacement]]:
|
||||
"""Add placements to map.
|
||||
|
||||
Args:
|
||||
placements (Iterable[WidgetPlacement]): A number of placements.
|
||||
"""
|
||||
map: defaultdict[tuple[int, int], list[WidgetPlacement]] = defaultdict(list)
|
||||
get_bucket = map.__getitem__
|
||||
|
||||
block_width = self._block_width
|
||||
block_height = self._block_height
|
||||
|
||||
self.total_region = Region.from_union(
|
||||
[
|
||||
placement.region.grow(placement.margin)
|
||||
for placement in placements
|
||||
if not placement.fixed
|
||||
]
|
||||
)
|
||||
|
||||
placements, self._fixed = partition(attrgetter("fixed"), placements)
|
||||
|
||||
for placement in placements:
|
||||
x1, y1, width, height = placement.region
|
||||
x2 = x1 + width
|
||||
y2 = y1 + height
|
||||
for coord in product(
|
||||
range(x1 // block_width, x2 // block_width + 1),
|
||||
range(y1 // block_height, y2 // block_height + 1),
|
||||
):
|
||||
get_bucket(coord).append(placement)
|
||||
return map
|
||||
|
||||
def get_placements(self, screen_region: Region) -> list[WidgetPlacement]:
|
||||
"""Get placements that may overlap a given region. There may be false positives,
|
||||
but no false negatives.
|
||||
|
||||
Args:
|
||||
region (Region): Container region.
|
||||
|
||||
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()
|
||||
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),
|
||||
):
|
||||
block_placements = map_get(coord)
|
||||
if block_placements is not None:
|
||||
extend_placements(block_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
|
||||
@@ -39,7 +39,6 @@ from ._context import active_app
|
||||
from ._easing import DEFAULT_SCROLL_EASING
|
||||
from ._layout import Layout
|
||||
from ._segment_tools import align_lines
|
||||
from ._spatial_map import SpatialMap
|
||||
from ._styles_cache import StylesCache
|
||||
from ._types import Lines
|
||||
from .await_remove import AwaitRemove
|
||||
@@ -429,7 +428,7 @@ class Widget(DOMNode):
|
||||
placements, widgets, spacing = arrange(
|
||||
self, self.children, size, self.screen.size
|
||||
)
|
||||
arrange_result = SpatialMap(placements), widgets, spacing
|
||||
arrange_result = placements, widgets, spacing
|
||||
self._arrangement = arrange_result
|
||||
return self._arrangement
|
||||
|
||||
|
||||
Reference in New Issue
Block a user