marco.pms.mobile/lib/helpers/widgets/my_dotted_line.dart
Vaibhav Surve 99902e743c Flutter application
- Created generated_plugin_registrant.cc and generated_plugin_registrant.h to manage plugin registration.
- Added generated_plugins.cmake for plugin configuration in CMake.
- Implemented CMakeLists.txt for the Windows runner, defining build settings and dependencies.
- Created Runner.rc for application resources including versioning and icons.
- Developed flutter_window.cpp and flutter_window.h to manage the Flutter window lifecycle.
- Implemented main.cpp as the entry point for the Windows application.
- Added resource.h for resource definitions.
- Included app icon in resources.
- Created runner.exe.manifest for application settings.
- Developed utils.cpp and utils.h for console management and command line argument handling.
- Implemented win32_window.cpp and win32_window.h for high DPI-aware window management.
2025-04-17 12:30:38 +05:30

202 lines
5.8 KiB
Dart

// ignore_for_file: empty_catches
import 'dart:ui';
import 'package:flutter/material.dart';
bool _isEmpty(double? d) {
return d == null || d == 0.0;
}
class MyDottedLineCorner {
final double leftTopCorner;
final double rightTopCorner;
final double rightBottomCorner;
final double leftBottomCorner;
const MyDottedLineCorner({
this.leftTopCorner = 0,
this.rightTopCorner = 0,
this.rightBottomCorner = 0,
this.leftBottomCorner = 0,
});
MyDottedLineCorner.all(double radius)
: leftTopCorner = radius,
rightTopCorner = radius,
rightBottomCorner = radius,
leftBottomCorner = radius;
}
class MyDottedLine extends StatefulWidget {
final Color color;
final double? height;
final double? width;
final double strokeWidth;
final double dottedLength;
final double space;
final MyDottedLineCorner? corner;
final Widget? child;
MyDottedLine({
super.key,
this.color = Colors.black,
this.height,
this.width,
this.dottedLength = 5.0,
this.space = 3.0,
this.strokeWidth = 1.0,
this.corner,
this.child,
}) {
assert(width != null || height != null || child != null);
}
@override
_MyDottedLineState createState() => _MyDottedLineState();
}
class _MyDottedLineState extends State<MyDottedLine> {
double? childWidth;
double? childHeight;
GlobalKey childKey = GlobalKey();
@override
Widget build(BuildContext context) {
if (_isEmpty(widget.width) && _isEmpty(widget.height) && widget.child == null) {
return Container();
}
if (widget.child != null) {
tryToGetChildSize();
List<Widget> children = [];
children.add(Container(
clipBehavior: widget.corner == null ? Clip.none : Clip.antiAlias,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(widget.corner != null ? widget.corner!.leftTopCorner : 0.0),
topRight: Radius.circular(widget.corner != null ? widget.corner!.rightTopCorner : 0.0),
bottomLeft: Radius.circular(widget.corner != null ? widget.corner!.leftBottomCorner : 0.0),
bottomRight: Radius.circular(widget.corner != null ? widget.corner!.rightBottomCorner : 0.0),
),
),
key: childKey,
child: widget.child,
));
if (childWidth != null && childHeight != null) {
children.add(dashPath(width: childWidth, height: childHeight));
}
return Stack(
children: children,
);
} else {
return dashPath(width: widget.width, height: widget.height);
}
}
void tryToGetChildSize() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
try {
RenderBox box = childKey.currentContext!.findRenderObject() as RenderBox;
double tempWidth = box.size.width;
double tempHeight = box.size.height;
bool needUpdate = tempWidth != childWidth || tempHeight != childHeight;
if (needUpdate) {
setState(() {
childWidth = tempWidth;
childHeight = tempHeight;
});
}
} catch (e) {}
});
}
CustomPaint dashPath({double? width, double? height}) {
return CustomPaint(
size: Size(_isEmpty(width) ? widget.strokeWidth : width!, _isEmpty(height) ? widget.strokeWidth : height!),
foregroundPainter: _DottedLinePainter()
..color = widget.color
..dottedLength = widget.dottedLength
..space = widget.space
..strokeWidth = widget.strokeWidth
..corner = widget.corner
..isShape = !_isEmpty(height) && !_isEmpty(width),
);
}
}
class _DottedLinePainter extends CustomPainter {
late Color color;
double? dottedLength;
double? space;
late double strokeWidth;
late bool isShape;
MyDottedLineCorner? corner;
Radius topLeft = Radius.zero;
Radius topRight = Radius.zero;
Radius bottomRight = Radius.zero;
Radius bottomLeft = Radius.zero;
@override
void paint(Canvas canvas, Size size) {
var isHorizontal = size.width > size.height;
final Paint paint = Paint()
..isAntiAlias = true
..filterQuality = FilterQuality.high
..color = color
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth;
if (!isShape) {
double length = isHorizontal ? size.width : size.height;
double count = (length) / (dottedLength! + space!);
if (count < 2.0) return;
var startOffset = Offset(0, 0);
for (int i = 0; i < count.toInt(); i++) {
canvas.drawLine(startOffset, startOffset.translate((isHorizontal ? dottedLength! : 0), (isHorizontal ? 0 : dottedLength!)), paint);
startOffset = startOffset.translate((isHorizontal ? (dottedLength! + space!) : 0), (isHorizontal ? 0 : (dottedLength! + space!)));
}
} else {
Path path = Path();
path.addRRect(RRect.fromLTRBAndCorners(
0,
0,
size.width,
size.height,
topLeft: Radius.circular(corner != null ? corner!.leftTopCorner : 0.0),
topRight: Radius.circular(corner != null ? corner!.rightTopCorner : 0.0),
bottomLeft: Radius.circular(corner != null ? corner!.leftBottomCorner : 0.0),
bottomRight: Radius.circular(corner != null ? corner!.rightBottomCorner : 0.0),
));
Path draw = buildDashPath(path, dottedLength, space);
canvas.drawPath(draw, paint);
}
}
Path buildDashPath(Path path, double? dottedLength, double? space) {
final Path r = Path();
for (PathMetric metric in path.computeMetrics()) {
double start = 0.0;
while (start < metric.length) {
double end = start + dottedLength!;
r.addPath(metric.extractPath(start, end), Offset.zero);
start = end + space!;
}
}
return r;
}
@override
bool shouldRepaint(_DottedLinePainter oldDelegate) {
return true;
}
}