link fixes

This commit is contained in:
Will McGugan
2022-09-23 11:05:15 +01:00
parent 4437c7b640
commit 8d2ef708bd
7 changed files with 76 additions and 36 deletions

View File

@@ -29,7 +29,7 @@ if TYPE_CHECKING:
RenderLineCallback: TypeAlias = Callable[[int], List[Segment]]
def _style_links(
def style_links(
segments: Iterable[Segment], link_id: str, link_style: Style
) -> list[Segment]:
@@ -38,7 +38,7 @@ def _style_links(
segments = [
_Segment(
text,
(link_style + style if style else None)
(style + link_style if style else None)
if (style and style._link_id == link_id)
else style,
control,
@@ -125,13 +125,21 @@ class StylesCache:
padding=styles.padding,
crop=crop,
)
if widget.hover_style.link_id:
if widget.auto_links:
_style_links = style_links
hover_style = widget.hover_style
link_hover_style = widget.link_hover_style
if link_hover_style:
lines = [
_style_links(line, widget.hover_style.link_id, link_hover_style)
for line in lines
]
if (
link_hover_style
and hover_style._link_id
and hover_style._meta
and "@click" in hover_style.meta
):
if link_hover_style:
lines = [
_style_links(line, hover_style.link_id, link_hover_style)
for line in lines
]
return lines

View File

@@ -581,8 +581,12 @@ class StylesBuilder:
alpha: float | None = None
for token in tokens:
if name == "color" and token.name == "token" and token.value == "auto":
self.styles._rules["auto_color"] = True
if (
"background" not in name
and token.name == "token"
and token.value == "auto"
):
self.styles._rules[f"auto_{name}"] = True
elif token.name == "scalar":
alpha_scalar = Scalar.parse(token.value)
if alpha_scalar.unit != Unit.PERCENT:

View File

@@ -161,10 +161,12 @@ class RulesMap(TypedDict, total=False):
text_align: TextAlign
link_color: Color
auto_link_color: bool
link_background: Color
link_style: Style
hover_color: Color
auto_hover_color: bool
hover_background: Color
hover_style: Style
@@ -297,10 +299,12 @@ class StylesBase(ABC):
text_align = StringEnumProperty(VALID_TEXT_ALIGN, "start")
link_color = ColorProperty("transparent")
auto_link_color = BooleanProperty(False)
link_background = ColorProperty("transparent")
link_style = StyleFlagsProperty()
hover_color = ColorProperty("transparent")
auto_hover_color = BooleanProperty(False)
hover_background = ColorProperty("transparent")
hover_style = StyleFlagsProperty()

View File

@@ -17,7 +17,7 @@ from rich.console import (
RenderResult,
)
from rich.segment import Segment
from rich.style import Style, StyleType
from rich.style import Style
from rich.text import Text
from . import errors, events, messages
@@ -30,7 +30,6 @@ from ._styles_cache import StylesCache
from ._types import Lines
from .binding import NoBinding
from .box_model import BoxModel, get_box_model
from .css.constants import VALID_TEXT_ALIGN
from .dom import DOMNode, NoScreen
from .geometry import Offset, Region, Size, Spacing, clamp
from .layouts.vertical import VerticalLayout
@@ -67,7 +66,7 @@ class _Styled:
"""
def __init__(
self, renderable: "RenderableType", style: Style, link_style: Style
self, renderable: "RenderableType", style: Style, link_style: Style | None
) -> None:
self.renderable = renderable
self.style = style
@@ -93,7 +92,7 @@ class _Styled:
text,
style
if style._meta is None
else (link_style + style if "@click" in style.meta else style),
else (style + link_style if "@click" in style.meta else style),
control,
)
for text, style, control in result_segments
@@ -126,9 +125,12 @@ class Widget(DOMNode):
scrollbar-corner-color: $panel-darken-1;
scrollbar-size-vertical: 2;
scrollbar-size-horizontal: 1;
link-background:;
link-color: $text;
link-style: underline;
hover-background: $boost;
hover-style: not underline;
hover-background: $accent;
hover-color: $text;
hover-style: bold not underline;
}
"""
COMPONENT_CLASSES: ClassVar[set[str]] = set()
@@ -141,6 +143,8 @@ class Widget(DOMNode):
"""Rich renderable may expand."""
shrink = Reactive(True)
"""Rich renderable may shrink."""
auto_links = Reactive(True)
"""Widget will highlight links automatically."""
hover_style: Reactive[Style] = Reactive(Style)
@@ -180,7 +184,7 @@ class Widget(DOMNode):
self._styles_cache = StylesCache()
self._rich_style_cache: dict[str, Style] = {}
self._link_styles: dict[str, Style] = {}
self._stabilized_scrollbar_size: Size | None = None
self._lock = Lock()
super().__init__(
@@ -432,13 +436,6 @@ class Widget(DOMNode):
return height
def watch_hover_style(self, old_style: Style, new_style: Style) -> None:
self._link_styles.pop(old_style.link_id, None)
if new_style.link_id:
meta = new_style.meta
if "@click" in meta:
self._link_styles[new_style.link_id] = self.link_hover_style
def watch_scroll_x(self, new_value: float) -> None:
self.horizontal_scrollbar.position = int(new_value)
self.refresh(layout=True)
@@ -557,10 +554,16 @@ class Widget(DOMNode):
elif overflow_y == "auto":
show_vertical = self.virtual_size.height > height
if overflow_x == "auto" and show_vertical and not show_horizontal:
if (
overflow_x == "auto"
and show_vertical
and not show_horizontal
and self._stabilized_scrollbar_size != self.container_size
):
show_horizontal = (
self.virtual_size.width + styles.scrollbar_size_vertical > width
)
self._stabilized_scrollbar_size = self.container_size
self.show_horizontal_scrollbar = show_horizontal
self.show_vertical_scrollbar = show_vertical
@@ -856,21 +859,35 @@ class Widget(DOMNode):
@property
def link_style(self) -> Style:
"""Style of links."""
styles = self.styles
base, _, background, color = self.colors
_, background = self.background_colors
link_background = background + styles.link_background
link_color = link_background + (
link_background.get_contrast_text(styles.link_color.a)
if styles.auto_link_color
else styles.link_color
)
style = styles.link_style + Style.from_color(
(color + styles.link_color).rich_color,
(background + styles.link_background).rich_color,
link_color.rich_color,
link_background.rich_color,
)
return style
@property
def link_hover_style(self) -> Style:
"""Style of links with mouse hover."""
styles = self.styles
base, _, background, color = self.colors
_, background = self.background_colors
hover_background = background + styles.hover_background
hover_color = hover_background + (
hover_background.get_contrast_text(styles.hover_color.a)
if styles.auto_hover_color
else styles.hover_color
)
style = styles.hover_style + Style.from_color(
(color + styles.hover_color).rich_color,
(background + styles.hover_background).rich_color,
hover_color.rich_color,
hover_background.rich_color,
)
return style
@@ -1489,7 +1506,9 @@ class Widget(DOMNode):
):
renderable.justify = text_justify
renderable = _Styled(renderable, self.rich_style, self.link_style)
renderable = _Styled(
renderable, self.rich_style, self.link_style if self.auto_links else None
)
return renderable
@@ -1789,6 +1808,7 @@ class Widget(DOMNode):
def _on_leave(self, event: events.Leave) -> None:
self.mouse_over = False
self.hover_style = Style()
def _on_enter(self, event: events.Enter) -> None:
self.mouse_over = True

View File

@@ -7,6 +7,7 @@ import os.path
from rich.console import RenderableType
import rich.repr
from rich.text import Text
from .. import events

View File

@@ -45,6 +45,7 @@ class Footer(Widget):
def __init__(self) -> None:
super().__init__()
self._key_text: Text | None = None
self.auto_links = False
highlight_key: Reactive[str | None] = Reactive(None)

View File

@@ -5,7 +5,7 @@ from typing import ClassVar, Generic, Iterator, NewType, TypeVar
import rich.repr
from rich.console import RenderableType
from rich.style import Style
from rich.style import Style, NULL_STYLE
from rich.text import Text, TextType
from rich.tree import Tree
@@ -219,6 +219,7 @@ class TreeControl(Generic[NodeDataType], Static, can_focus=True):
id: str | None = None,
classes: str | None = None,
) -> None:
super().__init__(name=name, id=id, classes=classes)
self.data = data
self.node_id = NodeID(0)
@@ -231,7 +232,8 @@ class TreeControl(Generic[NodeDataType], Static, can_focus=True):
self._tree.label = self.root
self.nodes[NodeID(self.node_id)] = self.root
super().__init__(name=name, id=id, classes=classes)
self.auto_links = False
hover_node: Reactive[NodeID | None] = Reactive(None)
cursor: Reactive[NodeID] = Reactive(NodeID(0))
@@ -324,8 +326,8 @@ class TreeControl(Generic[NodeDataType], Static, can_focus=True):
if isinstance(node.label, str)
else node.label
)
# if node.id == self.hover_node:
# label.stylize("underline")
if node.id == self.hover_node:
label.stylize("underline")
label.apply_meta({"@click": f"click_label({node.id})", "tree_node": node.id})
return label