styles renderer update

This commit is contained in:
Will McGugan
2022-06-30 10:54:37 +01:00
parent b2f0dbb8a2
commit 410fc91a0e
5 changed files with 51 additions and 20 deletions

View File

@@ -115,7 +115,7 @@ class BasicApp(App, css_path="basic.css"):
Static(Syntax(CODE, "python"), classes="code"),
classes="scrollable",
),
table,
# table,
Error(),
Tweet(TweetBody(), classes="scrollbar-size-custom"),
Warning(),

View File

@@ -35,7 +35,7 @@ def line_crop(
for segment in iter_segments:
end_pos = pos + _cell_len(segment.text)
if end_pos > start:
segment = segment.split_cells(start - pos)[-1]
segment = segment.split_cells(start - pos)[1]
break
pos = end_pos
else:
@@ -86,5 +86,5 @@ def line_trim(segments: list[Segment], start: bool, end: bool) -> list[Segment]:
if last_segment.text:
segments[-1] = last_segment
else:
segments.pop(-1)
segments.pop()
return segments

View File

@@ -11,11 +11,11 @@ from .css.types import EdgeType
from ._segment_tools import line_crop
from ._types import Lines
from .geometry import Region, Size
from .widget import Widget
if TYPE_CHECKING:
from .css.styles import RenderStyles
from .widget import Widget
NORMALIZE_BORDER: dict[EdgeType, EdgeType] = {"none": "", "hidden": ""}
@@ -27,8 +27,14 @@ class StylesRenderer:
self._cache: dict[int, list[Segment]] = {}
self._dirty_lines: set[int] = set()
def invalidate(self, region: Region) -> None:
self._dirty_lines.update(region.y_range)
def set_dirty(self, *regions: Region) -> None:
if regions:
for region in regions:
self._dirty_lines.update(region.y_range)
else:
self._dirty_lines.clear()
for y in self._widget.size.lines:
self._dirty_lines.add(y)
def render(self, region: Region) -> Lines:
@@ -50,12 +56,14 @@ class StylesRenderer:
width, height = size
lines: Lines = []
add_line = lines.append
simplify = Segment.simplify
is_dirty = self._dirty_lines.__contains__
render_line = self.render_line
for y in region.y_range:
if is_dirty(y) or y not in self._cache:
line = render_line(styles, y, size, base_background, background)
line = list(simplify(line))
self._cache[y] = line
else:
line = self._cache[y]
@@ -64,13 +72,13 @@ class StylesRenderer:
if region.x_extents != (0, width):
_line_crop = line_crop
x1, x2 = region.x_range
x1, x2 = region.x_extents
lines = [_line_crop(line, x1, x2, width) for line in lines]
return lines
def render_content_line(self, y: int, width: int) -> list[Segment]:
return [Segment((str(y) * width)[:width])]
def render_content_line(self, y: int) -> list[Segment]:
return self._widget.render_line(y)
def render_line(
self,
@@ -149,11 +157,9 @@ class StylesRenderer:
return [Segment(" " * width, background_style)]
# Apply background style
line = list(
Segment.apply_style(
self.render_content_line(y - gutter.top, content_width), inner_style
)
)
line = self.render_content_line(y - gutter.top)
if inner_style:
line = list(Segment.apply_style(line, inner_style))
# Add padding
if pad_left and pad_right:
@@ -184,7 +190,7 @@ class StylesRenderer:
from_color(border_left_color.rich_color),
)
_, (_, _, right), _ = get_box(
border_left,
border_right,
inner_style,
outer_style,
from_color(border_right_color.rich_color),
@@ -195,7 +201,7 @@ class StylesRenderer:
elif border_left:
return [left, *line]
return [right, *line]
return [*line, right]
if __name__ == "__main__":

View File

@@ -139,6 +139,10 @@ class Size(NamedTuple):
width, height = self
return Region(0, 0, width, height)
@property
def lines(self) -> list[int]:
return list(range(self.height))
def __add__(self, other: object) -> Size:
if isinstance(other, tuple):
width, height = self

View File

@@ -17,6 +17,7 @@ from rich.align import Align
from rich.console import Console, RenderableType
from rich.measure import Measurement
from rich.padding import Padding
from rich.segment import Segment
from rich.style import Style
from . import errors
@@ -25,6 +26,7 @@ from ._animator import BoundAnimator
from ._border import Border
from .box_model import BoxModel, get_box_model
from ._context import active_app
from ._styles_render import StylesRenderer
from ._types import Lines
from .dom import DOMNode
from ._layout import ArrangeResult
@@ -118,6 +120,8 @@ class Widget(DOMNode):
self._arrangement: ArrangeResult | None = None
self._arrangement_cache_key: tuple[int, Size] = (-1, Size())
self._styles_renderer = StylesRenderer(self)
super().__init__(name=name, id=id, classes=classes)
self.add_children(*children)
@@ -833,9 +837,18 @@ class Widget(DOMNode):
"""
renderable = self.render()
renderable = self._style_renderable(renderable)
styles = self.styles
content_align = (styles.content_align_horizontal, styles.content_align_vertical)
if content_align != ("left", "top"):
horizontal, vertical = content_align
renderable = Align(renderable, horizontal, vertical=vertical)
return renderable
@property
def content_size(self) -> Size:
return self._size - self.styles.gutter.totals
@property
def size(self) -> Size:
return self._size
@@ -955,13 +968,13 @@ class Widget(DOMNode):
def _render_lines(self) -> None:
"""Render all lines."""
width, height = self.size
width, height = self.content_size
renderable = self.render_styled()
options = self.console.options.update_dimensions(width, height).update(
highlight=False
)
lines = self.console.render_lines(renderable, options)
self._render_cache = RenderCache(self.size, lines)
lines = self.console.render_lines(renderable, options, style=self.rich_style)
self._render_cache = RenderCache(self.content_size, lines)
self._dirty_regions.clear()
def _crop_lines(self, lines: Lines, x1, x2) -> Lines:
@@ -971,6 +984,10 @@ class Widget(DOMNode):
lines = [_line_crop(line, x1, x2, width) for line in lines]
return lines
def render_line(self, y) -> list[Segment]:
line = self._render_cache.lines[y]
return line
def render_lines(self, crop: Region) -> Lines:
"""Render the widget in to lines.
@@ -981,8 +998,12 @@ class Widget(DOMNode):
Lines: A list of list of segments
"""
if self._dirty_regions:
self._styles_renderer.set_dirty(*self._dirty_regions)
self._render_lines()
lines = self._styles_renderer.render(crop)
return lines
x1, y1, x2, y2 = crop.corners
lines = self._render_cache.lines[y1:y2]
lines = self._crop_lines(lines, x1, x2)