deargui-vpl/docs/groups-new.md

9.2 KiB

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)