Refactor TiltPresetPicker to use a circular D-pad for tilt controls; enhance gesture handling for smoother input
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
+90
-18
@@ -349,40 +349,112 @@ class _SparkleShapePicker extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Preset controls for feeding an external tilt stream.
|
||||
/// Circular D-pad control for feeding the external tilt stream.
|
||||
class _TiltPresetPicker extends StatelessWidget {
|
||||
const _TiltPresetPicker({required this.onChanged});
|
||||
|
||||
final ValueChanged<Offset> onChanged;
|
||||
|
||||
static const double _tiltAmount = 0.7;
|
||||
static const double _deadZoneRatio = 0.18;
|
||||
|
||||
void _emitDragTilt(Offset localPosition, Size size) {
|
||||
final Offset center = Offset(size.width / 2.0, size.height / 2.0);
|
||||
final double radius = size.shortestSide / 2.0;
|
||||
final Offset delta = localPosition - center;
|
||||
final double distance = delta.distance;
|
||||
|
||||
if (radius <= 0 || distance <= radius * _deadZoneRatio) {
|
||||
onChanged(Offset.zero);
|
||||
return;
|
||||
}
|
||||
|
||||
Offset normalized = delta / radius;
|
||||
final double normalizedDistance = normalized.distance;
|
||||
if (normalizedDistance > 1.0) {
|
||||
normalized = normalized / normalizedDistance;
|
||||
}
|
||||
|
||||
onChanged(normalized * _tiltAmount);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: 176,
|
||||
height: 176,
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
final Size size = constraints.biggest;
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPanDown: (DragDownDetails details) {
|
||||
_emitDragTilt(details.localPosition, size);
|
||||
},
|
||||
onPanUpdate: (DragUpdateDetails details) {
|
||||
_emitDragTilt(details.localPosition, size);
|
||||
},
|
||||
onPanEnd: (_) => onChanged(Offset.zero),
|
||||
onPanCancel: () => onChanged(Offset.zero),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: FilledButton.tonalIcon(
|
||||
onPressed: () => onChanged(const Offset(-0.7, 0.0)),
|
||||
icon: const Icon(Icons.keyboard_double_arrow_left),
|
||||
label: const Text('Tilt Left'),
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: IconButton.filledTonal(
|
||||
tooltip: 'Tilt Up',
|
||||
onPressed: () =>
|
||||
onChanged(const Offset(0.0, -_tiltAmount)),
|
||||
icon: const Icon(Icons.keyboard_arrow_up),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: IconButton.filledTonal(
|
||||
tooltip: 'Tilt Left',
|
||||
onPressed: () =>
|
||||
onChanged(const Offset(-_tiltAmount, 0.0)),
|
||||
icon: const Icon(Icons.keyboard_arrow_left),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: IconButton.outlined(
|
||||
tooltip: 'Center Tilt',
|
||||
onPressed: () => onChanged(Offset.zero),
|
||||
icon: const Icon(Icons.restart_alt),
|
||||
label: const Text('Center'),
|
||||
icon: const Icon(Icons.adjust),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: FilledButton.tonalIcon(
|
||||
onPressed: () => onChanged(const Offset(0.7, 0.0)),
|
||||
icon: const Icon(Icons.keyboard_double_arrow_right),
|
||||
label: const Text('Tilt Right'),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: IconButton.filledTonal(
|
||||
tooltip: 'Tilt Right',
|
||||
onPressed: () =>
|
||||
onChanged(const Offset(_tiltAmount, 0.0)),
|
||||
icon: const Icon(Icons.keyboard_arrow_right),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: IconButton.filledTonal(
|
||||
tooltip: 'Tilt Down',
|
||||
onPressed: () =>
|
||||
onChanged(const Offset(0.0, _tiltAmount)),
|
||||
icon: const Icon(Icons.keyboard_arrow_down),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user