-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdouble_value_box.dart
118 lines (97 loc) · 3.88 KB
/
double_value_box.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import 'package:flutter/material.dart';
import 'package:format/format.dart' as fmt;
import 'package:boatinstrument/boatinstrument_controller.dart';
abstract class SpeedBox extends DoubleValueBox {
const SpeedBox(super.config, super.title, super.path, {super.key}) : super(minLen: 1);
@override
double convert(double value) {
return config.controller.speedToDisplay(value);
}
@override
String units(double value) {
return config.controller.speedUnits.unit;
}
}
abstract class DoubleValueBox extends BoxWidget {
final String title;
final String path;
final int precision;
final int minLen;
final double? minValue;
final double? maxValue;
final bool angle;
final bool relativeAngle;
final bool smoothing;
final bool portStarboard;
final bool dataTimeout;
const DoubleValueBox(super.config, this.title, this.path, {this.precision = 1, this.minLen = 2, this.minValue, this.maxValue, this.angle = false, this.relativeAngle = false, this.smoothing = true, this.portStarboard = false, this.dataTimeout = true, super.key});
@override
State<DoubleValueBox> createState() => DoubleValueBoxState();
double extractValue(Update update) {
return (update.value as num).toDouble();
}
double convert(double value);
String units(double value);
}
class DoubleValueBoxState<T extends DoubleValueBox> extends State<T> {
double? value;
double? displayValue;
@override
void initState() {
super.initState();
widget.config.controller.configure(onUpdate: processUpdates, paths: {widget.path}, dataTimeout: widget.dataTimeout);
}
@override
Widget build(BuildContext context) {
if(widget.config.editMode) {
displayValue = 12.3;
}
String valueText = (displayValue == null) ?
'-' :
fmt.format('{:${widget.minLen+(widget.precision > 0?1:0)+widget.precision}.${widget.precision}f}', widget.portStarboard ? displayValue!.abs() : displayValue!);
TextStyle style = Theme.of(context).textTheme.titleMedium!.copyWith(height: 1.0);
const double pad = 5.0;
double fontSize = maxFontSize(valueText, style,
widget.config.constraints.maxHeight - style.fontSize! - (3 * pad),
widget.config.constraints.maxWidth - (2 * pad));
return Column(mainAxisAlignment: MainAxisAlignment.start, children: [
Row(children: [Padding(padding: const EdgeInsets.only(top: pad, left: pad), child: Text('${widget.title} ${widget.units(value??0)} ${widget.portStarboard ? val2PS(displayValue??0):''}', style: style))]),
// We need to disable the device text scaling as this interferes with our text scaling.
Expanded(child: Center(child: Padding(padding: const EdgeInsets.all(pad),
child: Text(valueText, textScaler: TextScaler.noScaling,
style: style.copyWith(fontSize: fontSize, color: widget.portStarboard ? widget.config.controller.val2PSColor(context, displayValue??0) : null)))))
]);
}
processUpdates(List<Update>? updates) {
if(updates == null) {
value = displayValue = null;
} else {
try {
double next = widget.extractValue(updates[0]);
if(widget.smoothing) {
if (widget.angle) {
value = averageAngle(value ?? next, next,
smooth: widget.config.controller.valueSmoothing,
relative: widget.relativeAngle);
} else {
value = averageDouble(value ?? next, next,
smooth: widget.config.controller.valueSmoothing);
}
} else {
value = next;
}
if ((widget.minValue != null && value! < widget.minValue!) ||
(widget.maxValue != null && value! > widget.maxValue!)) {
displayValue = null;
} else {
displayValue = widget.convert(value!);
}
} catch (e) {
widget.config.controller.l.e("Error converting $updates", error: e);
}
}
if(mounted) {
setState(() {});
}
}
}