vispy 0.15.0__cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
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.
Potentially problematic release.
This version of vispy might be problematic. Click here for more details.
- vispy/__init__.py +33 -0
- vispy/app/__init__.py +15 -0
- vispy/app/_default_app.py +76 -0
- vispy/app/_detect_eventloop.py +148 -0
- vispy/app/application.py +263 -0
- vispy/app/backends/__init__.py +52 -0
- vispy/app/backends/_egl.py +264 -0
- vispy/app/backends/_glfw.py +513 -0
- vispy/app/backends/_jupyter_rfb.py +278 -0
- vispy/app/backends/_offscreen_util.py +121 -0
- vispy/app/backends/_osmesa.py +235 -0
- vispy/app/backends/_pyglet.py +451 -0
- vispy/app/backends/_pyqt4.py +36 -0
- vispy/app/backends/_pyqt5.py +36 -0
- vispy/app/backends/_pyqt6.py +40 -0
- vispy/app/backends/_pyside.py +37 -0
- vispy/app/backends/_pyside2.py +52 -0
- vispy/app/backends/_pyside6.py +53 -0
- vispy/app/backends/_qt.py +1003 -0
- vispy/app/backends/_sdl2.py +444 -0
- vispy/app/backends/_template.py +244 -0
- vispy/app/backends/_test.py +8 -0
- vispy/app/backends/_tk.py +800 -0
- vispy/app/backends/_wx.py +476 -0
- vispy/app/backends/tests/__init__.py +0 -0
- vispy/app/backends/tests/test_offscreen_util.py +52 -0
- vispy/app/backends/tests/test_rfb.py +77 -0
- vispy/app/base.py +294 -0
- vispy/app/canvas.py +828 -0
- vispy/app/qt.py +92 -0
- vispy/app/tests/__init__.py +0 -0
- vispy/app/tests/qt-designer.ui +58 -0
- vispy/app/tests/test_app.py +442 -0
- vispy/app/tests/test_backends.py +164 -0
- vispy/app/tests/test_canvas.py +122 -0
- vispy/app/tests/test_context.py +92 -0
- vispy/app/tests/test_qt.py +47 -0
- vispy/app/tests/test_simultaneous.py +134 -0
- vispy/app/timer.py +174 -0
- vispy/color/__init__.py +17 -0
- vispy/color/_color_dict.py +193 -0
- vispy/color/color_array.py +447 -0
- vispy/color/color_space.py +181 -0
- vispy/color/colormap.py +1213 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +378 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1522 -0
- vispy/ext/cubehelix.py +138 -0
- vispy/ext/egl.py +375 -0
- vispy/ext/fontconfig.py +118 -0
- vispy/ext/gdi32plus.py +206 -0
- vispy/ext/osmesa.py +105 -0
- vispy/geometry/__init__.py +23 -0
- vispy/geometry/_triangulation_debugger.py +171 -0
- vispy/geometry/calculations.py +162 -0
- vispy/geometry/curves.py +399 -0
- vispy/geometry/generation.py +643 -0
- vispy/geometry/isocurve.py +175 -0
- vispy/geometry/isosurface.py +465 -0
- vispy/geometry/meshdata.py +700 -0
- vispy/geometry/normals.py +78 -0
- vispy/geometry/parametric.py +56 -0
- vispy/geometry/polygon.py +137 -0
- vispy/geometry/rect.py +210 -0
- vispy/geometry/tests/__init__.py +0 -0
- vispy/geometry/tests/test_calculations.py +23 -0
- vispy/geometry/tests/test_generation.py +56 -0
- vispy/geometry/tests/test_meshdata.py +106 -0
- vispy/geometry/tests/test_triangulation.py +594 -0
- vispy/geometry/torusknot.py +142 -0
- vispy/geometry/triangulation.py +876 -0
- vispy/gloo/__init__.py +56 -0
- vispy/gloo/buffer.py +505 -0
- vispy/gloo/context.py +272 -0
- vispy/gloo/framebuffer.py +257 -0
- vispy/gloo/gl/__init__.py +234 -0
- vispy/gloo/gl/_constants.py +332 -0
- vispy/gloo/gl/_es2.py +986 -0
- vispy/gloo/gl/_gl2.py +1365 -0
- vispy/gloo/gl/_proxy.py +499 -0
- vispy/gloo/gl/_pyopengl2.py +362 -0
- vispy/gloo/gl/dummy.py +24 -0
- vispy/gloo/gl/es2.py +62 -0
- vispy/gloo/gl/gl2.py +98 -0
- vispy/gloo/gl/glplus.py +168 -0
- vispy/gloo/gl/pyopengl2.py +97 -0
- vispy/gloo/gl/tests/__init__.py +0 -0
- vispy/gloo/gl/tests/test_basics.py +282 -0
- vispy/gloo/gl/tests/test_functionality.py +568 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1824 -0
- vispy/gloo/globject.py +101 -0
- vispy/gloo/preprocessor.py +67 -0
- vispy/gloo/program.py +543 -0
- vispy/gloo/tests/__init__.py +0 -0
- vispy/gloo/tests/test_buffer.py +558 -0
- vispy/gloo/tests/test_context.py +119 -0
- vispy/gloo/tests/test_framebuffer.py +195 -0
- vispy/gloo/tests/test_glir.py +307 -0
- vispy/gloo/tests/test_globject.py +35 -0
- vispy/gloo/tests/test_program.py +302 -0
- vispy/gloo/tests/test_texture.py +732 -0
- vispy/gloo/tests/test_use_gloo.py +187 -0
- vispy/gloo/tests/test_util.py +60 -0
- vispy/gloo/tests/test_wrappers.py +261 -0
- vispy/gloo/texture.py +1046 -0
- vispy/gloo/util.py +129 -0
- vispy/gloo/wrappers.py +762 -0
- vispy/glsl/__init__.py +42 -0
- vispy/glsl/antialias/antialias.glsl +7 -0
- vispy/glsl/antialias/cap-butt.glsl +31 -0
- vispy/glsl/antialias/cap-round.glsl +29 -0
- vispy/glsl/antialias/cap-square.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
- vispy/glsl/antialias/cap.glsl +67 -0
- vispy/glsl/antialias/caps.glsl +67 -0
- vispy/glsl/antialias/filled.glsl +50 -0
- vispy/glsl/antialias/outline.glsl +40 -0
- vispy/glsl/antialias/stroke.glsl +43 -0
- vispy/glsl/arrowheads/angle.glsl +99 -0
- vispy/glsl/arrowheads/arrowheads.frag +60 -0
- vispy/glsl/arrowheads/arrowheads.glsl +12 -0
- vispy/glsl/arrowheads/arrowheads.vert +83 -0
- vispy/glsl/arrowheads/curved.glsl +48 -0
- vispy/glsl/arrowheads/inhibitor.glsl +26 -0
- vispy/glsl/arrowheads/stealth.glsl +46 -0
- vispy/glsl/arrowheads/triangle.glsl +97 -0
- vispy/glsl/arrowheads/util.glsl +13 -0
- vispy/glsl/arrows/angle-30.glsl +12 -0
- vispy/glsl/arrows/angle-60.glsl +12 -0
- vispy/glsl/arrows/angle-90.glsl +12 -0
- vispy/glsl/arrows/arrow.frag +39 -0
- vispy/glsl/arrows/arrow.vert +49 -0
- vispy/glsl/arrows/arrows.glsl +17 -0
- vispy/glsl/arrows/common.glsl +187 -0
- vispy/glsl/arrows/curved.glsl +63 -0
- vispy/glsl/arrows/stealth.glsl +50 -0
- vispy/glsl/arrows/triangle-30.glsl +12 -0
- vispy/glsl/arrows/triangle-60.glsl +12 -0
- vispy/glsl/arrows/triangle-90.glsl +12 -0
- vispy/glsl/arrows/util.glsl +98 -0
- vispy/glsl/build_spatial_filters.py +660 -0
- vispy/glsl/collections/agg-fast-path.frag +20 -0
- vispy/glsl/collections/agg-fast-path.vert +78 -0
- vispy/glsl/collections/agg-glyph.frag +60 -0
- vispy/glsl/collections/agg-glyph.vert +33 -0
- vispy/glsl/collections/agg-marker.frag +35 -0
- vispy/glsl/collections/agg-marker.vert +48 -0
- vispy/glsl/collections/agg-path.frag +55 -0
- vispy/glsl/collections/agg-path.vert +166 -0
- vispy/glsl/collections/agg-point.frag +21 -0
- vispy/glsl/collections/agg-point.vert +35 -0
- vispy/glsl/collections/agg-segment.frag +32 -0
- vispy/glsl/collections/agg-segment.vert +75 -0
- vispy/glsl/collections/marker.frag +38 -0
- vispy/glsl/collections/marker.vert +48 -0
- vispy/glsl/collections/raw-path.frag +15 -0
- vispy/glsl/collections/raw-path.vert +24 -0
- vispy/glsl/collections/raw-point.frag +14 -0
- vispy/glsl/collections/raw-point.vert +31 -0
- vispy/glsl/collections/raw-segment.frag +18 -0
- vispy/glsl/collections/raw-segment.vert +26 -0
- vispy/glsl/collections/raw-triangle.frag +13 -0
- vispy/glsl/collections/raw-triangle.vert +26 -0
- vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
- vispy/glsl/collections/sdf-glyph.frag +80 -0
- vispy/glsl/collections/sdf-glyph.vert +59 -0
- vispy/glsl/collections/tick-labels.vert +71 -0
- vispy/glsl/colormaps/autumn.glsl +20 -0
- vispy/glsl/colormaps/blues.glsl +20 -0
- vispy/glsl/colormaps/color-space.glsl +17 -0
- vispy/glsl/colormaps/colormaps.glsl +24 -0
- vispy/glsl/colormaps/cool.glsl +20 -0
- vispy/glsl/colormaps/fire.glsl +21 -0
- vispy/glsl/colormaps/gray.glsl +20 -0
- vispy/glsl/colormaps/greens.glsl +20 -0
- vispy/glsl/colormaps/hot.glsl +22 -0
- vispy/glsl/colormaps/ice.glsl +20 -0
- vispy/glsl/colormaps/icefire.glsl +23 -0
- vispy/glsl/colormaps/parse.py +40 -0
- vispy/glsl/colormaps/reds.glsl +20 -0
- vispy/glsl/colormaps/spring.glsl +20 -0
- vispy/glsl/colormaps/summer.glsl +20 -0
- vispy/glsl/colormaps/user.glsl +22 -0
- vispy/glsl/colormaps/util.glsl +41 -0
- vispy/glsl/colormaps/wheel.glsl +21 -0
- vispy/glsl/colormaps/winter.glsl +20 -0
- vispy/glsl/lines/agg.frag +320 -0
- vispy/glsl/lines/agg.vert +241 -0
- vispy/glsl/markers/arrow.glsl +12 -0
- vispy/glsl/markers/asterisk.glsl +16 -0
- vispy/glsl/markers/chevron.glsl +14 -0
- vispy/glsl/markers/clover.glsl +20 -0
- vispy/glsl/markers/club.glsl +31 -0
- vispy/glsl/markers/cross.glsl +17 -0
- vispy/glsl/markers/diamond.glsl +12 -0
- vispy/glsl/markers/disc.glsl +9 -0
- vispy/glsl/markers/ellipse.glsl +67 -0
- vispy/glsl/markers/hbar.glsl +9 -0
- vispy/glsl/markers/heart.glsl +15 -0
- vispy/glsl/markers/infinity.glsl +15 -0
- vispy/glsl/markers/marker-sdf.frag +74 -0
- vispy/glsl/markers/marker-sdf.vert +41 -0
- vispy/glsl/markers/marker.frag +36 -0
- vispy/glsl/markers/marker.vert +46 -0
- vispy/glsl/markers/markers.glsl +24 -0
- vispy/glsl/markers/pin.glsl +18 -0
- vispy/glsl/markers/ring.glsl +11 -0
- vispy/glsl/markers/spade.glsl +28 -0
- vispy/glsl/markers/square.glsl +10 -0
- vispy/glsl/markers/tag.glsl +11 -0
- vispy/glsl/markers/triangle.glsl +14 -0
- vispy/glsl/markers/vbar.glsl +9 -0
- vispy/glsl/math/circle-through-2-points.glsl +30 -0
- vispy/glsl/math/constants.glsl +48 -0
- vispy/glsl/math/double.glsl +114 -0
- vispy/glsl/math/functions.glsl +20 -0
- vispy/glsl/math/point-to-line-distance.glsl +31 -0
- vispy/glsl/math/point-to-line-projection.glsl +29 -0
- vispy/glsl/math/signed-line-distance.glsl +27 -0
- vispy/glsl/math/signed-segment-distance.glsl +30 -0
- vispy/glsl/misc/regular-grid.frag +244 -0
- vispy/glsl/misc/spatial-filters.frag +1407 -0
- vispy/glsl/misc/viewport-NDC.glsl +20 -0
- vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
- vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
- vispy/glsl/transforms/hammer.glsl +44 -0
- vispy/glsl/transforms/identity.glsl +6 -0
- vispy/glsl/transforms/identity_forward.glsl +23 -0
- vispy/glsl/transforms/identity_inverse.glsl +23 -0
- vispy/glsl/transforms/linear-scale.glsl +127 -0
- vispy/glsl/transforms/log-scale.glsl +126 -0
- vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
- vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
- vispy/glsl/transforms/panzoom.glsl +10 -0
- vispy/glsl/transforms/polar.glsl +41 -0
- vispy/glsl/transforms/position.glsl +44 -0
- vispy/glsl/transforms/power-scale.glsl +139 -0
- vispy/glsl/transforms/projection.glsl +7 -0
- vispy/glsl/transforms/pvm.glsl +13 -0
- vispy/glsl/transforms/rotate.glsl +45 -0
- vispy/glsl/transforms/trackball.glsl +15 -0
- vispy/glsl/transforms/translate.glsl +35 -0
- vispy/glsl/transforms/transverse_mercator.glsl +38 -0
- vispy/glsl/transforms/viewport-clipping.glsl +14 -0
- vispy/glsl/transforms/viewport-transform.glsl +16 -0
- vispy/glsl/transforms/viewport.glsl +50 -0
- vispy/glsl/transforms/x.glsl +24 -0
- vispy/glsl/transforms/y.glsl +19 -0
- vispy/glsl/transforms/z.glsl +14 -0
- vispy/io/__init__.py +20 -0
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +94 -0
- vispy/io/image.py +231 -0
- vispy/io/mesh.py +122 -0
- vispy/io/stl.py +167 -0
- vispy/io/tests/__init__.py +0 -0
- vispy/io/tests/test_image.py +47 -0
- vispy/io/tests/test_io.py +121 -0
- vispy/io/wavefront.py +350 -0
- vispy/plot/__init__.py +36 -0
- vispy/plot/fig.py +58 -0
- vispy/plot/plotwidget.py +522 -0
- vispy/plot/tests/__init__.py +0 -0
- vispy/plot/tests/test_plot.py +46 -0
- vispy/scene/__init__.py +43 -0
- vispy/scene/cameras/__init__.py +27 -0
- vispy/scene/cameras/_base.py +38 -0
- vispy/scene/cameras/arcball.py +105 -0
- vispy/scene/cameras/base_camera.py +551 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +311 -0
- vispy/scene/cameras/perspective.py +338 -0
- vispy/scene/cameras/tests/__init__.py +0 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_link.py +53 -0
- vispy/scene/cameras/tests/test_perspective.py +122 -0
- vispy/scene/cameras/turntable.py +183 -0
- vispy/scene/canvas.py +639 -0
- vispy/scene/events.py +85 -0
- vispy/scene/node.py +644 -0
- vispy/scene/subscene.py +20 -0
- vispy/scene/tests/__init__.py +0 -0
- vispy/scene/tests/test_canvas.py +119 -0
- vispy/scene/tests/test_node.py +142 -0
- vispy/scene/tests/test_visuals.py +141 -0
- vispy/scene/visuals.py +276 -0
- vispy/scene/widgets/__init__.py +18 -0
- vispy/scene/widgets/anchor.py +25 -0
- vispy/scene/widgets/axis.py +88 -0
- vispy/scene/widgets/colorbar.py +176 -0
- vispy/scene/widgets/console.py +351 -0
- vispy/scene/widgets/grid.py +509 -0
- vispy/scene/widgets/label.py +50 -0
- vispy/scene/widgets/tests/__init__.py +0 -0
- vispy/scene/widgets/tests/test_colorbar.py +47 -0
- vispy/scene/widgets/viewbox.py +199 -0
- vispy/scene/widgets/widget.py +478 -0
- vispy/testing/__init__.py +51 -0
- vispy/testing/_runners.py +448 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +494 -0
- vispy/testing/rendered_array_tester.py +85 -0
- vispy/testing/tests/__init__.py +0 -0
- vispy/testing/tests/test_testing.py +20 -0
- vispy/util/__init__.py +32 -0
- vispy/util/bunch.py +15 -0
- vispy/util/check_environment.py +57 -0
- vispy/util/config.py +490 -0
- vispy/util/dpi/__init__.py +19 -0
- vispy/util/dpi/_linux.py +69 -0
- vispy/util/dpi/_quartz.py +26 -0
- vispy/util/dpi/_win32.py +34 -0
- vispy/util/dpi/tests/__init__.py +0 -0
- vispy/util/dpi/tests/test_dpi.py +16 -0
- vispy/util/eq.py +41 -0
- vispy/util/event.py +774 -0
- vispy/util/fetching.py +276 -0
- vispy/util/filter.py +44 -0
- vispy/util/fonts/__init__.py +14 -0
- vispy/util/fonts/_freetype.py +73 -0
- vispy/util/fonts/_quartz.py +192 -0
- vispy/util/fonts/_triage.py +36 -0
- vispy/util/fonts/_vispy_fonts.py +20 -0
- vispy/util/fonts/_win32.py +105 -0
- vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
- vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
- vispy/util/fonts/tests/__init__.py +0 -0
- vispy/util/fonts/tests/test_font.py +45 -0
- vispy/util/fourier.py +69 -0
- vispy/util/frozen.py +25 -0
- vispy/util/gallery_scraper.py +268 -0
- vispy/util/keys.py +91 -0
- vispy/util/logs.py +358 -0
- vispy/util/osmesa_gl.py +17 -0
- vispy/util/profiler.py +135 -0
- vispy/util/ptime.py +16 -0
- vispy/util/quaternion.py +229 -0
- vispy/util/svg/__init__.py +18 -0
- vispy/util/svg/base.py +20 -0
- vispy/util/svg/color.py +219 -0
- vispy/util/svg/element.py +51 -0
- vispy/util/svg/geometry.py +478 -0
- vispy/util/svg/group.py +66 -0
- vispy/util/svg/length.py +81 -0
- vispy/util/svg/number.py +25 -0
- vispy/util/svg/path.py +332 -0
- vispy/util/svg/shapes.py +57 -0
- vispy/util/svg/style.py +59 -0
- vispy/util/svg/svg.py +40 -0
- vispy/util/svg/transform.py +223 -0
- vispy/util/svg/transformable.py +28 -0
- vispy/util/svg/viewport.py +73 -0
- vispy/util/tests/__init__.py +0 -0
- vispy/util/tests/test_config.py +58 -0
- vispy/util/tests/test_docstring_parameters.py +123 -0
- vispy/util/tests/test_emitter_group.py +262 -0
- vispy/util/tests/test_event_emitter.py +743 -0
- vispy/util/tests/test_fourier.py +35 -0
- vispy/util/tests/test_gallery_scraper.py +112 -0
- vispy/util/tests/test_import.py +127 -0
- vispy/util/tests/test_key.py +22 -0
- vispy/util/tests/test_logging.py +45 -0
- vispy/util/tests/test_run.py +14 -0
- vispy/util/tests/test_transforms.py +42 -0
- vispy/util/tests/test_vispy.py +48 -0
- vispy/util/transforms.py +201 -0
- vispy/util/wrappers.py +155 -0
- vispy/version.py +21 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +487 -0
- vispy/visuals/axis.py +678 -0
- vispy/visuals/border.py +208 -0
- vispy/visuals/box.py +79 -0
- vispy/visuals/collections/__init__.py +30 -0
- vispy/visuals/collections/agg_fast_path_collection.py +219 -0
- vispy/visuals/collections/agg_path_collection.py +197 -0
- vispy/visuals/collections/agg_point_collection.py +52 -0
- vispy/visuals/collections/agg_segment_collection.py +142 -0
- vispy/visuals/collections/array_list.py +401 -0
- vispy/visuals/collections/base_collection.py +482 -0
- vispy/visuals/collections/collection.py +253 -0
- vispy/visuals/collections/path_collection.py +23 -0
- vispy/visuals/collections/point_collection.py +19 -0
- vispy/visuals/collections/polygon_collection.py +25 -0
- vispy/visuals/collections/raw_path_collection.py +119 -0
- vispy/visuals/collections/raw_point_collection.py +113 -0
- vispy/visuals/collections/raw_polygon_collection.py +77 -0
- vispy/visuals/collections/raw_segment_collection.py +112 -0
- vispy/visuals/collections/raw_triangle_collection.py +78 -0
- vispy/visuals/collections/segment_collection.py +19 -0
- vispy/visuals/collections/triangle_collection.py +16 -0
- vispy/visuals/collections/util.py +168 -0
- vispy/visuals/colorbar.py +699 -0
- vispy/visuals/cube.py +41 -0
- vispy/visuals/ellipse.py +162 -0
- vispy/visuals/filters/__init__.py +10 -0
- vispy/visuals/filters/base_filter.py +242 -0
- vispy/visuals/filters/clipper.py +60 -0
- vispy/visuals/filters/clipping_planes.py +122 -0
- vispy/visuals/filters/color.py +181 -0
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +801 -0
- vispy/visuals/filters/picking.py +60 -0
- vispy/visuals/filters/tests/__init__.py +3 -0
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
- vispy/visuals/glsl/__init__.py +1 -0
- vispy/visuals/glsl/antialiasing.py +133 -0
- vispy/visuals/glsl/color.py +63 -0
- vispy/visuals/graphs/__init__.py +1 -0
- vispy/visuals/graphs/graph.py +240 -0
- vispy/visuals/graphs/layouts/__init__.py +55 -0
- vispy/visuals/graphs/layouts/circular.py +49 -0
- vispy/visuals/graphs/layouts/force_directed.py +211 -0
- vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
- vispy/visuals/graphs/layouts/random.py +52 -0
- vispy/visuals/graphs/tests/__init__.py +1 -0
- vispy/visuals/graphs/tests/test_layouts.py +139 -0
- vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
- vispy/visuals/graphs/util.py +120 -0
- vispy/visuals/gridlines.py +161 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +701 -0
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/infinite_line.py +199 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +213 -0
- vispy/visuals/isoline.py +241 -0
- vispy/visuals/isosurface.py +113 -0
- vispy/visuals/line/__init__.py +6 -0
- vispy/visuals/line/arrow.py +289 -0
- vispy/visuals/line/dash_atlas.py +90 -0
- vispy/visuals/line/line.py +545 -0
- vispy/visuals/line_plot.py +135 -0
- vispy/visuals/linear_region.py +199 -0
- vispy/visuals/markers.py +819 -0
- vispy/visuals/mesh.py +373 -0
- vispy/visuals/mesh_normals.py +159 -0
- vispy/visuals/plane.py +54 -0
- vispy/visuals/polygon.py +145 -0
- vispy/visuals/rectangle.py +196 -0
- vispy/visuals/regular_polygon.py +56 -0
- vispy/visuals/scrolling_lines.py +197 -0
- vispy/visuals/shaders/__init__.py +17 -0
- vispy/visuals/shaders/compiler.py +206 -0
- vispy/visuals/shaders/expression.py +99 -0
- vispy/visuals/shaders/function.py +788 -0
- vispy/visuals/shaders/multiprogram.py +145 -0
- vispy/visuals/shaders/parsing.py +140 -0
- vispy/visuals/shaders/program.py +161 -0
- vispy/visuals/shaders/shader_object.py +162 -0
- vispy/visuals/shaders/tests/__init__.py +0 -0
- vispy/visuals/shaders/tests/test_function.py +486 -0
- vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
- vispy/visuals/shaders/tests/test_parsing.py +57 -0
- vispy/visuals/shaders/variable.py +272 -0
- vispy/visuals/spectrogram.py +169 -0
- vispy/visuals/sphere.py +80 -0
- vispy/visuals/surface_plot.py +192 -0
- vispy/visuals/tests/__init__.py +0 -0
- vispy/visuals/tests/test_arrows.py +109 -0
- vispy/visuals/tests/test_axis.py +120 -0
- vispy/visuals/tests/test_collections.py +15 -0
- vispy/visuals/tests/test_colorbar.py +179 -0
- vispy/visuals/tests/test_colormap.py +97 -0
- vispy/visuals/tests/test_ellipse.py +122 -0
- vispy/visuals/tests/test_gridlines.py +30 -0
- vispy/visuals/tests/test_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +392 -0
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_infinite_line.py +53 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_isosurface.py +22 -0
- vispy/visuals/tests/test_linear_region.py +152 -0
- vispy/visuals/tests/test_markers.py +54 -0
- vispy/visuals/tests/test_mesh.py +261 -0
- vispy/visuals/tests/test_mesh_normals.py +218 -0
- vispy/visuals/tests/test_polygon.py +112 -0
- vispy/visuals/tests/test_rectangle.py +163 -0
- vispy/visuals/tests/test_regular_polygon.py +111 -0
- vispy/visuals/tests/test_scalable_textures.py +196 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -0
- vispy/visuals/tests/test_surface_plot.py +57 -0
- vispy/visuals/tests/test_text.py +95 -0
- vispy/visuals/tests/test_volume.py +542 -0
- vispy/visuals/tests/test_windbarb.py +33 -0
- vispy/visuals/text/__init__.py +7 -0
- vispy/visuals/text/_sdf_cpu.cpython-313-aarch64-linux-gnu.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +112 -0
- vispy/visuals/text/_sdf_gpu.py +316 -0
- vispy/visuals/text/text.py +675 -0
- vispy/visuals/transforms/__init__.py +34 -0
- vispy/visuals/transforms/_util.py +191 -0
- vispy/visuals/transforms/base_transform.py +233 -0
- vispy/visuals/transforms/chain.py +300 -0
- vispy/visuals/transforms/interactive.py +98 -0
- vispy/visuals/transforms/linear.py +564 -0
- vispy/visuals/transforms/nonlinear.py +398 -0
- vispy/visuals/transforms/tests/__init__.py +0 -0
- vispy/visuals/transforms/tests/test_transforms.py +243 -0
- vispy/visuals/transforms/transform_system.py +339 -0
- vispy/visuals/tube.py +173 -0
- vispy/visuals/visual.py +923 -0
- vispy/visuals/volume.py +1366 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.15.0.dist-info/METADATA +243 -0
- vispy-0.15.0.dist-info/RECORD +521 -0
- vispy-0.15.0.dist-info/WHEEL +6 -0
- vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
- vispy-0.15.0.dist-info/top_level.txt +1 -0
vispy/app/canvas.py
ADDED
|
@@ -0,0 +1,828 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
3
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
4
|
+
|
|
5
|
+
from __future__ import division, print_function
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import numpy as np
|
|
9
|
+
from time import sleep
|
|
10
|
+
|
|
11
|
+
from ..util.event import EmitterGroup, Event, WarningEmitter
|
|
12
|
+
from ..util.ptime import time
|
|
13
|
+
from ..util.dpi import get_dpi
|
|
14
|
+
from ..util import config as util_config, logger
|
|
15
|
+
from . import Application, use_app
|
|
16
|
+
from ..gloo.context import (GLContext, set_current_canvas, forget_canvas)
|
|
17
|
+
from ..gloo import FrameBuffer, RenderBuffer
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# todo: add functions for asking about current mouse/keyboard state
|
|
21
|
+
# todo: add hover enter/exit events
|
|
22
|
+
# todo: add focus events
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Canvas(object):
|
|
26
|
+
"""Representation of a GUI element with an OpenGL context
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
title : str
|
|
31
|
+
The widget title
|
|
32
|
+
size : (width, height)
|
|
33
|
+
The size of the window.
|
|
34
|
+
position : (x, y)
|
|
35
|
+
The position of the window in screen coordinates.
|
|
36
|
+
show : bool
|
|
37
|
+
Whether to show the widget immediately. Default False.
|
|
38
|
+
autoswap : bool
|
|
39
|
+
Whether to swap the buffers automatically after a draw event.
|
|
40
|
+
Default True. If True, the ``swap_buffers`` Canvas method will
|
|
41
|
+
be called last (by default) by the ``canvas.draw`` event handler.
|
|
42
|
+
app : Application | str
|
|
43
|
+
Give vispy Application instance to use as a backend.
|
|
44
|
+
(vispy.app is used by default.) If str, then an application
|
|
45
|
+
using the chosen backend (e.g., 'pyglet') will be created.
|
|
46
|
+
Note the canvas application can be accessed at ``canvas.app``.
|
|
47
|
+
create_native : bool
|
|
48
|
+
Whether to create the widget immediately. Default True.
|
|
49
|
+
vsync : bool
|
|
50
|
+
Enable vertical synchronization.
|
|
51
|
+
resizable : bool
|
|
52
|
+
Allow the window to be resized.
|
|
53
|
+
decorate : bool
|
|
54
|
+
Decorate the window. Default True.
|
|
55
|
+
fullscreen : bool | int
|
|
56
|
+
If False, windowed mode is used (default). If True, the default
|
|
57
|
+
monitor is used. If int, the given monitor number is used.
|
|
58
|
+
config : dict
|
|
59
|
+
A dict with OpenGL configuration options, which is combined
|
|
60
|
+
with the default configuration options and used to initialize
|
|
61
|
+
the context. See ``canvas.context.config`` for possible
|
|
62
|
+
options.
|
|
63
|
+
shared : Canvas | GLContext | None
|
|
64
|
+
An existing canvas or context to share OpenGL objects with.
|
|
65
|
+
keys : str | dict | None
|
|
66
|
+
Default key mapping to use. If 'interactive', escape and F11 will
|
|
67
|
+
close the canvas and toggle full-screen mode, respectively.
|
|
68
|
+
If dict, maps keys to functions. If dict values are strings,
|
|
69
|
+
they are assumed to be ``Canvas`` methods, otherwise they should
|
|
70
|
+
be callable.
|
|
71
|
+
parent : widget-object
|
|
72
|
+
The parent widget if this makes sense for the used backend.
|
|
73
|
+
dpi : float | None
|
|
74
|
+
Resolution in dots-per-inch to use for the canvas. If dpi is None,
|
|
75
|
+
then the value will be determined by querying the global config first,
|
|
76
|
+
and then the operating system.
|
|
77
|
+
always_on_top : bool
|
|
78
|
+
If True, try to create the window in always-on-top mode.
|
|
79
|
+
px_scale : int > 0
|
|
80
|
+
A scale factor to apply between logical and physical pixels in addition
|
|
81
|
+
to the actual scale factor determined by the backend. This option
|
|
82
|
+
allows the scale factor to be adjusted for testing.
|
|
83
|
+
backend_kwargs : dict
|
|
84
|
+
Keyword arguments to be supplied to the backend canvas object.
|
|
85
|
+
|
|
86
|
+
Notes
|
|
87
|
+
-----
|
|
88
|
+
The `Canvas` receives the following events:
|
|
89
|
+
|
|
90
|
+
* initialize
|
|
91
|
+
* resize
|
|
92
|
+
* draw
|
|
93
|
+
* mouse_press
|
|
94
|
+
* mouse_release
|
|
95
|
+
* mouse_double_click
|
|
96
|
+
* mouse_move
|
|
97
|
+
* mouse_wheel
|
|
98
|
+
* key_press
|
|
99
|
+
* key_release
|
|
100
|
+
* stylus
|
|
101
|
+
* touch
|
|
102
|
+
* close
|
|
103
|
+
|
|
104
|
+
The ordering of the mouse_double_click, mouse_press, and mouse_release
|
|
105
|
+
events are not guaranteed to be consistent between backends. Only certain
|
|
106
|
+
backends natively support double-clicking (currently Qt and WX); on other
|
|
107
|
+
backends, they are detected manually with a fixed time delay.
|
|
108
|
+
This can cause problems with accessibility, as increasing the OS detection
|
|
109
|
+
time or using a dedicated double-click button will not be respected.
|
|
110
|
+
|
|
111
|
+
Backend-specific arguments can be given through the `backend_kwargs`
|
|
112
|
+
argument.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def __init__(self, title='VisPy canvas', size=(800, 600), position=None,
|
|
116
|
+
show=False, autoswap=True, app=None, create_native=True,
|
|
117
|
+
vsync=False, resizable=True, decorate=True, fullscreen=False,
|
|
118
|
+
config=None, shared=None, keys=None, parent=None, dpi=None,
|
|
119
|
+
always_on_top=False, px_scale=1, backend_kwargs=None):
|
|
120
|
+
|
|
121
|
+
size = tuple(int(s) * px_scale for s in size)
|
|
122
|
+
if len(size) != 2:
|
|
123
|
+
raise ValueError('size must be a 2-element list')
|
|
124
|
+
title = str(title)
|
|
125
|
+
if not isinstance(fullscreen, (bool, int)):
|
|
126
|
+
raise TypeError('fullscreen must be bool or int')
|
|
127
|
+
|
|
128
|
+
# Initialize some values
|
|
129
|
+
self._autoswap = autoswap
|
|
130
|
+
self._title = title
|
|
131
|
+
self._frame_count = 0
|
|
132
|
+
self._fps = 0
|
|
133
|
+
self._basetime = time()
|
|
134
|
+
self._fps_callback = None
|
|
135
|
+
self._backend = None
|
|
136
|
+
self._closed = False
|
|
137
|
+
self._fps_window = 0.
|
|
138
|
+
self._px_scale = int(px_scale)
|
|
139
|
+
|
|
140
|
+
if dpi is None:
|
|
141
|
+
dpi = util_config['dpi']
|
|
142
|
+
if dpi is None:
|
|
143
|
+
dpi = get_dpi(raise_error=False)
|
|
144
|
+
self.dpi = dpi
|
|
145
|
+
|
|
146
|
+
# Create events
|
|
147
|
+
self.events = EmitterGroup(source=self,
|
|
148
|
+
initialize=Event,
|
|
149
|
+
resize=ResizeEvent,
|
|
150
|
+
draw=DrawEvent,
|
|
151
|
+
mouse_press=MouseEvent,
|
|
152
|
+
mouse_release=MouseEvent,
|
|
153
|
+
mouse_double_click=MouseEvent,
|
|
154
|
+
mouse_move=MouseEvent,
|
|
155
|
+
mouse_wheel=MouseEvent,
|
|
156
|
+
key_press=KeyEvent,
|
|
157
|
+
key_release=KeyEvent,
|
|
158
|
+
stylus=Event,
|
|
159
|
+
touch=Event,
|
|
160
|
+
close=Event)
|
|
161
|
+
|
|
162
|
+
# Deprecated paint emitter
|
|
163
|
+
emitter = WarningEmitter('Canvas.events.paint and Canvas.on_paint are '
|
|
164
|
+
'deprecated; use Canvas.events.draw and '
|
|
165
|
+
'Canvas.on_draw instead.',
|
|
166
|
+
source=self, type='draw',
|
|
167
|
+
event_class=DrawEvent)
|
|
168
|
+
self.events.add(paint=emitter)
|
|
169
|
+
self.events.draw.connect(self.events.paint)
|
|
170
|
+
|
|
171
|
+
# Get app instance
|
|
172
|
+
if app is None:
|
|
173
|
+
self._app = use_app(call_reuse=False)
|
|
174
|
+
elif isinstance(app, Application):
|
|
175
|
+
self._app = app
|
|
176
|
+
elif isinstance(app, str):
|
|
177
|
+
self._app = Application(app)
|
|
178
|
+
else:
|
|
179
|
+
raise ValueError('Invalid value for app %r' % app)
|
|
180
|
+
|
|
181
|
+
# Check shared and context
|
|
182
|
+
if shared is None:
|
|
183
|
+
pass
|
|
184
|
+
elif isinstance(shared, Canvas):
|
|
185
|
+
shared = shared.context.shared
|
|
186
|
+
elif isinstance(shared, GLContext):
|
|
187
|
+
shared = shared.shared
|
|
188
|
+
else:
|
|
189
|
+
raise TypeError('shared must be a Canvas, not %s' % type(shared))
|
|
190
|
+
config = config or {}
|
|
191
|
+
if not isinstance(config, dict):
|
|
192
|
+
raise TypeError('config must be a dict, not %s' % type(config))
|
|
193
|
+
|
|
194
|
+
# Create new context
|
|
195
|
+
self._context = GLContext(config, shared)
|
|
196
|
+
|
|
197
|
+
# Deal with special keys
|
|
198
|
+
self._set_keys(keys)
|
|
199
|
+
|
|
200
|
+
# store arguments that get set on Canvas init
|
|
201
|
+
self._backend_kwargs = dict(
|
|
202
|
+
title=title, size=size, position=position, show=show,
|
|
203
|
+
vsync=vsync, resizable=resizable, decorate=decorate,
|
|
204
|
+
fullscreen=fullscreen, context=self._context,
|
|
205
|
+
parent=parent, always_on_top=always_on_top)
|
|
206
|
+
if backend_kwargs is not None:
|
|
207
|
+
self._backend_kwargs.update(**backend_kwargs)
|
|
208
|
+
|
|
209
|
+
# Create widget now (always do this *last*, after all err checks)
|
|
210
|
+
if create_native:
|
|
211
|
+
self.create_native()
|
|
212
|
+
|
|
213
|
+
# Now we're ready to become current
|
|
214
|
+
self.set_current()
|
|
215
|
+
|
|
216
|
+
if '--vispy-fps' in sys.argv:
|
|
217
|
+
self.measure_fps()
|
|
218
|
+
|
|
219
|
+
def create_native(self):
|
|
220
|
+
"""Create the native widget if not already done so. If the widget
|
|
221
|
+
is already created, this function does nothing.
|
|
222
|
+
"""
|
|
223
|
+
if self._backend is not None:
|
|
224
|
+
return
|
|
225
|
+
# Make sure that the app is active
|
|
226
|
+
assert self._app.native
|
|
227
|
+
# Instantiate the backend with the right class
|
|
228
|
+
self._app.backend_module.CanvasBackend(self, **self._backend_kwargs)
|
|
229
|
+
# self._backend = set by BaseCanvasBackend
|
|
230
|
+
self._backend_kwargs = None # Clean up
|
|
231
|
+
|
|
232
|
+
# Connect to draw event (append to the end)
|
|
233
|
+
# Process GLIR commands at each paint event
|
|
234
|
+
self.events.draw.connect(self.context.flush_commands, position='last')
|
|
235
|
+
if self._autoswap:
|
|
236
|
+
self.events.draw.connect((self, 'swap_buffers'),
|
|
237
|
+
ref=True, position='last')
|
|
238
|
+
|
|
239
|
+
def _set_keys(self, keys):
|
|
240
|
+
if keys is not None:
|
|
241
|
+
if isinstance(keys, str):
|
|
242
|
+
if keys != 'interactive':
|
|
243
|
+
raise ValueError('keys, if string, must be "interactive", '
|
|
244
|
+
'not %s' % (keys,))
|
|
245
|
+
|
|
246
|
+
def toggle_fs():
|
|
247
|
+
self.fullscreen = not self.fullscreen
|
|
248
|
+
keys = dict(escape='close', F11=toggle_fs)
|
|
249
|
+
else:
|
|
250
|
+
keys = {}
|
|
251
|
+
if not isinstance(keys, dict):
|
|
252
|
+
raise TypeError('keys must be a dict, str, or None')
|
|
253
|
+
if len(keys) > 0:
|
|
254
|
+
lower_keys = {}
|
|
255
|
+
# ensure all are callable
|
|
256
|
+
for key, val in keys.items():
|
|
257
|
+
if isinstance(val, str):
|
|
258
|
+
new_val = getattr(self, val, None)
|
|
259
|
+
if new_val is None:
|
|
260
|
+
raise ValueError('value %s is not an attribute of '
|
|
261
|
+
'Canvas' % val)
|
|
262
|
+
val = new_val
|
|
263
|
+
if not hasattr(val, '__call__'):
|
|
264
|
+
raise TypeError('Entry for key %s is not callable' % key)
|
|
265
|
+
# convert to lower-case representation
|
|
266
|
+
lower_keys[key.lower()] = val
|
|
267
|
+
self._keys_check = lower_keys
|
|
268
|
+
|
|
269
|
+
def keys_check(event):
|
|
270
|
+
if event.key is not None:
|
|
271
|
+
use_name = event.key.name.lower()
|
|
272
|
+
if use_name in self._keys_check:
|
|
273
|
+
self._keys_check[use_name]()
|
|
274
|
+
self.events.key_press.connect(keys_check, ref=True)
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def context(self):
|
|
278
|
+
"""The OpenGL context of the native widget
|
|
279
|
+
|
|
280
|
+
It gives access to OpenGL functions to call on this canvas object,
|
|
281
|
+
and to the shared context namespace.
|
|
282
|
+
"""
|
|
283
|
+
return self._context
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def app(self):
|
|
287
|
+
"""The vispy Application instance on which this Canvas is based."""
|
|
288
|
+
return self._app
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
def native(self):
|
|
292
|
+
"""The native widget object on which this Canvas is based."""
|
|
293
|
+
return self._backend._vispy_get_native_canvas()
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def dpi(self):
|
|
297
|
+
"""The physical resolution of the canvas in dots per inch."""
|
|
298
|
+
return self._dpi
|
|
299
|
+
|
|
300
|
+
@dpi.setter
|
|
301
|
+
def dpi(self, dpi):
|
|
302
|
+
self._dpi = float(dpi)
|
|
303
|
+
self.update()
|
|
304
|
+
|
|
305
|
+
def connect(self, fun):
|
|
306
|
+
"""Connect a function to an event
|
|
307
|
+
|
|
308
|
+
The name of the function
|
|
309
|
+
should be on_X, with X the name of the event (e.g. 'on_draw').
|
|
310
|
+
|
|
311
|
+
This method is typically used as a decorator on a function
|
|
312
|
+
definition for an event handler.
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
fun : callable
|
|
317
|
+
The function.
|
|
318
|
+
"""
|
|
319
|
+
# Get and check name
|
|
320
|
+
name = fun.__name__
|
|
321
|
+
if not name.startswith('on_'):
|
|
322
|
+
raise ValueError('When connecting a function based on its name, '
|
|
323
|
+
'the name should start with "on_"')
|
|
324
|
+
eventname = name[3:]
|
|
325
|
+
# Get emitter
|
|
326
|
+
try:
|
|
327
|
+
emitter = self.events[eventname]
|
|
328
|
+
except KeyError:
|
|
329
|
+
raise ValueError(
|
|
330
|
+
'Event "%s" not available on this canvas.' %
|
|
331
|
+
eventname)
|
|
332
|
+
# Connect
|
|
333
|
+
emitter.connect(fun)
|
|
334
|
+
|
|
335
|
+
# ---------------------------------------------------------------- size ---
|
|
336
|
+
@property
|
|
337
|
+
def size(self):
|
|
338
|
+
"""The size of canvas/window."""
|
|
339
|
+
# Note that _px_scale is an additional factor applied in addition to
|
|
340
|
+
# the scale factor imposed by the backend.
|
|
341
|
+
size = self._backend._vispy_get_size()
|
|
342
|
+
return (size[0] // self._px_scale, size[1] // self._px_scale)
|
|
343
|
+
|
|
344
|
+
@size.setter
|
|
345
|
+
def size(self, size):
|
|
346
|
+
return self._backend._vispy_set_size(size[0] * self._px_scale,
|
|
347
|
+
size[1] * self._px_scale)
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def physical_size(self):
|
|
351
|
+
"""The physical size of the canvas/window, which may differ from the
|
|
352
|
+
size property on backends that expose HiDPI.
|
|
353
|
+
"""
|
|
354
|
+
return self._backend._vispy_get_physical_size()
|
|
355
|
+
|
|
356
|
+
@property
|
|
357
|
+
def pixel_scale(self):
|
|
358
|
+
"""The ratio between the number of logical pixels, or 'points', and
|
|
359
|
+
the physical pixels on the device. In most cases this will be 1.0,
|
|
360
|
+
but on certain backends this will be greater than 1. This should be
|
|
361
|
+
used as a scaling factor when writing your own visualisations
|
|
362
|
+
with gloo (make a copy and multiply all your logical pixel values
|
|
363
|
+
by it). When writing Visuals or SceneGraph visualisations, this value
|
|
364
|
+
is exposed as `TransformSystem.px_scale`.
|
|
365
|
+
"""
|
|
366
|
+
return self.physical_size[0] / self.size[0]
|
|
367
|
+
|
|
368
|
+
@property
|
|
369
|
+
def fullscreen(self):
|
|
370
|
+
return self._backend._vispy_get_fullscreen()
|
|
371
|
+
|
|
372
|
+
@fullscreen.setter
|
|
373
|
+
def fullscreen(self, fullscreen):
|
|
374
|
+
return self._backend._vispy_set_fullscreen(fullscreen)
|
|
375
|
+
|
|
376
|
+
# ------------------------------------------------------------ position ---
|
|
377
|
+
@property
|
|
378
|
+
def position(self):
|
|
379
|
+
"""The position of canvas/window relative to screen."""
|
|
380
|
+
return self._backend._vispy_get_position()
|
|
381
|
+
|
|
382
|
+
@position.setter
|
|
383
|
+
def position(self, position):
|
|
384
|
+
assert len(position) == 2
|
|
385
|
+
return self._backend._vispy_set_position(position[0], position[1])
|
|
386
|
+
|
|
387
|
+
# --------------------------------------------------------------- title ---
|
|
388
|
+
@property
|
|
389
|
+
def title(self):
|
|
390
|
+
"""The title of canvas/window."""
|
|
391
|
+
return self._title
|
|
392
|
+
|
|
393
|
+
@title.setter
|
|
394
|
+
def title(self, title):
|
|
395
|
+
self._title = title
|
|
396
|
+
self._backend._vispy_set_title(title)
|
|
397
|
+
|
|
398
|
+
# ----------------------------------------------------------------- fps ---
|
|
399
|
+
@property
|
|
400
|
+
def fps(self):
|
|
401
|
+
"""The fps of canvas/window, as the rate that events.draw is emitted."""
|
|
402
|
+
return self._fps
|
|
403
|
+
|
|
404
|
+
def set_current(self, event=None):
|
|
405
|
+
"""Make this the active GL canvas
|
|
406
|
+
|
|
407
|
+
Parameters
|
|
408
|
+
----------
|
|
409
|
+
event : None
|
|
410
|
+
Not used.
|
|
411
|
+
"""
|
|
412
|
+
self._backend._vispy_set_current()
|
|
413
|
+
set_current_canvas(self)
|
|
414
|
+
|
|
415
|
+
def swap_buffers(self, event=None):
|
|
416
|
+
"""Swap GL buffers such that the offscreen buffer becomes visible
|
|
417
|
+
|
|
418
|
+
Parameters
|
|
419
|
+
----------
|
|
420
|
+
event : None
|
|
421
|
+
Not used.
|
|
422
|
+
"""
|
|
423
|
+
self._backend._vispy_swap_buffers()
|
|
424
|
+
|
|
425
|
+
def show(self, visible=True, run=False):
|
|
426
|
+
"""Show or hide the canvas
|
|
427
|
+
|
|
428
|
+
Parameters
|
|
429
|
+
----------
|
|
430
|
+
visible : bool
|
|
431
|
+
Make the canvas visible.
|
|
432
|
+
run : bool
|
|
433
|
+
Run the backend event loop.
|
|
434
|
+
"""
|
|
435
|
+
self._backend._vispy_set_visible(visible)
|
|
436
|
+
if run:
|
|
437
|
+
self.app.run()
|
|
438
|
+
|
|
439
|
+
def update(self, event=None):
|
|
440
|
+
"""Inform the backend that the Canvas needs to be redrawn
|
|
441
|
+
|
|
442
|
+
Parameters
|
|
443
|
+
----------
|
|
444
|
+
event : None
|
|
445
|
+
Not used.
|
|
446
|
+
"""
|
|
447
|
+
if self._backend is not None:
|
|
448
|
+
self._backend._vispy_update()
|
|
449
|
+
|
|
450
|
+
def close(self):
|
|
451
|
+
"""Close the canvas
|
|
452
|
+
|
|
453
|
+
Notes
|
|
454
|
+
-----
|
|
455
|
+
This will usually destroy the GL context. For Qt, the context
|
|
456
|
+
(and widget) will be destroyed only if the widget is top-level.
|
|
457
|
+
To avoid having the widget destroyed (more like standard Qt
|
|
458
|
+
behavior), consider making the widget a sub-widget.
|
|
459
|
+
"""
|
|
460
|
+
if self._backend is not None and not self._closed:
|
|
461
|
+
logger.debug('Closing canvas %s' % (self,))
|
|
462
|
+
self._closed = True
|
|
463
|
+
self.events.close()
|
|
464
|
+
self._backend._vispy_close()
|
|
465
|
+
forget_canvas(self)
|
|
466
|
+
|
|
467
|
+
def _update_fps(self, event):
|
|
468
|
+
"""Update the fps after every window"""
|
|
469
|
+
self._frame_count += 1
|
|
470
|
+
diff = time() - self._basetime
|
|
471
|
+
if (diff > self._fps_window):
|
|
472
|
+
self._fps = self._frame_count / diff
|
|
473
|
+
self._basetime = time()
|
|
474
|
+
self._frame_count = 0
|
|
475
|
+
self._fps_callback(self.fps)
|
|
476
|
+
|
|
477
|
+
def measure_fps(self, window=1, callback='%1.1f FPS'):
|
|
478
|
+
"""Measure the current FPS
|
|
479
|
+
|
|
480
|
+
Sets the update window, connects the draw event to update_fps
|
|
481
|
+
and sets the callback function.
|
|
482
|
+
|
|
483
|
+
Parameters
|
|
484
|
+
----------
|
|
485
|
+
window : float
|
|
486
|
+
The time-window (in seconds) to calculate FPS. Default 1.0.
|
|
487
|
+
callback : function | str
|
|
488
|
+
The function to call with the float FPS value, or the string
|
|
489
|
+
to be formatted with the fps value and then printed. The
|
|
490
|
+
default is ``'%1.1f FPS'``. If callback evaluates to False, the
|
|
491
|
+
FPS measurement is stopped.
|
|
492
|
+
"""
|
|
493
|
+
# Connect update_fps function to draw
|
|
494
|
+
self.events.draw.disconnect(self._update_fps)
|
|
495
|
+
if callback:
|
|
496
|
+
if isinstance(callback, str):
|
|
497
|
+
callback_str = callback # because callback gets overwritten
|
|
498
|
+
|
|
499
|
+
def callback(x):
|
|
500
|
+
print(callback_str % x)
|
|
501
|
+
|
|
502
|
+
self._fps_window = window
|
|
503
|
+
self.events.draw.connect(self._update_fps)
|
|
504
|
+
self._fps_callback = callback
|
|
505
|
+
else:
|
|
506
|
+
self._fps_callback = None
|
|
507
|
+
|
|
508
|
+
# ---------------------------------------------------------------- misc ---
|
|
509
|
+
def __repr__(self):
|
|
510
|
+
return ('<%s (%s) at %s>'
|
|
511
|
+
% (self.__class__.__name__,
|
|
512
|
+
self.app.backend_name, hex(id(self))))
|
|
513
|
+
|
|
514
|
+
def _repr_mimebundle_(self, *args, **kwargs):
|
|
515
|
+
"""If the backend implements _repr_mimebundle_, we proxy it here.
|
|
516
|
+
"""
|
|
517
|
+
# See https://ipython.readthedocs.io/en/stable/config/integrating.html
|
|
518
|
+
f = getattr(self._backend, "_repr_mimebundle_", None)
|
|
519
|
+
if f is not None:
|
|
520
|
+
return f(*args, **kwargs)
|
|
521
|
+
else:
|
|
522
|
+
# Let Jupyter know this failed - otherwise the standard repr is not shown
|
|
523
|
+
raise NotImplementedError()
|
|
524
|
+
|
|
525
|
+
def _ipython_display_(self):
|
|
526
|
+
"""If the backend implements _ipython_display_, we proxy it here.
|
|
527
|
+
"""
|
|
528
|
+
# See https://ipython.readthedocs.io/en/stable/config/integrating.html
|
|
529
|
+
f = getattr(self._backend, "_ipython_display_", None)
|
|
530
|
+
if f is not None:
|
|
531
|
+
return f()
|
|
532
|
+
else:
|
|
533
|
+
# Let Jupyter know this failed - otherwise the standard repr is not shown
|
|
534
|
+
raise NotImplementedError()
|
|
535
|
+
|
|
536
|
+
def __enter__(self):
|
|
537
|
+
logger.debug('Context manager enter starting for %s' % (self,))
|
|
538
|
+
self.show()
|
|
539
|
+
self._backend._vispy_warmup()
|
|
540
|
+
return self
|
|
541
|
+
|
|
542
|
+
def __exit__(self, type, value, traceback):
|
|
543
|
+
# ensure all GL calls are complete
|
|
544
|
+
logger.debug('Context manager exit starting for %s' % (self,))
|
|
545
|
+
if not self._closed:
|
|
546
|
+
self._backend._vispy_set_current()
|
|
547
|
+
self.context.finish()
|
|
548
|
+
self.close()
|
|
549
|
+
sleep(0.1) # ensure window is really closed/destroyed
|
|
550
|
+
logger.debug('Context manager exit complete for %s' % (self,))
|
|
551
|
+
|
|
552
|
+
def render(self, alpha=True):
|
|
553
|
+
"""Render the canvas to an offscreen buffer and return the image array.
|
|
554
|
+
|
|
555
|
+
Parameters
|
|
556
|
+
----------
|
|
557
|
+
alpha : bool
|
|
558
|
+
If True (default) produce an RGBA array (M, N, 4). If False,
|
|
559
|
+
remove the Alpha channel and return the RGB array (M, N, 3).
|
|
560
|
+
This may be useful if blending of various elements requires a
|
|
561
|
+
solid background to produce the expected visualization.
|
|
562
|
+
|
|
563
|
+
Returns
|
|
564
|
+
-------
|
|
565
|
+
image : array
|
|
566
|
+
Numpy array of type ubyte and shape (h, w, 4). Index [0, 0] is the
|
|
567
|
+
upper-left corner of the rendered region. If ``alpha`` is ``False``,
|
|
568
|
+
then only 3 channels will be returned (RGB).
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
"""
|
|
572
|
+
self.set_current()
|
|
573
|
+
size = self.physical_size
|
|
574
|
+
fbo = FrameBuffer(color=RenderBuffer(size[::-1]),
|
|
575
|
+
depth=RenderBuffer(size[::-1]))
|
|
576
|
+
|
|
577
|
+
try:
|
|
578
|
+
fbo.activate()
|
|
579
|
+
self.events.draw()
|
|
580
|
+
result = fbo.read()
|
|
581
|
+
finally:
|
|
582
|
+
fbo.deactivate()
|
|
583
|
+
|
|
584
|
+
if not alpha:
|
|
585
|
+
result = result[..., :3]
|
|
586
|
+
return result
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
# Event subclasses specific to the Canvas
|
|
590
|
+
class MouseEvent(Event):
|
|
591
|
+
"""Mouse event class
|
|
592
|
+
|
|
593
|
+
Note that each event object has an attribute for each of the input
|
|
594
|
+
arguments listed below, as well as a "time" attribute with the event's
|
|
595
|
+
precision start time.
|
|
596
|
+
|
|
597
|
+
Parameters
|
|
598
|
+
----------
|
|
599
|
+
type : str
|
|
600
|
+
String indicating the event type (e.g. mouse_press, key_release)
|
|
601
|
+
pos : (int, int)
|
|
602
|
+
The position of the mouse (in screen coordinates).
|
|
603
|
+
button : int | None
|
|
604
|
+
The button that generated this event (can be None).
|
|
605
|
+
Left=1, right=2, middle=3. During a mouse drag, this
|
|
606
|
+
will return the button that started the drag (same thing as
|
|
607
|
+
``event.press_event.button``).
|
|
608
|
+
buttons : [int, ...]
|
|
609
|
+
The list of buttons pressed during this event.
|
|
610
|
+
modifiers : tuple of Key instances
|
|
611
|
+
Tuple that specifies which modifier keys were pressed down at the
|
|
612
|
+
time of the event (shift, control, alt, meta).
|
|
613
|
+
delta : (float, float)
|
|
614
|
+
The amount of scrolling in horizontal and vertical direction. One
|
|
615
|
+
"tick" corresponds to a delta of 1.0.
|
|
616
|
+
press_event : MouseEvent
|
|
617
|
+
The press event that was generated at the start of the current drag,
|
|
618
|
+
if any.
|
|
619
|
+
last_event : MouseEvent
|
|
620
|
+
The MouseEvent immediately preceding the current event. During drag
|
|
621
|
+
operations, all generated events retain their last_event properties,
|
|
622
|
+
allowing the entire drag to be reconstructed.
|
|
623
|
+
native : object (optional)
|
|
624
|
+
The native GUI event object
|
|
625
|
+
**kwargs : keyword arguments
|
|
626
|
+
All extra keyword arguments become attributes of the event object.
|
|
627
|
+
"""
|
|
628
|
+
|
|
629
|
+
def __init__(self, type, pos=None, button=None, buttons=None,
|
|
630
|
+
modifiers=None, delta=None, last_event=None, press_event=None,
|
|
631
|
+
**kwargs):
|
|
632
|
+
Event.__init__(self, type, **kwargs)
|
|
633
|
+
self._pos = np.array([0, 0]) if (pos is None) else np.array(pos)
|
|
634
|
+
self._button = int(button) if (button is not None) else None
|
|
635
|
+
# Explicitly add button to buttons if newly pressed, check #2344 for more reference
|
|
636
|
+
newly_pressed_buttons = [button] if button is not None and type == 'mouse_press' else []
|
|
637
|
+
self._buttons = [] if (buttons is None) else buttons + newly_pressed_buttons
|
|
638
|
+
self._modifiers = tuple(modifiers or ())
|
|
639
|
+
self._delta = np.zeros(2) if (delta is None) else np.array(delta)
|
|
640
|
+
self._last_event = last_event
|
|
641
|
+
self._press_event = press_event
|
|
642
|
+
self._time = time()
|
|
643
|
+
|
|
644
|
+
@property
|
|
645
|
+
def pos(self):
|
|
646
|
+
return self._pos
|
|
647
|
+
|
|
648
|
+
@property
|
|
649
|
+
def button(self):
|
|
650
|
+
return self._button
|
|
651
|
+
|
|
652
|
+
@property
|
|
653
|
+
def buttons(self):
|
|
654
|
+
return self._buttons
|
|
655
|
+
|
|
656
|
+
@property
|
|
657
|
+
def modifiers(self):
|
|
658
|
+
return self._modifiers
|
|
659
|
+
|
|
660
|
+
@property
|
|
661
|
+
def delta(self):
|
|
662
|
+
return self._delta
|
|
663
|
+
|
|
664
|
+
@property
|
|
665
|
+
def press_event(self):
|
|
666
|
+
return self._press_event
|
|
667
|
+
|
|
668
|
+
@property
|
|
669
|
+
def last_event(self):
|
|
670
|
+
return self._last_event
|
|
671
|
+
|
|
672
|
+
@property
|
|
673
|
+
def time(self):
|
|
674
|
+
return self._time
|
|
675
|
+
|
|
676
|
+
def _forget_last_event(self):
|
|
677
|
+
# Needed to break otherwise endless last-event chains
|
|
678
|
+
self._last_event = None
|
|
679
|
+
|
|
680
|
+
@property
|
|
681
|
+
def is_dragging(self):
|
|
682
|
+
"""Indicates whether this event is part of a mouse drag operation."""
|
|
683
|
+
return self.press_event is not None
|
|
684
|
+
|
|
685
|
+
def drag_events(self):
|
|
686
|
+
"""Return a list of all mouse events in the current drag operation.
|
|
687
|
+
|
|
688
|
+
Returns None if there is no current drag operation.
|
|
689
|
+
"""
|
|
690
|
+
if not self.is_dragging:
|
|
691
|
+
return None
|
|
692
|
+
|
|
693
|
+
event = self
|
|
694
|
+
events = []
|
|
695
|
+
while True:
|
|
696
|
+
# mouse_press events can only be the start of a trail
|
|
697
|
+
if event is None or event.type == 'mouse_press':
|
|
698
|
+
break
|
|
699
|
+
events.append(event)
|
|
700
|
+
event = event.last_event
|
|
701
|
+
|
|
702
|
+
return events[::-1]
|
|
703
|
+
|
|
704
|
+
def trail(self):
|
|
705
|
+
"""Return an (N, 2) array of mouse coordinates for every event in the
|
|
706
|
+
current mouse drag operation.
|
|
707
|
+
|
|
708
|
+
Returns None if there is no current drag operation.
|
|
709
|
+
"""
|
|
710
|
+
events = self.drag_events()
|
|
711
|
+
if events is None:
|
|
712
|
+
return None
|
|
713
|
+
|
|
714
|
+
trail = np.empty((len(events), 2), dtype=int)
|
|
715
|
+
for i, ev in enumerate(events):
|
|
716
|
+
trail[i] = ev.pos
|
|
717
|
+
|
|
718
|
+
return trail
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
class KeyEvent(Event):
|
|
722
|
+
"""Key event class
|
|
723
|
+
|
|
724
|
+
Note that each event object has an attribute for each of the input
|
|
725
|
+
arguments listed below.
|
|
726
|
+
|
|
727
|
+
Parameters
|
|
728
|
+
----------
|
|
729
|
+
type : str
|
|
730
|
+
String indicating the event type (e.g. mouse_press, key_release)
|
|
731
|
+
key : vispy.keys.Key instance
|
|
732
|
+
The Key object for this event. Can be compared to string names.
|
|
733
|
+
text : str
|
|
734
|
+
The text representation of the key (can be an empty string).
|
|
735
|
+
modifiers : tuple of Key instances
|
|
736
|
+
Tuple that specifies which modifier keys were pressed down at the
|
|
737
|
+
time of the event (shift, control, alt, meta).
|
|
738
|
+
native : object (optional)
|
|
739
|
+
The native GUI event object
|
|
740
|
+
**kwargs : keyword arguments
|
|
741
|
+
All extra keyword arguments become attributes of the event object.
|
|
742
|
+
"""
|
|
743
|
+
|
|
744
|
+
def __init__(self, type, key=None, text='', modifiers=None, **kwargs):
|
|
745
|
+
Event.__init__(self, type, **kwargs)
|
|
746
|
+
self._key = key
|
|
747
|
+
self._text = text
|
|
748
|
+
self._modifiers = tuple(modifiers or ())
|
|
749
|
+
|
|
750
|
+
@property
|
|
751
|
+
def key(self):
|
|
752
|
+
return self._key
|
|
753
|
+
|
|
754
|
+
@property
|
|
755
|
+
def text(self):
|
|
756
|
+
return self._text
|
|
757
|
+
|
|
758
|
+
@property
|
|
759
|
+
def modifiers(self):
|
|
760
|
+
return self._modifiers
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
class ResizeEvent(Event):
|
|
764
|
+
"""Resize event class
|
|
765
|
+
|
|
766
|
+
Note that each event object has an attribute for each of the input
|
|
767
|
+
arguments listed below.
|
|
768
|
+
|
|
769
|
+
Parameters
|
|
770
|
+
----------
|
|
771
|
+
type : str
|
|
772
|
+
String indicating the event type (e.g. mouse_press, key_release)
|
|
773
|
+
size : (int, int)
|
|
774
|
+
The new size of the Canvas, in points (logical pixels).
|
|
775
|
+
physical_size : (int, int)
|
|
776
|
+
The new physical size of the Canvas, in pixels.
|
|
777
|
+
native : object (optional)
|
|
778
|
+
The native GUI event object
|
|
779
|
+
**kwargs : extra keyword arguments
|
|
780
|
+
All extra keyword arguments become attributes of the event object.
|
|
781
|
+
"""
|
|
782
|
+
|
|
783
|
+
def __init__(self, type, size=None, physical_size=None, **kwargs):
|
|
784
|
+
Event.__init__(self, type, **kwargs)
|
|
785
|
+
self._size = tuple(size)
|
|
786
|
+
if physical_size is None:
|
|
787
|
+
self._physical_size = self._size
|
|
788
|
+
else:
|
|
789
|
+
self._physical_size = tuple(physical_size)
|
|
790
|
+
|
|
791
|
+
@property
|
|
792
|
+
def size(self):
|
|
793
|
+
return self._size
|
|
794
|
+
|
|
795
|
+
@property
|
|
796
|
+
def physical_size(self):
|
|
797
|
+
return self._physical_size
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
class DrawEvent(Event):
|
|
801
|
+
"""Draw event class
|
|
802
|
+
|
|
803
|
+
This type of event is sent to Canvas.events.draw when a redraw
|
|
804
|
+
is required.
|
|
805
|
+
|
|
806
|
+
Note that each event object has an attribute for each of the input
|
|
807
|
+
arguments listed below.
|
|
808
|
+
|
|
809
|
+
Parameters
|
|
810
|
+
----------
|
|
811
|
+
type : str
|
|
812
|
+
String indicating the event type (e.g. mouse_press, key_release)
|
|
813
|
+
region : (int, int, int, int) or None
|
|
814
|
+
The region of the canvas which needs to be redrawn (x, y, w, h).
|
|
815
|
+
If None, the entire canvas must be redrawn.
|
|
816
|
+
native : object (optional)
|
|
817
|
+
The native GUI event object
|
|
818
|
+
**kwargs : extra keyword arguments
|
|
819
|
+
All extra keyword arguments become attributes of the event object.
|
|
820
|
+
"""
|
|
821
|
+
|
|
822
|
+
def __init__(self, type, region=None, **kwargs):
|
|
823
|
+
Event.__init__(self, type, **kwargs)
|
|
824
|
+
self._region = region
|
|
825
|
+
|
|
826
|
+
@property
|
|
827
|
+
def region(self):
|
|
828
|
+
return self._region
|