Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement window refresh lock #2438

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/2438.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Windows now have a refresh lock to stop refreshing window layout happening after every add()
3 changes: 3 additions & 0 deletions core/src/toga/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ def enabled(self, value: bool) -> None:
self._impl.set_enabled(bool(value))

def refresh(self) -> None:
if self.window is not None and self.window.locked:
return

self._impl.refresh()

# Refresh the layout
Expand Down
26 changes: 26 additions & 0 deletions core/src/toga/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
from toga.screens import Screen
from toga.widgets.base import Widget

from contextlib import contextmanager


class FilteredWidgetRegistry:
# A class that exposes a mapping lookup interface, filtered to widgets from a single
Expand Down Expand Up @@ -174,6 +176,7 @@ def __init__(
self._content = None
self._is_full_screen = False
self._closed = False
self._locked = False

self._resizable = resizable
self._closable = closable
Expand Down Expand Up @@ -346,6 +349,29 @@ def size(self, size: tuple[int, int]) -> None:
if self.content:
self.content.refresh()

@property
def locked(self) -> bool:
"""Is the window locked from refreshes?"""
return self._locked

@locked.setter
def locked(self, locked: bool) -> None:
"""Lock or unlock window refresh.
When window is unlocked, refresh the content
"""
self._locked = locked
if not locked:
self.content.refresh()

@contextmanager
def refresh_lock(self, *args, **kwargs):
"""Obtain a refresh lock on the window. Unlocks
automatically when context manager leaves scope.
"""
self.locked = True
yield
self.locked = False

######################################################################
# Window position
######################################################################
Expand Down
36 changes: 36 additions & 0 deletions core/tests/test_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,42 @@ def test_change_content(window, app):
assert content1.window is None


def test_change_content_locked(window, app):
"""The refresh of a window can be locked"""
with window.refresh_lock():
assert window.content is None
assert window.app == app

# Set the content of the window
content1 = toga.Box()
window.content = content1

# The content has been assigned and not (yet) refreshed
assert content1.app == app
assert content1.window == window
assert_action_performed_with(window, "set content", widget=content1._impl)
assert_action_not_performed(content1, "refresh")

# Set the content of the window to something new
content2 = toga.Box()
window.content = content2

# The content has been assigned and not (yet) refreshed
assert content2.app == app
assert content2.window == window
assert_action_performed_with(window, "set content", widget=content2._impl)
assert_action_not_performed(content2, "refresh")

# The original content has been removed
assert content1.window is None

# Action refresh must not have been performed on content1
assert_action_not_performed(content1, "refresh")

# Action refresh must have been performed on content2
assert_action_performed(content2, "refresh")


def test_set_position(window):
"""The position of the window can be set."""
window.position = (123, 456)
Expand Down
Loading