From c669ab85d44b3e4f3a5825fafa4619547bf7000e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 11 Nov 2021 15:14:44 +0000 Subject: [PATCH] text style properties --- src/textual/css/_style_properties.py | 34 +++++++++++++++++++--------- src/textual/css/_styles_builder.py | 4 ++++ src/textual/css/styles.py | 7 ++++-- src/textual/css/stylesheet.py | 13 +++++++---- src/textual/css/tokenizer.py | 3 +++ src/textual/view.py | 4 +++- 6 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/textual/css/_style_properties.py b/src/textual/css/_style_properties.py index 4906318c0..bd9170857 100644 --- a/src/textual/css/_style_properties.py +++ b/src/textual/css/_style_properties.py @@ -143,11 +143,10 @@ class StyleProperty: color = getattr(obj, self._color_name) or Color.default() bgcolor = getattr(obj, self._bgcolor_name) or Color.default() - style = Style(color=color, bgcolor=bgcolor) + style = Style.from_color(color, bgcolor) style_flags = getattr(obj, self._style_name) if style_flags is not None: - flags = Style.parse(style_flags) - style += flags + style += style_flags return style def __set__(self, obj: Styles, style: Style | str | None) -> Style | str | None: @@ -327,22 +326,35 @@ class ColorProperty: class StyleFlagsProperty: - _VALID_PROPERTIES = {"not", "bold", "italic", "underline", "overline", "strike"} + _VALID_PROPERTIES = { + "not", + "bold", + "italic", + "underline", + "overline", + "strike", + "b", + "i", + "u", + "o", + } def __set_name__(self, owner: Styles, name: str) -> None: self._name = name self._internal_name = f"_rule_{name}" - def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> str: - return getattr(obj, self._internal_name, None) or "" + def __get__(self, obj: Styles, objtype: type[Styles] | None = None) -> Style: + return getattr(obj, self._internal_name, None) or Style.null() def __set__(self, obj: Styles, style_flags: str | None) -> str | None: if style_flags is None: setattr(self, self._internal_name, None) else: - # TODO: more specific error - words = {word.strip() for word in style_flags.split(" ")} - if words not in self._VALID_PROPERTIES: - raise StyleValueError(f"unknown style attribute(s) in {style_flags!r}") - setattr(self, self._internal_name, " ".join(words)) + words = [word.strip() for word in style_flags.split(" ")] + valid_word = self._VALID_PROPERTIES.__contains__ + for word in words: + if not valid_word(word): + raise StyleValueError(f"unknown word {word!r} in style flags") + style = Style.parse(" ".join(words)) + setattr(obj, self._internal_name, style) return style_flags diff --git a/src/textual/css/_styles_builder.py b/src/textual/css/_styles_builder.py index 0b92aae3c..6546265ad 100644 --- a/src/textual/css/_styles_builder.py +++ b/src/textual/css/_styles_builder.py @@ -239,6 +239,10 @@ class StylesBuilder: name, token, f"unexpected token {token.value!r} in declaration" ) + def process_text_style(self, name: str, tokens: list[Token]) -> None: + style_definition = " ".join(token.value for token in tokens) + self.styles.text_style = style_definition + def process_dock_group(self, name: str, tokens: list[Token]) -> None: if len(tokens) > 1: diff --git a/src/textual/css/styles.py b/src/textual/css/styles.py index a0285923f..5d8cf7b18 100644 --- a/src/textual/css/styles.py +++ b/src/textual/css/styles.py @@ -45,7 +45,7 @@ class Styles: _rule_text_color: Color | None = None _rule_text_bgcolor: Color | None = None - _rule_text_style: str | None = None + _rule_text_style: Style | None = None _rule_padding: Spacing | None = None _rule_margin: Spacing | None = None @@ -274,12 +274,15 @@ if __name__ == "__main__": styles.border = ("solid", "rgb(10,20,30)") styles.outline_right = ("solid", "red") styles.docks = "foo bar" - styles.text = "italic blue" + styles.text_style = "italic" styles.dock_group = "bar" styles.layers = "foo bar" from rich import inspect, print + print(styles.text_style) + print(styles.text) + print(styles) print(styles.css) diff --git a/src/textual/css/stylesheet.py b/src/textual/css/stylesheet.py index 5cb81a44d..dfc1ab331 100644 --- a/src/textual/css/stylesheet.py +++ b/src/textual/css/stylesheet.py @@ -9,9 +9,8 @@ import rich.repr from .errors import StylesheetError from .match import _check_selectors -from .model import CombinatorType, RuleSet, Selector +from .model import RuleSet from .parse import parse -from .styles import Styles from .types import Specificity3, Specificity4 from ..dom import DOMNode @@ -133,13 +132,15 @@ if __name__ == "__main__": } Widget{ - text: purple; - + text: red; + text-style: bold } + /* View #widget1 { text: green !important; } + */ App > View.-subview { @@ -152,8 +153,12 @@ if __name__ == "__main__": stylesheet = Stylesheet() stylesheet.parse(CSS) + print(widget1.styles) + stylesheet.apply(widget1) + print(widget1.styles) + # from .query import DOMQuery # tests = ["View", "App > View", "Widget.float", ".float.transient", "*"] diff --git a/src/textual/css/tokenizer.py b/src/textual/css/tokenizer.py index 83caf480c..9a48c6573 100644 --- a/src/textual/css/tokenizer.py +++ b/src/textual/css/tokenizer.py @@ -44,6 +44,9 @@ class Token(NamedTuple): name: str value: str + def __str__(self) -> str: + return self.value + class Tokenizer: def __init__(self, text: str) -> None: diff --git a/src/textual/view.py b/src/textual/view.py index 80a5532c5..ad2ac2257 100644 --- a/src/textual/view.py +++ b/src/textual/view.py @@ -3,7 +3,7 @@ from __future__ import annotations from itertools import chain from typing import Callable, Iterable, ClassVar, TYPE_CHECKING -from rich.console import Console, ConsoleOptions, RenderResult, RenderableType +from rich.console import RenderableType import rich.repr from rich.style import Style @@ -143,9 +143,11 @@ class View(Widget): name_widgets = chain( ((None, widget) for widget in anon_widgets), widgets.items() ) + stylesheet = self.app.stylesheet for name, widget in name_widgets: if name is not None: widget.name = name + stylesheet.apply(widget) self._add_child(widget) self.refresh()