Merge pull request #1268 from Textualize/spatial-map

Optimisations and fixes
This commit is contained in:
Will McGugan
2022-11-25 13:42:55 +08:00
committed by GitHub
5 changed files with 38 additions and 18 deletions

View File

@@ -10,7 +10,7 @@ if TYPE_CHECKING:
from .widget import Widget
ArrangeResult: TypeAlias = "tuple[list[WidgetPlacement], set[Widget]]"
DockArrangeResult: TypeAlias = "tuple[list[WidgetPlacement], set[Widget], Spacing]"
DockArrangeResult: TypeAlias = "tuple[list[WidgetPlacement], set[Widget], Spacing]]"
class WidgetPlacement(NamedTuple):

View File

@@ -1,5 +1,7 @@
from __future__ import annotations
from functools import lru_cache
from sys import intern
from typing import TYPE_CHECKING, Callable, Iterable, List
from rich.segment import Segment
@@ -52,6 +54,20 @@ def style_links(
return segments
@lru_cache(1024 * 8)
def make_blank(width, style: Style) -> Segment:
"""Make a blank segment.
Args:
width (_type_): Width of blank.
style (Style): Style of blank.
Returns:
Segment: A single segment
"""
return Segment(intern(" " * width), style)
class StylesCache:
"""Responsible for rendering CSS Styles and keeping a cache of rendered lines.
@@ -319,20 +335,20 @@ class StylesCache:
right_style = from_color(color=(background + border_right_color).rich_color)
right = get_box(border_right, inner, outer, right_style)[1][2]
if border_left and border_right:
line = [left, Segment(" " * (width - 2), background_style), right]
line = [left, make_blank(width - 2, background_style), right]
elif border_left:
line = [left, Segment(" " * (width - 1), background_style)]
line = [left, make_blank(width - 1, background_style)]
elif border_right:
line = [Segment(" " * (width - 1), background_style), right]
line = [make_blank(width - 1, background_style), right]
else:
line = [Segment(" " * width, background_style)]
line = [make_blank(width, background_style)]
else:
# Content with border and padding (C)
content_y = y - gutter.top
if content_y < content_height:
line = render_content_line(y - gutter.top)
else:
line = [Segment(" " * content_width, inner)]
line = [make_blank(content_width, inner)]
if inner:
line = Segment.apply_style(line, inner)
line = line_pad(line, pad_left, pad_right, inner)

View File

@@ -305,7 +305,7 @@ class BoxProperty:
current_value: tuple[str, Color] = cast(
"tuple[str, Color]", obj.get_rule(self.name)
)
has_edge = current_value and current_value[0]
has_edge = bool(current_value and current_value[0])
new_edge = bool(_type)
if obj.set_rule(self.name, new_value):
obj.refresh(layout=has_edge != new_edge)

View File

@@ -594,8 +594,10 @@ class Styles(StylesBase):
Returns:
bool: ``True`` if a rule was cleared, or ``False`` if it was already not set.
"""
self._updates += 1
return self._rules.pop(rule, None) is not None
changed = self._rules.pop(rule, None) is not None
if changed:
self._updates += 1
return changed
def get_rules(self) -> RulesMap:
return self._rules.copy()
@@ -610,12 +612,17 @@ class Styles(StylesBase):
Returns:
bool: ``True`` if the rule changed, otherwise ``False``.
"""
self._updates += 1
if value is None:
return self._rules.pop(rule, None) is not None
changed = self._rules.pop(rule, None) is not None
if changed:
self._updates += 1
return changed
current = self._rules.get(rule)
self._rules[rule] = value
return current != value
changed = current != value
if changed:
self._updates += 1
return changed
def get_rule(self, rule: str, default: object = None) -> object:
return self._rules.get(rule, default)

View File

@@ -1,8 +1,8 @@
from __future__ import annotations
from collections import Counter
from asyncio import Event as AsyncEvent
from asyncio import Lock, create_task, wait
from collections import Counter
from fractions import Fraction
from itertools import islice
from operator import attrgetter
@@ -53,7 +53,6 @@ from .message import Message
from .messages import CallbackType
from .reactive import Reactive
from .render import measure
from .await_remove import AwaitRemove
from .walk import walk_depth_first
if TYPE_CHECKING:
@@ -755,14 +754,12 @@ class Widget(DOMNode):
def watch_scroll_x(self, new_value: float) -> None:
if self.show_horizontal_scrollbar:
self.horizontal_scrollbar.position = int(new_value)
self.horizontal_scrollbar.refresh()
self.refresh(layout=True)
self.refresh(layout=True, repaint=False)
def watch_scroll_y(self, new_value: float) -> None:
if self.show_vertical_scrollbar:
self.vertical_scrollbar.position = int(new_value)
self.vertical_scrollbar.refresh()
self.refresh(layout=True)
self.refresh(layout=True, repaint=False)
def validate_scroll_x(self, value: float) -> float:
return clamp(value, 0, self.max_scroll_x)