Skip to content

Commit

Permalink
text alignment
Browse files Browse the repository at this point in the history
  • Loading branch information
willmcgugan committed Nov 5, 2024
1 parent 06387de commit b3c8467
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 18 deletions.
4 changes: 1 addition & 3 deletions src/textual/_segment_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,6 @@ def blank_lines(count: int) -> list[list[Segment]]:
if top_blank_lines:
yield from blank_lines(top_blank_lines)

horizontal_excess_space = max(0, width - shape_width)

if horizontal == "left":
for cell_length, line in zip(line_lengths, lines):
if cell_length == width:
Expand All @@ -241,7 +239,7 @@ def blank_lines(count: int) -> list[list[Segment]]:
yield line_pad(line, 0, width - cell_length, style)

elif horizontal == "center":
left_space = horizontal_excess_space // 2
left_space = max(0, width - shape_width) // 2
for cell_length, line in zip(line_lengths, lines):
if cell_length == width:
yield line
Expand Down
11 changes: 4 additions & 7 deletions src/textual/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from __future__ import annotations

import re
from itertools import zip_longest
from operator import itemgetter
from typing import Callable, Iterable, NamedTuple, Sequence

Expand Down Expand Up @@ -73,12 +72,10 @@ def _justify_lines(
spaces[len(spaces) - index - 1] += 1
num_spaces += 1
index = (index + 1) % len(spaces)
tokens: list[Content] = []
for index, (word, next_word) in enumerate(zip_longest(words, words[1:])):
if index < len(spaces):
tokens.append(word.extend_right(spaces[index]))
else:
tokens.append(word)
tokens = [
word.extend_right(spaces[index]) if index < len(spaces) else word
for index, word in enumerate(words)
]
new_lines[line_index] = Content("").join(tokens)

return new_lines
Expand Down
85 changes: 84 additions & 1 deletion src/textual/strip.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
from rich.segment import Segment
from rich.style import Style, StyleType

from textual._segment_tools import index_to_cell_position
from textual._segment_tools import index_to_cell_position, line_pad
from textual.cache import FIFOCache
from textual.color import Color
from textual.constants import DEBUG
from textual.css.types import AlignHorizontal, AlignVertical
from textual.filter import LineFilter
from textual.geometry import Size


def get_line_length(segments: Iterable[Segment]) -> int:
Expand Down Expand Up @@ -157,6 +159,87 @@ def from_lines(
"""
return [cls(segments, cell_length) for segments in lines]

@classmethod
def align(
cls,
strips: list[Strip],
style: Style,
size: Size,
horizontal: AlignHorizontal,
vertical: AlignVertical,
) -> Iterable[Strip]:
if not strips:
return
width, height = size
line_lengths = [strip.cell_length for strip in strips]
shape_width = max(line_lengths)
shape_height = len(line_lengths)

def blank_lines(count: int) -> Iterable[Strip]:
"""Create blank lines.
Args:
count: Desired number of blank lines.
Returns:
An iterable of blank lines.
"""
blank = cls([Segment(" " * width, style)], width)
for _ in range(count):
yield blank

top_blank_lines = bottom_blank_lines = 0
vertical_excess_space = max(0, height - shape_height)

if vertical == "top":
bottom_blank_lines = vertical_excess_space
elif vertical == "middle":
top_blank_lines = vertical_excess_space // 2
bottom_blank_lines = vertical_excess_space - top_blank_lines
elif vertical == "bottom":
top_blank_lines = vertical_excess_space

if top_blank_lines:
yield from blank_lines(top_blank_lines)

if horizontal == "left":
for strip in strips:
if strip.cell_length == width:
yield strip
else:
yield Strip(
line_pad(strip._segments, 0, width - strip.cell_length, style),
width,
)
elif horizontal == "center":
left_space = max(0, width - shape_width) // 2
for strip in strips:
if strip.cell_length == width:
yield strip
else:
yield Strip(
line_pad(
strip._segments,
left_space,
width - strip.cell_length - left_space,
style,
),
width,
)

elif horizontal == "right":
for strip in strips:
if strip.cell_length == width:
yield strip
else:
yield cls(
line_pad(strip._segments, width - strip.cell_length, 0, style),
width,
)

if bottom_blank_lines:
yield from blank_lines(bottom_blank_lines)

def index_to_cell_position(self, index: int) -> int:
"""Given a character index, return the cell position of that character.
This is the sum of the cell lengths of all the characters *before* the character
Expand Down
18 changes: 11 additions & 7 deletions src/textual/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -3700,20 +3700,26 @@ def _render_content(self) -> None:
"""Render all lines."""
width, height = self.size
renderable = self.render()
styles = self.styles
align_horizontal, align_vertical = styles.content_align

visual = textualize(renderable)
if visual is not None:
visual_style = self.visual_style
strips = visual.render_strips(
width,
height=height,
base_style=self.visual_style,
justify=self._get_justify_method() or "left",
)
strips = [
strip.adjust_cell_length(width, visual_style.rich_style)
for strip in strips
]
strips = list(
Strip.align(
strips,
_NULL_STYLE,
self.size,
align_horizontal,
align_vertical,
)
)

else:
renderable = self.post_render(renderable)
Expand All @@ -3732,8 +3738,6 @@ def _render_content(self) -> None:
)
)

styles = self.styles
align_horizontal, align_vertical = styles.content_align
lines = list(
align_lines(
lines,
Expand Down

0 comments on commit b3c8467

Please sign in to comment.