| Index: sky/sdk/lib/framework/components2/ink_well.dart
|
| diff --git a/sky/sdk/lib/framework/components2/ink_well.dart b/sky/sdk/lib/framework/components2/ink_well.dart
|
| index 05120acddb1ba1a992190e5d6c830b52239a2c00..914ebce536d84621540f6672c85ffc7c6b5cf435 100644
|
| --- a/sky/sdk/lib/framework/components2/ink_well.dart
|
| +++ b/sky/sdk/lib/framework/components2/ink_well.dart
|
| @@ -2,125 +2,126 @@
|
| // 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 '../fn2.dart';
|
| +import '../rendering/box.dart';
|
| import '../rendering/flex.dart';
|
| +import '../rendering/object.dart';
|
| +import '../theme/view_configuration.dart' as config;
|
| +import 'dart:async';
|
| import 'dart:collection';
|
| +import 'dart:math' as math;
|
| import 'dart:sky' as sky;
|
| -// import 'ink_splash.dart';
|
| -import 'scrollable.dart';
|
|
|
| -class InkWell extends Component implements ScrollClient {
|
| +const int _kSplashInitialOpacity = 0x80;
|
| +const double _kSplashInitialSize = 0.0;
|
| +const double _kSplashConfirmedDuration = 350.0;
|
| +const double _kSplashUnconfirmedDuration = config.kDefaultLongPressTimeout;
|
| +const double _kSplashInitialDelay = 0.0; // we could delay initially in case the user scrolls
|
|
|
| - InkWell({ Object key, this.children }) : super(key: key);
|
| +double _getSplashTargetSize(Size bounds, Point position) {
|
| + return 2.0 * math.max(math.max(position.x, bounds.width - position.x),
|
| + math.max(position.y, bounds.height - position.y));
|
| +}
|
|
|
| - // static final Style _containmentStyleHack = new Style('''
|
| - // align-items: center;
|
| - // transform: translateX(0);''');
|
| +class InkSplash {
|
| + final int pointer;
|
| + final Point position;
|
| + final RenderInkWell well;
|
|
|
| - // LinkedHashSet<SplashController> _splashes;
|
| + double _targetRadius;
|
| + AnimatedValue _radius;
|
|
|
| - List<UINode> children;
|
| + InkSplash(this.pointer, this.position, this.well) {
|
| + _targetRadius = _getSplashTargetSize(well.size, position);
|
| + _radius = new AnimatedValue(_kSplashInitialSize, onChange: _handleRadiusChange);
|
| + _radius.animateTo(_targetRadius, _kSplashUnconfirmedDuration,
|
| + curve: easeOut, initialDelay: _kSplashInitialDelay);
|
| + }
|
|
|
| - // InkWell({ Object key, this.inlineStyle, this.children })
|
| - // : super(key: key) {
|
| - // onDidUnmount(() {
|
| - // _cancelSplashes(null);
|
| - // });
|
| - // }
|
| + void confirm() {
|
| + double fractionRemaining = (_targetRadius - _radius.value) / _targetRadius;
|
| + double duration = fractionRemaining * _kSplashConfirmedDuration;
|
| + if (duration <= 0.0)
|
| + return;
|
| + _radius.animateTo(_targetRadius, duration, curve: easeOut);
|
| + }
|
|
|
| - UINode build() {
|
| - return new FlexContainer(
|
| - direction: FlexDirection.horizontal,
|
| - justifyContent: FlexJustifyContent.center,
|
| - children: children);
|
| - // List<UINode> childrenIncludingSplashes = [];
|
| -
|
| - // if (_splashes != null) {
|
| - // childrenIncludingSplashes.addAll(
|
| - // _splashes.map((s) => new InkSplash(s.onStyleChanged)));
|
| - // }
|
| -
|
| - // if (children != null)
|
| - // childrenIncludingSplashes.addAll(children);
|
| -
|
| - // return new EventListenerNode(
|
| - // new FlexContainer(
|
| - // direction: FlexDirection.horizontal,
|
| - // style: _containmentStyleHack,
|
| - // inlineStyle: inlineStyle,
|
| - // children: childrenIncludingSplashes),
|
| - // onGestureTapDown: _startSplash,
|
| - // onGestureTap: _confirmSplash
|
| - // );
|
| + void _handleRadiusChange() {
|
| + if (_radius.value == _targetRadius)
|
| + well._splashes.remove(this);
|
| + well.markNeedsPaint();
|
| }
|
|
|
| - // void _startSplash(sky.GestureEvent event) {
|
| - // setState(() {
|
| - // if (_splashes == null)
|
| - // _splashes = new LinkedHashSet<SplashController>();
|
| - // var splash;
|
| - // var root = getRoot();
|
| - // splash = new SplashController(root.rect, event.x, event.y,
|
| - // pointer: event.primaryPointer,
|
| - // onDone: () { _splashDone(splash); });
|
| - // _splashes.add(splash);
|
| - // UINode node = parent;
|
| - // while (node != null) {
|
| - // if (node is Scrollable)
|
| - // node.registerScrollClient(this);
|
| - // node = node.parent;
|
| - // }
|
| - // });
|
| - // }
|
| -
|
| - bool ancestorScrolled(Scrollable ancestor) {
|
| - // _abortSplashes();
|
| - return false;
|
| + void paint(RenderObjectDisplayList canvas) {
|
| + int opacity = (_kSplashInitialOpacity * (1.0 - (_radius.value / _targetRadius))).floor();
|
| + sky.Paint paint = new sky.Paint()..color = new sky.Color(opacity << 24);
|
| + canvas.drawCircle(position.x, position.y, _radius.value, paint);
|
| }
|
| +}
|
|
|
| - // void handleRemoved() {
|
| - // UINode node = parent;
|
| - // while (node != null) {
|
| - // if (node is Scrollable)
|
| - // node.unregisterScrollClient(this);
|
| - // node = node.parent;
|
| - // }
|
| - // super.handleRemoved();
|
| - // }
|
| -
|
| - // void _confirmSplash(sky.GestureEvent event) {
|
| - // if (_splashes == null)
|
| - // return;
|
| - // _splashes.where((splash) => splash.pointer == event.primaryPointer)
|
| - // .forEach((splash) { splash.confirm(); });
|
| - // }
|
| -
|
| - // void _abortSplashes() {
|
| - // if (_splashes == null)
|
| - // return;
|
| - // setState(() {
|
| - // _splashes.forEach((s) { s.abort(); });
|
| - // });
|
| - // }
|
| -
|
| - // void _cancelSplashes(sky.Event event) {
|
| - // if (_splashes == null)
|
| - // return;
|
| - // setState(() {
|
| - // var splashes = _splashes;
|
| - // _splashes = null;
|
| - // splashes.forEach((s) { s.cancel(); });
|
| - // });
|
| - // }
|
| -
|
| - // void _splashDone(SplashController splash) {
|
| - // if (_splashes == null)
|
| - // return;
|
| - // setState(() {
|
| - // _splashes.remove(splash);
|
| - // if (_splashes.length == 0)
|
| - // _splashes = null;
|
| - // });
|
| - // }
|
| +class RenderInkWell extends RenderProxyBox {
|
| + final List<InkSplash> _splashes = new List<InkSplash>();
|
| +
|
| + RenderInkWell({ RenderBox child }) : super(child);
|
| +
|
| + void handleEvent(sky.Event event) {
|
| + switch (event.type) {
|
| + case 'gesturetapdown':
|
| + // TODO(abarth): We should position the splash at the location of the tap.
|
| + _startSplash(event.primaryPointer, new Point(size.width / 2.0, size.height / 2.0));
|
| + break;
|
| + case 'gesturetap':
|
| + _confirmSplash(event.primaryPointer);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void _startSplash(int pointer, Point position) {
|
| + _splashes.add(new InkSplash(pointer, position, this));
|
| + markNeedsPaint();
|
| + }
|
|
|
| + void _confirmSplash(int pointer) {
|
| + _splashes.where((splash) => splash.pointer == pointer)
|
| + .forEach((splash) { splash.confirm(); });
|
| + markNeedsPaint();
|
| + }
|
| +
|
| + void paint(RenderObjectDisplayList canvas) {
|
| + if (!_splashes.isEmpty) {
|
| + canvas.save();
|
| + canvas.clipRect(new Rect.fromSize(size));
|
| + for (InkSplash splash in _splashes)
|
| + splash.paint(canvas);
|
| + canvas.restore();
|
| + }
|
| + super.paint(canvas);
|
| + }
|
| +}
|
| +
|
| +class InkWellWrapper extends OneChildRenderObjectWrapper {
|
| + RenderInkWell root;
|
| +
|
| + InkWellWrapper({ UINode child, Object key })
|
| + : super(child: child, key: key);
|
| +
|
| + RenderInkWell createNode() => new RenderInkWell();
|
| +}
|
| +
|
| +class InkWell extends Component {
|
| + List<UINode> children;
|
| +
|
| + InkWell({ Object key, this.children }) : super(key: key);
|
| +
|
| + UINode build() {
|
| + return new InkWellWrapper(
|
| + child: new FlexContainer(
|
| + direction: FlexDirection.horizontal,
|
| + justifyContent: FlexJustifyContent.center,
|
| + children: children
|
| + )
|
| + );
|
| + }
|
| }
|
|
|