mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Text justify initial work, help text
This commit is contained in:
43
sandbox/darren/text_justify.py
Normal file
43
sandbox/darren/text_justify.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from rich.text import Text
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Static
|
||||
|
||||
TEXT = """I must not fear.
|
||||
Fear is the mind-killer.
|
||||
Fear is the little-death that brings total obliteration.
|
||||
I will face my fear.
|
||||
I will permit it to pass over me and through me.
|
||||
And when it has gone past, I will turn the inner eye to see its path.
|
||||
Where the fear has gone there will be nothing. Only I will remain."""
|
||||
|
||||
|
||||
class TextJustify(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
left = Static(Text(TEXT))
|
||||
left.styles.text_justify = "left"
|
||||
yield left
|
||||
|
||||
right = Static(TEXT)
|
||||
right.styles.text_justify = "right"
|
||||
yield right
|
||||
|
||||
center = Static(TEXT)
|
||||
center.styles.text_justify = "center"
|
||||
yield center
|
||||
|
||||
full = Static(TEXT)
|
||||
full.styles.text_justify = "full"
|
||||
yield full
|
||||
|
||||
|
||||
app = TextJustify(css_path="text_justify.scss", watch_css=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
from rich.console import Console
|
||||
|
||||
console = Console()
|
||||
text = Text(TEXT)
|
||||
console.print(TEXT, justify="full")
|
||||
0
sandbox/darren/text_justify.scss
Normal file
0
sandbox/darren/text_justify.scss
Normal file
@@ -13,6 +13,7 @@ from textual.css.constants import (
|
||||
VALID_ALIGN_HORIZONTAL,
|
||||
VALID_ALIGN_VERTICAL,
|
||||
VALID_STYLE_FLAGS,
|
||||
VALID_JUSTIFY,
|
||||
)
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
@@ -648,6 +649,39 @@ def align_help_text() -> HelpText:
|
||||
)
|
||||
|
||||
|
||||
def text_justify_help_text(context: str) -> HelpText:
|
||||
"""Help text to show when the user supplies an invalid value for the text-justify property
|
||||
|
||||
Returns:
|
||||
HelpText: Renderable for displaying the help text for this property.
|
||||
"""
|
||||
return HelpText(
|
||||
summary="Invalid value for the [i]text-justify[/] property.",
|
||||
bullets=[
|
||||
*ContextSpecificBullets(
|
||||
css=[
|
||||
Bullet(
|
||||
f"The [i]text-justify[/] property must be one of {friendly_list(VALID_JUSTIFY)}",
|
||||
examples=[
|
||||
Example("text-justify: center;"),
|
||||
Example("text-justify: right;"),
|
||||
],
|
||||
)
|
||||
],
|
||||
inline=[
|
||||
Bullet(
|
||||
f"The [i]text_justify[/] property must be one of {friendly_list(VALID_JUSTIFY)}",
|
||||
examples=[
|
||||
Example("widget.styles.text_justify = 'center'"),
|
||||
Example("widget.styles.text_justify = 'right'"),
|
||||
],
|
||||
)
|
||||
],
|
||||
).get_by_context(context)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def offset_single_axis_help_text(property_name: str) -> HelpText:
|
||||
"""Help text to show when the user supplies an invalid value for an offset-* property.
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ from ._help_text import (
|
||||
property_invalid_value_help_text,
|
||||
scrollbar_size_property_help_text,
|
||||
scrollbar_size_single_axis_help_text,
|
||||
text_justify_help_text,
|
||||
)
|
||||
from .constants import (
|
||||
VALID_ALIGN_HORIZONTAL,
|
||||
@@ -36,6 +37,7 @@ from .constants import (
|
||||
VALID_VISIBILITY,
|
||||
VALID_STYLE_FLAGS,
|
||||
VALID_SCROLLBAR_GUTTER,
|
||||
VALID_JUSTIFY,
|
||||
)
|
||||
from .errors import DeclarationError, StyleValueError
|
||||
from .model import Declaration
|
||||
@@ -618,6 +620,19 @@ class StylesBuilder:
|
||||
style_definition = " ".join(token.value for token in tokens)
|
||||
self.styles.text_style = style_definition
|
||||
|
||||
def process_text_justify(self, name: str, tokens: list[Token]) -> None:
|
||||
if not tokens:
|
||||
return
|
||||
|
||||
if len(tokens) > 1 or tokens[0].value not in VALID_JUSTIFY:
|
||||
self.error(
|
||||
name,
|
||||
tokens[0],
|
||||
text_justify_help_text("css"),
|
||||
)
|
||||
|
||||
self.styles._rules["text_justify"] = tokens[0].value
|
||||
|
||||
def process_dock(self, name: str, tokens: list[Token]) -> None:
|
||||
if not tokens:
|
||||
return
|
||||
|
||||
@@ -38,6 +38,7 @@ VALID_BOX_SIZING: Final = {"border-box", "content-box"}
|
||||
VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"}
|
||||
VALID_ALIGN_HORIZONTAL: Final = {"left", "center", "right"}
|
||||
VALID_ALIGN_VERTICAL: Final = {"top", "middle", "bottom"}
|
||||
VALID_JUSTIFY: Final = {"left", "center", "right", "full"}
|
||||
VALID_SCROLLBAR_GUTTER: Final = {"auto", "stable"}
|
||||
VALID_STYLE_FLAGS: Final = {
|
||||
"none",
|
||||
|
||||
@@ -41,6 +41,7 @@ from .constants import (
|
||||
VALID_OVERFLOW,
|
||||
VALID_SCROLLBAR_GUTTER,
|
||||
VALID_VISIBILITY,
|
||||
VALID_JUSTIFY,
|
||||
)
|
||||
from .scalar import Scalar, ScalarOffset, Unit
|
||||
from .scalar_animation import ScalarAnimation
|
||||
@@ -56,6 +57,7 @@ from .types import (
|
||||
Specificity3,
|
||||
Specificity6,
|
||||
Visibility,
|
||||
TextJustify,
|
||||
)
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
@@ -142,6 +144,8 @@ class RulesMap(TypedDict, total=False):
|
||||
content_align_horizontal: AlignHorizontal
|
||||
content_align_vertical: AlignVertical
|
||||
|
||||
text_justify: TextJustify
|
||||
|
||||
|
||||
RULE_NAMES = list(RulesMap.__annotations__.keys())
|
||||
RULE_NAMES_SET = frozenset(RULE_NAMES)
|
||||
@@ -249,6 +253,8 @@ class StylesBase(ABC):
|
||||
content_align_vertical = StringEnumProperty(VALID_ALIGN_VERTICAL, "top")
|
||||
content_align = AlignProperty()
|
||||
|
||||
text_justify = StringEnumProperty(VALID_JUSTIFY, "left")
|
||||
|
||||
def __eq__(self, styles: object) -> bool:
|
||||
"""Check that Styles contains the same rules."""
|
||||
if not isinstance(styles, StylesBase):
|
||||
@@ -458,7 +464,6 @@ class StylesBase(ABC):
|
||||
@rich.repr.auto
|
||||
@dataclass
|
||||
class Styles(StylesBase):
|
||||
|
||||
node: DOMNode | None = None
|
||||
_rules: RulesMap = field(default_factory=dict)
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ ScrollbarGutter = Literal["auto", "stable"]
|
||||
BoxSizing = Literal["border-box", "content-box"]
|
||||
Overflow = Literal["scroll", "hidden", "auto"]
|
||||
EdgeStyle = Tuple[EdgeType, Color]
|
||||
TextJustify = Literal["left", "center", "right", "full"]
|
||||
|
||||
Specificity3 = Tuple[int, int, int]
|
||||
Specificity4 = Tuple[int, int, int, int]
|
||||
|
||||
@@ -982,11 +982,12 @@ class Widget(DOMNode):
|
||||
"""
|
||||
|
||||
if isinstance(renderable, str):
|
||||
renderable = Text.from_markup(renderable)
|
||||
renderable = Text.from_markup(renderable, justify=self.styles.text_justify)
|
||||
|
||||
rich_style = self.rich_style
|
||||
if isinstance(renderable, Text):
|
||||
renderable.stylize(rich_style)
|
||||
renderable.justify = self.styles.text_justify
|
||||
else:
|
||||
renderable = Styled(renderable, rich_style)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user