mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
auto grid docs and test
This commit is contained in:
11
docs/examples/guide/layout/grid_layout_auto.css
Normal file
11
docs/examples/guide/layout/grid_layout_auto.css
Normal file
@@ -0,0 +1,11 @@
|
||||
Screen {
|
||||
layout: grid;
|
||||
grid-size: 3;
|
||||
grid-columns: auto 1fr 1fr;
|
||||
grid-rows: 25% 75%;
|
||||
}
|
||||
|
||||
.box {
|
||||
height: 100%;
|
||||
border: solid green;
|
||||
}
|
||||
19
docs/examples/guide/layout/grid_layout_auto.py
Normal file
19
docs/examples/guide/layout/grid_layout_auto.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Static
|
||||
|
||||
|
||||
class GridLayoutExample(App):
|
||||
CSS_PATH = "grid_layout_auto.css"
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Static("First column", classes="box")
|
||||
yield Static("Two", classes="box")
|
||||
yield Static("Three", classes="box")
|
||||
yield Static("Four", classes="box")
|
||||
yield Static("Five", classes="box")
|
||||
yield Static("Six", classes="box")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = GridLayoutExample()
|
||||
app.run()
|
||||
@@ -326,6 +326,33 @@ If you don't specify enough values in a `grid-columns` or `grid-rows` declaratio
|
||||
For example, if your grid has four columns (i.e. `grid-size: 4;`), then `grid-columns: 2 4;` is equivalent to `grid-columns: 2 4 2 4;`.
|
||||
If it instead had three columns, then `grid-columns: 2 4;` would be equivalent to `grid-columns: 2 4 2;`.
|
||||
|
||||
#### Auto rows / columns
|
||||
|
||||
The `grid-columns` and `grid-rows` rules can both accept a value of "auto" in place of any of the dimensions, which tells Textual to calculate an optimal size based on the content.
|
||||
|
||||
Let's modify the previous example to make the first column an `auto` column.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/guide/layout/grid_layout_auto.py"}
|
||||
```
|
||||
|
||||
=== "grid_layout_auto.py"
|
||||
|
||||
```python hl_lines="6 9"
|
||||
--8<-- "docs/examples/guide/layout/grid_layout_auto.py"
|
||||
```
|
||||
|
||||
=== "grid_layout_auto.css"
|
||||
|
||||
```sass hl_lines="4"
|
||||
--8<-- "docs/examples/guide/layout/grid_layout_auto.css"
|
||||
```
|
||||
|
||||
Notice how the first column is just wide enough to fit the content of each cell.
|
||||
The layout will adjust accordingly if you update the content for any widget in that column.
|
||||
|
||||
|
||||
### Cell spans
|
||||
|
||||
Cells may _span_ multiple rows or columns, to create more interesting grid arrangements.
|
||||
|
||||
@@ -114,6 +114,52 @@ class GridLayout(Layout):
|
||||
row_scalars, table_size_rows if table_size_rows else row + 1
|
||||
)
|
||||
|
||||
def apply_width_limits(widget: Widget, width: int) -> int:
|
||||
"""Apply min and max widths to dimension.
|
||||
|
||||
Args:
|
||||
widget: A Widget.
|
||||
width: A width.
|
||||
|
||||
Returns:
|
||||
New width.
|
||||
"""
|
||||
styles = widget.styles
|
||||
if styles.min_width is not None:
|
||||
width = max(
|
||||
width,
|
||||
int(styles.min_width.resolve(size, viewport, Fraction(width))),
|
||||
)
|
||||
if styles.max_width is not None:
|
||||
width = min(
|
||||
width,
|
||||
int(styles.max_width.resolve(size, viewport, Fraction(width))),
|
||||
)
|
||||
return width
|
||||
|
||||
def apply_height_limits(widget: Widget, height: int) -> int:
|
||||
"""Apply min and max height to a dimension.
|
||||
|
||||
Args:
|
||||
widget: A widget.
|
||||
height: A height.
|
||||
|
||||
Returns:
|
||||
New height
|
||||
"""
|
||||
styles = widget.styles
|
||||
if styles.min_height is not None:
|
||||
height = max(
|
||||
height,
|
||||
int(styles.min_height.resolve(size, viewport, Fraction(height))),
|
||||
)
|
||||
if styles.max_height is not None:
|
||||
height = min(
|
||||
height,
|
||||
int(styles.max_height.resolve(size, viewport, Fraction(height))),
|
||||
)
|
||||
return height
|
||||
|
||||
# Handle any auto columns
|
||||
for column, scalar in enumerate(column_scalars):
|
||||
if scalar.is_auto:
|
||||
@@ -129,8 +175,11 @@ class GridLayout(Layout):
|
||||
continue
|
||||
width = max(
|
||||
width,
|
||||
widget.get_content_width(size, viewport)
|
||||
+ widget.styles.gutter.width,
|
||||
apply_width_limits(
|
||||
widget,
|
||||
widget.get_content_width(size, viewport)
|
||||
+ widget.styles.gutter.width,
|
||||
),
|
||||
)
|
||||
column_scalars[column] = Scalar.from_number(width)
|
||||
|
||||
@@ -150,13 +199,14 @@ class GridLayout(Layout):
|
||||
if widget.styles.row_span != 1:
|
||||
continue
|
||||
column_width = columns[column][1]
|
||||
widget_height = (
|
||||
widget_height = apply_height_limits(
|
||||
widget,
|
||||
widget.get_content_height(
|
||||
size,
|
||||
viewport,
|
||||
column_width - parent.styles.grid_gutter_vertical,
|
||||
)
|
||||
+ widget.styles.gutter.height
|
||||
+ widget.styles.gutter.height,
|
||||
)
|
||||
height = max(height, widget_height)
|
||||
row_scalars[row] = Scalar.from_number(height)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -16,15 +16,33 @@ class GridApp(App):
|
||||
height:auto;
|
||||
border: solid green;
|
||||
}
|
||||
|
||||
#c2 Label {
|
||||
min-width: 20;
|
||||
}
|
||||
|
||||
#c3 Label {
|
||||
max-width: 30;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Container():
|
||||
with Container(id="c1"):
|
||||
yield Label("foo")
|
||||
yield Input()
|
||||
yield Label("Longer label")
|
||||
yield Input()
|
||||
with Container(id="c2"):
|
||||
yield Label("foo")
|
||||
yield Input()
|
||||
yield Label("Longer label")
|
||||
yield Input()
|
||||
with Container(id="c3"):
|
||||
yield Label("foo bar " * 10)
|
||||
yield Input()
|
||||
yield Label("Longer label")
|
||||
yield Input()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user