Text justify has become text align

This commit is contained in:
Darren Burns
2022-08-26 15:33:42 +01:00
parent 3b155216f0
commit ad803a7753
13 changed files with 134 additions and 118 deletions

View File

@@ -1,21 +1,21 @@
#one { #one {
text-justify: left; text-align: left;
background: lightblue; background: lightblue;
} }
#two { #two {
text-justify: center; text-align: center;
background: indianred; background: indianred;
} }
#three { #three {
text-justify: right; text-align: right;
background: palegreen; background: palegreen;
} }
#four { #four {
text-justify: full; text-align: justify;
background: palevioletred; background: palevioletred;
} }

View File

@@ -10,19 +10,19 @@ TEXT = (
) )
class TextJustify(App): class TextAlign(App):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
left = Static("[b]Left justified[/]\n" + TEXT, id="one") left = Static("[b]Left aligned[/]\n" + TEXT, id="one")
yield left yield left
right = Static("[b]Center justified[/]\n" + TEXT, id="two") right = Static("[b]Center aligned[/]\n" + TEXT, id="two")
yield right yield right
center = Static("[b]Right justified[/]\n" + TEXT, id="three") center = Static("[b]Right aligned[/]\n" + TEXT, id="three")
yield center yield center
full = Static("[b]Full justified[/]\n" + TEXT, id="four") full = Static("[b]Justified[/]\n" + TEXT, id="four")
yield full yield full
app = TextJustify(css_path="text_justify.css") app = TextAlign(css_path="text_align.css")

57
docs/styles/text_align.md Normal file
View File

@@ -0,0 +1,57 @@
# Text-align
The `text-align` rule aligns text within a widget.
## Syntax
```
text-align: [left|start|center|right|end|justify];
```
### Values
| Value | Description |
|-----------|----------------------------------|
| `left` | Left aligns text in the widget |
| `start` | Left aligns text in the widget |
| `center` | Center aligns text in the widget |
| `right` | Right aligns text in the widget |
| `end` | Right aligns text in the widget |
| `justify` | Justifies text in the widget |
## Example
This example shows, from top to bottom: `left`, `center`, `right`, and `justify` text alignments.
=== "text_align.py"
```python
--8<-- "docs/examples/styles/text_align.py"
```
=== "text_align.css"
```css
--8<-- "docs/examples/styles/text_align.css"
```
=== "Output"
```{.textual path="docs/examples/styles/text_align.py"}
```
## CSS
```sass
/* Set text in all Widgets to be right aligned */
Widget {
text-align: right;
}
```
## Python
```python
# Set text in the widget to be right aligned
widget.styles.text_align = "right"
```

View File

@@ -1,57 +0,0 @@
# Text-justify
The `text-justify` rule justifies text within a widget.
This property is not the same as the `text-justify` property in browser CSS.
## Syntax
```
text-justify: [left|center|right|full];
```
### Values
| Value | Description |
|----------|-------------------------------------|
| `left` | Left justifies text in the widget |
| `center` | Center justifies text in the widget |
| `right` | Right justifies text in the widget |
| `full` | Fully justifies text in the widget |
## Example
This example shows, from top to bottom: `left`, `center`, `right`, and `full` justified text.
=== "text_justify.py"
```python
--8<-- "docs/examples/styles/text_justify.py"
```
=== "text_justify.css"
```css
--8<-- "docs/examples/styles/text_justify.css"
```
=== "Output"
```{.textual path="docs/examples/styles/text_justify.py"}
```
## CSS
```sass
/* Set text in all Widgets to be right justified */
Widget {
text-justify: right;
}
```
## Python
```python
# Set text in the widget to be right justified
widget.styles.text_justify = "right"
```

View File

@@ -56,7 +56,7 @@ nav:
- "styles/scrollbar.md" - "styles/scrollbar.md"
- "styles/scrollbar_gutter.md" - "styles/scrollbar_gutter.md"
- "styles/scrollbar_size.md" - "styles/scrollbar_size.md"
- "styles/text_justify.md" - "styles/text_align.md"
- "styles/text_style.md" - "styles/text_style.md"
- "styles/tint.md" - "styles/tint.md"
- "styles/visibility.md" - "styles/visibility.md"

View File

