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

refactor: use rendercanvas instead of wgpu.gui #140

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion src/ndv/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def nd_sine_wave(
# Assign to the output array
output[angle_idx, freq_idx, phase_idx] = sine_wave

return output
return output.astype(np.float32)


def cells3d() -> np.ndarray:
Expand Down
32 changes: 4 additions & 28 deletions src/ndv/views/_pygfx/_array_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from ndv.views.bases import ArrayCanvas, CanvasElement, ImageHandle
from ndv.views.bases._graphics._canvas_elements import RectangularROIHandle, ROIMoveMode

from ._util import rendercanvas_class

if TYPE_CHECKING:
from collections.abc import Sequence
from typing import TypeAlias
Expand Down Expand Up @@ -347,32 +349,6 @@ def remove(self) -> None:
par.remove(self._container)


def get_canvas_class() -> WgpuCanvas:
from ndv.views._app import GuiFrontend, gui_frontend

frontend = gui_frontend()
if frontend == GuiFrontend.QT:
from qtpy.QtCore import QSize
from wgpu.gui import qt

class QWgpuCanvas(qt.QWgpuCanvas):
def installEventFilter(self, filter: Any) -> None:
self._subwidget.installEventFilter(filter)

def sizeHint(self) -> QSize:
return QSize(self.width(), self.height())

return QWgpuCanvas
if frontend == GuiFrontend.JUPYTER:
from wgpu.gui.jupyter import JupyterWgpuCanvas

return JupyterWgpuCanvas
if frontend == GuiFrontend.WX:
from wgpu.gui.wx import WxWgpuCanvas

return WxWgpuCanvas


class GfxArrayCanvas(ArrayCanvas):
"""pygfx-based canvas wrapper."""

Expand All @@ -382,14 +358,14 @@ def __init__(self, viewer_model: ArrayViewerModel) -> None:
self._current_shape: tuple[int, ...] = ()
self._last_state: dict[Literal[2, 3], Any] = {}

cls = get_canvas_class()
cls = rendercanvas_class()
self._canvas = cls(size=(600, 600))

# this filter needs to remain in scope for the lifetime of the canvas
# or mouse events will not be intercepted
# the returned function can be called to remove the filter, (and it also
# closes on the event filter and keeps it in scope).
self._disconnect_mouse_events = filter_mouse_events(self._canvas, self)

self._renderer = pygfx.renderers.WgpuRenderer(self._canvas)
try:
# requires https://github.com/pygfx/pygfx/pull/752
Expand Down
32 changes: 3 additions & 29 deletions src/ndv/views/_pygfx/_histogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from ndv.views._app import filter_mouse_events
from ndv.views.bases import HistogramCanvas

from ._util import rendercanvas_class

if TYPE_CHECKING:
from collections.abc import Sequence
from typing import TypeAlias
Expand All @@ -33,34 +35,6 @@ class Grabbable(Enum):
GAMMA = auto()


def get_canvas_class() -> WgpuCanvas:
from ndv.views._app import GuiFrontend, gui_frontend

frontend = gui_frontend()
if frontend == GuiFrontend.QT:
from qtpy.QtCore import QSize
from wgpu.gui import qt

class QWgpuCanvas(qt.QWgpuCanvas):
def installEventFilter(self, filter: Any) -> None:
self._subwidget.installEventFilter(filter)

def sizeHint(self) -> QSize:
return QSize(self.width(), self.height())

return QWgpuCanvas
if frontend == GuiFrontend.JUPYTER:
from wgpu.gui.jupyter import JupyterWgpuCanvas

return JupyterWgpuCanvas
if frontend == GuiFrontend.WX:
from wgpu.gui.wx import WxWgpuCanvas

return WxWgpuCanvas

raise Exception(f"No canvas available for frontend {frontend}")


class PyGFXHistogramCanvas(HistogramCanvas):
"""A HistogramCanvas utilizing VisPy."""

Expand Down Expand Up @@ -90,7 +64,7 @@ def __init__(self, *, vertical: bool = False) -> None:
self.margin_top = 15

# ------------ PyGFX Canvas ------------ #
cls = get_canvas_class()
cls = rendercanvas_class()
self._size = (600, 600)
self._canvas = cls(size=self._size)

Expand Down
31 changes: 31 additions & 0 deletions src/ndv/views/_pygfx/_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from rendercanvas import BaseRenderCanvas


def rendercanvas_class() -> "BaseRenderCanvas":
from ndv.views._app import GuiFrontend, gui_frontend

frontend = gui_frontend()
if frontend == GuiFrontend.QT:
import rendercanvas.qt
from qtpy.QtCore import QSize

class QRenderWidget(rendercanvas.qt.QRenderWidget):
def sizeHint(self) -> QSize:
return QSize(self.width(), self.height())

return QRenderWidget

if frontend == GuiFrontend.JUPYTER:
import rendercanvas.jupyter

return rendercanvas.jupyter.JupyterRenderCanvas
if frontend == GuiFrontend.WX:
# ...still not working
# import rendercanvas.wx
# return rendercanvas.wx.WxRenderWidget
from wgpu.gui.wx import WxWgpuCanvas

return WxWgpuCanvas
5 changes: 4 additions & 1 deletion src/ndv/views/_wx/_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@
from ndv.views.bases._app import P, T
from ndv.views.bases._graphics._mouseable import Mouseable

_app = None


class WxAppWrap(NDVApp):
"""Provider for wxPython."""

IPY_MAGIC_KEY = "wx"

def create_app(self) -> Any:
global _app
if (wxapp := wx.App.Get()) is None:
wxapp = wx.App()
_app = wxapp = wx.App()

self._maybe_enable_ipython_gui()
self._install_excepthook()
Expand Down
Loading