route_planning.dart 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import 'dart:async';
  2. import 'package:fixnum/fixnum.dart';
  3. import 'package:get/get.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:trackoffical_app/generated/assets.dart';
  6. import 'package:trackoffical_app/logger.dart';
  7. import 'package:trackoffical_app/model/m_control_point.dart';
  8. import 'package:trackoffical_app/screen.dart';
  9. import 'package:trackoffical_app/service/game/game_model.dart';
  10. import 'package:trackoffical_app/view/ingame/utils.dart';
  11. class RoutePlanning extends StatefulWidget {
  12. const RoutePlanning({super.key,
  13. required this.want,
  14. required this.nextPlanPoint,
  15. required this.nextWantPoint,
  16. required this.onClick});
  17. final List<MControlPoint> want;
  18. final MControlPoint? nextPlanPoint;
  19. final MControlPoint? nextWantPoint;
  20. final void Function (MControlPoint point) onClick;
  21. @override
  22. State<StatefulWidget> createState() {
  23. return RoutePlanningState();
  24. }
  25. }
  26. const _iconSize = 6.0;
  27. const _rowSpace = 5.23;
  28. const _columSpace = 20.0;
  29. const _pointWidth = 18.0;
  30. class RoutePlanningState extends State<RoutePlanning> {
  31. var contentHeight=0.0;
  32. @override
  33. Widget build(BuildContext context) {
  34. return DefaultTextStyle(style: context.textTheme.bodyLarge??const TextStyle(), child: Container(
  35. margin: EdgeInsets.fromLTRB(5.6.wp, 11.45.wp, 5.6.wp, 11.45.wp),
  36. padding: EdgeInsets.all(5.3.wp),
  37. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(2.29.wp)),
  38. child: Column(
  39. crossAxisAlignment: CrossAxisAlignment.center,
  40. children: [
  41. Text('路径规划', style: context.textTheme.titleLarge?.copyWith(fontSize: 5.6.wp)),
  42. SizedBox(height: 4.0.wp,),
  43. Expanded(child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
  44. final height = constraints.maxHeight;
  45. final iconSize = _iconSize.wp;
  46. final rowSpace = _rowSpace.wp;
  47. final columSpace = _columSpace.wp;
  48. final pointWidth = _pointWidth.wp;
  49. final rowCount = (height - rowSpace) ~/ (rowSpace + iconSize);
  50. final contentHeight = rowCount * (rowSpace + iconSize);
  51. final columCount = (widget.want.length.toDouble() / rowCount).ceil();
  52. final width = (columSpace+pointWidth) * (columCount);
  53. final colum = <Widget>[];
  54. var index = 0;
  55. for(var i=0; i< columCount; i++){
  56. var row = <Widget>[];
  57. final isOdd = i % 2 == 1;
  58. for(var j=0; j< rowCount; j++){
  59. if(index == widget.want.length){
  60. break;
  61. }
  62. final point = widget.want[index];
  63. Widget? next;
  64. if(widget.nextWantPoint?.intId==point.intId){
  65. next = Image.asset(Assets.imagesWarnRun, height: 7.0.wp, color: Colors.grey);
  66. }
  67. if(widget.nextPlanPoint?.intId==point.intId){
  68. next = Image.asset(Assets.imagesWarnRun, height: 7.0.wp, color: Colors.black);
  69. }
  70. row.addAll([
  71. Row(
  72. children: [
  73. Container(width: columSpace, alignment: Alignment.centerRight, child: next),
  74. GestureDetector(
  75. onTap: ()=>widget.onClick(point),
  76. child: SizedBox(
  77. width: pointWidth,
  78. child: Column(
  79. crossAxisAlignment: CrossAxisAlignment.start,
  80. children: [
  81. (point.isFinish && isOdd) || point.isStart? SizedBox(height: rowSpace/2):
  82. Container(
  83. margin: EdgeInsets.only(left: iconSize/2-0.5.wp/2),
  84. height: rowSpace/2,
  85. width: 0.5.wp,
  86. color: const Color(0xff707070),
  87. ),
  88. Row(
  89. children: [
  90. _icon(point, iconSize),
  91. Text(' ${point.snString}', style: TextStyle(fontSize: 3.56.wp),)
  92. ],
  93. ),
  94. point.isFinish && !isOdd? const SizedBox():
  95. Container(
  96. margin: EdgeInsets.only(left: iconSize/2-0.5.wp/2),
  97. height: rowSpace/2,
  98. width: 0.5.wp,
  99. color: const Color(0xff707070),
  100. )
  101. ],
  102. )
  103. )
  104. ),
  105. ],
  106. ),
  107. ] );
  108. index++;
  109. }
  110. if(isOdd){
  111. row=row.reversed.toList();
  112. }
  113. colum.add(SizedBox(height: contentHeight, child: Column(
  114. mainAxisAlignment: !isOdd? MainAxisAlignment.start: MainAxisAlignment.end,
  115. mainAxisSize: MainAxisSize.max,
  116. children: row))) ;
  117. }
  118. return ListView(
  119. scrollDirection: Axis.horizontal,
  120. children: [
  121. SizedBox(
  122. height: height,
  123. width: width,
  124. child: Column(
  125. children: [
  126. CustomPaint(painter: _BottomPainter(columCount, false), size: Size(width, rowSpace/2)),
  127. Row(
  128. mainAxisSize: MainAxisSize.min,
  129. children: colum,
  130. ),
  131. CustomPaint(painter: _BottomPainter(columCount, true), size: Size(width, rowSpace/2))
  132. ],
  133. ),
  134. )
  135. ],
  136. );
  137. })),
  138. FilledButton(onPressed: ()=>Get.back(), child: const Text('返回'))
  139. ],
  140. )
  141. ) );
  142. }
  143. }
  144. Widget _icon(MControlPoint point, double iconSize){
  145. var w = point.icon(height: iconSize);
  146. if(!point.isSuccess){
  147. if(point.isFinish){
  148. w = Image.asset(Assets.imagesIcCpFinishUncheck, height: iconSize,);
  149. }else{
  150. w = Image.asset(Assets.imagesIcCpUncheck, height: iconSize);
  151. }
  152. }
  153. return w;
  154. }
  155. class _BottomPainter extends CustomPainter{
  156. _BottomPainter(this.columCount, this.isBottom);
  157. final int columCount;
  158. final bool isBottom;
  159. final iconSize = _iconSize.wp;
  160. final rowSpace = _rowSpace.wp;
  161. final columSpace = _columSpace.wp;
  162. final pointWidth = _pointWidth.wp;
  163. @override
  164. void paint(Canvas canvas, Size size) {
  165. final paint = Paint()
  166. ..color=const Color(0xff707070)
  167. ..strokeWidth=0.5.wp
  168. ..style=PaintingStyle.stroke;
  169. for(var i=0; i< columCount; i++){
  170. final isOdd = i%2==1;
  171. if(isBottom){
  172. if(!isOdd){
  173. continue;
  174. }
  175. }else{
  176. if(i==0){
  177. continue;
  178. }
  179. if(isOdd){
  180. continue;
  181. }
  182. }
  183. final path = Path();
  184. var x = 0.0;
  185. var y = 0.0;
  186. x = iconSize/2 + columSpace + (columSpace + pointWidth) * i;
  187. if(!isBottom){
  188. y=size.height;
  189. }
  190. path.moveTo(x, y);
  191. if(isBottom){
  192. y+= size.height;
  193. }else{
  194. y-= size.height-1;
  195. }
  196. path.lineTo(x, y);
  197. x -= columSpace+pointWidth;
  198. path.lineTo(x, y);
  199. if(isBottom){
  200. y-= size.height;
  201. }else{
  202. y+=size.height;
  203. }
  204. path.lineTo(x, y);
  205. canvas.drawPath(path, paint);
  206. }
  207. }
  208. @override
  209. bool shouldRepaint(covariant CustomPainter oldDelegate) {
  210. return false;
  211. }
  212. }
  213. void dialogRoutePlanning(){
  214. Get.dialog(Center(
  215. child: Obx((){
  216. final model = Get.find<GameModel> ();
  217. return RoutePlanning(
  218. want: model.controlPointWantSequence,
  219. nextPlanPoint: model.nextPlanPoint,
  220. nextWantPoint: model.getNextWantPoint(0),
  221. onClick: (point){
  222. model.nextPlanPoint=point;
  223. });
  224. }) ),
  225. );
  226. }
  227. void main(){
  228. final want = <MControlPoint>[];
  229. for(var i=0; i< 15; i++){
  230. want.add(MControlPoint()
  231. ..sn='$i'
  232. ..intId=Int64(i)
  233. ..isSuccess=i<8);
  234. }
  235. want[0].isStart=true;
  236. want.last.isFinish=true;
  237. runPreview(Scaffold(
  238. body: RoutePlanning(
  239. want: want,
  240. nextPlanPoint: want[2],
  241. nextWantPoint: want[3], onClick: (MControlPoint point) {
  242. debug('点击 ${point.snString}');
  243. },
  244. ),
  245. ));
  246. }