Merge remote-tracking branch 'upstream/master' into arena_sweep
This commit is contained in:
commit
14c9a2c755
@ -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';
|
|||||||
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;
|
|||||||
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';
|
|||||||
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';
|
|||||||
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';
|
|||||||
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';
|
|||||||
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';
|
|||||||
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)
|
||||||
|
@ -1,9 +1,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 '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> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleToolbarPointerDown(ui.PointerEvent event) {
|
void handleToolbarPointerDown(PointerInputEvent event) {
|
||||||
setState(() {
|
setState(() {
|
||||||
resetGame();
|
resetGame();
|
||||||
});
|
});
|
||||||
|
@ -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 {
|
|||||||
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 @@
|
|||||||
// 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 {
|
|||||||
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 @@
|
|||||||
// 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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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)];
|
||||||
|
12
examples/widgets/README
Normal file
12
examples/widgets/README
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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.
|
67
examples/widgets/scrollbar.dart
Normal file
67
examples/widgets/scrollbar.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// 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;
|
|||||||
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';
|
|||||||
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;
|
|||||||
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);
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
|||||||
}) : 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> {
|
|||||||
}) : 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> {
|
|||||||
}) : 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;
|
||||||
}
|
}
|
||||||
|
70
packages/flutter/lib/src/gestures/events.dart
Normal file
70
packages/flutter/lib/src/gestures/events.dart
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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 @@
|
|||||||
// 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 {
|
|||||||
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 @@
|
|||||||
// 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 {
|
|||||||
|
|
||||||
/// 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 {
|
|||||||
/// 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;
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
|||||||
// 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 {
|
|||||||
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 @@
|
|||||||
// 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 {
|
|||||||
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 {
|
|||||||
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 @@
|
|||||||
// 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> {
|
|||||||
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;
|
||||||
|
82
packages/flutter/lib/src/material/scrollbar_painter.dart
Normal file
82
packages/flutter/lib/src/material/scrollbar_painter.dart
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// 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';
|
|||||||
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 {
|
|||||||
|
|
||||||
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) {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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) {
|
void _handlePointerInputEvent(PointerInputEvent event) {
|
||||||
Point position = new Point(event.x, event.y);
|
HitTestResult result = _resultForPointer[event.pointer];
|
||||||
|
|
||||||
_PointerState state = _stateForPointer[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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 @@
|
|||||||
// 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;
|
|||||||
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 {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
|||||||
// 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 @@
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 @@
|
|||||||
// 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 {
|
|||||||
|
|
||||||
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 @@
|
|||||||
// 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 {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 @@
|
|||||||
// 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> {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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> {
|
|||||||
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> {
|
|||||||
|
|
||||||
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> {
|
|||||||
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> {
|
|||||||
_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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
|||||||
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 {
|
|||||||
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
|
|||||||
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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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;
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
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:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# skysprites
|
# Flutter Sprites
|
||||||
|
|
||||||
A sprite toolkit built on top of Flutter.
|
A sprite toolkit built on top of Flutter.
|
||||||
|
|
||||||
|
48
packages/flutter_sprites/lib/flutter_sprites.dart
Normal file
48
packages/flutter_sprites/lib/flutter_sprites.dart
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
library flutter_sprites;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
import 'package:box2d/box2d.dart' as box2d;
|
||||||
|
import 'package:mojo/core.dart';
|
||||||
|
import 'package:sky_services/media/media.mojom.dart';
|
||||||
|
import 'package:flutter/animation.dart';
|
||||||
|
import 'package:flutter/painting.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
|
part 'src/action.dart';
|
||||||
|
part 'src/action_spline.dart';
|
||||||
|
part 'src/color_secuence.dart';
|
||||||
|
part 'src/constraint.dart';
|
||||||
|
part 'src/effect_line.dart';
|
||||||
|
part 'src/image_map.dart';
|
||||||
|
part 'src/label.dart';
|
||||||
|
part 'src/layer.dart';
|
||||||
|
part 'src/node.dart';
|
||||||
|
part 'src/node3d.dart';
|
||||||
|
part 'src/node_with_size.dart';
|
||||||
|
part 'src/particle_system.dart';
|
||||||
|
part 'src/physics_body.dart';
|
||||||
|
part 'src/physics_joint.dart';
|
||||||
|
part 'src/physics_node.dart';
|
||||||
|
part 'src/physics_shape.dart';
|
||||||
|
part 'src/sound.dart';
|
||||||
|
part 'src/sound_manager.dart';
|
||||||
|
part 'src/sprite.dart';
|
||||||
|
part 'src/spritesheet.dart';
|
||||||
|
part 'src/sprite_box.dart';
|
||||||
|
part 'src/sprite_widget.dart';
|
||||||
|
part 'src/texture.dart';
|
||||||
|
part 'src/textured_line.dart';
|
||||||
|
part 'src/util.dart';
|
||||||
|
part 'src/virtual_joystick.dart';
|
@ -1,65 +0,0 @@
|
|||||||
part of skysprites;
|
|
||||||
|
|
||||||
abstract class PhysicsShape {
|
|
||||||
|
|
||||||
box2d.Shape _b2Shape;
|
|
||||||
|
|
||||||
Object userObject;
|
|
||||||
|
|
||||||
box2d.Shape getB2Shape(PhysicsNode node) {
|
|
||||||
if (_b2Shape == null) {
|
|
||||||
_b2Shape = _createB2Shape(node);
|
|
||||||
}
|
|
||||||
return _b2Shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
box2d.Shape _createB2Shape(PhysicsNode node);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhysicsShapeCircle extends PhysicsShape {
|
|
||||||
PhysicsShapeCircle(this.point, this.radius);
|
|
||||||
|
|
||||||
final Point point;
|
|
||||||
final double radius;
|
|
||||||
|
|
||||||
box2d.Shape _createB2Shape(PhysicsNode node) {
|
|
||||||
box2d.CircleShape shape = new box2d.CircleShape();
|
|
||||||
shape.p.x = point.x / node.b2WorldToNodeConversionFactor;
|
|
||||||
shape.p.y = point.y / node.b2WorldToNodeConversionFactor;
|
|
||||||
shape.radius = radius / node.b2WorldToNodeConversionFactor;
|
|
||||||
return shape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhysicsShapePolygon extends PhysicsShape {
|
|
||||||
|
|
||||||
PhysicsShapePolygon(this.points);
|
|
||||||
|
|
||||||
final List<Point> points;
|
|
||||||
|
|
||||||
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.PolygonShape shape = new box2d.PolygonShape();
|
|
||||||
shape.set(vectors, vectors.length);
|
|
||||||
return shape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhysicsShapeGroup extends PhysicsShape {
|
|
||||||
|
|
||||||
PhysicsShapeGroup(this.shapes);
|
|
||||||
|
|
||||||
final List<PhysicsShape> shapes;
|
|
||||||
|
|
||||||
box2d.Shape _createB2Shape(PhysicsNode node) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
library skysprites;
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:math' as math;
|
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'dart:ui' as ui;
|
|
||||||
|
|
||||||
import 'package:box2d/box2d.dart' as box2d;
|
|
||||||
import 'package:mojo/core.dart';
|
|
||||||
import 'package:sky_services/media/media.mojom.dart';
|
|
||||||
import 'package:flutter/animation.dart';
|
|
||||||
import 'package:flutter/painting.dart';
|
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
|
||||||
|
|
||||||
part 'action.dart';
|
|
||||||
part 'action_spline.dart';
|
|
||||||
part 'color_secuence.dart';
|
|
||||||
part 'constraint.dart';
|
|
||||||
part 'effect_line.dart';
|
|
||||||
part 'image_map.dart';
|
|
||||||
part 'label.dart';
|
|
||||||
part 'layer.dart';
|
|
||||||
part 'node.dart';
|
|
||||||
part 'node3d.dart';
|
|
||||||
part 'node_with_size.dart';
|
|
||||||
part 'particle_system.dart';
|
|
||||||
part 'physics_body.dart';
|
|
||||||
part 'physics_joint.dart';
|
|
||||||
part 'physics_node.dart';
|
|
||||||
part 'physics_shape.dart';
|
|
||||||
part 'sound.dart';
|
|
||||||
part 'sound_manager.dart';
|
|
||||||
part 'sprite.dart';
|
|
||||||
part 'spritesheet.dart';
|
|
||||||
part 'sprite_box.dart';
|
|
||||||
part 'sprite_widget.dart';
|
|
||||||
part 'texture.dart';
|
|
||||||
part 'textured_line.dart';
|
|
||||||
part 'util.dart';
|
|
||||||
part 'virtual_joystick.dart';
|
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
typedef void ActionCallback();
|
typedef void ActionCallback();
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
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;
|
@ -1,4 +1,4 @@
|
|||||||
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
|
@ -1,4 +1,4 @@
|
|||||||
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
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
enum EffectLineWidthMode {
|
enum EffectLineWidthMode {
|
||||||
linear,
|
linear,
|
@ -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;
|
@ -1,4 +1,4 @@
|
|||||||
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.
|
@ -1,4 +1,4 @@
|
|||||||
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
|
@ -1,4 +1,4 @@
|
|||||||
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;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
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.
|
@ -1,4 +1,4 @@
|
|||||||
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.
|
||||||
///
|
///
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
class _Particle {
|
class _Particle {
|
||||||
Vector2 pos;
|
Vector2 pos;
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
enum PhysicsBodyType {
|
enum PhysicsBodyType {
|
||||||
static,
|
static,
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
typedef void PhysicsJointBreakCallback(PhysicsJoint joint);
|
typedef void PhysicsJointBreakCallback(PhysicsJoint joint);
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
enum PhysicsContactType {
|
enum PhysicsContactType {
|
||||||
preSolve,
|
preSolve,
|
139
packages/flutter_sprites/lib/src/physics_shape.dart
Normal file
139
packages/flutter_sprites/lib/src/physics_shape.dart
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
part of flutter_sprites;
|
||||||
|
|
||||||
|
abstract class PhysicsShape {
|
||||||
|
|
||||||
|
box2d.Shape _b2Shape;
|
||||||
|
|
||||||
|
Object userObject;
|
||||||
|
|
||||||
|
box2d.Shape getB2Shape(PhysicsNode node) {
|
||||||
|
if (_b2Shape == null) {
|
||||||
|
_b2Shape = _createB2Shape(node);
|
||||||
|
}
|
||||||
|
return _b2Shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
box2d.Shape _createB2Shape(PhysicsNode node);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PhysicsShapeCircle extends PhysicsShape {
|
||||||
|
PhysicsShapeCircle(this.point, this.radius);
|
||||||
|
|
||||||
|
final Point point;
|
||||||
|
final double radius;
|
||||||
|
|
||||||
|
box2d.Shape _createB2Shape(PhysicsNode node) {
|
||||||
|
box2d.CircleShape shape = new box2d.CircleShape();
|
||||||
|
shape.p.x = point.x / node.b2WorldToNodeConversionFactor;
|
||||||
|
shape.p.y = point.y / node.b2WorldToNodeConversionFactor;
|
||||||
|
shape.radius = radius / node.b2WorldToNodeConversionFactor;
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PhysicsShapePolygon extends PhysicsShape {
|
||||||
|
PhysicsShapePolygon(this.points);
|
||||||
|
|
||||||
|
final List<Point> points;
|
||||||
|
|
||||||
|
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.PolygonShape shape = new box2d.PolygonShape();
|
||||||
|
shape.set(vectors, vectors.length);
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
PhysicsShapeGroup(this.shapes);
|
||||||
|
|
||||||
|
final List<PhysicsShape> shapes;
|
||||||
|
|
||||||
|
box2d.Shape _createB2Shape(PhysicsNode node) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
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
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
enum SoundFadeMode {
|
enum SoundFadeMode {
|
||||||
crossFade,
|
crossFade,
|
@ -1,4 +1,4 @@
|
|||||||
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 {
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
/// Options for setting up a [SpriteBox].
|
/// Options for setting up a [SpriteBox].
|
||||||
///
|
///
|
@ -1,4 +1,4 @@
|
|||||||
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 {
|
@ -1,4 +1,4 @@
|
|||||||
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.
|
||||||
///
|
///
|
@ -1,4 +1,4 @@
|
|||||||
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.
|
||||||
///
|
///
|
@ -1,4 +1,4 @@
|
|||||||
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]) {
|
@ -1,4 +1,4 @@
|
|||||||
part of skysprites;
|
part of flutter_sprites;
|
||||||
|
|
||||||
|
|
||||||
math.Random _random = new math.Random();
|
math.Random _random = new math.Random();
|
@ -1,4 +1,4 @@
|
|||||||
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)) {
|
@ -1,9 +1,9 @@
|
|||||||
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"
|
||||||
|
@ -1,64 +1,9 @@
|
|||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
|
||||||
export 'dart:ui' show Point;
|
export 'dart:ui' show Point;
|
||||||
|
|
||||||
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.
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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';
|
|||||||
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,
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
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';
|
|||||||
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() {
|
|||||||
|
|
||||||
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() {
|
|||||||
|
|
||||||
// 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() {
|
|||||||
|
|
||||||
// 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() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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';
|
|||||||
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,
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
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 {
|
|||||||
_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user