mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
new border renderable includes outline
This commit is contained in:
@@ -14,25 +14,55 @@ class Border:
|
|||||||
self,
|
self,
|
||||||
renderable: RenderableType,
|
renderable: RenderableType,
|
||||||
edge_styles: tuple[EdgeStyle, EdgeStyle, EdgeStyle, EdgeStyle],
|
edge_styles: tuple[EdgeStyle, EdgeStyle, EdgeStyle, EdgeStyle],
|
||||||
|
outline: bool = False,
|
||||||
):
|
):
|
||||||
self.renderable = renderable
|
self.renderable = renderable
|
||||||
self.edge_styles = edge_styles
|
self.edge_styles = edge_styles
|
||||||
|
self.outline = outline
|
||||||
|
|
||||||
@property
|
(
|
||||||
def sides(self) -> tuple[str, str, str, str]:
|
(top, top_style),
|
||||||
(top, _), (right, _), (bottom, _), (left, _) = self.edge_styles
|
(right, right_style),
|
||||||
return (top or "none", right or "none", bottom or "none", left or "none")
|
(bottom, bottom_style),
|
||||||
|
(left, left_style),
|
||||||
|
) = edge_styles
|
||||||
|
self._sides = (top or "none", right or "none", bottom or "none", left or "none")
|
||||||
|
self._styles = (top_style, right_style, bottom_style, left_style)
|
||||||
|
|
||||||
@property
|
def _crop_renderable(self, lines: list[list[Segment]], width: int) -> None:
|
||||||
def styles(self) -> tuple[Style, Style, Style, Style]:
|
"""Crops a renderable in place.
|
||||||
(_, top), (_, right), (_, left), (_, bottom) = self.edge_styles
|
|
||||||
return (top, right, left, bottom)
|
Args:
|
||||||
|
lines (list[list[Segment]]): Segment lines.
|
||||||
|
width (int): Desired width.
|
||||||
|
"""
|
||||||
|
top, right, bottom, left = self._sides
|
||||||
|
has_left = left != "none"
|
||||||
|
has_right = right != "none"
|
||||||
|
has_top = top != "none"
|
||||||
|
has_bottom = bottom != "none"
|
||||||
|
|
||||||
|
if has_top:
|
||||||
|
lines.pop(0)
|
||||||
|
if has_bottom:
|
||||||
|
lines.pop(-1)
|
||||||
|
|
||||||
|
divide = Segment.divide
|
||||||
|
if has_left and has_right:
|
||||||
|
for line in lines:
|
||||||
|
_, line[:] = divide(line, [1, width - 1])
|
||||||
|
elif has_left:
|
||||||
|
for line in lines:
|
||||||
|
_, line[:] = divide(line, [1, width])
|
||||||
|
elif has_right:
|
||||||
|
for line in lines:
|
||||||
|
line[:], _ = divide(line, [width - 1, width])
|
||||||
|
|
||||||
def __rich_console__(
|
def __rich_console__(
|
||||||
self, console: "Console", options: "ConsoleOptions"
|
self, console: "Console", options: "ConsoleOptions"
|
||||||
) -> "RenderResult":
|
) -> "RenderResult":
|
||||||
top, right, bottom, left = self.sides
|
top, right, bottom, left = self._sides
|
||||||
top_style, right_style, bottom_style, left_style = self.styles
|
top_style, right_style, bottom_style, left_style = self._styles
|
||||||
BOX = BOX_STYLES
|
BOX = BOX_STYLES
|
||||||
|
|
||||||
has_left = left != "none"
|
has_left = left != "none"
|
||||||
@@ -41,6 +71,9 @@ class Border:
|
|||||||
has_bottom = bottom != "none"
|
has_bottom = bottom != "none"
|
||||||
|
|
||||||
width = options.max_width - has_left - has_right
|
width = options.max_width - has_left - has_right
|
||||||
|
if self.outline:
|
||||||
|
render_options = options
|
||||||
|
else:
|
||||||
if options.height is None:
|
if options.height is None:
|
||||||
render_options = options.update_width(width)
|
render_options = options.update_width(width)
|
||||||
else:
|
else:
|
||||||
@@ -48,6 +81,8 @@ class Border:
|
|||||||
render_options = options.update_dimensions(width, height)
|
render_options = options.update_dimensions(width, height)
|
||||||
|
|
||||||
lines = console.render_lines(self.renderable, render_options)
|
lines = console.render_lines(self.renderable, render_options)
|
||||||
|
if self.outline:
|
||||||
|
self._crop_renderable(lines, options.max_width)
|
||||||
|
|
||||||
_Segment = Segment
|
_Segment = Segment
|
||||||
new_line = _Segment.line()
|
new_line = _Segment.line()
|
||||||
@@ -63,13 +98,12 @@ class Border:
|
|||||||
box_left = BOX[left][1][0]
|
box_left = BOX[left][1][0]
|
||||||
box_right = BOX[right][1][2]
|
box_right = BOX[right][1][2]
|
||||||
left_segment = _Segment(box_left, left_style)
|
left_segment = _Segment(box_left, left_style)
|
||||||
right_segment = _Segment(box_right, right_style)
|
right_segment = _Segment(box_right + "\n", right_style)
|
||||||
if has_left and has_right:
|
if has_left and has_right:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
yield left_segment
|
yield left_segment
|
||||||
yield from line
|
yield from line
|
||||||
yield right_segment
|
yield right_segment
|
||||||
yield new_line
|
|
||||||
elif has_left:
|
elif has_left:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
yield left_segment
|
yield left_segment
|
||||||
@@ -79,7 +113,6 @@ class Border:
|
|||||||
for line in lines:
|
for line in lines:
|
||||||
yield from line
|
yield from line
|
||||||
yield right_segment
|
yield right_segment
|
||||||
yield new_line
|
|
||||||
else:
|
else:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
yield from line
|
yield from line
|
||||||
@@ -100,14 +133,18 @@ if __name__ == "__main__":
|
|||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
|
|
||||||
text = Text("Textual " * 40, style="dim")
|
text = Text("Textual " * 40, style="dim")
|
||||||
print(
|
border = Border(
|
||||||
Border(
|
|
||||||
text,
|
text,
|
||||||
(
|
(
|
||||||
("outer", Style.parse("green on red")),
|
("outer", Style.parse("green")),
|
||||||
("none", Style.parse("green")),
|
("outer", Style.parse("green")),
|
||||||
("double", Style.parse("green")),
|
("outer", Style.parse("green")),
|
||||||
("double", Style.parse("green")),
|
("outer", Style.parse("green")),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
print(text)
|
||||||
|
print()
|
||||||
|
print(border)
|
||||||
|
print()
|
||||||
|
border.outline = True
|
||||||
|
print(border)
|
||||||
|
|||||||
Reference in New Issue
Block a user