@@ -12,22 +12,22 @@ TEXT = (
) )
class TextJustify(App): class TextAlign(App):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
left = Static("[b]Left justified[/]\n" + TEXT, id="one") left = Static("[b]Left aligned[/]\n" + TEXT, id="one")
yield left yield left
right = Static("[b]Center justified[/]\n" + TEXT, id="two") right = Static("[b]Center aligned[/]\n" + TEXT, id="two")
yield right yield right
center = Static("[b]Right justified[/]\n" + TEXT, id="three") center = Static("[b]Right aligned[/]\n" + TEXT, id="three")
yield center yield center
full = Static("[b]Full justified[/]\n" + TEXT, id="four") full = Static("[b]Fully justified[/]\n" + TEXT, id="four")
yield full yield full
app = TextJustify(css_path="text_justify.scss", watch_css=True) app = TextAlign(css_path="text_align.scss", watch_css=True)
if __name__ == "__main__": if __name__ == "__main__":
app.run() app.run()

View File

@@ -1,21 +1,21 @@
#one { #one {
text-justify: left; text-align: left;
background: lightblue; background: lightblue;
} }
#two { #two {
text-justify: center; text-align: center;
background: indianred; background: indianred;
} }
#three { #three {
text-justify: right; text-align: right;
background: palegreen; background: palegreen;
} }
#four { #four {
text-justify: full; text-align: justify;
background: palevioletred; background: palevioletred;
} }

View File

