kaxe 1.8.1.dev5__tar.gz → 1.9.0.dev0__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.
- {kaxe-1.8.1.dev5/src/kaxe.egg-info → kaxe-1.9.0.dev0}/PKG-INFO +4 -2
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/README.md +3 -1
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/pyproject.toml +1 -1
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/axis.py +9 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/marker.py +2 -1
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/text.py +4 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/viewer/window.py +88 -9
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0/src/kaxe.egg-info}/PKG-INFO +4 -2
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/tests/test_viewer.py +30 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/LICENSE +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/MANIFEST.in +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/setup.cfg +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/__main__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/_require_3d.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/_require_viewer.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/chart/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/chart/bar.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/chart/box.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/chart/pie.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/chart/qqplot.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/cli.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/bounds.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/color.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/backend.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/camera.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/helper.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/hud.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/objects/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/objects/color.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/objects/line.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/objects/point.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/objects/pointer.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/objects/triangle.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/openglrender.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/d3/translator.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/draw.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/fileloader.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/helper.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/ipython_display.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/legend.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/line.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/palette.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/profiler.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/progress.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/round.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/shapes.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/styles.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/svg.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/svg_pdf.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/symbol.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/thin.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/core/window.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/data/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/data/excel.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/_lazy.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/arrow.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/bubble.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/contour.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/equation.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/fill.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/function.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/guide_grid.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/inequality.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/map.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/parameter.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/pillar.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d2/point.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d3/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d3/base.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d3/function.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d3/mesh.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d3/point.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/d3/potato.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/function.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/legend.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/mapdata.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/point.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/objects/text.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/_lazy.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/box.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/constants.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/d3/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/d3/axes.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/d3/geometry.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/d3/plot3d.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/d3/variants.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/double.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/empty.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/grid.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/log.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/polar.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/standard.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/themes.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/zoom.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/plot/zoom_connector.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/codec.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/context.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/document.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/registry.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/sample.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/sampled_curve.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/serializers.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/project/window.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-semibold.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-semiboldoblique.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.classical-serif-italic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-italic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-bold.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-boldoblique.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-demi-condensed-demicondensed.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-medium.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-oblique.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-boldslanted.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-romanslanted.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-upright-italic-uprightitalic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bold.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-italic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-light.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-lightoblique.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-regular.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-italic.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-medium.ttf +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/readme.txt +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/logo-small.png +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/viewer/__init__.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/viewer/cli.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/viewer/client.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/viewer/server.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe.egg-info/SOURCES.txt +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe.egg-info/dependency_links.txt +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe.egg-info/entry_points.txt +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe.egg-info/requires.txt +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe.egg-info/top_level.txt +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/tests/test.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/tests/test2.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/tests/test3.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/tests/test_4.py +0 -0
- {kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/tests/test_5.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.0.dev0
|
|
4
4
|
Summary: A small graphing tool for functions, points, equations and more
|
|
5
5
|
Author-email: Valter Yde Daugberg <valteryde@hotmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/valteryde/kaxe
|
|
@@ -87,7 +87,9 @@ When the viewer is open, `.show()` instantly streams plots to cards on your canv
|
|
|
87
87
|
**Canvas & Card Controls:**
|
|
88
88
|
* **Click & Drag on a Card**: Move that card freely across the canvas
|
|
89
89
|
* **Click & Drag on Empty Space**: Pan the camera across the workspace
|
|
90
|
-
* **
|
|
90
|
+
* **Two-Finger Scroll / Trackpad**: Pan canvas side-to-side and up/down without zooming
|
|
91
|
+
* **`[Shift]` + Scroll**: Pan horizontally (for 1D mouse wheels)
|
|
92
|
+
* **`[Cmd]` / `[Ctrl]` + Scroll**: Smooth zoom anchored to cursor
|
|
91
93
|
* **`[A]`**: Auto-arrange all cards in a neat row
|
|
92
94
|
* **`[Space]` or `[R]`**: Fit all cards on the canvas into view
|
|
93
95
|
* **`[1]`**: View canvas at 100% native pixel scale
|
|
@@ -54,7 +54,9 @@ When the viewer is open, `.show()` instantly streams plots to cards on your canv
|
|
|
54
54
|
**Canvas & Card Controls:**
|
|
55
55
|
* **Click & Drag on a Card**: Move that card freely across the canvas
|
|
56
56
|
* **Click & Drag on Empty Space**: Pan the camera across the workspace
|
|
57
|
-
* **
|
|
57
|
+
* **Two-Finger Scroll / Trackpad**: Pan canvas side-to-side and up/down without zooming
|
|
58
|
+
* **`[Shift]` + Scroll**: Pan horizontally (for 1D mouse wheels)
|
|
59
|
+
* **`[Cmd]` / `[Ctrl]` + Scroll**: Smooth zoom anchored to cursor
|
|
58
60
|
* **`[A]`**: Auto-arrange all cards in a neat row
|
|
59
61
|
* **`[Space]` or `[R]`**: Fit all cards on the canvas into view
|
|
60
62
|
* **`[1]`**: View canvas at 100% native pixel scale
|
|
@@ -362,6 +362,7 @@ class Axis(AttrObject):
|
|
|
362
362
|
|
|
363
363
|
if (i + markerOffset) % maxOverlays != 0:
|
|
364
364
|
|
|
365
|
+
marker.textLabel.hide()
|
|
365
366
|
marker.textLabel.img = Image.new('RGBA', (0,0))
|
|
366
367
|
if hasattr(marker, 'line'):
|
|
367
368
|
marker.line.color = (
|
|
@@ -589,6 +590,10 @@ class Axis(AttrObject):
|
|
|
589
590
|
|
|
590
591
|
|
|
591
592
|
def __pixelCollision__(self, label:Text, title:Text):
|
|
593
|
+
if label.__hidden__ or label.img.width == 0 or label.img.height == 0:
|
|
594
|
+
return False
|
|
595
|
+
if title.__hidden__ or title.img.width == 0 or title.img.height == 0:
|
|
596
|
+
return False
|
|
592
597
|
|
|
593
598
|
lx, ly, lwidth, lheight = label.getBoundingBox()
|
|
594
599
|
tx, ty, twidth, theight = title.getBoundingBox()
|
|
@@ -770,6 +775,10 @@ class Axis(AttrObject):
|
|
|
770
775
|
for a, b in l:
|
|
771
776
|
if not hasattr(a, 'textLabel') or not hasattr(b, 'textLabel'):
|
|
772
777
|
continue
|
|
778
|
+
if a.textLabel.__hidden__ or b.textLabel.__hidden__:
|
|
779
|
+
continue
|
|
780
|
+
if a.textLabel.img.width == 0 or b.textLabel.img.width == 0:
|
|
781
|
+
continue
|
|
773
782
|
|
|
774
783
|
if not self.__topLeftBoxOverlays__(a.textLabel, b.textLabel):
|
|
775
784
|
continue
|
|
@@ -193,7 +193,8 @@ class Marker(AttrObject):
|
|
|
193
193
|
label_y += nudge[1]
|
|
194
194
|
|
|
195
195
|
self.textLabel.setCenterPos(label_x, label_y)
|
|
196
|
-
self.textLabel.
|
|
196
|
+
if self.textLabel.img.width > 0 and self.textLabel.img.height > 0:
|
|
197
|
+
self.textLabel.show()
|
|
197
198
|
|
|
198
199
|
|
|
199
200
|
def getBoundingBox(self):
|
|
@@ -178,6 +178,8 @@ class Text(Shape):
|
|
|
178
178
|
]
|
|
179
179
|
|
|
180
180
|
def drawPillow(self, surface):
|
|
181
|
+
if self.__hidden__ or self.img.width == 0 or self.img.height == 0:
|
|
182
|
+
return
|
|
181
183
|
[y] = flipHorizontal(surface, self.__center__[1] + self.height/2)
|
|
182
184
|
if self.clip_box is not None:
|
|
183
185
|
blit_image_clipped(
|
|
@@ -191,6 +193,8 @@ class Text(Shape):
|
|
|
191
193
|
blitImageToSurface(surface, self.img, (self.__leftTop__[0], y))
|
|
192
194
|
|
|
193
195
|
def drawSvg(self, doc):
|
|
196
|
+
if self.__hidden__ or self.img.width == 0 or self.img.height == 0:
|
|
197
|
+
return
|
|
194
198
|
kaxe_top = self.__center__[1] + self.height / 2
|
|
195
199
|
svg_top = doc.flip_y(kaxe_top)
|
|
196
200
|
rotate_center = (
|
|
@@ -277,6 +277,11 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
277
277
|
self.pan_camera_start_x: float = 0.0
|
|
278
278
|
self.pan_camera_start_y: float = 0.0
|
|
279
279
|
|
|
280
|
+
# Key state handler for live modifier tracking (Cmd, Ctrl, Shift)
|
|
281
|
+
self.keys = key.KeyStateHandler()
|
|
282
|
+
self.push_handlers(self.keys)
|
|
283
|
+
self.current_modifiers: int = 0
|
|
284
|
+
|
|
280
285
|
self.show_hud: bool = True
|
|
281
286
|
self.notification_text: str = ""
|
|
282
287
|
self.notification_expiry: float = 0.0
|
|
@@ -307,7 +312,7 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
307
312
|
)
|
|
308
313
|
|
|
309
314
|
self.hud_right = pyglet.text.Label(
|
|
310
|
-
"[Drag] Move card / Pan [Scroll] Zoom [
|
|
315
|
+
"[Drag] Move card / Pan [Cmd+Scroll] Zoom [Scroll] Pan [A] Arrange [Space] Fit",
|
|
311
316
|
font_size=11,
|
|
312
317
|
x=self.width - 15,
|
|
313
318
|
y=15,
|
|
@@ -489,19 +494,90 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
489
494
|
self.dragging_card = None
|
|
490
495
|
self.is_panning_camera = False
|
|
491
496
|
|
|
497
|
+
def is_zoom_modifier_pressed(self) -> bool:
|
|
498
|
+
"""Return True if Meta (Command) or Control key is held down."""
|
|
499
|
+
if sys.platform == "darwin":
|
|
500
|
+
try:
|
|
501
|
+
from pyglet.libs.darwin import cocoapy
|
|
502
|
+
flags = cocoapy.NSEvent.modifierFlags()
|
|
503
|
+
if flags & (cocoapy.NSCommandKeyMask | cocoapy.NSControlKeyMask):
|
|
504
|
+
return True
|
|
505
|
+
except Exception:
|
|
506
|
+
pass
|
|
507
|
+
|
|
508
|
+
if hasattr(self, "keys") and self.keys is not None:
|
|
509
|
+
if (
|
|
510
|
+
self.keys[key.LCOMMAND]
|
|
511
|
+
or self.keys[key.RCOMMAND]
|
|
512
|
+
or self.keys[key.LCTRL]
|
|
513
|
+
or self.keys[key.RCTRL]
|
|
514
|
+
):
|
|
515
|
+
return True
|
|
516
|
+
|
|
517
|
+
if getattr(self, "current_modifiers", 0) & (key.MOD_COMMAND | key.MOD_CTRL):
|
|
518
|
+
return True
|
|
519
|
+
|
|
520
|
+
return False
|
|
521
|
+
|
|
522
|
+
def is_shift_pressed(self) -> bool:
|
|
523
|
+
"""Return True if Shift key is held down."""
|
|
524
|
+
if sys.platform == "darwin":
|
|
525
|
+
try:
|
|
526
|
+
from pyglet.libs.darwin import cocoapy
|
|
527
|
+
flags = cocoapy.NSEvent.modifierFlags()
|
|
528
|
+
if flags & cocoapy.NSShiftKeyMask:
|
|
529
|
+
return True
|
|
530
|
+
except Exception:
|
|
531
|
+
pass
|
|
532
|
+
|
|
533
|
+
if hasattr(self, "keys") and self.keys is not None:
|
|
534
|
+
if self.keys[key.LSHIFT] or self.keys[key.RSHIFT]:
|
|
535
|
+
return True
|
|
536
|
+
|
|
537
|
+
if getattr(self, "current_modifiers", 0) & key.MOD_SHIFT:
|
|
538
|
+
return True
|
|
539
|
+
|
|
540
|
+
return False
|
|
541
|
+
|
|
492
542
|
def on_mouse_scroll(self, x: int, y: int, scroll_x: float, scroll_y: float):
|
|
493
|
-
"""
|
|
494
|
-
zoom_factor = 1.05 ** (-scroll_y)
|
|
495
|
-
new_zoom = max(0.04, min(self.zoom * zoom_factor, 20.0))
|
|
543
|
+
"""Scroll handler:
|
|
496
544
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
545
|
+
- If Meta (Cmd) or Control is held: ZOOM anchored at cursor.
|
|
546
|
+
- Otherwise: PAN canvas side-to-side and up/down without zooming.
|
|
547
|
+
"""
|
|
548
|
+
if hasattr(self, "keys") and self.keys is not None:
|
|
549
|
+
should_zoom = self.is_zoom_modifier_pressed()
|
|
550
|
+
else:
|
|
551
|
+
# Fallback for mock unit test instances
|
|
552
|
+
should_zoom = True
|
|
501
553
|
|
|
502
|
-
|
|
554
|
+
if should_zoom:
|
|
555
|
+
zoom_factor = 1.05 ** (-scroll_y)
|
|
556
|
+
new_zoom = max(0.04, min(self.zoom * zoom_factor, 25.0))
|
|
557
|
+
|
|
558
|
+
if hasattr(self, "width"):
|
|
559
|
+
wx, wy = self.screen_to_world(x, y)
|
|
560
|
+
self.camera_x = wx - (x - self.width / 2.0) / new_zoom
|
|
561
|
+
self.camera_y = wy - (y - self.height / 2.0) / new_zoom
|
|
562
|
+
|
|
563
|
+
self.zoom = new_zoom
|
|
564
|
+
else:
|
|
565
|
+
# Pan without zooming
|
|
566
|
+
dx = scroll_x
|
|
567
|
+
dy = scroll_y
|
|
568
|
+
|
|
569
|
+
# Holding Shift converts vertical wheel into horizontal pan
|
|
570
|
+
if self.is_shift_pressed() and dy != 0.0 and dx == 0.0:
|
|
571
|
+
dx = dy
|
|
572
|
+
dy = 0.0
|
|
573
|
+
|
|
574
|
+
pan_speed = 20.0
|
|
575
|
+
self.camera_x -= (dx * pan_speed) / self.zoom
|
|
576
|
+
self.camera_y += (dy * pan_speed) / self.zoom
|
|
503
577
|
|
|
504
578
|
def on_key_press(self, symbol: int, modifiers: int):
|
|
579
|
+
self.current_modifiers = modifiers
|
|
580
|
+
|
|
505
581
|
# Fit all
|
|
506
582
|
if symbol in (key.R, key.SPACE):
|
|
507
583
|
self.fit_all_cards()
|
|
@@ -537,6 +613,9 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
537
613
|
elif symbol == key.S:
|
|
538
614
|
self.save_selected_card()
|
|
539
615
|
|
|
616
|
+
def on_key_release(self, symbol: int, modifiers: int):
|
|
617
|
+
self.current_modifiers = modifiers
|
|
618
|
+
|
|
540
619
|
def copy_selected_card(self):
|
|
541
620
|
if not self.selected_card or not self.selected_card.current_version:
|
|
542
621
|
return
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.0.dev0
|
|
4
4
|
Summary: A small graphing tool for functions, points, equations and more
|
|
5
5
|
Author-email: Valter Yde Daugberg <valteryde@hotmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/valteryde/kaxe
|
|
@@ -87,7 +87,9 @@ When the viewer is open, `.show()` instantly streams plots to cards on your canv
|
|
|
87
87
|
**Canvas & Card Controls:**
|
|
88
88
|
* **Click & Drag on a Card**: Move that card freely across the canvas
|
|
89
89
|
* **Click & Drag on Empty Space**: Pan the camera across the workspace
|
|
90
|
-
* **
|
|
90
|
+
* **Two-Finger Scroll / Trackpad**: Pan canvas side-to-side and up/down without zooming
|
|
91
|
+
* **`[Shift]` + Scroll**: Pan horizontally (for 1D mouse wheels)
|
|
92
|
+
* **`[Cmd]` / `[Ctrl]` + Scroll**: Smooth zoom anchored to cursor
|
|
91
93
|
* **`[A]`**: Auto-arrange all cards in a neat row
|
|
92
94
|
* **`[Space]` or `[R]`**: Fit all cards on the canvas into view
|
|
93
95
|
* **`[1]`**: View canvas at 100% native pixel scale
|
|
@@ -220,6 +220,36 @@ def test_viewer_zoom_reversed_and_less_sensitive():
|
|
|
220
220
|
assert abs(window.zoom - 1.05) < 1e-6
|
|
221
221
|
|
|
222
222
|
|
|
223
|
+
def test_scroll_pans_side_to_side_without_zoom_modifier():
|
|
224
|
+
from unittest.mock import MagicMock
|
|
225
|
+
from kaxe.viewer.window import KaxeViewerWindow
|
|
226
|
+
from pyglet.window import key
|
|
227
|
+
|
|
228
|
+
window = object.__new__(KaxeViewerWindow)
|
|
229
|
+
window.keys = {key.LCOMMAND: False, key.RCOMMAND: False, key.LCTRL: False, key.RCTRL: False, key.LSHIFT: False, key.RSHIFT: False}
|
|
230
|
+
window.current_modifiers = 0
|
|
231
|
+
window.camera_x = 0.0
|
|
232
|
+
window.camera_y = 0.0
|
|
233
|
+
window.zoom = 1.0
|
|
234
|
+
|
|
235
|
+
# Horizontal scroll without Cmd/Ctrl -> pans horizontally, zoom stays unchanged!
|
|
236
|
+
window.on_mouse_scroll(x=400, y=300, scroll_x=2.0, scroll_y=0.0)
|
|
237
|
+
assert window.zoom == 1.0
|
|
238
|
+
assert window.camera_x < 0.0 # Camera moved left
|
|
239
|
+
|
|
240
|
+
# Vertical scroll without Cmd/Ctrl -> pans vertically, zoom stays unchanged!
|
|
241
|
+
orig_cam_x = window.camera_x
|
|
242
|
+
window.on_mouse_scroll(x=400, y=300, scroll_x=0.0, scroll_y=3.0)
|
|
243
|
+
assert window.zoom == 1.0
|
|
244
|
+
assert window.camera_x == orig_cam_x
|
|
245
|
+
assert window.camera_y > 0.0
|
|
246
|
+
|
|
247
|
+
# With Cmd key pressed -> zooms!
|
|
248
|
+
window.keys[key.LCOMMAND] = True
|
|
249
|
+
window.on_mouse_scroll(x=400, y=300, scroll_x=0.0, scroll_y=-1.0)
|
|
250
|
+
assert window.zoom > 1.0
|
|
251
|
+
|
|
252
|
+
|
|
223
253
|
def test_plot_id_chaining_and_streaming(monkeypatch):
|
|
224
254
|
import kaxe
|
|
225
255
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf
RENAMED
|
File without changes
|
{kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf
RENAMED
|
File without changes
|
{kaxe-1.8.1.dev5 → kaxe-1.9.0.dev0}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|