rendercanvas 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. rendercanvas-1.0.0/LICENSE +25 -0
  2. rendercanvas-1.0.0/PKG-INFO +160 -0
  3. rendercanvas-1.0.0/README.md +122 -0
  4. rendercanvas-1.0.0/pyproject.toml +61 -0
  5. rendercanvas-1.0.0/rendercanvas/__init__.py +17 -0
  6. rendercanvas-1.0.0/rendercanvas/__pyinstaller/__init__.py +12 -0
  7. rendercanvas-1.0.0/rendercanvas/__pyinstaller/conftest.py +1 -0
  8. rendercanvas-1.0.0/rendercanvas/__pyinstaller/hook-rendercanvas.py +22 -0
  9. rendercanvas-1.0.0/rendercanvas/__pyinstaller/test_rendercanvas.py +47 -0
  10. rendercanvas-1.0.0/rendercanvas/_context.py +78 -0
  11. rendercanvas-1.0.0/rendercanvas/_coreutils.py +264 -0
  12. rendercanvas-1.0.0/rendercanvas/_events.py +218 -0
  13. rendercanvas-1.0.0/rendercanvas/_loop.py +456 -0
  14. rendercanvas-1.0.0/rendercanvas/_version.py +113 -0
  15. rendercanvas-1.0.0/rendercanvas/asyncio.py +76 -0
  16. rendercanvas-1.0.0/rendercanvas/auto.py +206 -0
  17. rendercanvas-1.0.0/rendercanvas/base.py +568 -0
  18. rendercanvas-1.0.0/rendercanvas/glfw.py +570 -0
  19. rendercanvas-1.0.0/rendercanvas/jupyter.py +150 -0
  20. rendercanvas-1.0.0/rendercanvas/offscreen.py +135 -0
  21. rendercanvas-1.0.0/rendercanvas/pyqt5.py +11 -0
  22. rendercanvas-1.0.0/rendercanvas/pyqt6.py +11 -0
  23. rendercanvas-1.0.0/rendercanvas/pyside2.py +11 -0
  24. rendercanvas-1.0.0/rendercanvas/pyside6.py +11 -0
  25. rendercanvas-1.0.0/rendercanvas/qt.py +588 -0
  26. rendercanvas-1.0.0/rendercanvas/stub.py +120 -0
  27. rendercanvas-1.0.0/rendercanvas/utils/__init__.py +0 -0
  28. rendercanvas-1.0.0/rendercanvas/utils/bitmappresentadapter.py +344 -0
  29. rendercanvas-1.0.0/rendercanvas/utils/bitmaprenderingcontext.py +101 -0
  30. rendercanvas-1.0.0/rendercanvas/utils/cube.py +446 -0
  31. rendercanvas-1.0.0/rendercanvas/wx.py +522 -0
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2019-2024, Almar Klein, Korijn van Golen
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.1
2
+ Name: rendercanvas
3
+ Version: 1.0.0
4
+ Summary: One canvas API, multiple backends
5
+ Keywords: canvas,rendering,graphics,wgpu,qt,wx,glfw,jupyter
6
+ Author: Almar Klein, Korijn van Golen
7
+ Requires-Python: >= 3.9
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: rendercanvas[lint,tests,examples,docs] ; extra == "dev"
10
+ Requires-Dist: sphinx>7.2 ; extra == "docs"
11
+ Requires-Dist: sphinx_rtd_theme ; extra == "docs"
12
+ Requires-Dist: sphinx-gallery ; extra == "docs"
13
+ Requires-Dist: numpy ; extra == "docs"
14
+ Requires-Dist: wgpu ; extra == "docs"
15
+ Requires-Dist: numpy ; extra == "examples"
16
+ Requires-Dist: wgpu ; extra == "examples"
17
+ Requires-Dist: glfw ; extra == "examples"
18
+ Requires-Dist: pyside6 ; extra == "examples"
19
+ Requires-Dist: glfw>=1.9 ; extra == "glfw"
20
+ Requires-Dist: jupyter_rfb>=0.4.2 ; extra == "jupyter"
21
+ Requires-Dist: ruff ; extra == "lint"
22
+ Requires-Dist: pre-commit ; extra == "lint"
23
+ Requires-Dist: pytest ; extra == "tests"
24
+ Requires-Dist: numpy ; extra == "tests"
25
+ Requires-Dist: wgpu ; extra == "tests"
26
+ Requires-Dist: glfw ; extra == "tests"
27
+ Project-URL: Documentation, https://rendercanvas.readthedocs.io
28
+ Project-URL: Homepage, https://github.com/pygfx/rendercanvas
29
+ Project-URL: Repository, https://github.com/pygfx/rendercanvas
30
+ Provides-Extra: dev
31
+ Provides-Extra: docs
32
+ Provides-Extra: examples
33
+ Provides-Extra: glfw
34
+ Provides-Extra: jupyter
35
+ Provides-Extra: lint
36
+ Provides-Extra: tests
37
+
38
+ [![CI](https://github.com/pygfx/rendercanvas/workflows/CI/badge.svg)](https://github.com/pygfx/rendercanvas/actions)
39
+ [![Documentation Status](https://readthedocs.org/projects/rendercanvas/badge/?version=stable)](https://rendercanvas.readthedocs.io)
40
+ [![PyPI version](https://badge.fury.io/py/rendercanvas.svg)](https://badge.fury.io/py/rendercanvas)
41
+ [![EffVer Versioning](https://img.shields.io/badge/version_scheme-EffVer-0097a7)](https://jacobtomlinson.dev/effver)
42
+
43
+
44
+ # rendercanvas
45
+
46
+ One canvas API, multiple backends 🚀
47
+
48
+ <div>
49
+ <img width=354 src='https://github.com/user-attachments/assets/42656d13-0d81-47dd-b9c7-d76da8cfa6c1' />
50
+ <img width=354 src='https://github.com/user-attachments/assets/af8eefe0-4485-4daf-9fbd-36710e44f07c' />
51
+ </div>
52
+
53
+ *This project is part of [pygfx.org](https://pygfx.org)*
54
+
55
+
56
+ ## Introduction
57
+
58
+ See how the two windows above look the same? That's the idea; they also look the
59
+ same to the code that renders to them. Yet, the GUI systems are very different
60
+ (Qt vs glfw in this case). Now that's a powerful abstraction!
61
+
62
+
63
+ ## Purpose
64
+
65
+ * Provide a generic canvas API to render to.
66
+ * Provide an event loop for scheduling events and draws.
67
+ * Provide a simple but powerful event system with standardized event objects.
68
+ * Provide various canvas implementations:
69
+ * One that is light and easily installed (glfw).
70
+ * For various GUI libraries (e.g. qt and wx), so visuzalizations can be embedded in a GUI.
71
+ * For specific platforms (e.g. Jupyter, browser).
72
+
73
+
74
+ The main use-case is rendering with [wgpu](https://github.com/pygfx/wgpu-py),
75
+ but ``rendercanvas``can be used by anything that can render based on a window-id or
76
+ by producing bitmap images.
77
+
78
+
79
+ ## Installation
80
+
81
+ ```
82
+ pip install rendercanvas
83
+ ```
84
+
85
+ To have at least one backend, we recommend:
86
+ ```
87
+ pip install rendercanvas glfw
88
+ ```
89
+
90
+ ## Usage
91
+
92
+ Also see the [online documentation](https://rendercanvas.readthedocs.io) and the [examples](https://github.com/pygfx/rendercanvas/tree/main/examples).
93
+
94
+ A minimal example that renders noise:
95
+ ```py
96
+ import numpy as np
97
+ from rendercanvas.auto import RenderCanvas, loop
98
+
99
+ canvas = RenderCanvas(update_mode="continuous")
100
+ context = canvas.get_context("bitmap")
101
+
102
+ @canvas.request_draw
103
+ def animate():
104
+ w, h = canvas.get_logical_size()
105
+ bitmap = np.random.uniform(0, 255, (h, w)).astype(np.uint8)
106
+ context.set_bitmap(bitmap)
107
+
108
+ loop.run()
109
+ ```
110
+
111
+ Run wgpu visualizations:
112
+ ```py
113
+ from rendercanvas.auto import RenderCanvas, loop
114
+ from rendercanvas.utils.cube import setup_drawing_sync
115
+
116
+
117
+ canvas = RenderCanvas(
118
+ title="The wgpu cube example on $backend", update_mode="continuous"
119
+ )
120
+ draw_frame = setup_drawing_sync(canvas)
121
+ canvas.request_draw(draw_frame)
122
+
123
+ loop.run()
124
+ ````
125
+
126
+ Embed in a Qt application:
127
+ ```py
128
+ from PySide6 import QtWidgets
129
+ from rendercanvas.qt import QRenderWidget
130
+
131
+ class Main(QtWidgets.QWidget):
132
+
133
+ def __init__(self):
134
+ super().__init__()
135
+
136
+ splitter = QtWidgets.QSplitter()
137
+ self.canvas = QRenderWidget(splitter)
138
+ ...
139
+
140
+
141
+ app = QtWidgets.QApplication([])
142
+ main = Main()
143
+ app.exec()
144
+ ```
145
+
146
+
147
+ ## License
148
+
149
+ This code is distributed under the 2-clause BSD license.
150
+
151
+
152
+ ## Developers
153
+
154
+ * Clone the repo.
155
+ * Install `rendercanvas` and developer deps using `pip install -e .[dev]`.
156
+ * Use `ruff format` to apply autoformatting.
157
+ * Use `ruff check` to check for linting errors.
158
+ * Optionally, if you install [pre-commit](https://github.com/pre-commit/pre-commit/) hooks with `pre-commit install`, lint fixes and formatting will be automatically applied on `git commit`.
159
+ * Use `pytest tests` to run the tests.
160
+
@@ -0,0 +1,122 @@
1
+ [![CI](https://github.com/pygfx/rendercanvas/workflows/CI/badge.svg)](https://github.com/pygfx/rendercanvas/actions)
2
+ [![Documentation Status](https://readthedocs.org/projects/rendercanvas/badge/?version=stable)](https://rendercanvas.readthedocs.io)
3
+ [![PyPI version](https://badge.fury.io/py/rendercanvas.svg)](https://badge.fury.io/py/rendercanvas)
4
+ [![EffVer Versioning](https://img.shields.io/badge/version_scheme-EffVer-0097a7)](https://jacobtomlinson.dev/effver)
5
+
6
+
7
+ # rendercanvas
8
+
9
+ One canvas API, multiple backends 🚀
10
+
11
+ <div>
12
+ <img width=354 src='https://github.com/user-attachments/assets/42656d13-0d81-47dd-b9c7-d76da8cfa6c1' />
13
+ <img width=354 src='https://github.com/user-attachments/assets/af8eefe0-4485-4daf-9fbd-36710e44f07c' />
14
+ </div>
15
+
16
+ *This project is part of [pygfx.org](https://pygfx.org)*
17
+
18
+
19
+ ## Introduction
20
+
21
+ See how the two windows above look the same? That's the idea; they also look the
22
+ same to the code that renders to them. Yet, the GUI systems are very different
23
+ (Qt vs glfw in this case). Now that's a powerful abstraction!
24
+
25
+
26
+ ## Purpose
27
+
28
+ * Provide a generic canvas API to render to.
29
+ * Provide an event loop for scheduling events and draws.
30
+ * Provide a simple but powerful event system with standardized event objects.
31
+ * Provide various canvas implementations:
32
+ * One that is light and easily installed (glfw).
33
+ * For various GUI libraries (e.g. qt and wx), so visuzalizations can be embedded in a GUI.
34
+ * For specific platforms (e.g. Jupyter, browser).
35
+
36
+
37
+ The main use-case is rendering with [wgpu](https://github.com/pygfx/wgpu-py),
38
+ but ``rendercanvas``can be used by anything that can render based on a window-id or
39
+ by producing bitmap images.
40
+
41
+
42
+ ## Installation
43
+
44
+ ```
45
+ pip install rendercanvas
46
+ ```
47
+
48
+ To have at least one backend, we recommend:
49
+ ```
50
+ pip install rendercanvas glfw
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ Also see the [online documentation](https://rendercanvas.readthedocs.io) and the [examples](https://github.com/pygfx/rendercanvas/tree/main/examples).
56
+
57
+ A minimal example that renders noise:
58
+ ```py
59
+ import numpy as np
60
+ from rendercanvas.auto import RenderCanvas, loop
61
+
62
+ canvas = RenderCanvas(update_mode="continuous")
63
+ context = canvas.get_context("bitmap")
64
+
65
+ @canvas.request_draw
66
+ def animate():
67
+ w, h = canvas.get_logical_size()
68
+ bitmap = np.random.uniform(0, 255, (h, w)).astype(np.uint8)
69
+ context.set_bitmap(bitmap)
70
+
71
+ loop.run()
72
+ ```
73
+
74
+ Run wgpu visualizations:
75
+ ```py
76
+ from rendercanvas.auto import RenderCanvas, loop
77
+ from rendercanvas.utils.cube import setup_drawing_sync
78
+
79
+
80
+ canvas = RenderCanvas(
81
+ title="The wgpu cube example on $backend", update_mode="continuous"
82
+ )
83
+ draw_frame = setup_drawing_sync(canvas)
84
+ canvas.request_draw(draw_frame)
85
+
86
+ loop.run()
87
+ ````
88
+
89
+ Embed in a Qt application:
90
+ ```py
91
+ from PySide6 import QtWidgets
92
+ from rendercanvas.qt import QRenderWidget
93
+
94
+ class Main(QtWidgets.QWidget):
95
+
96
+ def __init__(self):
97
+ super().__init__()
98
+
99
+ splitter = QtWidgets.QSplitter()
100
+ self.canvas = QRenderWidget(splitter)
101
+ ...
102
+
103
+
104
+ app = QtWidgets.QApplication([])
105
+ main = Main()
106
+ app.exec()
107
+ ```
108
+
109
+
110
+ ## License
111
+
112
+ This code is distributed under the 2-clause BSD license.
113
+
114
+
115
+ ## Developers
116
+
117
+ * Clone the repo.
118
+ * Install `rendercanvas` and developer deps using `pip install -e .[dev]`.
119
+ * Use `ruff format` to apply autoformatting.
120
+ * Use `ruff check` to check for linting errors.
121
+ * Optionally, if you install [pre-commit](https://github.com/pre-commit/pre-commit/) hooks with `pre-commit install`, lint fixes and formatting will be automatically applied on `git commit`.
122
+ * Use `pytest tests` to run the tests.
@@ -0,0 +1,61 @@
1
+ # ===== Project info
2
+
3
+ [project]
4
+ dynamic = ["version"]
5
+ name = "rendercanvas"
6
+ description = "One canvas API, multiple backends"
7
+ readme = "README.md"
8
+ license = { file = "LICENSE" }
9
+ authors = [{ name = "Almar Klein" }, { name = "Korijn van Golen" }]
10
+ keywords = [
11
+ "canvas",
12
+ "rendering",
13
+ "graphics",
14
+ "wgpu",
15
+ "qt",
16
+ "wx",
17
+ "glfw",
18
+ "jupyter",
19
+ ]
20
+ requires-python = ">= 3.9"
21
+ dependencies = [] # no dependencies!
22
+ [project.optional-dependencies]
23
+ # For users
24
+ jupyter = ["jupyter_rfb>=0.4.2"]
25
+ glfw = ["glfw>=1.9"]
26
+ # For devs / ci
27
+ lint = ["ruff", "pre-commit"]
28
+ examples = ["numpy", "wgpu", "glfw", "pyside6"]
29
+ docs = ["sphinx>7.2", "sphinx_rtd_theme", "sphinx-gallery", "numpy", "wgpu"]
30
+ tests = ["pytest", "numpy", "wgpu", "glfw"]
31
+ dev = ["rendercanvas[lint,tests,examples,docs]"]
32
+
33
+ [project.entry-points."pyinstaller40"]
34
+ hook-dirs = "rendercanvas.__pyinstaller:get_hook_dirs"
35
+ tests = "rendercanvas.__pyinstaller:get_test_dirs"
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/pygfx/rendercanvas"
39
+ Documentation = "https://rendercanvas.readthedocs.io"
40
+ Repository = "https://github.com/pygfx/rendercanvas"
41
+
42
+ # ===== Building
43
+
44
+ # Flit is great solution for simple pure-Python projects.
45
+ [build-system]
46
+ requires = ["flit_core >=3.2,<4"]
47
+ build-backend = "flit_core.buildapi"
48
+
49
+ # ===== Tooling
50
+
51
+ [tool.ruff]
52
+ line-length = 88
53
+
54
+ [tool.ruff.lint]
55
+ select = ["F", "E", "W", "N", "B", "RUF"]
56
+ ignore = [
57
+ "E501", # Line too long
58
+ "E731", # Do not assign a `lambda` expression, use a `def`
59
+ "B007", # Loop control variable `x` not used within loop body
60
+ "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
61
+ ]
@@ -0,0 +1,17 @@
1
+ """
2
+ RenderCanvas: one canvas API, multiple backends.
3
+ """
4
+
5
+ # ruff: noqa: F401
6
+
7
+ from ._version import __version__, version_info
8
+ from . import _coreutils
9
+ from ._events import EventType
10
+ from .base import BaseRenderCanvas, BaseLoop, BaseTimer
11
+
12
+ __all__ = [
13
+ "BaseRenderCanvas",
14
+ "EventType",
15
+ "BaseLoop",
16
+ "BaseTimer",
17
+ ]
@@ -0,0 +1,12 @@
1
+ from os.path import dirname
2
+
3
+
4
+ HERE = dirname(__file__)
5
+
6
+
7
+ def get_hook_dirs():
8
+ return [HERE]
9
+
10
+
11
+ def get_test_dirs():
12
+ return [HERE]
@@ -0,0 +1 @@
1
+ from PyInstaller.utils.conftest import * # noqa: F403
@@ -0,0 +1,22 @@
1
+ # ruff: noqa: N999
2
+
3
+ from PyInstaller.utils.hooks import collect_dynamic_libs
4
+
5
+ # Init variables that PyInstaller will pick up.
6
+ hiddenimports = []
7
+ datas = []
8
+ binaries = []
9
+
10
+ # Add modules that are safe to add, i.e. don't pull in dependencies that we don't want.
11
+ hiddenimports += ["rendercanvas.offscreen"]
12
+
13
+ # Since glfw does not have a hook like this, it does not include the glfw binary
14
+ # when freezing. We can solve this with the code below. Makes the binary a bit
15
+ # larger, but only marginally (less than 300kb).
16
+ try:
17
+ import glfw # noqa: F401
18
+ except ImportError:
19
+ pass
20
+ else:
21
+ hiddenimports += ["rendercanvas.glfw"]
22
+ binaries += collect_dynamic_libs("glfw")
@@ -0,0 +1,47 @@
1
+ script = """
2
+ # The script part
3
+ import sys
4
+ import importlib
5
+
6
+ from rendercanvas.auto import RenderCanvas
7
+
8
+ if "glfw" not in RenderCanvas.__name__.lower():
9
+ raise RuntimeError(f"Expected a glfw canvas, got {RenderCanvas.__name__}")
10
+
11
+ # The test part
12
+ if "is_test" in sys.argv:
13
+ included_modules = [
14
+ "rendercanvas.glfw",
15
+ "rendercanvas.offscreen",
16
+ "glfw",
17
+ ]
18
+ excluded_modules = [
19
+ "PySide6.QtGui",
20
+ "PyQt6.QtGui",
21
+ ]
22
+ for module_name in included_modules:
23
+ importlib.import_module(module_name)
24
+ for module_name in excluded_modules:
25
+ try:
26
+ importlib.import_module(module_name)
27
+ except ModuleNotFoundError:
28
+ continue
29
+ raise RuntimeError(module_name + " is not supposed to be importable.")
30
+ """
31
+
32
+
33
+ def test_pyi_rendercanvas(pyi_builder):
34
+ pyi_builder.test_source(script, app_args=["is_test"])
35
+
36
+
37
+ # We could also test the script below, but it's not that interesting since it uses direct imports.
38
+ # To safe CI-time we don't actively test it.
39
+ script_qt = """
40
+ import sys
41
+ import importlib
42
+
43
+ import PySide6
44
+ from rendercanvas.qt import RenderCanvas
45
+
46
+ assert "qt" in RenderCanvas.__name__.lower()
47
+ """
@@ -0,0 +1,78 @@
1
+ """
2
+ A stub context implementation for documentation purposes.
3
+ It does actually work, but presents nothing.
4
+ """
5
+
6
+ import weakref
7
+
8
+
9
+ def rendercanvas_context_hook(canvas, present_methods):
10
+ """Hook function to allow ``rendercanvas`` to detect your context implementation.
11
+
12
+ If you make a function with this name available in the module ``your.module``,
13
+ ``rendercanvas`` will detect and call this function in order to obtain the canvas object.
14
+ That way, anyone can use ``canvas.get_context("your.module")`` to use your context.
15
+ The arguments are the same as for ``ContextInterface``.
16
+ """
17
+ return ContextInterface(canvas, present_methods)
18
+
19
+
20
+ class ContextInterface:
21
+ """The interface that a context must implement, to be usable with a ``RenderCanvas``.
22
+
23
+ Arguments:
24
+ canvas (BaseRenderCanvas): the canvas to render to.
25
+ present_methods (dict): The supported present methods of the canvas.
26
+
27
+ The ``present_methods`` dict has a field for each supported present-method. A
28
+ canvas must support either "screen" or "bitmap". It may support both, as well as
29
+ additional (specialized) present methods. Below we list the common methods and
30
+ what fields the subdicts have.
31
+
32
+ * Render method "screen":
33
+ * "window": the native window id.
34
+ * "display": the native display id (Linux only).
35
+ * "platform": to determine between "x11" and "wayland" (Linux only).
36
+ * Render method "bitmap":
37
+ * "formats": a list of supported formats. It should always include "rgba-u8".
38
+ Other options can be be "i-u8" (intensity/grayscale), "i-f32", "bgra-u8", "rgba-u16", etc.
39
+
40
+ """
41
+
42
+ def __init__(self, canvas, present_methods):
43
+ self._canvas_ref = weakref.ref(canvas)
44
+ self._present_methods = present_methods
45
+
46
+ @property
47
+ def canvas(self):
48
+ """The associated canvas object. Internally, this should preferably be stored using a weakref."""
49
+ return self._canvas_ref()
50
+
51
+ def present(self):
52
+ """Present the result to the canvas.
53
+
54
+ This is called by the canvas, and should not be called by user-code.
55
+
56
+ The implementation should always return a present-result dict, which
57
+ should have at least a field 'method'. The value of 'method' must be
58
+ one of the methods that the canvas supports, i.e. it must be in ``present_methods``.
59
+
60
+ * If there is nothing to present, e.g. because nothing was rendered yet:
61
+ * return ``{"method": "skip"}`` (special case).
62
+ * If presentation could not be done for some reason:
63
+ * return ``{"method": "fail", "message": "xx"}`` (special case).
64
+ * If ``present_method`` is "screen":
65
+ * Render to screen using the info in ``present_methods['screen']``).
66
+ * Return ``{"method", "screen"}`` as confirmation.
67
+ * If ``present_method`` is "bitmap":
68
+ * Return ``{"method": "bitmap", "data": data, "format": format}``.
69
+ * 'data' is a memoryview, or something that can be converted to a memoryview, like a numpy array.
70
+ * 'format' is the format of the bitmap, must be in ``present_methods['bitmap']['formats']`` ("rgba-u8" is always supported).
71
+ * If ``present_method`` is something else:
72
+ * Return ``{"method": "xx", ...}``.
73
+ * It's the responsibility of the context to use a render method that is supported by the canvas,
74
+ and that the appropriate arguments are supplied.
75
+ """
76
+
77
+ # This is a stub
78
+ return {"method": "skip"}