import 'dart:async'; import 'package:fixnum/fixnum.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:trackoffical_app/generated/assets.dart'; import 'package:trackoffical_app/logger.dart'; import 'package:trackoffical_app/model/m_control_point.dart'; import 'package:trackoffical_app/screen.dart'; import 'package:trackoffical_app/service/game/game_model.dart'; import 'package:trackoffical_app/view/ingame/utils.dart'; class RoutePlanning extends StatefulWidget { const RoutePlanning({super.key, required this.want, required this.nextPlanPoint, required this.nextWantPoint, required this.onClick}); final List want; final MControlPoint? nextPlanPoint; final MControlPoint? nextWantPoint; final void Function (MControlPoint point) onClick; @override State createState() { return RoutePlanningState(); } } const _iconSize = 6.0; const _rowSpace = 5.23; const _columSpace = 20.0; const _pointWidth = 18.0; class RoutePlanningState extends State { var contentHeight=0.0; @override Widget build(BuildContext context) { return DefaultTextStyle(style: context.textTheme.bodyLarge??const TextStyle(), child: Container( margin: EdgeInsets.fromLTRB(5.6.wp, 11.45.wp, 5.6.wp, 11.45.wp), padding: EdgeInsets.all(5.3.wp), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(2.29.wp)), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text('路径规划', style: context.textTheme.titleLarge?.copyWith(fontSize: 5.6.wp)), SizedBox(height: 4.0.wp,), Expanded(child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { final height = constraints.maxHeight; final iconSize = _iconSize.wp; final rowSpace = _rowSpace.wp; final columSpace = _columSpace.wp; final pointWidth = _pointWidth.wp; final rowCount = (height - rowSpace) ~/ (rowSpace + iconSize); final contentHeight = rowCount * (rowSpace + iconSize); final columCount = (widget.want.length.toDouble() / rowCount).ceil(); final width = (columSpace+pointWidth) * (columCount); final colum = []; var index = 0; for(var i=0; i< columCount; i++){ var row = []; final isOdd = i % 2 == 1; for(var j=0; j< rowCount; j++){ if(index == widget.want.length){ break; } final point = widget.want[index]; Widget? next; if(widget.nextWantPoint?.intId==point.intId){ next = Image.asset(Assets.imagesWarnRun, height: 7.0.wp, color: Colors.grey); } if(widget.nextPlanPoint?.intId==point.intId){ next = Image.asset(Assets.imagesWarnRun, height: 7.0.wp, color: Colors.black); } row.addAll([ Row( children: [ Container(width: columSpace, alignment: Alignment.centerRight, child: next), GestureDetector( onTap: ()=>widget.onClick(point), child: SizedBox( width: pointWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ (point.isFinish && isOdd) || point.isStart? SizedBox(height: rowSpace/2): Container( margin: EdgeInsets.only(left: iconSize/2-0.5.wp/2), height: rowSpace/2, width: 0.5.wp, color: const Color(0xff707070), ), Row( children: [ _icon(point, iconSize), Text(' ${point.snString}', style: TextStyle(fontSize: 3.56.wp),) ], ), point.isFinish && !isOdd? const SizedBox(): Container( margin: EdgeInsets.only(left: iconSize/2-0.5.wp/2), height: rowSpace/2, width: 0.5.wp, color: const Color(0xff707070), ) ], ) ) ), ], ), ] ); index++; } if(isOdd){ row=row.reversed.toList(); } colum.add(SizedBox(height: contentHeight, child: Column( mainAxisAlignment: !isOdd? MainAxisAlignment.start: MainAxisAlignment.end, mainAxisSize: MainAxisSize.max, children: row))) ; } return ListView( scrollDirection: Axis.horizontal, children: [ SizedBox( height: height, width: width, child: Column( children: [ CustomPaint(painter: _BottomPainter(columCount, false), size: Size(width, rowSpace/2)), Row( mainAxisSize: MainAxisSize.min, children: colum, ), CustomPaint(painter: _BottomPainter(columCount, true), size: Size(width, rowSpace/2)) ], ), ) ], ); })), FilledButton(onPressed: ()=>Get.back(), child: const Text('返回')) ], ) ) ); } } Widget _icon(MControlPoint point, double iconSize){ var w = point.icon(height: iconSize); if(!point.isSuccess){ if(point.isFinish){ w = Image.asset(Assets.imagesIcCpFinishUncheck, height: iconSize,); }else{ w = Image.asset(Assets.imagesIcCpUncheck, height: iconSize); } } return w; } class _BottomPainter extends CustomPainter{ _BottomPainter(this.columCount, this.isBottom); final int columCount; final bool isBottom; final iconSize = _iconSize.wp; final rowSpace = _rowSpace.wp; final columSpace = _columSpace.wp; final pointWidth = _pointWidth.wp; @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color=const Color(0xff707070) ..strokeWidth=0.5.wp ..style=PaintingStyle.stroke; for(var i=0; i< columCount; i++){ final isOdd = i%2==1; if(isBottom){ if(!isOdd){ continue; } }else{ if(i==0){ continue; } if(isOdd){ continue; } } final path = Path(); var x = 0.0; var y = 0.0; x = iconSize/2 + columSpace + (columSpace + pointWidth) * i; if(!isBottom){ y=size.height; } path.moveTo(x, y); if(isBottom){ y+= size.height; }else{ y-= size.height-1; } path.lineTo(x, y); x -= columSpace+pointWidth; path.lineTo(x, y); if(isBottom){ y-= size.height; }else{ y+=size.height; } path.lineTo(x, y); canvas.drawPath(path, paint); } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) { return false; } } void dialogRoutePlanning(){ Get.dialog(Center( child: Obx((){ final model = Get.find (); return RoutePlanning( want: model.controlPointWantSequence, nextPlanPoint: model.nextPlanPoint, nextWantPoint: model.getNextWantPoint(0), onClick: (point){ model.nextPlanPoint=point; }); }) ), ); } void main(){ final want = []; for(var i=0; i< 15; i++){ want.add(MControlPoint() ..sn='$i' ..intId=Int64(i) ..isSuccess=i<8); } want[0].isStart=true; want.last.isFinish=true; runPreview(Scaffold( body: RoutePlanning( want: want, nextPlanPoint: want[2], nextWantPoint: want[3], onClick: (MControlPoint point) { debug('点击 ${point.snString}'); }, ), )); }