mirror of
				https://github.com/dancojocaru2000/logic-circuits-simulator.git
				synced 2025-11-04 00:46:32 +02:00 
			
		
		
		
	Implemented partial simulation and design*
- Implemented partial (step by step) simulation of visually designed components - Implemented moving components in design mode and simulating components in simulation mode (click inputs to toggle) TODO: - add/remove subcomponents, wires via GUI - add GUI for step by step simulation
This commit is contained in:
		
							parent
							
								
									4a6caee702
								
							
						
					
					
						commit
						c2d5d86554
					
				
					 11 changed files with 2035 additions and 99 deletions
				
			
		
							
								
								
									
										296
									
								
								lib/components/visual_component.dart
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								lib/components/visual_component.dart
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,296 @@
 | 
			
		|||
import 'dart:math';
 | 
			
		||||
import 'dart:ui';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.dart';
 | 
			
		||||
 | 
			
		||||
class VisualComponent extends HookWidget {
 | 
			
		||||
  final String name;
 | 
			
		||||
  final List<String> inputs;
 | 
			
		||||
  final List<String> outputs;
 | 
			
		||||
  final Map<String, Color?> inputColors;
 | 
			
		||||
  final Map<String, Color?> outputColors;
 | 
			
		||||
 | 
			
		||||
  VisualComponent({super.key, required this.name, required this.inputs, required this.outputs, Map<String, Color?>? inputColors, Map<String, Color?>? outputColors}) 
 | 
			
		||||
    : inputColors = inputColors ?? {}
 | 
			
		||||
    , outputColors = outputColors ?? {};
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final hovered = useState(false);
 | 
			
		||||
 | 
			
		||||
    final inputsWidth = inputs.map((input) => IOLabel.getNeededWidth(context, input)).fold<double>(0, (previousValue, element) => max(previousValue, element));
 | 
			
		||||
    final outputsWidth = outputs.map((output) => IOLabel.getNeededWidth(context, output)).fold<double>(0, (previousValue, element) => max(previousValue, element));
 | 
			
		||||
 | 
			
