diff --git a/lib/components/truth_table.dart b/lib/components/truth_table.dart new file mode 100644 index 0000000..3c6fcfa --- /dev/null +++ b/lib/components/truth_table.dart @@ -0,0 +1,183 @@ +import 'package:flutter/material.dart'; +import 'package:logic_circuits_simulator/utils/iterable_extension.dart'; + +class TruthTableHeaderText extends StatelessWidget { + final String text; + final BoxBorder? border; + + const TruthTableHeaderText(this.text, {super.key, this.border}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: border, + ), + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), + child: Text( + text, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + ); + } +} + +class TruthTableTrue extends StatelessWidget { + final BoxBorder? border; + final void Function()? onTap; + + const TruthTableTrue({super.key, this.border, this.onTap}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: border, + ), + child: InkWell( + onTap: onTap, + child: Text( + 'T', + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Colors.green, + fontSize: 20, + ), + ), + ), + ); + } +} + +class TruthTableFalse extends StatelessWidget { + final BoxBorder? border; + final void Function()? onTap; + + const TruthTableFalse({super.key, this.border, this.onTap}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: border, + ), + child: InkWell( + onTap: onTap, + child: Text( + 'F', + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Colors.red, + fontSize: 20, + ), + ), + ), + ); + } +} + +class TruthTableEditor extends StatelessWidget { + static const marginBorder = BorderSide( + color: Colors.black, + width: 2, + ); + static const innerBorder = BorderSide( + color: Colors.black45, + width: 1, + ); + + final List inputs; + final List outputs; + final List truthTable; + + final void Function(int, String)? onUpdateTable; + + const TruthTableEditor({Key? key, required this.inputs, required this.outputs, required this.truthTable, required this.onUpdateTable}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Table( + defaultColumnWidth: const IntrinsicColumnWidth(), + border: TableBorder.symmetric(outside: const BorderSide(width: 2)), + children: List.generate( + truthTable.length + 1, + (index) { + if (index == 0) { + return TableRow( + children: inputs + .indexedMap( + (index, e) => TruthTableHeaderText( + e, + border: Border( + bottom: marginBorder, + right: index == inputs.length - 1 + ? marginBorder + : innerBorder, + ), + ) + ) + .followedBy( + outputs + .indexedMap( + (index, e) => TruthTableHeaderText( + e, + border: Border( + bottom: const BorderSide(width: 2), + right: index == outputs.length - 1 + ? BorderSide.none + : innerBorder, + ), + ) + ) + ) + .toList(), + ); + } + final inputBinary = (index - 1).toRadixString(2).padLeft(inputs.length, '0'); + final outputBinary = truthTable[index - 1]; + + Widget runeToWidget({required int rune, void Function()? onTap, BoxBorder? border}) { + return int.parse(String.fromCharCode(rune)) != 0 + ? TruthTableTrue( + border: border, + onTap: onTap, + ) + : TruthTableFalse( + border: border, + onTap: onTap, + ); + } + + return TableRow( + children: inputBinary.runes.indexedMap( + (i, r) => runeToWidget( + rune: r, + border: i == inputBinary.runes.length - 1 + ? const Border(right: marginBorder) + : const Border(right: innerBorder), + ) + ) + .followedBy(outputBinary.runes.indexedMap( + (i, r) => runeToWidget( + rune: r, + border: i == outputBinary.runes.length - 1 + ? null + : const Border(right: innerBorder), + onTap: onUpdateTable == null ? null : () { + onUpdateTable!(index - 1, outputBinary.replaceRange(i, i+1, (outputBinary[i] == "1") ? "0" : "1")); + }, + ), + )) + .toList(), + ); + }, + ), + ); + } +} diff --git a/lib/pages/edit_component.dart b/lib/pages/edit_component.dart index 9606b74..c09f5ce 100644 --- a/lib/pages/edit_component.dart +++ b/lib/pages/edit_component.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:logic_circuits_simulator/components/truth_table.dart'; import 'package:logic_circuits_simulator/dialogs/new_ask_for_name.dart'; import 'package:logic_circuits_simulator/models/project.dart'; import 'package:logic_circuits_simulator/state/project.dart'; @@ -398,155 +399,3 @@ class EditComponentPage extends HookWidget { ); } } - -class TruthTableHeaderText extends StatelessWidget { - final String text; - final BoxBorder? border; - - const TruthTableHeaderText(this.text, {super.key, this.border}); - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - border: border, - ), - child: Text( - text, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - fontWeight: FontWeight.bold, - fontSize: 24, - ), - ), - ); - } -} - -class TruthTableTrue extends StatelessWidget { - final BoxBorder? border; - final void Function()? onTap; - - const TruthTableTrue({super.key, this.border, this.onTap}); - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - border: border, - ), - child: InkWell( - onTap: onTap, - child: Text( - 'T', - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Colors.green, - fontSize: 20, - ), - ), - ), - ); - } -} - -class TruthTableFalse extends StatelessWidget { - final BoxBorder? border; - final void Function()? onTap; - - const TruthTableFalse({super.key, this.border, this.onTap}); - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - border: border, - ), - child: InkWell( - onTap: onTap, - child: Text( - 'F', - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Colors.red, - fontSize: 20, - ), - ), - ), - ); - } -} - -class TruthTableEditor extends StatelessWidget { - final List inputs; - final List outputs; - final List truthTable; - - final void Function(int, String) onUpdateTable; - - const TruthTableEditor({Key? key, required this.inputs, required this.outputs, required this.truthTable, required this.onUpdateTable}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Table( - defaultColumnWidth: const IntrinsicColumnWidth(), - border: TableBorder.symmetric(outside: const BorderSide(width: 2)), - children: List.generate( - truthTable.length + 1, - (index) { - if (index == 0) { - return TableRow( - children: inputs - .indexedMap( - (index, e) => TruthTableHeaderText( - e, - border: Border( - bottom: const BorderSide(width: 2), - right: index == inputs.length - 1 ? const BorderSide(width: 2) : BorderSide.none, - ), - ) - ) - .followedBy( - outputs - .map((e) => TruthTableHeaderText(e, border: const Border(bottom: BorderSide(width: 2)),)) - ) - .toList(), - ); - } - final inputBinary = (index - 1).toRadixString(2).padLeft(inputs.length, '0'); - final outputBinary = truthTable[index - 1]; - - Widget runeToWidget({required int rune, void Function()? onTap, BoxBorder? border}) { - return int.parse(String.fromCharCode(rune)) != 0 - ? TruthTableTrue( - border: border, - onTap: onTap, - ) - : TruthTableFalse( - border: border, - onTap: onTap, - ); - } - - return TableRow( - children: inputBinary.runes.indexedMap( - (i, r) => runeToWidget( - rune: r, - border: i == inputBinary.runes.length - 1 ? const Border(right: BorderSide(width: 2)) : null, - ) - ) - .followedBy(outputBinary.runes.indexedMap( - (i, r) => runeToWidget( - rune: r, - onTap: () { - onUpdateTable(index - 1, outputBinary.replaceRange(i, i+1, (outputBinary[i] == "1") ? "0" : "1")); - }, - ), - )) - .toList(), - ); - }, - ), - ); - } -}