internalInitController method
void
internalInitController({
- required NodeFlowTheme theme,
- required Size portSizeResolver(
- Port port
- NodeShape? nodeShapeBuilder(
- Node<
T> node
- Node<
- bool Function(Connection connection, Offset point)? connectionHitTesterBuilder(
- ConnectionPainter painter
- List<
Rect> connectionSegmentCalculator(- Connection connection
- NodeFlowEvents<
T> ? events,
Initializes the controller for use with the NodeFlow editor.
THIS IS THE CANONICAL INITIALIZATION POINT.
All editor infrastructure is set up here in a specific order. This method
must be called from NodeFlowEditor.initState before any other operations.
@internal - This method is for internal use by NodeFlowEditor only. Do not call directly from application code.
Parameters
theme: The visual theme for the editor (required)portSizeResolver: Resolves the size of a port for spatial indexing (required)nodeShapeBuilder: Optional builder for custom node shapesconnectionHitTesterBuilder: Builder for the connection hit test callback. This receives the ConnectionPainter and returns a hit test function.connectionSegmentCalculator: Calculates segment bounds for connection spatial indexing. Required for accurate connection hit testing.events: Optional event handlers for node/connection/viewport events
Example
// In NodeFlowEditor.initState():
widget.controller.internalInitController(
theme: widget.theme,
portSizeResolver: (port) => port.size ?? widget.theme.portTheme.size,
nodeShapeBuilder: widget.nodeShapeBuilder != null
? (node) => widget.nodeShapeBuilder!(context, node)
: null,
connectionHitTesterBuilder: (painter) => (connection, point) {
// hit test logic using painter
},
connectionSegmentCalculator: (connection) {
// calculate segment bounds
},
events: widget.events,
);
Implementation
void internalInitController({
required NodeFlowTheme theme,
required Size Function(Port port) portSizeResolver,
NodeShape? Function(Node<T> node)? nodeShapeBuilder,
bool Function(Connection connection, Offset point)? Function(
ConnectionPainter painter,
)?
connectionHitTesterBuilder,
List<Rect> Function(Connection connection)? connectionSegmentCalculator,
NodeFlowEvents<T>? events,
}) {
// Idempotent - only initialize once
if (_editorInitialized) return;
_editorInitialized = true;
// =========================================================================
// Step 1: Store the theme
// =========================================================================
runInAction(() => _themeObservable.value = theme);
// =========================================================================
// Step 2: Set up node shape builder
// =========================================================================
// This must happen before spatial index setup and connection painter
// creation since both use the shape builder.
_nodeShapeBuilder = nodeShapeBuilder;
// =========================================================================
// Step 3: Set up spatial index callbacks
// =========================================================================
// These callbacks are used when calculating bounds for nodes and ports.
// They must be set before any spatial index operations.
_spatialIndex.portSizeResolver = portSizeResolver;
_spatialIndex.nodeShapeBuilder = nodeShapeBuilder;
// =========================================================================
// Step 4: Create connection painter
// =========================================================================
// The connection painter handles rendering and hit testing of connections.
// It needs the theme and optionally the node shape builder.
_connectionPainter = ConnectionPainter(
theme: theme,
nodeShape: nodeShapeBuilder != null
? (node) => nodeShapeBuilder(node as Node<T>)
: null,
);
// =========================================================================
// Step 5: Set up connection hit tester
// =========================================================================
// Now that the connection painter exists, we can create the hit tester.
if (connectionHitTesterBuilder != null) {
_spatialIndex.connectionHitTester = connectionHitTesterBuilder(
_connectionPainter!,
);
}
// =========================================================================
// Step 6: Set up render order provider
// =========================================================================
// This enables accurate hit testing based on visual stacking order.
_spatialIndex.renderOrderProvider = () => sortedNodes;
// =========================================================================
// Step 7: Store connection segment calculator for later use
// =========================================================================
_connectionSegmentCalculator = connectionSegmentCalculator;
// =========================================================================
// Step 8: Set up spatial index reactions
// =========================================================================
// These reactions automatically sync the spatial index when nodes,
// connections, or theme properties change.
_setupSpatialIndexReactions();
// =========================================================================
// Step 9: Set up event handlers
// =========================================================================
if (events != null) {
_events = events;
}
// =========================================================================
// Step 10: Initialize spatial indexes and node infrastructure
// =========================================================================
// If nodes were pre-loaded (e.g., from loadDocument before editor mounted),
// we need to set up their infrastructure and rebuild spatial indexes now.
_initializeLoadedNodes();
_rebuildSpatialIndexes();
}