Skip to content

Commit 452bd0e

Browse files
bhowiebkrBryan Howard
andauthored
Fix group deletion functionality - enable Delete key support for groups (#42)
* Fix group nodes undo/redo duplication bug - Initialize groups list in NodeGraph constructor - Add groups serialization/deserialization to persist groups in files - Add groups cleanup to clear_graph() method - Add duplicate prevention checks in CreateGroupCommand - Groups now properly survive file save/load cycles - Multiple undo/redo operations no longer create duplicate groups Fixes issue where undoing and redoing group creation would result in duplicate groups appearing in the scene. 🤖 Generated with [Claude Code](https://claude.ai/code) * Add group properties editor with transparency support - Add GroupPropertiesDialog with full UI for editing group properties - Add alpha sliders for precise transparency control (background, border, title, selection colors) - Add GroupPropertyChangeCommand for undoable property changes with batch support - Add context menu support in Group class and NodeEditorView - Add GroupPreviewWidget with transparency visualization - Fix QPainter cleanup and QPointF arithmetic issues - Simplify CSS styling to avoid Qt stylesheet parser warnings Users can now right-click groups to access Properties dialog and adjust all color properties including transparency values with proper undo/redo support. * Implement groups save/load functionality for markdown files - Add Groups section parsing to FlowFormatHandler markdown parser - Add Groups section export to FlowFormatHandler markdown writer - Update Group.serialize() to include complete color data with RGBA values - Update Group.deserialize() to restore all color properties and brushes - Update FlowSpec documentation with comprehensive groups specification - Remove creation_timestamp from groups (unused metadata clutter) - Add password_generator_tool_group.md example demonstrating groups in markdown Groups now fully serialize/deserialize with transparency support in .md files. All group properties including colors, position, size, padding, and membership are properly saved and restored when loading graphs from markdown format. * Implement comprehensive copy/paste functionality for groups and nodes - Enhanced copy_selected() to include groups in clipboard data - Added complete property preservation for nodes (colors, size, GUI state) - Implemented group copy/paste with full property restoration - Fixed CreateNodeCommand to use correct Node API (calculate_absolute_minimum_size) - Added external clipboard support for selections with groups - Resolved 'Node object has no attribute min_width' runtime error 🤖 Generated with [Claude Code](https://claude.ai/code) * Fix double transformation in group paste operations Fixed issue where pasted groups with member nodes were being transformed twice: - Once correctly by PasteNodesCommand applying mouse position offset - Again incorrectly by Group.itemChange automatically moving member nodes Changes: - Added _is_pasting flag to NodeGraph to track paste operations - Modified Group.itemChange to skip automatic node movement during paste - Enhanced paste() method to accept mouse position parameter - Fixed data conversion to handle both 'uuid' and 'id' node identifiers Groups now paste correctly at mouse cursor position with proper node positioning. Generated with [Claude Code](https://claude.ai/code) * Fix GUI refresh for pasted nodes with GUI code Added deferred GUI update mechanism for pasted nodes to ensure GUI widgets refresh correctly, similar to when loading graphs from files. Changes: - Added deferred _final_paste_update() method to PasteNodesCommand - Schedules GUI layout updates using QTimer.singleShot after paste completes - Calls node._update_layout() to force complete layout rebuild and pin updates - Only applies to regular nodes (excludes reroute nodes) This ensures pasted nodes with GUI code display their widgets correctly and behave identically to loaded nodes. Generated with [Claude Code](https://claude.ai/code) * Refactor node_commands.py into modular package structure Split the monolithic 1,181-line node_commands.py file into a well-organized package structure for better maintainability and code organization. Changes: - Created src/commands/node/ package with focused modules: * basic_operations.py - Create, delete, move node commands * property_changes.py - Property and code change commands * batch_operations.py - Paste, move/delete multiple commands - Reduced main node_commands.py to 21 lines (97% reduction) - Maintained 100% backward compatibility through re-exports - Added comprehensive docstrings and module documentation - Preserved all existing functionality and command behavior Benefits: - Better code organization and maintainability - Easier navigation and understanding of command types - Improved testability with focused modules - Extensible structure for future command additions Generated with [Claude Code](https://claude.ai/code) * Fix group deletion functionality - groups can now be deleted with Delete key - Add DeleteGroupCommand with full state preservation and undo support - Enhance DeleteMultipleCommand to handle Group objects alongside nodes/connections - Fix node_graph.py keyPressEvent to use DeleteMultipleCommand for all item types - Groups were previously ignored in keyboard deletion, now work seamlessly - Comprehensive undo/redo support maintains group properties, colors, and positioning - Update command exports to include new DeleteGroupCommand 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Bryan Howard <[email protected]>
1 parent 7c262ef commit 452bd0e

16 files changed

+3151
-1003
lines changed

docs/specifications/flow_spec.md

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,70 @@ def set_initial_state(widgets, state):
291291
- The function's return values are passed to `set_values()` for display
292292
- Widget state is automatically saved to `gui_state` in the node's metadata
293293

294-
### 3.5 Connections Section
294+
### 3.5 Groups Section (Optional)
295+
296+
Files MAY contain a Groups section for organizing nodes visually:
297+
298+
```markdown
299+
## Groups
300+
```json
301+
[
302+
{
303+
"uuid": "group-1",
304+
"name": "Data Processing",
305+
"description": "Processes input data through multiple stages",
306+
"member_node_uuids": ["node1", "node2", "node3"],
307+
"position": {"x": 150, "y": 200},
308+
"size": {"width": 400, "height": 300},
309+
"padding": 20,
310+
"is_expanded": true,
311+
"colors": {
312+
"background": {"r": 45, "g": 45, "b": 55, "a": 120},
313+
"border": {"r": 100, "g": 150, "b": 200, "a": 180},
314+
"title_bg": {"r": 60, "g": 60, "b": 70, "a": 200},
315+
"title_text": {"r": 220, "g": 220, "b": 220, "a": 255},
316+
"selection": {"r": 255, "g": 165, "b": 0, "a": 100}
317+
}
318+
}
319+
]
320+
```
321+
322+
**Group Properties:**
323+
324+
**Required Fields:**
325+
- `uuid`: Unique identifier for the group (string)
326+
- `name`: Human-readable group name (string)
327+
- `member_node_uuids`: Array of UUIDs for nodes contained in this group
328+
329+
**Optional Fields:**
330+
- `description`: Group description (string, default: "")
331+
- `position`: Group position as {x, y} coordinates (object, default: {x: 0, y: 0})
332+
- `size`: Group dimensions as {width, height} (object, default: {width: 200, height: 150})
333+
- `padding`: Internal padding around member nodes (number, default: 20)
334+
- `is_expanded`: Whether group is visually expanded (boolean, default: true)
335+
- `colors`: Visual appearance colors with RGBA values (object)
336+
- `background`: Semi-transparent group background color
337+
- `border`: Group border outline color
338+
- `title_bg`: Title bar background color
339+
- `title_text`: Title text color
340+
- `selection`: Selection highlight color when group is selected
341+
342+
**Color Format:**
343+
Each color in the `colors` object uses RGBA format:
344+
```json
345+
{"r": 255, "g": 165, "b": 0, "a": 100}
346+
```
347+
Where r, g, b are 0-255 and a (alpha/transparency) is 0-255 (0 = fully transparent, 255 = fully opaque).
348+
349+
**Group Behavior:**
350+
- Groups are organizational containers that visually group related nodes
351+
- Member nodes move when the group is moved
352+
- Groups can be resized, automatically updating membership based on contained nodes
353+
- Groups support transparency for better visual layering
354+
- Groups maintain their own undo/redo history for property changes
355+
- Groups can be collapsed/expanded to manage visual complexity
356+
357+
### 3.6 Connections Section
295358

296359
The file MUST contain exactly one Connections section:
297360

@@ -337,7 +400,7 @@ The file MUST contain exactly one Connections section:
337400
]
338401
```
339402

340-
### 3.6 GUI Integration & Data Flow
403+
### 3.7 GUI Integration & Data Flow
341404

342405
When a node has both GUI components and pin connections, the data flows as follows:
343406

@@ -392,7 +455,7 @@ This state is:
392455
- Restored when the graph is loaded via `set_initial_state()`
393456
- Updated whenever widget values change
394457

395-
### 3.7 Reroute Nodes
458+
### 3.8 Reroute Nodes
396459

397460
Reroute nodes are special organizational nodes that help manage connection routing and graph layout without affecting data flow.
398461

@@ -442,7 +505,7 @@ Reroute nodes are special organizational nodes that help manage connection routi
442505
]
443506
```
444507

445-
### 3.8 Execution Modes
508+
### 3.9 Execution Modes
446509

447510
PyFlowGraph supports two distinct execution modes that determine how the graph processes data:
448511

@@ -476,7 +539,7 @@ PyFlowGraph supports two distinct execution modes that determine how the graph p
476539
- GUI buttons in nodes are inactive in batch mode
477540
- Live mode enables event handlers in node GUIs
478541

479-
### 3.9 Virtual Environments
542+
### 3.10 Virtual Environments
480543

481544
PyFlowGraph uses isolated Python virtual environments to manage dependencies for each graph:
482545

@@ -506,7 +569,7 @@ PyFlowGraph/
506569
- Flexibility: Different graphs can use different package versions
507570
- Portability: Environments can be recreated from requirements
508571

509-
### 3.10 Subprocess Data Transfer
572+
### 3.11 Subprocess Data Transfer
510573

511574
PyFlowGraph executes each node in an isolated subprocess for security and stability. Understanding how data flows between these processes is crucial for working with the system.
512575

@@ -618,7 +681,7 @@ The execution system maintains a `pin_values` dictionary that:
618681
- Data is duplicated, not shared
619682
- Large datasets consume memory in both processes
620683

621-
### 3.11 Error Handling
684+
### 3.12 Error Handling
622685

623686
The system provides comprehensive error handling during graph execution:
624687

@@ -842,6 +905,30 @@ def set_initial_state(widgets, state):
842905
widgets['operation'].setCurrentText(state.get('operation', 'add'))
843906
```
844907

908+
## Groups
909+
910+
```json
911+
[
912+
{
913+
"uuid": "calc-group",
914+
"name": "Calculator Components",
915+
"description": "All calculator-related functionality",
916+
"member_node_uuids": ["calc-node"],
917+
"position": {"x": 150, "y": 150},
918+
"size": {"width": 350, "height": 300},
919+
"padding": 25,
920+
"is_expanded": true,
921+
"colors": {
922+
"background": {"r": 45, "g": 45, "b": 55, "a": 120},
923+
"border": {"r": 100, "g": 150, "b": 200, "a": 180},
924+
"title_bg": {"r": 60, "g": 60, "b": 70, "a": 200},
925+
"title_text": {"r": 220, "g": 220, "b": 220, "a": 255},
926+
"selection": {"r": 255, "g": 165, "b": 0, "a": 100}
927+
}
928+
}
929+
]
930+
```
931+
845932
## Connections
846933

847934
```json
@@ -858,7 +945,7 @@ A parser should use markdown-it-py to tokenize the document:
858945
2. **State Machine**: Track current node and component being parsed
859946
3. **Section Detection**:
860947
- `h1`: Graph title
861-
- `h2`: Node header (regex: `Node: (.*) \(ID: (.*)\)`) or "Connections"
948+
- `h2`: Node header (regex: `Node: (.*) \(ID: (.*)\)`), "Groups", or "Connections"
862949
- `h3`: Component type (Metadata, Logic, etc.)
863950
4. **Data Extraction**: Extract `content` from `fence` tokens based on `info` language tag
864951
5. **@node_entry Function Identification**:
@@ -886,7 +973,10 @@ A parser should use markdown-it-py to tokenize the document:
886973
- The `@node_entry` function must have valid Python syntax
887974
- Type hints on the `@node_entry` function should be valid for pin generation
888975
- Connections section is required
889-
- JSON must be valid in metadata and connections
976+
- Groups section is optional; if present, must contain valid JSON
977+
- JSON must be valid in metadata, groups, and connections
978+
- Group UUIDs must be unique across all groups
979+
- Group member_node_uuids must reference existing nodes
890980

891981
**GUI-Specific Rules (when GUI components are present):**
892982
- GUI Definition must be valid Python code that creates PySide6 widgets
@@ -941,6 +1031,7 @@ Both formats represent identical graph information:
9411031
| ### Logic | "code" field | Execution code |
9421032
| ### GUI Definition | "gui_code" field | Widget creation |
9431033
| ### GUI State Handler | "gui_get_values_code" | State management |
1034+
| ## Groups | "groups" array | Group definitions |
9441035
| ## Connections | "connections" array | Graph edges |
9451036

9461037
### 7.3 Use Cases

0 commit comments

Comments
 (0)