mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Fix frame rate limiter (#2318)
* simplify * fix for frame rate limiter * fix update * fix update * update comment * No need for lock * remove comment * fix for glitched test * force update * implement dim fix * docstrings * foreground fix * cached filters * cache default * fix for filter tests * docstring * optimization * Update src/textual/filter.py Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * Update src/textual/constants.py Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com> * fix cache * remove comment [skip ci] --------- Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>
This commit is contained in:
@@ -245,19 +245,15 @@ class ChopsUpdate(CompositorUpdate):
|
||||
append(strip.render(console))
|
||||
continue
|
||||
|
||||
if x < x1:
|
||||
strip = strip.crop(x1 - x, x2 - x)
|
||||
append(move_to(x1, y).segment.text)
|
||||
else:
|
||||
strip = strip.crop(0, x2 - x)
|
||||
append(move_to(x, y).segment.text)
|
||||
|
||||
strip = strip.crop(0, min(end, x2) - x)
|
||||
append(move_to(x, y).segment.text)
|
||||
append(strip.render(console))
|
||||
|
||||
if y != last_y:
|
||||
append("\n")
|
||||
|
||||
return "".join(sequences)
|
||||
terminal_sequences = "".join(sequences)
|
||||
return terminal_sequences
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
yield from ()
|
||||
|
||||
@@ -117,12 +117,8 @@ def dim_style(style: Style, background: Color, factor: float) -> Style:
|
||||
style
|
||||
+ Style.from_color(
|
||||
dim_color(
|
||||
(
|
||||
background.rich_color
|
||||
if style.bgcolor.is_default
|
||||
else (style.bgcolor or DEFAULT_COLOR)
|
||||
),
|
||||
style.color or DEFAULT_COLOR,
|
||||
(background.rich_color if style.bgcolor.is_default else style.bgcolor),
|
||||
style.color,
|
||||
factor,
|
||||
),
|
||||
None,
|
||||
|
||||
@@ -141,6 +141,7 @@ class Pilot(Generic[ReturnType]):
|
||||
delay: Seconds to pause, or None to wait for cpu idle.
|
||||
"""
|
||||
# These sleep zeros, are to force asyncio to give up a time-slice,
|
||||
self.app.screen._on_timer_update() # Force one last repaint
|
||||
if delay is None:
|
||||
await wait_for_idle(0)
|
||||
else:
|
||||
|
||||
@@ -42,8 +42,8 @@ from .widget import Widget
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Final
|
||||
|
||||
# Screen updates will be batched so that they don't happen more often than 120 times per second:
|
||||
UPDATE_PERIOD: Final[float] = 1 / 120
|
||||
# Screen updates will be batched so that they don't happen more often than 60 times per second:
|
||||
UPDATE_PERIOD: Final[float] = 1 / 60
|
||||
|
||||
ScreenResultType = TypeVar("ScreenResultType")
|
||||
"""The result type of a screen."""
|
||||
@@ -437,42 +437,49 @@ class Screen(Generic[ScreenResultType], Widget):
|
||||
event.prevent_default()
|
||||
|
||||
if not self.app._batch_count and self.is_current:
|
||||
async with self.app._dom_lock:
|
||||
if self.is_current:
|
||||
if self._layout_required:
|
||||
self._refresh_layout()
|
||||
self._layout_required = False
|
||||
self._scroll_required = False
|
||||
self._dirty_widgets.clear()
|
||||
elif self._scroll_required:
|
||||
self._refresh_layout(scroll=True)
|
||||
self._scroll_required = False
|
||||
|
||||
if self._repaint_required:
|
||||
self._dirty_widgets.clear()
|
||||
self._dirty_widgets.add(self)
|
||||
self._repaint_required = False
|
||||
|
||||
if self._dirty_widgets:
|
||||
self._update_timer.resume()
|
||||
if (
|
||||
self._layout_required
|
||||
or self._scroll_required
|
||||
or self._repaint_required
|
||||
or self._dirty_widgets
|
||||
):
|
||||
self._update_timer.resume()
|
||||
|
||||
# The Screen is idle - a good opportunity to invoke the scheduled callbacks
|
||||
await self._invoke_and_clear_callbacks()
|
||||
|
||||
if self._callbacks:
|
||||
self._on_timer_update()
|
||||
|
||||
def _on_timer_update(self) -> None:
|
||||
"""Called by the _update_timer."""
|
||||
# Render widgets together
|
||||
if self._dirty_widgets and self.is_current:
|
||||
self._compositor.update_widgets(self._dirty_widgets)
|
||||
update = self._compositor.render_update(
|
||||
screen_stack=self.app._background_screens
|
||||
)
|
||||
self.app._display(self, update)
|
||||
self._dirty_widgets.clear()
|
||||
if self._callbacks:
|
||||
self.post_message(events.InvokeCallbacks())
|
||||
|
||||
self._update_timer.pause()
|
||||
if self.is_current:
|
||||
if self._layout_required:
|
||||
self._refresh_layout()
|
||||
self._layout_required = False
|
||||
self._scroll_required = False
|
||||
self._dirty_widgets.clear()
|
||||
elif self._scroll_required:
|
||||
self._refresh_layout(scroll=True)
|
||||
self._scroll_required = False
|
||||
|
||||
if self._repaint_required:
|
||||
self._update_timer.resume()
|
||||
self._dirty_widgets.clear()
|
||||
self._dirty_widgets.add(self)
|
||||
self._repaint_required = False
|
||||
|
||||
if self._dirty_widgets and self.is_current:
|
||||
self._compositor.update_widgets(self._dirty_widgets)
|
||||
update = self._compositor.render_update(
|
||||
screen_stack=self.app._background_screens
|
||||
)
|
||||
self.app._display(self, update)
|
||||
self._dirty_widgets.clear()
|
||||
|
||||
if self._callbacks:
|
||||
self.post_message(events.InvokeCallbacks())
|
||||
|
||||
async def _on_invoke_callbacks(self, event: events.InvokeCallbacks) -> None:
|
||||
"""Handle PostScreenUpdate events, which are sent after the screen is updated"""
|
||||
|
||||
@@ -282,6 +282,7 @@ class Strip:
|
||||
cached_strip = Strip(
|
||||
filter.apply(self._segments, background), self._cell_length
|
||||
)
|
||||
self._filter_cache[(filter, background)] = cached_strip
|
||||
return cached_strip
|
||||
|
||||
def style_links(self, link_id: str, link_style: Style) -> Strip:
|
||||
@@ -312,7 +313,7 @@ class Strip:
|
||||
]
|
||||
return Strip(segments, self._cell_length)
|
||||
|
||||
def crop(self, start: int, end: int) -> Strip:
|
||||
def crop(self, start: int, end: int | None = None) -> Strip:
|
||||
"""Crop a strip between two cell positions.
|
||||
|
||||
Args:
|
||||
@@ -323,7 +324,7 @@ class Strip:
|
||||
A new Strip.
|
||||
"""
|
||||
start = max(0, start)
|
||||
end = min(self.cell_length, end)
|
||||
end = self.cell_length if end is None else min(self.cell_length, end)
|
||||
if start == 0 and end == self.cell_length:
|
||||
return self
|
||||
cache_key = (start, end)
|
||||
|
||||
Reference in New Issue
Block a user