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 {
class ScaleUpdateDetails {
/// 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.
ScaleUpdateDetails({
this.focalPoint = Offset.zero,
this.scale = 1.0,
this.horizontalScale = 1.0,
this.verticalScale = 1.0,
this.rotation = 0.0,
}) : assert(focalPoint != null),
assert(scale != null && scale >= 0.0),
assert(horizontalScale != null && horizontalScale >= 0.0),
assert(verticalScale != null && verticalScale >= 0.0),
assert(rotation != null);
/// The focal point of the pointers in contact with the screen. Reported in
/// global coordinates.
/// The focal point of the pointers in contact with the screen.
///
/// Reported in global coordinates.
final Offset focalPoint;
/// The scale implied by the pointers in contact with the screen. A value
/// greater than or equal to zero.
/// The scale implied by the average distance between the pointers in contact
/// 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;
/// 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 screen. Expressed in radians.
/// the screen.
///
/// Expressed in radians.
final double rotation;
@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].
......@@ -165,6 +202,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
Offset _currentFocalPoint;
double _initialSpan;
double _currentSpan;
double _initialHorizontalSpan;
double _currentHorizontalSpan;
double _initialVerticalSpan;
double _currentVerticalSpan;
_LineBetweenPointers _initialLine;
_LineBetweenPointers _currentLine;
Map<int, Offset> _pointerLocations;
......@@ -173,6 +214,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
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() {
if (_initialLine == null || _currentLine == null) {
return 0.0;
......@@ -201,6 +246,10 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
_state = _ScaleState.possible;
_initialSpan = 0.0;
_currentSpan = 0.0;
_initialHorizontalSpan = 0.0;
_currentHorizontalSpan = 0.0;
_initialVerticalSpan = 0.0;
_currentVerticalSpan = 0.0;
_pointerLocations = <int, Offset>{};
_pointerQueue = <int>[];
}
......@@ -246,11 +295,20 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
focalPoint += _pointerLocations[pointer];
_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;
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;
totalHorizontalDeviation += (_currentFocalPoint.dx - _pointerLocations[pointer].dx).abs();
totalVerticalDeviation += (_currentFocalPoint.dy - _pointerLocations[pointer].dy).abs();
}
_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
......@@ -269,7 +327,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
pointerStartId: _pointerQueue[0],
pointerStartLocation: _pointerLocations[_pointerQueue[0]],
pointerEndId: _pointerQueue[1],
pointerEndLocation: _pointerLocations[ _pointerQueue[1]]
pointerEndLocation: _pointerLocations[_pointerQueue[1]]
);
} else {
/// A new rotation process is on the way, set the [_initialLine]
......@@ -277,7 +335,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
pointerStartId: _pointerQueue[0],
pointerStartLocation: _pointerLocations[_pointerQueue[0]],
pointerEndId: _pointerQueue[1],
pointerEndLocation: _pointerLocations[ _pointerQueue[1]]
pointerEndLocation: _pointerLocations[_pointerQueue[1]]
);
_currentLine = null;
}
......@@ -287,6 +345,8 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
_initialFocalPoint = _currentFocalPoint;
_initialSpan = _currentSpan;
_initialLine = _currentLine;
_initialHorizontalSpan = _currentHorizontalSpan;
_initialVerticalSpan = _currentVerticalSpan;
if (_state == _ScaleState.started) {
if (onEnd != null) {
final VelocityTracker tracker = _velocityTrackers[pointer];
......@@ -327,7 +387,15 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
}
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() {
......
......@@ -24,8 +24,12 @@ void main() {
};
double updatedScale;
double updatedHorizontalScale;
double updatedVerticalScale;
scale.onUpdate = (ScaleUpdateDetails details) {
updatedScale = details.scale;
updatedHorizontalScale = details.horizontalScale;
updatedVerticalScale = details.verticalScale;
updatedFocalPoint = details.focalPoint;
};
......@@ -91,18 +95,35 @@ void main() {
expect(updatedFocalPoint, const Offset(10.0, 20.0));
updatedFocalPoint = null;
expect(updatedScale, 2.0);
expect(updatedHorizontalScale, 2.0);
expect(updatedVerticalScale, 2.0);
updatedScale = null;
updatedHorizontalScale = null;
updatedVerticalScale = null;
expect(didEndScale, isFalse);
expect(didTap, isFalse);
// Zoom out
tester.route(pointer2.move(const Offset(15.0, 25.0)));
expect(updatedFocalPoint, const Offset(17.5, 27.5));
updatedFocalPoint = null;
expect(updatedScale, 0.5);
updatedScale = null;
expect(updatedHorizontalScale, 0.5);
expect(updatedVerticalScale, 0.5);
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
final TestPointer pointer3 = TestPointer(3);
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