Skip to content

Commit

Permalink
Add event pubsub for glfw and jupyter canvas (#224)
Browse files Browse the repository at this point in the history
* add event pubsub for glfw and jupyter canvas

* support multiple type registration and decorator style

* reverse decorating flag so variable names make more sense

* Allow docs to be built on Windows, and add docstrings for add_event_handler and remove_event_handler

* correct typo
  • Loading branch information
Korijn authored Dec 22, 2021
1 parent 451a7bd commit bac3f94
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
with open(os.path.join(ROOT_DIR, "docs", "reference_wgpu.rst"), "rb") as f:
wgpu_api_docs_text = f.read().decode()
for cls_name in wgpu.base.__all__:
expected_line = f".. autoclass:: wgpu.{cls_name}\n"
expected_line = f".. autoclass:: wgpu.{cls_name}"
assert expected_line in wgpu_api_docs_text, f"Missing docs for {cls_name}"

# Make flags and enum appear better in docs
Expand Down
59 changes: 58 additions & 1 deletion wgpu/gui/glfw.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
or ``sudo apt install libglfw3-wayland`` when using Wayland.
"""

from collections import defaultdict
import os
import sys
import time
Expand Down Expand Up @@ -138,6 +139,7 @@ def __init__(self, *, size=None, title=None, **kwargs):
self._need_draw = False
self._request_draw_timer_running = False
self._changing_pixel_ratio = False
self._event_handlers = defaultdict(set)

# Register ourselves
all_glfw_canvases.add(self)
Expand Down Expand Up @@ -308,7 +310,62 @@ def handle_event(self, event):
is a dict with at least the key event_type. For details, see
https://jupyter-rfb.readthedocs.io/en/latest/events.html
"""
pass
event_type = event.get("event_type")
for callback in self._event_handlers[event_type]:
callback(event)

def add_event_handler(self, *args):
"""Register an event handler.
Arguments:
callback (callable): The event handler. Must accept a
single event argument.
*types (list of strings): A list of event types.
For the available events, see
https://jupyter-rfb.readthedocs.io/en/latest/events.html
Can also be used as a decorator.
Example:
.. code-block:: py
def my_handler(event):
print(event)
canvas.add_event_handler(my_handler, "pointer_up", "pointer_down")
Decorator usage example:
.. code-block:: py
@canvas.add_event_handler("pointer_up", "pointer_down")
def my_handler(event):
print(event)
"""
decorating = not callable(args[0])
callback = None if decorating else args[0]
types = args if decorating else args[1:]

def decorator(_callback):
for type in types:
self._event_handlers[type].add(_callback)
return _callback

if decorating:
return decorator
return decorator(callback)

def remove_event_handler(self, callback, *types):
"""Unregister an event handler.
Arguments:
callback (callable): The event handler.
*types (list of strings): A list of event types.
"""
for type in types:
self._event_handlers[type].remove(callback)

# User events

Expand Down
60 changes: 59 additions & 1 deletion wgpu/gui/jupyter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
can be used as cell output, or embedded in a ipywidgets gui.
"""

from collections import defaultdict
import weakref
import asyncio

Expand All @@ -27,6 +28,7 @@ def __init__(self, *, size=None, title=None, **kwargs):
self._logical_size = 0, 0
self._is_closed = False
self._request_draw_timer_running = False
self._event_handlers = defaultdict(set)

# Register so this can be display'ed when run() is called
pending_jupyter_canvases.append(weakref.ref(self))
Expand All @@ -38,13 +40,69 @@ def __init__(self, *, size=None, title=None, **kwargs):
# Implementation needed for RemoteFrameBuffer

def handle_event(self, event):
event_type = event.get("event_type", "")
event_type = event.get("event_type")
if event_type == "close":
self._is_closed = True
elif event_type == "resize":
self._pixel_ratio = event["pixel_ratio"]
self._logical_size = event["width"], event["height"]

for callback in self._event_handlers[event_type]:
callback(event)

def add_event_handler(self, *args):
"""Register an event handler.
Arguments:
callback (callable): The event handler. Must accept a
single event argument.
*types (list of strings): A list of event types.
For the available events, see
https://jupyter-rfb.readthedocs.io/en/latest/events.html
Can also be used as a decorator.
Example:
.. code-block:: py
def my_handler(event):
print(event)
canvas.add_event_handler(my_handler, "pointer_up", "pointer_down")
Decorator usage example:
.. code-block:: py
@canvas.add_event_handler("pointer_up", "pointer_down")
def my_handler(event):
print(event)
"""
decorating = not callable(args[0])
callback = None if decorating else args[0]
types = args if decorating else args[1:]

def decorator(_callback):
for type in types:
self._event_handlers[type].add(_callback)
return _callback

if decorating:
return decorator
return decorator(callback)

def remove_event_handler(self, callback, *types):
"""Unregister an event handler.
Arguments:
callback (callable): The event handler.
*types (list of strings): A list of event types.
"""
for type in types:
self._event_handlers[type].remove(callback)

def get_frame(self):
self._request_draw_timer_running = False
# The _draw_frame_and_present() does the drawing and then calls
Expand Down

0 comments on commit bac3f94

Please sign in to comment.