From 8a361dde5820a076fbd0ede6aa1bacbade811a35 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Mon, 3 Aug 2015 15:21:51 -0700 Subject: [PATCH] Teach event system about disposition and make 'consumed' disposition terminal This introduces the notion of event disposition and allows event targets (widgets and render objects) to consume events that should not be processed further. This is needed by the Switch component in the Drawer in the stocks example. The Switch is embedded in a DrawerItem. The Switch handles the gesture tap event to toggle its state and should handle pointer events to allow swiping and draw its own radial reaction. The DrawerItem also handles gesture taps to allow toggling the switch value when tapping anywhere on the drawer and to draw its own ink splash. When tapping on the switch, both the switch's render object and the DrawerItem's listener are in the event dispatch path. The Switch needs to signal in some fashion that it consumed the event so the DrawerItem does not also try to toggle the switch's state. --- .../sky/example/demo_launcher/lib/main.dart | 3 +- .../sky/example/fitness/lib/feed.dart | 6 ++-- .../sky/example/fitness/lib/meal.dart | 3 +- .../sky/example/fitness/lib/measurement.dart | 5 +-- .../sky/example/game/lib/sprite_box.dart | 5 +-- .../sky/example/mine_digger/lib/main.dart | 3 +- sky/packages/sky/example/rendering/flex.dart | 10 ++++-- .../sky/example/rendering/sector_layout.dart | 10 ++++-- .../example/rendering/solid_color_box.dart | 10 ++++-- .../sky/example/rendering/touch_demo.dart | 6 ++-- .../sky/example/stocks/lib/stock_home.dart | 6 ++-- .../example/stocks/lib/stock_settings.dart | 3 +- sky/packages/sky/example/widgets/piano.dart | 10 +++--- .../sky/example/widgets/styled_text.dart | 3 +- sky/packages/sky/lib/base/hit_test.dart | 8 ++++- sky/packages/sky/lib/editing/input.dart | 3 +- sky/packages/sky/lib/rendering/flex.dart | 2 ++ sky/packages/sky/lib/rendering/object.dart | 5 +-- .../sky/lib/rendering/sky_binding.dart | 17 +++++++--- sky/packages/sky/lib/widgets/basic.dart | 1 + sky/packages/sky/lib/widgets/button_base.dart | 9 +++-- sky/packages/sky/lib/widgets/dismissable.dart | 18 ++++++---- sky/packages/sky/lib/widgets/drawer.dart | 33 ++++++++++++++----- sky/packages/sky/lib/widgets/drawer_item.dart | 7 ++-- sky/packages/sky/lib/widgets/ink_well.dart | 7 ++-- sky/packages/sky/lib/widgets/radio.dart | 5 +-- sky/packages/sky/lib/widgets/scrollable.dart | 22 +++++++++---- sky/packages/sky/lib/widgets/switch.dart | 9 +++-- sky/packages/sky/lib/widgets/tabs.dart | 4 ++- sky/packages/sky/lib/widgets/toggleable.dart | 3 +- sky/packages/sky/lib/widgets/widget.dart | 29 +++++++++++----- 31 files changed, 182 insertions(+), 83 deletions(-) diff --git a/sky/packages/sky/example/demo_launcher/lib/main.dart b/sky/packages/sky/example/demo_launcher/lib/main.dart index c1458a24f2d..b2e550513c1 100644 --- a/sky/packages/sky/example/demo_launcher/lib/main.dart +++ b/sky/packages/sky/example/demo_launcher/lib/main.dart @@ -18,7 +18,7 @@ AssetBundle _initBundle() { final AssetBundle _bundle = _initBundle(); -void launch(String relativeUrl, String bundle) { +EventDisposition launch(String relativeUrl, String bundle) { // TODO(eseidel): This is a hack to keep non-skyx examples working for now: Uri productionBase = Uri.parse( 'https://domokit.github.io/example/demo_launcher/lib/main.dart'); @@ -42,6 +42,7 @@ void launch(String relativeUrl, String bundle) { } activity.startActivity(intent); + return EventDisposition.processed; } class SkyDemo { diff --git a/sky/packages/sky/example/fitness/lib/feed.dart b/sky/packages/sky/example/fitness/lib/feed.dart index c68e5ec316e..1bfc9104891 100644 --- a/sky/packages/sky/example/fitness/lib/feed.dart +++ b/sky/packages/sky/example/fitness/lib/feed.dart @@ -82,11 +82,12 @@ class FeedFragment extends StatefulComponent { bool _isShowingSnackBar = false; - void _handleFitnessModeChange(FitnessMode value) { + EventDisposition _handleFitnessModeChange(FitnessMode value) { setState(() { _fitnessMode = value; _drawerShowing = false; }); + return EventDisposition.processed; } Drawer buildDrawer() { @@ -137,9 +138,10 @@ class FeedFragment extends StatefulComponent { }); } - void _handleShowSettings() { + EventDisposition _handleShowSettings() { navigator.pop(); navigator.pushNamed('/settings'); + return EventDisposition.processed; } // TODO(jackson): We should be localizing diff --git a/sky/packages/sky/example/fitness/lib/meal.dart b/sky/packages/sky/example/fitness/lib/meal.dart index 0ce8ba9aafa..deaccd09dc1 100644 --- a/sky/packages/sky/example/fitness/lib/meal.dart +++ b/sky/packages/sky/example/fitness/lib/meal.dart @@ -56,9 +56,10 @@ class MealFragment extends StatefulComponent { String _description = ""; - void _handleSave() { + EventDisposition _handleSave() { onCreated(new Meal(when: new DateTime.now(), description: _description)); navigator.pop(); + return EventDisposition.processed; } Widget buildToolBar() { diff --git a/sky/packages/sky/example/fitness/lib/measurement.dart b/sky/packages/sky/example/fitness/lib/measurement.dart index eb202025b55..26b2cab9204 100644 --- a/sky/packages/sky/example/fitness/lib/measurement.dart +++ b/sky/packages/sky/example/fitness/lib/measurement.dart @@ -60,7 +60,7 @@ class MeasurementFragment extends StatefulComponent { String _weight = ""; String _errorMessage = null; - void _handleSave() { + EventDisposition _handleSave() { double parsedWeight; try { parsedWeight = double.parse(_weight); @@ -68,10 +68,11 @@ class MeasurementFragment extends StatefulComponent { setState(() { _errorMessage = "Save failed"; }); - return; + return EventDisposition.processed; } onCreated(new Measurement(when: new DateTime.now(), weight: parsedWeight)); navigator.pop(); + return EventDisposition.processed; } Widget buildToolBar() { diff --git a/sky/packages/sky/example/game/lib/sprite_box.dart b/sky/packages/sky/example/game/lib/sprite_box.dart index 52e2ba45c60..5312d251538 100644 --- a/sky/packages/sky/example/game/lib/sprite_box.dart +++ b/sky/packages/sky/example/game/lib/sprite_box.dart @@ -174,9 +174,9 @@ class SpriteBox extends RenderBox { } } - void handleEvent(Event event, _SpriteBoxHitTestEntry entry) { + EventDisposition handleEvent(Event event, _SpriteBoxHitTestEntry entry) { if (!attached) - return; + return EventDisposition.ignored; if (event is PointerEvent) { @@ -225,6 +225,7 @@ class SpriteBox extends RenderBox { } } } + return EventDisposition.ignored; } bool hitTest(HitTestResult result, { Point position }) { diff --git a/sky/packages/sky/example/mine_digger/lib/main.dart b/sky/packages/sky/example/mine_digger/lib/main.dart index ccedf360974..35a86651850 100644 --- a/sky/packages/sky/example/mine_digger/lib/main.dart +++ b/sky/packages/sky/example/mine_digger/lib/main.dart @@ -208,10 +208,11 @@ class MineDiggerApp extends App { ); } - void handleToolbarPointerDown(sky.PointerEvent event) { + EventDisposition handleToolbarPointerDown(sky.PointerEvent event) { setState(() { resetGame(); }); + return EventDisposition.processed; } // User action. The user uncovers the cell which can cause losing the game. diff --git a/sky/packages/sky/example/rendering/flex.dart b/sky/packages/sky/example/rendering/flex.dart index 702dbc7d0c3..55b2460040c 100644 --- a/sky/packages/sky/example/rendering/flex.dart +++ b/sky/packages/sky/example/rendering/flex.dart @@ -37,11 +37,15 @@ class RenderSolidColor extends RenderDecoratedBox { size = constraints.constrain(desiredSize); } - void handleEvent(sky.Event event, BoxHitTestEntry entry) { - if (event.type == 'pointerdown') + EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) { + if (event.type == 'pointerdown') { decoration = new BoxDecoration(backgroundColor: const sky.Color(0xFFFF0000)); - else if (event.type == 'pointerup') + return EventDisposition.processed; + } else if (event.type == 'pointerup') { decoration = new BoxDecoration(backgroundColor: backgroundColor); + return EventDisposition.processed; + } + return super.handleEvent(event, entry); } } diff --git a/sky/packages/sky/example/rendering/sector_layout.dart b/sky/packages/sky/example/rendering/sector_layout.dart index 52dd265b336..a91914c5076 100644 --- a/sky/packages/sky/example/rendering/sector_layout.dart +++ b/sky/packages/sky/example/rendering/sector_layout.dart @@ -517,11 +517,15 @@ class RenderSolidColor extends RenderDecoratedSector { deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta); } - void handleEvent(sky.Event event, HitTestEntry entry) { - if (event.type == 'pointerdown') + EventDisposition handleEvent(sky.Event event, HitTestEntry entry) { + if (event.type == 'pointerdown') { decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000)); - else if (event.type == 'pointerup') + return EventDisposition.processed; + } else if (event.type == 'pointerup') { decoration = new BoxDecoration(backgroundColor: backgroundColor); + return EventDisposition.processed; + } + return EventDisposition.ignored; } } diff --git a/sky/packages/sky/example/rendering/solid_color_box.dart b/sky/packages/sky/example/rendering/solid_color_box.dart index b6624c666fb..edca5473ee1 100644 --- a/sky/packages/sky/example/rendering/solid_color_box.dart +++ b/sky/packages/sky/example/rendering/solid_color_box.dart @@ -42,10 +42,14 @@ class RenderSolidColorBox extends RenderDecoratedBox { size = constraints.constrain(desiredSize); } - void handleEvent(sky.Event event, BoxHitTestEntry entry) { - if (event.type == 'pointerdown') + EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) { + if (event.type == 'pointerdown') { decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000)); - else if (event.type == 'pointerup') + return EventDisposition.processed; + } else if (event.type == 'pointerup') { decoration = new BoxDecoration(backgroundColor: backgroundColor); + return EventDisposition.processed; + } + return EventDisposition.ignored; } } diff --git a/sky/packages/sky/example/rendering/touch_demo.dart b/sky/packages/sky/example/rendering/touch_demo.dart index edd6f129f07..fcda20e5549 100644 --- a/sky/packages/sky/example/rendering/touch_demo.dart +++ b/sky/packages/sky/example/rendering/touch_demo.dart @@ -43,7 +43,7 @@ class RenderTouchDemo extends RenderBox { RenderTouchDemo(); - void handleEvent(sky.Event event, BoxHitTestEntry entry) { + EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) { if (event is sky.PointerEvent) { switch (event.type) { case 'pointerdown': @@ -60,8 +60,10 @@ class RenderTouchDemo extends RenderBox { dots[event.pointer].update(event); break; } + markNeedsPaint(); + return EventDisposition.processed; } - markNeedsPaint(); + return EventDisposition.processed; } void performLayout() { diff --git a/sky/packages/sky/example/stocks/lib/stock_home.dart b/sky/packages/sky/example/stocks/lib/stock_home.dart index f286e9d73aa..1aa50a1dfe5 100644 --- a/sky/packages/sky/example/stocks/lib/stock_home.dart +++ b/sky/packages/sky/example/stocks/lib/stock_home.dart @@ -103,12 +103,13 @@ class StockHome extends StatefulComponent { }); } - void _handleStockModeChange(StockMode value) { + EventDisposition _handleStockModeChange(StockMode value) { setState(() { stockMode = value; }); if (modeUpdater != null) modeUpdater(value); + return EventDisposition.processed; } Drawer buildDrawer() { @@ -156,9 +157,10 @@ class StockHome extends StatefulComponent { ); } - void _handleShowSettings() { + EventDisposition _handleShowSettings() { navigator.pop(); navigator.pushNamed('/settings'); + return EventDisposition.processed; } Widget buildToolBar() { diff --git a/sky/packages/sky/example/stocks/lib/stock_settings.dart b/sky/packages/sky/example/stocks/lib/stock_settings.dart index 27432b8890e..c3ddb8efbcc 100644 --- a/sky/packages/sky/example/stocks/lib/stock_settings.dart +++ b/sky/packages/sky/example/stocks/lib/stock_settings.dart @@ -39,7 +39,7 @@ class StockSettings extends StatefulComponent { sendUpdates(); } - void _confirmOptimismChange() { + EventDisposition _confirmOptimismChange() { switch (optimism) { case StockMode.optimistic: _handleOptimismChanged(false); @@ -70,6 +70,7 @@ class StockSettings extends StatefulComponent { }).then(_handleOptimismChanged); break; } + return EventDisposition.processed; } void sendUpdates() { diff --git a/sky/packages/sky/example/widgets/piano.dart b/sky/packages/sky/example/widgets/piano.dart index 658d63527e5..6625d12bca9 100644 --- a/sky/packages/sky/example/widgets/piano.dart +++ b/sky/packages/sky/example/widgets/piano.dart @@ -26,17 +26,19 @@ class Key { final String soundUrl; MediaPlayerProxy player; - void down() { + EventDisposition down() { if (player == null) - return; + return EventDisposition.ignored; player.ptr.seekTo(0); player.ptr.start(); + return EventDisposition.processed; } - void up() { + EventDisposition up() { if (player == null) - return; + return EventDisposition.ignored; player.ptr.pause(); + return EventDisposition.processed; } } diff --git a/sky/packages/sky/example/widgets/styled_text.dart b/sky/packages/sky/example/widgets/styled_text.dart index 5a639d143bd..9892a2ebeef 100644 --- a/sky/packages/sky/example/widgets/styled_text.dart +++ b/sky/packages/sky/example/widgets/styled_text.dart @@ -71,10 +71,11 @@ HAL: This mission is too important for me to allow you to jeopardize it.'''; ); } - void toggleToTextFunction(_) { + EventDisposition toggleToTextFunction(_) { setState(() { toText = (toText == toPlainText) ? toStyledText : toPlainText; }); + return EventDisposition.processed; } Widget build() { diff --git a/sky/packages/sky/lib/base/hit_test.dart b/sky/packages/sky/lib/base/hit_test.dart index 9707142760d..4d769a0464c 100644 --- a/sky/packages/sky/lib/base/hit_test.dart +++ b/sky/packages/sky/lib/base/hit_test.dart @@ -4,8 +4,14 @@ import 'dart:sky' as sky; +enum EventDisposition { + ignored, + processed, + consumed, +} + abstract class HitTestTarget { - void handleEvent(sky.Event event, HitTestEntry entry); + EventDisposition handleEvent(sky.Event event, HitTestEntry entry); } class HitTestEntry { diff --git a/sky/packages/sky/lib/editing/input.dart b/sky/packages/sky/lib/editing/input.dart index e9f806034e6..b63251ec455 100644 --- a/sky/packages/sky/lib/editing/input.dart +++ b/sky/packages/sky/lib/editing/input.dart @@ -107,7 +107,7 @@ class Input extends StatefulComponent { ); } - void focus(_) { + EventDisposition focus(_) { if (Focus.at(this)) { assert(_keyboardHandle.attached); _keyboardHandle.showByRequest(); @@ -115,6 +115,7 @@ class Input extends StatefulComponent { Focus.moveTo(this); // we'll get told to rebuild and we'll take care of the keyboard then } + return EventDisposition.processed; } void didUnmount() { diff --git a/sky/packages/sky/lib/rendering/flex.dart b/sky/packages/sky/lib/rendering/flex.dart index 8b61489dfb4..5bc9d0380b3 100644 --- a/sky/packages/sky/lib/rendering/flex.dart +++ b/sky/packages/sky/lib/rendering/flex.dart @@ -7,6 +7,8 @@ import 'dart:math' as math; import 'package:sky/rendering/box.dart'; import 'package:sky/rendering/object.dart'; +export 'package:sky/rendering/object.dart' show EventDisposition; + class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin { int flex; diff --git a/sky/packages/sky/lib/rendering/object.dart b/sky/packages/sky/lib/rendering/object.dart index 06fdf3c9cda..18ece8d4d70 100644 --- a/sky/packages/sky/lib/rendering/object.dart +++ b/sky/packages/sky/lib/rendering/object.dart @@ -12,7 +12,7 @@ import 'package:sky/base/node.dart'; import 'package:sky/base/scheduler.dart' as scheduler; export 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; -export 'package:sky/base/hit_test.dart' show HitTestTarget, HitTestEntry, HitTestResult; +export 'package:sky/base/hit_test.dart' show EventDisposition, HitTestTarget, HitTestEntry, HitTestResult; class ParentData { void detach() { @@ -415,9 +415,10 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { // EVENTS - void handleEvent(sky.Event event, HitTestEntry entry) { + EventDisposition handleEvent(sky.Event event, HitTestEntry entry) { // override this if you have a client, to hand it to the client // override this if you want to do anything with the event + return EventDisposition.ignored; } diff --git a/sky/packages/sky/lib/rendering/sky_binding.dart b/sky/packages/sky/lib/rendering/sky_binding.dart index 8eadf4b7c0e..7d4e4f98f59 100644 --- a/sky/packages/sky/lib/rendering/sky_binding.dart +++ b/sky/packages/sky/lib/rendering/sky_binding.dart @@ -109,7 +109,7 @@ class SkyBinding { return state; } - void _handlePointerEvent(sky.PointerEvent event) { + EventDisposition _handlePointerEvent(sky.PointerEvent event) { Point position = new Point(event.x, event.y); PointerState state = _getOrCreateStateForPointer(event, position); @@ -123,13 +123,20 @@ class SkyBinding { event.dy = position.y - state.lastPosition.y; state.lastPosition = position; - dispatchEvent(event, state.result); + return dispatchEvent(event, state.result); } - void dispatchEvent(sky.Event event, HitTestResult result) { + EventDisposition dispatchEvent(sky.Event event, HitTestResult result) { assert(result != null); - for (HitTestEntry entry in result.path.reversed) - entry.target.handleEvent(event, entry); + EventDisposition disposition = EventDisposition.ignored; + for (HitTestEntry entry in result.path.reversed) { + EventDisposition entryDisposition = entry.target.handleEvent(event, entry); + if (entryDisposition == EventDisposition.consumed) + return EventDisposition.consumed; + else if (entryDisposition == EventDisposition.processed) + disposition = EventDisposition.processed; + } + return disposition; } String toString() => 'Render Tree:\n${_renderView}'; diff --git a/sky/packages/sky/lib/widgets/basic.dart b/sky/packages/sky/lib/widgets/basic.dart index 30ee9577325..8763cd046e6 100644 --- a/sky/packages/sky/lib/widgets/basic.dart +++ b/sky/packages/sky/lib/widgets/basic.dart @@ -19,6 +19,7 @@ import 'package:sky/rendering/stack.dart'; import 'package:sky/widgets/default_text_style.dart'; import 'package:sky/widgets/widget.dart'; +export 'package:sky/base/hit_test.dart' show EventDisposition; export 'package:sky/rendering/box.dart' show BackgroundImage, BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims; export 'package:sky/rendering/flex.dart' show FlexDirection, FlexJustifyContent, FlexAlignItems; export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path; diff --git a/sky/packages/sky/lib/widgets/button_base.dart b/sky/packages/sky/lib/widgets/button_base.dart index aa3db426131..a6a378fd475 100644 --- a/sky/packages/sky/lib/widgets/button_base.dart +++ b/sky/packages/sky/lib/widgets/button_base.dart @@ -14,20 +14,23 @@ abstract class ButtonBase extends StatefulComponent { highlight = source.highlight; } - void _handlePointerDown(_) { + EventDisposition _handlePointerDown(_) { setState(() { highlight = true; }); + return EventDisposition.processed; } - void _handlePointerUp(_) { + EventDisposition _handlePointerUp(_) { setState(() { highlight = false; }); + return EventDisposition.processed; } - void _handlePointerCancel(_) { + EventDisposition _handlePointerCancel(_) { setState(() { highlight = false; }); + return EventDisposition.processed; } Widget build() { diff --git a/sky/packages/sky/lib/widgets/dismissable.dart b/sky/packages/sky/lib/widgets/dismissable.dart index b89787e4e1c..f3415ccd5f1 100644 --- a/sky/packages/sky/lib/widgets/dismissable.dart +++ b/sky/packages/sky/lib/widgets/dismissable.dart @@ -99,15 +99,16 @@ class Dismissable extends StatefulComponent { _maybeCallOnResized(); } - void _handlePointerDown(sky.PointerEvent event) { + EventDisposition _handlePointerDown(sky.PointerEvent event) { _dragUnderway = true; _dragX = 0.0; _fadePerformance.progress = 0.0; + return EventDisposition.processed; } - void _handlePointerMove(sky.PointerEvent event) { + EventDisposition _handlePointerMove(sky.PointerEvent event) { if (!_isActive) - return; + return EventDisposition.ignored; double oldDragX = _dragX; _dragX += event.dx; @@ -115,17 +116,19 @@ class Dismissable extends StatefulComponent { setState(() {}); // Rebuild to update the new drag endpoint. if (!_fadePerformance.isAnimating) _fadePerformance.progress = _dragX.abs() / (_size.width * _kDismissCardThreshold); + return EventDisposition.processed; } - void _handlePointerUpOrCancel(_) { + EventDisposition _handlePointerUpOrCancel(_) { if (!_isActive) - return; + return EventDisposition.ignored; _dragUnderway = false; if (_fadePerformance.isCompleted) _startResizePerformance(); else if (!_fadePerformance.isAnimating) _fadePerformance.reverse(); + return EventDisposition.processed; } bool _isHorizontalFlingGesture(sky.GestureEvent event) { @@ -134,15 +137,16 @@ class Dismissable extends StatefulComponent { return vx - vy > _kMinFlingVelocityDelta && vx > _kMinFlingVelocity; } - void _handleFlingStart(sky.GestureEvent event) { + EventDisposition _handleFlingStart(sky.GestureEvent event) { if (!_isActive) - return; + return EventDisposition.ignored; if (_isHorizontalFlingGesture(event)) { _dragUnderway = false; _dragX = event.velocityX.sign; _fadePerformance.fling(Direction.forward, velocity: event.velocityX.abs() * _kFlingVelocityScale); } + return EventDisposition.processed; } void _handleSizeChanged(Size newSize) { diff --git a/sky/packages/sky/lib/widgets/drawer.dart b/sky/packages/sky/lib/widgets/drawer.dart index 4537ee58d80..7cb8df0a0f8 100644 --- a/sky/packages/sky/lib/widgets/drawer.dart +++ b/sky/packages/sky/lib/widgets/drawer.dart @@ -139,33 +139,48 @@ class Drawer extends StatefulComponent { void _settle() { _isMostlyClosed ? _performance.reverse() : _performance.play(); } - void handleMaskTap(_) { _performance.reverse(); } + EventDisposition handleMaskTap(_) { + _performance.reverse(); + return EventDisposition.consumed; + } // TODO(mpcomplete): Figure out how to generalize these handlers on a // "PannableThingy" interface. - void handlePointerDown(_) { _performance.stop(); } + EventDisposition handlePointerDown(_) { + _performance.stop(); + return EventDisposition.processed; + } - void handlePointerMove(sky.PointerEvent event) { + EventDisposition handlePointerMove(sky.PointerEvent event) { if (_performance.isAnimating) - return; + return EventDisposition.ignored; _performance.progress += event.dx / _kWidth; + return EventDisposition.processed; } - void handlePointerUp(_) { - if (!_performance.isAnimating) + EventDisposition handlePointerUp(_) { + if (!_performance.isAnimating) { _settle(); + return EventDisposition.processed; + } + return EventDisposition.ignored; } - void handlePointerCancel(_) { - if (!_performance.isAnimating) + EventDisposition handlePointerCancel(_) { + if (!_performance.isAnimating) { _settle(); + return EventDisposition.processed; + } + return EventDisposition.ignored; } - void handleFlingStart(event) { + EventDisposition handleFlingStart(event) { if (event.velocityX.abs() >= _kMinFlingVelocity) { _performance.fling( event.velocityX < 0.0 ? Direction.reverse : Direction.forward, velocity: event.velocityX.abs() * _kFlingVelocityScale); + return EventDisposition.processed; } + return EventDisposition.ignored; } } diff --git a/sky/packages/sky/lib/widgets/drawer_item.dart b/sky/packages/sky/lib/widgets/drawer_item.dart index 1e179dc5718..4ac5b210640 100644 --- a/sky/packages/sky/lib/widgets/drawer_item.dart +++ b/sky/packages/sky/lib/widgets/drawer_item.dart @@ -14,13 +14,15 @@ import 'package:sky/widgets/ink_well.dart'; import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/widget.dart'; +typedef EventDisposition OnPressedFunction(); + class DrawerItem extends ButtonBase { DrawerItem({ Key key, this.icon, this.children, this.onPressed, this.selected: false }) : super(key: key); String icon; List children; - Function onPressed; + OnPressedFunction onPressed; bool selected; void syncFields(DrawerItem source) { @@ -82,7 +84,8 @@ class DrawerItem extends ButtonBase { return new Listener( onGestureTap: (_) { if (onPressed != null) - onPressed(); + return onPressed(); + return EventDisposition.ignored; }, child: new Container( height: 48.0, diff --git a/sky/packages/sky/lib/widgets/ink_well.dart b/sky/packages/sky/lib/widgets/ink_well.dart index 86139365e0c..6fc097f31e2 100644 --- a/sky/packages/sky/lib/widgets/ink_well.dart +++ b/sky/packages/sky/lib/widgets/ink_well.dart @@ -84,17 +84,18 @@ class RenderInkWell extends RenderProxyBox { final List _splashes = new List(); - void handleEvent(sky.Event event, BoxHitTestEntry entry) { + EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) { if (event is sky.GestureEvent) { switch (event.type) { case 'gesturetapdown': _startSplash(event.primaryPointer, entry.localPosition); - break; + return EventDisposition.processed; case 'gesturetap': _confirmSplash(event.primaryPointer); - break; + return EventDisposition.processed; } } + return EventDisposition.ignored; } void _startSplash(int pointer, Point position) { diff --git a/sky/packages/sky/lib/widgets/radio.dart b/sky/packages/sky/lib/widgets/radio.dart index 1a77d5120ce..abad4085d1e 100644 --- a/sky/packages/sky/lib/widgets/radio.dart +++ b/sky/packages/sky/lib/widgets/radio.dart @@ -68,12 +68,13 @@ class Radio extends ButtonBase { } ) ), - onGestureTap: _handleClick + onGestureTap: _handleTap ); } - void _handleClick(_) { + EventDisposition _handleTap(_) { onChanged(value); + return EventDisposition.consumed; } } diff --git a/sky/packages/sky/lib/widgets/scrollable.dart b/sky/packages/sky/lib/widgets/scrollable.dart index 0d0e84c3837..5f21205e030 100644 --- a/sky/packages/sky/lib/widgets/scrollable.dart +++ b/sky/packages/sky/lib/widgets/scrollable.dart @@ -181,20 +181,23 @@ abstract class Scrollable extends StatefulComponent { scrollTo(value); } - void _handlePointerDown(_) { + EventDisposition _handlePointerDown(_) { _stopToEndAnimation(); _stopToOffsetAnimation(); + return EventDisposition.processed; } - void _handleScrollUpdate(sky.GestureEvent event) { + EventDisposition _handleScrollUpdate(sky.GestureEvent event) { scrollBy(direction == ScrollDirection.horizontal ? event.dx : -event.dy); + return EventDisposition.processed; } - void _handleFlingStart(sky.GestureEvent event) { + EventDisposition _handleFlingStart(sky.GestureEvent event) { double eventVelocity = direction == ScrollDirection.horizontal ? -event.velocityX : -event.velocityY; _startToEndAnimation(velocity: _velocityForFlingGesture(eventVelocity)); + return EventDisposition.processed; } void _maybeSettleScrollOffset() { @@ -202,13 +205,20 @@ abstract class Scrollable extends StatefulComponent { settleScrollOffset(); } - void _handlePointerUpOrCancel(_) { _maybeSettleScrollOffset(); } + EventDisposition _handlePointerUpOrCancel(_) { + _maybeSettleScrollOffset(); + return EventDisposition.processed; + } - void _handleFlingCancel(sky.GestureEvent event) { _maybeSettleScrollOffset(); } + EventDisposition _handleFlingCancel(sky.GestureEvent event) { + _maybeSettleScrollOffset(); + return EventDisposition.processed; + } - void _handleWheel(sky.WheelEvent event) { + EventDisposition _handleWheel(sky.WheelEvent event) { scrollBy(-event.offsetY); + return EventDisposition.processed; } } diff --git a/sky/packages/sky/lib/widgets/switch.dart b/sky/packages/sky/lib/widgets/switch.dart index f943378fc50..969936fab2b 100644 --- a/sky/packages/sky/lib/widgets/switch.dart +++ b/sky/packages/sky/lib/widgets/switch.dart @@ -80,9 +80,12 @@ class _RenderSwitch extends RenderConstrainedBox { ..addListener(markNeedsPaint); } - void handleEvent(sky.Event event, BoxHitTestEntry entry) { - if (event is sky.GestureEvent && - event.type == 'gesturetap') _onChanged(!_value); + EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) { + if (event is sky.GestureEvent && event.type == 'gesturetap') { + _onChanged(!_value); + return EventDisposition.consumed; + } + return EventDisposition.ignored; } bool _value; diff --git a/sky/packages/sky/lib/widgets/tabs.dart b/sky/packages/sky/lib/widgets/tabs.dart index 669da4d0ffb..71f94bb1ea7 100644 --- a/sky/packages/sky/lib/widgets/tabs.dart +++ b/sky/packages/sky/lib/widgets/tabs.dart @@ -475,7 +475,7 @@ class TabBar extends Scrollable { .clamp(scrollBehavior.minScrollOffset, scrollBehavior.maxScrollOffset); } - void _handleTap(int tabIndex) { + EventDisposition _handleTap(int tabIndex) { if (tabIndex != selectedIndex) { if (_tabWidths != null) { if (isScrollable) @@ -484,7 +484,9 @@ class TabBar extends Scrollable { } if (onChanged != null) onChanged(tabIndex); + return EventDisposition.processed; } + return EventDisposition.ignored; } Widget _toTab(TabLabel label, int tabIndex) { diff --git a/sky/packages/sky/lib/widgets/toggleable.dart b/sky/packages/sky/lib/widgets/toggleable.dart index 0a02fde3a10..347089efd0b 100644 --- a/sky/packages/sky/lib/widgets/toggleable.dart +++ b/sky/packages/sky/lib/widgets/toggleable.dart @@ -57,8 +57,9 @@ abstract class Toggleable extends AnimatedComponent { super.syncFields(source); } - void _handleClick(sky.Event e) { + EventDisposition _handleClick(sky.Event e) { onChanged(!value); + return EventDisposition.consumed; } // Override these to draw yourself diff --git a/sky/packages/sky/lib/widgets/widget.dart b/sky/packages/sky/lib/widgets/widget.dart index dcab05d7437..2b4ba213071 100644 --- a/sky/packages/sky/lib/widgets/widget.dart +++ b/sky/packages/sky/lib/widgets/widget.dart @@ -13,6 +13,7 @@ import 'package:sky/rendering/box.dart'; import 'package:sky/rendering/object.dart'; import 'package:sky/rendering/sky_binding.dart'; +export 'package:sky/base/hit_test.dart' show EventDisposition; export 'package:sky/rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims; export 'package:sky/rendering/flex.dart' show FlexDirection; export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path; @@ -446,9 +447,9 @@ abstract class Inherited extends TagNode { } -typedef void GestureEventListener(sky.GestureEvent e); -typedef void PointerEventListener(sky.PointerEvent e); -typedef void EventListener(sky.Event e); +typedef EventDisposition GestureEventListener(sky.GestureEvent e); +typedef EventDisposition PointerEventListener(sky.PointerEvent e); +typedef EventDisposition EventListener(sky.Event e); class Listener extends TagNode { @@ -529,11 +530,12 @@ class Listener extends TagNode { return listeners; } - void _handleEvent(sky.Event e) { + EventDisposition _handleEvent(sky.Event e) { EventListener listener = listeners[e.type]; if (listener != null) { - listener(e); + return listener(e); } + return EventDisposition.ignored; } } @@ -1169,20 +1171,29 @@ class WidgetSkyBinding extends SkyBinding { assert(SkyBinding.instance is WidgetSkyBinding); } - void dispatchEvent(sky.Event event, HitTestResult result) { + EventDisposition dispatchEvent(sky.Event event, HitTestResult result) { assert(SkyBinding.instance == this); - super.dispatchEvent(event, result); + EventDisposition disposition = super.dispatchEvent(event, result); + if (disposition == EventDisposition.consumed) + return EventDisposition.consumed; for (HitTestEntry entry in result.path.reversed) { Widget target = RenderObjectWrapper._getMounted(entry.target); if (target == null) continue; RenderObject targetRoot = target.root; while (target != null && target.root == targetRoot) { - if (target is Listener) - target._handleEvent(event); + if (target is Listener) { + EventDisposition targetDisposition = target._handleEvent(event); + if (targetDisposition == EventDisposition.consumed) { + return targetDisposition; + } else if (targetDisposition == EventDisposition.processed) { + disposition = EventDisposition.processed; + } + } target = target._parent; } } + return disposition; } void beginFrame(double timeStamp) {