py2max 0.2.1__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.
- py2max-0.2.1/CHANGELOG.md +559 -0
- py2max-0.2.1/LICENSE +19 -0
- py2max-0.2.1/PKG-INFO +390 -0
- py2max-0.2.1/README.md +355 -0
- py2max-0.2.1/py2max/__init__.py +67 -0
- py2max-0.2.1/py2max/__main__.py +6 -0
- py2max-0.2.1/py2max/cli.py +1251 -0
- py2max-0.2.1/py2max/core/__init__.py +39 -0
- py2max-0.2.1/py2max/core/abstract.py +146 -0
- py2max-0.2.1/py2max/core/box.py +231 -0
- py2max-0.2.1/py2max/core/common.py +19 -0
- py2max-0.2.1/py2max/core/patcher.py +1658 -0
- py2max-0.2.1/py2max/core/patchline.py +68 -0
- py2max-0.2.1/py2max/exceptions.py +385 -0
- py2max-0.2.1/py2max/export/__init__.py +20 -0
- py2max-0.2.1/py2max/export/converters.py +345 -0
- py2max-0.2.1/py2max/export/svg.py +393 -0
- py2max-0.2.1/py2max/layout/__init__.py +26 -0
- py2max-0.2.1/py2max/layout/base.py +463 -0
- py2max-0.2.1/py2max/layout/flow.py +405 -0
- py2max-0.2.1/py2max/layout/grid.py +374 -0
- py2max-0.2.1/py2max/layout/matrix.py +628 -0
- py2max-0.2.1/py2max/log.py +338 -0
- py2max-0.2.1/py2max/maxref/__init__.py +78 -0
- py2max-0.2.1/py2max/maxref/category.py +163 -0
- py2max-0.2.1/py2max/maxref/db.py +1082 -0
- py2max-0.2.1/py2max/maxref/legacy.py +324 -0
- py2max-0.2.1/py2max/maxref/parser.py +703 -0
- py2max-0.2.1/py2max/py.typed +0 -0
- py2max-0.2.1/py2max/server/__init__.py +54 -0
- py2max-0.2.1/py2max/server/client.py +295 -0
- py2max-0.2.1/py2max/server/inline.py +312 -0
- py2max-0.2.1/py2max/server/repl.py +561 -0
- py2max-0.2.1/py2max/server/rpc.py +240 -0
- py2max-0.2.1/py2max/server/websocket.py +997 -0
- py2max-0.2.1/py2max/static/cola.min.js +4 -0
- py2max-0.2.1/py2max/static/d3.v7.min.js +2 -0
- py2max-0.2.1/py2max/static/dagre-bundle.js +328 -0
- py2max-0.2.1/py2max/static/elk.bundled.js +6663 -0
- py2max-0.2.1/py2max/static/index.html +168 -0
- py2max-0.2.1/py2max/static/interactive.html +589 -0
- py2max-0.2.1/py2max/static/interactive.js +2111 -0
- py2max-0.2.1/py2max/static/live-preview.js +324 -0
- py2max-0.2.1/py2max/static/svg.min.js +13 -0
- py2max-0.2.1/py2max/static/svg.min.js.map +1 -0
- py2max-0.2.1/py2max/transformers.py +168 -0
- py2max-0.2.1/py2max/utils.py +83 -0
- py2max-0.2.1/pyproject.toml +77 -0
- py2max-0.2.1/tests/__init__.py +0 -0
- py2max-0.2.1/tests/data/complex.maxpat +1348 -0
- py2max-0.2.1/tests/data/desc.maxpat +136 -0
- py2max-0.2.1/tests/data/empty.maxpat +47 -0
- py2max-0.2.1/tests/data/nested.maxpat +181 -0
- py2max-0.2.1/tests/data/simple.maxpat +86 -0
- py2max-0.2.1/tests/data/tabular.maxpat +216 -0
- py2max-0.2.1/tests/data/umenu.maxref.xml +1129 -0
- py2max-0.2.1/tests/examples/README.md +92 -0
- py2max-0.2.1/tests/examples/advanced/connection_patterns.py +128 -0
- py2max-0.2.1/tests/examples/advanced/custom_extensions.py +192 -0
- py2max-0.2.1/tests/examples/advanced/data_containers.py +140 -0
- py2max-0.2.1/tests/examples/advanced/error_handling.py +162 -0
- py2max-0.2.1/tests/examples/advanced/performance_optimization.py +131 -0
- py2max-0.2.1/tests/examples/advanced/subpatchers.py +90 -0
- py2max-0.2.1/tests/examples/api/box_api_examples.py +249 -0
- py2max-0.2.1/tests/examples/api/patcher_api_examples.py +225 -0
- py2max-0.2.1/tests/examples/auto_layout_demo.py +205 -0
- py2max-0.2.1/tests/examples/db/category_db_demo.py +136 -0
- py2max-0.2.1/tests/examples/db/maxref_db_demo.py +108 -0
- py2max-0.2.1/tests/examples/info_command_demo.py +106 -0
- py2max-0.2.1/tests/examples/inline_repl_verification.py +64 -0
- py2max-0.2.1/tests/examples/interactive_demo.py +228 -0
- py2max-0.2.1/tests/examples/interactive_save_demo.py +164 -0
- py2max-0.2.1/tests/examples/layout/columnar_layout_examples.py +169 -0
- py2max-0.2.1/tests/examples/layout/flow_layout_examples.py +210 -0
- py2max-0.2.1/tests/examples/layout/grid_layout_examples.py +181 -0
- py2max-0.2.1/tests/examples/layout/matrix_layout_examples.py +286 -0
- py2max-0.2.1/tests/examples/live_preview_demo.py +225 -0
- py2max-0.2.1/tests/examples/preview/basic_synth.maxpat +180 -0
- py2max-0.2.1/tests/examples/preview/basic_synth.svg +39 -0
- py2max-0.2.1/tests/examples/preview/complex_synth.maxpat +379 -0
- py2max-0.2.1/tests/examples/preview/complex_synth.svg +71 -0
- py2max-0.2.1/tests/examples/preview/flow_layout.maxpat +198 -0
- py2max-0.2.1/tests/examples/preview/flow_layout.svg +45 -0
- py2max-0.2.1/tests/examples/preview/grid_layout.maxpat +198 -0
- py2max-0.2.1/tests/examples/preview/grid_layout.svg +45 -0
- py2max-0.2.1/tests/examples/preview/horizontal_layout.maxpat +198 -0
- py2max-0.2.1/tests/examples/preview/horizontal_layout.svg +45 -0
- py2max-0.2.1/tests/examples/preview/styled_no_ports.svg +22 -0
- py2max-0.2.1/tests/examples/preview/styled_no_title.svg +27 -0
- py2max-0.2.1/tests/examples/preview/styled_patch.maxpat +105 -0
- py2max-0.2.1/tests/examples/preview/styled_with_ports.svg +29 -0
- py2max-0.2.1/tests/examples/preview/svg_preview_demo.py +255 -0
- py2max-0.2.1/tests/examples/preview/vertical_layout.maxpat +198 -0
- py2max-0.2.1/tests/examples/preview/vertical_layout.svg +45 -0
- py2max-0.2.1/tests/examples/preview/workflow_demo.maxpat +242 -0
- py2max-0.2.1/tests/examples/preview/workflow_demo.svg +50 -0
- py2max-0.2.1/tests/examples/quickstart/basic_patch.py +43 -0
- py2max-0.2.1/tests/examples/quickstart/layout_examples.py +128 -0
- py2max-0.2.1/tests/examples/refresh_function_verification.py +54 -0
- py2max-0.2.1/tests/examples/repl_client_server_demo.py +171 -0
- py2max-0.2.1/tests/examples/repl_quickstart.py +140 -0
- py2max-0.2.1/tests/examples/tutorial/generative_music.py +104 -0
- py2max-0.2.1/tests/examples/tutorial/interactive_controller.py +77 -0
- py2max-0.2.1/tests/examples/tutorial/signal_processing_chain.py +84 -0
- py2max-0.2.1/tests/examples/tutorial/simple_synthesis.py +66 -0
- py2max-0.2.1/tests/graphs/random/v30e33.tglf +64 -0
- py2max-0.2.1/tests/registry.py +1526 -0
- py2max-0.2.1/tests/scratch.py +80 -0
- py2max-0.2.1/tests/test_abstract_coverage.py +286 -0
- py2max-0.2.1/tests/test_abstraction.py +21 -0
- py2max-0.2.1/tests/test_add.py +65 -0
- py2max-0.2.1/tests/test_attrui.py +54 -0
- py2max-0.2.1/tests/test_basic.py +11 -0
- py2max-0.2.1/tests/test_beap.py +9 -0
- py2max-0.2.1/tests/test_bpatcher.py +20 -0
- py2max-0.2.1/tests/test_cli.py +409 -0
- py2max-0.2.1/tests/test_coll.py +16 -0
- py2max-0.2.1/tests/test_colors.py +9 -0
- py2max-0.2.1/tests/test_comment.py +8 -0
- py2max-0.2.1/tests/test_connection_validation.py +182 -0
- py2max-0.2.1/tests/test_converters.py +167 -0
- py2max-0.2.1/tests/test_core_coverage.py +164 -0
- py2max-0.2.1/tests/test_db.py +884 -0
- py2max-0.2.1/tests/test_defaults.py +11 -0
- py2max-0.2.1/tests/test_dict.py +7 -0
- py2max-0.2.1/tests/test_error_handling.py +319 -0
- py2max-0.2.1/tests/test_examples.py +473 -0
- py2max-0.2.1/tests/test_ezdac.py +10 -0
- py2max-0.2.1/tests/test_gen.py +27 -0
- py2max-0.2.1/tests/test_group.py +41 -0
- py2max-0.2.1/tests/test_itable.py +7 -0
- py2max-0.2.1/tests/test_js.py +55 -0
- py2max-0.2.1/tests/test_kwds_filter.py +116 -0
- py2max-0.2.1/tests/test_layout.py +13 -0
- py2max-0.2.1/tests/test_layout_builtins.py +414 -0
- py2max-0.2.1/tests/test_layout_coverage.py +233 -0
- py2max-0.2.1/tests/test_layout_flow.py +287 -0
- py2max-0.2.1/tests/test_layout_graph_layout.py +113 -0
- py2max-0.2.1/tests/test_layout_hola1.py +114 -0
- py2max-0.2.1/tests/test_layout_hola2.py +100 -0
- py2max-0.2.1/tests/test_layout_hola3.py +123 -0
- py2max-0.2.1/tests/test_layout_hola_graph.py +124 -0
- py2max-0.2.1/tests/test_layout_matrix.py +760 -0
- py2max-0.2.1/tests/test_layout_networkx1.py +128 -0
- py2max-0.2.1/tests/test_layout_networkx2.py +96 -0
- py2max-0.2.1/tests/test_layout_nx_graphviz.py +96 -0
- py2max-0.2.1/tests/test_layout_nx_orthogonal.py +120 -0
- py2max-0.2.1/tests/test_layout_nx_tsmpy.py +108 -0
- py2max-0.2.1/tests/test_layout_vertical.py +43 -0
- py2max-0.2.1/tests/test_linking.py +40 -0
- py2max-0.2.1/tests/test_maxref.py +470 -0
- py2max-0.2.1/tests/test_mc_cycle.py +7 -0
- py2max-0.2.1/tests/test_message.py +7 -0
- py2max-0.2.1/tests/test_mypatch.py +12 -0
- py2max-0.2.1/tests/test_nested.py +18 -0
- py2max-0.2.1/tests/test_nested_patchers.py +279 -0
- py2max-0.2.1/tests/test_number_tilde.py +52 -0
- py2max-0.2.1/tests/test_numbers.py +34 -0
- py2max-0.2.1/tests/test_param.py +8 -0
- py2max-0.2.1/tests/test_patcher.py +43 -0
- py2max-0.2.1/tests/test_pitched_osc.py +15 -0
- py2max-0.2.1/tests/test_pydantic.py +160 -0
- py2max-0.2.1/tests/test_repl.py +309 -0
- py2max-0.2.1/tests/test_repl_client.py +348 -0
- py2max-0.2.1/tests/test_repl_inline.py +283 -0
- py2max-0.2.1/tests/test_repl_server.py +316 -0
- py2max-0.2.1/tests/test_rnbo.py +146 -0
- py2max-0.2.1/tests/test_rnbo_subpatcher.py +19 -0
- py2max-0.2.1/tests/test_scripting_name.py +7 -0
- py2max-0.2.1/tests/test_search.py +166 -0
- py2max-0.2.1/tests/test_semantic_ids.py +258 -0
- py2max-0.2.1/tests/test_subpatch.py +17 -0
- py2max-0.2.1/tests/test_svg.py +331 -0
- py2max-0.2.1/tests/test_table.py +68 -0
- py2max-0.2.1/tests/test_transformers.py +54 -0
- py2max-0.2.1/tests/test_tree.py +74 -0
- py2max-0.2.1/tests/test_tree_builder.py +193 -0
- py2max-0.2.1/tests/test_tutorial_simple_synthesis.py +44 -0
- py2max-0.2.1/tests/test_two_sines.py +47 -0
- py2max-0.2.1/tests/test_umenu.py +11 -0
- py2max-0.2.1/tests/test_utils.py +18 -0
- py2max-0.2.1/tests/test_varname.py +11 -0
- py2max-0.2.1/tests/test_websocket.py +232 -0
- py2max-0.2.1/tests/test_zl_group.py +11 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.2.1] - 2026-01-11
|
|
6
|
+
|
|
7
|
+
### New: Dagre Layout Algorithm
|
|
8
|
+
|
|
9
|
+
- Added Dagre (Directed Acyclic Graph) as third layout algorithm option alongside WebCola and ELK
|
|
10
|
+
- Integrated `dagre-bundle.js` combining graphlib with require shim for browser compatibility
|
|
11
|
+
- Added Dagre-specific controls: Ranker (network-simplex, longest-path, tight-tree) and Align options
|
|
12
|
+
- Supports all flow directions: top-bottom, bottom-top, left-right, right-left
|
|
13
|
+
|
|
14
|
+
### Improved: Interactive Editor Visualization
|
|
15
|
+
|
|
16
|
+
- **ViewBox Scaling**: Dynamic padding (10% of content, min 30px, max 100px) with aspect ratio preservation
|
|
17
|
+
- **Port Position Safety**: Added bounds checking with `safeIndex` clamping to prevent invalid port positions
|
|
18
|
+
- **Patchline Animation**: Added `animatePatchlines()` method for smooth patchline transitions during layout
|
|
19
|
+
- **Layout Centering**: Added `centerLayout()` helper method - all three algorithms now center content within canvas
|
|
20
|
+
- **Delta Updates**: Position updates now send only changed box data instead of full patcher state
|
|
21
|
+
- Added `updateBoxPosition()` for efficient single-box DOM updates
|
|
22
|
+
- Added `updateConnectedLines()` to update patchlines without full re-render
|
|
23
|
+
- Significantly reduces bandwidth during drag operations
|
|
24
|
+
|
|
25
|
+
### Improved: FlowLayoutManager
|
|
26
|
+
|
|
27
|
+
- **Line Crossing Minimization**: Added `_minimize_crossings()` method using barycenter heuristic
|
|
28
|
+
- Objects within each level are reordered based on average position of connected objects in previous level
|
|
29
|
+
- Reduces visual line crossings for cleaner layouts
|
|
30
|
+
- **Negative Position Prevention**: Added bounds clamping and auto-scaling when content exceeds available space
|
|
31
|
+
- **Incremental Layout**: Supports `optimize_layout(changed_objects)` for efficient partial updates
|
|
32
|
+
|
|
33
|
+
### Improved: GridLayoutManager
|
|
34
|
+
|
|
35
|
+
- Fixed integer division to float division for consistent cluster positioning
|
|
36
|
+
- Now uses consistent float spacing within clusters
|
|
37
|
+
- **Incremental Layout**: Supports `optimize_layout(changed_objects)` for efficient partial updates
|
|
38
|
+
|
|
39
|
+
### Improved: WebSocket Server Security
|
|
40
|
+
|
|
41
|
+
- **Input Validation**: Added comprehensive schema-based message validation
|
|
42
|
+
- `MESSAGE_SCHEMAS` defines required fields and types for each message type
|
|
43
|
+
- `MAX_STRING_LENGTHS` prevents abuse (256 chars for IDs, 10000 for text, 4096 for filepaths)
|
|
44
|
+
- `COORDINATE_BOUNDS` validates positions (-100000 to 100000)
|
|
45
|
+
- Checks for control characters in strings
|
|
46
|
+
- Validates optional fields (outlet/inlet indices 0-255)
|
|
47
|
+
- Validation errors sent back to client as error messages
|
|
48
|
+
|
|
49
|
+
### New: Save As Dialog
|
|
50
|
+
|
|
51
|
+
- Added `save_as_required` message type when patcher has no filepath
|
|
52
|
+
- Added `handle_save_as()` handler for saving with specified filepath
|
|
53
|
+
- Added `showSaveAsDialog()` in JavaScript with filename prompt
|
|
54
|
+
- Automatically adds `.maxpat` extension if not provided
|
|
55
|
+
|
|
56
|
+
### Fixed: ELK Layout
|
|
57
|
+
|
|
58
|
+
- Fixed "Referenced shape does not exist" errors by validating edges before creating ports
|
|
59
|
+
- Ports now created based on actual connections, not just declared counts
|
|
60
|
+
|
|
61
|
+
### Fixed: Static File Paths
|
|
62
|
+
|
|
63
|
+
- Fixed 404 error for `interactive.html` by correcting static file path resolution
|
|
64
|
+
|
|
65
|
+
### Improved: Base LayoutManager
|
|
66
|
+
|
|
67
|
+
- Added `prevent_overlaps()` method for iterative overlap prevention
|
|
68
|
+
- **Incremental Layout System**: Added smart layout optimization that only repositions affected objects
|
|
69
|
+
- `optimize_layout(changed_objects)` accepts optional set of changed object IDs
|
|
70
|
+
- `should_use_incremental()` determines when to use incremental vs full layout (30% threshold)
|
|
71
|
+
- `get_affected_objects()` finds changed objects plus their connected neighbors
|
|
72
|
+
- `_incremental_layout()` repositions only affected objects using spiral search
|
|
73
|
+
- `_find_non_overlapping_position()` finds nearby positions that don't overlap with fixed objects
|
|
74
|
+
- `_full_layout()` for complete layout recalculation (subclasses override)
|
|
75
|
+
|
|
76
|
+
## [0.2.0]
|
|
77
|
+
|
|
78
|
+
### Updated: Optional Layout Dependencies
|
|
79
|
+
|
|
80
|
+
- Updated `pycola` dependency to `graph-layout` package (<https://github.com/shakfu/graph-layout>)
|
|
81
|
+
- Renamed test file from `test_layout_pycola.py` to `test_layout_graph_layout.py`
|
|
82
|
+
- Updated API to use `ColaLayoutAdapter` from `graph_layout` module
|
|
83
|
+
|
|
84
|
+
- Updated `pyhola` dependency to `hola-graph` package (<https://github.com/shakfu/hola-graph>)
|
|
85
|
+
- Renamed test file from `test_layout_pyhola.py` to `test_layout_hola_graph.py`
|
|
86
|
+
- Updated imports to use `hola_graph._core` module
|
|
87
|
+
|
|
88
|
+
- Fixed `test_layout_networkx2.py` to properly check for `pygraphviz` dependency
|
|
89
|
+
- Test now correctly skips when pygraphviz is not installed
|
|
90
|
+
|
|
91
|
+
### Simplified: Optional Dependencies
|
|
92
|
+
|
|
93
|
+
- Consolidated optional dependencies in `pyproject.toml` to single `server` option
|
|
94
|
+
- Removed `repl` and `all` options
|
|
95
|
+
- `server` now includes both `websockets` and `ptpython`
|
|
96
|
+
- Install with: `pip install py2max[server]`
|
|
97
|
+
|
|
98
|
+
### New: Interactive Editor - Advanced Layout with SVG.js, WebCola, and D3.js
|
|
99
|
+
|
|
100
|
+
- Added complete SVG.js (v3.2.5) integration for all SVG manipulation and animation in the interactive editor
|
|
101
|
+
|
|
102
|
+
- Added WebCola constraint-based force-directed graph layout engine with D3.js (v7) integration
|
|
103
|
+
|
|
104
|
+
- Added interactive auto-layout controls panel with real-time parameter adjustment
|
|
105
|
+
|
|
106
|
+
- Added 5 adjustable layout parameters via sliders and controls:
|
|
107
|
+
- **Link Distance** (50-300): Controls spacing between connected objects
|
|
108
|
+
- **Iterations** (10-200): Controls layout quality and convergence
|
|
109
|
+
- **Canvas Width** (400-1600): Adjustable layout area width
|
|
110
|
+
- **Canvas Height** (300-1200): Adjustable layout area height
|
|
111
|
+
- **Avoid Overlaps** (checkbox): Toggle automatic overlap prevention
|
|
112
|
+
|
|
113
|
+
- Added constraint-based layout system with 4 presets:
|
|
114
|
+
- **None**: Natural force-directed layout without alignment constraints
|
|
115
|
+
- **Horizontal Flow**: Aligns objects in horizontal rows (left-to-right signal flow)
|
|
116
|
+
- **Vertical Flow**: Aligns objects in vertical columns (top-to-bottom signal flow)
|
|
117
|
+
- **Grid**: Strict grid alignment with both row and column constraints
|
|
118
|
+
|
|
119
|
+
- Added smooth SVG.js animations (500ms ease-in-out) for layout transitions
|
|
120
|
+
|
|
121
|
+
- Added constraint generation algorithm that analyzes object positions and creates alignment constraints
|
|
122
|
+
|
|
123
|
+
- Added collapsible controls panel with "Apply Layout" and "Hide" buttons
|
|
124
|
+
|
|
125
|
+
- Added visual feedback showing active parameters and constraint count
|
|
126
|
+
|
|
127
|
+
**SVG.js Implementation:**
|
|
128
|
+
|
|
129
|
+
- Refactored all SVG rendering to use SVG.js declarative API instead of native DOM manipulation
|
|
130
|
+
- `initializeSVG()`: Creates SVG canvas and layer groups using SVG.js
|
|
131
|
+
- `createBox()`: Renders boxes with rectangles, text, and clipping paths using SVG.js
|
|
132
|
+
- `createLine()`: Renders connection lines with hitboxes using SVG.js
|
|
133
|
+
- `addPorts()`: Renders inlet/outlet circles using SVG.js
|
|
134
|
+
- `autoLayout()`: Animates box movements using SVG.js transforms
|
|
135
|
+
|
|
136
|
+
**WebCola Integration:**
|
|
137
|
+
|
|
138
|
+
- Force-directed graph layout with configurable parameters
|
|
139
|
+
- Constraint-based positioning using alignment constraints
|
|
140
|
+
- Automatic overlap avoidance with adjustable node dimensions
|
|
141
|
+
- Handles disconnected graph components gracefully
|
|
142
|
+
- Jaccard link lengths for natural connection spacing
|
|
143
|
+
|
|
144
|
+
**Constraint System:**
|
|
145
|
+
|
|
146
|
+
- Automatic constraint generation based on object proximity (50px threshold)
|
|
147
|
+
- Alignment constraints for horizontal rows (Y-axis alignment)
|
|
148
|
+
- Alignment constraints for vertical columns (X-axis alignment)
|
|
149
|
+
- Grid constraints combining both row and column alignment
|
|
150
|
+
- Real-time constraint application with visual feedback
|
|
151
|
+
|
|
152
|
+
**Documentation:**
|
|
153
|
+
|
|
154
|
+
- Added comprehensive `docs/LIBRARIES_INTEGRATION.md` (518 lines)
|
|
155
|
+
- Detailed parameter descriptions and effects
|
|
156
|
+
- Constraint preset usage examples
|
|
157
|
+
- Testing procedures and expected behavior
|
|
158
|
+
- Code examples and API documentation
|
|
159
|
+
- Performance considerations for different patch sizes
|
|
160
|
+
|
|
161
|
+
**Demo Scripts:**
|
|
162
|
+
|
|
163
|
+
- Added `examples/auto_layout_demo.py`: Complex synthesizer with randomized positions (13 objects, 16 connections)
|
|
164
|
+
- Hierarchical layout demo: Tree structure with multiple processing layers (12 objects)
|
|
165
|
+
|
|
166
|
+
**Benefits:**
|
|
167
|
+
|
|
168
|
+
- Professional animated transitions for all layout operations
|
|
169
|
+
- Interactive experimentation with layout parameters
|
|
170
|
+
- Structured layouts matching typical Max patch patterns
|
|
171
|
+
- Clean, maintainable SVG.js codebase
|
|
172
|
+
- Four layout presets for different use cases
|
|
173
|
+
- Real-time visual feedback
|
|
174
|
+
- Minimal overhead (234KB total: D3 + SVG.js + WebCola, minified)
|
|
175
|
+
|
|
176
|
+
**Example Usage:**
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Start interactive editor
|
|
180
|
+
py2max serve outputs/auto_layout_demo.maxpat
|
|
181
|
+
|
|
182
|
+
# In browser:
|
|
183
|
+
# 1. Click "Auto-Layout" to show controls
|
|
184
|
+
# 2. Adjust Link Distance slider (50-300)
|
|
185
|
+
# 3. Select Constraint Preset (Grid/Horizontal/Vertical/None)
|
|
186
|
+
# 4. Adjust Iterations for convergence quality
|
|
187
|
+
# 5. Click "Apply Layout" to see smooth animations
|
|
188
|
+
# 6. Experiment with different parameter combinations
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### New: Interactive Editor - Nested Patcher Navigation
|
|
192
|
+
|
|
193
|
+
- Added full nested patcher (subpatcher) navigation support in interactive editor
|
|
194
|
+
- Double-click on subpatcher boxes (blue dashed border) to navigate into them
|
|
195
|
+
- Navigate back using "Parent" button or ESC key
|
|
196
|
+
- Breadcrumb navigation displays current location (e.g., "Main / Oscillator / Envelope")
|
|
197
|
+
- Subpatcher boxes are fully interactive: draggable, connectable, deletable
|
|
198
|
+
- Visual distinction: subpatcher boxes have blue dashed borders and bold blue text
|
|
199
|
+
- Event delegation for reliable double-click detection even with dynamic DOM updates
|
|
200
|
+
- Automatic parent reference restoration when loading patches from files
|
|
201
|
+
|
|
202
|
+
**Server-Side Changes:**
|
|
203
|
+
|
|
204
|
+
- Modified `get_patcher_state_json()` to include `has_subpatcher` flag and `patcher_path` breadcrumb
|
|
205
|
+
- Added `handle_navigate_to_subpatcher()`, `handle_navigate_to_parent()`, `handle_navigate_to_root()` handlers
|
|
206
|
+
- Fixed inlet/outlet count detection to use `numinlets`/`numoutlets` attributes from loaded files
|
|
207
|
+
- Handler now tracks both `root_patcher` (for saving) and `patcher` (current view)
|
|
208
|
+
|
|
209
|
+
**Client-Side Changes:**
|
|
210
|
+
|
|
211
|
+
- Added breadcrumb UI showing patcher hierarchy
|
|
212
|
+
- Implemented event delegation for double-click handling on dynamically created boxes
|
|
213
|
+
- Fixed object positioning by flattening `patching_rect` into `x`, `y`, `width`, `height`
|
|
214
|
+
- CSS styling for subpatcher boxes with distinct visual appearance
|
|
215
|
+
- ESC key navigation support
|
|
216
|
+
|
|
217
|
+
**Core Changes:**
|
|
218
|
+
|
|
219
|
+
- Modified `Patcher.from_dict()` to set `_parent` references for nested subpatchers when loading from files
|
|
220
|
+
- Ensures bidirectional parent-child relationships for proper navigation
|
|
221
|
+
|
|
222
|
+
**Tests:**
|
|
223
|
+
|
|
224
|
+
- Added 14 comprehensive tests in `tests/test_nested_patchers.py`
|
|
225
|
+
- All tests passing (326 passed, 14 skipped)
|
|
226
|
+
|
|
227
|
+
**Demo:**
|
|
228
|
+
|
|
229
|
+
- Added `examples/nested_patcher_demo.py` with three demonstration patches:
|
|
230
|
+
- Synthesizer with nested envelope subpatcher
|
|
231
|
+
- Effects chain with parallel subpatchers
|
|
232
|
+
- Deeply nested hierarchy (6 levels)
|
|
233
|
+
|
|
234
|
+
### New: SVG Preview Feature
|
|
235
|
+
|
|
236
|
+
- Added `py2max preview` CLI command for offline visual validation of Max patches
|
|
237
|
+
|
|
238
|
+
- Added `py2max.svg` module with complete SVG rendering engine (330 lines)
|
|
239
|
+
|
|
240
|
+
- Added `export_svg()` and `export_svg_string()` functions for programmatic SVG generation
|
|
241
|
+
|
|
242
|
+
- Added SVG rendering for boxes with type-specific styling:
|
|
243
|
+
- Regular objects: Light gray fill
|
|
244
|
+
- Comments: Yellow fill (#ffffd0)
|
|
245
|
+
- Messages: Medium gray fill
|
|
246
|
+
|
|
247
|
+
- Added patchline rendering with correct inlet/outlet connection points
|
|
248
|
+
|
|
249
|
+
- Added optional inlet/outlet port visualization (blue inlets, orange outlets)
|
|
250
|
+
|
|
251
|
+
- Added automatic port detection from MaxRef metadata via `get_inlet_count()` and `get_outlet_count()`
|
|
252
|
+
|
|
253
|
+
- Added support for both Rect objects and list/tuple coordinate formats
|
|
254
|
+
|
|
255
|
+
- Added proper XML text escaping for special characters
|
|
256
|
+
|
|
257
|
+
- Added automatic viewBox calculation with padding
|
|
258
|
+
|
|
259
|
+
- Added browser integration with `--open` flag
|
|
260
|
+
|
|
261
|
+
- Added 17 comprehensive tests covering all SVG functionality
|
|
262
|
+
|
|
263
|
+
- Added `tests/examples/preview/svg_preview_demo.py` demonstration script
|
|
264
|
+
|
|
265
|
+
- Added `docs/SVG_PREVIEW.md` complete documentation
|
|
266
|
+
|
|
267
|
+
**CLI Usage:**
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# Basic preview (saves to /tmp)
|
|
271
|
+
py2max preview my-patch.maxpat
|
|
272
|
+
|
|
273
|
+
# Specify output path
|
|
274
|
+
py2max preview my-patch.maxpat -o output.svg
|
|
275
|
+
|
|
276
|
+
# Custom title
|
|
277
|
+
py2max preview my-patch.maxpat --title "My Synth"
|
|
278
|
+
|
|
279
|
+
# Hide inlet/outlet ports
|
|
280
|
+
py2max preview my-patch.maxpat --no-ports
|
|
281
|
+
|
|
282
|
+
# Open in browser automatically
|
|
283
|
+
py2max preview my-patch.maxpat --open
|
|
284
|
+
|
|
285
|
+
# Combine options
|
|
286
|
+
py2max preview synth.maxpat -o docs/synth.svg --title "Synth" --open
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Python API:**
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
from py2max import Patcher, export_svg, export_svg_string
|
|
293
|
+
|
|
294
|
+
# Create and export
|
|
295
|
+
p = Patcher('synth.maxpat', layout='grid')
|
|
296
|
+
osc = p.add_textbox('cycle~ 440')
|
|
297
|
+
dac = p.add_textbox('ezdac~')
|
|
298
|
+
p.add_line(osc, dac)
|
|
299
|
+
p.optimize_layout()
|
|
300
|
+
export_svg(p, 'synth.svg', title="Simple Synth", show_ports=True)
|
|
301
|
+
|
|
302
|
+
# Export to string
|
|
303
|
+
svg_content = export_svg_string(p, show_ports=True)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Benefits:**
|
|
307
|
+
|
|
308
|
+
- No Max installation required for visual validation
|
|
309
|
+
- High-quality, scalable vector graphics
|
|
310
|
+
- Works with all py2max layout managers
|
|
311
|
+
- Perfect for CI/CD, documentation, and version control
|
|
312
|
+
- Pure Python implementation with no binary dependencies
|
|
313
|
+
- Viewable in any web browser
|
|
314
|
+
|
|
315
|
+
### New: SQLite Database Support
|
|
316
|
+
|
|
317
|
+
- Added `py2max.db` module with comprehensive SQLite database support for Max object reference data
|
|
318
|
+
|
|
319
|
+
- Added `MaxRefDB` class for creating, querying, and managing Max object databases
|
|
320
|
+
|
|
321
|
+
- Added 14 normalized database tables: objects, metadata, inlets, outlets, methods, method_args, attributes, attribute_enums, objargs, examples, seealso, misc, palette, parameter
|
|
322
|
+
|
|
323
|
+
- Added support for both in-memory and file-based databases
|
|
324
|
+
|
|
325
|
+
- Added database query API: `search_objects()`, `get_objects_by_category()`, `get_all_categories()`
|
|
326
|
+
|
|
327
|
+
- Added bidirectional conversion: .maxref.xml → SQLite → JSON
|
|
328
|
+
|
|
329
|
+
- Added `export_to_json()` and `import_from_json()` methods for database portability
|
|
330
|
+
|
|
331
|
+
- Added `create_database()` convenience function for database creation and population
|
|
332
|
+
|
|
333
|
+
- Added category-based population methods: `populate_all_objects()`, `populate_all_max_objects()`, `populate_all_jit_objects()`, `populate_all_msp_objects()`, `populate_all_m4l_objects()`
|
|
334
|
+
|
|
335
|
+
- Added maxref category helper functions: `get_all_max_objects()`, `get_all_jit_objects()`, `get_all_msp_objects()`, `get_all_m4l_objects()`, `get_objects_by_category()`
|
|
336
|
+
|
|
337
|
+
- Added category tracking to maxref module (462 Max, 448 MSP, 210 Jitter, 37 M4L objects)
|
|
338
|
+
|
|
339
|
+
- Added complete test suite with 17 test cases
|
|
340
|
+
|
|
341
|
+
- Added `examples/maxref_db_demo.py` demonstration script
|
|
342
|
+
|
|
343
|
+
- Added `examples/category_db_demo.py` category-specific examples
|
|
344
|
+
|
|
345
|
+
- Added `docs/database.md` API documentation
|
|
346
|
+
|
|
347
|
+
### Improved: MaxRefDB API Enhancements
|
|
348
|
+
|
|
349
|
+
**Python API Improvements:**
|
|
350
|
+
|
|
351
|
+
- Added Pythonic properties: `.count`, `.categories`, `.objects` for cleaner access
|
|
352
|
+
- Added magic methods: `len(db)`, `'obj' in db`, `db['obj']`, `repr(db)` for natural Python usage
|
|
353
|
+
- Added simplified methods: `populate()`, `search()`, `by_category()`, `export()`, `load()` with cleaner naming
|
|
354
|
+
- Added `summary()` method for database statistics with category breakdown
|
|
355
|
+
- Maintained full backward compatibility with deprecated methods
|
|
356
|
+
- All 18 database tests pass
|
|
357
|
+
|
|
358
|
+
**CLI Improvements:**
|
|
359
|
+
|
|
360
|
+
- Added comprehensive `py2max db` subcommand with 7 operations:
|
|
361
|
+
- `db create` - Create new databases with optional category filtering
|
|
362
|
+
- `db populate` - Add objects to existing databases
|
|
363
|
+
- `db info` - Show database information with summary and listing options
|
|
364
|
+
- `db search` - Search objects by text or category with verbose mode
|
|
365
|
+
- `db query` - Get detailed object information (JSON, dict, or human-readable)
|
|
366
|
+
- `db export` - Export database to JSON
|
|
367
|
+
- `db import` - Import JSON data into database
|
|
368
|
+
- Updated `convert maxref-to-sqlite` to use MaxRefDB internally
|
|
369
|
+
- Added 7 new CLI tests covering all db subcommands
|
|
370
|
+
- All 272 tests pass (258 passed, 14 skipped)
|
|
371
|
+
|
|
372
|
+
**Example Usage:**
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
# New Pythonic API
|
|
376
|
+
db = MaxRefDB('maxref.db')
|
|
377
|
+
db.populate(category='msp')
|
|
378
|
+
print(len(db)) # Total objects
|
|
379
|
+
if 'cycle~' in db:
|
|
380
|
+
cycle = db['cycle~']
|
|
381
|
+
results = db.search('filter')
|
|
382
|
+
db.export('backup.json')
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
# New CLI commands
|
|
387
|
+
py2max db create msp.db --category msp
|
|
388
|
+
py2max db info msp.db --summary
|
|
389
|
+
py2max db search msp.db "oscillator" -v
|
|
390
|
+
py2max db query msp.db cycle~ --json
|
|
391
|
+
py2max db export msp.db backup.json
|
|
392
|
+
|
|
393
|
+
# Cache management
|
|
394
|
+
py2max db cache location
|
|
395
|
+
py2max db cache init
|
|
396
|
+
py2max db cache clear
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### New: Automatic Cache System
|
|
400
|
+
|
|
401
|
+
**Platform-Specific Cache:**
|
|
402
|
+
|
|
403
|
+
MaxRefDB now automatically creates and populates a cache database on first use:
|
|
404
|
+
|
|
405
|
+
- **macOS**: `~/Library/Caches/py2max/maxref.db`
|
|
406
|
+
- **Linux**: `~/.cache/py2max/maxref.db`
|
|
407
|
+
- **Windows**: `~/AppData/Local/py2max/Cache/maxref.db`
|
|
408
|
+
|
|
409
|
+
**Benefits:**
|
|
410
|
+
|
|
411
|
+
- One-time population of all 1157 Max objects
|
|
412
|
+
- Instant access on subsequent use
|
|
413
|
+
- No manual setup required
|
|
414
|
+
- Platform-appropriate cache location
|
|
415
|
+
|
|
416
|
+
**New Static Methods:**
|
|
417
|
+
|
|
418
|
+
- `MaxRefDB.get_cache_dir()` - Get platform-specific cache directory
|
|
419
|
+
- `MaxRefDB.get_default_db_path()` - Get default database path
|
|
420
|
+
|
|
421
|
+
**Updated API:**
|
|
422
|
+
|
|
423
|
+
- `MaxRefDB()` - Now uses cache by default
|
|
424
|
+
- `MaxRefDB(db_path, auto_populate=True)` - Control auto-population
|
|
425
|
+
- `MaxRefDB(':memory:')` - In-memory database (no caching)
|
|
426
|
+
|
|
427
|
+
**New CLI Commands:**
|
|
428
|
+
|
|
429
|
+
- `py2max db cache location` - Show cache location and status
|
|
430
|
+
- `py2max db cache init` - Manually initialize cache
|
|
431
|
+
- `py2max db cache clear` - Clear cache database
|
|
432
|
+
|
|
433
|
+
**Example Usage:**
|
|
434
|
+
|
|
435
|
+
```python
|
|
436
|
+
# Automatic caching (default)
|
|
437
|
+
from py2max.db import MaxRefDB
|
|
438
|
+
db = MaxRefDB() # Auto-populates cache on first use
|
|
439
|
+
print(f"Objects: {len(db)}") # 1157
|
|
440
|
+
|
|
441
|
+
# Get cache location
|
|
442
|
+
print(f"Cache: {MaxRefDB.get_default_db_path()}")
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## [0.1.2]
|
|
446
|
+
|
|
447
|
+
### Improvements in Type Safety
|
|
448
|
+
|
|
449
|
+
- Added type safety improvements via compliance with `mypy` checks
|
|
450
|
+
|
|
451
|
+
### Improvements in Layout
|
|
452
|
+
|
|
453
|
+
- Added `optimize_layout()` method for post-connection layout optimization
|
|
454
|
+
|
|
455
|
+
- Added `cluster_connected` parameter to `GridLayoutManager` for connection-aware object clustering
|
|
456
|
+
|
|
457
|
+
- Added `flow_direction` parameter support for both horizontal and vertical layouts in all layout managers
|
|
458
|
+
|
|
459
|
+
- Added backward compatibility for legacy layout manager APIs
|
|
460
|
+
|
|
461
|
+
- Enhanced layout performance with connection-aware clustering algorithms
|
|
462
|
+
|
|
463
|
+
- Improved layout manager consistency with unified `GridLayoutManager` and `FlowLayoutManager` APIs
|
|
464
|
+
|
|
465
|
+
- Added `FlowLayoutManager` with intelligent signal flow analysis and hierarchical positioning
|
|
466
|
+
|
|
467
|
+
- Added `GridLayoutManager` with connection-aware clustering and configurable flow direction
|
|
468
|
+
|
|
469
|
+
### Improvements in Max Object Introspection
|
|
470
|
+
|
|
471
|
+
- Added optional connection validation system with inlet/outlet validation and `InvalidConnectionError`. This is early stages, and may have some false positives, but planned improvements in handling of excepttions should make this accurate and useful.
|
|
472
|
+
|
|
473
|
+
- Added object introspection methods: `get_inlet_count()`, `get_outlet_count()`, `get_inlet_types()`, `get_outlet_types()`
|
|
474
|
+
|
|
475
|
+
- Added `Box.help()`, `Box.help_text()` and `Box.get_info()` methods for rich object documentation.
|
|
476
|
+
|
|
477
|
+
- Added `maxref` integration system with dynamic help for 1157 Max objects using `.maxref.xml` files
|
|
478
|
+
|
|
479
|
+
### Bug Fixes
|
|
480
|
+
|
|
481
|
+
- Fixed `maxclass` assignment bug that was preventing patchlines from connecting properly
|
|
482
|
+
|
|
483
|
+
### Improvements in Project Management
|
|
484
|
+
|
|
485
|
+
- Converted to [uv](https://github.com/astral-sh/uv) for project and dependency management.
|
|
486
|
+
|
|
487
|
+
## [0.1.1]
|
|
488
|
+
|
|
489
|
+
- Added `Makefile` frontend
|
|
490
|
+
|
|
491
|
+
- Changed package manager to `uv`
|
|
492
|
+
|
|
493
|
+
- Improved compatibility with Python 3.7
|
|
494
|
+
|
|
495
|
+
- Improved core Coverage: 99%
|
|
496
|
+
|
|
497
|
+
- Added clean script: `./scripts/clean.sh`
|
|
498
|
+
|
|
499
|
+
- Added coverage script and reporting: `./scripts/coverage.sh`
|
|
500
|
+
|
|
501
|
+
- Moved `tests` folder from `py2max/py2max/tests` to `py2max/tests`
|
|
502
|
+
|
|
503
|
+
- Added gradual types to `py2max/core`, no errors with `mypy`
|
|
504
|
+
|
|
505
|
+
- Added `number_tilde` test
|
|
506
|
+
|
|
507
|
+
- Fixed `comment` positioning
|
|
508
|
+
|
|
509
|
+
- Added `pyhola` layout.
|
|
510
|
+
|
|
511
|
+
- Added `graphviz` layouts.
|
|
512
|
+
|
|
513
|
+
- Fixed `Adaptagrams` layout.
|
|
514
|
+
|
|
515
|
+
- Added graph layout comparison and additional layouts.
|
|
516
|
+
|
|
517
|
+
- Added vertical layout variant.
|
|
518
|
+
|
|
519
|
+
- Added boolean `tilde` parameter for objects which have a tilde sibling.
|
|
520
|
+
|
|
521
|
+
- Added preliminary support for `rnbo~` include rnbo codebox
|
|
522
|
+
|
|
523
|
+
## [0.1.0]
|
|
524
|
+
|
|
525
|
+
- Added a generic `.add` method to `Patcher` objects which include some logic to to figure out to which specialized method to dispatch to. See: `tests/test_add.py` for examples of this.
|
|
526
|
+
|
|
527
|
+
- Major refactoring after `test_tree_builder` design experiment, so we have now only one simple extendable Box class, and there is round trip conversion between .maxpat files and patchers.
|
|
528
|
+
|
|
529
|
+
- Added `test_tree_builder.py` which shows that the json tree can be converted to a python object tree which corresponds to it on a one-on-one basis, which itself can be used to generate the json tree for round-trip conversion.
|
|
530
|
+
|
|
531
|
+
- Added `from_file` classmethod to `Patcher` to populate object from `.maxpat` file.
|
|
532
|
+
|
|
533
|
+
- Added `coll`, `dict` and `table` objects and tests
|
|
534
|
+
|
|
535
|
+
- Added some tests which try to use generic layout algorithm in Networkx but the results are quite terrible using builtin algorithms so probably better to try to create something fit-for-purpose.
|
|
536
|
+
|
|
537
|
+
- Added `gen` subpatcher
|
|
538
|
+
|
|
539
|
+
- Moved `varname` to optional kwds instead of being an explicit parameter since it's optional and its inclusion when not populated is sometimes problematic.
|
|
540
|
+
|
|
541
|
+
- Renamed odb to maxclassdb since it only relates to defaults per `maxclass`
|
|
542
|
+
|
|
543
|
+
- Added smarter textbox which uses odb to improve object creation.
|
|
544
|
+
|
|
545
|
+
- Added separate test folder
|
|
546
|
+
|
|
547
|
+
- Added `odb.py` in package with a number of default configs of objects
|
|
548
|
+
|
|
549
|
+
- Converted to package.
|
|
550
|
+
|
|
551
|
+
- Added some notes on graph drawing and layout algorithms
|
|
552
|
+
|
|
553
|
+
- Added comments keyword in box objects + PositionManager for easy documentation
|
|
554
|
+
|
|
555
|
+
- Added Comments objects
|
|
556
|
+
|
|
557
|
+
- Refactor: MaxPatch and Patcher objects are now one.
|
|
558
|
+
|
|
559
|
+
- Initial release
|
py2max-0.2.1/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2025 Shakeeb Alireza
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|