		||||
    return MouseRegion(
 | 
			
		||||
      onEnter: (event) => hovered.value = true,
 | 
			
		||||
      onExit: (event) => hovered.value = false,
 | 
			
		||||
      child: Row(
 | 
			
		||||
        children: [
 | 
			
		||||
          Column(
 | 
			
		||||
            children: [
 | 
			
		||||
              for (final input in inputs) Padding(
 | 
			
		||||
                padding: const EdgeInsets.symmetric(vertical: 5.0),
 | 
			
		||||
                  child: IOLabel(
 | 
			
		||||
                    label: input,
 | 
			
		||||
                    input: true,
 | 
			
		||||
                    lineColor: hovered.value 
 | 
			
		||||
                      ? Theme.of(context).colorScheme.primary 
 | 
			
		||||
                      : inputColors[input] ?? Colors.black,
 | 
			
		||||
                    width: inputsWidth,
 | 
			
		||||
                  ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
          Container(
 | 
			
		||||
            width: 100,
 | 
			
		||||
            decoration: BoxDecoration(
 | 
			
		||||
              border: Border.all(
 | 
			
		||||
                color: hovered.value ? Theme.of(context).colorScheme.primary : Colors.black,
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            child: Center(
 | 
			
		||||
              child: Text(
 | 
			
		||||
                name,
 | 
			
		||||
                softWrap: true,
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
          Column(
 | 
			
		||||
            children: [
 | 
			
		||||
              for (final output in outputs) Padding(
 | 
			
		||||
                padding: const EdgeInsets.symmetric(vertical: 5.0),
 | 
			
		||||
                  child: IOLabel(
 | 
			
		||||
                    label: output,
 | 
			
		||||
                    input: false,
 | 
			
		||||
                    lineColor: hovered.value 
 | 
			
		||||
                      ? Theme.of(context).colorScheme.primary 
 | 
			
		||||
                      : outputColors[output] ?? Colors.black,
 | 
			
		||||
                    width: outputsWidth,
 | 
			
		||||
                  ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static double getNeededWidth(BuildContext context, List<String> inputs, List<String> outputs, [TextStyle? textStyle]) {
 | 
			
		||||
    final inputsWidth = inputs.map((input) => IOLabel.getNeededWidth(context, input, textStyle)).fold<double>(0, (previousValue, element) => max(previousValue, element));
 | 
			
		||||
    final outputsWidth = outputs.map((output) => IOLabel.getNeededWidth(context, output, textStyle)).fold<double>(0, (previousValue, element) => max(previousValue, element));
 | 
			
		||||
    return inputsWidth + outputsWidth + 100;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static double getHeightOfIO(BuildContext context, List<String> options, int index, [TextStyle? textStyle]) {
 | 
			
		||||
    assert(index < options.length);
 | 
			
		||||
    getHeightOfText(String text) {
 | 
			
		||||
      final textPainter = TextPainter(
 | 
			
		||||
        text: TextSpan(
 | 
			
		||||
          text: text,
 | 
			
		||||
          style: (textStyle ?? DefaultTextStyle.of(context).style).merge(
 | 
			
		||||
            const TextStyle(
 | 
			
		||||
              inherit: true,
 | 
			
		||||
              fontFeatures: [
 | 
			
		||||
                FontFeature.tabularFigures(),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
        textDirection: TextDirection.ltr,
 | 
			
		||||
        maxLines: 1,
 | 
			
		||||
      )..layout();
 | 
			
		||||
      return textPainter.height;
 | 
			
		||||
    }
 | 
			
		||||
    var result = 0.0;
 | 
			
		||||
    for (var i = 0; i < index; i++) {
 | 
			
		||||
      result += 5.0 + getHeightOfText(options[i]) + 5.0;
 | 
			
		||||
    }
 | 
			
		||||
    result += 5.0 + getHeightOfText(options[index]);
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class IOComponent extends HookWidget {
 | 
			
		||||
  final bool input;
 | 
			
		||||
  final String name;
 | 
			
		||||
  final double width;
 | 
			
		||||
  final double circleDiameter;
 | 
			
		||||
  final Color? color;
 | 
			
		||||
  final void Function()? onTap;
 | 
			
		||||
 | 
			
		||||
  const IOComponent({super.key, required this.name, required this.input, this.width = 100, this.circleDiameter = 20, this.color, this.onTap});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final hovered = useState(false);
 | 
			
		||||
 | 
			
		||||
    return MouseRegion(
 | 
			
		||||
      onEnter: (event) => hovered.value = true,
 | 
			
		||||
      onExit: (event) => hovered.value = false,
 | 
			
		||||
      hitTestBehavior: HitTestBehavior.translucent,
 | 
			
		||||
      child: GestureDetector(
 | 
			
		||||
        onTap: onTap,
 | 
			
		||||
        child: Builder(
 | 
			
		||||
          builder: (context) {
 | 
			
		||||
            final lineColor = hovered.value ? Theme.of(context).colorScheme.primary : color ?? Colors.black;
 | 
			
		||||
      
 | 
			
		||||
            return Row(
 | 
			
		||||
              crossAxisAlignment: CrossAxisAlignment.center,
 | 
			
		||||
              children: [
 | 
			
		||||
                if (input) Container(
 | 
			
		||||
                  width: circleDiameter,
 | 
			
		||||
                  height: circleDiameter,
 | 
			
		||||
                  decoration: BoxDecoration(
 | 
			
		||||
                    border: Border.all(color: lineColor),
 | 
			
		||||
                    shape: BoxShape.circle,
 | 
			
		||||
                    color: color,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
                Padding(
 | 
			
		||||
                  padding: EdgeInsets.only(bottom: circleDiameter - 2),
 | 
			
		||||
                  child: IOLabel(
 | 
			
		||||
                    label: name,
 | 
			
		||||
                    input: !input,
 | 
			
		||||
                    lineColor: lineColor,
 | 
			
		||||
                    width: width - circleDiameter,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
                if (!input) Container(
 | 
			
		||||
                  width: circleDiameter,
 | 
			
		||||
                  height: circleDiameter,
 | 
			
		||||
                  decoration: BoxDecoration(
 | 
			
		||||
                    border: Border.all(color: lineColor),
 | 
			
		||||
                    shape: BoxShape.circle,
 | 
			
		||||
                    color: color,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ],
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static double getNeededWidth(BuildContext context, String name, {double circleDiameter = 20, TextStyle? textStyle}) {
 | 
			
		||||
    return circleDiameter + IOLabel.getNeededWidth(context, name, textStyle);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class IOLabel extends StatelessWidget {
 | 
			
		||||
  final bool input;
 | 
			
		||||
  final String label;
 | 
			
		||||
  final Color lineColor;
 | 
			
		||||
  final double width;
 | 
			
		||||
 | 
			
		||||
  const IOLabel({super.key, required this.lineColor, required this.label, required this.input, this.width = 80});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Container(
 | 
			
		||||
      width: width,
 | 
			
		||||
      height: 20,
 | 
			
		||||
      decoration: BoxDecoration(
 | 
			
		||||
        border: Border(
 | 
			
		||||
          bottom: BorderSide(color: lineColor),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      child: Align(
 | 
			
		||||
        alignment: input ? Alignment.bottomRight : Alignment.bottomLeft,
 | 
			
		||||
        child: Padding(
 | 
			
		||||
          padding: const EdgeInsets.symmetric(horizontal: 4.0),
 | 
			
		||||
          child: Text(
 | 
			
		||||
            label,
 | 
			
		||||
            style: const TextStyle(
 | 
			
		||||
              inherit: true,
 | 
			
		||||
              fontFeatures: [
 | 
			
		||||
                FontFeature.tabularFigures(),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static double getNeededWidth(BuildContext context, String text, [TextStyle? textStyle]) {
 | 
			
		||||
    final textPainter = TextPainter(
 | 
			
		||||
      text: TextSpan(
 | 
			
		||||
        text: text,
 | 
			
		||||
        style: (textStyle ?? DefaultTextStyle.of(context).style).merge(
 | 
			
		||||
          const TextStyle(
 | 
			
		||||
            inherit: true,
 | 
			
		||||
            fontFeatures: [
 | 
			
		||||
              FontFeature.tabularFigures(),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      textDirection: TextDirection.ltr,
 | 
			
		||||
      maxLines: 1,
 | 
			
		||||
    )..layout();
 | 
			
		||||
    return textPainter.width + 10;
 | 
			
		||||
  }  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class WireWidget extends StatelessWidget {
 | 
			
		||||
  final Offset from;
 | 
			
		||||
  final Offset to;
 | 
			
		||||
  final Color color;
 | 
			
		||||
 | 
			
		||||
  const WireWidget({
 | 
			
		||||
    required this.from,
 | 
			
		||||
    required this.to,
 | 
			
		||||
    this.color = Colors.black,
 | 
			
		||||
    super.key,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return CustomPaint(
 | 
			
		||||
      painter: _WireCustomPainter(
 | 
			
		||||
        color: color, 
 | 
			
		||||
        primaryDiagonal: 
 | 
			
		||||
          (from.dx < to.dx && from.dy < to.dy) || 
 | 
			
		||||
          (from.dx > to.dx && from.dy > to.dy),
 | 
			
		||||
      ),
 | 
			
		||||
      child: SizedBox(
 | 
			
		||||
        height: (to - from).dy.abs(),
 | 
			
		||||
        width: (to - from).dx.abs(),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _WireCustomPainter extends CustomPainter {
 | 
			
		||||
  final Color color;
 | 
			
		||||
  final bool primaryDiagonal;
 | 
			
		||||
 | 
			
		||||
  const _WireCustomPainter({required this.color, required this.primaryDiagonal});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void paint(Canvas canvas, Size size) {
 | 
			
		||||
    final paint = Paint()
 | 
			
		||||
      ..color = color;
 | 
			
		||||
    if (primaryDiagonal) {
 | 
			
		||||
      canvas.drawLine(
 | 
			
		||||
        Offset.zero,
 | 
			
		||||
        Offset(size.width, size.height),
 | 
			
		||||
        paint,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      canvas.drawLine(
 | 
			
		||||
        Offset(size.width, 0),
 | 
			
		||||
        Offset(0, size.height),
 | 
			
		||||
        paint,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
export 'package:logic_circuits_simulator/models/projects.dart';
 | 
			
		||||
export 'package:logic_circuits_simulator/models/project.dart';
 | 
			
		||||
export 'package:logic_circuits_simulator/models/component.dart';
 | 
			
		||||
export 'package:logic_circuits_simulator/models/design.dart';
 | 
			
		||||
export 'package:logic_circuits_simulator/models/project.dart';
 | 
			
		||||
export 'package:logic_circuits_simulator/models/projects.dart';
 | 
			
		||||
export 'package:logic_circuits_simulator/models/wiring.dart';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										60
									
								
								lib/models/design.dart
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								lib/models/design.dart
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
import 'package:freezed_annotation/freezed_annotation.dart';
 | 
			
		||||
 | 
			
		||||
part 'design.freezed.dart';
 | 
			
		||||
part 'design.g.dart';
 | 
			
		||||
 | 
			
		||||
@freezed
 | 
			
		||||
class Design with _$Design {
 | 
			
		||||
  const factory Design({
 | 
			
		||||
    required List<DesignComponent> components,
 | 
			
		||||
    required List<DesignWire> wires,
 | 
			
		||||
    required List<DesignInput> inputs,
 | 
			
		||||
    required List<DesignOutput> outputs,
 | 
			
		||||
  }) = _Design;
 | 
			
		||||
 | 
			
		||||
  factory Design.fromJson(Map<String, dynamic> json) => _$DesignFromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@freezed
 | 
			
		||||
class DesignComponent with _$DesignComponent {
 | 
			
		||||
  const factory DesignComponent({
 | 
			
		||||
    required String instanceId,
 | 
			
		||||
    required double x,
 | 
			
		||||
    required double y,
 | 
			
		||||
  }) = _DesignComponent;
 | 
			
		||||
 | 
			
		||||
  factory DesignComponent.fromJson(Map<String, dynamic> json) => _$DesignComponentFromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@freezed
 | 
			
		||||
class DesignWire with _$DesignWire {
 | 
			
		||||
  const factory DesignWire({
 | 
			
		||||
    required String wireId,
 | 
			
		||||
    required double x,
 | 
			
		||||
    required double y,
 | 
			
		||||
  }) = _DesignWire;
 | 
			
		||||
 | 
			
		||||
  factory DesignWire.fromJson(Map<String, dynamic> json) => _$DesignWireFromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@freezed
 | 
			
		||||
class DesignInput with _$DesignInput {
 | 
			
		||||
  const factory DesignInput({
 | 
			
		||||
    required String name,
 | 
			
		||||
    required double x,
 | 
			
		||||
    required double y,
 | 
			
		||||
  }) = _DesignInput;
 | 
			
		||||
 | 
			
		||||
  factory DesignInput.fromJson(Map<String, dynamic> json) => _$DesignInputFromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@freezed
 | 
			
		||||
class DesignOutput with _$DesignOutput {
 | 
			
		||||
  const factory DesignOutput({
 | 
			
		||||
    required String name,
 | 
			
		||||
    required double x,
 | 
			
		||||
    required double y,
 | 
			
		||||
  }) = _DesignOutput;
 | 
			
		||||
 | 
			
		||||
  factory DesignOutput.fromJson(Map<String, dynamic> json) => _$DesignOutputFromJson(json);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										908
									
								
								lib/models/design.freezed.dart
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										908
									
								
								lib/models/design.freezed.dart
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,908 @@
 | 
			
		|||
// coverage:ignore-file
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
// ignore_for_file: type=lint
 | 
			
		||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
 | 
			
		||||
 | 
			
		||||
part of 'design.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// FreezedGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
T _$identity<T>(T value) => value;
 | 
			
		||||
 | 
			
		||||
final _privateConstructorUsedError = UnsupportedError(
 | 
			
		||||
    'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
 | 
			
		||||
 | 
			
		||||
Design _$DesignFromJson(Map<String, dynamic> json) {
 | 
			
		||||
  return _Design.fromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
mixin _$Design {
 | 
			
		||||
  List<DesignComponent> get components => throw _privateConstructorUsedError;
 | 
			
		||||
  List<DesignWire> get wires => throw _privateConstructorUsedError;
 | 
			
		||||
  List<DesignInput> get inputs => throw _privateConstructorUsedError;
 | 
			
		||||
  List<DesignOutput> get outputs => throw _privateConstructorUsedError;
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  $DesignCopyWith<Design> get copyWith => throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class $DesignCopyWith<$Res> {
 | 
			
		||||
  factory $DesignCopyWith(Design value, $Res Function(Design) then) =
 | 
			
		||||
      _$DesignCopyWithImpl<$Res>;
 | 
			
		||||
  $Res call(
 | 
			
		||||
      {List<DesignComponent> components,
 | 
			
		||||
      List<DesignWire> wires,
 | 
			
		||||
      List<DesignInput> inputs,
 | 
			
		||||
      List<DesignOutput> outputs});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class _$DesignCopyWithImpl<$Res> implements $DesignCopyWith<$Res> {
 | 
			
		||||
  _$DesignCopyWithImpl(this._value, this._then);
 | 
			
		||||
 | 
			
		||||
  final Design _value;
 | 
			
		||||
  // ignore: unused_field
 | 
			
		||||
  final $Res Function(Design) _then;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? components = freezed,
 | 
			
		||||
    Object? wires = freezed,
 | 
			
		||||
    Object? inputs = freezed,
 | 
			
		||||
    Object? outputs = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_value.copyWith(
 | 
			
		||||
      components: components == freezed
 | 
			
		||||
          ? _value.components
 | 
			
		||||
          : components // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignComponent>,
 | 
			
		||||
      wires: wires == freezed
 | 
			
		||||
          ? _value.wires
 | 
			
		||||
          : wires // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignWire>,
 | 
			
		||||
      inputs: inputs == freezed
 | 
			
		||||
          ? _value.inputs
 | 
			
		||||
          : inputs // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignInput>,
 | 
			
		||||
      outputs: outputs == freezed
 | 
			
		||||
          ? _value.outputs
 | 
			
		||||
          : outputs // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignOutput>,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class _$$_DesignCopyWith<$Res> implements $DesignCopyWith<$Res> {
 | 
			
		||||
  factory _$$_DesignCopyWith(_$_Design value, $Res Function(_$_Design) then) =
 | 
			
		||||
      __$$_DesignCopyWithImpl<$Res>;
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call(
 | 
			
		||||
      {List<DesignComponent> components,
 | 
			
		||||
      List<DesignWire> wires,
 | 
			
		||||
      List<DesignInput> inputs,
 | 
			
		||||
      List<DesignOutput> outputs});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class __$$_DesignCopyWithImpl<$Res> extends _$DesignCopyWithImpl<$Res>
 | 
			
		||||
    implements _$$_DesignCopyWith<$Res> {
 | 
			
		||||
  __$$_DesignCopyWithImpl(_$_Design _value, $Res Function(_$_Design) _then)
 | 
			
		||||
      : super(_value, (v) => _then(v as _$_Design));
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _$_Design get _value => super._value as _$_Design;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? components = freezed,
 | 
			
		||||
    Object? wires = freezed,
 | 
			
		||||
    Object? inputs = freezed,
 | 
			
		||||
    Object? outputs = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_$_Design(
 | 
			
		||||
      components: components == freezed
 | 
			
		||||
          ? _value._components
 | 
			
		||||
          : components // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignComponent>,
 | 
			
		||||
      wires: wires == freezed
 | 
			
		||||
          ? _value._wires
 | 
			
		||||
          : wires // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignWire>,
 | 
			
		||||
      inputs: inputs == freezed
 | 
			
		||||
          ? _value._inputs
 | 
			
		||||
          : inputs // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignInput>,
 | 
			
		||||
      outputs: outputs == freezed
 | 
			
		||||
          ? _value._outputs
 | 
			
		||||
          : outputs // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as List<DesignOutput>,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
@JsonSerializable()
 | 
			
		||||
class _$_Design implements _Design {
 | 
			
		||||
  const _$_Design(
 | 
			
		||||
      {required final List<DesignComponent> components,
 | 
			
		||||
      required final List<DesignWire> wires,
 | 
			
		||||
      required final List<DesignInput> inputs,
 | 
			
		||||
      required final List<DesignOutput> outputs})
 | 
			
		||||
      : _components = components,
 | 
			
		||||
        _wires = wires,
 | 
			
		||||
        _inputs = inputs,
 | 
			
		||||
        _outputs = outputs;
 | 
			
		||||
 | 
			
		||||
  factory _$_Design.fromJson(Map<String, dynamic> json) =>
 | 
			
		||||
      _$$_DesignFromJson(json);
 | 
			
		||||
 | 
			
		||||
  final List<DesignComponent> _components;
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignComponent> get components {
 | 
			
		||||
    // ignore: implicit_dynamic_type
 | 
			
		||||
    return EqualUnmodifiableListView(_components);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final List<DesignWire> _wires;
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignWire> get wires {
 | 
			
		||||
    // ignore: implicit_dynamic_type
 | 
			
		||||
    return EqualUnmodifiableListView(_wires);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final List<DesignInput> _inputs;
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignInput> get inputs {
 | 
			
		||||
    // ignore: implicit_dynamic_type
 | 
			
		||||
    return EqualUnmodifiableListView(_inputs);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final List<DesignOutput> _outputs;
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignOutput> get outputs {
 | 
			
		||||
    // ignore: implicit_dynamic_type
 | 
			
		||||
    return EqualUnmodifiableListView(_outputs);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() {
 | 
			
		||||
    return 'Design(components: $components, wires: $wires, inputs: $inputs, outputs: $outputs)';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(dynamic other) {
 | 
			
		||||
    return identical(this, other) ||
 | 
			
		||||
        (other.runtimeType == runtimeType &&
 | 
			
		||||
            other is _$_Design &&
 | 
			
		||||
            const DeepCollectionEquality()
 | 
			
		||||
                .equals(other._components, _components) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other._wires, _wires) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other._inputs, _inputs) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other._outputs, _outputs));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => Object.hash(
 | 
			
		||||
      runtimeType,
 | 
			
		||||
      const DeepCollectionEquality().hash(_components),
 | 
			
		||||
      const DeepCollectionEquality().hash(_wires),
 | 
			
		||||
      const DeepCollectionEquality().hash(_inputs),
 | 
			
		||||
      const DeepCollectionEquality().hash(_outputs));
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  _$$_DesignCopyWith<_$_Design> get copyWith =>
 | 
			
		||||
      __$$_DesignCopyWithImpl<_$_Design>(this, _$identity);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    return _$$_DesignToJson(this);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class _Design implements Design {
 | 
			
		||||
  const factory _Design(
 | 
			
		||||
      {required final List<DesignComponent> components,
 | 
			
		||||
      required final List<DesignWire> wires,
 | 
			
		||||
      required final List<DesignInput> inputs,
 | 
			
		||||
      required final List<DesignOutput> outputs}) = _$_Design;
 | 
			
		||||
 | 
			
		||||
  factory _Design.fromJson(Map<String, dynamic> json) = _$_Design.fromJson;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignComponent> get components => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignWire> get wires => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignInput> get inputs => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  List<DesignOutput> get outputs => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  _$$_DesignCopyWith<_$_Design> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DesignComponent _$DesignComponentFromJson(Map<String, dynamic> json) {
 | 
			
		||||
  return _DesignComponent.fromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
mixin _$DesignComponent {
 | 
			
		||||
  String get instanceId => throw _privateConstructorUsedError;
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  $DesignComponentCopyWith<DesignComponent> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class $DesignComponentCopyWith<$Res> {
 | 
			
		||||
  factory $DesignComponentCopyWith(
 | 
			
		||||
          DesignComponent value, $Res Function(DesignComponent) then) =
 | 
			
		||||
      _$DesignComponentCopyWithImpl<$Res>;
 | 
			
		||||
  $Res call({String instanceId, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class _$DesignComponentCopyWithImpl<$Res>
 | 
			
		||||
    implements $DesignComponentCopyWith<$Res> {
 | 
			
		||||
  _$DesignComponentCopyWithImpl(this._value, this._then);
 | 
			
		||||
 | 
			
		||||
  final DesignComponent _value;
 | 
			
		||||
  // ignore: unused_field
 | 
			
		||||
  final $Res Function(DesignComponent) _then;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? instanceId = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_value.copyWith(
 | 
			
		||||
      instanceId: instanceId == freezed
 | 
			
		||||
          ? _value.instanceId
 | 
			
		||||
          : instanceId // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class _$$_DesignComponentCopyWith<$Res>
 | 
			
		||||
    implements $DesignComponentCopyWith<$Res> {
 | 
			
		||||
  factory _$$_DesignComponentCopyWith(
 | 
			
		||||
          _$_DesignComponent value, $Res Function(_$_DesignComponent) then) =
 | 
			
		||||
      __$$_DesignComponentCopyWithImpl<$Res>;
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({String instanceId, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class __$$_DesignComponentCopyWithImpl<$Res>
 | 
			
		||||
    extends _$DesignComponentCopyWithImpl<$Res>
 | 
			
		||||
    implements _$$_DesignComponentCopyWith<$Res> {
 | 
			
		||||
  __$$_DesignComponentCopyWithImpl(
 | 
			
		||||
      _$_DesignComponent _value, $Res Function(_$_DesignComponent) _then)
 | 
			
		||||
      : super(_value, (v) => _then(v as _$_DesignComponent));
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _$_DesignComponent get _value => super._value as _$_DesignComponent;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? instanceId = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_$_DesignComponent(
 | 
			
		||||
      instanceId: instanceId == freezed
 | 
			
		||||
          ? _value.instanceId
 | 
			
		||||
          : instanceId // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
@JsonSerializable()
 | 
			
		||||
class _$_DesignComponent implements _DesignComponent {
 | 
			
		||||
  const _$_DesignComponent(
 | 
			
		||||
      {required this.instanceId, required this.x, required this.y});
 | 
			
		||||
 | 
			
		||||
  factory _$_DesignComponent.fromJson(Map<String, dynamic> json) =>
 | 
			
		||||
      _$$_DesignComponentFromJson(json);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  final String instanceId;
 | 
			
		||||
  @override
 | 
			
		||||
  final double x;
 | 
			
		||||
  @override
 | 
			
		||||
  final double y;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() {
 | 
			
		||||
    return 'DesignComponent(instanceId: $instanceId, x: $x, y: $y)';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(dynamic other) {
 | 
			
		||||
    return identical(this, other) ||
 | 
			
		||||
        (other.runtimeType == runtimeType &&
 | 
			
		||||
            other is _$_DesignComponent &&
 | 
			
		||||
            const DeepCollectionEquality()
 | 
			
		||||
                .equals(other.instanceId, instanceId) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.x, x) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.y, y));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => Object.hash(
 | 
			
		||||
      runtimeType,
 | 
			
		||||
      const DeepCollectionEquality().hash(instanceId),
 | 
			
		||||
      const DeepCollectionEquality().hash(x),
 | 
			
		||||
      const DeepCollectionEquality().hash(y));
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  _$$_DesignComponentCopyWith<_$_DesignComponent> get copyWith =>
 | 
			
		||||
      __$$_DesignComponentCopyWithImpl<_$_DesignComponent>(this, _$identity);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    return _$$_DesignComponentToJson(this);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class _DesignComponent implements DesignComponent {
 | 
			
		||||
  const factory _DesignComponent(
 | 
			
		||||
      {required final String instanceId,
 | 
			
		||||
      required final double x,
 | 
			
		||||
      required final double y}) = _$_DesignComponent;
 | 
			
		||||
 | 
			
		||||
  factory _DesignComponent.fromJson(Map<String, dynamic> json) =
 | 
			
		||||
      _$_DesignComponent.fromJson;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String get instanceId => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  _$$_DesignComponentCopyWith<_$_DesignComponent> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DesignWire _$DesignWireFromJson(Map<String, dynamic> json) {
 | 
			
		||||
  return _DesignWire.fromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
mixin _$DesignWire {
 | 
			
		||||
  String get wireId => throw _privateConstructorUsedError;
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  $DesignWireCopyWith<DesignWire> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class $DesignWireCopyWith<$Res> {
 | 
			
		||||
  factory $DesignWireCopyWith(
 | 
			
		||||
          DesignWire value, $Res Function(DesignWire) then) =
 | 
			
		||||
      _$DesignWireCopyWithImpl<$Res>;
 | 
			
		||||
  $Res call({String wireId, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class _$DesignWireCopyWithImpl<$Res> implements $DesignWireCopyWith<$Res> {
 | 
			
		||||
  _$DesignWireCopyWithImpl(this._value, this._then);
 | 
			
		||||
 | 
			
		||||
  final DesignWire _value;
 | 
			
		||||
  // ignore: unused_field
 | 
			
		||||
  final $Res Function(DesignWire) _then;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? wireId = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_value.copyWith(
 | 
			
		||||
      wireId: wireId == freezed
 | 
			
		||||
          ? _value.wireId
 | 
			
		||||
          : wireId // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class _$$_DesignWireCopyWith<$Res>
 | 
			
		||||
    implements $DesignWireCopyWith<$Res> {
 | 
			
		||||
  factory _$$_DesignWireCopyWith(
 | 
			
		||||
          _$_DesignWire value, $Res Function(_$_DesignWire) then) =
 | 
			
		||||
      __$$_DesignWireCopyWithImpl<$Res>;
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({String wireId, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class __$$_DesignWireCopyWithImpl<$Res> extends _$DesignWireCopyWithImpl<$Res>
 | 
			
		||||
    implements _$$_DesignWireCopyWith<$Res> {
 | 
			
		||||
  __$$_DesignWireCopyWithImpl(
 | 
			
		||||
      _$_DesignWire _value, $Res Function(_$_DesignWire) _then)
 | 
			
		||||
      : super(_value, (v) => _then(v as _$_DesignWire));
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _$_DesignWire get _value => super._value as _$_DesignWire;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? wireId = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_$_DesignWire(
 | 
			
		||||
      wireId: wireId == freezed
 | 
			
		||||
          ? _value.wireId
 | 
			
		||||
          : wireId // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
@JsonSerializable()
 | 
			
		||||
class _$_DesignWire implements _DesignWire {
 | 
			
		||||
  const _$_DesignWire({required this.wireId, required this.x, required this.y});
 | 
			
		||||
 | 
			
		||||
  factory _$_DesignWire.fromJson(Map<String, dynamic> json) =>
 | 
			
		||||
      _$$_DesignWireFromJson(json);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  final String wireId;
 | 
			
		||||
  @override
 | 
			
		||||
  final double x;
 | 
			
		||||
  @override
 | 
			
		||||
  final double y;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() {
 | 
			
		||||
    return 'DesignWire(wireId: $wireId, x: $x, y: $y)';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(dynamic other) {
 | 
			
		||||
    return identical(this, other) ||
 | 
			
		||||
        (other.runtimeType == runtimeType &&
 | 
			
		||||
            other is _$_DesignWire &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.wireId, wireId) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.x, x) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.y, y));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => Object.hash(
 | 
			
		||||
      runtimeType,
 | 
			
		||||
      const DeepCollectionEquality().hash(wireId),
 | 
			
		||||
      const DeepCollectionEquality().hash(x),
 | 
			
		||||
      const DeepCollectionEquality().hash(y));
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  _$$_DesignWireCopyWith<_$_DesignWire> get copyWith =>
 | 
			
		||||
      __$$_DesignWireCopyWithImpl<_$_DesignWire>(this, _$identity);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    return _$$_DesignWireToJson(this);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class _DesignWire implements DesignWire {
 | 
			
		||||
  const factory _DesignWire(
 | 
			
		||||
      {required final String wireId,
 | 
			
		||||
      required final double x,
 | 
			
		||||
      required final double y}) = _$_DesignWire;
 | 
			
		||||
 | 
			
		||||
  factory _DesignWire.fromJson(Map<String, dynamic> json) =
 | 
			
		||||
      _$_DesignWire.fromJson;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String get wireId => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  _$$_DesignWireCopyWith<_$_DesignWire> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DesignInput _$DesignInputFromJson(Map<String, dynamic> json) {
 | 
			
		||||
  return _DesignInput.fromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
mixin _$DesignInput {
 | 
			
		||||
  String get name => throw _privateConstructorUsedError;
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  $DesignInputCopyWith<DesignInput> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class $DesignInputCopyWith<$Res> {
 | 
			
		||||
  factory $DesignInputCopyWith(
 | 
			
		||||
          DesignInput value, $Res Function(DesignInput) then) =
 | 
			
		||||
      _$DesignInputCopyWithImpl<$Res>;
 | 
			
		||||
  $Res call({String name, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class _$DesignInputCopyWithImpl<$Res> implements $DesignInputCopyWith<$Res> {
 | 
			
		||||
  _$DesignInputCopyWithImpl(this._value, this._then);
 | 
			
		||||
 | 
			
		||||
  final DesignInput _value;
 | 
			
		||||
  // ignore: unused_field
 | 
			
		||||
  final $Res Function(DesignInput) _then;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? name = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_value.copyWith(
 | 
			
		||||
      name: name == freezed
 | 
			
		||||
          ? _value.name
 | 
			
		||||
          : name // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class _$$_DesignInputCopyWith<$Res>
 | 
			
		||||
    implements $DesignInputCopyWith<$Res> {
 | 
			
		||||
  factory _$$_DesignInputCopyWith(
 | 
			
		||||
          _$_DesignInput value, $Res Function(_$_DesignInput) then) =
 | 
			
		||||
      __$$_DesignInputCopyWithImpl<$Res>;
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({String name, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class __$$_DesignInputCopyWithImpl<$Res> extends _$DesignInputCopyWithImpl<$Res>
 | 
			
		||||
    implements _$$_DesignInputCopyWith<$Res> {
 | 
			
		||||
  __$$_DesignInputCopyWithImpl(
 | 
			
		||||
      _$_DesignInput _value, $Res Function(_$_DesignInput) _then)
 | 
			
		||||
      : super(_value, (v) => _then(v as _$_DesignInput));
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _$_DesignInput get _value => super._value as _$_DesignInput;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? name = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_$_DesignInput(
 | 
			
		||||
      name: name == freezed
 | 
			
		||||
          ? _value.name
 | 
			
		||||
          : name // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
@JsonSerializable()
 | 
			
		||||
class _$_DesignInput implements _DesignInput {
 | 
			
		||||
  const _$_DesignInput({required this.name, required this.x, required this.y});
 | 
			
		||||
 | 
			
		||||
  factory _$_DesignInput.fromJson(Map<String, dynamic> json) =>
 | 
			
		||||
      _$$_DesignInputFromJson(json);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  final String name;
 | 
			
		||||
  @override
 | 
			
		||||
  final double x;
 | 
			
		||||
  @override
 | 
			
		||||
  final double y;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() {
 | 
			
		||||
    return 'DesignInput(name: $name, x: $x, y: $y)';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(dynamic other) {
 | 
			
		||||
    return identical(this, other) ||
 | 
			
		||||
        (other.runtimeType == runtimeType &&
 | 
			
		||||
            other is _$_DesignInput &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.name, name) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.x, x) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.y, y));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => Object.hash(
 | 
			
		||||
      runtimeType,
 | 
			
		||||
      const DeepCollectionEquality().hash(name),
 | 
			
		||||
      const DeepCollectionEquality().hash(x),
 | 
			
		||||
      const DeepCollectionEquality().hash(y));
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  _$$_DesignInputCopyWith<_$_DesignInput> get copyWith =>
 | 
			
		||||
      __$$_DesignInputCopyWithImpl<_$_DesignInput>(this, _$identity);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    return _$$_DesignInputToJson(this);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class _DesignInput implements DesignInput {
 | 
			
		||||
  const factory _DesignInput(
 | 
			
		||||
      {required final String name,
 | 
			
		||||
      required final double x,
 | 
			
		||||
      required final double y}) = _$_DesignInput;
 | 
			
		||||
 | 
			
		||||
  factory _DesignInput.fromJson(Map<String, dynamic> json) =
 | 
			
		||||
      _$_DesignInput.fromJson;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String get name => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  _$$_DesignInputCopyWith<_$_DesignInput> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DesignOutput _$DesignOutputFromJson(Map<String, dynamic> json) {
 | 
			
		||||
  return _DesignOutput.fromJson(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
mixin _$DesignOutput {
 | 
			
		||||
  String get name => throw _privateConstructorUsedError;
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  $DesignOutputCopyWith<DesignOutput> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class $DesignOutputCopyWith<$Res> {
 | 
			
		||||
  factory $DesignOutputCopyWith(
 | 
			
		||||
          DesignOutput value, $Res Function(DesignOutput) then) =
 | 
			
		||||
      _$DesignOutputCopyWithImpl<$Res>;
 | 
			
		||||
  $Res call({String name, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class _$DesignOutputCopyWithImpl<$Res> implements $DesignOutputCopyWith<$Res> {
 | 
			
		||||
  _$DesignOutputCopyWithImpl(this._value, this._then);
 | 
			
		||||
 | 
			
		||||
  final DesignOutput _value;
 | 
			
		||||
  // ignore: unused_field
 | 
			
		||||
  final $Res Function(DesignOutput) _then;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? name = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_value.copyWith(
 | 
			
		||||
      name: name == freezed
 | 
			
		||||
          ? _value.name
 | 
			
		||||
          : name // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
abstract class _$$_DesignOutputCopyWith<$Res>
 | 
			
		||||
    implements $DesignOutputCopyWith<$Res> {
 | 
			
		||||
  factory _$$_DesignOutputCopyWith(
 | 
			
		||||
          _$_DesignOutput value, $Res Function(_$_DesignOutput) then) =
 | 
			
		||||
      __$$_DesignOutputCopyWithImpl<$Res>;
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({String name, double x, double y});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
class __$$_DesignOutputCopyWithImpl<$Res>
 | 
			
		||||
    extends _$DesignOutputCopyWithImpl<$Res>
 | 
			
		||||
    implements _$$_DesignOutputCopyWith<$Res> {
 | 
			
		||||
  __$$_DesignOutputCopyWithImpl(
 | 
			
		||||
      _$_DesignOutput _value, $Res Function(_$_DesignOutput) _then)
 | 
			
		||||
      : super(_value, (v) => _then(v as _$_DesignOutput));
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _$_DesignOutput get _value => super._value as _$_DesignOutput;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  $Res call({
 | 
			
		||||
    Object? name = freezed,
 | 
			
		||||
    Object? x = freezed,
 | 
			
		||||
    Object? y = freezed,
 | 
			
		||||
  }) {
 | 
			
		||||
    return _then(_$_DesignOutput(
 | 
			
		||||
      name: name == freezed
 | 
			
		||||
          ? _value.name
 | 
			
		||||
          : name // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as String,
 | 
			
		||||
      x: x == freezed
 | 
			
		||||
          ? _value.x
 | 
			
		||||
          : x // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
      y: y == freezed
 | 
			
		||||
          ? _value.y
 | 
			
		||||
          : y // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
              as double,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @nodoc
 | 
			
		||||
@JsonSerializable()
 | 
			
		||||
class _$_DesignOutput implements _DesignOutput {
 | 
			
		||||
  const _$_DesignOutput({required this.name, required this.x, required this.y});
 | 
			
		||||
 | 
			
		||||
  factory _$_DesignOutput.fromJson(Map<String, dynamic> json) =>
 | 
			
		||||
      _$$_DesignOutputFromJson(json);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  final String name;
 | 
			
		||||
  @override
 | 
			
		||||
  final double x;
 | 
			
		||||
  @override
 | 
			
		||||
  final double y;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() {
 | 
			
		||||
    return 'DesignOutput(name: $name, x: $x, y: $y)';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(dynamic other) {
 | 
			
		||||
    return identical(this, other) ||
 | 
			
		||||
        (other.runtimeType == runtimeType &&
 | 
			
		||||
            other is _$_DesignOutput &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.name, name) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.x, x) &&
 | 
			
		||||
            const DeepCollectionEquality().equals(other.y, y));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => Object.hash(
 | 
			
		||||
      runtimeType,
 | 
			
		||||
      const DeepCollectionEquality().hash(name),
 | 
			
		||||
      const DeepCollectionEquality().hash(x),
 | 
			
		||||
      const DeepCollectionEquality().hash(y));
 | 
			
		||||
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  @override
 | 
			
		||||
  _$$_DesignOutputCopyWith<_$_DesignOutput> get copyWith =>
 | 
			
		||||
      __$$_DesignOutputCopyWithImpl<_$_DesignOutput>(this, _$identity);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    return _$$_DesignOutputToJson(this);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class _DesignOutput implements DesignOutput {
 | 
			
		||||
  const factory _DesignOutput(
 | 
			
		||||
      {required final String name,
 | 
			
		||||
      required final double x,
 | 
			
		||||
      required final double y}) = _$_DesignOutput;
 | 
			
		||||
 | 
			
		||||
  factory _DesignOutput.fromJson(Map<String, dynamic> json) =
 | 
			
		||||
      _$_DesignOutput.fromJson;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String get name => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get x => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  double get y => throw _privateConstructorUsedError;
 | 
			
		||||
  @override
 | 
			
		||||
  @JsonKey(ignore: true)
 | 
			
		||||
  _$$_DesignOutputCopyWith<_$_DesignOutput> get copyWith =>
 | 
			
		||||
      throw _privateConstructorUsedError;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								lib/models/design.g.dart
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								lib/models/design.g.dart
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,85 @@
 | 
			
		|||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'design.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// JsonSerializableGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
_$_Design _$$_DesignFromJson(Map<String, dynamic> json) => _$_Design(
 | 
			
		||||
      components: (json['components'] as List<dynamic>)
 | 
			
		||||
          .map((e) => DesignComponent.fromJson(e as Map<String, dynamic>))
 | 
			
		||||
          .toList(),
 | 
			
		||||
      wires: (json['wires'] as List<dynamic>)
 | 
			
		||||
          .map((e) => DesignWire.fromJson(e as Map<String, dynamic>))
 | 
			
		||||
          .toList(),
 | 
			
		||||
      inputs: (json['inputs'] as List<dynamic>)
 | 
			
		||||
          .map((e) => DesignInput.fromJson(e as Map<String, dynamic>))
 | 
			
		||||
          .toList(),
 | 
			
		||||
      outputs: (json['outputs'] as List<dynamic>)
 | 
			
		||||
          .map((e) => DesignOutput.fromJson(e as Map<String, dynamic>))
 | 
			
		||||
          .toList(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$$_DesignToJson(_$_Design instance) => <String, dynamic>{
 | 
			
		||||
      'components': instance.components,
 | 
			
		||||
      'wires': instance.wires,
 | 
			
		||||
      'inputs': instance.inputs,
 | 
			
		||||
      'outputs': instance.outputs,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
_$_DesignComponent _$$_DesignComponentFromJson(Map<String, dynamic> json) =>
 | 
			
		||||
    _$_DesignComponent(
 | 
			
		||||
      instanceId: json['instanceId'] as String,
 | 
			
		||||
      x: (json['x'] as num).toDouble(),
 | 
			
		||||
      y: (json['y'] as num).toDouble(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$$_DesignComponentToJson(_$_DesignComponent instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'instanceId': instance.instanceId,
 | 
			
		||||
      'x': instance.x,
 | 
			
		||||
      'y': instance.y,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
_$_DesignWire _$$_DesignWireFromJson(Map<String, dynamic> json) =>
 | 
			
		||||
    _$_DesignWire(
 | 
			
		||||
      wireId: json['wireId'] as String,
 | 
			
		||||
      x: (json['x'] as num).toDouble(),
 | 
			
		||||
      y: (json['y'] as num).toDouble(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$$_DesignWireToJson(_$_DesignWire instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'wireId': instance.wireId,
 | 
			
		||||
      'x': instance.x,
 | 
			
		||||
      'y': instance.y,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
_$_DesignInput _$$_DesignInputFromJson(Map<String, dynamic> json) =>
 | 
			
		||||
    _$_DesignInput(
 | 
			
		||||
      name: json['name'] as String,
 | 
			
		||||
      x: (json['x'] as num).toDouble(),
 | 
			
		||||
      y: (json['y'] as num).toDouble(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$$_DesignInputToJson(_$_DesignInput instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'name': instance.name,
 | 
			
		||||
      'x': instance.x,
 | 
			
		||||
      'y': instance.y,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
_$_DesignOutput _$$_DesignOutputFromJson(Map<String, dynamic> json) =>
 | 
			
		||||
    _$_DesignOutput(
 | 
			
		||||
      name: json['name'] as String,
 | 
			
		||||
      x: (json['x'] as num).toDouble(),
 | 
			
		||||
      y: (json['y'] as num).toDouble(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$$_DesignOutputToJson(_$_DesignOutput instance) =>
 | 
			
		||||
    <String, dynamic>{
 | 
			
		||||
      'name': instance.name,
 | 
			
		||||
      'x': instance.x,
 | 
			
		||||
      'y': instance.y,
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -1,12 +1,19 @@
 | 
			
		|||
import 'dart:math';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/components/visual_component.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/models.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/pages_arguments/design_component.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/state/component.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/utils/future_call_debounce.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/utils/provider_hook.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/utils/stack_canvas_controller_hook.dart';
 | 
			
		||||
import 'package:stack_canvas/stack_canvas.dart';
 | 
			
		||||
 | 
			
		||||
Key canvasKey = GlobalKey();
 | 
			
		||||
 | 
			
		||||
class DesignComponentPage extends HookWidget {
 | 
			
		||||
  final ComponentEntry component;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,23 +26,342 @@ class DesignComponentPage extends HookWidget {
 | 
			
		|||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final componentState = useProvider<ComponentState>();
 | 
			
		||||
    final canvasController = useStackCanvasController();
 | 
			
		||||
    final widgets = useState(<CanvasObject<Widget>>[]);
 | 
			
		||||
    final canvasController = useStackCanvasController(
 | 
			
		||||
      offsetReference: Reference.Center,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Simulation vars
 | 
			
		||||
    final isSimulating = useState(false);
 | 
			
		||||
    final simulatePartially = useState(false);
 | 
			
		||||
    
 | 
			
		||||
    useListenable(componentState.partialVisualSimulation!);
 | 
			
		||||
 | 
			
		||||
    final movingWidgetUpdater = useState<void Function(double dx, double dy)?>(null);
 | 
			
		||||
    final movingWidget = useState<dynamic>(null);
 | 
			
		||||
    final widgets = useMemoized(() => [
 | 
			
		||||
      for (final subcomponent in componentState.designDraft.components)
 | 
			
		||||
        CanvasObject(
 | 
			
		||||
          dx: subcomponent.x, 
 | 
			
		||||
          dy: subcomponent.y, 
 | 
			
		||||
          width: VisualComponent.getNeededWidth(
 | 
			
		||||
            context,
 | 
			
		||||
            componentState
 | 
			
		||||
                .getMetaByInstance(subcomponent.instanceId)
 | 
			
		||||
                .item2
 | 
			
		||||
                .inputs,
 | 
			
		||||
            componentState
 | 
			
		||||
                .getMetaByInstance(subcomponent.instanceId)
 | 
			
		||||
                .item2
 | 
			
		||||
                .outputs,
 | 
			
		||||
            Theme.of(context).textTheme.bodyMedium,
 | 
			
		||||
          ), 
 | 
			
		||||
          height: max(
 | 
			
		||||
            componentState.getMetaByInstance(subcomponent.instanceId).item2.inputs.length, 
 | 
			
		||||
            componentState.getMetaByInstance(subcomponent.instanceId).item2.outputs.length, 
 | 
			
		||||
          ) * 30 + 10, 
 | 
			
		||||
          child: Listener(
 | 
			
		||||
            behavior: HitTestBehavior.translucent,
 | 
			
		||||
            onPointerDown: (event) {
 | 
			
		||||
              final debouncer = FutureCallDebounce<List<double>>(
 | 
			
		||||
                futureCall: (xyList) {
 | 
			
		||||
                  final dx = xyList[0];
 | 
			
		||||
                  final dy = xyList[1];
 | 
			
		||||
                  return componentState.updateDesign(componentState.designDraft.copyWith(
 | 
			
		||||
                    components: componentState.designDraft.components.map(
 | 
			
		||||
                      (e) => e.instanceId == subcomponent.instanceId ? e.copyWith(
 | 
			
		||||
                        x: subcomponent.x + dx,
 | 
			
		||||
                        y: subcomponent.y + dy,
 | 
			
		||||
                      ) : e,
 | 
			
		||||
                    ).toList(),
 | 
			
		||||
                  ), commit: false);
 | 
			
		||||
                }, 
 | 
			
		||||
                combiner: (oldParams, newParams) {
 | 
			
		||||
                  return oldParams.zipWith([newParams], (deltas) => deltas.fold<double>(0.0, (prev, elem) => prev + elem)).toList();
 | 
			
		||||
                },
 | 
			
		||||
              );
 | 
			
		||||
              movingWidgetUpdater.value = (dx, dy) {
 | 
			
		||||
                debouncer.call([dx, dy]);
 | 
			
		||||
              };
 | 
			
		||||
              movingWidget.value = subcomponent;
 | 
			
		||||
            },
 | 
			
		||||
            onPointerUp: (event) {
 | 
			
		||||
              componentState.updateDesign(componentState.designDraft);
 | 
			
		||||
              movingWidgetUpdater.value = null;
 | 
			
		||||
              movingWidget.value = null;
 | 
			
		||||
            },
 | 
			
		||||
            child: MouseRegion(
 | 
			
		||||
              cursor: movingWidget.value == subcomponent ? SystemMouseCursors.move : MouseCursor.defer,
 | 
			
		||||
              child: VisualComponent(
 | 
			
		||||
                name: componentState.getMetaByInstance(subcomponent.instanceId).item2.componentName, 
 | 
			
		||||
                inputs: componentState.getMetaByInstance(subcomponent.instanceId).item2.inputs, 
 | 
			
		||||
                outputs: componentState.getMetaByInstance(subcomponent.instanceId).item2.outputs,
 | 
			
		||||
                inputColors: isSimulating.value ? {
 | 
			
		||||
                  for (final input in componentState.getMetaByInstance(subcomponent.instanceId).item2.inputs)
 | 
			
		||||
                    input: componentState.partialVisualSimulation!.inputsValues['${subcomponent.instanceId}/$input'] == true ? Colors.green 
 | 
			
		||||
                      : componentState.partialVisualSimulation!.inputsValues['${subcomponent.instanceId}/$input'] == false ? Colors.red 
 | 
			
		||||
                      : Colors.black,
 | 
			
		||||
                } : null,
 | 
			
		||||
                outputColors: isSimulating.value ? {
 | 
			
		||||
                  for (final output in componentState.getMetaByInstance(subcomponent.instanceId).item2.outputs)
 | 
			
		||||
                    output: componentState.partialVisualSimulation!.outputsValues['${subcomponent.instanceId}/$output'] == true ? Colors.green 
 | 
			
		||||
                      : componentState.partialVisualSimulation!.outputsValues['${subcomponent.instanceId}/$output'] == false ? Colors.red 
 | 
			
		||||
                      : Colors.black,
 | 
			
		||||
                } : null,
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      for (final input in componentState.designDraft.inputs)
 | 
			
		||||
        CanvasObject(
 | 
			
		||||
          dx: input.x, 
 | 
			
		||||
          dy: input.y, 
 | 
			
		||||
          width: IOComponent.getNeededWidth(context, input.name, textStyle: Theme.of(context).textTheme.bodyMedium), 
 | 
			
		||||
          height: 40, 
 | 
			
		||||
          child: Listener(
 | 
			
		||||
            behavior: HitTestBehavior.translucent,
 | 
			
		||||
            onPointerDown: (event) {
 | 
			
		||||
              final debouncer = FutureCallDebounce<List<double>>(
 | 
			
		||||
                futureCall: (xyList) {
 | 
			
		||||
                  final dx = xyList[0];
 | 
			
		||||
                  final dy = xyList[1];
 | 
			
		||||
                  return componentState.updateDesign(componentState.designDraft.copyWith(
 | 
			
		||||
                    inputs: componentState.designDraft.inputs.map(
 | 
			
		||||
                      (e) => e.name == input.name ? e.copyWith(
 | 
			
		||||
                        x: input.x + dx,
 | 
			
		||||
                        y: input.y + dy,
 | 
			
		||||
                      ) : e,
 | 
			
		||||
                    ).toList(),
 | 
			
		||||
                  ), commit: false);
 | 
			
		||||
                }, 
 | 
			
		||||
                combiner: (oldParams, newParams) {
 | 
			
		||||
                  return oldParams.zipWith([newParams], (deltas) => deltas.fold<double>(0.0, (prev, elem) => prev + elem)).toList();
 | 
			
		||||
                },
 | 
			
		||||
              );
 | 
			
		||||
              movingWidgetUpdater.value = (dx, dy) {
 | 
			
		||||
                debouncer.call([dx, dy]);
 | 
			
		||||
              };
 | 
			
		||||
            },
 | 
			
		||||
            onPointerUp: (event) {
 | 
			
		||||
              componentState.updateDesign(componentState.designDraft);
 | 
			
		||||
              movingWidgetUpdater.value = null;
 | 
			
		||||
            },
 | 
			
		||||
            child: IOComponent(
 | 
			
		||||
              input: true,
 | 
			
		||||
              name: input.name,
 | 
			
		||||
              width: IOComponent.getNeededWidth(context, input.name, textStyle: Theme.of(context).textTheme.bodyMedium),
 | 
			
		||||
              color: isSimulating.value 
 | 
			
		||||
                ? (componentState.partialVisualSimulation!.outputsValues['self/${input.name}']! 
 | 
			
		||||
                  ? Colors.green
 | 
			
		||||
                  : Colors.red) 
 | 
			
		||||
                : null,
 | 
			
		||||
              onTap: isSimulating.value ? () {
 | 
			
		||||
                componentState.partialVisualSimulation!.toggleInput(input.name);
 | 
			
		||||
              } : null,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      for (final output in componentState.designDraft.outputs)
 | 
			
		||||
        CanvasObject(
 | 
			
		||||
          dx: output.x, 
 | 
			
		||||
          dy: output.y, 
 | 
			
		||||
          width: IOComponent.getNeededWidth(context, output.name, textStyle: Theme.of(context).textTheme.bodyMedium), 
 | 
			
		||||
          height: 40, 
 | 
			
		||||
          child: Listener(
 | 
			
		||||
            behavior: HitTestBehavior.translucent,
 | 
			
		||||
            onPointerDown: (event) {
 | 
			
		||||
              final debouncer = FutureCallDebounce<List<double>>(
 | 
			
		||||
                futureCall: (xyList) {
 | 
			
		||||
                  final dx = xyList[0];
 | 
			
		||||
                  final dy = xyList[1];
 | 
			
		||||
                  return componentState.updateDesign(componentState.designDraft.copyWith(
 | 
			
		||||
                    outputs: componentState.designDraft.outputs.map(
 | 
			
		||||
                      (e) => e.name == output.name ? e.copyWith(
 | 
			
		||||
                        x: output.x + dx,
 | 
			
		||||
                        y: output.y + dy,
 | 
			
		||||
                      ) : e,
 | 
			
		||||
                    ).toList(),
 | 
			
		||||
                  ), commit: false);
 | 
			
		||||
                }, 
 | 
			
		||||
                combiner: (oldParams, newParams) {
 | 
			
		||||
                  return oldParams.zipWith([newParams], (deltas) => deltas.fold<double>(0.0, (prev, elem) => prev + elem)).toList();
 | 
			
		||||
                },
 | 
			
		||||
              );
 | 
			
		||||
              movingWidgetUpdater.value = (dx, dy) {
 | 
			
		||||
                debouncer.call([dx, dy]);
 | 
			
		||||
              };
 | 
			
		||||
            },
 | 
			
		||||
            onPointerUp: (event) {
 | 
			
		||||
              componentState.updateDesign(componentState.designDraft);
 | 
			
		||||
              movingWidgetUpdater.value = null;
 | 
			
		||||
            },
 | 
			
		||||
            child: IOComponent(
 | 
			
		||||
              input: false,
 | 
			
		||||
              name: output.name,
 | 
			
		||||
              width: IOComponent.getNeededWidth(context, output.name, textStyle: Theme.of(context).textTheme.bodyMedium),
 | 
			
		||||
              color: isSimulating.value 
 | 
			
		||||
                ? (componentState.partialVisualSimulation!.inputsValues['self/${output.name}'] == true ? Colors.green
 | 
			
		||||
                  : componentState.partialVisualSimulation!.inputsValues['self/${output.name}'] == false ? Colors.red
 | 
			
		||||
                  : null) 
 | 
			
		||||
                : null,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      for (final wire in componentState.wiring.wires)
 | 
			
		||||
        (() {
 | 
			
		||||
          const ioCircleDiameter = 20;
 | 
			
		||||
 | 
			
		||||
          Offset from, to;
 | 
			
		||||
          if (wire.output.split('/')[0] == 'self') {
 | 
			
		||||
            // It's a component input
 | 
			
		||||
            
 | 
			
		||||
            // Find input
 | 
			
		||||
            final inputName = wire.output.split('/')[1];
 | 
			
		||||
            final design = componentState.designDraft.inputs.where((i) => i.name == inputName).first;
 | 
			
		||||
 | 
			
		||||
            from = Offset(
 | 
			
		||||
              // Take into account widget length
 | 
			
		||||
              design.x +
 | 
			
		||||
                  IOComponent.getNeededWidth(
 | 
			
		||||
                    context,
 | 
			
		||||
                    inputName,
 | 
			
		||||
                    textStyle: Theme.of(context).textTheme.bodyMedium,
 | 
			
		||||
                  ),
 | 
			
		||||
              design.y + ioCircleDiameter + 1,
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            // It's a subcomponent output
 | 
			
		||||
 | 
			
		||||
            // Find subcomponent
 | 
			
		||||
            final split = wire.output.split('/');
 | 
			
		||||
            final subcomponentId = split[0];
 | 
			
		||||
            final outputName = split[1];
 | 
			
		||||
            final design = componentState.designDraft.components.where((c) => c.instanceId == subcomponentId).first;
 | 
			
		||||
            final subcomponent = componentState.getMetaByInstance(subcomponentId).item2;
 | 
			
		||||
 | 
			
		||||
            from = Offset(
 | 
			
		||||
              // Take into account widget length
 | 
			
		||||
              design.x +
 | 
			
		||||
                VisualComponent.getNeededWidth(
 | 
			
		||||
                  context,
 | 
			
		||||
                  subcomponent.inputs,
 | 
			
		||||
                  subcomponent.outputs,
 | 
			
		||||
                  Theme.of(context).textTheme.bodyMedium,
 | 
			
		||||
                ),
 | 
			
		||||
              design.y +
 | 
			
		||||
                VisualComponent.getHeightOfIO(
 | 
			
		||||
                  context,
 | 
			
		||||
                  subcomponent.outputs,
 | 
			
		||||
                  subcomponent.outputs.indexOf(outputName),
 | 
			
		||||
                  Theme.of(context).textTheme.bodyMedium,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (wire.input.split('/')[0] == 'self') {
 | 
			
		||||
            // It's a component output
 | 
			
		||||
            
 | 
			
		||||
            // Find output
 | 
			
		||||
            final outputName = wire.input.split('/')[1];
 | 
			
		||||
            final design = componentState.designDraft.outputs.where((o) => o.name == outputName).first;
 | 
			
		||||
 | 
			
		||||
            to = Offset(
 | 
			
		||||
              design.x,
 | 
			
		||||
              design.y + ioCircleDiameter + 1,
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            // It's a subcomponent input
 | 
			
		||||
 | 
			
		||||
            // Find subcomponent
 | 
			
		||||
            final split = wire.input.split('/');
 | 
			
		||||
            final subcomponentId = split[0];
 | 
			
		||||
            final inputName = split[1];
 | 
			
		||||
            final design = componentState.designDraft.components.where((c) => c.instanceId == subcomponentId).first;
 | 
			
		||||
            final subcomponent = componentState.getMetaByInstance(subcomponentId).item2;
 | 
			
		||||
 | 
			
		||||
            to = Offset(
 | 
			
		||||
              // Take into account widget length
 | 
			
		||||
              design.x,
 | 
			
		||||
              design.y +
 | 
			
		||||
                VisualComponent.getHeightOfIO(
 | 
			
		||||
                  context,
 | 
			
		||||
                  subcomponent.inputs,
 | 
			
		||||
                  subcomponent.inputs.indexOf(inputName),
 | 
			
		||||
                  Theme.of(context).textTheme.bodyMedium,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          var wireColor = Colors.black;
 | 
			
		||||
          if (isSimulating.value) {
 | 
			
		||||
            final wireValue = componentState.partialVisualSimulation!.outputsValues[wire.output];
 | 
			
		||||
            if (wireValue == true) {
 | 
			
		||||
              wireColor = Colors.green;
 | 
			
		||||
            }
 | 
			
		||||
            else if (wireValue == false) {
 | 
			
		||||
              wireColor = Colors.red;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          return CanvasObject(
 | 
			
		||||
            dx: min(from.dx, to.dx),
 | 
			
		||||
            dy: min(from.dy, to.dy),
 | 
			
		||||
            width: (to - from).dx.abs(),
 | 
			
		||||
            height: (to - from).dy.abs(),
 | 
			
		||||
            child: IgnorePointer(
 | 
			
		||||
              child: WireWidget(
 | 
			
		||||
                from: from, 
 | 
			
		||||
                to: to,
 | 
			
		||||
                color: wireColor,
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        })(),
 | 
			
		||||
    ], [componentState.designDraft, isSimulating.value, componentState.partialVisualSimulation!.outputsValues]);
 | 
			
		||||
    useEffect(() {
 | 
			
		||||
      canvasController.addCanvasObjects(widgets.value);
 | 
			
		||||
      final wList = widgets;
 | 
			
		||||
      canvasController.addCanvasObjects(wList);
 | 
			
		||||
 | 
			
		||||
      return () {
 | 
			
		||||
        // Cleanup
 | 
			
		||||
        canvasController.clearCanvas();
 | 
			
		||||
        for (final obj in wList) {
 | 
			
		||||
          canvasController.removeCanvasObject(obj);
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
    }, [widgets]);
 | 
			
		||||
    useEffect(() {
 | 
			
		||||
      if (isSimulating.value && !simulatePartially.value && componentState.partialVisualSimulation!.nextToSimulate.isNotEmpty) {
 | 
			
		||||
        componentState.partialVisualSimulation!.nextStep();
 | 
			
		||||
      }
 | 
			
		||||
      return null;
 | 
			
		||||
    }, [componentState.partialVisualSimulation!.outputsValues.entries.map((e) => '${e.key}:${e.value}').join(';'), simulatePartially.value, isSimulating.value]);
 | 
			
		||||
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      appBar: AppBar(
 | 
			
		||||
        centerTitle: true,
 | 
			
		||||
        title: Text('Design - ${component.componentName}'),
 | 
			
		||||
        title: Text('${isSimulating.value ? 'Simulation' : 'Design'} - ${component.componentName}'),
 | 
			
		||||
        actions: [
 | 
			
		||||
          IconButton(
 | 
			
		||||
            icon: Icon(isSimulating.value ? Icons.stop : Icons.start),
 | 
			
		||||
            tooltip: isSimulating.value ? 'Stop Simulation' : 'Start Simulation',
 | 
			
		||||
            onPressed: () {
 | 
			
		||||
              isSimulating.value = !isSimulating.value;
 | 
			
		||||
            },
 | 
			
		||||
          ),
 | 
			
		||||
      body: OrientationBuilder(
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
      body: GestureDetector(
 | 
			
		||||
        onPanUpdate: (update) {
 | 
			
		||||
          final hw = movingWidgetUpdater.value;
 | 
			
		||||
          if (hw == null || isSimulating.value) {
 | 
			
		||||
            canvasController.offset = canvasController.offset.translate(update.delta.dx, update.delta.dy);
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            hw(update.delta.dx, update.delta.dy);
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        child: OrientationBuilder(
 | 
			
		||||
          builder: (context, orientation) {
 | 
			
		||||
            if (orientation == Orientation.portrait) {
 | 
			
		||||
              return Column(
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +369,10 @@ class DesignComponentPage extends HookWidget {
 | 
			
		|||
                children: [
 | 
			
		||||
                  Expanded(
 | 
			
		||||
                    child: StackCanvas(
 | 
			
		||||
                      key: canvasKey,
 | 
			
		||||
                      canvasController: canvasController,
 | 
			
		||||
                      animationDuration: const Duration(milliseconds: 50),
 | 
			
		||||
                      // disposeController: false,
 | 
			
		||||
                      backgroundColor: Theme.of(context).colorScheme.background,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +385,11 @@ class DesignComponentPage extends HookWidget {
 | 
			
		|||
                children: [
 | 
			
		||||
                  Expanded(
 | 
			
		||||
                    child: StackCanvas(
 | 
			
		||||
                      key: canvasKey,
 | 
			
		||||
                      canvasController: canvasController,
 | 
			
		||||
                      animationDuration: const Duration(milliseconds: 50),
 | 
			
		||||
                      // disposeController: false,
 | 
			
		||||
                      backgroundColor: Theme.of(context).colorScheme.background,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                ],
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +397,7 @@ class DesignComponentPage extends HookWidget {
 | 
			
		|||
            }
 | 
			
		||||
          }
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -12,13 +12,41 @@ class ComponentState extends ChangeNotifier {
 | 
			
		|||
  ProjectEntry? _currentProject;
 | 
			
		||||
  ComponentEntry? _currentComponent;
 | 
			
		||||
  Wiring _wiring = const Wiring(instances: [], wires: []);
 | 
			
		||||
  Wiring? _wiringDraft;
 | 
			
		||||
  Design _design = const Design(components: [], wires: [], inputs: [], outputs: []);
 | 
			
		||||
  Design? _designDraft;
 | 
			
		||||
  SimulatedComponent? _simulatedComponent;
 | 
			
		||||
  PartialVisualSimulation? _partialVisualSimulation;
 | 
			
		||||
 | 
			
		||||
  final Map<String, Tuple2<ProjectEntry, ComponentEntry>> _dependenciesMap = {};
 | 
			
		||||
 | 
			
		||||
  ProjectEntry? get currentProject => _currentProject;
 | 
			
		||||
  ComponentEntry? get currentComponent => _currentComponent;
 | 
			
		||||
  Wiring get wiring => _wiring;
 | 
			
		||||
  Wiring get wiringDraft => _wiringDraft ?? _wiring;
 | 
			
		||||
  Design get design => _design;
 | 
			
		||||
  Design get designDraft => _designDraft ?? _design;
 | 
			
		||||
  PartialVisualSimulation? get partialVisualSimulation => _partialVisualSimulation;
 | 
			
		||||
 | 
			
		||||
  Future<SimulatedComponent> _onRequiredDependency(String depId) async {
 | 
			
		||||
    final t = _dependenciesMap[depId]!;
 | 
			
		||||
    final proj = t.item1;
 | 
			
		||||
    final comp = t.item2;
 | 
			
		||||
    final state = comp.visualDesigned ? ComponentState() : null;
 | 
			
		||||
    if (state != null) {
 | 
			
		||||
      await state.setCurrentComponent(
 | 
			
		||||
        project: proj, 
 | 
			
		||||
        component: comp, 
 | 
			
		||||
        onDependencyNeeded: (projId, compId) async => _dependenciesMap['$projId/$compId'],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return SimulatedComponent(
 | 
			
		||||
      project: proj, 
 | 
			
		||||
      component: comp, 
 | 
			
		||||
      onRequiredDependency: _onRequiredDependency,
 | 
			
		||||
      state: state,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Directory> _getComponentDir() async {
 | 
			
		||||
    if (_currentProject == null) {
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +68,11 @@ class ComponentState extends ChangeNotifier {
 | 
			
		|||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<File> _getDesignFile() async {
 | 
			
		||||
    final result = File(path.join((await _getComponentDir()).path, 'design.json'));
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> _loadComponentFiles() async {
 | 
			
		||||
    final wiringFile = await _getWiringFile();
 | 
			
		||||
    if (!await wiringFile.exists()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +82,17 @@ class ComponentState extends ChangeNotifier {
 | 
			
		|||
    else {
 | 
			
		||||
      _wiring = Wiring.fromJson(jsonDecode(await wiringFile.readAsString()));
 | 
			
		||||
    }
 | 
			
		||||
    _wiringDraft = null;
 | 
			
		||||
 | 
			
		||||
    final designFile = await _getDesignFile();
 | 
			
		||||
    if (!await designFile.exists()) {
 | 
			
		||||
      _design = const Design(components: [], wires: [], inputs: [], outputs: []);
 | 
			
		||||
      await designFile.writeAsString(jsonEncode(_design));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      _design = Design.fromJson(jsonDecode(await designFile.readAsString()));
 | 
			
		||||
    }
 | 
			
		||||
    _designDraft = null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> setCurrentComponent({
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +122,18 @@ class ComponentState extends ChangeNotifier {
 | 
			
		|||
      throw DependenciesNotSatisfiedException(dependencies: unsatisfiedDependencies);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _loadComponentFiles().then((_) => notifyListeners());
 | 
			
		||||
    await _loadComponentFiles();
 | 
			
		||||
 | 
			
		||||
    if (component.visualDesigned) {
 | 
			
		||||
      _partialVisualSimulation = await PartialVisualSimulation.init(
 | 
			
		||||
        project: project,
 | 
			
		||||
        component: component,
 | 
			
		||||
        state: this,
 | 
			
		||||
        onRequiredDependency: _onRequiredDependency,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void noComponent() {
 | 
			
		||||
| 
						 | 
				
			
			@ -86,41 +141,63 @@ class ComponentState extends ChangeNotifier {
 | 
			
		|||
    _currentProject = null;
 | 
			
		||||
    _currentComponent = null;
 | 
			
		||||
    _wiring = const Wiring(instances: [], wires: []);
 | 
			
		||||
    _design = const Design(components: [], wires: [], inputs: [], outputs: []);
 | 
			
		||||
    _wiringDraft = _designDraft = null;
 | 
			
		||||
    _simulatedComponent = null;
 | 
			
		||||
    _partialVisualSimulation = null;
 | 
			
		||||
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Tuple2<ProjectEntry, ComponentEntry> getMetaByInstance(String instanceId) {
 | 
			
		||||
    for (final instance in wiring.instances) {
 | 
			
		||||
      if (instance.instanceId == instanceId) {
 | 
			
		||||
        return _dependenciesMap[instance.componentId]!;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    throw Exception('Instance $instanceId not found in the dependencies map');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Map<String, bool>> simulate(Map<String, bool> inputs) async {
 | 
			
		||||
    Future<SimulatedComponent> onRequiredDependency(String depId) async {
 | 
			
		||||
      final t = _dependenciesMap[depId]!;
 | 
			
		||||
      final proj = t.item1;
 | 
			
		||||
      final comp = t.item2;
 | 
			
		||||
      final state = comp.visualDesigned ? ComponentState() : null;
 | 
			
		||||
      if (state != null) {
 | 
			
		||||
        await state.setCurrentComponent(
 | 
			
		||||
          project: proj, 
 | 
			
		||||
          component: comp, 
 | 
			
		||||
          onDependencyNeeded: (projId, compId) async => _dependenciesMap['$projId/$compId'],
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
      return SimulatedComponent(
 | 
			
		||||
        project: proj, 
 | 
			
		||||
        component: comp, 
 | 
			
		||||
        onRequiredDependency: onRequiredDependency,
 | 
			
		||||
        state: state,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _simulatedComponent ??= SimulatedComponent(
 | 
			
		||||
      project: _currentProject!, 
 | 
			
		||||
      component: _currentComponent!, 
 | 
			
		||||
      onRequiredDependency: onRequiredDependency,
 | 
			
		||||
      onRequiredDependency: _onRequiredDependency,
 | 
			
		||||
      state: this,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return _simulatedComponent!.simulate(inputs);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Design> updateDesign(Design newDesign, {bool commit = true}) async {
 | 
			
		||||
    if (commit) {
 | 
			
		||||
      _design = newDesign;
 | 
			
		||||
      _designDraft = null;
 | 
			
		||||
      final designFile = await _getDesignFile();
 | 
			
		||||
      await designFile.writeAsString(jsonEncode(newDesign));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      _designDraft = newDesign;
 | 
			
		||||
    }
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
    return designDraft;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<Wiring> updateWiring(Wiring newWiring, {bool commit = true}) async {
 | 
			
		||||
    if (commit) {
 | 
			
		||||
      _wiring = newWiring;
 | 
			
		||||
      _wiringDraft = null;
 | 
			
		||||
      final wiringFile = await _getWiringFile();
 | 
			
		||||
      await wiringFile.writeAsString(jsonEncode(newWiring));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      _wiringDraft = newWiring;
 | 
			
		||||
    }
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
    return wiringDraft;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DependenciesNotSatisfiedException with Exception {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								lib/utils/future_call_debounce.dart
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/utils/future_call_debounce.dart
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
class FutureCallDebounce<TParams extends Object> {
 | 
			
		||||
  TParams? _params;
 | 
			
		||||
  Future? _awaited;
 | 
			
		||||
  final Future Function(TParams) futureCall;
 | 
			
		||||
  final TParams Function(TParams oldParams, TParams newParams) combiner;
 | 
			
		||||
 | 
			
		||||
  static TParams _defaultCombiner<TParams>(TParams _, TParams newParams) => newParams;
 | 
			
		||||
 | 
			
		||||
  FutureCallDebounce({required this.futureCall, required this.combiner});
 | 
			
		||||
  FutureCallDebounce.replaceCombiner({required this.futureCall}) : combiner = _defaultCombiner;
 | 
			
		||||
 | 
			
		||||
  void call(TParams newParams) {
 | 
			
		||||
    if (_params != null) {
 | 
			
		||||
      _params = combiner(_params!, newParams);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      _params = newParams;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _awaited ??= futureCall(_params!).then((value) => _awaited = null);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
import 'package:collection/collection.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/models.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/state/component.dart';
 | 
			
		||||
import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
 | 
			
		||||
| 
						 | 
				
			
			@ -10,19 +12,18 @@ class SimulatedComponent {
 | 
			
		|||
  final Future<SimulatedComponent> Function(String depId) onRequiredDependency;
 | 
			
		||||
  final _instances = <String, SimulatedComponent>{};
 | 
			
		||||
 | 
			
		||||
  SimulatedComponent({
 | 
			
		||||
    required this.project, 
 | 
			
		||||
  SimulatedComponent(
 | 
			
		||||
      {required this.project,
 | 
			
		||||
      required this.component,
 | 
			
		||||
      required this.onRequiredDependency,
 | 
			
		||||
    this.state
 | 
			
		||||
  });
 | 
			
		||||
      this.state});
 | 
			
		||||
 | 
			
		||||
  Future<SimulatedComponent> _getInstance(String instanceId, String? depId) async {
 | 
			
		||||
  Future<SimulatedComponent> _getInstance(
 | 
			
		||||
      String instanceId, String? depId) async {
 | 
			
		||||
    if (!_instances.containsKey(instanceId)) {
 | 
			
		||||
      if (depId != null) {
 | 
			
		||||
        _instances[instanceId] = await onRequiredDependency(depId);
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
      } else {
 | 
			
		||||
        throw Exception('Attempted to get instance of unknown component');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -37,13 +38,11 @@ class SimulatedComponent {
 | 
			
		|||
    if (component.truthTable != null) {
 | 
			
		||||
      final output = component.truthTable![input];
 | 
			
		||||
      return {
 | 
			
		||||
        for (final it in component.outputs.indexedMap(
 | 
			
		||||
          (index, outName) => [outName, output[index]]
 | 
			
		||||
        )) 
 | 
			
		||||
        it[0] : it[1] == '1'
 | 
			
		||||
        for (final it in component.outputs
 | 
			
		||||
            .indexedMap((index, outName) => [outName, output[index]]))
 | 
			
		||||
          it[0]: it[1] == '1'
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    else if (component.logicExpression != null) {
 | 
			
		||||
    } else if (component.logicExpression != null) {
 | 
			
		||||
      // Somehow?
 | 
			
		||||
      // A truth table should be automatically generated for every logic expression component.
 | 
			
		||||
      // Might as well handle cases where that isn't done anyway.
 | 
			
		||||
| 
						 | 
				
			
			@ -55,15 +54,10 @@ class SimulatedComponent {
 | 
			
		|||
          return [output, le.evaluate(inputs)];
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
      return {
 | 
			
		||||
        for (final it in results)
 | 
			
		||||
        it[0] as String : it[1] as bool
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    else if (state == null) {
 | 
			
		||||
      return {for (final it in results) it[0] as String: it[1] as bool};
 | 
			
		||||
    } else if (state == null) {
 | 
			
		||||
      throw Exception('Cannot simulate designed component without its state');
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    } else {
 | 
			
		||||
      // Create instances
 | 
			
		||||
      final wiring = state!.wiring;
 | 
			
		||||
      for (final instance in wiring.instances) {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,8 +69,7 @@ class SimulatedComponent {
 | 
			
		|||
        ...component.outputs.map((output) => 'self/$output'),
 | 
			
		||||
      ];
 | 
			
		||||
      final knownSources = {
 | 
			
		||||
        for (final entry in inputs.entries)
 | 
			
		||||
        'self/${entry.key}': entry.value
 | 
			
		||||
        for (final entry in inputs.entries) 'self/${entry.key}': entry.value
 | 
			
		||||
      };
 | 
			
		||||
      final knownSinks = <String, bool>{};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -86,37 +79,40 @@ class SimulatedComponent {
 | 
			
		|||
        if (knownSinks.containsKey(sink)) {
 | 
			
		||||
          // Requirement satisfied
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        } else {
 | 
			
		||||
          // Find wire that provides sink
 | 
			
		||||
          final wire = wiring.wires.where((wire) => wire.input == sink).first;
 | 
			
		||||
          if (knownSources.containsKey(wire.output)) {
 | 
			
		||||
            // If we know the output provided through the wire,
 | 
			
		||||
            // we know the input provided to the sink
 | 
			
		||||
            knownSinks[sink] = knownSources[wire.output]!;
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
          } else {
 | 
			
		||||
            // The instance providing the source for the wire has not been simulated.
 | 
			
		||||
            // See if all its sinks are known:
 | 
			
		||||
            final instanceId = wire.output.split('/')[0];
 | 
			
		||||
            final instance = await _getInstance(instanceId, null);
 | 
			
		||||
            final depSinks = instance.component.inputs.map((input) => '$instanceId/$input').toList();
 | 
			
		||||
            if (depSinks.map((depSink) => !knownSinks.containsKey(depSink)).where((cond) => cond).isEmpty) {
 | 
			
		||||
            final depSinks = instance.component.inputs
 | 
			
		||||
                .map((input) => '$instanceId/$input')
 | 
			
		||||
                .toList();
 | 
			
		||||
            if (depSinks
 | 
			
		||||
                .map((depSink) => !knownSinks.containsKey(depSink))
 | 
			
		||||
                .where((cond) => cond)
 | 
			
		||||
                .isEmpty) {
 | 
			
		||||
              // If so, then simulate
 | 
			
		||||
              final results = await instance.simulate({
 | 
			
		||||
                for (final depSink in depSinks)
 | 
			
		||||
                depSink.split('/')[1] : knownSinks[depSink]!
 | 
			
		||||
                  depSink.split('/')[1]: knownSinks[depSink]!
 | 
			
		||||
              });
 | 
			
		||||
              knownSources.addAll({
 | 
			
		||||
                for (final result in results.entries)
 | 
			
		||||
                '$instanceId/${result.key}' : result.value
 | 
			
		||||
                  '$instanceId/${result.key}': result.value
 | 
			
		||||
              });
 | 
			
		||||
              // And resolve needed sink
 | 
			
		||||
              knownSinks[sink] = knownSources[wire.output]!;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
            } else {
 | 
			
		||||
              // Otherwise, require the sinks and reschedule the current one
 | 
			
		||||
              requiredSinks.addAll(depSinks.where((depSink) => !knownSinks.containsKey(depSink)));
 | 
			
		||||
              requiredSinks.addAll(depSinks
 | 
			
		||||
                  .where((depSink) => !knownSinks.containsKey(depSink)));
 | 
			
		||||
              requiredSinks.add(sink);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
| 
						 | 
				
			
			@ -125,8 +121,162 @@ class SimulatedComponent {
 | 
			
		|||
 | 
			
		||||
      return {
 | 
			
		||||
        for (final output in component.outputs)
 | 
			
		||||
        output : knownSinks['self/$output']!
 | 
			
		||||
          output: knownSinks['self/$output']!
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PartialVisualSimulation with ChangeNotifier {
 | 
			
		||||
  final Map<String, bool?> _outputsValues = {};
 | 
			
		||||
  final List<String> nextToSimulate = [];
 | 
			
		||||
  final List<String> _alreadySimulated = [];
 | 
			
		||||
 | 
			
		||||
  UnmodifiableMapView<String, bool?> get outputsValues => UnmodifiableMapView(_outputsValues);
 | 
			
		||||
  UnmodifiableMapView<String, bool?> get inputsValues => UnmodifiableMapView({
 | 
			
		||||
    for (final entry in outputsValues.entries)
 | 
			
		||||
      if (entry.value != null)
 | 
			
		||||
        for (final wire in state.wiringDraft.wires.where((w) => w.output == entry.key))
 | 
			
		||||
          wire.input: entry.value
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  final ProjectEntry project;
 | 
			
		||||
  final ComponentEntry component;
 | 
			
		||||
  final ComponentState state;
 | 
			
		||||
  final Future<SimulatedComponent> Function(String depId) onRequiredDependency;
 | 
			
		||||
  final _instances = <String, SimulatedComponent>{};
 | 
			
		||||
 | 
			
		||||
  PartialVisualSimulation._(
 | 
			
		||||
      {required this.project,
 | 
			
		||||
      required this.component,
 | 
			
		||||
      required this.state,
 | 
			
		||||
      required this.onRequiredDependency});
 | 
			
		||||
 | 
			
		||||
  Future<SimulatedComponent> _getInstance(
 | 
			
		||||
      String instanceId, String? depId) async {
 | 
			
		||||
    if (!_instances.containsKey(instanceId)) {
 | 
			
		||||
      if (depId != null) {
 | 
			
		||||
        _instances[instanceId] = await onRequiredDependency(depId);
 | 
			
		||||
      } else {
 | 
			
		||||
        throw Exception('Attempted to get instance of unknown component');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return _instances[instanceId]!;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Future<PartialVisualSimulation> init({
 | 
			
		||||
    required ProjectEntry project,
 | 
			
		||||
    required ComponentEntry component,
 | 
			
		||||
    required ComponentState state,
 | 
			
		||||
    required Future<SimulatedComponent> Function(String depId) onRequiredDependency,
 | 
			
		||||
    Map<String, bool>? inputs,
 | 
			
		||||
  }) async {
 | 
			
		||||
    final sim = PartialVisualSimulation._(project: project, component: component, state: state, onRequiredDependency: onRequiredDependency);
 | 
			
		||||
 | 
			
		||||
    // Create instances
 | 
			
		||||
    final wiring = state.wiring;
 | 
			
		||||
    for (final instance in wiring.instances) {
 | 
			
		||||
      await sim._getInstance(instance.instanceId, instance.componentId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Populate inputs
 | 
			
		||||
    inputs ??= {};
 | 
			
		||||
    for (final input in component.inputs) {
 | 
			
		||||
      if (!inputs.containsKey(input)) {
 | 
			
		||||
        inputs[input] = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    await sim.provideInputs(inputs);
 | 
			
		||||
 | 
			
		||||
    return sim;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> toggleInput(String inputName) {
 | 
			
		||||
    final inputValue = _outputsValues['self/$inputName']!;
 | 
			
		||||
    return modifyInput(inputName, !inputValue);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> modifyInput(String inputName, bool newValue) {
 | 
			
		||||
    _outputsValues['self/$inputName'] = newValue;
 | 
			
		||||
    for (final key in _outputsValues.keys.toList()) {
 | 
			
		||||
      if (!key.startsWith('self/')) {
 | 
			
		||||
        _outputsValues.remove(key);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    _alreadySimulated.clear();
 | 
			
		||||
    return reset();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> provideInputs(Map<String, bool> inputs) {
 | 
			
		||||
    _alreadySimulated.clear();
 | 
			
		||||
    _outputsValues.clear();
 | 
			
		||||
    for (final entry in inputs.entries) {
 | 
			
		||||
      _outputsValues['self/${entry.key}'] = entry.value;
 | 
			
		||||
    }
 | 
			
		||||
    return reset();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> reset() async {
 | 
			
		||||
    nextToSimulate.clear();
 | 
			
		||||
 | 
			
		||||
    final neededToBeNext = <String, List<String>>{};
 | 
			
		||||
 | 
			
		||||
    for (final wire in state.wiringDraft.wires) {
 | 
			
		||||
      if (_outputsValues.containsKey(wire.output)) {
 | 
			
		||||
        final subcomponentId = wire.input.split('/')[0];
 | 
			
		||||
 | 
			
		||||
        // Ignore component outputs, they require no computation
 | 
			
		||||
        if (subcomponentId == 'self') {
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Skip already simulated subcomponents
 | 
			
		||||
        if (_alreadySimulated.contains(subcomponentId)) {
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (neededToBeNext.containsKey(subcomponentId)) {
 | 
			
		||||
          neededToBeNext[subcomponentId]!.remove(wire.input.split('/')[1]);
 | 
			
		||||
          if (neededToBeNext[subcomponentId]!.isEmpty) {
 | 
			
		||||
            nextToSimulate.add(subcomponentId);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          neededToBeNext[subcomponentId] = 
 | 
			
		||||
            (await _getInstance(subcomponentId, null))
 | 
			
		||||
            .component
 | 
			
		||||
            .inputs
 | 
			
		||||
            .whereNot((e) => e == wire.input.split('/')[1])
 | 
			
		||||
            .toList();
 | 
			
		||||
          if (neededToBeNext[subcomponentId]!.isEmpty) {
 | 
			
		||||
            nextToSimulate.add(subcomponentId);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    notifyListeners();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> nextStep() async {
 | 
			
		||||
    if (nextToSimulate.isEmpty) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final currentlySimulating = nextToSimulate.toList();
 | 
			
		||||
 | 
			
		||||
    for (final subcomponentId in currentlySimulating) {
 | 
			
		||||
      final sim = await _getInstance(subcomponentId, null);
 | 
			
		||||
      final outputs = await sim.simulate({
 | 
			
		||||
        for (final input in sim.component.inputs)
 | 
			
		||||
          input: inputsValues['$subcomponentId/$input']!
 | 
			
		||||
      });
 | 
			
		||||
      for (final entry in outputs.entries) {
 | 
			
		||||
        _outputsValues['$subcomponentId/${entry.key}'] = entry.value;
 | 
			
		||||
      }
 | 
			
		||||
      _alreadySimulated.add(subcomponentId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return reset();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -633,9 +633,11 @@ packages:
 | 
			
		|||
  stack_canvas:
 | 
			
		||||
    dependency: "direct main"
 | 
			
		||||
    description:
 | 
			
		||||
      name: stack_canvas
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
      path: "."
 | 
			
		||||
      ref: HEAD
 | 
			
		||||
      resolved-ref: "83e1032940e9424572c60ddad397f38320ee9cd4"
 | 
			
		||||
      url: "https://github.com/dancojocaru2000/stack_canvas.git"
 | 
			
		||||
    source: git
 | 
			
		||||
    version: "0.2.0+2"
 | 
			
		||||
  stack_trace:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,8 @@ dependencies:
 | 
			
		|||
  archive: ^3.3.0
 | 
			
		||||
  file_picker: ^4.6.1
 | 
			
		||||
  share_plus: ^4.0.8
 | 
			
		||||
  stack_canvas: ^0.2.0+2
 | 
			
		||||
  stack_canvas:
 | 
			
		||||
    git: https://github.com/dancojocaru2000/stack_canvas.git
 | 
			
		||||
  tuple: ^2.0.0
 | 
			
		||||
 | 
			
		||||
dev_dependencies:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue