# Group Block Implementation Plan - Spatial Grouping ## Overview This document outlines the implementation plan for adding **spatial grouping functionality** to Group blocks in Expanded mode. This allows Group blocks to act as containers that automatically adopt nodes when they are dragged into their bounds, similar to the "Test Comment" nodes in the old demo. **Core Principle:** Groups work through **spatial containment** - any node whose bounds fall within a group's `m_GroupBounds` becomes a child. The group can be dragged by its header to move all children together, and can be resized to adjust its containment area. ## Reference Implementation Based on `ref/old_demo.cpp` and `ref/old_editor.cpp`, the old comment/group nodes worked as follows: 1. **`ed::Group(size)`**: Called during `ed::BeginNode()` / `ed::EndNode()` to mark the node as a group and set its group bounds 2. **Spatial Containment**: Nodes within `m_GroupBounds` are automatically considered children 3. **`GetGroupedNodes()`**: Recursively finds all nodes within bounds using `FindNodesInRect()` 4. **Header Dragging**: Dragging the group header moves the group and all children 5. **Resizing**: Groups can be resized by dragging edges/corners, updating `m_GroupBounds` 6. **Group Hints**: `BeginGroupHint()` / `EndGroupHint()` allow rendering title bar outside bounds ## Architecture Notes - The imgui_node_editor uses **internal `NodeType::Group`** in `ed::Node` (separate from our application `NodeType::Group`) - Our Group blocks use **application-level `NodeType::Group`** but need to integrate with editor's group system - The editor's group system is based on **spatial containment** - no explicit parent/child references - Groups are sorted separately from regular nodes for rendering order ## Implementation Tasks ### Phase 1: Basic Group Infrastructure #### Task 1.1: Integrate Group Block with Editor's Group System **Files:** `examples/blueprints-example/blocks/group_block.cpp` - [ ] Update `RenderExpanded()` to call `ed::Group(size)` during node rendering - Call `ed::Group(groupSize)` within `ed::BeginNode()` / `ed::EndNode()` - Store group size in GroupBlock (initial size from node bounds or default) - This marks the node as a group in the editor's internal system - [ ] Add group size tracking to GroupBlock - Add `ImVec2 m_GroupSize` member variable - Initialize with default size (e.g., 400x300) or based on node bounds - Save/load group size in `SaveState()` / `LoadState()` - [ ] Verify node is recognized as group by editor - Editor should automatically recognize it via `ed::Group()` call - Check that `IsGroup()` returns true for our nodes **Dependencies:** None --- #### Task 1.2: Implement Group Hints (Title Bar Rendering) **Files:** `examples/blueprints-example/blocks/group_block.cpp` - [ ] Render group title bar using `ed::BeginGroupHint()` / `ed::EndGroupHint()` - Display group name in the hint - Position title bar at top of group bounds (using `ed::GetGroupMin()`) - Style similar to old comment nodes (semi-transparent background) - [ ] Make title bar draggable - Editor automatically handles dragging when `GetRegion()` returns `NodeRegion::Header` - Verify dragging group header moves the group **Dependencies:** Task 1.1 --- ### Phase 2: Spatial Containment & Child Management #### Task 2.1: Automatic Child Detection **Files:** `examples/blueprints-example/blocks/group_block.cpp`, `examples/blueprints-example/app-render.cpp` - [ ] Verify automatic child detection works - Editor's `GetGroupedNodes()` automatically finds nodes within `m_GroupBounds` - Uses `FindNodesInRect(m_GroupBounds)` internally - Test: Drag a block into group bounds → should become child - [ ] Optional: Store child node IDs for quick access - Not strictly necessary (editor handles this via `GetGroupedNodes()`) - Could cache for performance if needed later **Dependencies:** Task 1.1 --- #### Task 2.2: Dragging Group Header Moves Children **Files:** `examples/blueprints-example/app-render.cpp` (if needed) - [ ] Verify editor automatically handles child movement - Editor's `DragAction` calls `GetGroupedNodes()` when dragging group - Children are included in drag operation automatically - Test: Drag group header → all children should move - [ ] Handle edge cases - Prevent dragging children out of group when dragging group - Or allow it (editor might handle automatically) **Dependencies:** Task 1.1, 2.1 --- ### Phase 3: Group Resizing #### Task 3.1: Enable Group Resizing **Files:** `examples/blueprints-example/blocks/group_block.cpp`, `examples/blueprints-example/app-render.cpp` - [ ] Verify editor handles resizing automatically - Editor's `SizeAction` handles group resizing when `IsGroup()` is true - User can drag edges/corners to resize - Updates both `m_Bounds` and `m_GroupBounds` - [ ] Update group size tracking - When group is resized, update `m_GroupSize` in GroupBlock - Save updated size in `SaveState()` - [ ] Call `ed::SetGroupSize()` if needed for initial size - May need to call this after creating group to set initial bounds **Dependencies:** Task 1.1 --- #### Task 3.2: Auto-Resize Based on Children **Files:** `examples/blueprints-example/blocks/group_block.cpp` - [ ] Optional: Auto-expand group when nodes are added - Calculate bounding box of all child nodes - Expand `m_GroupBounds` to encompass all children (with padding) - Update `m_GroupSize` accordingly - [ ] Optional: Auto-shrink when nodes removed - Recalculate bounds when child count decreases - Shrink group to fit remaining children **Dependencies:** Task 3.1, 2.1 --- ### Phase 4: Visual Polish #### Task 4.1: Group Visual Styling **Files:** `examples/blueprints-example/blocks/group_block.cpp` - [ ] Style group background (in Expanded mode) - Semi-transparent background (similar to old comment nodes) - Border styling - Visual distinction from regular blocks - [ ] Style group title bar (hint) - Background color - Text styling - Padding and spacing **Dependencies:** Task 1.1, 1.2 --- #### Task 4.2: Visual Feedback for Child Nodes **Files:** `examples/blueprints-example/app-render.cpp` (if needed) - [ ] Optional: Visual indication of group membership - Slight visual change for nodes inside groups - Border color change or subtle background tint - Or keep same (spatial containment is self-evident) **Dependencies:** Task 2.1 --- ### Phase 5: Edge Cases & Validation #### Task 5.1: Prevent Group Nesting Issues **Files:** `examples/blueprints-example/app-logic.cpp` - [ ] Validate group operations - Prevent groups from being dragged into themselves (recursive nesting) - Handle groups being moved into other groups (nested groups) - Editor should handle this, but verify behavior - [ ] Handle group deletion - When group is deleted, children should become top-level nodes - Or delete children too (decide on behavior) **Dependencies:** Task 2.1 --- #### Task 5.2: Save/Load Group Bounds **Files:** `examples/blueprints-example/blocks/group_block.cpp` - [ ] Save group size to JSON - Already added in Task 1.1, verify it works - [ ] Load group size from JSON - Restore size when loading saved graph - Call `ed::SetGroupSize()` if needed after loading **Dependencies:** Task 1.1 --- ### Phase 6: Collapsed Mode (Future) #### Task 6.1: Collapsed Mode Rendering **Files:** `examples/blueprints-example/blocks/group_block.cpp` - [ ] Implement `RenderCollapsed()` - Show compact representation (just title, maybe pin count) - Hide all child nodes visually - Children still exist but not rendered - [ ] Toggle between modes - User can switch via context menu - State persists across save/load **Dependencies:** Task 1.1, 4.1 --- ## Key API Functions From imgui_node_editor: - `ed::Group(ImVec2 size)` - Mark node as group and set group bounds - `ed::SetGroupSize(NodeId, ImVec2)` - Set group size externally - `ed::BeginGroupHint(NodeId)` / `ed::EndGroupHint()` - Render title bar - `ed::GetGroupMin()` / `ed::GetGroupMax()` - Get group bounds (in hint context) - `node->GetGroupedNodes(vector)` - Find all nodes within bounds - Editor automatically handles dragging groups with children via `GetGroupedNodes()` ## Testing Checklist - [ ] Create Group block → should show as group with title bar - [ ] Drag block into group → should become child - [ ] Drag group header → should move group and all children - [ ] Resize group → should update bounds, children still contained - [ ] Drag child out of group → should work - [ ] Save/load → group size should persist - [ ] Toggle display mode → should switch between expanded/collapsed ## Notes - The editor's group system is **spatial-based**, not reference-based - No explicit parent/child links needed - containment is automatic - `ed::Group()` must be called during node rendering, not after - Group bounds (`m_GroupBounds`) are separate from node bounds (`m_Bounds`) - `m_Bounds` = the actual node rectangle (for header/title bar) - `m_GroupBounds` = the area that contains child nodes (usually larger)