mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Cleanup of _border.py
All indications are that Border isn't used within Textual any more.
This commit is contained in:
@@ -3,9 +3,7 @@ from __future__ import annotations
|
||||
from functools import lru_cache
|
||||
from typing import cast, Tuple, Union
|
||||
|
||||
from rich.console import Console, ConsoleOptions, RenderResult, RenderableType
|
||||
import rich.repr
|
||||
from rich.segment import Segment, SegmentLines
|
||||
from rich.segment import Segment
|
||||
from rich.style import Style
|
||||
|
||||
from .color import Color
|
||||
@@ -158,164 +156,6 @@ def render_row(
|
||||
return [Segment(box2.text * width, box2.style)]
|
||||
|
||||
|
||||
@rich.repr.auto
|
||||
class Border:
|
||||
"""Renders Textual CSS borders.
|
||||
|
||||
This is analogous to Rich's `Box` but more flexible. Different borders may be
|
||||
applied to each of the four edges, and more advanced borders can be achieved through
|
||||
various combinations of Widget and parent background colors.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
renderable: RenderableType,
|
||||
borders: Borders,
|
||||
inner_color: Color,
|
||||
outer_color: Color,
|
||||
outline: bool = False,
|
||||
):
|
||||
self.renderable = renderable
|
||||
self.edge_styles = borders
|
||||
self.outline = outline
|
||||
|
||||
(
|
||||
(top, top_color),
|
||||
(right, right_color),
|
||||
(bottom, bottom_color),
|
||||
(left, left_color),
|
||||
) = borders
|
||||
self._sides: tuple[EdgeType, EdgeType, EdgeType, EdgeType]
|
||||
self._sides = (top, right, bottom, left)
|
||||
from_color = Style.from_color
|
||||
|
||||
self._styles = (
|
||||
from_color(top_color.rich_color),
|
||||
from_color(right_color.rich_color),
|
||||
from_color(bottom_color.rich_color),
|
||||
from_color(left_color.rich_color),
|
||||
)
|
||||
self.inner_style = from_color(bgcolor=inner_color.rich_color)
|
||||
self.outer_style = from_color(bgcolor=outer_color.rich_color)
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
yield self.renderable
|
||||
yield self.edge_styles
|
||||
|
||||
def _crop_renderable(self, lines: list[list[Segment]], width: int) -> None:
|
||||
"""Crops a renderable in place.
|
||||
|
||||
Args:
|
||||
lines (list[list[Segment]]): Segment lines.
|
||||
width (int): Desired width.
|
||||
"""
|
||||
top, right, bottom, left = self._sides
|
||||
# the 4 following lines rely on the fact that we normalise "none" and "hidden" to en empty string
|
||||
has_left = bool(left)
|
||||
has_right = bool(right)
|
||||
has_top = bool(top)
|
||||
has_bottom = bool(bottom)
|
||||
|
||||
if has_top:
|
||||
lines.pop(0)
|
||||
if has_bottom and lines:
|
||||
lines.pop(-1)
|
||||
|
||||
# TODO: Divide is probably quite inefficient here,
|
||||
# It could be much faster for the specific case of one off the start end end
|
||||
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__(
|
||||
self, console: "Console", options: "ConsoleOptions"
|
||||
) -> "RenderResult":
|
||||
top, right, bottom, left = self._sides
|
||||
style = console.get_style(self.inner_style)
|
||||
outer_style = console.get_style(self.outer_style)
|
||||
top_style, right_style, bottom_style, left_style = self._styles
|
||||
|
||||
# ditto than in `_crop_renderable` ☝
|
||||
has_left = bool(left)
|
||||
has_right = bool(right)
|
||||
has_top = bool(top)
|
||||
has_bottom = bool(bottom)
|
||||
|
||||
width = options.max_width - has_left - has_right
|
||||
|
||||
if width <= 2:
|
||||
lines = console.render_lines(self.renderable, options, new_lines=True)
|
||||
yield SegmentLines(lines)
|
||||
return
|
||||
|
||||
if self.outline:
|
||||
render_options = options
|
||||
else:
|
||||
if options.height is None:
|
||||
render_options = options.update_width(width)
|
||||
else:
|
||||
new_height = options.height - has_top - has_bottom
|
||||
if new_height >= 1:
|
||||
render_options = options.update_dimensions(width, new_height)
|
||||
else:
|
||||
render_options = options.update_width(width)
|
||||
|
||||
lines = console.render_lines(self.renderable, render_options)
|
||||
if self.outline:
|
||||
self._crop_renderable(lines, options.max_width)
|
||||
|
||||
_Segment = Segment
|
||||
new_line = _Segment.line()
|
||||
if has_top:
|
||||
box1, box2, box3 = get_box(top, style, outer_style, top_style)[0]
|
||||
if has_left:
|
||||
yield box1 if top == left else _Segment(" ", box2.style)
|
||||
yield _Segment(box2.text * width, box2.style)
|
||||
if has_right:
|
||||
yield box3 if top == left else _Segment(" ", box3.style)
|
||||
yield new_line
|
||||
|
||||
left_segment = get_box(left, style, outer_style, left_style)[1][0]
|
||||
_right_segment = get_box(right, style, outer_style, right_style)[1][2]
|
||||
right_segment = _Segment(_right_segment.text + "\n", _right_segment.style)
|
||||
|
||||
if has_left and has_right:
|
||||
for line in lines:
|
||||
yield left_segment
|
||||
yield from line
|
||||
yield right_segment
|
||||
elif has_left:
|
||||
for line in lines:
|
||||
yield left_segment
|
||||
yield from line
|
||||
yield new_line
|
||||
elif has_right:
|
||||
for line in lines:
|
||||
yield from line
|
||||
yield right_segment
|
||||
else:
|
||||
for line in lines:
|
||||
yield from line
|
||||
yield new_line
|
||||
|
||||
if has_bottom:
|
||||
box1, box2, box3 = get_box(bottom, style, outer_style, bottom_style)[2]
|
||||
if has_left:
|
||||
yield box1 if bottom == left else _Segment(" ", box1.style)
|
||||
yield _Segment(box2.text * width, box2.style)
|
||||
if has_right:
|
||||
yield box3 if bottom == right else _Segment(" ", box3.style)
|
||||
yield new_line
|
||||
|
||||
|
||||
_edge_type_normalization_table: dict[EdgeType, EdgeType] = {
|
||||
# i.e. we normalize "border: none;" to "border: ;".
|
||||
# As a result our layout-related calculations that include borders are simpler (and have better performance)
|
||||
@@ -326,49 +166,3 @@ _edge_type_normalization_table: dict[EdgeType, EdgeType] = {
|
||||
|
||||
def normalize_border_value(value: BorderValue) -> BorderValue:
|
||||
return _edge_type_normalization_table.get(value[0], value[0]), value[1]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from rich import print
|
||||
from rich.text import Text
|
||||
from rich.padding import Padding
|
||||
|
||||
from .color import Color
|
||||
|
||||
inner = Color.parse("#303F9F")
|
||||
outer = Color.parse("#212121")
|
||||
|
||||
lorem = """[#C5CAE9]Lorem ipsum dolor sit amet, consectetur adipiscing elit. In velit libero, volutpat nec hendrerit at, faucibus in odio. Aliquam hendrerit nibh sed quam volutpat maximus. Nullam suscipit convallis lorem quis sodales. In tristique lobortis ante et dictum. Ut at finibus ipsum. In urna dolor, placerat et mi facilisis, congue sollicitudin massa. Phasellus felis turpis, cursus eu lectus et, porttitor malesuada augue. Sed feugiat volutpat velit, sollicitudin fringilla velit bibendum faucibus."""
|
||||
text = Text.from_markup(lorem)
|
||||
border = Border(
|
||||
Padding(text, 1, style="on #303F9F"),
|
||||
(
|
||||
("none", Color.parse("#C5CAE9")),
|
||||
("none", Color.parse("#C5CAE9")),
|
||||
("wide", Color.parse("#C5CAE9")),
|
||||
("none", Color.parse("#C5CAE9")),
|
||||
),
|
||||
inner_color=inner,
|
||||
outer_color=outer,
|
||||
)
|
||||
|
||||
print(
|
||||
Padding(border, (1, 2), style="on #212121"),
|
||||
)
|
||||
print()
|
||||
|
||||
border = Border(
|
||||
Padding(text, 1, style="on #303F9F"),
|
||||
(
|
||||
("hkey", Color.parse("#8BC34A")),
|
||||
("hkey", Color.parse("#8BC34A")),
|
||||
("hkey", Color.parse("#8BC34A")),
|
||||
("hkey", Color.parse("#8BC34A")),
|
||||
),
|
||||
inner_color=inner,
|
||||
outer_color=outer,
|
||||
)
|
||||
|
||||
print(
|
||||
Padding(border, (1, 2), style="on #212121"),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user