diff --git a/sandbox/align.css b/sandbox/align.css index 28497b73b..37cdea344 100644 --- a/sandbox/align.css +++ b/sandbox/align.css @@ -1,19 +1,39 @@ + Screen { layout: horizontal; } -Widget#thing { +Widget { + margin:1; +} + +#thing { width: 20; height: 10; - align: center middle; + + background:magenta; + margin: 1; + padding: 1; + /* border: solid white; */ + align-vertical: middle; } -Widget#thing2 { - width: 30; - height: 8; - align: center middle; - background: green; -} \ No newline at end of file +#thing2 { + width: 20; + height: 10; + + background:green; + align-vertical: middle; +} + + +#thing3 { + width: 20; + height: 10; + + background:blue; + align-vertical: bottom; +} diff --git a/sandbox/align.py b/sandbox/align.py index 851dcbfae..06d0b366f 100644 --- a/sandbox/align.py +++ b/sandbox/align.py @@ -1,14 +1,21 @@ +from rich.text import Text + from textual.app import App from textual.widget import Widget +class Thing(Widget): + def render(self): + return Text.from_markup("Hello, World. [b magenta]Lorem impsum.") + + class AlignApp(App): def on_load(self): self.bind("t", "log_tree") def on_mount(self) -> None: self.log("MOUNTED") - self.mount(thing=Widget(), thing2=Widget()) + self.mount(thing=Thing(), thing2=Widget(), thing3=Widget()) def action_log_tree(self): self.log(self.screen.tree) diff --git a/sandbox/basic.css b/sandbox/basic.css index 4d3e64d65..7ab6d8530 100644 --- a/sandbox/basic.css +++ b/sandbox/basic.css @@ -21,6 +21,7 @@ App > Screen { color: $text-background; } + #sidebar { color: $text-primary; background: $primary; @@ -81,7 +82,8 @@ Tweet { /* border: outer $primary; */ padding: 1; border: wide $panel-darken-2; - overflow-y: scroll + overflow-y: scroll; + align-horizontal: center; } @@ -168,6 +170,7 @@ Error { margin: 1 3; text-style: bold; + align-horizontal: center; } Warning { @@ -179,6 +182,7 @@ Warning { border-bottom: hkey $warning-darken-2; margin: 1 2; text-style: bold; + align-horizontal: center; } Success { @@ -190,4 +194,5 @@ Success { border-bottom: hkey $success; margin: 1 2; text-style: bold; + align-horizontal: center; } diff --git a/src/textual/css/_style_properties.py b/src/textual/css/_style_properties.py index af4a9cdd7..9f650be06 100644 --- a/src/textual/css/_style_properties.py +++ b/src/textual/css/_style_properties.py @@ -8,6 +8,7 @@ when setting and getting. """ from __future__ import annotations +from tkinter.tix import AUTO from typing import Iterable, NamedTuple, TYPE_CHECKING, cast @@ -47,10 +48,14 @@ class ScalarProperty: """Descriptor for getting and setting scalar properties. Scalars are numeric values with a unit, e.g. "50vh".""" def __init__( - self, units: set[Unit] | None = None, percent_unit: Unit = Unit.WIDTH + self, + units: set[Unit] | None = None, + percent_unit: Unit = Unit.WIDTH, + allow_auto: bool = True, ) -> None: self.units: set[Unit] = units or {*UNIT_SYMBOL} self.percent_unit = percent_unit + self.allow_auto = allow_auto super().__init__() def __set_name__(self, owner: Styles, name: str) -> None: @@ -90,7 +95,7 @@ class ScalarProperty: if value is None: obj.clear_rule(self.name) return - if isinstance(value, float): + if isinstance(value, (int, float)): new_value = Scalar(float(value), Unit.CELLS, Unit.WIDTH) elif isinstance(value, Scalar): new_value = value @@ -101,12 +106,23 @@ class ScalarProperty: raise StyleValueError("unable to parse scalar from {value!r}") else: raise StyleValueError("expected float, Scalar, or None") - if new_value is not None and new_value.unit not in self.units: - raise StyleValueError( - f"{self.name} units must be one of {friendly_list(get_symbols(self.units))}" - ) - if new_value is not None and new_value.is_percent: - new_value = Scalar(float(new_value.value), self.percent_unit, Unit.WIDTH) + + if ( + new_value is not None + and new_value.unit == Unit.AUTO + and not self.allow_auto + ): + raise StyleValueError("'auto' not allowed here") + + if new_value.unit != Unit.AUTO: + if new_value is not None and new_value.unit not in self.units: + raise StyleValueError( + f"{self.name} units must be one of {friendly_list(get_symbols(self.units))}" + ) + if new_value is not None and new_value.is_percent: + new_value = Scalar( + float(new_value.value), self.percent_unit, Unit.WIDTH + ) if obj.set_rule(self.name, new_value): obj.refresh() diff --git a/src/textual/css/_styles_builder.py b/src/textual/css/_styles_builder.py index e49d3f38c..1e3c07b46 100644 --- a/src/textual/css/_styles_builder.py +++ b/src/textual/css/_styles_builder.py @@ -625,7 +625,9 @@ class StylesBuilder: self.styles._rules["align_vertical"] = token_vertical.value def process_align_horizontal(self, name: str, tokens: list[Token]) -> None: - self._process_enum(name, tokens, VALID_ALIGN_HORIZONTAL) + value = self._process_enum(name, tokens, VALID_ALIGN_HORIZONTAL) + self.styles._rules["align_horizontal"] = value def process_align_vertical(self, name: str, tokens: list[Token]) -> None: - self._process_enum(name, tokens, VALID_ALIGN_VERTICAL) + value = self._process_enum(name, tokens, VALID_ALIGN_VERTICAL) + self.styles._rules["align_vertical"] = value diff --git a/src/textual/css/scalar.py b/src/textual/css/scalar.py index 25bcca554..33703ac81 100644 --- a/src/textual/css/scalar.py +++ b/src/textual/css/scalar.py @@ -152,6 +152,7 @@ class Scalar(NamedTuple): float: _description_ """ value, unit, percent_unit = self + if unit == Unit.PERCENT: unit = percent_unit try: diff --git a/src/textual/css/styles.py b/src/textual/css/styles.py index 57fcf1013..eb9caa517 100644 --- a/src/textual/css/styles.py +++ b/src/textual/css/styles.py @@ -418,8 +418,8 @@ class StylesBase(ABC): margin = self.margin else: # border-box - if has_rule("padding"): - size -= self.padding.totals + # if has_rule("padding"): + # size -= self.padding.totals if has_rule("border"): size -= self.border.spacing.totals if has_rule("margin"): @@ -458,7 +458,7 @@ class StylesBase(ABC): """ offset_y = 0 align_vertical = self.align_vertical - if align_vertical != "left": + if align_vertical != "top": if align_vertical == "middle": offset_y = (parent_height - height) // 2 else: diff --git a/src/textual/layouts/dock.py b/src/textual/layouts/dock.py index e040a9642..b507bbc67 100644 --- a/src/textual/layouts/dock.py +++ b/src/textual/layouts/dock.py @@ -3,6 +3,7 @@ from __future__ import annotations import sys from collections import defaultdict from dataclasses import dataclass +from operator import attrgetter from typing import Iterable, TYPE_CHECKING, NamedTuple, Sequence from .._layout_resolve import layout_resolve @@ -91,7 +92,7 @@ class DockLayout(Layout): add_placement = placements.append arranged_widgets: set[Widget] = set() - for edge, widgets, z in docks: + for z, (edge, widgets, _z) in enumerate(sorted(docks, key=attrgetter("z"))): arranged_widgets.update(widgets) dock_options = [make_dock_options(widget, edge) for widget in widgets] diff --git a/src/textual/layouts/horizontal.py b/src/textual/layouts/horizontal.py index 3245c5362..9bf3485c6 100644 --- a/src/textual/layouts/horizontal.py +++ b/src/textual/layouts/horizontal.py @@ -29,7 +29,9 @@ class HorizontalLayout(Layout): (content_width, content_height), margin = widget.styles.get_box_model( size, parent_size ) - offset_y = styles.align_height(content_height, parent_size.height) + offset_y = styles.align_height( + content_height + margin.height, parent_size.height + ) region = Region( margin.left + x, margin.top + offset_y, content_width, content_height ) diff --git a/src/textual/layouts/vertical.py b/src/textual/layouts/vertical.py index f18a39477..9af7e76cb 100644 --- a/src/textual/layouts/vertical.py +++ b/src/textual/layouts/vertical.py @@ -31,7 +31,9 @@ class VerticalLayout(Layout): (content_width, content_height), margin = styles.get_box_model( size, parent_size ) - offset_x = styles.align_width(content_width, parent_size.width) + offset_x = styles.align_width( + content_width + margin.width, parent_size.width + ) region = Region( margin.left + offset_x, y + margin.top, content_width, content_height diff --git a/src/textual/widget.py b/src/textual/widget.py index 74dc4aabf..e987980c0 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -6,7 +6,6 @@ from typing import ( Awaitable, TYPE_CHECKING, Callable, - ClassVar, Iterable, NamedTuple, cast, @@ -16,10 +15,9 @@ import rich.repr from rich.align import Align from rich.console import Console, RenderableType from rich.padding import Padding -from rich.pretty import Pretty from rich.style import Style from rich.styled import Styled -from rich.text import Text + from . import errors, log from . import events @@ -394,10 +392,7 @@ class Widget(DOMNode): if renderable_text_style: renderable = Styled(renderable, renderable_text_style) - if styles.padding: - renderable = Padding( - renderable, styles.padding, style=renderable_text_style - ) + renderable = Padding(renderable, styles.padding, style=renderable_text_style) if styles.border: renderable = Border(