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
|
||||
individual Dart application package. If you wish to run them with `sky_tool`
|
||||
then you will want to run `pub get` inside their directory before running
|
||||
`./packages/sky/sky_tool start`.
|
||||
individual Dart application package.
|
||||
|
||||
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."
|
||||
|
||||
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.
|
||||
|
||||
3. *Widgets.* The [widgets app](widgets) contains a number of Flutter widgets so
|
||||
you can experiment with them in a simple container.
|
||||
- *Widgets.* The [widget apps](widgets) demonstrate a number of Flutter widgets
|
||||
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/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:skysprites/skysprites.dart';
|
||||
import 'package:flutter_sprites/flutter_sprites.dart';
|
||||
|
||||
AssetBundle _initBundle() {
|
||||
if (rootBundle != null)
|
||||
|
@ -5,7 +5,7 @@ import 'dart:math' as math;
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
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';
|
||||
|
||||
part 'custom_actions.dart';
|
||||
|
@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:skysprites/skysprites.dart';
|
||||
import 'package:flutter_sprites/flutter_sprites.dart';
|
||||
|
||||
import 'game_demo.dart';
|
||||
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:skysprites/skysprites.dart';
|
||||
import 'package:flutter_sprites/flutter_sprites.dart';
|
||||
|
||||
AssetBundle _initBundle() {
|
||||
if (rootBundle != null)
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:skysprites/skysprites.dart';
|
||||
import 'package:flutter_sprites/flutter_sprites.dart';
|
||||
|
||||
AssetBundle _initBundle() {
|
||||
if (rootBundle != null)
|
||||
|
@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:skysprites/skysprites.dart';
|
||||
import 'package:flutter_sprites/flutter_sprites.dart';
|
||||
|
||||
AssetBundle _initBundle() {
|
||||
if (rootBundle != null)
|
||||
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:skysprites/skysprites.dart';
|
||||
import 'package:flutter_sprites/flutter_sprites.dart';
|
||||
|
||||
AssetBundle _initBundle() {
|
||||
if (rootBundle != null)
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@ -85,7 +85,7 @@ class MineDiggerState extends State<MineDigger> {
|
||||
}
|
||||
|
||||
PointerEventListener _pointerDownHandlerFor(int posX, int posY) {
|
||||
return (ui.PointerEvent event) {
|
||||
return (PointerInputEvent event) {
|
||||
if (event.buttons == 1) {
|
||||
probe(posX, posY);
|
||||
} else if (event.buttons == 2) {
|
||||
@ -190,7 +190,7 @@ class MineDiggerState extends State<MineDigger> {
|
||||
);
|
||||
}
|
||||
|
||||
void handleToolbarPointerDown(ui.PointerEvent event) {
|
||||
void handleToolbarPointerDown(PointerInputEvent event) {
|
||||
setState(() {
|
||||
resetGame();
|
||||
});
|
||||
|
@ -3,9 +3,9 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
const double kTwoPi = 2 * math.PI;
|
||||
|
||||
@ -518,7 +518,7 @@ class RenderSolidColor extends RenderDecoratedSector {
|
||||
deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
|
||||
}
|
||||
|
||||
void handleEvent(ui.Event event, HitTestEntry entry) {
|
||||
void handleEvent(InputEvent event, HitTestEntry entry) {
|
||||
if (event.type == 'pointerdown')
|
||||
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
|
||||
else if (event.type == 'pointerup')
|
||||
|
@ -2,9 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
class RenderSolidColorBox extends RenderDecoratedBox {
|
||||
final Size desiredSize;
|
||||
@ -42,7 +41,7 @@ class RenderSolidColorBox extends RenderDecoratedBox {
|
||||
size = constraints.constrain(desiredSize);
|
||||
}
|
||||
|
||||
void handleEvent(ui.Event event, BoxHitTestEntry entry) {
|
||||
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
|
||||
if (event.type == 'pointerdown')
|
||||
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
|
||||
else if (event.type == 'pointerup')
|
||||
|
@ -2,10 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
// Material design colors. :p
|
||||
List<Color> kColors = [
|
||||
@ -24,7 +23,7 @@ class Dot {
|
||||
|
||||
Dot({ Color color }) : _paint = new Paint()..color = color;
|
||||
|
||||
void update(ui.PointerEvent event) {
|
||||
void update(PointerInputEvent event) {
|
||||
position = new Point(event.x, event.y);
|
||||
radius = 5 + (95 * event.pressure);
|
||||
}
|
||||
@ -39,8 +38,8 @@ class RenderTouchDemo extends RenderBox {
|
||||
|
||||
RenderTouchDemo();
|
||||
|
||||
void handleEvent(ui.Event event, BoxHitTestEntry entry) {
|
||||
if (event is ui.PointerEvent) {
|
||||
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
|
||||
if (event is PointerInputEvent) {
|
||||
switch (event.type) {
|
||||
case 'pointerdown':
|
||||
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/constants.dart';
|
||||
export 'src/gestures/drag.dart';
|
||||
export 'src/gestures/events.dart';
|
||||
export 'src/gestures/long_press.dart';
|
||||
export 'src/gestures/pointer_router.dart';
|
||||
export 'src/gestures/recognizer.dart';
|
||||
|
@ -33,6 +33,7 @@ export 'src/material/progress_indicator.dart';
|
||||
export 'src/material/radio.dart';
|
||||
export 'src/material/raised_button.dart';
|
||||
export 'src/material/scaffold.dart';
|
||||
export 'src/material/scrollbar_painter.dart';
|
||||
export 'src/material/shadows.dart';
|
||||
export 'src/material/snack_bar.dart';
|
||||
export 'src/material/switch.dart';
|
||||
|
@ -7,6 +7,7 @@ import 'dart:ui' as ui;
|
||||
import 'arena.dart';
|
||||
import 'recognizer.dart';
|
||||
import 'constants.dart';
|
||||
import 'events.dart';
|
||||
|
||||
enum DragState {
|
||||
ready,
|
||||
@ -24,7 +25,7 @@ typedef void GesturePanEndCallback(ui.Offset velocity);
|
||||
|
||||
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) {
|
||||
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 get _initialPendingDragDelta;
|
||||
T _getDragDelta(ui.PointerEvent event);
|
||||
T _getDragDelta(PointerInputEvent event);
|
||||
bool get _hasSufficientPendingDragDeltaToAccept;
|
||||
|
||||
final ui.VelocityTracker _velocityTracker = new ui.VelocityTracker();
|
||||
|
||||
void addPointer(ui.PointerEvent event) {
|
||||
void addPointer(PointerInputEvent event) {
|
||||
startTrackingPointer(event.pointer);
|
||||
if (_state == DragState.ready) {
|
||||
_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);
|
||||
if (event.type == 'pointermove') {
|
||||
_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);
|
||||
|
||||
double get _initialPendingDragDelta => 0.0;
|
||||
double _getDragDelta(ui.PointerEvent event) => event.dy;
|
||||
double _getDragDelta(PointerInputEvent event) => event.dy;
|
||||
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
|
||||
}
|
||||
|
||||
@ -133,7 +134,7 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
||||
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd);
|
||||
|
||||
double get _initialPendingDragDelta => 0.0;
|
||||
double _getDragDelta(ui.PointerEvent event) => event.dx;
|
||||
double _getDragDelta(PointerInputEvent event) => event.dx;
|
||||
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);
|
||||
|
||||
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 {
|
||||
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
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'arena.dart';
|
||||
import 'constants.dart';
|
||||
import 'events.dart';
|
||||
import 'pointer_router.dart';
|
||||
import 'recognizer.dart';
|
||||
|
||||
@ -22,7 +21,7 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
onLongPress();
|
||||
}
|
||||
|
||||
void handlePrimaryPointer(ui.PointerEvent event) {
|
||||
void handlePrimaryPointer(PointerInputEvent event) {
|
||||
if (event.type == 'pointerup')
|
||||
resolve(GestureDisposition.rejected);
|
||||
}
|
||||
|
@ -2,18 +2,18 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
import 'events.dart';
|
||||
|
||||
/// A callback that receives a [ui.PointerEvent]
|
||||
typedef void PointerRoute(ui.PointerEvent event);
|
||||
/// A callback that receives a [PointerInputEvent]
|
||||
typedef void PointerRoute(PointerInputEvent event);
|
||||
|
||||
/// A routing table for [ui.PointerEvent] events.
|
||||
/// A routing table for [PointerInputEvent] events.
|
||||
class PointerRouter {
|
||||
final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>();
|
||||
|
||||
/// 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.
|
||||
void addRoute(int pointer, PointerRoute route) {
|
||||
List<PointerRoute> routes = _routeMap.putIfAbsent(pointer, () => new List<PointerRoute>());
|
||||
@ -23,7 +23,7 @@ class PointerRouter {
|
||||
|
||||
/// 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.
|
||||
void removeRoute(int pointer, PointerRoute route) {
|
||||
assert(_routeMap.containsKey(pointer));
|
||||
@ -37,7 +37,7 @@ class PointerRouter {
|
||||
/// Call the routes registed for this pointer event.
|
||||
///
|
||||
/// 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];
|
||||
if (routes == null)
|
||||
return;
|
||||
|
@ -7,6 +7,7 @@ import 'dart:ui' as ui;
|
||||
|
||||
import 'arena.dart';
|
||||
import 'constants.dart';
|
||||
import 'events.dart';
|
||||
import 'pointer_router.dart';
|
||||
|
||||
export 'pointer_router.dart' show PointerRouter;
|
||||
@ -22,9 +23,9 @@ abstract class GestureRecognizer extends GestureArenaMember {
|
||||
final Set<int> _trackedPointers = new Set<int>();
|
||||
|
||||
/// 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 rejectGesture(int pointer) { }
|
||||
void didStopTrackingLastPointer(int pointer);
|
||||
@ -58,7 +59,7 @@ abstract class GestureRecognizer extends GestureArenaMember {
|
||||
didStopTrackingLastPointer(pointer);
|
||||
}
|
||||
|
||||
void stopTrackingIfPointerNoLongerDown(ui.PointerEvent event) {
|
||||
void stopTrackingIfPointerNoLongerDown(PointerInputEvent event) {
|
||||
if (event.type == 'pointerup' || event.type == 'pointercancel')
|
||||
stopTrackingPointer(event.pointer);
|
||||
}
|
||||
@ -71,7 +72,7 @@ enum GestureRecognizerState {
|
||||
defunct
|
||||
}
|
||||
|
||||
ui.Point _getPoint(ui.PointerEvent event) {
|
||||
ui.Point _getPoint(PointerInputEvent event) {
|
||||
return new ui.Point(event.x, event.y);
|
||||
}
|
||||
|
||||
@ -86,7 +87,7 @@ abstract class PrimaryPointerGestureRecognizer extends GestureRecognizer {
|
||||
ui.Point initialPosition;
|
||||
Timer _timer;
|
||||
|
||||
void addPointer(ui.PointerEvent event) {
|
||||
void addPointer(PointerInputEvent event) {
|
||||
startTrackingPointer(event.pointer);
|
||||
if (state == GestureRecognizerState.ready) {
|
||||
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);
|
||||
if (state == GestureRecognizerState.possible && event.pointer == primaryPointer) {
|
||||
// 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.
|
||||
void handlePrimaryPointer(ui.PointerEvent event);
|
||||
void handlePrimaryPointer(PointerInputEvent event);
|
||||
|
||||
/// 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;
|
||||
return offset.distance;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import 'dart:ui' as ui;
|
||||
import 'arena.dart';
|
||||
import 'recognizer.dart';
|
||||
import 'constants.dart';
|
||||
import 'events.dart';
|
||||
|
||||
enum ScaleState {
|
||||
ready,
|
||||
@ -35,7 +36,7 @@ class ScaleGestureRecognizer extends GestureRecognizer {
|
||||
|
||||
double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0;
|
||||
|
||||
void addPointer(ui.PointerEvent event) {
|
||||
void addPointer(PointerInputEvent event) {
|
||||
startTrackingPointer(event.pointer);
|
||||
if (_state == ScaleState.ready) {
|
||||
_state = ScaleState.possible;
|
||||
@ -45,7 +46,7 @@ class ScaleGestureRecognizer extends GestureRecognizer {
|
||||
}
|
||||
}
|
||||
|
||||
void handleEvent(ui.PointerEvent event) {
|
||||
void handleEvent(PointerInputEvent event) {
|
||||
assert(_state != ScaleState.ready);
|
||||
bool configChanged = false;
|
||||
switch(event.type) {
|
||||
|
@ -2,10 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'arena.dart';
|
||||
import 'constants.dart';
|
||||
import 'events.dart';
|
||||
import 'recognizer.dart';
|
||||
|
||||
typedef void GestureShowPressCallback();
|
||||
@ -23,7 +22,7 @@ class ShowPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
onShowPress();
|
||||
}
|
||||
|
||||
void handlePrimaryPointer(ui.PointerEvent event) {
|
||||
void handlePrimaryPointer(PointerInputEvent event) {
|
||||
if (event.type == 'pointerup')
|
||||
resolve(GestureDisposition.rejected);
|
||||
}
|
||||
|
@ -2,9 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'arena.dart';
|
||||
import 'events.dart';
|
||||
import 'recognizer.dart';
|
||||
|
||||
typedef void GestureTapCallback();
|
||||
@ -17,7 +16,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
GestureTapCallback onTapDown;
|
||||
GestureTapCallback onTapCancel;
|
||||
|
||||
void handlePrimaryPointer(ui.PointerEvent event) {
|
||||
void handlePrimaryPointer(PointerInputEvent event) {
|
||||
if (event.type == 'pointerdown') {
|
||||
if (onTapDown != null)
|
||||
onTapDown();
|
||||
|
@ -137,7 +137,7 @@ class _RenderInkWell extends RenderProxyBox {
|
||||
TapGestureRecognizer _tap;
|
||||
LongPressGestureRecognizer _longPress;
|
||||
|
||||
void handleEvent(ui.Event event, BoxHitTestEntry entry) {
|
||||
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
|
||||
if (event.type == 'pointerdown' && (_tap != null || _longPress != null)) {
|
||||
_tap?.addPointer(event);
|
||||
_longPress?.addPointer(event);
|
||||
|
@ -2,8 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -56,7 +55,7 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _backHandler(ui.Event event) {
|
||||
void _backHandler(InputEvent event) {
|
||||
assert(mounted);
|
||||
if (event.type == 'back') {
|
||||
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 'package:flutter/painting.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
@ -82,8 +83,8 @@ class _RenderSwitch extends RenderToggleable {
|
||||
|
||||
RadialReaction _radialReaction;
|
||||
|
||||
void handleEvent(ui.Event event, BoxHitTestEntry entry) {
|
||||
if (event is ui.PointerEvent) {
|
||||
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
|
||||
if (event is PointerInputEvent) {
|
||||
if (event.type == 'pointerdown')
|
||||
_showRadialReaction(entry.localPosition);
|
||||
else if (event.type == 'pointerup')
|
||||
|
@ -23,13 +23,7 @@ int _hammingWeight(int value) {
|
||||
return weight;
|
||||
}
|
||||
|
||||
class _PointerState {
|
||||
_PointerState({ this.result, this.lastPosition });
|
||||
HitTestResult result;
|
||||
Point lastPosition;
|
||||
}
|
||||
|
||||
typedef void EventListener(ui.Event event);
|
||||
typedef void EventListener(InputEvent event);
|
||||
|
||||
/// A hit test entry used by [FlutterBinding]
|
||||
class BindingHitTestEntry extends HitTestEntry {
|
||||
@ -39,6 +33,93 @@ class BindingHitTestEntry extends HitTestEntry {
|
||||
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
|
||||
class FlutterBinding extends HitTestTarget {
|
||||
|
||||
@ -95,11 +176,12 @@ class FlutterBinding extends HitTestTarget {
|
||||
bool removeEventListener(EventListener listener) => _eventListeners.remove(listener);
|
||||
|
||||
void _handleEvent(ui.Event event) {
|
||||
if (event is ui.PointerEvent) {
|
||||
_handlePointerEvent(event);
|
||||
InputEvent ourEvent = _UiEventConverter.convert(event);
|
||||
if (ourEvent is PointerInputEvent) {
|
||||
_handlePointerInputEvent(ourEvent);
|
||||
} else {
|
||||
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.
|
||||
/// We do not track the state of hovering pointers because we need
|
||||
/// to hit-test them on each movement.
|
||||
Map<int, _PointerState> _stateForPointer = new Map<int, _PointerState>();
|
||||
Map<int, HitTestResult> _resultForPointer = new Map<int, HitTestResult>();
|
||||
|
||||
void _handlePointerEvent(ui.PointerEvent event) {
|
||||
Point position = new Point(event.x, event.y);
|
||||
|
||||
_PointerState state = _stateForPointer[event.pointer];
|
||||
void _handlePointerInputEvent(PointerInputEvent event) {
|
||||
HitTestResult result = _resultForPointer[event.pointer];
|
||||
switch (event.type) {
|
||||
case 'pointerdown':
|
||||
if (state == null) {
|
||||
state = new _PointerState(result: hitTest(position), lastPosition: position);
|
||||
_stateForPointer[event.pointer] = state;
|
||||
if (result == null) {
|
||||
result = hitTest(new Point(event.x, event.y));
|
||||
_resultForPointer[event.pointer] = result;
|
||||
}
|
||||
break;
|
||||
case 'pointermove':
|
||||
if (state == null) {
|
||||
if (result == null) {
|
||||
// The pointer is hovering, ignore it for now since we don't
|
||||
// know what to do with it yet.
|
||||
return;
|
||||
}
|
||||
event.dx = position.x - state.lastPosition.x;
|
||||
event.dy = position.y - state.lastPosition.y;
|
||||
state.lastPosition = position;
|
||||
break;
|
||||
case 'pointerup':
|
||||
case 'pointercancel':
|
||||
if (state == null) {
|
||||
if (result == null) {
|
||||
// This seems to be a spurious event. Ignore it.
|
||||
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)
|
||||
_stateForPointer.remove(event.pointer);
|
||||
_resultForPointer.remove(event.pointer);
|
||||
break;
|
||||
}
|
||||
dispatchEvent(event, state.result);
|
||||
dispatchEvent(event, result);
|
||||
}
|
||||
|
||||
/// 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
|
||||
void dispatchEvent(ui.Event event, HitTestResult result) {
|
||||
void dispatchEvent(InputEvent event, HitTestResult result) {
|
||||
assert(result != null);
|
||||
for (HitTestEntry entry in result.path)
|
||||
entry.target.handleEvent(event, entry);
|
||||
}
|
||||
|
||||
void handleEvent(ui.Event e, BindingHitTestEntry entry) {
|
||||
if (e is ui.PointerEvent) {
|
||||
ui.PointerEvent event = e;
|
||||
void handleEvent(InputEvent e, BindingHitTestEntry entry) {
|
||||
if (e is PointerInputEvent) {
|
||||
PointerInputEvent event = e;
|
||||
pointerRouter.route(event);
|
||||
if (event.type == 'pointerdown')
|
||||
GestureArena.instance.close(event.pointer);
|
||||
|
@ -237,6 +237,7 @@ class RenderBlockViewport extends RenderBlockBase {
|
||||
ExtentCallback totalExtentCallback,
|
||||
ExtentCallback maxCrossAxisDimensionCallback,
|
||||
ExtentCallback minCrossAxisDimensionCallback,
|
||||
Painter overlayPainter,
|
||||
BlockDirection direction: BlockDirection.vertical,
|
||||
double itemExtent,
|
||||
double minExtent: 0.0,
|
||||
@ -246,6 +247,7 @@ class RenderBlockViewport extends RenderBlockBase {
|
||||
_totalExtentCallback = totalExtentCallback,
|
||||
_maxCrossAxisExtentCallback = maxCrossAxisDimensionCallback,
|
||||
_minCrossAxisExtentCallback = minCrossAxisDimensionCallback,
|
||||
_overlayPainter = overlayPainter,
|
||||
_startOffset = startOffset,
|
||||
super(children: children, direction: direction, itemExtent: itemExtent, minExtent: minExtent);
|
||||
|
||||
@ -298,6 +300,27 @@ class RenderBlockViewport extends RenderBlockBase {
|
||||
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
|
||||
///
|
||||
/// 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) {
|
||||
context.canvas.save();
|
||||
|
||||
context.canvas.clipRect(offset & size);
|
||||
if (isVertical)
|
||||
defaultPaint(context, offset.translate(0.0, startOffset));
|
||||
else
|
||||
defaultPaint(context, offset.translate(startOffset, 0.0));
|
||||
|
||||
overlayPainter?.paint(context, offset);
|
||||
|
||||
context.canvas.restore();
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
/// An object that can handle events.
|
||||
abstract class HitTestTarget {
|
||||
/// 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].
|
||||
|
@ -7,6 +7,7 @@ import 'dart:ui' as ui;
|
||||
import 'dart:ui' show Point, Offset, Size, Rect, Color, Paint, Path;
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:vector_math/vector_math_64.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
|
||||
///
|
||||
/// Concrete layout models (such as box) will create concrete subclasses to
|
||||
@ -1071,7 +1093,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
// EVENTS
|
||||
|
||||
/// 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 'package:flutter/painting.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:vector_math/vector_math_64.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.
|
||||
class RenderPointerListener extends RenderProxyBox {
|
||||
@ -1071,7 +1072,7 @@ class RenderPointerListener extends RenderProxyBox {
|
||||
PointerEventListener onPointerUp;
|
||||
PointerEventListener onPointerCancel;
|
||||
|
||||
void handleEvent(ui.Event event, HitTestEntry entry) {
|
||||
void handleEvent(InputEvent event, HitTestEntry entry) {
|
||||
if (onPointerDown != null && event.type == 'pointerdown')
|
||||
return onPointerDown(event);
|
||||
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
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
@ -37,7 +35,7 @@ abstract class RenderToggleable extends RenderConstrainedBox {
|
||||
|
||||
double get position => _performance.value;
|
||||
|
||||
void handleEvent(ui.Event event, BoxHitTestEntry entry) {
|
||||
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
|
||||
if (event.type == 'pointerdown')
|
||||
_tap.addPointer(event);
|
||||
}
|
||||
|
@ -3,9 +3,9 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:collection';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
import 'basic.dart';
|
||||
@ -69,7 +69,7 @@ class Draggable extends StatefulComponent {
|
||||
class _DraggableState extends State<Draggable> {
|
||||
DragRoute _route;
|
||||
|
||||
void _startDrag(ui.PointerEvent event) {
|
||||
void _startDrag(PointerInputEvent event) {
|
||||
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.
|
||||
final Point point = new Point(event.x, event.y);
|
||||
@ -97,7 +97,7 @@ class _DraggableState extends State<Draggable> {
|
||||
config.navigator.push(_route);
|
||||
}
|
||||
|
||||
void _updateDrag(ui.PointerEvent event) {
|
||||
void _updateDrag(PointerInputEvent event) {
|
||||
if (_route != null) {
|
||||
config.navigator.setState(() {
|
||||
_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) {
|
||||
config.navigator.popRoute(_route, DragEndKind.canceled);
|
||||
assert(_route == null);
|
||||
}
|
||||
}
|
||||
|
||||
void _drop(ui.PointerEvent event) {
|
||||
void _drop(PointerInputEvent event) {
|
||||
if (_route != null) {
|
||||
_route.update(new Point(event.x, event.y));
|
||||
config.navigator.popRoute(_route, DragEndKind.dropped);
|
||||
|
@ -128,6 +128,8 @@ class EditableString implements KeyboardClient {
|
||||
selection = new TextRange(start: start, end: end);
|
||||
onUpdated();
|
||||
}
|
||||
|
||||
void submit(SubmitAction action) {}
|
||||
}
|
||||
|
||||
class EditableText extends StatefulComponent {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
@ -187,7 +185,7 @@ class _GestureDetectorState extends State<GestureDetector> {
|
||||
return null;
|
||||
}
|
||||
|
||||
void _handlePointerDown(ui.PointerEvent event) {
|
||||
void _handlePointerDown(PointerInputEvent event) {
|
||||
if (_tap != null)
|
||||
_tap.addPointer(event);
|
||||
if (_showPress != null)
|
||||
|
@ -18,7 +18,8 @@ class HomogeneousViewport extends RenderObjectWidget {
|
||||
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.direction: ScrollDirection.vertical,
|
||||
this.startOffset: 0.0
|
||||
this.startOffset: 0.0,
|
||||
this.overlayPainter
|
||||
}) : super(key: key) {
|
||||
assert(itemExtent != null);
|
||||
}
|
||||
@ -29,6 +30,7 @@ class HomogeneousViewport extends RenderObjectWidget {
|
||||
final int itemCount;
|
||||
final ScrollDirection direction;
|
||||
final double startOffset;
|
||||
final Painter overlayPainter;
|
||||
|
||||
_HomogeneousViewportElement createElement() => new _HomogeneousViewportElement(this);
|
||||
|
||||
@ -70,6 +72,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
|
||||
renderObject.totalExtentCallback = getTotalExtent;
|
||||
renderObject.minCrossAxisExtentCallback = getMinCrossAxisExtent;
|
||||
renderObject.maxCrossAxisExtentCallback = getMaxCrossAxisExtent;
|
||||
renderObject.overlayPainter = widget.overlayPainter;
|
||||
}
|
||||
|
||||
void unmount() {
|
||||
@ -77,6 +80,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
|
||||
renderObject.totalExtentCallback = null;
|
||||
renderObject.minCrossAxisExtentCallback = null;
|
||||
renderObject.maxCrossAxisExtentCallback = null;
|
||||
renderObject.overlayPainter = null;
|
||||
super.unmount();
|
||||
}
|
||||
|
||||
@ -134,6 +138,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
|
||||
renderObject.itemExtent = widget.itemExtent;
|
||||
renderObject.minExtent = getTotalExtent(null);
|
||||
renderObject.startOffset = offset;
|
||||
renderObject.overlayPainter = widget.overlayPainter;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,9 @@ abstract class Scrollable extends StatefulComponent {
|
||||
Key key,
|
||||
this.initialScrollOffset,
|
||||
this.scrollDirection: ScrollDirection.vertical,
|
||||
this.onScrollStart,
|
||||
this.onScroll,
|
||||
this.onScrollEnd,
|
||||
this.snapOffsetCallback,
|
||||
this.snapAlignmentOffset: 0.0
|
||||
}) : super(key: key) {
|
||||
@ -42,7 +44,9 @@ abstract class Scrollable extends StatefulComponent {
|
||||
|
||||
final double initialScrollOffset;
|
||||
final ScrollDirection scrollDirection;
|
||||
final ScrollListener onScrollStart;
|
||||
final ScrollListener onScroll;
|
||||
final ScrollListener onScrollEnd;
|
||||
final SnapOffsetCallback snapOffsetCallback;
|
||||
final double snapAlignmentOffset;
|
||||
}
|
||||
@ -74,6 +78,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
|
||||
return _scrollBehavior;
|
||||
}
|
||||
|
||||
GestureDragStartCallback _getDragStartHandler(ScrollDirection direction) {
|
||||
if (config.scrollDirection != direction || !scrollBehavior.isScrollable)
|
||||
return null;
|
||||
return _handleDragStart;
|
||||
}
|
||||
|
||||
GestureDragUpdateCallback _getDragUpdateHandler(ScrollDirection direction) {
|
||||
if (config.scrollDirection != direction || !scrollBehavior.isScrollable)
|
||||
return null;
|
||||
@ -88,8 +98,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return new GestureDetector(
|
||||
onVerticalDragStart: _getDragStartHandler(ScrollDirection.vertical),
|
||||
onVerticalDragUpdate: _getDragUpdateHandler(ScrollDirection.vertical),
|
||||
onVerticalDragEnd: _getDragEndHandler(ScrollDirection.vertical),
|
||||
onHorizontalDragStart: _getDragStartHandler(ScrollDirection.horizontal),
|
||||
onHorizontalDragUpdate: _getDragUpdateHandler(ScrollDirection.horizontal),
|
||||
onHorizontalDragEnd: _getDragEndHandler(ScrollDirection.horizontal),
|
||||
child: new Listener(
|
||||
@ -199,12 +211,22 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
|
||||
return _startToEndAnimation();
|
||||
}
|
||||
|
||||
void dispatchOnScrollStart() {
|
||||
if (config.onScrollStart != null)
|
||||
config.onScrollStart(_scrollOffset);
|
||||
}
|
||||
|
||||
// Derived classes can override this method and call super.dispatchOnScroll()
|
||||
void dispatchOnScroll() {
|
||||
if (config.onScroll != null)
|
||||
config.onScroll(_scrollOffset);
|
||||
}
|
||||
|
||||
void dispatchOnScrollEnd() {
|
||||
if (config.onScrollEnd != null)
|
||||
config.onScrollEnd(_scrollOffset);
|
||||
}
|
||||
|
||||
double _scrollVelocity(ui.Offset velocity) {
|
||||
double scrollVelocity = config.scrollDirection == ScrollDirection.horizontal
|
||||
? -velocity.dx
|
||||
@ -216,14 +238,20 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
|
||||
_animation.stop();
|
||||
}
|
||||
|
||||
void _handleDragStart() {
|
||||
scheduleMicrotask(dispatchOnScrollStart);
|
||||
}
|
||||
|
||||
void _handleDragUpdate(double delta) {
|
||||
// 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).
|
||||
scrollBy(-delta);
|
||||
}
|
||||
|
||||
void _handleDragEnd(Offset velocity) {
|
||||
fling(velocity);
|
||||
Future _handleDragEnd(Offset 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
|
||||
/// the same size (extent) in the scrollDirection. For example for
|
||||
/// ScrollDirection.vertical itemExtent is the height of each item. Use this
|
||||
@ -394,7 +468,8 @@ abstract class ScrollableWidgetList extends Scrollable {
|
||||
double snapAlignmentOffset: 0.0,
|
||||
this.itemsWrap: false,
|
||||
this.itemExtent,
|
||||
this.padding
|
||||
this.padding,
|
||||
this.scrollableListPainter
|
||||
}) : super(
|
||||
key: key,
|
||||
initialScrollOffset: initialScrollOffset,
|
||||
@ -409,6 +484,7 @@ abstract class ScrollableWidgetList extends Scrollable {
|
||||
final bool itemsWrap;
|
||||
final double itemExtent;
|
||||
final EdgeDims padding;
|
||||
final ScrollableListPainter scrollableListPainter;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void _updateScrollBehavior() {
|
||||
// if you don't call this from build(), you must call it from setState().
|
||||
double get _contentExtent {
|
||||
double contentExtent = config.itemExtent * itemCount;
|
||||
if (config.padding != null)
|
||||
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(
|
||||
contentExtent: contentExtent,
|
||||
contentExtent: _contentExtent,
|
||||
containerExtent: _containerExtent,
|
||||
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) {
|
||||
if (itemCount != _previousItemCount) {
|
||||
_previousItemCount = itemCount;
|
||||
@ -508,7 +606,8 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends
|
||||
itemExtent: config.itemExtent,
|
||||
itemCount: itemCount,
|
||||
direction: config.scrollDirection,
|
||||
startOffset: scrollOffset - _leadingPadding
|
||||
startOffset: scrollOffset - _leadingPadding,
|
||||
overlayPainter: config.scrollableListPainter
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -541,7 +640,8 @@ class ScrollableList<T> extends ScrollableWidgetList {
|
||||
this.itemBuilder,
|
||||
itemsWrap: false,
|
||||
double itemExtent,
|
||||
EdgeDims padding
|
||||
EdgeDims padding,
|
||||
ScrollableListPainter scrollableListPainter
|
||||
}) : super(
|
||||
key: key,
|
||||
initialScrollOffset: initialScrollOffset,
|
||||
@ -551,7 +651,9 @@ class ScrollableList<T> extends ScrollableWidgetList {
|
||||
snapAlignmentOffset: snapAlignmentOffset,
|
||||
itemsWrap: itemsWrap,
|
||||
itemExtent: itemExtent,
|
||||
padding: padding);
|
||||
padding: padding,
|
||||
scrollableListPainter: scrollableListPainter
|
||||
);
|
||||
|
||||
final List<T> items;
|
||||
final ItemBuilder<T> itemBuilder;
|
||||
|
@ -1,17 +1,17 @@
|
||||
name: flutter
|
||||
version: 0.0.3
|
||||
version: 0.0.5
|
||||
author: Flutter Authors <flutter-dev@googlegroups.com>
|
||||
description: A framework for writing Flutter applications
|
||||
homepage: http://flutter.io
|
||||
dependencies:
|
||||
cassowary: '>=0.1.7 <0.2.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'
|
||||
newton: '>=0.1.4 <0.2.0'
|
||||
sky_engine: '>=0.0.34 <0.1.0'
|
||||
sky_services: '>=0.0.34 <0.1.0'
|
||||
sky_tools: '>=0.0.18 <0.1.0'
|
||||
sky_engine: 0.0.36
|
||||
sky_services: 0.0.36
|
||||
sky_tools: '>=0.0.20 <0.1.0'
|
||||
vector_math: '>=1.4.3 <2.0.0'
|
||||
intl: '>=0.12.4+2 <0.13.0'
|
||||
environment:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# skysprites
|
||||
# Flutter Sprites
|
||||
|
||||
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();
|
||||
|
@ -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) {
|
||||
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
|
||||
/// 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
|
||||
/// 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 {
|
||||
linear,
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
class ImageMap {
|
||||
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
|
||||
/// 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
|
||||
/// 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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
/// 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.
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
/// The super class of any [Node] that has a size.
|
||||
///
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
class _Particle {
|
||||
Vector2 pos;
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
enum PhysicsBodyType {
|
||||
static,
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
typedef void PhysicsJointBreakCallback(PhysicsJoint joint);
|
||||
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
enum PhysicsContactType {
|
||||
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
|
||||
// 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 {
|
||||
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.
|
||||
class Sprite extends NodeWithSize with SpritePaint {
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
///
|
@ -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.
|
||||
///
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
class TexturedLine extends Node {
|
||||
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();
|
@ -1,4 +1,4 @@
|
||||
part of skysprites;
|
||||
part of flutter_sprites;
|
||||
|
||||
class VirtualJoystick extends NodeWithSize {
|
||||
VirtualJoystick() : super(new Size(160.0, 160.0)) {
|
@ -1,9 +1,9 @@
|
||||
name: flutter_sprites
|
||||
description: A sprite toolkit built on top of Flutter
|
||||
version: 0.0.2
|
||||
version: 0.0.3
|
||||
author: Flutter Authors <flutter-dev@googlegroups.com>
|
||||
homepage: http://flutter.io
|
||||
dependencies:
|
||||
flutter: ">=0.0.3 <0.1.0"
|
||||
sky_tools: ">=0.0.18 <0.1.0"
|
||||
flutter: ">=0.0.5 <0.1.0"
|
||||
sky_tools: ">=0.0.20 <0.1.0"
|
||||
box2d: ">=0.2.0 <0.3.0"
|
||||
|
@ -1,64 +1,9 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
||||
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 {
|
||||
TestPointer([ this.pointer = 1 ]);
|
||||
|
||||
@ -66,11 +11,11 @@ class TestPointer {
|
||||
bool isDown = false;
|
||||
ui.Point location;
|
||||
|
||||
ui.PointerEvent down([ui.Point newLocation = ui.Point.origin ]) {
|
||||
PointerInputEvent down([ui.Point newLocation = ui.Point.origin ]) {
|
||||
assert(!isDown);
|
||||
isDown = true;
|
||||
location = newLocation;
|
||||
return new TestPointerEvent(
|
||||
return new PointerInputEvent(
|
||||
type: 'pointerdown',
|
||||
pointer: pointer,
|
||||
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);
|
||||
ui.Offset delta = newLocation - location;
|
||||
location = newLocation;
|
||||
return new TestPointerEvent(
|
||||
return new PointerInputEvent(
|
||||
type: 'pointermove',
|
||||
pointer: pointer,
|
||||
x: newLocation.x,
|
||||
@ -92,10 +37,10 @@ class TestPointer {
|
||||
);
|
||||
}
|
||||
|
||||
ui.PointerEvent up() {
|
||||
PointerInputEvent up() {
|
||||
assert(isDown);
|
||||
isDown = false;
|
||||
return new TestPointerEvent(
|
||||
return new PointerInputEvent(
|
||||
type: 'pointerup',
|
||||
pointer: pointer,
|
||||
x: location.x,
|
||||
@ -103,10 +48,10 @@ class TestPointer {
|
||||
);
|
||||
}
|
||||
|
||||
ui.PointerEvent cancel() {
|
||||
PointerInputEvent cancel() {
|
||||
assert(isDown);
|
||||
isDown = false;
|
||||
return new TestPointerEvent(
|
||||
return new PointerInputEvent(
|
||||
type: 'pointercancel',
|
||||
pointer: pointer,
|
||||
x: location.x,
|
||||
|
@ -2,16 +2,14 @@ import 'package:quiver/testing/async.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../engine/mock_events.dart';
|
||||
|
||||
final TestPointerEvent down = new TestPointerEvent(
|
||||
final PointerInputEvent down = new PointerInputEvent(
|
||||
pointer: 5,
|
||||
type: 'pointerdown',
|
||||
x: 10.0,
|
||||
y: 10.0
|
||||
);
|
||||
|
||||
final TestPointerEvent up = new TestPointerEvent(
|
||||
final PointerInputEvent up = new PointerInputEvent(
|
||||
pointer: 5,
|
||||
type: 'pointerup',
|
||||
x: 11.0,
|
||||
|
@ -1,5 +1,3 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@ -8,7 +6,7 @@ import '../engine/mock_events.dart';
|
||||
void main() {
|
||||
test('Should route pointers', () {
|
||||
bool callbackRan = false;
|
||||
void callback(ui.PointerEvent event) {
|
||||
void callback(PointerInputEvent event) {
|
||||
callbackRan = true;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ void main() {
|
||||
|
||||
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);
|
||||
tap.addPointer(down);
|
||||
|
||||
@ -67,7 +67,7 @@ void main() {
|
||||
|
||||
// Two-finger scaling
|
||||
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);
|
||||
tap.addPointer(down2);
|
||||
GestureArena.instance.close(2);
|
||||
@ -100,7 +100,7 @@ void main() {
|
||||
|
||||
// Three-finger scaling
|
||||
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);
|
||||
tap.addPointer(down3);
|
||||
GestureArena.instance.close(3);
|
||||
|
@ -32,7 +32,7 @@ void main() {
|
||||
};
|
||||
|
||||
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);
|
||||
tap.addPointer(down);
|
||||
GestureArena.instance.close(5);
|
||||
|
@ -2,16 +2,14 @@ import 'package:quiver/testing/async.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../engine/mock_events.dart';
|
||||
|
||||
final TestPointerEvent down = new TestPointerEvent(
|
||||
final PointerInputEvent down = new PointerInputEvent(
|
||||
pointer: 5,
|
||||
type: 'pointerdown',
|
||||
x: 10.0,
|
||||
y: 10.0
|
||||
);
|
||||
|
||||
final TestPointerEvent up = new TestPointerEvent(
|
||||
final PointerInputEvent up = new PointerInputEvent(
|
||||
pointer: 5,
|
||||
type: 'pointerup',
|
||||
x: 11.0,
|
||||
|
@ -1,8 +1,6 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../engine/mock_events.dart';
|
||||
|
||||
void main() {
|
||||
test('Should recognize tap', () {
|
||||
PointerRouter router = new PointerRouter();
|
||||
@ -13,7 +11,7 @@ void main() {
|
||||
tapRecognized = true;
|
||||
};
|
||||
|
||||
TestPointerEvent down = new TestPointerEvent(
|
||||
PointerInputEvent down = new PointerInputEvent(
|
||||
pointer: 5,
|
||||
type: 'pointerdown',
|
||||
x: 10.0,
|
||||
@ -26,7 +24,7 @@ void main() {
|
||||
router.route(down);
|
||||
expect(tapRecognized, isFalse);
|
||||
|
||||
TestPointerEvent up = new TestPointerEvent(
|
||||
PointerInputEvent up = new PointerInputEvent(
|
||||
pointer: 5,
|
||||
type: 'pointerup',
|
||||
x: 11.0,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:quiver/testing/async.dart';
|
||||
@ -159,13 +158,13 @@ class WidgetTester {
|
||||
_dispatchEvent(p.up(), result);
|
||||
}
|
||||
|
||||
void dispatchEvent(ui.Event event, Point location) {
|
||||
void dispatchEvent(InputEvent event, Point location) {
|
||||
_dispatchEvent(event, _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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user