nodeeditor-qtpy 0.8.1__tar.gz → 0.8.2__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.
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/HISTORY.rst +87 -1
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/PKG-INFO +3 -1
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/README.md +2 -0
- nodeeditor_qtpy-0.8.2/docs/api/comment.md +8 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/index.md +1 -0
- nodeeditor_qtpy-0.8.2/docs/guides/comments.md +96 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/calc_window.py +30 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/mkdocs.yml +2 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/__init__.py +5 -1
- nodeeditor_qtpy-0.8.2/nodeeditor/node_comment.py +735 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graphics_cutline.py +9 -2
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graphics_node.py +78 -7
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graphics_view.py +10 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_icon_graphics_node.py +52 -6
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_scene.py +148 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_scene_history.py +27 -2
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/pyproject.toml +1 -1
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/pyproject.toml.orig +1 -1
- nodeeditor_qtpy-0.8.2/tests/test_130_comment.py +283 -0
- nodeeditor_qtpy-0.8.2/tests/test_210_label_geometry.py +120 -0
- nodeeditor_qtpy-0.8.2/tests/test_400_comment.py +94 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/CHANGES.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/LICENCE +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/CONTRIBUTING.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/color-scheme.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/content.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/edge.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/editor-widget.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/editor-window.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/graph.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/graphics.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/group.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/node.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/scene.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/serializable.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/socket-shapes.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/socket.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/api/utils.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/events.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/coding-standards.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/edge-labels.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/graph-algorithms.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/group-nodes.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/multi-input-nodes.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/node-grouping.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/node-labels.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/guides/socket-shapes.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/edge-labels.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/graph-algorithms.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/group-collapsed.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/group-nodes.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/multi-input.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/node-labels.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/quickstart.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/images/socket-shapes.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/index.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/installation.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/quickstart.md +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/screenshot-calculator.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/docs/screenshot-example.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/calculator_ss_1.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/calc_conf.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/calc_drag_listbox.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/calc_graph_inspector.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/calc_node_base.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/calc_sub_window.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/example.json +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/example2.json +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/example3.json +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/File Output.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/add.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/divide.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/dot.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/icons.psd +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/in.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/mul.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/out.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/status_icons.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/status_icons.psd +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/icons/sub.png +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/main.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/nodes/__init__.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/nodes/check.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/nodes/input.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/nodes/multi_input.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/nodes/operations.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/nodes/output.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/qss/nodeeditor-dark.qss +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/qss/nodeeditor.qss +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/qss/nodeeditor.styl +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_calculator/qss/nodeeditor_dark_resources.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_color_config.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_socket_shapes.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_test/graph.json +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_test/graph2.json +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/examples/example_test/main_ex2.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_colors_config.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_content_widget.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_decorators.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_edge.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_edge_dragging.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_edge_intersect.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_edge_rerouting.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_edge_snapping.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_edge_validators.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_editor_widget.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_editor_window.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graph.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graphics_edge.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graphics_edge_path.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graphics_scene.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_graphics_socket.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_group.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_group_node.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_icon_content_widget.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_multi_input_node.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_node.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_scene_clipboard.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_serializable.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_socket.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/node_socket_shapes.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/py.typed +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/qss/nodestyle.qss +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/utils.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/nodeeditor/utils_no_qt.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/requirements_docs.txt +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/tests/__init__.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/tests/test_000_import.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/tests/test_100_multi_input.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/tests/test_110_socket_shapes.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/tests/test_120_graph.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/tests/test_200_detail_policy.py +0 -0
- {nodeeditor_qtpy-0.8.1 → nodeeditor_qtpy-0.8.2}/tests/test_300_hover_colors.py +0 -0
|
@@ -1,12 +1,98 @@
|
|
|
1
1
|
History
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
-
Release history for **qtpy
|
|
4
|
+
Release history for **nodeeditor-qtpy**.
|
|
5
5
|
|
|
6
6
|
This file tracks releases of this project. For the pre-fork upstream
|
|
7
7
|
`PyNodeEditor <https://github.com/benbyjones/PyQtNodeEditor>`_ lineage that
|
|
8
8
|
this code started from, see `CHANGES.md <CHANGES.md>`_.
|
|
9
9
|
|
|
10
|
+
0.8.2 - 2026-10-25
|
|
11
|
+
------------------
|
|
12
|
+
|
|
13
|
+
**Fixes**
|
|
14
|
+
|
|
15
|
+
- A dragged node no longer leaves a stack of label plates behind it. Two
|
|
16
|
+
declared rectangles were smaller than what their items painted:
|
|
17
|
+
``QDMGraphicsNodeLabel`` declared the text while painting a rounded box
|
|
18
|
+
padded by 6x3 px, and ``QDMGraphicsNode`` / ``QDMIconGraphicsNode`` declared
|
|
19
|
+
their body while the label floats above it. Qt repaints a moved item by the
|
|
20
|
+
rectangle it declared at the old position and dirties its children only at
|
|
21
|
+
the new one, so the old plate was never cleared. The label now declares its
|
|
22
|
+
plate, ``textRect()`` keeps the text rectangle for callers that position it,
|
|
23
|
+
the nodes expose ``labelRect()`` and include it in their own rectangle, and a
|
|
24
|
+
label that moves, changes text or is hidden by the level of detail re-indexes
|
|
25
|
+
its node with ``prepareGeometryChange()``.
|
|
26
|
+
- ``QDMGraphicsCutline`` declared the bare polyline while stroking it with a
|
|
27
|
+
2px pen, so a moving cut line left the outer half of the stroke behind. Its
|
|
28
|
+
rectangle now accounts for the pen.
|
|
29
|
+
|
|
30
|
+
**Tests**
|
|
31
|
+
|
|
32
|
+
- Added ``tests/test_210_label_geometry.py``: the label declares its plate, a
|
|
33
|
+
node declares the label above it, hiding the label leaves the body alone, and
|
|
34
|
+
a node move dirties the plate's old position.
|
|
35
|
+
- The suite now runs 121 tests.
|
|
36
|
+
|
|
37
|
+
0.8.1 - 2026-10-21
|
|
38
|
+
------------------
|
|
39
|
+
|
|
40
|
+
**Features**
|
|
41
|
+
|
|
42
|
+
- Added ``nodeeditor.node_graph``: graph algorithms over a ``Scene`` without a
|
|
43
|
+
third-party graph library. ``topological_order`` (Kahn's algorithm, scene
|
|
44
|
+
order as the tie-break, raising ``GraphCycleError``), ``descendants`` and
|
|
45
|
+
``ancestors`` (breadth-first with a visited set), ``components`` (the
|
|
46
|
+
disconnected subgraphs, via union-find), ``cycles`` (one representative cycle
|
|
47
|
+
per cyclic region), and ``paths`` and ``shortest_path`` (parallel edges stay
|
|
48
|
+
distinct). Every algorithm is also a thin wrapper on ``Scene``, so
|
|
49
|
+
``scene.shortest_path(a, b)`` works without importing the module, and
|
|
50
|
+
``GraphCycleError`` is exported from the package.
|
|
51
|
+
- Added a graph inspector panel to the calculator example, which runs the
|
|
52
|
+
algorithms on the active graph and selects the matching node on the canvas.
|
|
53
|
+
- ``Node.markDescendantsDirty`` and ``markDescendantsInvalid`` now walk with
|
|
54
|
+
``descendants()`` instead of recursing. The old walk raised
|
|
55
|
+
``RecursionError`` on a cycle and on chains over 1000 nodes, and visited a
|
|
56
|
+
node once per path into it: a 42-node diamond graph took 4.5 s, now about
|
|
57
|
+
0.0002 s.
|
|
58
|
+
|
|
59
|
+
**Packaging**
|
|
60
|
+
|
|
61
|
+
- First release on PyPI, as ``nodeeditor-qtpy``. The import package stays
|
|
62
|
+
``nodeeditor``.
|
|
63
|
+
- Built with ``uv_build``; the ``hatchling`` configuration is kept as a
|
|
64
|
+
fallback and produces the same artifacts.
|
|
65
|
+
- Dependencies are ``qtpy`` and ``orjson`` only. The bindings are optional
|
|
66
|
+
extras, ``pyqt6`` and ``pyside6``, and any binding QtPy supports keeps
|
|
67
|
+
working. Python 3.10 and newer.
|
|
68
|
+
- The licence is an SPDX ``MIT`` expression and the licence file ships in the
|
|
69
|
+
wheel, with the upstream copyright retained.
|
|
70
|
+
- Uploads run from GitHub Actions with PEP 740 attestations, so PyPI records
|
|
71
|
+
provenance instead of showing "without provenance".
|
|
72
|
+
- ``nodeeditor.__version__`` now reports the version of the installed
|
|
73
|
+
distribution, and importing the package without a Qt binding raises an error
|
|
74
|
+
that names the extras to install.
|
|
75
|
+
|
|
76
|
+
**Docs**
|
|
77
|
+
|
|
78
|
+
- New documentation site at
|
|
79
|
+
https://azadkshitij.github.io/qtpy-nodeeditor/, built with MkDocs, the
|
|
80
|
+
Material theme and mkdocstrings. The API reference is generated from the
|
|
81
|
+
docstrings in the source, so it always matches the installed code.
|
|
82
|
+
- Added pages for the installation, a quick start, the event system and node
|
|
83
|
+
groups, and the guides now carry screenshots.
|
|
84
|
+
- Documented every public class, method and function in the package.
|
|
85
|
+
- The site is redeployed whenever a commit pushed to ``main`` carries
|
|
86
|
+
"publish" in its message.
|
|
87
|
+
|
|
88
|
+
**Tests**
|
|
89
|
+
|
|
90
|
+
- Added ``tests/test_120_graph.py`` for the algorithms, the ``Scene`` wrappers
|
|
91
|
+
and the dirty walk.
|
|
92
|
+
- Moved the hover colour test into ``tests/``, where it runs with the suite; it
|
|
93
|
+
was stranded in the repository root and never collected.
|
|
94
|
+
- The suite now runs 90 tests.
|
|
95
|
+
|
|
10
96
|
0.8 - 2026-10-21
|
|
11
97
|
----------------
|
|
12
98
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nodeeditor-qtpy
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: Framework for building node editors and graph UIs in Qt, independent of the Qt binding (PyQt5/PyQt6/PySide2/PySide6 via QtPy)
|
|
5
5
|
Keywords: node editor,nodeeditor,node graph,graph,visual programming,qt,qtpy,pyqt6,pyside6
|
|
6
6
|
Author: Azad Kshitij
|
|
@@ -50,6 +50,7 @@ PyQt6 and PySide6.
|
|
|
50
50
|
- support for implementing evaluation logic
|
|
51
51
|
- hovering effects, dragging edges, cutting lines, snapping and more
|
|
52
52
|
- node groups, multi-input nodes, custom socket shapes and color schemes
|
|
53
|
+
- canvas comments (sticky notes) with inline editing and serialization
|
|
53
54
|
- ready-made examples you can copy from
|
|
54
55
|
|
|
55
56
|
## Requirements
|
|
@@ -142,6 +143,7 @@ from nodeeditor import NodeEditorColorScheme, get_socket_shape
|
|
|
142
143
|
from nodeeditor.node_scene import Scene
|
|
143
144
|
from nodeeditor.node_node import Node
|
|
144
145
|
from nodeeditor.node_edge import Edge
|
|
146
|
+
from nodeeditor.node_comment import Comment
|
|
145
147
|
```
|
|
146
148
|
|
|
147
149
|
## Credits
|
|
@@ -18,6 +18,7 @@ PyQt6 and PySide6.
|
|
|
18
18
|
- support for implementing evaluation logic
|
|
19
19
|
- hovering effects, dragging edges, cutting lines, snapping and more
|
|
20
20
|
- node groups, multi-input nodes, custom socket shapes and color schemes
|
|
21
|
+
- canvas comments (sticky notes) with inline editing and serialization
|
|
21
22
|
- ready-made examples you can copy from
|
|
22
23
|
|
|
23
24
|
## Requirements
|
|
@@ -110,6 +111,7 @@ from nodeeditor import NodeEditorColorScheme, get_socket_shape
|
|
|
110
111
|
from nodeeditor.node_scene import Scene
|
|
111
112
|
from nodeeditor.node_node import Node
|
|
112
113
|
from nodeeditor.node_edge import Edge
|
|
114
|
+
from nodeeditor.node_comment import Comment
|
|
113
115
|
```
|
|
114
116
|
|
|
115
117
|
## Credits
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
A `Comment` is a canvas note: a movable, selectable box that holds multi-line
|
|
2
|
+
plain text. It is a visual item like a `Group`, not a `Node`. It has no sockets,
|
|
3
|
+
never runs, and has no effect on evaluation.
|
|
4
|
+
|
|
5
|
+
See [Canvas comments](../guides/comments.md) for usage, editing semantics and
|
|
6
|
+
the serialized shape.
|
|
7
|
+
|
|
8
|
+
::: nodeeditor.node_comment
|
|
@@ -16,6 +16,7 @@ The package re-exports the pieces most applications need:
|
|
|
16
16
|
| [Scene](scene.md) | `node_scene`, `node_scene_clipboard`, `node_scene_history` |
|
|
17
17
|
| [Node](node.md) | `node_node`, `node_multi_input_node` |
|
|
18
18
|
| [Groups](group.md) | `node_group` |
|
|
19
|
+
| [Comments](comment.md) | `node_comment` |
|
|
19
20
|
| [Edge](edge.md) | `node_edge` and the edge interaction helpers |
|
|
20
21
|
| [Socket](socket.md) | `node_socket` |
|
|
21
22
|
| [Socket shapes](socket-shapes.md) | `node_socket_shapes` |
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Canvas comments
|
|
2
|
+
|
|
3
|
+
A `Comment` is a canvas note: a movable, selectable box that holds multi-line
|
|
4
|
+
plain text. It is a visual item like a `Group`, not a `Node`. It has no sockets,
|
|
5
|
+
never runs, and has no effect on evaluation.
|
|
6
|
+
|
|
7
|
+
Use `Scene.addComment()` as the short form:
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
note = scene.addComment(
|
|
11
|
+
"Remember to tune this after the first run.",
|
|
12
|
+
x=40, y=25, width=260,
|
|
13
|
+
)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or construct one directly. Both forms register the note with the scene:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from nodeeditor.node_comment import Comment
|
|
20
|
+
|
|
21
|
+
note = Comment(scene, "text", x=40, y=25, width=260, height=120)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The note auto-sizes: its width is the requested width (at least
|
|
25
|
+
`Comment.MIN_WIDTH`) and its height grows to fit the wrapped text, never below
|
|
26
|
+
`Comment.MIN_HEIGHT`. `setSize(w, h)` changes the requested size and
|
|
27
|
+
`setText()` replaces the text.
|
|
28
|
+
|
|
29
|
+
## Editing
|
|
30
|
+
|
|
31
|
+
Double-click the note, or call `begin_edit()`, to open the inline editor.
|
|
32
|
+
Editing ends in one of these ways:
|
|
33
|
+
|
|
34
|
+
- Focus leaves the editor (clicking elsewhere): the text is committed and a
|
|
35
|
+
`"Edited comment"` history entry is stored.
|
|
36
|
+
- `Escape` is pressed: the edit is cancelled and the text from before the edit
|
|
37
|
+
is restored. No history entry is stored.
|
|
38
|
+
- `Ctrl+Enter` is pressed, or `finish_edit()` is called: the text is committed.
|
|
39
|
+
- `cancel_edit()` is called: the edit is cancelled explicitly.
|
|
40
|
+
|
|
41
|
+
`setText(text, store_history=True)` also stores a history entry. The default
|
|
42
|
+
`store_history=False` keeps generated text and scene loading out of the undo
|
|
43
|
+
stack. History stamps snapshot the whole scene, and comments are part of that
|
|
44
|
+
snapshot, so undo and redo restore comment text, position, size, colours and
|
|
45
|
+
z-order.
|
|
46
|
+
|
|
47
|
+
## Colours and order
|
|
48
|
+
|
|
49
|
+
The defaults are theme-neutral, so the library does not read an application
|
|
50
|
+
theme manager:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
note.setBackgroundColor("#fff8d6")
|
|
54
|
+
note.setBorderColor((190, 175, 120))
|
|
55
|
+
note.setTextColor("#222222")
|
|
56
|
+
note.setColors(background="#e8f0ff", border="#8aa4c8")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Each setter accepts a `QColor`, a colour name or an RGB/RGBA tuple. Moving a
|
|
60
|
+
note updates its scene position. `bringToFront()`, `sendToBack()` and
|
|
61
|
+
`resetZValue()` change the stacking order; the z-value is saved with the note.
|
|
62
|
+
|
|
63
|
+
## Selection and removal
|
|
64
|
+
|
|
65
|
+
Notes are ordinary selectable items, so rubber-band selection and `Shift`
|
|
66
|
+
selection work. `Scene.getSelectedComments()` returns the selected notes.
|
|
67
|
+
`Delete` removes them through `QDMGraphicsView.deleteSelected()`, and the
|
|
68
|
+
context menu offers edit, order and delete actions. `note.remove()` removes a
|
|
69
|
+
note programmatically; the caller decides whether to store a history entry.
|
|
70
|
+
|
|
71
|
+
## Serialization
|
|
72
|
+
|
|
73
|
+
Comments are stored in the additive `Scene` key `"comments"`. Files written
|
|
74
|
+
before comments existed have no such key and load unchanged.
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"id": 1234,
|
|
79
|
+
"type": "Comment",
|
|
80
|
+
"version": 1,
|
|
81
|
+
"text": "first line\nsecond line",
|
|
82
|
+
"x": 40.0,
|
|
83
|
+
"y": 25.0,
|
|
84
|
+
"w": 240.0,
|
|
85
|
+
"h": 110.0,
|
|
86
|
+
"z": 1.0,
|
|
87
|
+
"style": {
|
|
88
|
+
"background": [255, 248, 214, 232],
|
|
89
|
+
"border": [190, 175, 120, 255],
|
|
90
|
+
"text": [35, 35, 35, 255]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`w` and `h` are the outer size after auto-sizing; `z` is the item z-value.
|
|
96
|
+
Missing `style` or `z` keys fall back to the neutral defaults.
|
|
@@ -135,6 +135,11 @@ class CalculatorWindow(NodeEditorWindow):
|
|
|
135
135
|
triggered=self.showSelectedPath)
|
|
136
136
|
self.actShortestPath.setShortcut(QKeySequence("Ctrl+Shift+P"))
|
|
137
137
|
|
|
138
|
+
self.actNewComment = QAction("&New Comment", self,
|
|
139
|
+
statusTip="Add a sticky note to the canvas",
|
|
140
|
+
triggered=self.onAddComment)
|
|
141
|
+
self.actNewComment.setShortcut(QKeySequence("Ctrl+Shift+N"))
|
|
142
|
+
|
|
138
143
|
def getCurrentScene(self):
|
|
139
144
|
"""Shortcut for the `Scene` of the active tab, or ``None``."""
|
|
140
145
|
active = self.getCurrentNodeEditorWidget()
|
|
@@ -214,6 +219,10 @@ class CalculatorWindow(NodeEditorWindow):
|
|
|
214
219
|
def createMenus(self):
|
|
215
220
|
super().createMenus()
|
|
216
221
|
|
|
222
|
+
# "New Comment" belongs next to the other Edit-menu editing actions.
|
|
223
|
+
self.editMenu.addSeparator()
|
|
224
|
+
self.editMenu.addAction(self.actNewComment)
|
|
225
|
+
|
|
217
226
|
self.graphMenu = self.menuBar().addMenu("&Graph")
|
|
218
227
|
self.graphMenu.addAction(self.actTopologicalOrder)
|
|
219
228
|
self.graphMenu.addAction(self.actComponents)
|
|
@@ -255,6 +264,7 @@ class CalculatorWindow(NodeEditorWindow):
|
|
|
255
264
|
self.actComponents.setEnabled(hasMdiChild)
|
|
256
265
|
self.actCycles.setEnabled(hasMdiChild)
|
|
257
266
|
self.actShortestPath.setEnabled(hasMdiChild)
|
|
267
|
+
self.actNewComment.setEnabled(hasMdiChild)
|
|
258
268
|
|
|
259
269
|
self.updateEditMenu()
|
|
260
270
|
|
|
@@ -290,6 +300,26 @@ class CalculatorWindow(NodeEditorWindow):
|
|
|
290
300
|
# gridAct.setChecked(self.scene.grScene.showGrid)
|
|
291
301
|
# gridAct.triggered.connect(self.onShowGrid)
|
|
292
302
|
|
|
303
|
+
def onAddComment(self):
|
|
304
|
+
"""Add a sticky note at the center of the active canvas and edit it."""
|
|
305
|
+
scene = self.getCurrentScene()
|
|
306
|
+
if scene is None:
|
|
307
|
+
self.statusBar().showMessage("Open a graph before adding a comment", 3000)
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
try:
|
|
311
|
+
view = self.getCurrentNodeEditorWidget().view
|
|
312
|
+
center = view.mapToScene(view.viewport().rect().center())
|
|
313
|
+
x, y = center.x(), center.y()
|
|
314
|
+
except Exception:
|
|
315
|
+
x, y = 0, 0
|
|
316
|
+
|
|
317
|
+
comment = scene.addComment("", x=x, y=y, width=240)
|
|
318
|
+
comment.begin_edit()
|
|
319
|
+
self.statusBar().showMessage(
|
|
320
|
+
"Comment added. Type your note, then click away or press Ctrl+Enter to save.",
|
|
321
|
+
4000)
|
|
322
|
+
|
|
293
323
|
def onShowGrid(self, checked: bool) -> None:
|
|
294
324
|
"""
|
|
295
325
|
Toggle the grid visibility for all subwindows
|
|
@@ -87,6 +87,7 @@ nav:
|
|
|
87
87
|
- Events: events.md
|
|
88
88
|
- Guides:
|
|
89
89
|
- Group nodes: guides/group-nodes.md
|
|
90
|
+
- Canvas comments: guides/comments.md
|
|
90
91
|
- Node grouping (reference): guides/node-grouping.md
|
|
91
92
|
- Multi-input nodes: guides/multi-input-nodes.md
|
|
92
93
|
- Graph algorithms: guides/graph-algorithms.md
|
|
@@ -99,6 +100,7 @@ nav:
|
|
|
99
100
|
- Scene: api/scene.md
|
|
100
101
|
- Node: api/node.md
|
|
101
102
|
- Groups: api/group.md
|
|
103
|
+
- Comments: api/comment.md
|
|
102
104
|
- Edge: api/edge.md
|
|
103
105
|
- Socket: api/socket.md
|
|
104
106
|
- Socket shapes: api/socket-shapes.md
|
|
@@ -9,7 +9,7 @@ __author__ = 'Azad Kshitij'
|
|
|
9
9
|
try:
|
|
10
10
|
__version__ = _dist_version("nodeeditor-qtpy")
|
|
11
11
|
except PackageNotFoundError: # running from a source checkout
|
|
12
|
-
__version__ = "0.8.
|
|
12
|
+
__version__ = "0.8.2"
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
_QT_API_NAME, _QT_API_VERSION = None, None
|
|
@@ -74,6 +74,9 @@ from nodeeditor.node_socket_shapes import (
|
|
|
74
74
|
# Export the graph algorithm exception
|
|
75
75
|
from nodeeditor.node_graph import GraphCycleError
|
|
76
76
|
|
|
77
|
+
# Export the canvas note item for convenient construction
|
|
78
|
+
from nodeeditor.node_comment import Comment
|
|
79
|
+
|
|
77
80
|
|
|
78
81
|
__all__ = [
|
|
79
82
|
"NodeEditorColorScheme",
|
|
@@ -90,4 +93,5 @@ __all__ = [
|
|
|
90
93
|
"get_socket_shape",
|
|
91
94
|
"SOCKET_SHAPES",
|
|
92
95
|
"GraphCycleError",
|
|
96
|
+
"Comment",
|
|
93
97
|
]
|