@@ -13,7 +13,7 @@ from textual.css.constants import (
VALID_ALIGN_HORIZONTAL, VALID_ALIGN_HORIZONTAL,
VALID_ALIGN_VERTICAL, VALID_ALIGN_VERTICAL,
VALID_STYLE_FLAGS, VALID_STYLE_FLAGS,
VALID_JUSTIFY, VALID_TEXT_ALIGN,
) )
if sys.version_info >= (3, 8): if sys.version_info >= (3, 8):
@@ -649,31 +649,31 @@ def align_help_text() -> HelpText:
) )
def text_justify_help_text(context: str) -> HelpText: def text_align_help_text(context: str) -> HelpText:
"""Help text to show when the user supplies an invalid value for the text-justify property """Help text to show when the user supplies an invalid value for the text-align property
Returns: Returns:
HelpText: Renderable for displaying the help text for this property. HelpText: Renderable for displaying the help text for this property.
""" """
return HelpText( return HelpText(
summary="Invalid value for the [i]text-justify[/] property.", summary="Invalid value for the [i]text-align[/] property.",
bullets=[ bullets=[
*ContextSpecificBullets( *ContextSpecificBullets(
css=[ css=[
Bullet( Bullet(
f"The [i]text-justify[/] property must be one of {friendly_list(VALID_JUSTIFY)}", f"The [i]text-align[/] property must be one of {friendly_list(VALID_TEXT_ALIGN)}",
examples=[ examples=[
Example("text-justify: center;"), Example("text-align: center;"),
Example("text-justify: right;"), Example("text-align: right;"),
], ],
) )
], ],
inline=[ inline=[
Bullet( Bullet(
f"The [i]text_justify[/] property must be one of {friendly_list(VALID_JUSTIFY)}", f"The [i]text_align[/] property must be one of {friendly_list(VALID_TEXT_ALIGN)}",
examples=[ examples=[
Example("widget.styles.text_justify = 'center'"), Example("widget.styles.text_align = 'center'"),
Example("widget.styles.text_justify = 'right'"), Example("widget.styles.text_align = 'right'"),
], ],
) )
], ],

View File

@@ -24,7 +24,7 @@ from ._help_text import (
property_invalid_value_help_text, property_invalid_value_help_text,
scrollbar_size_property_help_text, scrollbar_size_property_help_text,
scrollbar_size_single_axis_help_text, scrollbar_size_single_axis_help_text,
text_justify_help_text, text_align_help_text,
) )
from .constants import ( from .constants import (
VALID_ALIGN_HORIZONTAL, VALID_ALIGN_HORIZONTAL,
@@ -37,7 +37,7 @@ from .constants import (
VALID_VISIBILITY, VALID_VISIBILITY,
VALID_STYLE_FLAGS, VALID_STYLE_FLAGS,
VALID_SCROLLBAR_GUTTER, VALID_SCROLLBAR_GUTTER,
VALID_JUSTIFY, VALID_TEXT_ALIGN,
) )
from .errors import DeclarationError, StyleValueError from .errors import DeclarationError, StyleValueError
from .model import Declaration from .model import Declaration
@@ -620,19 +620,19 @@ class StylesBuilder:
style_definition = " ".join(token.value for token in tokens) style_definition = " ".join(token.value for token in tokens)
self.styles.text_style = style_definition self.styles.text_style = style_definition
def process_text_justify(self, name: str, tokens: list[Token]) -> None: def process_text_align(self, name: str, tokens: list[Token]) -> None:
"""Process a text-justify declaration""" """Process a text-align declaration"""
if not tokens: if not tokens:
return return
if len(tokens) > 1 or tokens[0].value not in VALID_JUSTIFY: if len(tokens) > 1 or tokens[0].value not in VALID_TEXT_ALIGN:
self.error( self.error(
name, name,
tokens[0], tokens[0],
text_justify_help_text("css"), text_align_help_text("css"),
) )
self.styles._rules["text_justify"] = tokens[0].value self.styles._rules["text_align"] = tokens[0].value
def process_dock(self, name: str, tokens: list[Token]) -> None: def process_dock(self, name: str, tokens: list[Token]) -> None:
if not tokens: if not tokens:

View File

@@ -38,7 +38,7 @@ VALID_BOX_SIZING: Final = {"border-box", "content-box"}
VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"} VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"}
VALID_ALIGN_HORIZONTAL: Final = {"left", "center", "right"} VALID_ALIGN_HORIZONTAL: Final = {"left", "center", "right"}
VALID_ALIGN_VERTICAL: Final = {"top", "middle", "bottom"} VALID_ALIGN_VERTICAL: Final = {"top", "middle", "bottom"}
VALID_JUSTIFY: Final = {"left", "center", "right", "full"} VALID_TEXT_ALIGN: Final = {"start", "end", "left", "right", "center", "justify"}
VALID_SCROLLBAR_GUTTER: Final = {"auto", "stable"} VALID_SCROLLBAR_GUTTER: Final = {"auto", "stable"}
VALID_STYLE_FLAGS: Final = { VALID_STYLE_FLAGS: Final = {
"none", "none",

View File

@@ -31,7 +31,6 @@ from ._style_properties import (
SpacingProperty, SpacingProperty,
StringEnumProperty, StringEnumProperty,
StyleFlagsProperty, StyleFlagsProperty,
StyleProperty,
TransitionsProperty, TransitionsProperty,
) )
from .constants import ( from .constants import (
@@ -42,7 +41,7 @@ from .constants import (
VALID_OVERFLOW, VALID_OVERFLOW,
VALID_SCROLLBAR_GUTTER, VALID_SCROLLBAR_GUTTER,
VALID_VISIBILITY, VALID_VISIBILITY,
VALID_JUSTIFY, VALID_TEXT_ALIGN,
) )
from .scalar import Scalar, ScalarOffset, Unit from .scalar import Scalar, ScalarOffset, Unit
from .scalar_animation import ScalarAnimation from .scalar_animation import ScalarAnimation
@@ -145,7 +144,7 @@ class RulesMap(TypedDict, total=False):
content_align_horizontal: AlignHorizontal content_align_horizontal: AlignHorizontal
content_align_vertical: AlignVertical content_align_vertical: AlignVertical
text_justify: TextJustify text_align: TextJustify
RULE_NAMES = list(RulesMap.__annotations__.keys()) RULE_NAMES = list(RulesMap.__annotations__.keys())
@@ -254,7 +253,7 @@ class StylesBase(ABC):
content_align_vertical = StringEnumProperty(VALID_ALIGN_VERTICAL, "top") content_align_vertical = StringEnumProperty(VALID_ALIGN_VERTICAL, "top")
content_align = AlignProperty() content_align = AlignProperty()
text_justify = StringEnumProperty(VALID_JUSTIFY, "left") text_align = StringEnumProperty(VALID_TEXT_ALIGN, "start")
def __eq__(self, styles: object) -> bool: def __eq__(self, styles: object) -> bool:
"""Check that Styles contains the same rules.""" """Check that Styles contains the same rules."""

View File

@@ -1,14 +1,11 @@
from __future__ import annotations from __future__ import annotations
from asyncio import Lock from asyncio import Lock
from itertools import islice
from fractions import Fraction from fractions import Fraction
from itertools import islice
from operator import attrgetter from operator import attrgetter
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any,
Awaitable,
Callable,
ClassVar, ClassVar,
Collection, Collection,
Iterable, Iterable,
@@ -16,8 +13,7 @@ from typing import (
) )
import rich.repr import rich.repr
from rich.console import Console, RenderableType, JustifyMethod
from rich.console import Console, RenderableType
from rich.measure import Measurement from rich.measure import Measurement
from rich.segment import Segment from rich.segment import Segment
from rich.style import Style from rich.style import Style
@@ -33,13 +29,13 @@ from ._segment_tools import align_lines
from ._styles_cache import StylesCache from ._styles_cache import StylesCache
from ._types import Lines from ._types import Lines
from .box_model import BoxModel, get_box_model from .box_model import BoxModel, get_box_model
from .css.constants import VALID_TEXT_ALIGN
from .dom import DOMNode from .dom import DOMNode
from .dom import NoScreen
from .geometry import Offset, Region, Size, Spacing, clamp from .geometry import Offset, Region, Size, Spacing, clamp
from .layouts.vertical import VerticalLayout from .layouts.vertical import VerticalLayout
from .message import Message from .message import Message
from .reactive import Reactive from .reactive import Reactive
from .dom import NoScreen
if TYPE_CHECKING: if TYPE_CHECKING:
from .app import App, ComposeResult from .app import App, ComposeResult
@@ -1215,13 +1211,15 @@ class Widget(DOMNode):
""" """
if isinstance(renderable, str): if isinstance(renderable, str):
renderable = Text.from_markup(renderable, justify=self.styles.text_justify) justify = _get_rich_justify(self.styles.text_align)
renderable = Text.from_markup(renderable, justify=justify)
rich_style = self.rich_style rich_style = self.rich_style
if isinstance(renderable, Text): if isinstance(renderable, Text):
renderable.stylize(rich_style) renderable.stylize(rich_style)
if not renderable.justify: if not renderable.justify:
renderable.justify = self.styles.text_justify justify = _get_rich_justify(self.styles.text_align)
renderable.justify = justify
else: else:
renderable = Styled(renderable, rich_style) renderable = Styled(renderable, rich_style)
@@ -1579,3 +1577,22 @@ class Widget(DOMNode):
self.scroll_page_up() self.scroll_page_up()
return True return True
return False return False
def _get_rich_justify(css_align: str) -> JustifyMethod:
"""Given the value for CSS text-align, return the analogous argument
for the Rich text `justify` parameter.
Args:
css_align: The value of text-align CSS property.
Returns:
JustifyMethod: The Rich JustifyMethod that corresponds to the text-align
value
"""
assert css_align in VALID_TEXT_ALIGN
return {
"start": "left",
"end": "right",
"justify": "full",
}.get(css_align, css_align)

View File

@@ -1134,14 +1134,14 @@ class TestParsePadding:
class TestParseTextJustify: class TestParseTextJustify:
@pytest.mark.parametrize("valid_justify", ["left", "center", "full", "right"]) @pytest.mark.parametrize("valid_justify", ["left", "center", "full", "right"])
def test_text_justify(self, valid_justify): def test_text_align(self, valid_justify):
css = f"#foo {{ text-justify: {valid_justify} }}" css = f"#foo {{ text-align: {valid_justify} }}"
stylesheet = Stylesheet() stylesheet = Stylesheet()
stylesheet.add_source(css) stylesheet.add_source(css)
assert stylesheet.rules[0].styles.text_justify == valid_justify assert stylesheet.rules[0].styles.text_align == valid_justify
def test_text_justify_invalid(self): def test_text_align_invalid(self):
css = "#foo { text-justify: invalid-value; }" css = "#foo { text-align: invalid-value; }"
stylesheet = Stylesheet() stylesheet = Stylesheet()
with pytest.raises(StylesheetParseError): with pytest.raises(StylesheetParseError):
stylesheet.add_source(css) stylesheet.add_source(css)
@@ -1149,8 +1149,8 @@ class TestParseTextJustify:
rules = stylesheet._parse_rules(css, "foo") rules = stylesheet._parse_rules(css, "foo")
assert rules[0].errors assert rules[0].errors
def test_text_justify_empty_uses_default(self): def test_text_align_empty_uses_default(self):
css = "#foo { text-justify: ; }" css = "#foo { text-align: ; }"
stylesheet = Stylesheet() stylesheet = Stylesheet()
stylesheet.add_source(css) stylesheet.add_source(css)
assert stylesheet.rules[0].styles.text_justify == "left" assert stylesheet.rules[0].styles.text_align == "left"