Skip to content

Commit d8fd360

Browse files
authored
Add canvas.set_update_mode() (#83)
1 parent 059f602 commit d8fd360

File tree

4 files changed

+50
-23
lines changed

4 files changed

+50
-23
lines changed

docs/api.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
API
22
===
33

4-
These are the base classes that make up the rendercanvas API:
4+
These are the classes that make up the rendercanvas API:
55

66
* The :class:`~rendercanvas.BaseRenderCanvas` represents the main API.
77
* The :class:`~rendercanvas.BaseLoop` provides functionality to work with the event-loop in a generic way.
88
* The :class:`~rendercanvas.EventType` enum specifies the types of events for :func:`canvas.add_event_handler() <rendercanvas.BaseRenderCanvas.add_event_handler>`.
9+
* The :class:`~rendercanvas.UpdateMode` enum specifies the scheduler behaviour for :func:`canvas.set_update_mode() <rendercanvas.BaseRenderCanvas.set_update_mode>`.
910
* The :class:`~rendercanvas.CursorShape` enum specifies the cursor shapes for :func:`canvas.set_cursor() <rendercanvas.BaseRenderCanvas.set_cursor>`.
1011

1112
.. autoclass:: rendercanvas.BaseRenderCanvas
@@ -20,6 +21,10 @@ These are the base classes that make up the rendercanvas API:
2021
:members:
2122
:member-order: bysource
2223

24+
.. autoclass:: rendercanvas.UpdateMode
25+
:members:
26+
:member-order: bysource
27+
2328
.. autoclass:: rendercanvas.CursorShape
2429
:members:
2530
:member-order: bysource

rendercanvas/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ._version import __version__, version_info
88
from . import _coreutils
99
from ._events import EventType
10+
from ._scheduler import UpdateMode
1011
from .base import BaseRenderCanvas, BaseLoop, CursorShape
1112

12-
__all__ = ["BaseLoop", "BaseRenderCanvas", "CursorShape", "EventType"]
13+
__all__ = ["BaseLoop", "BaseRenderCanvas", "CursorShape", "EventType", "UpdateMode"]

rendercanvas/_scheduler.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
class UpdateMode(BaseEnum):
13-
"""The different modes to schedule draws for the canvas."""
13+
"""The UpdateMode enum specifies the different modes to schedule draws for the canvas."""
1414

1515
manual = None #: Draw events are never scheduled. Draws only happen when you ``canvas.force_draw()``, and maybe when the GUI system issues them (e.g. when resizing).
1616
ondemand = None #: Draws are only scheduled when ``canvas.request_draw()`` is called when an update is needed. Safes your laptop battery. Honours ``min_fps`` and ``max_fps``.
@@ -48,7 +48,9 @@ class Scheduler:
4848
# Note that any extra draws, e.g. via force_draw() or due to window resizes,
4949
# don't affect the scheduling loop; they are just extra draws.
5050

51-
def __init__(self, canvas, events, *, mode="ondemand", min_fps=1, max_fps=30):
51+
def __init__(
52+
self, canvas, events, *, update_mode="ondemand", min_fps=0, max_fps=30
53+
):
5254
self.name = f"{canvas.__class__.__name__} scheduler"
5355

5456
# We don't keep a ref to the canvas to help gc. This scheduler object can be
@@ -58,13 +60,7 @@ def __init__(self, canvas, events, *, mode="ondemand", min_fps=1, max_fps=30):
5860
# ... = canvas.get_context() -> No, context creation should be lazy!
5961

6062
# Scheduling variables
61-
if mode not in UpdateMode:
62-
raise ValueError(
63-
f"Invalid update_mode '{mode}', must be in {set(UpdateMode)}."
64-
)
65-
self._mode = mode
66-
self._min_fps = float(min_fps)
67-
self._max_fps = float(max_fps)
63+
self.set_update_mode(update_mode, min_fps=min_fps, max_fps=max_fps)
6864
self._draw_requested = True # Start with a draw in ondemand mode
6965
self._async_draw_event = None
7066

@@ -86,6 +82,20 @@ def get_canvas(self):
8682
else:
8783
return canvas
8884

85+
def set_update_mode(self, update_mode, *, min_fps=None, max_fps=None):
86+
update_mode = str(update_mode)
87+
if update_mode not in UpdateMode:
88+
raise ValueError(
89+
f"Invalid update_mode '{update_mode}', must be in {set(UpdateMode)}."
90+
)
91+
self._mode = update_mode
92+
93+
if min_fps is not None:
94+
self._min_fps = max(0.0, float(min_fps))
95+
96+
if max_fps is not None:
97+
self._max_fps = max(1, float(max_fps))
98+
8999
def request_draw(self):
90100
"""Request a new draw to be done. Only affects the 'ondemand' mode."""
91101
# Just set the flag

rendercanvas/base.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
import sys
88
import weakref
99
import importlib
10+
from typing import Optional, Tuple
1011

1112
from ._events import EventEmitter, EventType # noqa: F401
1213
from ._loop import BaseLoop
13-
from ._scheduler import Scheduler
14+
from ._scheduler import Scheduler, UpdateMode
1415
from ._coreutils import logger, log_exception, BaseEnum
1516

1617

@@ -94,9 +95,8 @@ class BaseRenderCanvas:
9495
size (tuple): the logical size (width, height) of the canvas.
9596
title (str): The title of the canvas. Can use '$backend' to show the RenderCanvas class name,
9697
and '$fps' to show the fps.
97-
update_mode (EventType): The mode for scheduling draws and events. Default 'ondemand'.
98-
min_fps (float): A minimal frames-per-second to use when the ``update_mode`` is 'ondemand'.
99-
The default is 1: even without draws requested, it still draws every second.
98+
update_mode (UpdateMode): The mode for scheduling draws and events. Default 'ondemand'.
99+
min_fps (float): A minimal frames-per-second to use when the ``update_mode`` is 'ondemand'. The default is 0:
100100
max_fps (float): A maximal frames-per-second to use when the ``update_mode`` is 'ondemand'
101101
or 'continuous'. The default is 30, which is usually enough.
102102
vsync (bool): Whether to sync the draw with the monitor update. Helps
@@ -126,13 +126,13 @@ def select_loop(cls, loop):
126126
def __init__(
127127
self,
128128
*args,
129-
size=(640, 480),
130-
title="$backend",
131-
update_mode="ondemand",
132-
min_fps=1.0,
133-
max_fps=30.0,
134-
vsync=True,
135-
present_method=None,
129+
size: Tuple[int] = (640, 480),
130+
title: str = "$backend",
131+
update_mode: UpdateMode = "ondemand",
132+
min_fps: float = 0.0,
133+
max_fps: float = 30.0,
134+
vsync: bool = True,
135+
present_method: Optional[str] = None,
136136
**kwargs,
137137
):
138138
# Initialize superclass. Note that super() can be e.g. a QWidget, RemoteFrameBuffer, or object.
@@ -170,7 +170,7 @@ def __init__(
170170
self._events,
171171
min_fps=min_fps,
172172
max_fps=max_fps,
173-
mode=update_mode,
173+
update_mode=update_mode,
174174
)
175175
self._rc_canvas_group._register_canvas(self, self.__scheduler.get_task())
176176

@@ -354,6 +354,17 @@ def _draw_frame(self):
354354
"""
355355
pass
356356

357+
def set_update_mode(self, update_mode, *, min_fps=None, max_fps=None):
358+
"""Set the update mode for scheduling draws.
359+
360+
Arguments:
361+
update_mode (UpdateMode): The mode for scheduling draws and events.
362+
min_fps (float): The minimum fps with update mode 'ondemand'.
363+
max_fps (float): The maximum fps with update mode 'ondemand' and 'continuous'.
364+
365+
"""
366+
self.__scheduler.set_update_mode(update_mode, min_fps=min_fps, max_fps=max_fps)
367+
357368
def request_draw(self, draw_function=None):
358369
"""Schedule a new draw event.
359370

0 commit comments

Comments
 (0)