Commit 267404d4 authored by James Robinson's avatar James Robinson

Merge pull request #436 from jamesr/event_disposition

Teach event system about disposition and make 'consumed' disposition …
parents 198b6242 53163f8b
......@@ -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 {
......
......@@ -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
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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 }) {
......
......@@ -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.
......
......@@ -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);
}
}
......
......@@ -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;
}
}
......
......@@ -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;
}
}
......@@ -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() {
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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;
}
}
......
......@@ -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() {
......
......@@ -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 {
......
......@@ -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() {
......
......@@ -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<RenderBox> {
int flex;
......
......@@ -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;
}
......
......@@ -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}';
......
......@@ -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;
......
......@@ -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() {
......
......@@ -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) {
......
......@@ -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;
}
}
......@@ -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<Widget> 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,
......
......@@ -84,17 +84,18 @@ class RenderInkWell extends RenderProxyBox {
final List<InkSplash> _splashes = new List<InkSplash>();
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) {
......
......@@ -68,12 +68,13 @@ class Radio extends ButtonBase {
}
)
),
onGestureTap: _handleClick
onGestureTap: _handleTap
);
}
void _handleClick(_) {
EventDisposition _handleTap(_) {
onChanged(value);
return EventDisposition.consumed;
}
}
......@@ -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;
}
}
......
......@@ -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;
......
......@@ -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) {
......
......@@ -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
......
......@@ -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) {
......
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