Commit 14c9a2c7 authored by Kris Giesing's avatar Kris Giesing

Merge remote-tracking branch 'upstream/master' into arena_sweep

parents 30213814 2032d3e4
...@@ -2,15 +2,22 @@ Flutter Examples ...@@ -2,15 +2,22 @@ Flutter Examples
================ ================
This directory contains several examples of using Flutter. Each of these is an This directory contains several examples of using Flutter. Each of these is an
individual Dart application package. If you wish to run them with `sky_tool` individual Dart application package.
then you will want to run `pub get` inside their directory before running
`./packages/sky/sky_tool start`.
1. *Hello, world.* The [hello world app](hello_world) is a basic app that shows To run a sample with the `flutter` tool, run `pub get` inside its directory,
then run `flutter start`. (See the
[getting started guide](https://flutter.github.io/getting-started/) to install
the `flutter` tool.)
Available examples include:
- *Hello, world.* The [hello world app](hello_world) is a basic app that shows
the text "hello, world." the text "hello, world."
2. *Stocks.* The [stocks app](stocks) is an example of a typical mobile app - *Stocks.* The [stocks app](stocks) is an example of a typical mobile app
built using Flutter. The app shows a list of all the stocks in the NASDAQ. built using Flutter. The app shows a list of all the stocks in the NASDAQ.
3. *Widgets.* The [widgets app](widgets) contains a number of Flutter widgets so - *Widgets.* The [widget apps](widgets) demonstrate a number of Flutter widgets
you can experiment with them in a simple container. so you can experiment with them in a simple container. There is no main.dart
in this directory because each file is a standalone sample. To run a
particular file, use `flutter start -t filename.dart`.
...@@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; ...@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:skysprites/skysprites.dart'; import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() { AssetBundle _initBundle() {
if (rootBundle != null) if (rootBundle != null)
......
...@@ -5,7 +5,7 @@ import 'dart:math' as math; ...@@ -5,7 +5,7 @@ import 'dart:math' as math;
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:skysprites/skysprites.dart'; import 'package:flutter_sprites/flutter_sprites.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
part 'custom_actions.dart'; part 'custom_actions.dart';
......
...@@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; ...@@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:skysprites/skysprites.dart'; import 'package:flutter_sprites/flutter_sprites.dart';
import 'game_demo.dart'; import 'game_demo.dart';
......
...@@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; ...@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:skysprites/skysprites.dart'; import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() { AssetBundle _initBundle() {
if (rootBundle != null) if (rootBundle != null)
......
...@@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; ...@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:skysprites/skysprites.dart'; import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() { AssetBundle _initBundle() {
if (rootBundle != null) if (rootBundle != null)
......
...@@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; ...@@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:skysprites/skysprites.dart'; import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() { AssetBundle _initBundle() {
if (rootBundle != null) if (rootBundle != null)
......
...@@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; ...@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:skysprites/skysprites.dart'; import 'package:flutter_sprites/flutter_sprites.dart';
AssetBundle _initBundle() { AssetBundle _initBundle() {
if (rootBundle != null) if (rootBundle != null)
......
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'dart:math'; import 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
...@@ -85,7 +85,7 @@ class MineDiggerState extends State<MineDigger> { ...@@ -85,7 +85,7 @@ class MineDiggerState extends State<MineDigger> {
} }
PointerEventListener _pointerDownHandlerFor(int posX, int posY) { PointerEventListener _pointerDownHandlerFor(int posX, int posY) {
return (ui.PointerEvent event) { return (PointerInputEvent event) {
if (event.buttons == 1) { if (event.buttons == 1) {
probe(posX, posY); probe(posX, posY);
} else if (event.buttons == 2) { } else if (event.buttons == 2) {
...@@ -190,7 +190,7 @@ class MineDiggerState extends State<MineDigger> { ...@@ -190,7 +190,7 @@ class MineDiggerState extends State<MineDigger> {
); );
} }
void handleToolbarPointerDown(ui.PointerEvent event) { void handleToolbarPointerDown(PointerInputEvent event) {
setState(() { setState(() {
resetGame(); resetGame();
}); });
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart';
const double kTwoPi = 2 * math.PI; const double kTwoPi = 2 * math.PI;
...@@ -518,7 +518,7 @@ class RenderSolidColor extends RenderDecoratedSector { ...@@ -518,7 +518,7 @@ class RenderSolidColor extends RenderDecoratedSector {
deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta); deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
} }
void handleEvent(ui.Event event, HitTestEntry entry) { void handleEvent(InputEvent event, HitTestEntry entry) {
if (event.type == 'pointerdown') if (event.type == 'pointerdown')
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000)); decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
else if (event.type == 'pointerup') else if (event.type == 'pointerup')
......
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart';
class RenderSolidColorBox extends RenderDecoratedBox { class RenderSolidColorBox extends RenderDecoratedBox {
final Size desiredSize; final Size desiredSize;
...@@ -42,7 +41,7 @@ class RenderSolidColorBox extends RenderDecoratedBox { ...@@ -42,7 +41,7 @@ class RenderSolidColorBox extends RenderDecoratedBox {
size = constraints.constrain(desiredSize); size = constraints.constrain(desiredSize);
} }
void handleEvent(ui.Event event, BoxHitTestEntry entry) { void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown') if (event.type == 'pointerdown')
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000)); decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
else if (event.type == 'pointerup') else if (event.type == 'pointerup')
......
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart';
// Material design colors. :p // Material design colors. :p
List<Color> kColors = [ List<Color> kColors = [
...@@ -24,7 +23,7 @@ class Dot { ...@@ -24,7 +23,7 @@ class Dot {
Dot({ Color color }) : _paint = new Paint()..color = color; Dot({ Color color }) : _paint = new Paint()..color = color;
void update(ui.PointerEvent event) { void update(PointerInputEvent event) {
position = new Point(event.x, event.y); position = new Point(event.x, event.y);
radius = 5 + (95 * event.pressure); radius = 5 + (95 * event.pressure);
} }
...@@ -39,8 +38,8 @@ class RenderTouchDemo extends RenderBox { ...@@ -39,8 +38,8 @@ class RenderTouchDemo extends RenderBox {
RenderTouchDemo(); RenderTouchDemo();
void handleEvent(ui.Event event, BoxHitTestEntry entry) { void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event is ui.PointerEvent) { if (event is PointerInputEvent) {
switch (event.type) { switch (event.type) {
case 'pointerdown': case 'pointerdown':
Color color = kColors[event.pointer.remainder(kColors.length)]; Color color = kColors[event.pointer.remainder(kColors.length)];
......
Small examples of the Flutter widget framework
==============================================
To run these, open a terminal in this directory and use the following
command:
```bash
pub global activate flutter
flutter start --checked -t foo.dart
```
...where `foo.dart` is the file you want to run.
// 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 'package:intl/intl.dart';
import 'package:flutter/material.dart';
class ScrollbarApp extends StatefulComponent {
ScrollbarApp({ this.navigator });
final NavigatorState navigator;
ScrollbarAppState createState() => new ScrollbarAppState();
}
class ScrollbarAppState extends State<ScrollbarApp> {
final int _itemCount = 20;
final double _itemExtent = 50.0;
final ScrollbarPainter _scrollbarPainter = new ScrollbarPainter();
Widget _buildMenu(BuildContext context) {
NumberFormat dd = new NumberFormat("00", "en_US");
return new ScrollableList<int>(
items: new List<int>.generate(_itemCount, (int i) => i),
itemExtent: _itemExtent,
itemBuilder: (BuildContext _, int i) => new Text('Item ${dd.format(i)}', style: Theme.of(context).text.title),
scrollableListPainter: _scrollbarPainter
);
}
Widget build(BuildContext context) {
Widget scrollable = new Container(
margin: new EdgeDims.symmetric(horizontal: 6.0), // TODO(hansmuller) 6.0 should be based on _kScrollbarThumbWidth
child: new Center(
shrinkWrap: ShrinkWrap.both,
child: new Container(
width: 80.0,
height: _itemExtent * 5.0,
child: _buildMenu(context)
)
)
);
return new Scaffold(
toolBar: new ToolBar(center: new Text('Scrollbar Demo')),
body: new Container(
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
padding: new EdgeDims.all(12.0),
child: new Center(child: new Card(child: scrollable))
)
);
}
}
void main() {
runApp(new MaterialApp(
title: 'ScrollbarApp',
theme: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.blue,
accentColor: Colors.redAccent[200]
),
routes: {
'/': (RouteArguments args) => new ScrollbarApp(navigator: args.navigator),
}
));
}
...@@ -8,6 +8,7 @@ library gestures; ...@@ -8,6 +8,7 @@ library gestures;
export 'src/gestures/arena.dart'; export 'src/gestures/arena.dart';
export 'src/gestures/constants.dart'; export 'src/gestures/constants.dart';
export 'src/gestures/drag.dart'; export 'src/gestures/drag.dart';
export 'src/gestures/events.dart';
export 'src/gestures/long_press.dart'; export 'src/gestures/long_press.dart';
export 'src/gestures/pointer_router.dart'; export 'src/gestures/pointer_router.dart';
export 'src/gestures/recognizer.dart'; export 'src/gestures/recognizer.dart';
......
...@@ -33,6 +33,7 @@ export 'src/material/progress_indicator.dart'; ...@@ -33,6 +33,7 @@ export 'src/material/progress_indicator.dart';
export 'src/material/radio.dart'; export 'src/material/radio.dart';
export 'src/material/raised_button.dart'; export 'src/material/raised_button.dart';
export 'src/material/scaffold.dart'; export 'src/material/scaffold.dart';
export 'src/material/scrollbar_painter.dart';
export 'src/material/shadows.dart'; export 'src/material/shadows.dart';
export 'src/material/snack_bar.dart'; export 'src/material/snack_bar.dart';
export 'src/material/switch.dart'; export 'src/material/switch.dart';
......
...@@ -7,6 +7,7 @@ import 'dart:ui' as ui; ...@@ -7,6 +7,7 @@ import 'dart:ui' as ui;
import 'arena.dart'; import 'arena.dart';
import 'recognizer.dart'; import 'recognizer.dart';
import 'constants.dart'; import 'constants.dart';
import 'events.dart';
enum DragState { enum DragState {
ready, ready,
...@@ -24,7 +25,7 @@ typedef void GesturePanEndCallback(ui.Offset velocity); ...@@ -24,7 +25,7 @@ typedef void GesturePanEndCallback(ui.Offset velocity);
typedef void _GesturePolymorphicUpdateCallback<T>(T delta); typedef void _GesturePolymorphicUpdateCallback<T>(T delta);
int _eventTime(ui.PointerEvent event) => (event.timeStamp * 1000.0).toInt(); // microseconds int _eventTime(PointerInputEvent event) => (event.timeStamp * 1000.0).toInt(); // microseconds
bool _isFlingGesture(ui.GestureVelocity velocity) { bool _isFlingGesture(ui.GestureVelocity velocity) {
double velocitySquared = velocity.x * velocity.x + velocity.y * velocity.y; double velocitySquared = velocity.x * velocity.x + velocity.y * velocity.y;
...@@ -45,12 +46,12 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz ...@@ -45,12 +46,12 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz
T _pendingDragDelta; T _pendingDragDelta;
T get _initialPendingDragDelta; T get _initialPendingDragDelta;
T _getDragDelta(ui.PointerEvent event); T _getDragDelta(PointerInputEvent event);
bool get _hasSufficientPendingDragDeltaToAccept; bool get _hasSufficientPendingDragDeltaToAccept;
final ui.VelocityTracker _velocityTracker = new ui.VelocityTracker(); final ui.VelocityTracker _velocityTracker = new ui.VelocityTracker();
void addPointer(ui.PointerEvent event) { void addPointer(PointerInputEvent event) {
startTrackingPointer(event.pointer); startTrackingPointer(event.pointer);
if (_state == DragState.ready) { if (_state == DragState.ready) {
_state = DragState.possible; _state = DragState.possible;
...@@ -58,7 +59,7 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz ...@@ -58,7 +59,7 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz
} }
} }
void handleEvent(ui.PointerEvent event) { void handleEvent(PointerInputEvent event) {
assert(_state != DragState.ready); assert(_state != DragState.ready);
if (event.type == 'pointermove') { if (event.type == 'pointermove') {
_velocityTracker.addPosition(_eventTime(event), event.pointer, event.x, event.y); _velocityTracker.addPosition(_eventTime(event), event.pointer, event.x, event.y);
...@@ -120,7 +121,7 @@ class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> { ...@@ -120,7 +121,7 @@ class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd); }) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
double get _initialPendingDragDelta => 0.0; double get _initialPendingDragDelta => 0.0;
double _getDragDelta(ui.PointerEvent event) => event.dy; double _getDragDelta(PointerInputEvent event) => event.dy;
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop; bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
} }
...@@ -133,7 +134,7 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> { ...@@ -133,7 +134,7 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd); }) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
double get _initialPendingDragDelta => 0.0; double get _initialPendingDragDelta => 0.0;
double _getDragDelta(ui.PointerEvent event) => event.dx; double _getDragDelta(PointerInputEvent event) => event.dx;
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop; bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
} }
...@@ -146,7 +147,7 @@ class PanGestureRecognizer extends _DragGestureRecognizer<ui.Offset> { ...@@ -146,7 +147,7 @@ class PanGestureRecognizer extends _DragGestureRecognizer<ui.Offset> {
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd); }) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
ui.Offset get _initialPendingDragDelta => ui.Offset.zero; ui.Offset get _initialPendingDragDelta => ui.Offset.zero;
ui.Offset _getDragDelta(ui.PointerEvent event) => new ui.Offset(event.dx, event.dy); ui.Offset _getDragDelta(PointerInputEvent event) => new ui.Offset(event.dx, event.dy);
bool get _hasSufficientPendingDragDeltaToAccept { bool get _hasSufficientPendingDragDeltaToAccept {
return _pendingDragDelta.distance > kPanSlop; return _pendingDragDelta.distance > kPanSlop;
} }
......
// 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.
/// Base class for input events.
class InputEvent {
const InputEvent({ this.type, this.timeStamp: 0.0 });
final String type;
// TODO: Should timeStamp be a DateTime object instead of double?
// Some client code (e.g. drag.dart) does math on the time stamp.
final double timeStamp;
}
/// Input event representing a touch or button.
class PointerInputEvent extends InputEvent {
const PointerInputEvent({
String type,
double timeStamp: 0.0,
this.pointer,
this.kind,
this.x,
this.y,
this.dx,
this.dy,
this.buttons,
this.down,
this.primary,
this.obscured,
this.pressure,
this.pressureMin,
this.pressureMax,
this.distance,
this.distanceMin,
this.distanceMax,
this.radiusMajor,
this.radiusMinor,
this.radiusMin,
this.radiusMax,
this.orientation,
this.tilt
}) : super(type: type, timeStamp: timeStamp);
final int pointer;
final String kind;
final double x;
final double y;
final double dx;
final double dy;
final int buttons;
final bool down;
final bool primary;
final bool obscured;
final double pressure;
final double pressureMin;
final double pressureMax;
final double distance;
final double distanceMin;
final double distanceMax;
final double radiusMajor;
final double radiusMinor;
final double radiusMin;
final double radiusMax;
final double orientation;
final double tilt;
}
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'arena.dart'; import 'arena.dart';
import 'constants.dart'; import 'constants.dart';
import 'events.dart';
import 'pointer_router.dart'; import 'pointer_router.dart';
import 'recognizer.dart'; import 'recognizer.dart';
...@@ -22,7 +21,7 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer { ...@@ -22,7 +21,7 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
onLongPress(); onLongPress();
} }
void handlePrimaryPointer(ui.PointerEvent event) { void handlePrimaryPointer(PointerInputEvent event) {
if (event.type == 'pointerup') if (event.type == 'pointerup')
resolve(GestureDisposition.rejected); resolve(GestureDisposition.rejected);
} }
......
...@@ -2,18 +2,18 @@ ...@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui; import 'events.dart';
/// A callback that receives a [ui.PointerEvent] /// A callback that receives a [PointerInputEvent]
typedef void PointerRoute(ui.PointerEvent event); typedef void PointerRoute(PointerInputEvent event);
/// A routing table for [ui.PointerEvent] events. /// A routing table for [PointerInputEvent] events.
class PointerRouter { class PointerRouter {
final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>(); final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>();
/// Adds a route to the routing table /// Adds a route to the routing table
/// ///
/// Whenever this object routes a [ui.PointerEvent] corresponding to /// Whenever this object routes a [PointerInputEvent] corresponding to
/// pointer, call route. /// pointer, call route.
void addRoute(int pointer, PointerRoute route) { void addRoute(int pointer, PointerRoute route) {
List<PointerRoute> routes = _routeMap.putIfAbsent(pointer, () => new List<PointerRoute>()); List<PointerRoute> routes = _routeMap.putIfAbsent(pointer, () => new List<PointerRoute>());
...@@ -23,7 +23,7 @@ class PointerRouter { ...@@ -23,7 +23,7 @@ class PointerRouter {
/// Removes a route from the routing table /// Removes a route from the routing table
/// ///
/// No longer call route when routing a [ui.PointerEvent] corresponding to /// No longer call route when routing a [PointerInputEvent] corresponding to
/// pointer. Requires that this route was previously added to the router. /// pointer. Requires that this route was previously added to the router.
void removeRoute(int pointer, PointerRoute route) { void removeRoute(int pointer, PointerRoute route) {
assert(_routeMap.containsKey(pointer)); assert(_routeMap.containsKey(pointer));
...@@ -37,7 +37,7 @@ class PointerRouter { ...@@ -37,7 +37,7 @@ class PointerRouter {
/// Call the routes registed for this pointer event. /// Call the routes registed for this pointer event.
/// ///
/// Calls the routes in the order in which they were added to the route. /// Calls the routes in the order in which they were added to the route.
void route(ui.PointerEvent event) { void route(PointerInputEvent event) {
List<PointerRoute> routes = _routeMap[event.pointer]; List<PointerRoute> routes = _routeMap[event.pointer];
if (routes == null) if (routes == null)
return; return;
......
...@@ -7,6 +7,7 @@ import 'dart:ui' as ui; ...@@ -7,6 +7,7 @@ import 'dart:ui' as ui;
import 'arena.dart'; import 'arena.dart';
import 'constants.dart'; import 'constants.dart';
import 'events.dart';
import 'pointer_router.dart'; import 'pointer_router.dart';
export 'pointer_router.dart' show PointerRouter; export 'pointer_router.dart' show PointerRouter;
...@@ -22,9 +23,9 @@ abstract class GestureRecognizer extends GestureArenaMember { ...@@ -22,9 +23,9 @@ abstract class GestureRecognizer extends GestureArenaMember {
final Set<int> _trackedPointers = new Set<int>(); final Set<int> _trackedPointers = new Set<int>();
/// The primary entry point for users of this class. /// The primary entry point for users of this class.
void addPointer(ui.PointerEvent event); void addPointer(PointerInputEvent event);
void handleEvent(ui.PointerEvent event); void handleEvent(PointerInputEvent event);
void acceptGesture(int pointer) { } void acceptGesture(int pointer) { }
void rejectGesture(int pointer) { } void rejectGesture(int pointer) { }
void didStopTrackingLastPointer(int pointer); void didStopTrackingLastPointer(int pointer);
...@@ -58,7 +59,7 @@ abstract class GestureRecognizer extends GestureArenaMember { ...@@ -58,7 +59,7 @@ abstract class GestureRecognizer extends GestureArenaMember {
didStopTrackingLastPointer(pointer); didStopTrackingLastPointer(pointer);
} }
void stopTrackingIfPointerNoLongerDown(ui.PointerEvent event) { void stopTrackingIfPointerNoLongerDown(PointerInputEvent event) {
if (event.type == 'pointerup' || event.type == 'pointercancel') if (event.type == 'pointerup' || event.type == 'pointercancel')
stopTrackingPointer(event.pointer); stopTrackingPointer(event.pointer);
} }
...@@ -71,7 +72,7 @@ enum GestureRecognizerState { ...@@ -71,7 +72,7 @@ enum GestureRecognizerState {
defunct defunct
} }
ui.Point _getPoint(ui.PointerEvent event) { ui.Point _getPoint(PointerInputEvent event) {
return new ui.Point(event.x, event.y); return new ui.Point(event.x, event.y);
} }
...@@ -86,7 +87,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer { ...@@ -86,7 +87,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer {
ui.Point initialPosition; ui.Point initialPosition;
Timer _timer; Timer _timer;
void addPointer(ui.PointerEvent event) { void addPointer(PointerInputEvent event) {
startTrackingPointer(event.pointer); startTrackingPointer(event.pointer);
if (state == GestureRecognizerState.ready) { if (state == GestureRecognizerState.ready) {
state = GestureRecognizerState.possible; state = GestureRecognizerState.possible;
...@@ -97,7 +98,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer { ...@@ -97,7 +98,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer {
} }
} }
void handleEvent(ui.PointerEvent event) { void handleEvent(PointerInputEvent event) {
assert(state != GestureRecognizerState.ready); assert(state != GestureRecognizerState.ready);
if (state == GestureRecognizerState.possible && event.pointer == primaryPointer) { if (state == GestureRecognizerState.possible && event.pointer == primaryPointer) {
// TODO(abarth): Maybe factor the slop handling out into a separate class? // TODO(abarth): Maybe factor the slop handling out into a separate class?
...@@ -110,7 +111,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer { ...@@ -110,7 +111,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer {
} }
/// Override to provide behavior for the primary pointer when the gesture is still possible. /// Override to provide behavior for the primary pointer when the gesture is still possible.
void handlePrimaryPointer(ui.PointerEvent event); void handlePrimaryPointer(PointerInputEvent event);
/// Override to be notified with [deadline] is exceeded. /// Override to be notified with [deadline] is exceeded.
/// ///
...@@ -143,7 +144,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer { ...@@ -143,7 +144,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer {
} }
} }
double _getDistance(ui.PointerEvent event) { double _getDistance(PointerInputEvent event) {
ui.Offset offset = _getPoint(event) - initialPosition; ui.Offset offset = _getPoint(event) - initialPosition;
return offset.distance; return offset.distance;
} }
......
...@@ -7,6 +7,7 @@ import 'dart:ui' as ui; ...@@ -7,6 +7,7 @@ import 'dart:ui' as ui;
import 'arena.dart'; import 'arena.dart';
import 'recognizer.dart'; import 'recognizer.dart';
import 'constants.dart'; import 'constants.dart';
import 'events.dart';
enum ScaleState { enum ScaleState {
ready, ready,
...@@ -35,7 +36,7 @@ class ScaleGestureRecognizer extends GestureRecognizer { ...@@ -35,7 +36,7 @@ class ScaleGestureRecognizer extends GestureRecognizer {
double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0; double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0;
void addPointer(ui.PointerEvent event) { void addPointer(PointerInputEvent event) {
startTrackingPointer(event.pointer); startTrackingPointer(event.pointer);
if (_state == ScaleState.ready) { if (_state == ScaleState.ready) {
_state = ScaleState.possible; _state = ScaleState.possible;
...@@ -45,7 +46,7 @@ class ScaleGestureRecognizer extends GestureRecognizer { ...@@ -45,7 +46,7 @@ class ScaleGestureRecognizer extends GestureRecognizer {
} }
} }
void handleEvent(ui.PointerEvent event) { void handleEvent(PointerInputEvent event) {
assert(_state != ScaleState.ready); assert(_state != ScaleState.ready);
bool configChanged = false; bool configChanged = false;
switch(event.type) { switch(event.type) {
......
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'arena.dart'; import 'arena.dart';
import 'constants.dart'; import 'constants.dart';
import 'events.dart';
import 'recognizer.dart'; import 'recognizer.dart';
typedef void GestureShowPressCallback(); typedef void GestureShowPressCallback();
...@@ -23,7 +22,7 @@ class ShowPressGestureRecognizer extends PrimaryPointerGestureRecognizer { ...@@ -23,7 +22,7 @@ class ShowPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
onShowPress(); onShowPress();
} }
void handlePrimaryPointer(ui.PointerEvent event) { void handlePrimaryPointer(PointerInputEvent event) {
if (event.type == 'pointerup') if (event.type == 'pointerup')
resolve(GestureDisposition.rejected); resolve(GestureDisposition.rejected);
} }
......
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'arena.dart'; import 'arena.dart';
import 'events.dart';
import 'recognizer.dart'; import 'recognizer.dart';
typedef void GestureTapCallback(); typedef void GestureTapCallback();
...@@ -17,7 +16,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { ...@@ -17,7 +16,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
GestureTapCallback onTapDown; GestureTapCallback onTapDown;
GestureTapCallback onTapCancel; GestureTapCallback onTapCancel;
void handlePrimaryPointer(ui.PointerEvent event) { void handlePrimaryPointer(PointerInputEvent event) {
if (event.type == 'pointerdown') { if (event.type == 'pointerdown') {
if (onTapDown != null) if (onTapDown != null)
onTapDown(); onTapDown();
......
...@@ -137,7 +137,7 @@ class _RenderInkWell extends RenderProxyBox { ...@@ -137,7 +137,7 @@ class _RenderInkWell extends RenderProxyBox {
TapGestureRecognizer _tap; TapGestureRecognizer _tap;
LongPressGestureRecognizer _longPress; LongPressGestureRecognizer _longPress;
void handleEvent(ui.Event event, BoxHitTestEntry entry) { void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown' && (_tap != null || _longPress != null)) { if (event.type == 'pointerdown' && (_tap != null || _longPress != null)) {
_tap?.addPointer(event); _tap?.addPointer(event);
_longPress?.addPointer(event); _longPress?.addPointer(event);
......
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui; import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -56,7 +55,7 @@ class _MaterialAppState extends State<MaterialApp> { ...@@ -56,7 +55,7 @@ class _MaterialAppState extends State<MaterialApp> {
super.dispose(); super.dispose();
} }
void _backHandler(ui.Event event) { void _backHandler(InputEvent event) {
assert(mounted); assert(mounted);
if (event.type == 'back') { if (event.type == 'back') {
NavigatorState navigator = _navigator.currentState; NavigatorState navigator = _navigator.currentState;
......
// 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 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/animation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
const double _kMinScrollbarThumbLength = 18.0;
const double _kScrollbarThumbGirth = 6.0;
const Duration _kScrollbarThumbFadeDuration = const Duration(milliseconds: 300);
class ScrollbarPainter extends ScrollableListPainter {
double _opacity = 0.0;
int get _alpha => (_opacity * 0xFF).round();
// TODO(hansmuller): thumb color should come from ThemeData.
Color get thumbColor => const Color(0xFF9E9E9E);
void paintThumb(PaintingContext context, Rect thumbBounds) {
final Paint paint = new Paint()..color = thumbColor.withAlpha(_alpha);
context.canvas.drawRect(thumbBounds, paint);
}
void paintScrollbar(PaintingContext context, Offset offset) {
final Rect viewportBounds = offset & viewportSize;
Point thumbOrigin;
Size thumbSize;
if (isVertical) {
double thumbHeight = viewportBounds.height * viewportBounds.height / contentExtent;
thumbHeight = thumbHeight.clamp(_kMinScrollbarThumbLength, viewportBounds.height);
final double maxThumbTop = viewportBounds.height - thumbHeight;
double thumbTop = (scrollOffset / (contentExtent - viewportBounds.height)) * maxThumbTop;
thumbTop = viewportBounds.top + thumbTop.clamp(0.0, maxThumbTop);
thumbOrigin = new Point(viewportBounds.right - _kScrollbarThumbGirth, thumbTop);
thumbSize = new Size(_kScrollbarThumbGirth, thumbHeight);
} else {
double thumbWidth = viewportBounds.width * viewportBounds.width / contentExtent;
thumbWidth = thumbWidth.clamp(_kMinScrollbarThumbLength, viewportBounds.width);
final double maxThumbLeft = viewportBounds.width - thumbWidth;
double thumbLeft = (scrollOffset / (contentExtent - viewportBounds.width)) * maxThumbLeft;
thumbLeft = viewportBounds.left + thumbLeft.clamp(0.0, maxThumbLeft);
thumbOrigin = new Point(thumbLeft, viewportBounds.height - _kScrollbarThumbGirth);
thumbSize = new Size(thumbWidth, _kScrollbarThumbGirth);
}
paintThumb(context, thumbOrigin & thumbSize);
}
void paint(PaintingContext context, Offset offset) {
if (_alpha == 0)
return;
paintScrollbar(context, offset);
}
ValuePerformance<double> _fade;
Future scrollStarted() {
_fade ??= new ValuePerformance<double>()
..duration = _kScrollbarThumbFadeDuration
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: ease)
..addListener(() {
_opacity = _fade.value;
renderer?.markNeedsPaint();
});
return _fade.forward();
}
Future scrollEnded() {
return _fade.reverse();
}
void detach() {
super.detach();
_fade?.stop();
}
}
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -82,8 +83,8 @@ class _RenderSwitch extends RenderToggleable { ...@@ -82,8 +83,8 @@ class _RenderSwitch extends RenderToggleable {
RadialReaction _radialReaction; RadialReaction _radialReaction;
void handleEvent(ui.Event event, BoxHitTestEntry entry) { void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event is ui.PointerEvent) { if (event is PointerInputEvent) {
if (event.type == 'pointerdown') if (event.type == 'pointerdown')
_showRadialReaction(entry.localPosition); _showRadialReaction(entry.localPosition);
else if (event.type == 'pointerup') else if (event.type == 'pointerup')
......
...@@ -23,13 +23,7 @@ int _hammingWeight(int value) { ...@@ -23,13 +23,7 @@ int _hammingWeight(int value) {
return weight; return weight;
} }
class _PointerState { typedef void EventListener(InputEvent event);
_PointerState({ this.result, this.lastPosition });
HitTestResult result;
Point lastPosition;
}
typedef void EventListener(ui.Event event);
/// A hit test entry used by [FlutterBinding] /// A hit test entry used by [FlutterBinding]
class BindingHitTestEntry extends HitTestEntry { class BindingHitTestEntry extends HitTestEntry {
...@@ -39,6 +33,93 @@ class BindingHitTestEntry extends HitTestEntry { ...@@ -39,6 +33,93 @@ class BindingHitTestEntry extends HitTestEntry {
final HitTestResult result; final HitTestResult result;
} }
/// State used in converting ui.Event to InputEvent
class _PointerState {
_PointerState({ this.pointer, this.lastPosition });
int pointer;
Point lastPosition;
}
class _UiEventConverter {
static InputEvent convert(ui.Event event) {
if (event is ui.PointerEvent)
return convertPointerEvent(event);
// Default event
return new InputEvent(
type: event.type,
timeStamp: event.timeStamp
);
}
// Map actual input pointer value to a unique value
// Since events are serialized we can just use a counter
static Map<int, _PointerState> _stateForPointer = new Map<int, _PointerState>();
static int _pointerCount = 0;
static PointerInputEvent convertPointerEvent(ui.PointerEvent event) {
Point position = new Point(event.x, event.y);
_PointerState state = _stateForPointer[event.pointer];
double dx, dy;
switch (event.type) {
case 'pointerdown':
if (state == null) {
state = new _PointerState(lastPosition: position);
_stateForPointer[event.pointer] = state;
}
state.pointer = _pointerCount;
_pointerCount++;
break;
case 'pointermove':
// state == null means the pointer is hovering
if (state != null) {
dx = position.x - state.lastPosition.x;
dy = position.y - state.lastPosition.y;
state.lastPosition = position;
}
break;
case 'pointerup':
case 'pointercancel':
// state == null indicates spurious events
if (state != null) {
// Only remove the pointer state when the last button has been released.
if (_hammingWeight(event.buttons) <= 1)
_stateForPointer.remove(event.pointer);
}
break;
}
return new PointerInputEvent(
type: event.type,
timeStamp: event.timeStamp,
pointer: state.pointer,
kind: event.kind,
x: event.x,
y: event.y,
dx: dx,
dy: dy,
buttons: event.buttons,
down: event.down,
primary: event.primary,
obscured: event.obscured,
pressure: event.pressure,
pressureMin: event.pressureMin,
pressureMax: event.pressureMax,
distance: event.distance,
distanceMin: event.distanceMin,
distanceMax: event.distanceMax,
radiusMajor: event.radiusMajor,
radiusMinor: event.radiusMinor,
radiusMin: event.radiusMin,
radiusMax: event.radiusMax,
orientation: event.orientation,
tilt: event.tilt
);
}
}
/// The glue between the render tree and the Flutter engine /// The glue between the render tree and the Flutter engine
class FlutterBinding extends HitTestTarget { class FlutterBinding extends HitTestTarget {
...@@ -95,11 +176,12 @@ class FlutterBinding extends HitTestTarget { ...@@ -95,11 +176,12 @@ class FlutterBinding extends HitTestTarget {
bool removeEventListener(EventListener listener) => _eventListeners.remove(listener); bool removeEventListener(EventListener listener) => _eventListeners.remove(listener);
void _handleEvent(ui.Event event) { void _handleEvent(ui.Event event) {
if (event is ui.PointerEvent) { InputEvent ourEvent = _UiEventConverter.convert(event);
_handlePointerEvent(event); if (ourEvent is PointerInputEvent) {
_handlePointerInputEvent(ourEvent);
} else { } else {
for (EventListener listener in _eventListeners) for (EventListener listener in _eventListeners)
listener(event); listener(ourEvent);
} }
} }
...@@ -109,41 +191,36 @@ class FlutterBinding extends HitTestTarget { ...@@ -109,41 +191,36 @@ class FlutterBinding extends HitTestTarget {
/// State for all pointers which are currently down. /// State for all pointers which are currently down.
/// We do not track the state of hovering pointers because we need /// We do not track the state of hovering pointers because we need
/// to hit-test them on each movement. /// to hit-test them on each movement.
Map<int, _PointerState> _stateForPointer = new Map<int, _PointerState>(); Map<int, HitTestResult> _resultForPointer = new Map<int, HitTestResult>();
void _handlePointerEvent(ui.PointerEvent event) {
Point position = new Point(event.x, event.y);
_PointerState state = _stateForPointer[event.pointer]; void _handlePointerInputEvent(PointerInputEvent event) {
HitTestResult result = _resultForPointer[event.pointer];
switch (event.type) { switch (event.type) {
case 'pointerdown': case 'pointerdown':
if (state == null) { if (result == null) {
state = new _PointerState(result: hitTest(position), lastPosition: position); result = hitTest(new Point(event.x, event.y));
_stateForPointer[event.pointer] = state; _resultForPointer[event.pointer] = result;
} }
break; break;
case 'pointermove': case 'pointermove':
if (state == null) { if (result == null) {
// The pointer is hovering, ignore it for now since we don't // The pointer is hovering, ignore it for now since we don't
// know what to do with it yet. // know what to do with it yet.
return; return;
} }
event.dx = position.x - state.lastPosition.x;
event.dy = position.y - state.lastPosition.y;
state.lastPosition = position;
break; break;
case 'pointerup': case 'pointerup':
case 'pointercancel': case 'pointercancel':
if (state == null) { if (result == null) {
// This seems to be a spurious event. Ignore it. // This seems to be a spurious event. Ignore it.
return; return;
} }
// Only remove the pointer state when the last button has been released. // Only remove the hit test result when the last button has been released.
if (_hammingWeight(event.buttons) <= 1) if (_hammingWeight(event.buttons) <= 1)
_stateForPointer.remove(event.pointer); _resultForPointer.remove(event.pointer);
break; break;
} }
dispatchEvent(event, state.result); dispatchEvent(event, result);
} }
/// Determine which [HitTestTarget] objects are located at a given position /// Determine which [HitTestTarget] objects are located at a given position
...@@ -155,15 +232,15 @@ class FlutterBinding extends HitTestTarget { ...@@ -155,15 +232,15 @@ class FlutterBinding extends HitTestTarget {
} }
/// Dispatch the given event to the path of the given hit test result /// Dispatch the given event to the path of the given hit test result
void dispatchEvent(ui.Event event, HitTestResult result) { void dispatchEvent(InputEvent event, HitTestResult result) {
assert(result != null); assert(result != null);
for (HitTestEntry entry in result.path) for (HitTestEntry entry in result.path)
entry.target.handleEvent(event, entry); entry.target.handleEvent(event, entry);
} }
void handleEvent(ui.Event e, BindingHitTestEntry entry) { void handleEvent(InputEvent e, BindingHitTestEntry entry) {
if (e is ui.PointerEvent) { if (e is PointerInputEvent) {
ui.PointerEvent event = e; PointerInputEvent event = e;
pointerRouter.route(event); pointerRouter.route(event);
if (event.type == 'pointerdown') if (event.type == 'pointerdown')
GestureArena.instance.close(event.pointer); GestureArena.instance.close(event.pointer);
......
...@@ -237,6 +237,7 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -237,6 +237,7 @@ class RenderBlockViewport extends RenderBlockBase {
ExtentCallback totalExtentCallback, ExtentCallback totalExtentCallback,
ExtentCallback maxCrossAxisDimensionCallback, ExtentCallback maxCrossAxisDimensionCallback,
ExtentCallback minCrossAxisDimensionCallback, ExtentCallback minCrossAxisDimensionCallback,
Painter overlayPainter,
BlockDirection direction: BlockDirection.vertical, BlockDirection direction: BlockDirection.vertical,
double itemExtent, double itemExtent,
double minExtent: 0.0, double minExtent: 0.0,
...@@ -246,6 +247,7 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -246,6 +247,7 @@ class RenderBlockViewport extends RenderBlockBase {
_totalExtentCallback = totalExtentCallback, _totalExtentCallback = totalExtentCallback,
_maxCrossAxisExtentCallback = maxCrossAxisDimensionCallback, _maxCrossAxisExtentCallback = maxCrossAxisDimensionCallback,
_minCrossAxisExtentCallback = minCrossAxisDimensionCallback, _minCrossAxisExtentCallback = minCrossAxisDimensionCallback,
_overlayPainter = overlayPainter,
_startOffset = startOffset, _startOffset = startOffset,
super(children: children, direction: direction, itemExtent: itemExtent, minExtent: minExtent); super(children: children, direction: direction, itemExtent: itemExtent, minExtent: minExtent);
...@@ -298,6 +300,27 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -298,6 +300,27 @@ class RenderBlockViewport extends RenderBlockBase {
markNeedsLayout(); markNeedsLayout();
} }
Painter get overlayPainter => _overlayPainter;
Painter _overlayPainter;
void set overlayPainter(Painter value) {
if (_overlayPainter == value)
return;
_overlayPainter?.detach();
_overlayPainter = value;
_overlayPainter?.attach(this);
markNeedsPaint();
}
void attach() {
super.attach();
_overlayPainter?.attach(this);
}
void detach() {
super.detach();
_overlayPainter?.detach();
}
/// The offset at which to paint the first child /// The offset at which to paint the first child
/// ///
/// Note: you can modify this property from within [callback], if necessary. /// Note: you can modify this property from within [callback], if necessary.
...@@ -377,11 +400,15 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -377,11 +400,15 @@ class RenderBlockViewport extends RenderBlockBase {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
context.canvas.save(); context.canvas.save();
context.canvas.clipRect(offset & size); context.canvas.clipRect(offset & size);
if (isVertical) if (isVertical)
defaultPaint(context, offset.translate(0.0, startOffset)); defaultPaint(context, offset.translate(0.0, startOffset));
else else
defaultPaint(context, offset.translate(startOffset, 0.0)); defaultPaint(context, offset.translate(startOffset, 0.0));
overlayPainter?.paint(context, offset);
context.canvas.restore(); context.canvas.restore();
} }
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui; import 'package:flutter/gestures.dart';
/// An object that can handle events. /// An object that can handle events.
abstract class HitTestTarget { abstract class HitTestTarget {
/// Override this function to receive events. /// Override this function to receive events.
void handleEvent(ui.Event event, HitTestEntry entry); void handleEvent(InputEvent event, HitTestEntry entry);
} }
/// Data collected during a hit test about a specific [HitTestTarget]. /// Data collected during a hit test about a specific [HitTestTarget].
......
...@@ -7,6 +7,7 @@ import 'dart:ui' as ui; ...@@ -7,6 +7,7 @@ import 'dart:ui' as ui;
import 'dart:ui' show Point, Offset, Size, Rect, Color, Paint, Path; import 'dart:ui' show Point, Offset, Size, Rect, Color, Paint, Path;
import 'package:flutter/animation.dart'; import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
import 'debug.dart'; import 'debug.dart';
...@@ -394,6 +395,27 @@ class PaintingContext { ...@@ -394,6 +395,27 @@ class PaintingContext {
} }
/// An encapsulation of a renderer and a paint() method.
///
/// A renderer may allow its paint() method to be augmented or redefined by
/// providing a Painter. See for example overlayPainter in BlockViewport.
abstract class Painter {
RenderObject get renderObject => _renderObject;
RenderObject _renderObject;
void attach(RenderObject renderObject) {
assert(_renderObject == null);
_renderObject = renderObject;
}
void detach() {
assert(_renderObject != null);
_renderObject = null;
}
void paint(PaintingContext context, Offset offset);
}
/// An abstract set of layout constraints /// An abstract set of layout constraints
/// ///
/// Concrete layout models (such as box) will create concrete subclasses to /// Concrete layout models (such as box) will create concrete subclasses to
...@@ -1071,7 +1093,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -1071,7 +1093,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// EVENTS // EVENTS
/// Override this function to handle events that hit this render object /// Override this function to handle events that hit this render object
void handleEvent(ui.Event event, HitTestEntry entry) { void handleEvent(InputEvent event, HitTestEntry entry) {
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter/gestures.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
import 'box.dart'; import 'box.dart';
...@@ -1054,7 +1055,7 @@ class RenderCustomPaint extends RenderProxyBox { ...@@ -1054,7 +1055,7 @@ class RenderCustomPaint extends RenderProxyBox {
} }
} }
typedef void PointerEventListener(ui.PointerEvent e); typedef void PointerEventListener(PointerInputEvent e);
/// Invokes the callbacks in response to pointer events. /// Invokes the callbacks in response to pointer events.
class RenderPointerListener extends RenderProxyBox { class RenderPointerListener extends RenderProxyBox {
...@@ -1071,7 +1072,7 @@ class RenderPointerListener extends RenderProxyBox { ...@@ -1071,7 +1072,7 @@ class RenderPointerListener extends RenderProxyBox {
PointerEventListener onPointerUp; PointerEventListener onPointerUp;
PointerEventListener onPointerCancel; PointerEventListener onPointerCancel;
void handleEvent(ui.Event event, HitTestEntry entry) { void handleEvent(InputEvent event, HitTestEntry entry) {
if (onPointerDown != null && event.type == 'pointerdown') if (onPointerDown != null && event.type == 'pointerdown')
return onPointerDown(event); return onPointerDown(event);
if (onPointerMove != null && event.type == 'pointermove') if (onPointerMove != null && event.type == 'pointermove')
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/animation.dart'; import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
...@@ -37,7 +35,7 @@ abstract class RenderToggleable extends RenderConstrainedBox { ...@@ -37,7 +35,7 @@ abstract class RenderToggleable extends RenderConstrainedBox {
double get position => _performance.value; double get position => _performance.value;
void handleEvent(ui.Event event, BoxHitTestEntry entry) { void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown') if (event.type == 'pointerdown')
_tap.addPointer(event); _tap.addPointer(event);
} }
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:collection'; import 'dart:collection';
import 'dart:ui' as ui;
import 'package:flutter/animation.dart'; import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'basic.dart'; import 'basic.dart';
...@@ -69,7 +69,7 @@ class Draggable extends StatefulComponent { ...@@ -69,7 +69,7 @@ class Draggable extends StatefulComponent {
class _DraggableState extends State<Draggable> { class _DraggableState extends State<Draggable> {
DragRoute _route; DragRoute _route;
void _startDrag(ui.PointerEvent event) { void _startDrag(PointerInputEvent event) {
if (_route != null) if (_route != null)
return; // TODO(ianh): once we switch to using gestures, just hand the gesture to the route so it can do everything itself. then we can have multiple drags at the same time. return; // TODO(ianh): once we switch to using gestures, just hand the gesture to the route so it can do everything itself. then we can have multiple drags at the same time.
final Point point = new Point(event.x, event.y); final Point point = new Point(event.x, event.y);
...@@ -97,7 +97,7 @@ class _DraggableState extends State<Draggable> { ...@@ -97,7 +97,7 @@ class _DraggableState extends State<Draggable> {
config.navigator.push(_route); config.navigator.push(_route);
} }
void _updateDrag(ui.PointerEvent event) { void _updateDrag(PointerInputEvent event) {
if (_route != null) { if (_route != null) {
config.navigator.setState(() { config.navigator.setState(() {
_route.update(new Point(event.x, event.y)); _route.update(new Point(event.x, event.y));
...@@ -105,14 +105,14 @@ class _DraggableState extends State<Draggable> { ...@@ -105,14 +105,14 @@ class _DraggableState extends State<Draggable> {
} }
} }
void _cancelDrag(ui.PointerEvent event) { void _cancelDrag(PointerInputEvent event) {
if (_route != null) { if (_route != null) {
config.navigator.popRoute(_route, DragEndKind.canceled); config.navigator.popRoute(_route, DragEndKind.canceled);
assert(_route == null); assert(_route == null);
} }
} }
void _drop(ui.PointerEvent event) { void _drop(PointerInputEvent event) {
if (_route != null) { if (_route != null) {
_route.update(new Point(event.x, event.y)); _route.update(new Point(event.x, event.y));
config.navigator.popRoute(_route, DragEndKind.dropped); config.navigator.popRoute(_route, DragEndKind.dropped);
......
...@@ -128,6 +128,8 @@ class EditableString implements KeyboardClient { ...@@ -128,6 +128,8 @@ class EditableString implements KeyboardClient {
selection = new TextRange(start: start, end: end); selection = new TextRange(start: start, end: end);
onUpdated(); onUpdated();
} }
void submit(SubmitAction action) {}
} }
class EditableText extends StatefulComponent { class EditableText extends StatefulComponent {
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
...@@ -187,7 +185,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -187,7 +185,7 @@ class _GestureDetectorState extends State<GestureDetector> {
return null; return null;
} }
void _handlePointerDown(ui.PointerEvent event) { void _handlePointerDown(PointerInputEvent event) {
if (_tap != null) if (_tap != null)
_tap.addPointer(event); _tap.addPointer(event);
if (_showPress != null) if (_showPress != null)
......
...@@ -18,7 +18,8 @@ class HomogeneousViewport extends RenderObjectWidget { ...@@ -18,7 +18,8 @@ class HomogeneousViewport extends RenderObjectWidget {
this.itemExtent, // required this.itemExtent, // required
this.itemCount, // optional, but you cannot shrink-wrap this class or otherwise use its intrinsic dimensions if you don't specify it this.itemCount, // optional, but you cannot shrink-wrap this class or otherwise use its intrinsic dimensions if you don't specify it
this.direction: ScrollDirection.vertical, this.direction: ScrollDirection.vertical,
this.startOffset: 0.0 this.startOffset: 0.0,
this.overlayPainter
}) : super(key: key) { }) : super(key: key) {
assert(itemExtent != null); assert(itemExtent != null);
} }
...@@ -29,6 +30,7 @@ class HomogeneousViewport extends RenderObjectWidget { ...@@ -29,6 +30,7 @@ class HomogeneousViewport extends RenderObjectWidget {
final int itemCount; final int itemCount;
final ScrollDirection direction; final ScrollDirection direction;
final double startOffset; final double startOffset;
final Painter overlayPainter;
_HomogeneousViewportElement createElement() => new _HomogeneousViewportElement(this); _HomogeneousViewportElement createElement() => new _HomogeneousViewportElement(this);
...@@ -70,6 +72,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor ...@@ -70,6 +72,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
renderObject.totalExtentCallback = getTotalExtent; renderObject.totalExtentCallback = getTotalExtent;
renderObject.minCrossAxisExtentCallback = getMinCrossAxisExtent; renderObject.minCrossAxisExtentCallback = getMinCrossAxisExtent;
renderObject.maxCrossAxisExtentCallback = getMaxCrossAxisExtent; renderObject.maxCrossAxisExtentCallback = getMaxCrossAxisExtent;
renderObject.overlayPainter = widget.overlayPainter;
} }
void unmount() { void unmount() {
...@@ -77,6 +80,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor ...@@ -77,6 +80,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
renderObject.totalExtentCallback = null; renderObject.totalExtentCallback = null;
renderObject.minCrossAxisExtentCallback = null; renderObject.minCrossAxisExtentCallback = null;
renderObject.maxCrossAxisExtentCallback = null; renderObject.maxCrossAxisExtentCallback = null;
renderObject.overlayPainter = null;
super.unmount(); super.unmount();
} }
...@@ -134,6 +138,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor ...@@ -134,6 +138,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
renderObject.itemExtent = widget.itemExtent; renderObject.itemExtent = widget.itemExtent;
renderObject.minExtent = getTotalExtent(null); renderObject.minExtent = getTotalExtent(null);
renderObject.startOffset = offset; renderObject.startOffset = offset;
renderObject.overlayPainter = widget.overlayPainter;
}); });
} }
......
...@@ -32,7 +32,9 @@ abstract class Scrollable extends StatefulComponent { ...@@ -32,7 +32,9 @@ abstract class Scrollable extends StatefulComponent {
Key key, Key key,
this.initialScrollOffset, this.initialScrollOffset,
this.scrollDirection: ScrollDirection.vertical, this.scrollDirection: ScrollDirection.vertical,
this.onScrollStart,
this.onScroll, this.onScroll,
this.onScrollEnd,
this.snapOffsetCallback, this.snapOffsetCallback,
this.snapAlignmentOffset: 0.0 this.snapAlignmentOffset: 0.0
}) : super(key: key) { }) : super(key: key) {
...@@ -42,7 +44,9 @@ abstract class Scrollable extends StatefulComponent { ...@@ -42,7 +44,9 @@ abstract class Scrollable extends StatefulComponent {
final double initialScrollOffset; final double initialScrollOffset;
final ScrollDirection scrollDirection; final ScrollDirection scrollDirection;
final ScrollListener onScrollStart;
final ScrollListener onScroll; final ScrollListener onScroll;
final ScrollListener onScrollEnd;
final SnapOffsetCallback snapOffsetCallback; final SnapOffsetCallback snapOffsetCallback;
final double snapAlignmentOffset; final double snapAlignmentOffset;
} }
...@@ -74,6 +78,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -74,6 +78,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return _scrollBehavior; return _scrollBehavior;
} }
GestureDragStartCallback _getDragStartHandler(ScrollDirection direction) {
if (config.scrollDirection != direction || !scrollBehavior.isScrollable)
return null;
return _handleDragStart;
}
GestureDragUpdateCallback _getDragUpdateHandler(ScrollDirection direction) { GestureDragUpdateCallback _getDragUpdateHandler(ScrollDirection direction) {
if (config.scrollDirection != direction || !scrollBehavior.isScrollable) if (config.scrollDirection != direction || !scrollBehavior.isScrollable)
return null; return null;
...@@ -88,8 +98,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -88,8 +98,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new GestureDetector( return new GestureDetector(
onVerticalDragStart: _getDragStartHandler(ScrollDirection.vertical),
onVerticalDragUpdate: _getDragUpdateHandler(ScrollDirection.vertical), onVerticalDragUpdate: _getDragUpdateHandler(ScrollDirection.vertical),
onVerticalDragEnd: _getDragEndHandler(ScrollDirection.vertical), onVerticalDragEnd: _getDragEndHandler(ScrollDirection.vertical),
onHorizontalDragStart: _getDragStartHandler(ScrollDirection.horizontal),
onHorizontalDragUpdate: _getDragUpdateHandler(ScrollDirection.horizontal), onHorizontalDragUpdate: _getDragUpdateHandler(ScrollDirection.horizontal),
onHorizontalDragEnd: _getDragEndHandler(ScrollDirection.horizontal), onHorizontalDragEnd: _getDragEndHandler(ScrollDirection.horizontal),
child: new Listener( child: new Listener(
...@@ -199,12 +211,22 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -199,12 +211,22 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return _startToEndAnimation(); return _startToEndAnimation();
} }
void dispatchOnScrollStart() {
if (config.onScrollStart != null)
config.onScrollStart(_scrollOffset);
}
// Derived classes can override this method and call super.dispatchOnScroll() // Derived classes can override this method and call super.dispatchOnScroll()
void dispatchOnScroll() { void dispatchOnScroll() {
if (config.onScroll != null) if (config.onScroll != null)
config.onScroll(_scrollOffset); config.onScroll(_scrollOffset);
} }
void dispatchOnScrollEnd() {
if (config.onScrollEnd != null)
config.onScrollEnd(_scrollOffset);
}
double _scrollVelocity(ui.Offset velocity) { double _scrollVelocity(ui.Offset velocity) {
double scrollVelocity = config.scrollDirection == ScrollDirection.horizontal double scrollVelocity = config.scrollDirection == ScrollDirection.horizontal
? -velocity.dx ? -velocity.dx
...@@ -216,14 +238,20 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -216,14 +238,20 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
_animation.stop(); _animation.stop();
} }
void _handleDragStart() {
scheduleMicrotask(dispatchOnScrollStart);
}
void _handleDragUpdate(double delta) { void _handleDragUpdate(double delta) {
// We negate the delta here because a positive scroll offset moves the // We negate the delta here because a positive scroll offset moves the
// the content up (or to the left) rather than down (or the right). // the content up (or to the left) rather than down (or the right).
scrollBy(-delta); scrollBy(-delta);
} }
void _handleDragEnd(Offset velocity) { Future _handleDragEnd(Offset velocity) {
fling(velocity); return fling(velocity).then((_) {
dispatchOnScrollEnd();
});
} }
} }
...@@ -379,6 +407,52 @@ class Block extends StatelessComponent { ...@@ -379,6 +407,52 @@ class Block extends StatelessComponent {
} }
} }
abstract class ScrollableListPainter extends Painter {
void attach(RenderObject renderObject) {
assert(renderObject is RenderBlockViewport);
super.attach(renderObject);
}
RenderBlockViewport get renderer => renderObject;
bool get isVertical => renderer.isVertical;
Size get viewportSize => renderer.size;
double get contentExtent => _contentExtent;
double _contentExtent = 0.0;
void set contentExtent (double value) {
assert(value != null);
assert(value >= 0.0);
if (_contentExtent == value)
return;
_contentExtent = value;
renderer?.markNeedsPaint();
}
double get scrollOffset => _scrollOffset;
double _scrollOffset = 0.0;
void set scrollOffset (double value) {
assert(value != null);
assert(value >= 0.0 && value <= 1.0);
if (_scrollOffset == value)
return;
_scrollOffset = value;
renderer?.markNeedsPaint();
}
/// Called when a scroll starts. Subclasses may override this method to
/// initialize some state or to play an animation. The returned Future should
/// complete when the computation triggered by this method has finished.
Future scrollStarted() => new Future.value();
/// Similar to scrollStarted(). Called when a scroll ends. For fling scrolls
/// "ended" means that the scroll animation either stopped of its own accord
/// or was canceled by the user.
Future scrollEnded() => new Future.value();
}
/// An optimized scrollable widget for a large number of children that are all /// An optimized scrollable widget for a large number of children that are all
/// the same size (extent) in the scrollDirection. For example for /// the same size (extent) in the scrollDirection. For example for
/// ScrollDirection.vertical itemExtent is the height of each item. Use this /// ScrollDirection.vertical itemExtent is the height of each item. Use this
...@@ -394,7 +468,8 @@ abstract class ScrollableWidgetList extends Scrollable { ...@@ -394,7 +468,8 @@ abstract class ScrollableWidgetList extends Scrollable {
double snapAlignmentOffset: 0.0, double snapAlignmentOffset: 0.0,
this.itemsWrap: false, this.itemsWrap: false,
this.itemExtent, this.itemExtent,
this.padding this.padding,
this.scrollableListPainter
}) : super( }) : super(
key: key, key: key,
initialScrollOffset: initialScrollOffset, initialScrollOffset: initialScrollOffset,
...@@ -409,6 +484,7 @@ abstract class ScrollableWidgetList extends Scrollable { ...@@ -409,6 +484,7 @@ abstract class ScrollableWidgetList extends Scrollable {
final bool itemsWrap; final bool itemsWrap;
final double itemExtent; final double itemExtent;
final EdgeDims padding; final EdgeDims padding;
final ScrollableListPainter scrollableListPainter;
} }
abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ScrollableState<T> { abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ScrollableState<T> {
...@@ -480,18 +556,40 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ...@@ -480,18 +556,40 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends
return new EdgeDims.only(top: padding.top, bottom: padding.bottom); return new EdgeDims.only(top: padding.top, bottom: padding.bottom);
} }
void _updateScrollBehavior() { double get _contentExtent {
// if you don't call this from build(), you must call it from setState().
double contentExtent = config.itemExtent * itemCount; double contentExtent = config.itemExtent * itemCount;
if (config.padding != null) if (config.padding != null)
contentExtent += _leadingPadding + _trailingPadding; contentExtent += _leadingPadding + _trailingPadding;
return contentExtent;
}
void _updateScrollBehavior() {
// if you don't call this from build(), you must call it from setState().
if (config.scrollableListPainter != null)
config.scrollableListPainter.contentExtent = _contentExtent;
scrollTo(scrollBehavior.updateExtents( scrollTo(scrollBehavior.updateExtents(
contentExtent: contentExtent, contentExtent: _contentExtent,
containerExtent: _containerExtent, containerExtent: _containerExtent,
scrollOffset: scrollOffset scrollOffset: scrollOffset
)); ));
} }
void dispatchOnScrollStart() {
super.dispatchOnScrollStart();
config.scrollableListPainter?.scrollStarted();
}
void dispatchOnScroll() {
super.dispatchOnScroll();
if (config.scrollableListPainter != null)
config.scrollableListPainter.scrollOffset = scrollOffset;
}
void dispatchOnScrollEnd() {
super.dispatchOnScrollEnd();
config.scrollableListPainter?.scrollEnded();
}
Widget buildContent(BuildContext context) { Widget buildContent(BuildContext context) {
if (itemCount != _previousItemCount) { if (itemCount != _previousItemCount) {
_previousItemCount = itemCount; _previousItemCount = itemCount;
...@@ -508,7 +606,8 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ...@@ -508,7 +606,8 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends
itemExtent: config.itemExtent, itemExtent: config.itemExtent,
itemCount: itemCount, itemCount: itemCount,
direction: config.scrollDirection, direction: config.scrollDirection,
startOffset: scrollOffset - _leadingPadding startOffset: scrollOffset - _leadingPadding,
overlayPainter: config.scrollableListPainter
) )
) )
); );
...@@ -541,7 +640,8 @@ class ScrollableList<T> extends ScrollableWidgetList { ...@@ -541,7 +640,8 @@ class ScrollableList<T> extends ScrollableWidgetList {
this.itemBuilder, this.itemBuilder,
itemsWrap: false, itemsWrap: false,
double itemExtent, double itemExtent,
EdgeDims padding EdgeDims padding,
ScrollableListPainter scrollableListPainter
}) : super( }) : super(
key: key, key: key,
initialScrollOffset: initialScrollOffset, initialScrollOffset: initialScrollOffset,
...@@ -551,7 +651,9 @@ class ScrollableList<T> extends ScrollableWidgetList { ...@@ -551,7 +651,9 @@ class ScrollableList<T> extends ScrollableWidgetList {
snapAlignmentOffset: snapAlignmentOffset, snapAlignmentOffset: snapAlignmentOffset,
itemsWrap: itemsWrap, itemsWrap: itemsWrap,
itemExtent: itemExtent, itemExtent: itemExtent,
padding: padding); padding: padding,
scrollableListPainter: scrollableListPainter
);
final List<T> items; final List<T> items;
final ItemBuilder<T> itemBuilder; final ItemBuilder<T> itemBuilder;
......
name: flutter name: flutter
version: 0.0.3 version: 0.0.5
author: Flutter Authors <flutter-dev@googlegroups.com> author: Flutter Authors <flutter-dev@googlegroups.com>
description: A framework for writing Flutter applications description: A framework for writing Flutter applications
homepage: http://flutter.io homepage: http://flutter.io
dependencies: dependencies:
cassowary: '>=0.1.7 <0.2.0' cassowary: '>=0.1.7 <0.2.0'
material_design_icons: '>=0.0.3 <0.1.0' material_design_icons: '>=0.0.3 <0.1.0'
mojo_services: '>=0.2.0 <0.3.0' mojo_services: '>=0.3.0 <0.4.0'
mojo: '>=0.2.0 <0.3.0' mojo: '>=0.2.0 <0.3.0'
newton: '>=0.1.4 <0.2.0' newton: '>=0.1.4 <0.2.0'
sky_engine: '>=0.0.34 <0.1.0' sky_engine: 0.0.36
sky_services: '>=0.0.34 <0.1.0' sky_services: 0.0.36
sky_tools: '>=0.0.18 <0.1.0' sky_tools: '>=0.0.20 <0.1.0'
vector_math: '>=1.4.3 <2.0.0' vector_math: '>=1.4.3 <2.0.0'
intl: '>=0.12.4+2 <0.13.0' intl: '>=0.12.4+2 <0.13.0'
environment: environment:
......
# skysprites # Flutter Sprites
A sprite toolkit built on top of Flutter. A sprite toolkit built on top of Flutter.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
library skysprites; library flutter_sprites;
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
...@@ -20,29 +20,29 @@ import 'package:flutter/services.dart'; ...@@ -20,29 +20,29 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
part 'action.dart'; part 'src/action.dart';
part 'action_spline.dart'; part 'src/action_spline.dart';
part 'color_secuence.dart'; part 'src/color_secuence.dart';
part 'constraint.dart'; part 'src/constraint.dart';
part 'effect_line.dart'; part 'src/effect_line.dart';
part 'image_map.dart'; part 'src/image_map.dart';
part 'label.dart'; part 'src/label.dart';
part 'layer.dart'; part 'src/layer.dart';
part 'node.dart'; part 'src/node.dart';
part 'node3d.dart'; part 'src/node3d.dart';
part 'node_with_size.dart'; part 'src/node_with_size.dart';
part 'particle_system.dart'; part 'src/particle_system.dart';
part 'physics_body.dart'; part 'src/physics_body.dart';
part 'physics_joint.dart'; part 'src/physics_joint.dart';
part 'physics_node.dart'; part 'src/physics_node.dart';
part 'physics_shape.dart'; part 'src/physics_shape.dart';
part 'sound.dart'; part 'src/sound.dart';
part 'sound_manager.dart'; part 'src/sound_manager.dart';
part 'sprite.dart'; part 'src/sprite.dart';
part 'spritesheet.dart'; part 'src/spritesheet.dart';
part 'sprite_box.dart'; part 'src/sprite_box.dart';
part 'sprite_widget.dart'; part 'src/sprite_widget.dart';
part 'texture.dart'; part 'src/texture.dart';
part 'textured_line.dart'; part 'src/textured_line.dart';
part 'util.dart'; part 'src/util.dart';
part 'virtual_joystick.dart'; part 'src/virtual_joystick.dart';
part of skysprites; part of flutter_sprites;
typedef void ActionCallback(); typedef void ActionCallback();
......
part of skysprites; part of flutter_sprites;
Point _cardinalSplineAt(Point p0, Point p1, Point p2, Point p3, double tension, double t) { Point _cardinalSplineAt(Point p0, Point p1, Point p2, Point p3, double tension, double t) {
double t2 = t * t; double t2 = t * t;
......
part of skysprites; part of flutter_sprites;
/// A sequence of colors representing a gradient or a color transition over /// A sequence of colors representing a gradient or a color transition over
/// time. The sequence is represented by a list of [colors] and a list of /// time. The sequence is represented by a list of [colors] and a list of
......
part of skysprites; part of flutter_sprites;
/// A constraint limits or otherwise controls a [Node]'s properties, such as /// A constraint limits or otherwise controls a [Node]'s properties, such as
/// position or rotation. Add a list of constraints by setting the [Node]'s /// position or rotation. Add a list of constraints by setting the [Node]'s
......
part of skysprites; part of flutter_sprites;
enum EffectLineWidthMode { enum EffectLineWidthMode {
linear, linear,
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
part of skysprites; part of flutter_sprites;
class ImageMap { class ImageMap {
ImageMap(AssetBundle bundle) : _bundle = bundle; ImageMap(AssetBundle bundle) : _bundle = bundle;
......
part of skysprites; part of flutter_sprites;
/// Labels are used to display a string of text in a the node tree. To align /// Labels are used to display a string of text in a the node tree. To align
/// the label, the textAlign property of the [TextStyle] can be set. /// the label, the textAlign property of the [TextStyle] can be set.
......
part of skysprites; part of flutter_sprites;
/// A [Node] that provides an intermediate rendering surface in the sprite /// A [Node] that provides an intermediate rendering surface in the sprite
/// rendering tree. A [Layer] can be used to change the opacity, color, or to /// rendering tree. A [Layer] can be used to change the opacity, color, or to
......
part of skysprites; part of flutter_sprites;
double convertDegrees2Radians(double degrees) => degrees * math.PI/180.8; double convertDegrees2Radians(double degrees) => degrees * math.PI/180.8;
......
part of skysprites; part of flutter_sprites;
/// An node that transforms its children using a 3D perspective projection. This /// An node that transforms its children using a 3D perspective projection. This
/// node type can be used to create 3D flips and other similar effects. /// node type can be used to create 3D flips and other similar effects.
......
part of skysprites; part of flutter_sprites;
/// The super class of any [Node] that has a size. /// The super class of any [Node] that has a size.
/// ///
......
part of skysprites; part of flutter_sprites;
class _Particle { class _Particle {
Vector2 pos; Vector2 pos;
......
part of skysprites; part of flutter_sprites;
enum PhysicsBodyType { enum PhysicsBodyType {
static, static,
......
part of skysprites; part of flutter_sprites;
typedef void PhysicsJointBreakCallback(PhysicsJoint joint); typedef void PhysicsJointBreakCallback(PhysicsJoint joint);
......
part of skysprites; part of flutter_sprites;
enum PhysicsContactType { enum PhysicsContactType {
preSolve, preSolve,
......
part of skysprites; part of flutter_sprites;
abstract class PhysicsShape { abstract class PhysicsShape {
...@@ -32,7 +32,6 @@ class PhysicsShapeCircle extends PhysicsShape { ...@@ -32,7 +32,6 @@ class PhysicsShapeCircle extends PhysicsShape {
} }
class PhysicsShapePolygon extends PhysicsShape { class PhysicsShapePolygon extends PhysicsShape {
PhysicsShapePolygon(this.points); PhysicsShapePolygon(this.points);
final List<Point> points; final List<Point> points;
...@@ -53,6 +52,81 @@ class PhysicsShapePolygon extends PhysicsShape { ...@@ -53,6 +52,81 @@ class PhysicsShapePolygon extends PhysicsShape {
} }
} }
class PhysicsShapeBox extends PhysicsShape {
PhysicsShapeBox(
this.width,
this.height, [
this.center = Point.origin,
this.rotation = 0.0
]);
final double width;
final double height;
final Point center;
final double rotation;
box2d.Shape _createB2Shape(PhysicsNode node) {
box2d.PolygonShape shape = new box2d.PolygonShape();
shape.setAsBox(
width / node.b2WorldToNodeConversionFactor,
height / node.b2WorldToNodeConversionFactor,
new Vector2(
center.x / node.b2WorldToNodeConversionFactor,
center.y / node.b2WorldToNodeConversionFactor
),
radians(rotation)
);
return shape;
}
}
class PhysicsShapeChain extends PhysicsShape {
PhysicsShapeChain(this.points, [this.loop=false]);
final List<Point> points;
final bool loop;
box2d.Shape _createB2Shape(PhysicsNode node) {
List<Vector2> vectors = [];
for (Point point in points) {
Vector2 vec = new Vector2(
point.x / node.b2WorldToNodeConversionFactor,
point.y / node.b2WorldToNodeConversionFactor
);
vectors.add(vec);
}
box2d.ChainShape shape = new box2d.ChainShape();
if (loop)
shape.createLoop(vectors, vectors.length);
else
shape.createChain(vectors, vectors.length);
return shape;
}
}
class PhysicsShapeEdge extends PhysicsShape {
PhysicsShapeEdge(this.pointA, this.pointB);
final Point pointA;
final Point pointB;
box2d.Shape _createB2Shape(PhysicsNode node) {
box2d.EdgeShape shape = new box2d.EdgeShape();
shape.set(
new Vector2(
pointA.x / node.b2WorldToNodeConversionFactor,
pointA.y / node.b2WorldToNodeConversionFactor
),
new Vector2(
pointB.x / node.b2WorldToNodeConversionFactor,
pointB.y / node.b2WorldToNodeConversionFactor
)
);
return shape;
}
}
class PhysicsShapeGroup extends PhysicsShape { class PhysicsShapeGroup extends PhysicsShape {
PhysicsShapeGroup(this.shapes); PhysicsShapeGroup(this.shapes);
......
part of skysprites; part of flutter_sprites;
// TODO: The sound effects should probably use Android's SoundPool instead of // TODO: The sound effects should probably use Android's SoundPool instead of
// MediaPlayer as it is more efficient and flexible for playing back sound effects // MediaPlayer as it is more efficient and flexible for playing back sound effects
......
part of skysprites; part of flutter_sprites;
enum SoundFadeMode { enum SoundFadeMode {
crossFade, crossFade,
......
part of skysprites; part of flutter_sprites;
/// A Sprite is a [Node] that renders a bitmap image to the screen. /// A Sprite is a [Node] that renders a bitmap image to the screen.
class Sprite extends NodeWithSize with SpritePaint { class Sprite extends NodeWithSize with SpritePaint {
......
part of skysprites; part of flutter_sprites;
/// Options for setting up a [SpriteBox]. /// Options for setting up a [SpriteBox].
/// ///
......
part of skysprites; part of flutter_sprites;
/// A widget that uses a [SpriteBox] to render a sprite node tree to the screen. /// A widget that uses a [SpriteBox] to render a sprite node tree to the screen.
class SpriteWidget extends OneChildRenderObjectWidget { class SpriteWidget extends OneChildRenderObjectWidget {
......
part of skysprites; part of flutter_sprites;
/// A sprite sheet packs a number of smaller images into a single large image. /// A sprite sheet packs a number of smaller images into a single large image.
/// ///
......
part of skysprites; part of flutter_sprites;
/// A texture represents a rectangular area of an image and is typically used to draw a sprite to the screen. /// A texture represents a rectangular area of an image and is typically used to draw a sprite to the screen.
/// ///
......
part of skysprites; part of flutter_sprites;
class TexturedLine extends Node { class TexturedLine extends Node {
TexturedLine(List<Point> points, List<Color> colors, List<double> widths, [Texture texture, List<double> textureStops]) { TexturedLine(List<Point> points, List<Color> colors, List<double> widths, [Texture texture, List<double> textureStops]) {
......
part of skysprites; part of flutter_sprites;
math.Random _random = new math.Random(); math.Random _random = new math.Random();
......
part of skysprites; part of flutter_sprites;
class VirtualJoystick extends NodeWithSize { class VirtualJoystick extends NodeWithSize {
VirtualJoystick() : super(new Size(160.0, 160.0)) { VirtualJoystick() : super(new Size(160.0, 160.0)) {
......
name: flutter_sprites name: flutter_sprites
description: A sprite toolkit built on top of Flutter description: A sprite toolkit built on top of Flutter
version: 0.0.2 version: 0.0.3
author: Flutter Authors <flutter-dev@googlegroups.com> author: Flutter Authors <flutter-dev@googlegroups.com>
homepage: http://flutter.io homepage: http://flutter.io
dependencies: dependencies:
flutter: ">=0.0.3 <0.1.0" flutter: ">=0.0.5 <0.1.0"
sky_tools: ">=0.0.18 <0.1.0" sky_tools: ">=0.0.20 <0.1.0"
box2d: ">=0.2.0 <0.3.0" box2d: ">=0.2.0 <0.3.0"
import 'dart:ui' as ui; import 'dart:ui' as ui;
export 'dart:ui' show Point; import 'package:flutter/gestures.dart';
class TestPointerEvent extends ui.PointerEvent {
TestPointerEvent({
this.type,
this.pointer,
this.kind,
this.x,
this.y,
this.dx,
this.dy,
this.velocityX,
this.velocityY,
this.buttons,
this.down,
this.primary,
this.obscured,
this.pressure,
this.pressureMin,
this.pressureMax,
this.distance,
this.distanceMin,
this.distanceMax,
this.radiusMajor,
this.radiusMinor,
this.radiusMin,
this.radiusMax,
this.orientation,
this.tilt
});
// These are all of the PointerEvent members, but not all of Event. export 'dart:ui' show Point;
String type;
int pointer;
String kind;
double x;
double y;
double dx;
double dy;
double velocityX;
double velocityY;
int buttons;
bool down;
bool primary;
bool obscured;
double pressure;
double pressureMin;
double pressureMax;
double distance;
double distanceMin;
double distanceMax;
double radiusMajor;
double radiusMinor;
double radiusMin;
double radiusMax;
double orientation;
double tilt;
}
class TestPointer { class TestPointer {
TestPointer([ this.pointer = 1 ]); TestPointer([ this.pointer = 1 ]);
...@@ -66,11 +11,11 @@ class TestPointer { ...@@ -66,11 +11,11 @@ class TestPointer {
bool isDown = false; bool isDown = false;
ui.Point location; ui.Point location;
ui.PointerEvent down([ui.Point newLocation = ui.Point.origin ]) { PointerInputEvent down([ui.Point newLocation = ui.Point.origin ]) {
assert(!isDown); assert(!isDown);
isDown = true; isDown = true;
location = newLocation; location = newLocation;
return new TestPointerEvent( return new PointerInputEvent(
type: 'pointerdown', type: 'pointerdown',
pointer: pointer, pointer: pointer,
x: location.x, x: location.x,
...@@ -78,11 +23,11 @@ class TestPointer { ...@@ -78,11 +23,11 @@ class TestPointer {
); );
} }
ui.PointerEvent move([ui.Point newLocation = ui.Point.origin ]) { PointerInputEvent move([ui.Point newLocation = ui.Point.origin ]) {
assert(isDown); assert(isDown);
ui.Offset delta = newLocation - location; ui.Offset delta = newLocation - location;
location = newLocation; location = newLocation;
return new TestPointerEvent( return new PointerInputEvent(
type: 'pointermove', type: 'pointermove',
pointer: pointer, pointer: pointer,
x: newLocation.x, x: newLocation.x,
...@@ -92,10 +37,10 @@ class TestPointer { ...@@ -92,10 +37,10 @@ class TestPointer {
); );
} }
ui.PointerEvent up() { PointerInputEvent up() {
assert(isDown); assert(isDown);
isDown = false; isDown = false;
return new TestPointerEvent( return new PointerInputEvent(
type: 'pointerup', type: 'pointerup',
pointer: pointer, pointer: pointer,
x: location.x, x: location.x,
...@@ -103,10 +48,10 @@ class TestPointer { ...@@ -103,10 +48,10 @@ class TestPointer {
); );
} }
ui.PointerEvent cancel() { PointerInputEvent cancel() {
assert(isDown); assert(isDown);
isDown = false; isDown = false;
return new TestPointerEvent( return new PointerInputEvent(
type: 'pointercancel', type: 'pointercancel',
pointer: pointer, pointer: pointer,
x: location.x, x: location.x,
......
...@@ -2,16 +2,14 @@ import 'package:quiver/testing/async.dart'; ...@@ -2,16 +2,14 @@ import 'package:quiver/testing/async.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import '../engine/mock_events.dart'; final PointerInputEvent down = new PointerInputEvent(
final TestPointerEvent down = new TestPointerEvent(
pointer: 5, pointer: 5,
type: 'pointerdown', type: 'pointerdown',
x: 10.0, x: 10.0,
y: 10.0 y: 10.0
); );
final TestPointerEvent up = new TestPointerEvent( final PointerInputEvent up = new PointerInputEvent(
pointer: 5, pointer: 5,
type: 'pointerup', type: 'pointerup',
x: 11.0, x: 11.0,
......
import 'dart:ui' as ui;
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -8,7 +6,7 @@ import '../engine/mock_events.dart'; ...@@ -8,7 +6,7 @@ import '../engine/mock_events.dart';
void main() { void main() {
test('Should route pointers', () { test('Should route pointers', () {
bool callbackRan = false; bool callbackRan = false;
void callback(ui.PointerEvent event) { void callback(PointerInputEvent event) {
callbackRan = true; callbackRan = true;
} }
......
...@@ -36,7 +36,7 @@ void main() { ...@@ -36,7 +36,7 @@ void main() {
TestPointer pointer1 = new TestPointer(1); TestPointer pointer1 = new TestPointer(1);
ui.PointerEvent down = pointer1.down(new Point(10.0, 10.0)); PointerInputEvent down = pointer1.down(new Point(10.0, 10.0));
scale.addPointer(down); scale.addPointer(down);
tap.addPointer(down); tap.addPointer(down);
...@@ -67,7 +67,7 @@ void main() { ...@@ -67,7 +67,7 @@ void main() {
// Two-finger scaling // Two-finger scaling
TestPointer pointer2 = new TestPointer(2); TestPointer pointer2 = new TestPointer(2);
ui.PointerEvent down2 = pointer2.down(new Point(10.0, 20.0)); PointerInputEvent down2 = pointer2.down(new Point(10.0, 20.0));
scale.addPointer(down2); scale.addPointer(down2);
tap.addPointer(down2); tap.addPointer(down2);
GestureArena.instance.close(2); GestureArena.instance.close(2);
...@@ -100,7 +100,7 @@ void main() { ...@@ -100,7 +100,7 @@ void main() {
// Three-finger scaling // Three-finger scaling
TestPointer pointer3 = new TestPointer(3); TestPointer pointer3 = new TestPointer(3);
ui.PointerEvent down3 = pointer3.down(new Point(25.0, 35.0)); PointerInputEvent down3 = pointer3.down(new Point(25.0, 35.0));
scale.addPointer(down3); scale.addPointer(down3);
tap.addPointer(down3); tap.addPointer(down3);
GestureArena.instance.close(3); GestureArena.instance.close(3);
......
...@@ -32,7 +32,7 @@ void main() { ...@@ -32,7 +32,7 @@ void main() {
}; };
TestPointer pointer = new TestPointer(5); TestPointer pointer = new TestPointer(5);
ui.PointerEvent down = pointer.down(new Point(10.0, 10.0)); PointerInputEvent down = pointer.down(new Point(10.0, 10.0));
pan.addPointer(down); pan.addPointer(down);
tap.addPointer(down); tap.addPointer(down);
GestureArena.instance.close(5); GestureArena.instance.close(5);
......
...@@ -2,16 +2,14 @@ import 'package:quiver/testing/async.dart'; ...@@ -2,16 +2,14 @@ import 'package:quiver/testing/async.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import '../engine/mock_events.dart'; final PointerInputEvent down = new PointerInputEvent(
final TestPointerEvent down = new TestPointerEvent(
pointer: 5, pointer: 5,
type: 'pointerdown', type: 'pointerdown',
x: 10.0, x: 10.0,
y: 10.0 y: 10.0
); );
final TestPointerEvent up = new TestPointerEvent( final PointerInputEvent up = new PointerInputEvent(
pointer: 5, pointer: 5,
type: 'pointerup', type: 'pointerup',
x: 11.0, x: 11.0,
......
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import '../engine/mock_events.dart';
void main() { void main() {
test('Should recognize tap', () { test('Should recognize tap', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
...@@ -13,7 +11,7 @@ void main() { ...@@ -13,7 +11,7 @@ void main() {
tapRecognized = true; tapRecognized = true;
}; };
TestPointerEvent down = new TestPointerEvent( PointerInputEvent down = new PointerInputEvent(
pointer: 5, pointer: 5,
type: 'pointerdown', type: 'pointerdown',
x: 10.0, x: 10.0,
...@@ -26,7 +24,7 @@ void main() { ...@@ -26,7 +24,7 @@ void main() {
router.route(down); router.route(down);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
TestPointerEvent up = new TestPointerEvent( PointerInputEvent up = new PointerInputEvent(
pointer: 5, pointer: 5,
type: 'pointerup', type: 'pointerup',
x: 11.0, x: 11.0,
......
import 'dart:ui' as ui;
import 'package:flutter/animation.dart'; import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:quiver/testing/async.dart'; import 'package:quiver/testing/async.dart';
...@@ -159,13 +158,13 @@ class WidgetTester { ...@@ -159,13 +158,13 @@ class WidgetTester {
_dispatchEvent(p.up(), result); _dispatchEvent(p.up(), result);
} }
void dispatchEvent(ui.Event event, Point location) { void dispatchEvent(InputEvent event, Point location) {
_dispatchEvent(event, _hitTest(location)); _dispatchEvent(event, _hitTest(location));
} }
HitTestResult _hitTest(Point location) => WidgetFlutterBinding.instance.hitTest(location); HitTestResult _hitTest(Point location) => WidgetFlutterBinding.instance.hitTest(location);
void _dispatchEvent(ui.Event event, HitTestResult result) { void _dispatchEvent(InputEvent event, HitTestResult result) {
WidgetFlutterBinding.instance.dispatchEvent(event, result); WidgetFlutterBinding.instance.dispatchEvent(event, result);
} }
......
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