Merge pull request #755 from Textualize/layout-ordeer

Layout order
This commit is contained in:
Will McGugan
2022-09-09 20:56:03 +01:00
committed by GitHub
5 changed files with 97 additions and 13 deletions

View File

@@ -0,0 +1,36 @@
from textual.app import App, ComposeResult
from textual.widgets import Static
class OrderApp(App):
CSS = """
Screen {
layout: center;
}
Static {
border: heavy white;
}
#one {
background: red;
width:20;
height: 30;
dock:left;
}
#two {
background: blue;
width:30;
height: 20;
dock:left;
}
"""
def compose(self) -> ComposeResult:
yield Static("One", id="one")
yield Static("Two", id="two")
app = OrderApp()
if __name__ == "__main__":
app.run()

View File

@@ -0,0 +1,39 @@
from textual.app import App, ComposeResult
from textual.widgets import Static
class OrderApp(App):
CSS = """
Screen {
layout: center;
}
Static {
border: heavy white;
}
#one {
background: red;
width:20;
height: 30;
}
#two {
background: blue;
width:30;
height: 20;
}
#three {
background: green;
width:40;
height:10
}
"""
def compose(self) -> ComposeResult:
yield Static("One", id="one")
yield Static("Two", id="two")
yield Static("Three", id="three")
app = OrderApp()
if __name__ == "__main__":
app.run()

View File

@@ -1,6 +1,6 @@
from __future__ import annotations
from collections import defaultdict
from fractions import Fraction
from operator import attrgetter
from typing import Sequence, TYPE_CHECKING
@@ -30,14 +30,13 @@ def arrange(
Returns:
tuple[list[WidgetPlacement], set[Widget], Spacing]: Widget arrangement information.
"""
display_children = [child for child in children if child.display]
arrange_widgets: set[Widget] = set()
dock_layers: dict[str, list[Widget]] = {}
dock_layers_setdefault = dock_layers.setdefault
for child in display_children:
dock_layers_setdefault(child.styles.layer or "default", []).append(child)
dock_layers: defaultdict[str, list[Widget]] = defaultdict(list)
for child in children:
if child.display:
dock_layers[child.styles.layer or "default"].append(child)
width, height = size
@@ -103,7 +102,6 @@ def arrange(
layout_placements, arranged_layout_widgets = widget._layout.arrange(
widget, layout_widgets, region.size
)
if arranged_layout_widgets:
scroll_spacing = scroll_spacing.grow_maximum(dock_spacing)
arrange_widgets.update(arranged_layout_widgets)

View File

@@ -178,6 +178,7 @@ class Compositor:
def __init__(self) -> None:
# A mapping of Widget on to its "render location" (absolute position / depth)
self.map: CompositorMap = {}
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
@@ -255,6 +256,7 @@ class Compositor:
ReflowResult: Hidden shown and resized widgets
"""
self._cuts = None
self._layers = None
self.root = parent
self.size = size
@@ -342,7 +344,6 @@ class Compositor:
map: CompositorMap = {}
widgets: set[Widget] = set()
get_order = attrgetter("order")
def add_widget(
widget: Widget,
@@ -388,7 +389,6 @@ class Compositor:
child_region.size
)
widgets.update(arranged_widgets)
placements = sorted(placements, key=get_order)
# An offset added to all placements
placement_offset = container_region.offset + layout_offset
@@ -401,7 +401,9 @@ class Compositor:
get_layer_index = layers_to_index.get
# Add all the widgets
for sub_region, margin, sub_widget, z, fixed in 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
@@ -458,6 +460,15 @@ class Compositor:
add_widget(root, size.region, size.region, (0,), size.region)
return map, widgets
@property
def layers(self) -> list[tuple[Widget, MapGeometry]]:
"""Get widgets and geometry in layer order."""
if self._layers is None:
self._layers = sorted(
self.map.items(), key=lambda item: item[1].order, reverse=True
)
return self._layers
def __iter__(self) -> Iterator[tuple[Widget, Region, Region, Size, Size]]:
"""Iterate map with information regarding each widget and is position
@@ -465,9 +476,9 @@ class Compositor:
Iterator[tuple[Widget, Region, Region, Size, Size]]: Iterates a tuple of
Widget, clip region, region, virtual size, and container size.
"""
layers = sorted(self.map.items(), key=lambda item: item[1].order, reverse=True)
layers = self.layers
intersection = Region.intersection
for widget, (region, _order, clip, virtual_size, container_size, *_) in layers:
for widget, (region, _order, clip, virtual_size, container_size, _) in layers:
yield (
widget,
intersection(region, clip),

View File

@@ -31,7 +31,7 @@ class HeaderClock(Widget):
DEFAULT_CSS = """
HeaderClock {
dock: right;
width: auto;
width: 10;
padding: 0 1;
background: $secondary-background-lighten-1;
color: $text-secondary-background;