buildSchematicCanvas method

Widget buildSchematicCanvas({
  1. Color? backgroundColor,
  2. Key? canvasKey,
})

Build the schematic canvas with theme support.

Implementation

Widget buildSchematicCanvas({Color? backgroundColor, Key? canvasKey}) {
  if (layout == null) {
    return const SizedBox.shrink();
  }

  return BlocBuilder<SchematicThemeCubit, SchematicThemeMode>(
    builder: (context, themeMode) {
      final isDarkMode = themeMode == SchematicThemeMode.dark;
      final spinnerColor = isDarkMode ? Colors.white : Colors.black87;
      final textColor = isDarkMode ? Colors.white : Colors.black87;

      final canvas = SchematicCanvas(
        key: canvasKey,
        layout: layout!,
        netlistJson: schematicJson,
        externalHierarchy: externalHierarchy,
        colorScheme: isDarkMode
            ? SchematicColorScheme.dark
            : SchematicColorScheme.light,
        onNodeToggle: handleNodeToggle,
        onPortExpand: handlePortExpand,
        onPortExpandThrough: handlePortExpandThrough,
        onPortCollapse: handlePortCollapse,
        onPortCollapseThrough: handlePortCollapseThrough,
        onCollapsePartial: handleCollapsePartial,
        onExpandNonPrimitives: handleExpandNonPrimitives,
        onConvertToBlocksOnly: handleConvertToBlocksOnly,
        onNodeToggleRecursive: handleNodeToggleRecursive,
        onExpandNonPrimitivesRecursive: handleExpandNonPrimitivesRecursive,
        onConvertToBlocksOnlyRecursive: handleConvertToBlocksOnlyRecursive,
        onExpandChild: handleExpandChild,
        onExpandWire: handleExpandWire,
        onExpandPath: handleExpandPath,
        signalNameForPort: (nodeId, portId) =>
            schematicAdapter?.schematic.signalNameForPort(nodeId, portId),
        directDriverSignalPath: (wireName, scopePath) => schematicAdapter
            ?.schematic
            .directDriverSignalPath(wireName, scopePath),
        pendingToggleNodeId: pendingToggleNodeId,
        recentlyToggledNodeId: recentlyToggledNodeId,
        focusPortId: focusPortId,
        isDimmed: isToggling,
        signalValueLookup: signalValueLookup,
        onSendSignals: onSendSignals,
        hasExternalSignalListeners: hasExternalSignalListeners,
        onGoToSource: onGoToSource,
        availableSourceFormats: availableSourceFormats,
        incomingSignalPaths: incomingSignalPaths,
      );

      // Build the loading overlay — a small non-blocking corner badge
      // so the schematic stays visible while the layout recomputes.
      Widget buildLoadingOverlay() => Positioned(
            top: 8,
            right: 8,
            child: Material(
              color: Colors.transparent,
              child: Container(
                padding:
                    const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
                decoration: BoxDecoration(
                  color: isDarkMode
                      ? Colors.black.withValues(alpha: 0.65)
                      : Colors.white.withValues(alpha: 0.85),
                  borderRadius: BorderRadius.circular(20),
                  boxShadow: const [
                    BoxShadow(
                      color: Colors.black26,
                      blurRadius: 4,
                      offset: Offset(0, 2),
                    ),
                  ],
                ),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    SizedBox(
                      width: 14,
                      height: 14,
                      child: CircularProgressIndicator(
                        color: spinnerColor,
                        strokeWidth: 2,
                      ),
                    ),
                    const SizedBox(width: 8),
                    Text(
                      togglingLabel,
                      style: Theme.of(context).textTheme.bodySmall?.copyWith(
                            color: textColor,
                            fontWeight: FontWeight.w500,
                          ),
                    ),
                  ],
                ),
              ),
            ),
          );

      // Wrap in container with optional background color
      if (backgroundColor != null) {
        return ColoredBox(
          color: backgroundColor,
          child: Stack(
            children: [canvas, if (isToggling) buildLoadingOverlay()],
          ),
        );
      }

      // Return canvas with loading overlay
      return Stack(children: [canvas, if (isToggling) buildLoadingOverlay()]);
    },
  );
}