deargui-vpl/docs/groups-container-architecture.md

239 lines
7.7 KiB
Markdown

# BehaviorGraph Container-Based Architecture
**Core Principle:** All nodes, links, blocks exist within **containers**. Containers manage, run, and render their contents.
**Key Insight:** The app can have **multiple root containers**, each loaded from a separate file. Each root container represents a separate graph/document/workspace.
```
App
├── RootContainer1 (loaded from file1.json)
│ ├── Node A
│ ├── Node B
│ └── BehaviorGraph Container (Group 1)
│ ├── Node C
│ └── BehaviorGraph Container (Nested Group)
│ └── Node D
├── RootContainer2 (loaded from file2.json)
│ ├── Node E
│ └── Node F
└── RootContainer3 (loaded from file3.json)
└── BehaviorGraph Container (Group 2)
└── Node G
```
## Architecture Overview
### Container Hierarchy
- **App Level**
- Has **multiple root containers** (one per loaded file/graph)
- Each root container is a separate workspace/graph
- **Root Container** (one per file/graph)
- Contains top-level nodes for that graph
- Contains top-level groups for that graph
- Loaded from a single file
- **Group Containers** (BehaviorGraph instances)
- Contain inner nodes
- Can contain nested groups
- Have their own pin interface (for external connections)
### Key Benefits
1. **No Duplication**: Each node exists in exactly ONE container
2. **Clear Ownership**: Container owns its nodes/links
3. **Clean Separation**: Containers handle management, execution, rendering
4. **Natural Nesting**: Groups are just containers within containers
5. **Unified Interface**: Root and groups use same container interface
6. **State Management**: Containers have flags (hidden, active/disabled, running, error)
### App Structure Changes
### 2. Group Creation
**After:**
- Create BehaviorGraph container within **current active root container**
- Move selected nodes from active root container → group container
- Move links (internal links stay, external links need group pins)
- Group container owns these nodes now
- Groups belong to the root container they were created in
### 3. Rendering
- Render **active root container** (or all root containers if multi-view)
- Root container renders its nodes
- Root container renders its child containers (groups)
- Each container renders its own contents
- Different root containers can be in different tabs/views
### 4. Runtime Execution
**After:**
- **Active root container** runs (or all if running all graphs)
- Container iterates its nodes
- If node is a container (BehaviorGraph), call container->Run()
- Nested containers run recursively
- Each root container executes independently (or can be cross-container?)
### 5. Serialization
**Before:**
- Save all nodes
- Save groups with `m_ParentGroup` references
- Link up later
**After:**
- **Each root container saves to its own file**
- Save container hierarchy (root container + all nested groups)
- Each container saves its nodes/links
- Natural tree structure per file
- Multiple files = multiple root containers
### Introduces:
- ✅ Clean ownership model
- ✅ Natural nesting (containers in containers)
- ✅ Unified interface (root = container, groups = containers)
- ✅ Easier serialization (tree structure)
- ✅ Cleaner rendering (containers render themselves)
- ✅ State management (hidden, active/disabled, running, error flags)
### New Approach (Container)
```
App::m_RootContainers = [root1, root2]
RootContainer1::m_Nodes = [node1, node2]
RootContainer1::m_Children = [BehaviorGraphContainer1]
BehaviorGraphContainer1::m_Nodes = [node3, node4] // MOVED from root1
RootContainer2::m_Nodes = [node5, node6]
// Nodes exist in exactly ONE container
// No duplication, no parent tracking needed
// Each root container is independent (separate file/graph)
```
# Architecture Decision: Container-Based vs Node-Based
### Core Principle
**Everything lives in a container.** Containers own their contents (nodes, links, nested containers).
```
Root Container (implicit, always exists)
├── Node A
├── Node B
├── BehaviorGraph Container (Group 1)
│ ├── Node C
│ ├── Node D
│ └── BehaviorGraph Container (Nested Group)
│ └── Node E
└── Node F
```
### Key Concepts
1. **Single Ownership**: Each node/link exists in exactly ONE container
2. **Hierarchical**: Containers can contain other containers (natural nesting)
3. **Unified Interface**: Root and groups use the same container API
4. **Clean Separation**: Container handles management, execution, rendering
### Implementation Structure
```cpp
class Container
{
// Ownership
std::vector<Node*> m_Nodes; // Nodes in this container
std::vector<Link*> m_Links; // Links in this container
std::vector<Container*> m_Children; // Nested containers (groups)
// Interface (for groups only - root has no interface)
std::vector<GroupPin> m_InputFlowPins;
std::vector<GroupPin> m_OutputFlowPins;
std::vector<GroupPin> m_InputParamPins;
std::vector<GroupPin> m_OutputParamPins;
// Virtual connections (group pin → inner node pin)
std::map<ed::PinId, ed::PinId> m_GroupToInnerPins;
// Management
void AddNode(Node* node);
void RemoveNode(Node* node);
void AddLink(Link* link);
void RemoveLink(Link* link);
// Execution
void Run(App* app); // Execute container contents
// Rendering
void Render(App* app, Pin* newLinkPin);
// Query
Container* FindContainer(NodeId nodeId);
};
class BehaviorGraph : public Container, public ParameterizedBlock
{
// BehaviorGraph IS a container
// Also acts as a block (for runtime execution)
// Has group-specific UI (collapsed/expanded modes)
};
class App
{
Container* m_RootContainer; // Default container for top-level items
// Convenience methods
Container* GetRootContainer() { return m_RootContainer; }
Container* FindContainerForNode(NodeId nodeId);
// Backward compatibility (optional - can maintain flattened view)
std::vector<Node*> GetAllNodes(); // Recursive flattening
std::vector<Link*> GetAllLinks(); // Recursive flattening
};
```
## Migration Path
### Phase 2: Make BehaviorGraph a Container
1. BehaviorGraph inherits from Container
2. BehaviorGraph also inherits from ParameterizedBlock (block interface)
3. Group creation moves nodes from root → BehaviorGraph container
### Phase 3: Update All Systems
1. **Rendering**: Container-based (root renders self + children)
2. **Execution**: Container-based (root runs, nested containers run recursively)
3. **Serialization**: Container tree structure
4. **Queries**: Container-aware lookup methods
## Benefits Comparison
### Container-Based (New):
- ✅ Single ownership (node owned by exactly one container)
- ✅ No `m_ParentGroup` needed (container owns it)
- ✅ Unified patterns (all containers same interface)
- ✅ Natural serialization (save container tree)
- ✅ Clear ownership (container owns contents)
## Decision: Container-Based Architecture
**Alternative:** Can implement groups first with node-based approach, then refactor later (but creates technical debt).
## Next Steps
1. **Update Implementation Plan** - Reflect container architecture
2. **Design Container API** - Define exact interface
3. **Implement Root Container** - Move existing code
4. **Implement BehaviorGraph Container** - Group functionality
5. **Update All Systems** - Rendering, execution, serialization
See `docs/groups-container-architecture.md` for detailed container design.