Commit 2cbd050f authored by Tim Traversy's avatar Tim Traversy Committed by Michael Goderbauer

Adding horizontal and vertical scale parameter to ScaleUpdateDetails. (#27752)

parent ed4e3da3
...@@ -49,30 +49,67 @@ class ScaleStartDetails { ...@@ -49,30 +49,67 @@ class ScaleStartDetails {
class ScaleUpdateDetails { class ScaleUpdateDetails {
/// Creates details for [GestureScaleUpdateCallback]. /// Creates details for [GestureScaleUpdateCallback].
/// ///
/// The [focalPoint], [scale], [rotation] arguments must not be null. The [scale] /// The [focalPoint], [scale], [horizontalScale], [verticalScale], [rotation]
/// arguments must not be null. The [scale], [horizontalScale], and [verticalScale]
/// argument must be greater than or equal to zero. /// argument must be greater than or equal to zero.
ScaleUpdateDetails({ ScaleUpdateDetails({
this.focalPoint = Offset.zero, this.focalPoint = Offset.zero,
this.scale = 1.0, this.scale = 1.0,
this.horizontalScale = 1.0,
this.verticalScale = 1.0,
this.rotation = 0.0, this.rotation = 0.0,
}) : assert(focalPoint != null), }) : assert(focalPoint != null),
assert(scale != null && scale >= 0.0), assert(scale != null && scale >= 0.0),
assert(horizontalScale != null && horizontalScale >= 0.0),
assert(verticalScale != null && verticalScale >= 0.0),
assert(rotation != null); assert(rotation != null);
/// The focal point of the pointers in contact with the screen. Reported in /// The focal point of the pointers in contact with the screen.
/// global coordinates. ///
/// Reported in global coordinates.
final Offset focalPoint; final Offset focalPoint;
/// The scale implied by the pointers in contact with the screen. A value /// The scale implied by the average distance between the pointers in contact
/// greater than or equal to zero. /// with the screen.
///
/// This value must be greater than or equal to zero.
///
/// See also:
///
/// * [horizontalScale], which is the scale along the horizontal axis.
/// * [verticalScale], which is the scale along the vertical axis.
final double scale; final double scale;
/// The scale implied by the average distance along the horizontal axis
/// between the pointers in contact with the screen.
///
/// This value must be greater than or equal to zero.
///
/// See also:
///
/// * [scale], which is the general scale implied by the pointers.
/// * [verticalScale], which is the scale along the vertical axis.
final double horizontalScale;
/// The scale implied by the average distance along the vertical axis
/// between the pointers in contact with the screen.
///
/// This value must be greater than or equal to zero.
///
/// See also:
///
/// * [scale], which is the general scale implied by the pointers.
/// * [horizontalScale], which is the scale along the horizontal axis.
final double verticalScale;
/// The angle implied by the first two pointers to enter in contact with /// The angle implied by the first two pointers to enter in contact with
/// the screen. Expressed in radians. /// the screen.
///
/// Expressed in radians.
final double rotation; final double rotation;
@override @override
String toString() => 'ScaleUpdateDetails(focalPoint: $focalPoint, scale: $scale, rotation: $rotation)'; String toString() => 'ScaleUpdateDetails(focalPoint: $focalPoint, scale: $scale, horizontalScale: $horizontalScale, verticalScale: $verticalScale, rotation: $rotation)';
} }
/// Details for [GestureScaleEndCallback]. /// Details for [GestureScaleEndCallback].
...@@ -165,6 +202,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -165,6 +202,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
Offset _currentFocalPoint; Offset _currentFocalPoint;
double _initialSpan; double _initialSpan;
double _currentSpan; double _currentSpan;
double _initialHorizontalSpan;
double _currentHorizontalSpan;
double _initialVerticalSpan;
double _currentVerticalSpan;
_LineBetweenPointers _initialLine; _LineBetweenPointers _initialLine;
_LineBetweenPointers _currentLine; _LineBetweenPointers _currentLine;
Map<int, Offset> _pointerLocations; Map<int, Offset> _pointerLocations;
...@@ -173,6 +214,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -173,6 +214,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0; double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0;
double get _horizontalScaleFactor => _initialHorizontalSpan > 0.0 ? _currentHorizontalSpan / _initialHorizontalSpan : 1.0;
double get _verticalScaleFactor => _initialVerticalSpan > 0.0 ? _currentVerticalSpan / _initialVerticalSpan : 1.0;
double _computeRotationFactor() { double _computeRotationFactor() {
if (_initialLine == null || _currentLine == null) { if (_initialLine == null || _currentLine == null) {
return 0.0; return 0.0;
...@@ -201,6 +246,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -201,6 +246,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
_state = _ScaleState.possible; _state = _ScaleState.possible;
_initialSpan = 0.0; _initialSpan = 0.0;
_currentSpan = 0.0; _currentSpan = 0.0;
_initialHorizontalSpan = 0.0;
_currentHorizontalSpan = 0.0;
_initialVerticalSpan = 0.0;
_currentVerticalSpan = 0.0;
_pointerLocations = <int, Offset>{}; _pointerLocations = <int, Offset>{};
_pointerQueue = <int>[]; _pointerQueue = <int>[];
} }
...@@ -246,11 +295,20 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -246,11 +295,20 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
focalPoint += _pointerLocations[pointer]; focalPoint += _pointerLocations[pointer];
_currentFocalPoint = count > 0 ? focalPoint / count.toDouble() : Offset.zero; _currentFocalPoint = count > 0 ? focalPoint / count.toDouble() : Offset.zero;
// Span is the average deviation from focal point // Span is the average deviation from focal point. Horizontal and vertical
// spans are the average deviations from the focal point's horizontal and
// vertical coordinates, respectively.
double totalDeviation = 0.0; double totalDeviation = 0.0;
for (int pointer in _pointerLocations.keys) double totalHorizontalDeviation = 0.0;
double totalVerticalDeviation = 0.0;
for (int pointer in _pointerLocations.keys) {
totalDeviation += (_currentFocalPoint - _pointerLocations[pointer]).distance; totalDeviation += (_currentFocalPoint - _pointerLocations[pointer]).distance;
totalHorizontalDeviation += (_currentFocalPoint.dx - _pointerLocations[pointer].dx).abs();
totalVerticalDeviation += (_currentFocalPoint.dy - _pointerLocations[pointer].dy).abs();
}
_currentSpan = count > 0 ? totalDeviation / count : 0.0; _currentSpan = count > 0 ? totalDeviation / count : 0.0;
_currentHorizontalSpan = count > 0 ? totalHorizontalDeviation / count : 0.0;
_currentVerticalSpan = count > 0 ? totalVerticalDeviation / count : 0.0;
} }
/// Updates [_initialLine] and [_currentLine] accordingly to the situation of /// Updates [_initialLine] and [_currentLine] accordingly to the situation of
...@@ -269,7 +327,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -269,7 +327,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
pointerStartId: _pointerQueue[0], pointerStartId: _pointerQueue[0],
pointerStartLocation: _pointerLocations[_pointerQueue[0]], pointerStartLocation: _pointerLocations[_pointerQueue[0]],
pointerEndId: _pointerQueue[1], pointerEndId: _pointerQueue[1],
pointerEndLocation: _pointerLocations[ _pointerQueue[1]] pointerEndLocation: _pointerLocations[_pointerQueue[1]]
); );
} else { } else {
/// A new rotation process is on the way, set the [_initialLine] /// A new rotation process is on the way, set the [_initialLine]
...@@ -277,7 +335,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -277,7 +335,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
pointerStartId: _pointerQueue[0], pointerStartId: _pointerQueue[0],
pointerStartLocation: _pointerLocations[_pointerQueue[0]], pointerStartLocation: _pointerLocations[_pointerQueue[0]],
pointerEndId: _pointerQueue[1], pointerEndId: _pointerQueue[1],
pointerEndLocation: _pointerLocations[ _pointerQueue[1]] pointerEndLocation: _pointerLocations[_pointerQueue[1]]
); );
_currentLine = null; _currentLine = null;
} }
...@@ -287,6 +345,8 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -287,6 +345,8 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
_initialFocalPoint = _currentFocalPoint; _initialFocalPoint = _currentFocalPoint;
_initialSpan = _currentSpan; _initialSpan = _currentSpan;
_initialLine = _currentLine; _initialLine = _currentLine;
_initialHorizontalSpan = _currentHorizontalSpan;
_initialVerticalSpan = _currentVerticalSpan;
if (_state == _ScaleState.started) { if (_state == _ScaleState.started) {
if (onEnd != null) { if (onEnd != null) {
final VelocityTracker tracker = _velocityTrackers[pointer]; final VelocityTracker tracker = _velocityTrackers[pointer];
...@@ -327,7 +387,15 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -327,7 +387,15 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
} }
if (_state == _ScaleState.started && onUpdate != null) if (_state == _ScaleState.started && onUpdate != null)
invokeCallback<void>('onUpdate', () => onUpdate(ScaleUpdateDetails(scale: _scaleFactor, focalPoint: _currentFocalPoint, rotation: _computeRotationFactor()))); invokeCallback<void>('onUpdate', () {
onUpdate(ScaleUpdateDetails(
scale: _scaleFactor,
horizontalScale: _horizontalScaleFactor,
verticalScale: _verticalScaleFactor,
focalPoint: _currentFocalPoint,
rotation: _computeRotationFactor(),
));
});
} }
void _dispatchOnStartCallbackIfNeeded() { void _dispatchOnStartCallbackIfNeeded() {
......
...@@ -24,8 +24,12 @@ void main() { ...@@ -24,8 +24,12 @@ void main() {
}; };
double updatedScale; double updatedScale;
double updatedHorizontalScale;
double updatedVerticalScale;
scale.onUpdate = (ScaleUpdateDetails details) { scale.onUpdate = (ScaleUpdateDetails details) {
updatedScale = details.scale; updatedScale = details.scale;
updatedHorizontalScale = details.horizontalScale;
updatedVerticalScale = details.verticalScale;
updatedFocalPoint = details.focalPoint; updatedFocalPoint = details.focalPoint;
}; };
...@@ -91,18 +95,35 @@ void main() { ...@@ -91,18 +95,35 @@ void main() {
expect(updatedFocalPoint, const Offset(10.0, 20.0)); expect(updatedFocalPoint, const Offset(10.0, 20.0));
updatedFocalPoint = null; updatedFocalPoint = null;
expect(updatedScale, 2.0); expect(updatedScale, 2.0);
expect(updatedHorizontalScale, 2.0);
expect(updatedVerticalScale, 2.0);
updatedScale = null; updatedScale = null;
updatedHorizontalScale = null;
updatedVerticalScale = null;
expect(didEndScale, isFalse); expect(didEndScale, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
// Zoom out // Zoom out
tester.route(pointer2.move(const Offset(15.0, 25.0))); tester.route(pointer2.move(const Offset(15.0, 25.0)));
expect(updatedFocalPoint, const Offset(17.5, 27.5)); expect(updatedFocalPoint, const Offset(17.5, 27.5));
updatedFocalPoint = null;
expect(updatedScale, 0.5); expect(updatedScale, 0.5);
updatedScale = null; expect(updatedHorizontalScale, 0.5);
expect(updatedVerticalScale, 0.5);
expect(didTap, isFalse); expect(didTap, isFalse);
// Horizontal scaling
tester.route(pointer2.move(const Offset(0.0, 20.0)));
expect(updatedHorizontalScale, 2.0);
expect(updatedVerticalScale, 1.0);
// Vertical scaling
tester.route(pointer2.move(const Offset(10.0, 10.0)));
expect(updatedHorizontalScale, 1.0);
expect(updatedVerticalScale, 2.0);
tester.route(pointer2.move(const Offset(15.0, 25.0)));
updatedFocalPoint = null;
updatedScale = null;
// Three-finger scaling // Three-finger scaling
final TestPointer pointer3 = TestPointer(3); final TestPointer pointer3 = TestPointer(3);
final PointerDownEvent down3 = pointer3.down(const Offset(25.0, 35.0)); final PointerDownEvent down3 = pointer3.down(const Offset(25.0, 35.0));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment