Graphs_dart/flutter/lib/pages/drawing_page.dart

500 lines
17 KiB
Dart
Raw Normal View History

2021-11-05 14:25:36 +03:00
import 'package:graphs/src/graph.dart';
2021-11-05 00:35:51 +03:00
import 'package:graphs/curve_painter.dart';
2021-11-05 14:25:36 +03:00
import 'package:file_picker/file_picker.dart';
2021-11-05 00:35:51 +03:00
import 'package:flutter/material.dart';
Graphs getGraph() {
List<Dot> d = <Dot>[];
d.add(Dot.fromTwoLists("1", [2, 3], [5, 1]));
d.add(Dot.fromTwoLists("2", [1, 3], [1, 1]));
d.add(Dot.fromTwoLists("3", [1, 2], [1, 2]));
2021-11-08 18:37:13 +03:00
//d.add(Dot.fromTwoLists("Name1", [], []));
//d.add(Dot.fromTwoLists("Name2", [], []));
2021-11-09 03:15:36 +03:00
return Graphs.fromList("Имя", d, true, true);
}
2021-11-05 00:35:51 +03:00
class DrawingPage extends StatefulWidget {
const DrawingPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _DrawingPageState();
}
class _DrawingPageState extends State<DrawingPage> {
2021-11-05 01:40:16 +03:00
double screenSize = 0;
Graphs graphData = getGraph();
List<int>? bfsPath;
List<bool>? dfsAccessTable;
int? startDot;
int? endDot;
String? dropdownValue1;
String? dropdownValue2;
2021-11-05 00:35:51 +03:00
final _textNameController = TextEditingController();
final _textNumbController = TextEditingController();
2021-11-05 14:25:36 +03:00
final _textDestController = TextEditingController();
final _textLnthController = TextEditingController();
final _textGrNmController = TextEditingController();
2021-11-05 14:25:36 +03:00
void clearInputData() {
setState(() {
_textDestController.clear();
_textNumbController.clear();
_textLnthController.clear();
_textNameController.clear();
dropdownValue1 = null;
dropdownValue2 = null;
/*startDot = null;
bfsPath = null;
dfsAccessTable = null;
endDot = null;*/
});
}
2021-11-05 01:40:16 +03:00
2021-11-10 15:05:16 +03:00
// *************buttons*************
ElevatedButton createButton(String txt, void Function() onPressing) {
2021-11-05 00:35:51 +03:00
return ElevatedButton(
2021-11-05 01:40:16 +03:00
onPressed: onPressing,
2021-11-09 03:15:36 +03:00
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(states) => Colors.green.shade700)),
2021-11-05 00:35:51 +03:00
child: Text(txt,
style: const TextStyle(
fontSize: 15,
2021-11-09 03:15:36 +03:00
color: Colors.white70,
2021-11-05 00:35:51 +03:00
height: 1,
)),
);
}
2021-11-10 15:05:16 +03:00
void showPopUp(String alertTitle, String err) => showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text(alertTitle),
content: Text(err),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'OK'),
child: const Text('OK'),
),
],
),
);
// *************buttons*************
// ***addSpace***
SizedBox addSpaceH(double h) {
return SizedBox(height: h);
}
SizedBox addSpaceW(double w) {
return SizedBox(width: w);
}
// ***addSpace***
// *************inputs*************
Container createInputBox(String text, double wid, IconData? icon,
TextEditingController? controller) {
if (icon == null) {
return Container(
width: wid,
height: 40,
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: TextField(
controller: controller,
textAlign: TextAlign.center,
onChanged: (name) => graphData.setName(name),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
filled: true,
fillColor: Colors.white,
//prefixIcon: Icon(icon, color: Colors.black),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(40))),
hintStyle: const TextStyle(color: Colors.black38),
hintText: text),
));
}
2021-11-05 01:40:16 +03:00
return Container(
width: wid,
height: 40,
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: TextField(
controller: controller,
textAlign: TextAlign.center,
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
filled: true,
fillColor: Colors.white,
prefixIcon: Icon(icon, color: Colors.black),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(40))),
hintStyle: const TextStyle(color: Colors.black38),
hintText: text),
));
}
2021-11-10 15:05:16 +03:00
SizedBox dropList1(double width) {
var button = DropdownButton(
hint: const Text(
'Select Dot',
style: TextStyle(color: Colors.white, fontSize: 13),
),
//icon: const Icon(Icons.fiber_manual_record, color: Colors.white),
alignment: AlignmentDirectional.bottomEnd,
value: dropdownValue1,
isDense: true,
borderRadius: const BorderRadius.all(Radius.circular(20)),
dropdownColor: Colors.green.shade800,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue1 = newValue;
});
},
items: graphData.getDots().map((location) {
return DropdownMenuItem(
child: Text(location.getName()),
value: location.num.toString(),
);
}).toList(),
);
2021-11-05 00:35:51 +03:00
2021-11-10 15:05:16 +03:00
return SizedBox(
child: button,
width: width,
);
2021-11-05 01:40:16 +03:00
}
2021-11-10 15:05:16 +03:00
SizedBox dropList2(double width) {
var button = DropdownButton(
hint: const Text(
'Select Dot',
style: TextStyle(color: Colors.white, fontSize: 13),
),
alignment: AlignmentDirectional.centerEnd,
value: dropdownValue2,
isDense: true,
borderRadius: const BorderRadius.all(Radius.circular(20)),
dropdownColor: Colors.green.shade800,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue2 = newValue;
});
},
items: graphData.getDots().map((location) {
return DropdownMenuItem(
child: Text(location.getName()),
value: location.num.toString(),
);
}).toList(),
);
return SizedBox(
child: button,
width: width,
);
}
// *************inputs*************
//*********ButtonsFunctions*********
2021-11-05 01:40:16 +03:00
void addDotPushed() {
setState(() {
if (_textNameController.text == "") {
showPopUp("Error", "No name in \"Dot name\" box");
} else {
String? res = graphData.addIsolated(_textNameController.text);
if (res != null) {
showPopUp("Error", res);
}
}
clearInputData();
});
2021-11-05 14:25:36 +03:00
}
void addPathPushed() {
setState(() {
if (dropdownValue1 == null) {
showPopUp("Error", "Select output dot");
} else if (dropdownValue2 == null) {
showPopUp("Error", "select input dot");
} else if (_textLnthController.text == "" &&
graphData.getUseLengthBool()) {
showPopUp("Error", "No length in \"Input length\" box");
} else {
int? from = int.parse(dropdownValue1!);
int? to = int.parse(dropdownValue2!);
int? len = int.tryParse(_textLnthController.text);
if (len == null && graphData.getUseLengthBool()) {
showPopUp("Error",
"Can't parse input.\nInts only allowed in \"Dot number\", \"Destination number\" and \"Input length\"");
} else {
len ??= 0;
String? res = graphData.addPath(from, to, len);
if (res != null) {
showPopUp("Error", res);
}
}
2021-11-05 14:25:36 +03:00
}
clearInputData();
});
}
void changeOriented() {
setState(() {
String? res = graphData.flipUseOrientation();
if (res != null) showPopUp("Error", res);
});
}
void changeLength() {
setState(() {
String? res = graphData.flipUseLength();
if (res != null) showPopUp("Error", res);
});
}
2021-11-05 14:25:36 +03:00
void delPathPushed() {
setState(() {
if (_textNumbController.text == "") {
showPopUp("Error", "No number in \"Dot number\" box");
} else if (_textDestController.text == "") {
showPopUp("Error", "No name in \"Dot name\" box");
} else {
int? from = int.tryParse(_textNumbController.text);
int? to = int.tryParse(_textDestController.text);
if (from == null || to == null) {
showPopUp("Error",
"Can't parse input.\nInts only allowed in \"Dot number\" and \"Destination number\"");
} else {
String? res = graphData.delPath(from, to);
if (res != null) {
showPopUp("Error", res);
}
}
2021-11-05 14:25:36 +03:00
}
clearInputData();
});
}
void delDotPushed() {
setState(() {
if (dropdownValue1 != null) {
graphData.delDot(int.parse(dropdownValue1!));
} else {
showPopUp("Error", "Nothing in input");
}
clearInputData();
});
2021-11-05 01:40:16 +03:00
}
2021-11-05 14:25:36 +03:00
void fileOpener() async {
FilePickerResult? result =
await FilePicker.platform.pickFiles(allowedExtensions: ["txt"]);
setState(() {
if (result != null) {
if (!result.files.single.path!.endsWith(".txt")) {
showPopUp("Error", "Can open only \".txt\" files");
} else {
String? res =
graphData.replaceDataFromFile(result.files.single.path!);
if (res != null) showPopUp("Error", res);
}
} else {
showPopUp("Error", "No file selected");
}
});
}
2021-11-05 14:25:36 +03:00
void fileSaver() async {
String? outputFile = await FilePicker.platform.saveFile(
dialogTitle: 'Please select an output file:',
fileName: 'output-file.txt',
allowedExtensions: ["txt"]);
if (outputFile == null) {
showPopUp("Error", "Save cancelled");
} else {
if (!outputFile.endsWith(".txt")) {
outputFile += ".txt";
}
graphData.printToFile(outputFile);
2021-11-05 00:35:51 +03:00
}
}
2021-11-05 14:25:36 +03:00
void bfsPushed() {
setState(() {
bfsPath = null;
dfsAccessTable = null;
startDot = null;
endDot = null;
if (dropdownValue1 == null) {
showPopUp("Error", "No number in \"Dot number\" box");
} else if (dropdownValue2 == null) {
2021-11-09 03:15:36 +03:00
showPopUp("Error", "No number in \"Destination number\" box");
} else {
startDot = int.parse(dropdownValue1!);
endDot = int.parse(dropdownValue2!);
bfsPath = graphData.bfsPath(startDot!, endDot!);
if (bfsPath == null) {
showPopUp("Info", "There is no path");
}
print(bfsPath);
}
});
clearInputData();
}
void dfsPushed() {
setState(() {
bfsPath = null;
dfsAccessTable = null;
startDot = null;
endDot = null;
if (dropdownValue1 == null) {
showPopUp("Error", "No number in \"Dot number\" box");
} else {
startDot = int.parse(dropdownValue1!);
dfsAccessTable = graphData.dfsIterative(startDot!);
if (dfsAccessTable == null) {
showPopUp("Err", "report this error.");
}
print(dfsAccessTable);
}
clearInputData();
});
}
//*********ButtonsFunctions*********
2021-11-10 15:05:16 +03:00
// build
@override
Widget build(BuildContext context) {
screenSize = MediaQuery.of(context).size.width;
_textGrNmController.text = graphData.getName();
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Align(
alignment: Alignment.topLeft,
child: Text("Graph name:\n",
style: TextStyle(
fontSize: 18,
color: Colors.white,
))),
toolbarHeight: 110,
flexibleSpace: Container(
color: Colors.green.shade900,
child: Column(children: <Widget>[
const SizedBox(height: 5),
Row(children: [
addSpaceW(screenSize / 8 + 19),
createButton("\nAdd dot\n", addDotPushed),
createInputBox("Dot name", screenSize / 4 - 25, Icons.label,
_textNameController),
addSpaceW(8),
createButton("\nAdd path\n", addPathPushed),
createInputBox("Input length", screenSize / 4 - 25,
Icons.arrow_right_alt_outlined, _textLnthController),
]),
addSpaceH(3),
Row(children: [
addSpaceW(6),
createInputBox(
"Name", screenSize / 8 - 25, null, _textGrNmController),
//addSpaceW(screenSize / 8 - 4),
createButton("\nDel dot \n", delDotPushed),
//createInputBox("Dot number", screenSize / 4 - 25, Icons.fiber_manual_record, _textNumbController),
addSpaceW(54),
dropList1(screenSize / 4 - 80),
addSpaceW(54),
createButton("\nDel path\n", delPathPushed),
addSpaceW(54),
dropList2(screenSize / 4 - 80),
//createInputBox("Destination number", screenSize / 4 - 25, Icons.fiber_manual_record, _textDestController),
]),
]),
),
actions: [
IconButton(
onPressed: () {
setState(() {
startDot = null;
endDot = null;
bfsPath = null;
dfsAccessTable = null;
graphData.flushData();
clearInputData();
});
},
icon: const Icon(Icons.delete_sweep),
iconSize: 60,
),
]),
body: CustomPaint(
painter: CurvePainter(
graphData: graphData,
bfsPath: bfsPath,
dfsAccessTable: dfsAccessTable,
start: startDot,
end: endDot),
child: Align(
alignment: Alignment.topRight,
child: ButtonBar(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
createButton("Bfs", bfsPushed),
createButton("Dfs", dfsPushed),
createButton("Clear dfs or bfs", () {
setState(() {
bfsPath = null;
dfsAccessTable = null;
startDot = null;
endDot = null;
clearInputData();
});
}),
createButton(graphData.getUseLengthStr(), changeLength),
createButton(graphData.getDoubleSidedStr(), changeOriented),
createButton("Save to file", fileSaver),
createButton("Load from file", fileOpener),
createButton("Help", () {
String out =
" В поле \"Graph name\" можно сменить имя графу.\n";
out +=
" Для добавления точки необходимо ввести имя в \"Dot name\" и нажать на \"Add dot\".\n";
out +=
" Для удаления точки необходимо ввести номер в \"Dot number\" и нажать на \"Del dot\".\n";
out +=
" Для добавления пути необходимо ввести: номер выходной вершины в \"Dot number\", номер входной вершины в \"Destination number\" ";
out +=
"и, если граф взвешенный, то ввести длину пути в \"Input length\". Затем нажать \"Add path\".\n";
out +=
" Для удаления пути необходимо ввести номер выходной вершины в \"Dot number\" и номер входной вершины в \"Destination number\". Затем нажать \"Del path\".\n\n";
out +=
" Кнопки \"Bfs\" и \"Dfs\" нумеруют точки в зависимости от послежовательности, в которой они будут пройдены.\n";
out +=
" Кнопки \"Взвешенный\" и \"Ориентированный\" позволяют сменить эти значения перед построением графа (т.е. для их работы граф должен быть пустым).\n";
out +=
" Кнопки \"Save to file\" и \"Load from file\" позволяют вывести информацию в файл и загрузить информацию из файла соответственно.\n";
out +=
" Кнопка \"Help\" описывает работу с интерфейсом программы.";
showPopUp("Help:", out);
})
],
),
),
),
2021-11-10 15:05:16 +03:00
));
}
2021-11-05 00:35:51 +03:00
}