mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge pull request #774 from Textualize/dont-render-zero-opacity-text
Minimise rendering when text-opacity/opacity is zero
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
Screen {
|
||||
layout: center;
|
||||
background: darkslategrey;
|
||||
}
|
||||
|
||||
.box1 {
|
||||
#box1 {
|
||||
background: darkmagenta;
|
||||
width: auto;
|
||||
padding: 4 8;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Static
|
||||
from textual.binding import Binding
|
||||
from textual.widgets import Static, Footer
|
||||
|
||||
|
||||
class JustABox(App):
|
||||
BINDINGS = [
|
||||
Binding(key="t", action="text_fade_out", description="text-opacity fade out"),
|
||||
Binding(key="o", action="widget_fade_out", description="opacity fade out"),
|
||||
]
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Static("Hello, world!", classes="box1")
|
||||
yield Static("Hello, world!", id="box1")
|
||||
yield Footer()
|
||||
|
||||
def action_text_fade_out(self) -> None:
|
||||
box = self.query_one("#box1")
|
||||
self.animator.animate(box.styles, "text_opacity", value=0.0, duration=1)
|
||||
|
||||
def action_widget_fade_out(self) -> None:
|
||||
box = self.query_one("#box1")
|
||||
self.animator.animate(box.styles, "opacity", value=0.0, duration=1)
|
||||
|
||||
|
||||
app = JustABox(watch_css=True, css_path="../darren/just_a_box.css")
|
||||
|
||||
@@ -604,19 +604,28 @@ class Compositor:
|
||||
# up to this point.
|
||||
_rich_traceback_guard = True
|
||||
|
||||
def is_visible(widget: Widget) -> bool:
|
||||
"""Return True if the widget is (literally) visible by examining various
|
||||
properties which affect whether it can be seen or not."""
|
||||
return (
|
||||
widget.visible
|
||||
and not widget.is_transparent
|
||||
and widget.styles.opacity > 0
|
||||
)
|
||||
|
||||
if self.map:
|
||||
if crop:
|
||||
overlaps = crop.overlaps
|
||||
mapped_regions = [
|
||||
(widget, region, order, clip)
|
||||
for widget, (region, order, clip, *_) in self.map.items()
|
||||
if widget.visible and not widget.is_transparent and overlaps(crop)
|
||||
if is_visible(widget) and overlaps(crop)
|
||||
]
|
||||
else:
|
||||
mapped_regions = [
|
||||
(widget, region, order, clip)
|
||||
for widget, (region, order, clip, *_) in self.map.items()
|
||||
if widget.visible and not widget.is_transparent
|
||||
if is_visible(widget)
|
||||
]
|
||||
|
||||
widget_regions = sorted(mapped_regions, key=itemgetter(2), reverse=True)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import functools
|
||||
from typing import Iterable
|
||||
|
||||
from rich.cells import cell_len
|
||||
from rich.color import Color
|
||||
from rich.console import ConsoleOptions, Console, RenderResult, RenderableType
|
||||
from rich.segment import Segment
|
||||
@@ -59,6 +60,12 @@ class TextOpacity:
|
||||
|
||||
"""
|
||||
_Segment = Segment
|
||||
_from_color = Style.from_color
|
||||
if opacity == 0:
|
||||
for text, style, control in segments:
|
||||
invisible_style = _from_color(bgcolor=style.bgcolor)
|
||||
yield _Segment(cell_len(text) * " ", invisible_style)
|
||||
else:
|
||||
for segment in segments:
|
||||
text, style, control = segment
|
||||
if not style:
|
||||
|
||||
@@ -19,10 +19,9 @@ def test_simple_text_opacity(text):
|
||||
)
|
||||
|
||||
|
||||
def test_value_zero_sets_foreground_color_to_background_color(text):
|
||||
foreground = background = "0;255;0"
|
||||
def test_value_zero_doesnt_render_the_text(text):
|
||||
assert render(TextOpacity(text, opacity=0)) == (
|
||||
f"\x1b[38;2;{foreground};48;2;{background}mHello, world!{STOP}"
|
||||
f"\x1b[48;2;0;255;0m {STOP}"
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user