kaxe 1.8.1.dev4__tar.gz → 1.8.1.dev6__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.dev4/src/kaxe.egg-info → kaxe-1.8.1.dev6}/PKG-INFO +4 -2
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/README.md +3 -1
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/pyproject.toml +1 -1
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/viewer/window.py +109 -15
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6/src/kaxe.egg-info}/PKG-INFO +4 -2
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/tests/test_viewer.py +37 -5
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/LICENSE +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/MANIFEST.in +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/setup.cfg +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/__main__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/_require_3d.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/_require_viewer.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/chart/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/chart/bar.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/chart/box.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/chart/pie.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/chart/qqplot.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/cli.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/axis.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/bounds.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/color.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/backend.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/camera.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/helper.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/hud.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/objects/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/objects/color.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/objects/line.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/objects/point.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/objects/pointer.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/objects/triangle.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/openglrender.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/d3/translator.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/draw.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/fileloader.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/helper.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/ipython_display.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/legend.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/line.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/marker.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/palette.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/profiler.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/progress.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/round.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/shapes.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/styles.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/svg.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/svg_pdf.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/symbol.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/text.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/thin.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/core/window.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/data/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/data/excel.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/_lazy.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/arrow.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/bubble.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/contour.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/equation.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/fill.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/function.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/guide_grid.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/inequality.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/map.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/parameter.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/pillar.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d2/point.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d3/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d3/base.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d3/function.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d3/mesh.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d3/point.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/d3/potato.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/function.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/legend.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/mapdata.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/point.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/objects/text.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/_lazy.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/box.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/constants.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/d3/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/d3/axes.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/d3/geometry.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/d3/plot3d.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/d3/variants.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/double.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/empty.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/grid.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/log.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/polar.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/standard.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/themes.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/zoom.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/plot/zoom_connector.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/codec.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/context.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/document.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/registry.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/sample.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/sampled_curve.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/serializers.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/project/window.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.bright-roman.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.bright-semibold.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.bright-semiboldoblique.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.classical-serif-italic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.concrete-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.concrete-italic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.concrete-roman.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-bold.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-boldoblique.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-demi-condensed-demicondensed.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-medium.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.sans-serif-oblique.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-bold.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-boldslanted.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-extra-romanslanted.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-roman.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-upright-italic-uprightitalic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bold.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-bolditalic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-italic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-light.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-lightoblique.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-regular.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-italic.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.typewriter-text-variable-width-medium.ttf +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/readme.txt +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/logo-small.png +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/viewer/__init__.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/viewer/cli.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/viewer/client.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/viewer/server.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe.egg-info/SOURCES.txt +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe.egg-info/dependency_links.txt +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe.egg-info/entry_points.txt +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe.egg-info/requires.txt +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe.egg-info/top_level.txt +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/tests/test.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/tests/test2.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/tests/test3.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/tests/test_4.py +0 -0
- {kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/tests/test_5.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.8.1.
|
|
3
|
+
Version: 1.8.1.dev6
|
|
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
|
|
@@ -268,7 +268,19 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
268
268
|
|
|
269
269
|
# Mouse interaction state
|
|
270
270
|
self.dragging_card: Optional[PlotCard] = None
|
|
271
|
+
self.drag_offset_x: float = 0.0
|
|
272
|
+
self.drag_offset_y: float = 0.0
|
|
273
|
+
|
|
271
274
|
self.is_panning_camera: bool = False
|
|
275
|
+
self.pan_start_x: float = 0.0
|
|
276
|
+
self.pan_start_y: float = 0.0
|
|
277
|
+
self.pan_camera_start_x: float = 0.0
|
|
278
|
+
self.pan_camera_start_y: float = 0.0
|
|
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
|
|
272
284
|
|
|
273
285
|
self.show_hud: bool = True
|
|
274
286
|
self.notification_text: str = ""
|
|
@@ -300,7 +312,7 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
300
312
|
)
|
|
301
313
|
|
|
302
314
|
self.hud_right = pyglet.text.Label(
|
|
303
|
-
"[Drag] Move card / Pan [Scroll] Zoom [
|
|
315
|
+
"[Drag] Move card / Pan [Cmd+Scroll] Zoom [Scroll] Pan [A] Arrange [Space] Fit",
|
|
304
316
|
font_size=11,
|
|
305
317
|
x=self.width - 15,
|
|
306
318
|
y=15,
|
|
@@ -455,38 +467,117 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
455
467
|
self.cards.append(hit_card)
|
|
456
468
|
self.select_card(hit_card)
|
|
457
469
|
self.dragging_card = hit_card
|
|
470
|
+
# Anchor grab offset so dragging sticks directly to the cursor
|
|
471
|
+
self.drag_offset_x = wx - hit_card.world_x
|
|
472
|
+
self.drag_offset_y = wy - hit_card.world_y
|
|
458
473
|
else:
|
|
459
474
|
# Clicked empty canvas -> pan
|
|
460
475
|
self.select_card(None)
|
|
461
476
|
self.is_panning_camera = True
|
|
477
|
+
self.pan_start_x = x
|
|
478
|
+
self.pan_start_y = y
|
|
479
|
+
self.pan_camera_start_x = self.camera_x
|
|
480
|
+
self.pan_camera_start_y = self.camera_y
|
|
462
481
|
|
|
463
482
|
def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int):
|
|
464
483
|
if self.dragging_card:
|
|
465
|
-
#
|
|
466
|
-
|
|
467
|
-
self.dragging_card.
|
|
484
|
+
# Absolute position tracking: card sticks precisely to the cursor
|
|
485
|
+
wx, wy = self.screen_to_world(x, y)
|
|
486
|
+
self.dragging_card.world_x = wx - self.drag_offset_x
|
|
487
|
+
self.dragging_card.world_y = wy - self.drag_offset_y
|
|
468
488
|
elif self.is_panning_camera:
|
|
469
|
-
#
|
|
470
|
-
self.camera_x
|
|
471
|
-
self.camera_y
|
|
489
|
+
# Absolute canvas panning: workspace follows the mouse 1:1
|
|
490
|
+
self.camera_x = self.pan_camera_start_x - (x - self.pan_start_x) / self.zoom
|
|
491
|
+
self.camera_y = self.pan_camera_start_y - (y - self.pan_start_y) / self.zoom
|
|
472
492
|
|
|
473
493
|
def on_mouse_release(self, x: int, y: int, button: int, modifiers: int):
|
|
474
494
|
self.dragging_card = None
|
|
475
495
|
self.is_panning_camera = False
|
|
476
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
|
+
|
|
477
542
|
def on_mouse_scroll(self, x: int, y: int, scroll_x: float, scroll_y: float):
|
|
478
|
-
"""
|
|
479
|
-
zoom_factor = 1.05 ** (-scroll_y)
|
|
480
|
-
new_zoom = max(0.04, min(self.zoom * zoom_factor, 20.0))
|
|
543
|
+
"""Scroll handler:
|
|
481
544
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
|
486
553
|
|
|
487
|
-
|
|
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
|
|
488
577
|
|
|
489
578
|
def on_key_press(self, symbol: int, modifiers: int):
|
|
579
|
+
self.current_modifiers = modifiers
|
|
580
|
+
|
|
490
581
|
# Fit all
|
|
491
582
|
if symbol in (key.R, key.SPACE):
|
|
492
583
|
self.fit_all_cards()
|
|
@@ -522,6 +613,9 @@ class KaxeViewerWindow(pyglet.window.Window):
|
|
|
522
613
|
elif symbol == key.S:
|
|
523
614
|
self.save_selected_card()
|
|
524
615
|
|
|
616
|
+
def on_key_release(self, symbol: int, modifiers: int):
|
|
617
|
+
self.current_modifiers = modifiers
|
|
618
|
+
|
|
525
619
|
def copy_selected_card(self):
|
|
526
620
|
if not self.selected_card or not self.selected_card.current_version:
|
|
527
621
|
return
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaxe
|
|
3
|
-
Version: 1.8.1.
|
|
3
|
+
Version: 1.8.1.dev6
|
|
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
|
|
|
@@ -282,11 +312,13 @@ def test_canvas_multi_card_and_versioning():
|
|
|
282
312
|
assert window.cards[0].card_id == "graph_1"
|
|
283
313
|
assert window.cards[1].card_id == "graph_2"
|
|
284
314
|
|
|
285
|
-
# 4. Moving card changes its coordinates
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
window.
|
|
289
|
-
|
|
315
|
+
# 4. Moving card changes its coordinates via press and drag
|
|
316
|
+
card = window.cards[1]
|
|
317
|
+
sx, sy = window.world_to_screen(card.world_x + 20, card.world_y + 20)
|
|
318
|
+
window.on_mouse_press(int(sx), int(sy), button=1, modifiers=0)
|
|
319
|
+
orig_x = card.world_x
|
|
320
|
+
window.on_mouse_drag(int(sx + 50), int(sy + 20), dx=50, dy=20, buttons=1, modifiers=0)
|
|
321
|
+
assert card.world_x > orig_x
|
|
290
322
|
|
|
291
323
|
window.close()
|
|
292
324
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.bright-oblique.ttf
RENAMED
|
File without changes
|
{kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/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.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.concrete-bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/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.dev4 → kaxe-1.8.1.dev6}/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.dev4 → kaxe-1.8.1.dev6}/src/kaxe/resources/computer-modern-family/cmu.serif-italic.ttf
RENAMED
|
File without changes
|
{kaxe-1.8.1.dev4 → kaxe-1.8.1.dev6}/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
|