mirror of
https://github.com/dancojocaru2000/logic-circuits-simulator.git
synced 2025-06-19 10:32:28 +03:00
Compare commits
No commits in common. "8abd6b3ca8d620267384fd419a4e1aff9b287c93" and "ffa6ca414b1c74f357d4ab760a65e50b825ff20d" have entirely different histories.
8abd6b3ca8
...
ffa6ca414b
9 changed files with 31 additions and 262 deletions
|
@ -10,34 +10,13 @@ class VisualComponent extends HookWidget {
|
||||||
final List<String> outputs;
|
final List<String> outputs;
|
||||||
final Map<String, Color?> inputColors;
|
final Map<String, Color?> inputColors;
|
||||||
final Map<String, Color?> outputColors;
|
final Map<String, Color?> outputColors;
|
||||||
final bool isNextToSimulate;
|
|
||||||
|
|
||||||
VisualComponent({super.key, required this.name, required this.inputs, required this.outputs, Map<String, Color?>? inputColors, Map<String, Color?>? outputColors, this.isNextToSimulate = false})
|
VisualComponent({super.key, required this.name, required this.inputs, required this.outputs, Map<String, Color?>? inputColors, Map<String, Color?>? outputColors})
|
||||||
: inputColors = inputColors ?? {}
|
: inputColors = inputColors ?? {}
|
||||||
, outputColors = outputColors ?? {};
|
, outputColors = outputColors ?? {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final nextToSimulateFlashingAnimation = useAnimationController(
|
|
||||||
duration: const Duration(milliseconds: 500),
|
|
||||||
initialValue: 0.0,
|
|
||||||
lowerBound: 0.0,
|
|
||||||
upperBound: 1.0,
|
|
||||||
);
|
|
||||||
useEffect(() {
|
|
||||||
if (isNextToSimulate) {
|
|
||||||
nextToSimulateFlashingAnimation.repeat(
|
|
||||||
reverse: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nextToSimulateFlashingAnimation.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}, [isNextToSimulate]);
|
|
||||||
final nextToSimAnimProgress = useAnimation(nextToSimulateFlashingAnimation);
|
|
||||||
|
|
||||||
final hovered = useState(false);
|
final hovered = useState(false);
|
||||||
|
|
||||||
final inputsWidth = inputs.map((input) => IOLabel.getNeededWidth(context, input)).fold<double>(0, (previousValue, element) => max(previousValue, element));
|
final inputsWidth = inputs.map((input) => IOLabel.getNeededWidth(context, input)).fold<double>(0, (previousValue, element) => max(previousValue, element));
|
||||||
|
@ -67,11 +46,7 @@ class VisualComponent extends HookWidget {
|
||||||
width: 100,
|
width: 100,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Color.lerp(
|
color: hovered.value ? Theme.of(context).colorScheme.primary : Colors.black,
|
||||||
hovered.value ? Theme.of(context).colorScheme.primary : Colors.black,
|
|
||||||
Colors.blue,
|
|
||||||
nextToSimAnimProgress,
|
|
||||||
)!,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
|
|
|
@ -20,8 +20,6 @@ class ComponentEntry with _$ComponentEntry {
|
||||||
required bool visualDesigned,
|
required bool visualDesigned,
|
||||||
@JsonKey(defaultValue: [])
|
@JsonKey(defaultValue: [])
|
||||||
required List<String> dependencies,
|
required List<String> dependencies,
|
||||||
@JsonKey(defaultValue: false)
|
|
||||||
required bool scriptBased,
|
|
||||||
}) = _ComponentEntry;
|
}) = _ComponentEntry;
|
||||||
|
|
||||||
factory ComponentEntry.fromJson(Map<String, Object?> json) => _$ComponentEntryFromJson(json);
|
factory ComponentEntry.fromJson(Map<String, Object?> json) => _$ComponentEntryFromJson(json);
|
||||||
|
|
|
@ -34,8 +34,6 @@ mixin _$ComponentEntry {
|
||||||
bool get visualDesigned => throw _privateConstructorUsedError;
|
bool get visualDesigned => throw _privateConstructorUsedError;
|
||||||
@JsonKey(defaultValue: [])
|
@JsonKey(defaultValue: [])
|
||||||
List<String> get dependencies => throw _privateConstructorUsedError;
|
List<String> get dependencies => throw _privateConstructorUsedError;
|
||||||
@JsonKey(defaultValue: false)
|
|
||||||
bool get scriptBased => throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
|
@ -57,8 +55,7 @@ abstract class $ComponentEntryCopyWith<$Res> {
|
||||||
@JsonKey(includeIfNull: false) List<String>? truthTable,
|
@JsonKey(includeIfNull: false) List<String>? truthTable,
|
||||||
@JsonKey(includeIfNull: false) List<String>? logicExpression,
|
@JsonKey(includeIfNull: false) List<String>? logicExpression,
|
||||||
@JsonKey(defaultValue: false) bool visualDesigned,
|
@JsonKey(defaultValue: false) bool visualDesigned,
|
||||||
@JsonKey(defaultValue: []) List<String> dependencies,
|
@JsonKey(defaultValue: []) List<String> dependencies});
|
||||||
@JsonKey(defaultValue: false) bool scriptBased});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
@ -81,7 +78,6 @@ class _$ComponentEntryCopyWithImpl<$Res>
|
||||||
Object? logicExpression = freezed,
|
Object? logicExpression = freezed,
|
||||||
Object? visualDesigned = freezed,
|
Object? visualDesigned = freezed,
|
||||||
Object? dependencies = freezed,
|
Object? dependencies = freezed,
|
||||||
Object? scriptBased = freezed,
|
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
componentId: componentId == freezed
|
componentId: componentId == freezed
|
||||||
|
@ -120,10 +116,6 @@ class _$ComponentEntryCopyWithImpl<$Res>
|
||||||
? _value.dependencies
|
? _value.dependencies
|
||||||
: dependencies // ignore: cast_nullable_to_non_nullable
|
: dependencies // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,
|
as List<String>,
|
||||||
scriptBased: scriptBased == freezed
|
|
||||||
? _value.scriptBased
|
|
||||||
: scriptBased // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,8 +136,7 @@ abstract class _$$_ComponentEntryCopyWith<$Res>
|
||||||
@JsonKey(includeIfNull: false) List<String>? truthTable,
|
@JsonKey(includeIfNull: false) List<String>? truthTable,
|
||||||
@JsonKey(includeIfNull: false) List<String>? logicExpression,
|
@JsonKey(includeIfNull: false) List<String>? logicExpression,
|
||||||
@JsonKey(defaultValue: false) bool visualDesigned,
|
@JsonKey(defaultValue: false) bool visualDesigned,
|
||||||
@JsonKey(defaultValue: []) List<String> dependencies,
|
@JsonKey(defaultValue: []) List<String> dependencies});
|
||||||
@JsonKey(defaultValue: false) bool scriptBased});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
@ -170,7 +161,6 @@ class __$$_ComponentEntryCopyWithImpl<$Res>
|
||||||
Object? logicExpression = freezed,
|
Object? logicExpression = freezed,
|
||||||
Object? visualDesigned = freezed,
|
Object? visualDesigned = freezed,
|
||||||
Object? dependencies = freezed,
|
Object? dependencies = freezed,
|
||||||
Object? scriptBased = freezed,
|
|
||||||
}) {
|
}) {
|
||||||
return _then(_$_ComponentEntry(
|
return _then(_$_ComponentEntry(
|
||||||
componentId: componentId == freezed
|
componentId: componentId == freezed
|
||||||
|
@ -209,10 +199,6 @@ class __$$_ComponentEntryCopyWithImpl<$Res>
|
||||||
? _value._dependencies
|
? _value._dependencies
|
||||||
: dependencies // ignore: cast_nullable_to_non_nullable
|
: dependencies // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,
|
as List<String>,
|
||||||
scriptBased: scriptBased == freezed
|
|
||||||
? _value.scriptBased
|
|
||||||
: scriptBased // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,8 +215,7 @@ class _$_ComponentEntry implements _ComponentEntry {
|
||||||
@JsonKey(includeIfNull: false) final List<String>? truthTable,
|
@JsonKey(includeIfNull: false) final List<String>? truthTable,
|
||||||
@JsonKey(includeIfNull: false) final List<String>? logicExpression,
|
@JsonKey(includeIfNull: false) final List<String>? logicExpression,
|
||||||
@JsonKey(defaultValue: false) required this.visualDesigned,
|
@JsonKey(defaultValue: false) required this.visualDesigned,
|
||||||
@JsonKey(defaultValue: []) required final List<String> dependencies,
|
@JsonKey(defaultValue: []) required final List<String> dependencies})
|
||||||
@JsonKey(defaultValue: false) required this.scriptBased})
|
|
||||||
: _inputs = inputs,
|
: _inputs = inputs,
|
||||||
_outputs = outputs,
|
_outputs = outputs,
|
||||||
_truthTable = truthTable,
|
_truthTable = truthTable,
|
||||||
|
@ -292,13 +277,9 @@ class _$_ComponentEntry implements _ComponentEntry {
|
||||||
return EqualUnmodifiableListView(_dependencies);
|
return EqualUnmodifiableListView(_dependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
@JsonKey(defaultValue: false)
|
|
||||||
final bool scriptBased;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'ComponentEntry(componentId: $componentId, componentName: $componentName, componentDescription: $componentDescription, inputs: $inputs, outputs: $outputs, truthTable: $truthTable, logicExpression: $logicExpression, visualDesigned: $visualDesigned, dependencies: $dependencies, scriptBased: $scriptBased)';
|
return 'ComponentEntry(componentId: $componentId, componentName: $componentName, componentDescription: $componentDescription, inputs: $inputs, outputs: $outputs, truthTable: $truthTable, logicExpression: $logicExpression, visualDesigned: $visualDesigned, dependencies: $dependencies)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -321,9 +302,7 @@ class _$_ComponentEntry implements _ComponentEntry {
|
||||||
const DeepCollectionEquality()
|
const DeepCollectionEquality()
|
||||||
.equals(other.visualDesigned, visualDesigned) &&
|
.equals(other.visualDesigned, visualDesigned) &&
|
||||||
const DeepCollectionEquality()
|
const DeepCollectionEquality()
|
||||||
.equals(other._dependencies, _dependencies) &&
|
.equals(other._dependencies, _dependencies));
|
||||||
const DeepCollectionEquality()
|
|
||||||
.equals(other.scriptBased, scriptBased));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
|
@ -338,8 +317,7 @@ class _$_ComponentEntry implements _ComponentEntry {
|
||||||
const DeepCollectionEquality().hash(_truthTable),
|
const DeepCollectionEquality().hash(_truthTable),
|
||||||
const DeepCollectionEquality().hash(_logicExpression),
|
const DeepCollectionEquality().hash(_logicExpression),
|
||||||
const DeepCollectionEquality().hash(visualDesigned),
|
const DeepCollectionEquality().hash(visualDesigned),
|
||||||
const DeepCollectionEquality().hash(_dependencies),
|
const DeepCollectionEquality().hash(_dependencies));
|
||||||
const DeepCollectionEquality().hash(scriptBased));
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
|
@ -354,17 +332,20 @@ class _$_ComponentEntry implements _ComponentEntry {
|
||||||
|
|
||||||
abstract class _ComponentEntry implements ComponentEntry {
|
abstract class _ComponentEntry implements ComponentEntry {
|
||||||
const factory _ComponentEntry(
|
const factory _ComponentEntry(
|
||||||
{required final String componentId,
|
{required final String componentId,
|
||||||
required final String componentName,
|
required final String componentName,
|
||||||
@JsonKey(includeIfNull: false) final String? componentDescription,
|
@JsonKey(includeIfNull: false)
|
||||||
required final List<String> inputs,
|
final String? componentDescription,
|
||||||
required final List<String> outputs,
|
required final List<String> inputs,
|
||||||
@JsonKey(includeIfNull: false) final List<String>? truthTable,
|
required final List<String> outputs,
|
||||||
@JsonKey(includeIfNull: false) final List<String>? logicExpression,
|
@JsonKey(includeIfNull: false)
|
||||||
@JsonKey(defaultValue: false) required final bool visualDesigned,
|
final List<String>? truthTable,
|
||||||
@JsonKey(defaultValue: []) required final List<String> dependencies,
|
@JsonKey(includeIfNull: false)
|
||||||
@JsonKey(defaultValue: false) required final bool scriptBased}) =
|
final List<String>? logicExpression,
|
||||||
_$_ComponentEntry;
|
@JsonKey(defaultValue: false)
|
||||||
|
required final bool visualDesigned,
|
||||||
|
@JsonKey(defaultValue: [])
|
||||||
|
required final List<String> dependencies}) = _$_ComponentEntry;
|
||||||
|
|
||||||
factory _ComponentEntry.fromJson(Map<String, dynamic> json) =
|
factory _ComponentEntry.fromJson(Map<String, dynamic> json) =
|
||||||
_$_ComponentEntry.fromJson;
|
_$_ComponentEntry.fromJson;
|
||||||
|
@ -393,9 +374,6 @@ abstract class _ComponentEntry implements ComponentEntry {
|
||||||
@JsonKey(defaultValue: [])
|
@JsonKey(defaultValue: [])
|
||||||
List<String> get dependencies => throw _privateConstructorUsedError;
|
List<String> get dependencies => throw _privateConstructorUsedError;
|
||||||
@override
|
@override
|
||||||
@JsonKey(defaultValue: false)
|
|
||||||
bool get scriptBased => throw _privateConstructorUsedError;
|
|
||||||
@override
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
_$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith =>
|
_$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
|
|
|
@ -26,7 +26,6 @@ _$_ComponentEntry _$$_ComponentEntryFromJson(Map<String, dynamic> json) =>
|
||||||
?.map((e) => e as String)
|
?.map((e) => e as String)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
scriptBased: json['scriptBased'] as bool? ?? false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$$_ComponentEntryToJson(_$_ComponentEntry instance) {
|
Map<String, dynamic> _$$_ComponentEntryToJson(_$_ComponentEntry instance) {
|
||||||
|
@ -48,6 +47,5 @@ Map<String, dynamic> _$$_ComponentEntryToJson(_$_ComponentEntry instance) {
|
||||||
writeNotNull('logicExpression', instance.logicExpression);
|
writeNotNull('logicExpression', instance.logicExpression);
|
||||||
val['visualDesigned'] = instance.visualDesigned;
|
val['visualDesigned'] = instance.visualDesigned;
|
||||||
val['dependencies'] = instance.dependencies;
|
val['dependencies'] = instance.dependencies;
|
||||||
val['scriptBased'] = instance.scriptBased;
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,6 @@ class DesignComponentPage extends HookWidget {
|
||||||
: componentState.partialVisualSimulation!.outputsValues['${subcomponent.instanceId}/$output'] == false ? Colors.red
|
: componentState.partialVisualSimulation!.outputsValues['${subcomponent.instanceId}/$output'] == false ? Colors.red
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
} : null,
|
} : null,
|
||||||
isNextToSimulate: isSimulating.value && componentState.partialVisualSimulation!.nextToSimulate.contains(subcomponent.instanceId),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
|
||||||
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/logic_expression_field.dart';
|
import 'package:logic_circuits_simulator/components/logic_expression_field.dart';
|
||||||
|
@ -16,13 +14,10 @@ import 'package:logic_circuits_simulator/pages_arguments/edit_component.dart';
|
||||||
import 'package:logic_circuits_simulator/state/component.dart';
|
import 'package:logic_circuits_simulator/state/component.dart';
|
||||||
import 'package:logic_circuits_simulator/state/project.dart';
|
import 'package:logic_circuits_simulator/state/project.dart';
|
||||||
import 'package:logic_circuits_simulator/state/projects.dart';
|
import 'package:logic_circuits_simulator/state/projects.dart';
|
||||||
import 'package:logic_circuits_simulator/state/script.dart';
|
|
||||||
import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
|
import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
|
||||||
import 'package:logic_circuits_simulator/utils/logic_expressions.dart';
|
import 'package:logic_circuits_simulator/utils/logic_expressions.dart';
|
||||||
import 'package:logic_circuits_simulator/utils/logic_operators.dart';
|
import 'package:logic_circuits_simulator/utils/logic_operators.dart';
|
||||||
import 'package:logic_circuits_simulator/utils/provider_hook.dart';
|
import 'package:logic_circuits_simulator/utils/provider_hook.dart';
|
||||||
import 'package:path/path.dart' as path;
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
@ -49,7 +44,6 @@ class EditComponentPage extends HookWidget {
|
||||||
: List<LogicExpression?>.generate(logicExpressions.value!.length, (index) => null),
|
: List<LogicExpression?>.generate(logicExpressions.value!.length, (index) => null),
|
||||||
);
|
);
|
||||||
final visualDesigned = useState(ce().visualDesigned);
|
final visualDesigned = useState(ce().visualDesigned);
|
||||||
final scriptBased = useState(ce().scriptBased);
|
|
||||||
final inputs = useState(ce().inputs.toList());
|
final inputs = useState(ce().inputs.toList());
|
||||||
final outputs = useState(ce().outputs.toList());
|
final outputs = useState(ce().outputs.toList());
|
||||||
final componentNameEditingController = useTextEditingController(text: ce().componentName);
|
final componentNameEditingController = useTextEditingController(text: ce().componentName);
|
||||||
|
@ -70,7 +64,7 @@ class EditComponentPage extends HookWidget {
|
||||||
// Don't allow saving empty outputs
|
// Don't allow saving empty outputs
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (truthTable.value == null && logicExpressions.value == null && !visualDesigned.value && !scriptBased.value) {
|
if (truthTable.value == null && logicExpressions.value == null && !visualDesigned.value) {
|
||||||
// Don't allow saving components without functionality
|
// Don't allow saving components without functionality
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -97,9 +91,6 @@ class EditComponentPage extends HookWidget {
|
||||||
if (visualDesigned.value != ce().visualDesigned) {
|
if (visualDesigned.value != ce().visualDesigned) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (scriptBased.value != ce().scriptBased) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
@ -116,8 +107,6 @@ class EditComponentPage extends HookWidget {
|
||||||
visualDesigned.value,
|
visualDesigned.value,
|
||||||
ce().visualDesigned,
|
ce().visualDesigned,
|
||||||
logicExpressionsParsed.value,
|
logicExpressionsParsed.value,
|
||||||
ce().scriptBased,
|
|
||||||
scriptBased.value,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -424,7 +413,7 @@ class EditComponentPage extends HookWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
else if (truthTable.value == null && logicExpressions.value == null && !visualDesigned.value && !scriptBased.value) ...[
|
else if (truthTable.value == null && logicExpressions.value == null && !visualDesigned.value) ...[
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -473,13 +462,11 @@ class EditComponentPage extends HookWidget {
|
||||||
child: const Text('Visual Designer'),
|
child: const Text('Visual Designer'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
onPressed: () async {
|
onPressed: null,
|
||||||
scriptBased.value = true;
|
child: Text('Script'),
|
||||||
},
|
|
||||||
child: const Text('Script'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -592,7 +579,7 @@ class EditComponentPage extends HookWidget {
|
||||||
try {
|
try {
|
||||||
await Provider.of<ComponentState>(context, listen: false).setCurrentComponent(
|
await Provider.of<ComponentState>(context, listen: false).setCurrentComponent(
|
||||||
project: projectState.currentProject!,
|
project: projectState.currentProject!,
|
||||||
component: ce(),
|
component: component,
|
||||||
onDependencyNeeded: (String projectId, String componentId) async {
|
onDependencyNeeded: (String projectId, String componentId) async {
|
||||||
if (projectId == 'self') {
|
if (projectId == 'self') {
|
||||||
final maybeComponent = projectState.index.components.where((c) => c.componentId == componentId).firstOrNull;
|
final maybeComponent = projectState.index.components.where((c) => c.componentId == componentId).firstOrNull;
|
||||||
|
@ -635,95 +622,7 @@ class EditComponentPage extends HookWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
],
|
|
||||||
if (scriptBased.value) ...[
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Script Component",
|
|
||||||
style: Theme.of(context).textTheme.headline4,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
HookBuilder(
|
|
||||||
builder: (context) {
|
|
||||||
final stateListenable = useState(
|
|
||||||
ScriptState(
|
|
||||||
project: projectState.currentProject!,
|
|
||||||
component: ce(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
final scriptState = useListenable(stateListenable.value);
|
|
||||||
|
|
||||||
if (!scriptState.loaded) {
|
|
||||||
return const Padding(
|
|
||||||
padding: EdgeInsets.all(8.0),
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () async {
|
|
||||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
|
||||||
final picked = await FilePicker.platform.pickFiles(
|
|
||||||
dialogTitle: 'Select Script',
|
|
||||||
// allowedExtensions: ['ht', 'txt'],
|
|
||||||
allowMultiple: false,
|
|
||||||
type: FileType.any,
|
|
||||||
);
|
|
||||||
if (picked == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final file = File(picked.files.first.path!);
|
|
||||||
if (!await file.exists()) {
|
|
||||||
scaffoldMessenger.showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('The selected file does not exist'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await scriptState.setScriptContents(await file.readAsString());
|
|
||||||
},
|
|
||||||
child: Text(scriptState.scriptExists ? 'Replace Script' : 'Select Script'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (scriptState.scriptContent != null)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
scriptState.scriptContent!,
|
|
||||||
softWrap: true,
|
|
||||||
style: TextStyle(
|
|
||||||
inherit: true,
|
|
||||||
fontFamily: 'JetBrains Mono',
|
|
||||||
fontFamilyFallback: [
|
|
||||||
'JetBrains Mono',
|
|
||||||
'Ubuntu Mono',
|
|
||||||
'Menlo',
|
|
||||||
'Cascadia Code',
|
|
||||||
'Courier New',
|
|
||||||
'Courier',
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
const SliverPadding(
|
const SliverPadding(
|
||||||
padding: EdgeInsets.only(bottom: 56 + 16 + 16),
|
padding: EdgeInsets.only(bottom: 56 + 16 + 16),
|
||||||
|
@ -741,9 +640,9 @@ class EditComponentPage extends HookWidget {
|
||||||
truthTable: truthTable.value,
|
truthTable: truthTable.value,
|
||||||
logicExpression: logicExpressions.value,
|
logicExpression: logicExpressions.value,
|
||||||
visualDesigned: visualDesigned.value,
|
visualDesigned: visualDesigned.value,
|
||||||
scriptBased: scriptBased.value,
|
|
||||||
));
|
));
|
||||||
anySave.value = true;
|
anySave.value = true;
|
||||||
|
// TODO: Implement saving
|
||||||
},
|
},
|
||||||
tooltip: 'Save Component',
|
tooltip: 'Save Component',
|
||||||
child: const Icon(Icons.save),
|
child: const Icon(Icons.save),
|
||||||
|
|
|
@ -77,7 +77,6 @@ class ProjectState extends ChangeNotifier {
|
||||||
outputs: [],
|
outputs: [],
|
||||||
visualDesigned: false,
|
visualDesigned: false,
|
||||||
dependencies: [],
|
dependencies: [],
|
||||||
scriptBased: false,
|
|
||||||
);
|
);
|
||||||
await _updateIndex(index.copyWith(components: index.components + [newComponent]));
|
await _updateIndex(index.copyWith(components: index.components + [newComponent]));
|
||||||
return newComponent;
|
return newComponent;
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:logic_circuits_simulator/models.dart';
|
|
||||||
import 'package:path/path.dart' as path;
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
class ScriptState extends ChangeNotifier {
|
|
||||||
bool? _scriptExists;
|
|
||||||
String? _scriptContent;
|
|
||||||
|
|
||||||
bool get loaded => _scriptExists != null;
|
|
||||||
bool get scriptExists => _scriptExists ?? false;
|
|
||||||
String? get scriptContent => _scriptContent;
|
|
||||||
|
|
||||||
final ProjectEntry project;
|
|
||||||
final ComponentEntry component;
|
|
||||||
|
|
||||||
ScriptState({required this.project, required this.component, bool invokeInit = true}) {
|
|
||||||
if (invokeInit) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<File> _getScriptFile() async {
|
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
|
||||||
final componentDir = Directory(path.join(appDir.path, 'LogicCircuitsSimulator', 'projects', project.projectId, 'components', component.componentId));
|
|
||||||
if (!await componentDir.exists()) {
|
|
||||||
await componentDir.create(recursive: true);
|
|
||||||
}
|
|
||||||
return File(path.join(componentDir.path, 'script.ht'));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> init() async {
|
|
||||||
final scriptFile = await _getScriptFile();
|
|
||||||
_scriptExists = await scriptFile.exists();
|
|
||||||
if (scriptExists) {
|
|
||||||
_scriptContent = await scriptFile.readAsString();
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> setScriptContents(String newContents) async {
|
|
||||||
final scriptFile = await _getScriptFile();
|
|
||||||
await scriptFile.writeAsString(newContents);
|
|
||||||
_scriptContent = newContents;
|
|
||||||
_scriptExists = true;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> deleteScript() async {
|
|
||||||
final scriptFile = await _getScriptFile();
|
|
||||||
await scriptFile.delete();
|
|
||||||
_scriptContent = null;
|
|
||||||
_scriptExists = false;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,7 @@
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hetu_script/hetu_script.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/state/script.dart';
|
|
||||||
import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
|
import 'package:logic_circuits_simulator/utils/iterable_extension.dart';
|
||||||
import 'package:logic_circuits_simulator/utils/logic_expressions.dart';
|
import 'package:logic_circuits_simulator/utils/logic_expressions.dart';
|
||||||
|
|
||||||
|
@ -57,23 +55,6 @@ class SimulatedComponent {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return {for (final it in results) it[0] as String: it[1] as bool};
|
return {for (final it in results) it[0] as String: it[1] as bool};
|
||||||
} else if (component.scriptBased) {
|
|
||||||
final state = ScriptState(
|
|
||||||
component: component,
|
|
||||||
project: project,
|
|
||||||
invokeInit: false,
|
|
||||||
);
|
|
||||||
await state.init();
|
|
||||||
if (!state.scriptExists) {
|
|
||||||
throw Exception('Script for component ${project.projectId}/${component.componentId} does not exist');
|
|
||||||
}
|
|
||||||
final hetu = Hetu();
|
|
||||||
hetu.init();
|
|
||||||
final result = hetu.eval(state.scriptContent!, invokeFunc: 'simulate', positionalArgs: [inputs]);
|
|
||||||
return {
|
|
||||||
for (final output in component.outputs)
|
|
||||||
output: result[output]
|
|
||||||
};
|
|
||||||
} else if (state == null) {
|
} else if (state == null) {
|
||||||
throw Exception('Cannot simulate designed component without its state');
|
throw Exception('Cannot simulate designed component without its state');
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue