This commit is contained in:
Will McGugan
2022-04-14 16:55:58 +01:00
parent 8e76e524a8
commit cecbf655ab
11 changed files with 84 additions and 33 deletions

View File

@@ -1,19 +1,39 @@
Screen { Screen {
layout: horizontal; layout: horizontal;
} }
Widget#thing { Widget {
margin:1;
}
#thing {
width: 20; width: 20;
height: 10; height: 10;
align: center middle;
background:magenta;
margin: 1;
padding: 1;
/* border: solid white; */
align-vertical: middle;
} }
Widget#thing2 { #thing2 {
width: 30; width: 20;
height: 8; height: 10;
align: center middle;
background: green; background:green;
} align-vertical: middle;
}
#thing3 {
width: 20;
height: 10;
background:blue;
align-vertical: bottom;
}

View File

@@ -1,14 +1,21 @@
from rich.text import Text
from textual.app import App from textual.app import App
from textual.widget import Widget from textual.widget import Widget
class Thing(Widget):
def render(self):
return Text.from_markup("Hello, World. [b magenta]Lorem impsum.")
class AlignApp(App): class AlignApp(App):
def on_load(self): def on_load(self):
self.bind("t", "log_tree") self.bind("t", "log_tree")
def on_mount(self) -> None: def on_mount(self) -> None:
self.log("MOUNTED") self.log("MOUNTED")
self.mount(thing=Widget(), thing2=Widget()) self.mount(thing=Thing(), thing2=Widget(), thing3=Widget())
def action_log_tree(self): def action_log_tree(self):
self.log(self.screen.tree) self.log(self.screen.tree)

View File

@@ -21,6 +21,7 @@ App > Screen {
color: $text-background; color: $text-background;
} }
#sidebar { #sidebar {
color: $text-primary; color: $text-primary;
background: $primary; background: $primary;
@@ -81,7 +82,8 @@ Tweet {
/* border: outer $primary; */ /* border: outer $primary; */
padding: 1; padding: 1;
border: wide $panel-darken-2; border: wide $panel-darken-2;
overflow-y: scroll overflow-y: scroll;
align-horizontal: center;
} }
@@ -168,6 +170,7 @@ Error {
margin: 1 3; margin: 1 3;
text-style: bold; text-style: bold;
align-horizontal: center;
} }
Warning { Warning {
@@ -179,6 +182,7 @@ Warning {
border-bottom: hkey $warning-darken-2; border-bottom: hkey $warning-darken-2;
margin: 1 2; margin: 1 2;
text-style: bold; text-style: bold;
align-horizontal: center;
} }
Success { Success {
@@ -190,4 +194,5 @@ Success {
border-bottom: hkey $success; border-bottom: hkey $success;
margin: 1 2; margin: 1 2;
text-style: bold; text-style: bold;
align-horizontal: center;
} }

View File

@@ -8,6 +8,7 @@ when setting and getting.
""" """
from __future__ import annotations from __future__ import annotations
from tkinter.tix import AUTO
from typing import Iterable, NamedTuple, TYPE_CHECKING, cast 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".""" """Descriptor for getting and setting scalar properties. Scalars are numeric values with a unit, e.g. "50vh"."""
def __init__( 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: ) -> None:
self.units: set[Unit] = units or {*UNIT_SYMBOL} self.units: set[Unit] = units or {*UNIT_SYMBOL}
self.percent_unit = percent_unit self.percent_unit = percent_unit
self.allow_auto = allow_auto
super().__init__() super().__init__()
def __set_name__(self, owner: Styles, name: str) -> None: def __set_name__(self, owner: Styles, name: str) -> None:
@@ -90,7 +95,7 @@ class ScalarProperty:
if value is None: if value is None:
obj.clear_rule(self.name) obj.clear_rule(self.name)
return return
if isinstance(value, float): if isinstance(value, (int, float)):
new_value = Scalar(float(value), Unit.CELLS, Unit.WIDTH) new_value = Scalar(float(value), Unit.CELLS, Unit.WIDTH)
elif isinstance(value, Scalar): elif isinstance(value, Scalar):
new_value = value new_value = value
@@ -101,12 +106,23 @@ class ScalarProperty:
raise StyleValueError("unable to parse scalar from {value!r}") raise StyleValueError("unable to parse scalar from {value!r}")
else: else:
raise StyleValueError("expected float, Scalar, or None") raise StyleValueError("expected float, Scalar, or None")
if new_value is not None and new_value.unit not in self.units:
raise StyleValueError( if (
f"{self.name} units must be one of {friendly_list(get_symbols(self.units))}" new_value is not None
) and new_value.unit == Unit.AUTO
if new_value is not None and new_value.is_percent: and not self.allow_auto
new_value = Scalar(float(new_value.value), self.percent_unit, Unit.WIDTH) ):
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): if obj.set_rule(self.name, new_value):
obj.refresh() obj.refresh()

View File

@@ -625,7 +625,9 @@ class StylesBuilder:
self.styles._rules["align_vertical"] = token_vertical.value self.styles._rules["align_vertical"] = token_vertical.value
def process_align_horizontal(self, name: str, tokens: list[Token]) -> None: 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: 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

View File

@@ -152,6 +152,7 @@ class Scalar(NamedTuple):
float: _description_ float: _description_
""" """
value, unit, percent_unit = self value, unit, percent_unit = self
if unit == Unit.PERCENT: if unit == Unit.PERCENT:
unit = percent_unit unit = percent_unit
try: try:

View File

@@ -418,8 +418,8 @@ class StylesBase(ABC):
margin = self.margin margin = self.margin
else: # border-box else: # border-box
if has_rule("padding"): # if has_rule("padding"):
size -= self.padding.totals # size -= self.padding.totals
if has_rule("border"): if has_rule("border"):
size -= self.border.spacing.totals size -= self.border.spacing.totals
if has_rule("margin"): if has_rule("margin"):
@@ -458,7 +458,7 @@ class StylesBase(ABC):
""" """
offset_y = 0 offset_y = 0
align_vertical = self.align_vertical align_vertical = self.align_vertical
if align_vertical != "left": if align_vertical != "top":
if align_vertical == "middle": if align_vertical == "middle":
offset_y = (parent_height - height) // 2 offset_y = (parent_height - height) // 2
else: else:

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
import sys import sys
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass from dataclasses import dataclass
from operator import attrgetter
from typing import Iterable, TYPE_CHECKING, NamedTuple, Sequence from typing import Iterable, TYPE_CHECKING, NamedTuple, Sequence
from .._layout_resolve import layout_resolve from .._layout_resolve import layout_resolve
@@ -91,7 +92,7 @@ class DockLayout(Layout):
add_placement = placements.append add_placement = placements.append
arranged_widgets: set[Widget] = set() 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) arranged_widgets.update(widgets)
dock_options = [make_dock_options(widget, edge) for widget in widgets] dock_options = [make_dock_options(widget, edge) for widget in widgets]

View File

@@ -29,7 +29,9 @@ class HorizontalLayout(Layout):
(content_width, content_height), margin = widget.styles.get_box_model( (content_width, content_height), margin = widget.styles.get_box_model(
size, parent_size 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( region = Region(
margin.left + x, margin.top + offset_y, content_width, content_height margin.left + x, margin.top + offset_y, content_width, content_height
) )

View File

@@ -31,7 +31,9 @@ class VerticalLayout(Layout):
(content_width, content_height), margin = styles.get_box_model( (content_width, content_height), margin = styles.get_box_model(
size, parent_size 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( region = Region(
margin.left + offset_x, y + margin.top, content_width, content_height margin.left + offset_x, y + margin.top, content_width, content_height

View File

@@ -6,7 +6,6 @@ from typing import (
Awaitable, Awaitable,
TYPE_CHECKING, TYPE_CHECKING,
Callable, Callable,
ClassVar,
Iterable, Iterable,
NamedTuple, NamedTuple,
cast, cast,
@@ -16,10 +15,9 @@ import rich.repr
from rich.align import Align from rich.align import Align
from rich.console import Console, RenderableType from rich.console import Console, RenderableType
from rich.padding import Padding from rich.padding import Padding
from rich.pretty import Pretty
from rich.style import Style from rich.style import Style
from rich.styled import Styled from rich.styled import Styled
from rich.text import Text
from . import errors, log from . import errors, log
from . import events from . import events
@@ -394,10 +392,7 @@ class Widget(DOMNode):
if renderable_text_style: if renderable_text_style:
renderable = Styled(renderable, 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: if styles.border:
renderable = Border( renderable = Border(