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/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';
 | 
					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/material.dart';
 | 
				
			||||||
import 'package:flutter_hooks/flutter_hooks.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/models.dart';
 | 
				
			||||||
import 'package:logic_circuits_simulator/pages_arguments/design_component.dart';
 | 
					import 'package:logic_circuits_simulator/pages_arguments/design_component.dart';
 | 
				
			||||||
import 'package:logic_circuits_simulator/state/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/provider_hook.dart';
 | 
				
			||||||
import 'package:logic_circuits_simulator/utils/stack_canvas_controller_hook.dart';
 | 
					import 'package:logic_circuits_simulator/utils/stack_canvas_controller_hook.dart';
 | 
				
			||||||
import 'package:stack_canvas/stack_canvas.dart';
 | 
					import 'package:stack_canvas/stack_canvas.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Key canvasKey = GlobalKey();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DesignComponentPage extends HookWidget {
 | 
					class DesignComponentPage extends HookWidget {
 | 
				
			||||||
  final ComponentEntry component;
 | 
					  final ComponentEntry component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,23 +26,342 @@ class DesignComponentPage extends HookWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    final componentState = useProvider<ComponentState>();
 | 
					    final componentState = useProvider<ComponentState>();
 | 
				
			||||||
    final canvasController = useStackCanvasController();
 | 
					    final canvasController = useStackCanvasController(
 | 
				
			||||||
    final widgets = useState(<CanvasObject<Widget>>[]);
 | 
					      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(() {
 | 
					    useEffect(() {
 | 
				
			||||||
      canvasController.addCanvasObjects(widgets.value);
 | 
					      final wList = widgets;
 | 
				
			||||||
 | 
					      canvasController.addCanvasObjects(wList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return () {
 | 
					      return () {
 | 
				
			||||||
        // Cleanup
 | 
					        // Cleanup
 | 
				
			||||||
        canvasController.clearCanvas();
 | 
					        for (final obj in wList) {
 | 
				
			||||||
 | 
					          canvasController.removeCanvasObject(obj);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }, [widgets]);
 | 
					    }, [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(
 | 
					    return Scaffold(
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        centerTitle: true,
 | 
					        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) {
 | 
					          builder: (context, orientation) {
 | 
				
			||||||
            if (orientation == Orientation.portrait) {
 | 
					            if (orientation == Orientation.portrait) {
 | 
				
			||||||
              return Column(
 | 
					              return Column(
 | 
				
			||||||
| 
						 | 
					@ -43,7 +369,10 @@ class DesignComponentPage extends HookWidget {
 | 
				
			||||||
                children: [
 | 
					                children: [
 | 
				
			||||||
                  Expanded(
 | 
					                  Expanded(
 | 
				
			||||||
                    child: StackCanvas(
 | 
					                    child: StackCanvas(
 | 
				
			||||||
 | 
					                      key: canvasKey,
 | 
				
			||||||
                      canvasController: canvasController,
 | 
					                      canvasController: canvasController,
 | 
				
			||||||
 | 
					                      animationDuration: const Duration(milliseconds: 50),
 | 
				
			||||||
 | 
					                      // disposeController: false,
 | 
				
			||||||
                      backgroundColor: Theme.of(context).colorScheme.background,
 | 
					                      backgroundColor: Theme.of(context).colorScheme.background,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
| 
						 | 
					@ -56,7 +385,11 @@ class DesignComponentPage extends HookWidget {
 | 
				
			||||||
                children: [
 | 
					                children: [
 | 
				
			||||||
                  Expanded(
 | 
					                  Expanded(
 | 
				
			||||||
                    child: StackCanvas(
 | 
					                    child: StackCanvas(
 | 
				
			||||||
 | 
					                      key: canvasKey,
 | 
				
			||||||
                      canvasController: canvasController,
 | 
					                      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;
 | 
					  ProjectEntry? _currentProject;
 | 
				
			||||||
  ComponentEntry? _currentComponent;
 | 
					  ComponentEntry? _currentComponent;
 | 
				
			||||||
  Wiring _wiring = const Wiring(instances: [], wires: []);
 | 
					  Wiring _wiring = const Wiring(instances: [], wires: []);
 | 
				
			||||||
 | 
					  Wiring? _wiringDraft;
 | 
				
			||||||
 | 
					  Design _design = const Design(components: [], wires: [], inputs: [], outputs: []);
 | 
				
			||||||
 | 
					  Design? _designDraft;
 | 
				
			||||||
  SimulatedComponent? _simulatedComponent;
 | 
					  SimulatedComponent? _simulatedComponent;
 | 
				
			||||||
 | 
					  PartialVisualSimulation? _partialVisualSimulation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final Map<String, Tuple2<ProjectEntry, ComponentEntry>> _dependenciesMap = {};
 | 
					  final Map<String, Tuple2<ProjectEntry, ComponentEntry>> _dependenciesMap = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ProjectEntry? get currentProject => _currentProject;
 | 
					  ProjectEntry? get currentProject => _currentProject;
 | 
				
			||||||
  ComponentEntry? get currentComponent => _currentComponent;
 | 
					  ComponentEntry? get currentComponent => _currentComponent;
 | 
				
			||||||
  Wiring get wiring => _wiring;
 | 
					  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 {
 | 
					  Future<Directory> _getComponentDir() async {
 | 
				
			||||||
    if (_currentProject == null) {
 | 
					    if (_currentProject == null) {
 | 
				
			||||||
| 
						 | 
					@ -40,6 +68,11 @@ class ComponentState extends ChangeNotifier {
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<File> _getDesignFile() async {
 | 
				
			||||||
 | 
					    final result = File(path.join((await _getComponentDir()).path, 'design.json'));
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _loadComponentFiles() async {
 | 
					  Future<void> _loadComponentFiles() async {
 | 
				
			||||||
    final wiringFile = await _getWiringFile();
 | 
					    final wiringFile = await _getWiringFile();
 | 
				
			||||||
    if (!await wiringFile.exists()) {
 | 
					    if (!await wiringFile.exists()) {
 | 
				
			||||||
| 
						 | 
					@ -49,6 +82,17 @@ class ComponentState extends ChangeNotifier {
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      _wiring = Wiring.fromJson(jsonDecode(await wiringFile.readAsString()));
 | 
					      _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({
 | 
					  Future<void> setCurrentComponent({
 | 
				
			||||||
| 
						 | 
					@ -78,7 +122,18 @@ class ComponentState extends ChangeNotifier {
 | 
				
			||||||
      throw DependenciesNotSatisfiedException(dependencies: unsatisfiedDependencies);
 | 
					      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() {
 | 
					  void noComponent() {
 | 
				
			||||||
| 
						 | 
					@ -86,41 +141,63 @@ class ComponentState extends ChangeNotifier {
 | 
				
			||||||
    _currentProject = null;
 | 
					    _currentProject = null;
 | 
				
			||||||
    _currentComponent = null;
 | 
					    _currentComponent = null;
 | 
				
			||||||
    _wiring = const Wiring(instances: [], wires: []);
 | 
					    _wiring = const Wiring(instances: [], wires: []);
 | 
				
			||||||
 | 
					    _design = const Design(components: [], wires: [], inputs: [], outputs: []);
 | 
				
			||||||
 | 
					    _wiringDraft = _designDraft = null;
 | 
				
			||||||
    _simulatedComponent = null;
 | 
					    _simulatedComponent = null;
 | 
				
			||||||
 | 
					    _partialVisualSimulation = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    notifyListeners();
 | 
					    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<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(
 | 
					    _simulatedComponent ??= SimulatedComponent(
 | 
				
			||||||
      project: _currentProject!, 
 | 
					      project: _currentProject!, 
 | 
				
			||||||
      component: _currentComponent!, 
 | 
					      component: _currentComponent!, 
 | 
				
			||||||
      onRequiredDependency: onRequiredDependency,
 | 
					      onRequiredDependency: _onRequiredDependency,
 | 
				
			||||||
      state: this,
 | 
					      state: this,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return _simulatedComponent!.simulate(inputs);
 | 
					    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 {
 | 
					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/models.dart';
 | 
				
			||||||
import 'package:logic_circuits_simulator/state/component.dart';
 | 
					import 'package:logic_circuits_simulator/state/component.dart';
 | 
				
			||||||
import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
 | 
					import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
 | 
				
			||||||
| 
						 | 
					@ -10,19 +12,18 @@ class SimulatedComponent {
 | 
				
			||||||
  final Future<SimulatedComponent> Function(String depId) onRequiredDependency;
 | 
					  final Future<SimulatedComponent> Function(String depId) onRequiredDependency;
 | 
				
			||||||
  final _instances = <String, SimulatedComponent>{};
 | 
					  final _instances = <String, SimulatedComponent>{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SimulatedComponent({
 | 
					  SimulatedComponent(
 | 
				
			||||||
    required this.project, 
 | 
					      {required this.project,
 | 
				
			||||||
      required this.component,
 | 
					      required this.component,
 | 
				
			||||||
      required this.onRequiredDependency,
 | 
					      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 (!_instances.containsKey(instanceId)) {
 | 
				
			||||||
      if (depId != null) {
 | 
					      if (depId != null) {
 | 
				
			||||||
        _instances[instanceId] = await onRequiredDependency(depId);
 | 
					        _instances[instanceId] = await onRequiredDependency(depId);
 | 
				
			||||||
      }
 | 
					      } else {
 | 
				
			||||||
      else {
 | 
					 | 
				
			||||||
        throw Exception('Attempted to get instance of unknown component');
 | 
					        throw Exception('Attempted to get instance of unknown component');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -37,13 +38,11 @@ class SimulatedComponent {
 | 
				
			||||||
    if (component.truthTable != null) {
 | 
					    if (component.truthTable != null) {
 | 
				
			||||||
      final output = component.truthTable![input];
 | 
					      final output = component.truthTable![input];
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        for (final it in component.outputs.indexedMap(
 | 
					        for (final it in component.outputs
 | 
				
			||||||
          (index, outName) => [outName, output[index]]
 | 
					            .indexedMap((index, outName) => [outName, output[index]]))
 | 
				
			||||||
        )) 
 | 
					 | 
				
			||||||
          it[0]: it[1] == '1'
 | 
					          it[0]: it[1] == '1'
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    } else if (component.logicExpression != null) {
 | 
				
			||||||
    else if (component.logicExpression != null) {
 | 
					 | 
				
			||||||
      // Somehow?
 | 
					      // Somehow?
 | 
				
			||||||
      // A truth table should be automatically generated for every logic expression component.
 | 
					      // A truth table should be automatically generated for every logic expression component.
 | 
				
			||||||
      // Might as well handle cases where that isn't done anyway.
 | 
					      // Might as well handle cases where that isn't done anyway.
 | 
				
			||||||
| 
						 | 
					@ -55,15 +54,10 @@ class SimulatedComponent {
 | 
				
			||||||
          return [output, le.evaluate(inputs)];
 | 
					          return [output, le.evaluate(inputs)];
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      return {
 | 
					      return {for (final it in results) it[0] as String: it[1] as bool};
 | 
				
			||||||
        for (final it in results)
 | 
					    } else if (state == null) {
 | 
				
			||||||
        it[0] as String : it[1] as bool
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else if (state == null) {
 | 
					 | 
				
			||||||
      throw Exception('Cannot simulate designed component without its state');
 | 
					      throw Exception('Cannot simulate designed component without its state');
 | 
				
			||||||
    }
 | 
					    } else {
 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      // Create instances
 | 
					      // Create instances
 | 
				
			||||||
      final wiring = state!.wiring;
 | 
					      final wiring = state!.wiring;
 | 
				
			||||||
      for (final instance in wiring.instances) {
 | 
					      for (final instance in wiring.instances) {
 | 
				
			||||||
| 
						 | 
					@ -75,8 +69,7 @@ class SimulatedComponent {
 | 
				
			||||||
        ...component.outputs.map((output) => 'self/$output'),
 | 
					        ...component.outputs.map((output) => 'self/$output'),
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
      final knownSources = {
 | 
					      final knownSources = {
 | 
				
			||||||
        for (final entry in inputs.entries)
 | 
					        for (final entry in inputs.entries) 'self/${entry.key}': entry.value
 | 
				
			||||||
        'self/${entry.key}': entry.value
 | 
					 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      final knownSinks = <String, bool>{};
 | 
					      final knownSinks = <String, bool>{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,22 +79,25 @@ class SimulatedComponent {
 | 
				
			||||||
        if (knownSinks.containsKey(sink)) {
 | 
					        if (knownSinks.containsKey(sink)) {
 | 
				
			||||||
          // Requirement satisfied
 | 
					          // Requirement satisfied
 | 
				
			||||||
          continue;
 | 
					          continue;
 | 
				
			||||||
        }
 | 
					        } else {
 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
          // Find wire that provides sink
 | 
					          // Find wire that provides sink
 | 
				
			||||||
          final wire = wiring.wires.where((wire) => wire.input == sink).first;
 | 
					          final wire = wiring.wires.where((wire) => wire.input == sink).first;
 | 
				
			||||||
          if (knownSources.containsKey(wire.output)) {
 | 
					          if (knownSources.containsKey(wire.output)) {
 | 
				
			||||||
            // If we know the output provided through the wire,
 | 
					            // If we know the output provided through the wire,
 | 
				
			||||||
            // we know the input provided to the sink
 | 
					            // we know the input provided to the sink
 | 
				
			||||||
            knownSinks[sink] = knownSources[wire.output]!;
 | 
					            knownSinks[sink] = knownSources[wire.output]!;
 | 
				
			||||||
          }
 | 
					          } else {
 | 
				
			||||||
          else {
 | 
					 | 
				
			||||||
            // The instance providing the source for the wire has not been simulated.
 | 
					            // The instance providing the source for the wire has not been simulated.
 | 
				
			||||||
            // See if all its sinks are known:
 | 
					            // See if all its sinks are known:
 | 
				
			||||||
            final instanceId = wire.output.split('/')[0];
 | 
					            final instanceId = wire.output.split('/')[0];
 | 
				
			||||||
            final instance = await _getInstance(instanceId, null);
 | 
					            final instance = await _getInstance(instanceId, null);
 | 
				
			||||||
            final depSinks = instance.component.inputs.map((input) => '$instanceId/$input').toList();
 | 
					            final depSinks = instance.component.inputs
 | 
				
			||||||
            if (depSinks.map((depSink) => !knownSinks.containsKey(depSink)).where((cond) => cond).isEmpty) {
 | 
					                .map((input) => '$instanceId/$input')
 | 
				
			||||||
 | 
					                .toList();
 | 
				
			||||||
 | 
					            if (depSinks
 | 
				
			||||||
 | 
					                .map((depSink) => !knownSinks.containsKey(depSink))
 | 
				
			||||||
 | 
					                .where((cond) => cond)
 | 
				
			||||||
 | 
					                .isEmpty) {
 | 
				
			||||||
              // If so, then simulate
 | 
					              // If so, then simulate
 | 
				
			||||||
              final results = await instance.simulate({
 | 
					              final results = await instance.simulate({
 | 
				
			||||||
                for (final depSink in depSinks)
 | 
					                for (final depSink in depSinks)
 | 
				
			||||||
| 
						 | 
					@ -113,10 +109,10 @@ class SimulatedComponent {
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
              // And resolve needed sink
 | 
					              // And resolve needed sink
 | 
				
			||||||
              knownSinks[sink] = knownSources[wire.output]!;
 | 
					              knownSinks[sink] = knownSources[wire.output]!;
 | 
				
			||||||
            }
 | 
					            } else {
 | 
				
			||||||
            else {
 | 
					 | 
				
			||||||
              // Otherwise, require the sinks and reschedule the current one
 | 
					              // 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);
 | 
					              requiredSinks.add(sink);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
| 
						 | 
					@ -130,3 +126,157 @@ class SimulatedComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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:
 | 
					  stack_canvas:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: stack_canvas
 | 
					      path: "."
 | 
				
			||||||
      url: "https://pub.dartlang.org"
 | 
					      ref: HEAD
 | 
				
			||||||
    source: hosted
 | 
					      resolved-ref: "83e1032940e9424572c60ddad397f38320ee9cd4"
 | 
				
			||||||
 | 
					      url: "https://github.com/dancojocaru2000/stack_canvas.git"
 | 
				
			||||||
 | 
					    source: git
 | 
				
			||||||
    version: "0.2.0+2"
 | 
					    version: "0.2.0+2"
 | 
				
			||||||
  stack_trace:
 | 
					  stack_trace:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,8 @@ dependencies:
 | 
				
			||||||
  archive: ^3.3.0
 | 
					  archive: ^3.3.0
 | 
				
			||||||
  file_picker: ^4.6.1
 | 
					  file_picker: ^4.6.1
 | 
				
			||||||
  share_plus: ^4.0.8
 | 
					  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
 | 
					  tuple: ^2.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dev_dependencies:
 | 
					dev_dependencies:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue