Skip to content

Instantly share code, notes, and snippets.

@paplorinc
Created January 18, 2023 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paplorinc/eba33bd71b33d6b805627b53c57037cc to your computer and use it in GitHub Desktop.
Save paplorinc/eba33bd71b33d6b805627b53c57037cc to your computer and use it in GitHub Desktop.
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
void main() => runApp(const SticksApp());
class SticksApp extends StatelessWidget {
const SticksApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: SticksWidget()),
);
}
}
class SticksWidget extends StatefulWidget {
const SticksWidget({super.key});
@override
State<SticksWidget> createState() => SticksWidgetState();
}
class SticksWidgetState extends State<SticksWidget> {
var data = '\u{0}\u{1}\u{2}\u{3}\u{4}\u{5}\u{6}\u{7}\u{8}\u{9} - secret message';
@override
Widget build(BuildContext context) {
var width = MediaQuery.of(context).size.width;
return Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
TextFormField(
initialValue: data,
autovalidateMode: AutovalidateMode.always,
validator: (value) => isValidInput(value) ? null : "Only ASCII chars accepted!",
onChanged: (value) {
if (isValidInput(value)) {
setState(() {
data = value;
});
}
},
),
const SizedBox(height: 5),
CustomPaint(
size: Size(width, 100),
painter: SticksPainter(data),
),
],
),
);
}
bool isValidInput(String? value) => (value ?? '').codeUnits.every((c) => c >= 0 && c <= 255);
}
class SticksPainter extends CustomPainter {
final String data;
SticksPainter(this.data);
@override
void paint(Canvas canvas, Size size) {
var width = 15.0;
var height = 20.0;
var offset = const Offset(0.0, 0.0);
for (var c in data.codeUnits) {
drawChar(canvas, c, offset, width, height);
var textPainter = TextPainter(
text: TextSpan(text: c.toString().padLeft(3, ' '), style: const TextStyle(fontSize: 8, color: Colors.black)),
textDirection: TextDirection.ltr,
maxLines: 1,
textAlign: TextAlign.center,
)..layout();
textPainter.paint(canvas, offset.translate(0, height + 3));
offset = offset.translate(width * 1.3, 0);
if (offset.dx + width > size.width) {
offset = Offset(0, offset.dy + height * 2);
}
}
}
void drawChar(Canvas canvas, int value, Offset offset, double width, double height) {
var bounds = Rect.fromLTWH(offset.dx, offset.dy, width, height);
canvas.drawLine(bounds.topCenter, bounds.bottomCenter, getPaint());
value.toRadixString(2).padLeft(8, '0').characters.map((v) => v == "1").forEachIndexed((i, shouldDraw) {
if (shouldDraw) {
Offset from, to;
/*@formatter:off*/
switch (i) {
case 0: from = bounds.topLeft; to = bounds.topCenter; break;
case 1: from = bounds.topCenter; to = bounds.topRight; break;
case 2: from = bounds.topLeft; to = bounds.center; break;
case 3: from = bounds.topRight; to = bounds.center; break;
case 4: from = bounds.center; to = bounds.bottomLeft; break;
case 5: from = bounds.center; to = bounds.bottomRight; break;
case 6: from = bounds.bottomLeft; to = bounds.bottomCenter; break;
case 7: from = bounds.bottomCenter; to = bounds.bottomRight; break;
default: throw UnsupportedError(i.toString());
}
/*@formatter:on*/
canvas.drawLine(from, to, getPaint());
}
});
}
Paint getPaint() {
return Paint()
..color = Colors.black
..strokeWidth = 2
..strokeCap = StrokeCap.round
..strokeJoin = StrokeJoin.round;
}
@override
bool shouldRepaint(_) => true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment