rename table to gird, diagrams for layout

This commit is contained in:
Will McGugan
2022-09-06 10:16:52 +01:00
parent 6d6e385313
commit e8a4f2e806
17 changed files with 138 additions and 86 deletions

View File

@@ -1,7 +1,7 @@
Screen {
layout: table;
table-size: 2;
table-gutter: 2;
layout: grid;
grid-size: 2;
grid-gutter: 2;
padding: 2;
}
#question {

View File

@@ -1,56 +1,76 @@
# Layout
TODO: Explanation of layout
In textual the *layout* defines how widgets will be arranged (or *layed out*) on the screen. Textual supports a number of layouts which can be set either via a widgets `styles` object or via CSS.
## Vertical layout
## Vertical
A vertical layout will place new widgets below previous widgets, starting from the top of the screen.
<div class="excalidraw">
--8<-- "docs/images/layout_vertical.excalidraw.svg"
--8<-- "docs/images/layout/vertical.excalidraw.svg"
</div>
TODO: Explanation of vertical layout
## Horizontal layout
## Horizontal
A horizontal layout will place the first widget at the top left of the screen, and new widgets will be place directly to the right of the previous widget.
<div class="excalidraw">
--8<-- "docs/images/layout_horizontal.excalidraw.svg"
--8<-- "docs/images/layout/horizontal.excalidraw.svg"
</div>
TODO: Explantion of horizontal layout
## Center layout
## Center
A center widget will place the widget directly in the center of the screen. New widgets will also be placed in the center of the screen, overlapping previous widgets.
There probably isn't a practical use for such overlapping widgets. In practice this layout is probably only useful where you have a single child widget.
<div class="excalidraw">
--8<-- "docs/images/layout_center.excalidraw.svg"
--8<-- "docs/images/layout/center.excalidraw.svg"
</div>
TODO: Explanation of center layout
## Table layout
## Grid
A grid layout arranges widgets within a grid composed of columns and rows. Widgets can span multiple rows or columns to create more complex layouts.
<div class="excalidraw">
--8<-- "docs/images/layout_table.excalidraw.svg"
--8<-- "docs/images/layout/grid.excalidraw.svg"
</div>
TODO: Explanation of table layout
TODO: Explanation of grid layout
## Dock
## Docking
Widgets may be *docked*. Docking a widget removes it from the layout and fixes it position, aligned to either the top, right, bottom, or left edges of the screen. Docked widgets will not scroll, making them ideal for fixed headers / footers / sidebars.
<div class="excalidraw">
--8<-- "docs/images/layout/dock.excalidraw.svg"
</div>
TODO: Diagram
TODO: Explanation of dock
## Offsets
Widgets have a relative offset which is added to the widget's location, after its location has been determined via its layout.
<div class="excalidraw">
--8<-- "docs/images/layout/offset.excalidraw.svg"
</div>
TODO: Diagram
TODO: Offsets
## Box Model
TBC

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -3,11 +3,11 @@ Screen {
}
#calculator {
layout: table;
table-size: 4;
table-gutter: 1 2;
table-columns: 1fr;
table-rows: 2fr 1fr 1fr 1fr 1fr 1fr;
layout: grid;
grid-size: 4;
grid-gutter: 1 2;
grid-columns: 1fr;
grid-rows: 2fr 1fr 1fr 1fr 1fr 1fr;
margin: 1 2;
min-height:25;
min-width: 26;

View File

@@ -3,11 +3,11 @@ Screen {
}
#calculator {
layout: table;
table-size: 4;
table-gutter: 1 2;
table-columns: 1fr;
table-rows: 2fr 1fr 1fr 1fr 1fr 1fr;
layout: grid;
grid-size: 4;
grid-gutter: 1 2;
grid-columns: 1fr;
grid-rows: 2fr 1fr 1fr 1fr 1fr 1fr;
margin: 1 2;
min-height:25;
min-width: 26;

View File

@@ -1,8 +1,8 @@
Screen {
layout: table;
table-columns: 2fr 1fr 1fr;
table-rows: 1fr 1fr;
table-gutter: 1 2;
layout: grid;
grid-columns: 2fr 1fr 1fr;
grid-rows: 1fr 1fr;
grid-gutter: 1 2;
}
Static {

View File

@@ -847,7 +847,7 @@ class StylesBuilder:
self.error(name, token, scrollbar_size_single_axis_help_text(name))
self.styles._rules["scrollbar_size_horizontal"] = value
def _process_table_rows_or_columns(self, name: str, tokens: list[Token]) -> None:
def _process_grid_rows_or_columns(self, name: str, tokens: list[Token]) -> None:
scalars: list[Scalar] = []
for token in tokens:
if token.name == "number":
@@ -867,8 +867,8 @@ class StylesBuilder:
)
self.styles._rules[name.replace("-", "_")] = scalars
process_table_rows = _process_table_rows_or_columns
process_table_columns = _process_table_rows_or_columns
process_grid_rows = _process_grid_rows_or_columns
process_grid_columns = _process_grid_rows_or_columns
def _process_integer(self, name: str, tokens: list[Token]) -> None:
if not tokens:
@@ -884,14 +884,14 @@ class StylesBuilder:
self.error(name, token, integer_help_text(name))
self.styles._rules[name.replace("-", "_")] = value
process_table_gutter_horizontal = _process_integer
process_table_gutter_vertical = _process_integer
process_grid_gutter_horizontal = _process_integer
process_grid_gutter_vertical = _process_integer
process_column_span = _process_integer
process_row_span = _process_integer
process_table_size_columns = _process_integer
process_table_size_rows = _process_integer
process_grid_size_columns = _process_integer
process_grid_size_rows = _process_integer
def process_table_gutter(self, name: str, tokens: list[Token]) -> None:
def process_grid_gutter(self, name: str, tokens: list[Token]) -> None:
if not tokens:
return
if len(tokens) == 1:
@@ -899,25 +899,25 @@ class StylesBuilder:
if token.name != "number":
self.error(name, token, integer_help_text(name))
value = max(0, int(token.value))
self.styles._rules["table_gutter_horizontal"] = value
self.styles._rules["table_gutter_vertical"] = value
self.styles._rules["grid_gutter_horizontal"] = value
self.styles._rules["grid_gutter_vertical"] = value
elif len(tokens) == 2:
token = tokens[0]
if token.name != "number":
self.error(name, token, integer_help_text(name))
value = max(0, int(token.value))
self.styles._rules["table_gutter_horizontal"] = value
self.styles._rules["grid_gutter_horizontal"] = value
token = tokens[1]
if token.name != "number":
self.error(name, token, integer_help_text(name))
value = max(0, int(token.value))
self.styles._rules["table_gutter_vertical"] = value
self.styles._rules["grid_gutter_vertical"] = value
else:
self.error(name, tokens[0], "expected two integers here")
def process_table_size(self, name: str, tokens: list[Token]) -> None:
def process_grid_size(self, name: str, tokens: list[Token]) -> None:
if not tokens:
return
if len(tokens) == 1:
@@ -925,20 +925,20 @@ class StylesBuilder:
if token.name != "number":
self.error(name, token, integer_help_text(name))
value = max(0, int(token.value))
self.styles._rules["table_size_columns"] = value
self.styles._rules["table_size_rows"] = 0
self.styles._rules["grid_size_columns"] = value
self.styles._rules["grid_size_rows"] = 0
elif len(tokens) == 2:
token = tokens[0]
if token.name != "number":
self.error(name, token, integer_help_text(name))
value = max(0, int(token.value))
self.styles._rules["table_size_columns"] = value
self.styles._rules["grid_size_columns"] = value
token = tokens[1]
if token.name != "number":
self.error(name, token, integer_help_text(name))
value = max(0, int(token.value))
self.styles._rules["table_size_rows"] = value
self.styles._rules["grid_size_rows"] = value
else:
self.error(name, tokens[0], "expected two integers here")

View File

@@ -32,7 +32,7 @@ VALID_BORDER: Final[set[EdgeType]] = {
"wide",
}
VALID_EDGE: Final = {"top", "right", "bottom", "left"}
VALID_LAYOUT: Final = {"vertical", "horizontal", "center", "table"}
VALID_LAYOUT: Final = {"vertical", "horizontal", "center", "grid"}
VALID_BOX_SIZING: Final = {"border-box", "content-box"}
VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"}

View File

@@ -146,12 +146,12 @@ class RulesMap(TypedDict, total=False):
content_align_horizontal: AlignHorizontal
content_align_vertical: AlignVertical
table_size_rows: int
table_size_columns: int
table_gutter_horizontal: int
table_gutter_vertical: int
table_rows: tuple[Scalar, ...]
table_columns: tuple[Scalar, ...]
grid_size_rows: int
grid_size_columns: int
grid_gutter_horizontal: int
grid_gutter_vertical: int
grid_rows: tuple[Scalar, ...]
grid_columns: tuple[Scalar, ...]
row_span: int
column_span: int
@@ -267,13 +267,13 @@ class StylesBase(ABC):
content_align_vertical = StringEnumProperty(VALID_ALIGN_VERTICAL, "top")
content_align = AlignProperty()
table_rows = ScalarListProperty()
table_columns = ScalarListProperty()
grid_rows = ScalarListProperty()
grid_columns = ScalarListProperty()
table_size_columns = IntegerProperty(default=1, layout=True)
table_size_rows = IntegerProperty(default=0, layout=True)
table_gutter_horizontal = IntegerProperty(default=0, layout=True)
table_gutter_vertical = IntegerProperty(default=0, layout=True)
grid_size_columns = IntegerProperty(default=1, layout=True)
grid_size_rows = IntegerProperty(default=0, layout=True)
grid_gutter_horizontal = IntegerProperty(default=0, layout=True)
grid_gutter_vertical = IntegerProperty(default=0, layout=True)
row_span = IntegerProperty(default=1, layout=True)
column_span = IntegerProperty(default=1, layout=True)
@@ -805,26 +805,26 @@ class Styles(StylesBase):
)
elif has_rule("content_align_vertical"):
append_declaration("content-align-vertical", self.content_align_vertical)
elif has_rule("table_columns"):
elif has_rule("grid_columns"):
append_declaration(
"table-columns",
" ".join(str(scalar) for scalar in self.table_columns or ()),
"grid-columns",
" ".join(str(scalar) for scalar in self.grid_columns or ()),
)
elif has_rule("table_rows"):
elif has_rule("grid_rows"):
append_declaration(
"table-rows",
" ".join(str(scalar) for scalar in self.table_rows or ()),
"grid-rows",
" ".join(str(scalar) for scalar in self.grid_rows or ()),
)
elif has_rule("table_size_columns"):
append_declaration("table-size-columns", str(self.table_size_columns))
elif has_rule("table_size_rows"):
append_declaration("table-size-rows", str(self.table_size_rows))
elif has_rule("table_gutter_horizontal"):
elif has_rule("grid_size_columns"):
append_declaration("grid-size-columns", str(self.grid_size_columns))
elif has_rule("grid_size_rows"):
append_declaration("grid-size-rows", str(self.grid_size_rows))
elif has_rule("grid_gutter_horizontal"):
append_declaration(
"table-gutter-horizontal", str(self.table_gutter_horizontal)
"grid-gutter-horizontal", str(self.grid_gutter_horizontal)
)
elif has_rule("table_gutter_vertical"):
append_declaration("table-gutter-vertical", str(self.table_gutter_vertical))
elif has_rule("grid_gutter_vertical"):
append_declaration("grid-gutter-vertical", str(self.grid_gutter_vertical))
elif has_rule("row_span"):
append_declaration("row-span", str(self.row_span))
elif has_rule("column_span"):

View File

@@ -3,13 +3,13 @@ from __future__ import annotations
from .._layout import Layout
from .center import CenterLayout
from .horizontal import HorizontalLayout
from .table import TableLayout
from .grid import GridLayout
from .vertical import VerticalLayout
LAYOUT_MAP: dict[str, type[Layout]] = {
"center": CenterLayout,
"horizontal": HorizontalLayout,
"table": TableLayout,
"grid": GridLayout,
"vertical": VerticalLayout,
}

View File

@@ -12,21 +12,21 @@ if TYPE_CHECKING:
from ..widget import Widget
class TableLayout(Layout):
"""Used to layout Widgets in to a table."""
class GridLayout(Layout):
"""Used to layout Widgets in to a grid."""
name = "table"
name = "grid"
def arrange(
self, parent: Widget, children: list[Widget], size: Size
) -> ArrangeResult:
styles = parent.styles
row_scalars = styles.table_rows or [Scalar.parse("1fr")]
column_scalars = styles.table_columns or [Scalar.parse("1fr")]
gutter_horizontal = styles.table_gutter_horizontal
gutter_vertical = styles.table_gutter_vertical
table_size_columns = max(1, styles.table_size_columns)
table_size_rows = styles.table_size_rows
row_scalars = styles.grid_rows or [Scalar.parse("1fr")]
column_scalars = styles.grid_columns or [Scalar.parse("1fr")]
gutter_horizontal = styles.grid_gutter_horizontal
gutter_vertical = styles.grid_gutter_vertical
table_size_columns = max(1, styles.grid_size_columns)
table_size_rows = styles.grid_size_rows
viewport = parent.screen.size
def cell_coords(column_count: int) -> Iterable[tuple[int, int]]: