Skip to content

Commit 925c520

Browse files
committed
Stream layout
1 parent 7c2b65f commit 925c520

File tree

5 files changed

+63
-2
lines changed

5 files changed

+63
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ lib/
2929
lib64/
3030
parts/
3131
sdist/
32+
dist/
3233
var/
3334
wheels/
3435
*.egg-info/

src/textual/css/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"wide",
2929
}
3030
VALID_EDGE: Final = {"top", "right", "bottom", "left", "none"}
31-
VALID_LAYOUT: Final = {"vertical", "horizontal", "grid"}
31+
VALID_LAYOUT: Final = {"vertical", "horizontal", "grid", "stream"}
3232

3333
VALID_BOX_SIZING: Final = {"border-box", "content-box"}
3434
VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"}

src/textual/css/styles.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ class StylesBase:
284284
layout = LayoutProperty()
285285
"""Set the layout of the widget, defining how it's children are laid out.
286286
287-
Valid values are "grid", "horizontal", and "vertical" or None to clear any layout
287+
Valid values are "grid", "stream", "horizontal", or "vertical" or None to clear any layout
288288
that was set at runtime.
289289
290290
Raises:

src/textual/layouts/factory.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
from textual.layout import Layout
44
from textual.layouts.grid import GridLayout
55
from textual.layouts.horizontal import HorizontalLayout
6+
from textual.layouts.stream import StreamLayout
67
from textual.layouts.vertical import VerticalLayout
78

89
LAYOUT_MAP: dict[str, type[Layout]] = {
910
"horizontal": HorizontalLayout,
1011
"grid": GridLayout,
1112
"vertical": VerticalLayout,
13+
"stream": StreamLayout,
1214
}
1315

1416

src/textual/layouts/stream.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING
4+
5+
from textual.geometry import NULL_OFFSET, Region, Size
6+
from textual.layout import ArrangeResult, Layout, WidgetPlacement
7+
8+
if TYPE_CHECKING:
9+
10+
from textual.widget import Widget
11+
12+
13+
class StreamLayout(Layout):
14+
name = "stream"
15+
16+
def arrange(
17+
self, parent: Widget, children: list[Widget], size: Size, greedy: bool = True
18+
) -> ArrangeResult:
19+
parent.pre_layout(self)
20+
viewport = parent.app.size
21+
22+
placements: list[WidgetPlacement] = []
23+
if not children:
24+
return []
25+
width = size.width
26+
first_child_styles = children[0].styles
27+
y = first_child_styles.margin.top
28+
previous_margin = 0
29+
null_offset = NULL_OFFSET
30+
31+
for widget in children:
32+
styles = widget.styles
33+
overlay = styles.overlay == "screen"
34+
absolute = styles.has_rule("position") and styles.position == "absolute"
35+
margin = styles.margin
36+
top, right, bottom, left = margin
37+
margin_width = left + right
38+
y += max(top, previous_margin)
39+
previous_margin = bottom
40+
height = widget.get_content_height(size, viewport, width - margin_width)
41+
height += styles.gutter.height
42+
if (max_height := styles.max_height) is not None and max_height.is_cells:
43+
height = min(height, int(max_height.value))
44+
placements.append(
45+
WidgetPlacement(
46+
Region(left, y, width - margin_width, height),
47+
null_offset,
48+
margin,
49+
widget,
50+
0,
51+
False,
52+
overlay,
53+
absolute,
54+
)
55+
)
56+
y += height
57+
58+
return placements

0 commit comments

Comments
 (0)