diff --git a/engine/core/events/GestureEvent.cpp b/engine/core/events/GestureEvent.cpp index cd56f26e135..bdcb538546f 100644 --- a/engine/core/events/GestureEvent.cpp +++ b/engine/core/events/GestureEvent.cpp @@ -67,6 +67,7 @@ GestureEvent::GestureEvent() GestureEvent::GestureEvent(const WebGestureEvent& event) : Event(stringForType(event.type), true, true) + , m_primaryPointer(event.primaryPointer) , m_x(event.x) , m_y(event.y) , m_dx(0) @@ -90,6 +91,7 @@ GestureEvent::GestureEvent(const WebGestureEvent& event) GestureEvent::GestureEvent(const AtomicString& type, const GestureEventInit& initializer) : Event(type, initializer) + , m_primaryPointer(initializer.primaryPointer) , m_x(initializer.x) , m_y(initializer.y) , m_dx(initializer.dx) diff --git a/engine/core/events/GestureEvent.h b/engine/core/events/GestureEvent.h index f67b1893658..e6c46c539c3 100644 --- a/engine/core/events/GestureEvent.h +++ b/engine/core/events/GestureEvent.h @@ -11,6 +11,7 @@ namespace blink { struct GestureEventInit : public EventInit { + int primaryPointer = 0; double x = 0; double y = 0; double dx = 0; @@ -38,6 +39,7 @@ public: ~GestureEvent() override; const AtomicString& interfaceName() const override; + int primaryPointer() const { return m_primaryPointer; } float x() const { return m_x; } float y() const { return m_y; } float dx() const { return m_dx; } @@ -50,6 +52,7 @@ private: explicit GestureEvent(const WebGestureEvent&); GestureEvent(const AtomicString& type, const GestureEventInit&); + int m_primaryPointer; float m_x; float m_y; float m_dx; diff --git a/engine/core/events/GestureEvent.idl b/engine/core/events/GestureEvent.idl index 37b9ed5ec1b..5d2f3060937 100644 --- a/engine/core/events/GestureEvent.idl +++ b/engine/core/events/GestureEvent.idl @@ -5,6 +5,7 @@ [ EventConstructor, ] interface GestureEvent : Event { + [InitializedByEventConstructor] readonly attribute long primaryPointer; [InitializedByEventConstructor] readonly attribute double x; [InitializedByEventConstructor] readonly attribute double y; [InitializedByEventConstructor] readonly attribute double dx; diff --git a/engine/public/platform/WebInputEvent.h b/engine/public/platform/WebInputEvent.h index c1e66cb276d..b63becb1ef8 100644 --- a/engine/public/platform/WebInputEvent.h +++ b/engine/public/platform/WebInputEvent.h @@ -268,6 +268,7 @@ public: class WebGestureEvent : public WebInputEvent { public: + int primaryPointer = 0; float x = 0; float y = 0; diff --git a/examples/stocks-fn/lib/stock_row.dart b/examples/stocks-fn/lib/stock_row.dart index 6f75dee5db7..94abba7adbe 100644 --- a/examples/stocks-fn/lib/stock_row.dart +++ b/examples/stocks-fn/lib/stock_row.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:sky/framework/components/material.dart'; +import 'package:sky/framework/components/ink_well.dart'; import 'package:sky/framework/fn.dart'; import 'package:sky/framework/theme/typography.dart' as typography; import 'stock_arrow.dart'; @@ -68,7 +68,7 @@ class StockRow extends Component { ) ]; - return new Material( + return new InkWell( style: _style, children: children ); diff --git a/framework/components/ink_splash.dart b/framework/components/ink_splash.dart index c768cb6fccc..928dcdbc2ac 100644 --- a/framework/components/ink_splash.dart +++ b/framework/components/ink_splash.dart @@ -2,45 +2,69 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import '../animation/animated_value.dart'; import '../animation/curves.dart'; import '../animation/generators.dart'; import '../fn.dart'; +import '../theme/view-configuration.dart' as config; import 'dart:async'; +import 'dart:math' as math; import 'dart:sky' as sky; -const double _kSplashSize = 400.0; -const double _kSplashDuration = 500.0; +const double _kSplashConfirmedDuration = 350.0; +const double _kSplashUnconfirmedDuration = config.kDefaultLongPressTimeout; -class SplashAnimation { - AnimationGenerator _animation; +double _getSplashTargetSize(sky.ClientRect rect, double x, double y) { + return 2.0 * math.max(math.max(x - rect.left, rect.right - x), + math.max(y - rect.top, rect.bottom - y)); +} + +class SplashController { + final int pointer; + Stream get onStyleChanged => _styleStream; + + final AnimatedValue _size = new AnimatedValue(0.0); double _offsetX; double _offsetY; + double _targetSize; + Stream _styleStream; - Stream _styleChanged; + void start() { + _size.animateTo(_targetSize, _kSplashUnconfirmedDuration, curve: easeOut); + } - Stream get onStyleChanged => _styleChanged; + void confirm() { + double fractionRemaining = (_targetSize - _size.value) / _targetSize; + double duration = fractionRemaining * _kSplashConfirmedDuration; + if (duration <= 0.0) + return; + _size.animateTo(_targetSize, duration, curve: easeOut); + } - void cancel() => _animation.cancel(); + void cancel() { + _size.stop(); + } - SplashAnimation(sky.ClientRect rect, double x, double y, - { Function onDone }) + SplashController(sky.ClientRect rect, double x, double y, + { this.pointer, Function onDone }) : _offsetX = x - rect.left, - _offsetY = y - rect.top { + _offsetY = y - rect.top, + _targetSize = _getSplashTargetSize(rect, x, y) { - _animation = new AnimationGenerator( - duration:_kSplashDuration, - end: _kSplashSize, - curve: easeOut, - onDone: onDone); + _styleStream = _size.onValueChanged.map((p) { + if (p == _targetSize) { + onDone(); + } + return ''' + top: ${_offsetY - p/2}px; + left: ${_offsetX - p/2}px; + width: ${p}px; + height: ${p}px; + border-radius: ${p}px; + opacity: ${1.0 - (p / _targetSize)};'''; + }); - _styleChanged = _animation.onTick.map((p) => ''' - top: ${_offsetY - p/2}px; - left: ${_offsetX - p/2}px; - width: ${p}px; - height: ${p}px; - border-radius: ${p}px; - opacity: ${1.0 - (p / _kSplashSize)}; - '''); + start(); } } diff --git a/framework/components/ink_well.dart b/framework/components/ink_well.dart new file mode 100644 index 00000000000..601e3c75102 --- /dev/null +++ b/framework/components/ink_well.dart @@ -0,0 +1,85 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../fn.dart'; +import 'dart:collection'; +import 'dart:sky' as sky; +import 'ink_splash.dart'; + +class InkWell extends Component { + LinkedHashSet _splashes; + + Style style; + String inlineStyle; + List children; + + InkWell({ Object key, this.style, this.inlineStyle, this.children }) + : super(key: key); + + Node build() { + List childrenIncludingSplashes = []; + + if (_splashes != null) { + childrenIncludingSplashes.addAll( + _splashes.map((s) => new InkSplash(s.onStyleChanged))); + } + + if (children != null) + childrenIncludingSplashes.addAll(children); + + return new EventTarget( + new Container( + style: style, + inlineStyle: inlineStyle, + children: childrenIncludingSplashes), + onGestureTapDown: _startSplash, + onGestureTap: _confirmSplash + ); + } + + sky.ClientRect _getBoundingRect() => (getRoot() as sky.Element).getBoundingClientRect(); + + void _startSplash(sky.GestureEvent event) { + setState(() { + if (_splashes == null) + _splashes = new LinkedHashSet(); + var splash; + splash = new SplashController(_getBoundingRect(), event.x, event.y, + pointer: event.primaryPointer, + onDone: () { _splashDone(splash); }); + _splashes.add(splash); + }); + } + + void _confirmSplash(sky.GestureEvent event) { + if (_splashes == null) + return; + _splashes.where((splash) => splash.pointer == event.primaryPointer) + .forEach((splash) { splash.confirm(); }); + } + + void _cancelSplashes(sky.Event event) { + if (_splashes == null) + return; + setState(() { + var splashes = _splashes; + _splashes = null; + splashes.forEach((s) { s.cancel(); }); + }); + } + + void didUnmount() { + _cancelSplashes(null); + } + + void _splashDone(SplashController splash) { + if (_splashes == null) + return; + setState(() { + _splashes.remove(splash); + if (_splashes.length == 0) + _splashes = null; + }); + } +} diff --git a/framework/components/material.dart b/framework/components/material.dart index 12ee60724a5..b335785eae7 100644 --- a/framework/components/material.dart +++ b/framework/components/material.dart @@ -4,9 +4,7 @@ import '../fn.dart'; import '../theme/shadows.dart'; -import 'dart:collection'; -import 'dart:sky' as sky; -import 'ink_splash.dart'; +import 'ink_well.dart'; class Material extends Component { static final List