Move sky/examples to sky/sdk/lib/example, and code changes to support that change. Fixes T277.

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/1218593002.
This commit is contained in:
Ian Fischer 2015-06-26 15:06:40 -07:00
parent 75f1c05b85
commit 82404e030a
132 changed files with 0 additions and 65489 deletions

View File

@ -1,16 +0,0 @@
Sky Examples
============
This directory contains several examples of using Sky. 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`.
1. *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
built using Sky. The app shows a list of all the stocks in the NASDAQ.
3. *Widgets.* The [widgets app](widgets) contains a number of Sky widgets so
you can experiment with them in a simple container.

View File

@ -1,96 +0,0 @@
#!mojo mojo:sky_viewer
<!--
// 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.
-->
<sky>
<style>
#chooser {
display: flex;
flex-direction: column;
justify-content: center;
padding: 5%;
}
#color-wheel {
min-width: 100%;
height: auto;
}
#color-sample {
margin: 5%;
padding: 10%;
text-align: center;
border-radius: 10px;
}
</style>
<div id="chooser">
<img id="color-wheel" src="color-wheel.png"/>
<h1 id="color-sample">Select Color</h1>
</div>
<script>
import 'dart:sky';
import 'dart:math';
class RGB {
final int r;
final int g;
final int b;
const RGB(this.r, this.g, this.b);
String toString() => "rgb($r, $g, $b)";
}
RGB hsvToRgb(double h, double s, double v) {
var i = (h * 6).floor();
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
var r, g, b;
switch (i % 6) {
case 0: r = v; g = t; b = p; break;
case 1: r = q; g = v; b = p; break;
case 2: r = p; g = v; b = t; break;
case 3: r = p; g = q; b = v; break;
case 4: r = t; g = p; b = v; break;
case 5: r = v; g = p; b = q; break;
}
return new RGB((r * 255).floor(), (g * 255).floor(), (b * 255).floor());
}
RGB xyToRgb(x, y, radius) {
var rx = x - radius;
var ry = y - radius;
var d = radius * radius;
if (rx * rx + ry * ry > d)
return null;
var h = (atan2(ry, rx) + PI) / (2 * PI);
var s = sqrt(d) / radius;
return hsvToRgb(h, s, 1.0);
}
elt(String id) => document.getElementById(id);
void updateColor(event) {
var bounds = event.target.getBoundingClientRect();
var x = event.x - bounds.left;
var y = event.y - bounds.top;
var radius = min(bounds.width, bounds.height) / 2.0;
var rgb = xyToRgb(x, y, radius);
if (rgb != null) {
var ccsColor = rgb.toString();
elt("color-sample").style["background-color"] = ccsColor;
}
}
void selectColor(event) {
var ccsColor = elt("color-sample").style["background-color"];
print(ccsColor);
}
void main() {
elt("color-wheel").addEventListener("pointerdown", updateColor);
elt("color-sample").addEventListener("pointerdown", selectColor);
elt("color-sample").style["background-color"] = "rgb(0, 209, 255)";
}
</script>
</sky>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

View File

@ -1,3 +0,0 @@
name: color
dependencies:
sky: any

View File

@ -1,10 +0,0 @@
library game;
import 'dart:sky';
import 'dart:math' as Math;
import 'package:vector_math/vector_math_64.dart';
import 'sprites.dart';
import 'package:box2d/box2d.dart';
import 'package:sky/rendering/object.dart';
part 'game_demo_world.dart';

View File

@ -1,463 +0,0 @@
part of game;
const double _steeringThreshold = 0.0;
const double _steeringMax = 150.0;
// Random generator
Math.Random _rand = new Math.Random();
const double _gameSizeWidth = 1024.0;
const double _gameSizeHeight = 1024.0;
const double _shipRadius = 30.0;
const double _lrgAsteroidRadius = 40.0;
const double _medAsteroidRadius = 20.0;
const double _smlAsteroidRadius = 10.0;
const double _maxAsteroidSpeed = 1.0;
const int _lifeTimeLaser = 50;
const int _numStarsInStarField = 150;
class GameDemoWorld extends NodeWithSize {
// Images
Image _imgNebula;
SpriteSheet _spriteSheet;
// Inputs
double _joystickX = 0.0;
double _joystickY = 0.0;
bool _fire;
Node _gameLayer;
Ship _ship;
List<Asteroid> _asteroids = [];
List<Laser> _lasers = [];
StarField _starField;
Nebula _nebula;
GameDemoWorld(ImageMap images, this._spriteSheet) : super(new Size(_gameSizeWidth, _gameSizeHeight)) {
// Fetch images
_imgNebula = images["res/nebula.png"];
_gameLayer = new Node();
this.addChild(_gameLayer);
// Add some asteroids to the game world
for (int i = 0; i < 5; i++) {
addAsteroid(AsteroidSize.large);
}
for (int i = 0; i < 5; i++) {
addAsteroid(AsteroidSize.medium);
}
// Add ship
addShip();
// Add starfield
_starField = new StarField(_spriteSheet["star.png"], _numStarsInStarField);
_starField.zPosition = -2.0;
addChild(_starField);
// Add nebula
addNebula();
userInteractionEnabled = true;
handleMultiplePointers = true;
}
// Methods for adding game objects
void addAsteroid(AsteroidSize size, [Point pos]) {
Asteroid asteroid = new Asteroid(_spriteSheet["asteroid_big_1.png"], size);
asteroid.zPosition = 1.0;
if (pos != null) asteroid.position = pos;
_gameLayer.addChild(asteroid);
_asteroids.add(asteroid);
}
void addShip() {
Ship ship = new Ship(_spriteSheet["ship.png"]);
ship.zPosition = 10.0;
_gameLayer.addChild(ship);
_ship = ship;
}
void addLaser() {
Laser laser = new Laser(_spriteSheet["laser.png"], _ship);
laser.zPosition = 8.0;
_lasers.add(laser);
_gameLayer.addChild(laser);
}
void addNebula() {
_nebula = new Nebula.withImage(_imgNebula);
_gameLayer.addChild(_nebula);
}
void update(double dt) {
// Move asteroids
for (Asteroid asteroid in _asteroids) {
asteroid.position = pointAdd(asteroid.position, asteroid._movementVector);
}
// Move lasers and remove expired lasers
for (int i = _lasers.length - 1; i >= 0; i--) {
Laser laser = _lasers[i];
laser.move();
if (laser._frameCount > _lifeTimeLaser) {
laser.removeFromParent();
_lasers.removeAt(i);
}
}
// Apply thrust to ship
if (_joystickX != 0.0 || _joystickY != 0.0) {
_ship.thrust(_joystickX, _joystickY);
}
// Move ship
_ship.move();
// Check collisions between asteroids and lasers
for (int i = _lasers.length -1; i >= 0; i--) {
// Iterate over all the lasers
Laser laser = _lasers[i];
for (int j = _asteroids.length - 1; j >= 0; j--) {
// Iterate over all the asteroids
Asteroid asteroid = _asteroids[j];
// Check for collision
if (pointQuickDist(laser.position, asteroid.position) < laser.radius + asteroid.radius) {
// Remove laser
laser.removeFromParent();
_lasers.removeAt(i);
// Add asteroids
if (asteroid._asteroidSize == AsteroidSize.large) {
for (int a = 0; a < 3; a++) addAsteroid(AsteroidSize.medium, asteroid.position);
}
else if (asteroid._asteroidSize == AsteroidSize.medium) {
for (int a = 0; a < 5; a++) addAsteroid(AsteroidSize.small, asteroid.position);
}
// Remove asteroid
asteroid.removeFromParent();
_asteroids.removeAt(j);
break;
}
}
}
// Move objects to center camera and warp objects around the edges
centerCamera();
warpObjects();
}
void centerCamera() {
const cameraDampening = 0.1;
Point delta = new Point(_gameSizeWidth/2 - _ship.position.x, _gameSizeHeight/2 - _ship.position.y);
delta = pointMult(delta, cameraDampening);
for (Node child in _gameLayer.children) {
child.position = pointAdd(child.position, delta);
}
// Update starfield
_starField.move(delta.x, delta.y);
}
void warpObjects() {
for (Node child in _gameLayer.children) {
if (child.position.x < 0) child.position = pointAdd(child.position, new Point(_gameSizeWidth, 0.0));
if (child.position.x >= _gameSizeWidth) child.position = pointAdd(child.position, new Point(-_gameSizeWidth, 0.0));
if (child.position.y < 0) child.position = pointAdd(child.position, new Point(0.0, _gameSizeHeight));
if (child.position.y >= _gameSizeHeight) child.position = pointAdd(child.position, new Point(0.0, -_gameSizeHeight));
}
}
// Handling controls
void controlSteering(double x, double y) {
_joystickX = x;
_joystickY = y;
}
void controlFire() {
addLaser();
}
// Handle pointer events
int _firstPointer = -1;
int _secondPointer = -1;
Point _firstPointerDownPos;
bool handleEvent(SpriteBoxEvent event) {
Point pointerPos = convertPointToNodeSpace(event.boxPosition);
int pointer = event.pointer;
switch (event.type) {
case 'pointerdown':
if (_firstPointer == -1) {
// Assign the first pointer
_firstPointer = pointer;
_firstPointerDownPos = pointerPos;
}
else if (_secondPointer == -1) {
// Assign second pointer
_secondPointer = pointer;
controlFire();
}
else {
// There is a pointer used for steering, let's fire instead
controlFire();
}
break;
case 'pointermove':
if (pointer == _firstPointer) {
// Handle turning control
double joystickX = 0.0;
double deltaX = pointerPos.x - _firstPointerDownPos.x;
if (deltaX > _steeringThreshold || deltaX < -_steeringThreshold) {
joystickX = (deltaX - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickX > 1.0) joystickX = 1.0;
if (joystickX < -1.0) joystickX = -1.0;
}
double joystickY = 0.0;
double deltaY = pointerPos.y - _firstPointerDownPos.y;
if (deltaY > _steeringThreshold || deltaY < -_steeringThreshold) {
joystickY = (deltaY - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickY > 1.0) joystickY = 1.0;
if (joystickY < -1.0) joystickY = -1.0;
}
controlSteering(joystickX, joystickY);
}
break;
case 'pointerup':
case 'pointercancel':
if (pointer == _firstPointer) {
// Un-assign the first pointer
_firstPointer = -1;
_firstPointerDownPos = null;
controlSteering(0.0, 0.0);
}
else if (pointer == _secondPointer) {
_secondPointer = -1;
}
break;
default:
break;
}
return true;
}
}
// Game objects
enum AsteroidSize {
small,
medium,
large,
}
class Asteroid extends Sprite {
Point _movementVector;
AsteroidSize _asteroidSize;
double _radius;
double get radius {
if (_radius != null) return _radius;
if (_asteroidSize == AsteroidSize.small) _radius = _smlAsteroidRadius;
else if (_asteroidSize == AsteroidSize.medium) _radius = _medAsteroidRadius;
else if (_asteroidSize == AsteroidSize.large) _radius = _lrgAsteroidRadius;
return _radius;
}
Asteroid(Texture img, AsteroidSize this._asteroidSize) : super(img) {
size = new Size(radius * 2.0, radius * 2.0);
position = new Point(_gameSizeWidth * _rand.nextDouble(), _gameSizeHeight * _rand.nextDouble());
rotation = 360.0 * _rand.nextDouble();
_movementVector = new Point(_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed,
_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed);
userInteractionEnabled = true;
}
bool handleEvent(SpriteBoxEvent event) {
if (event.type == "pointerdown") {
colorOverlay = new Color(0x99ff0000);
}
else if (event.type == "pointerup") {
colorOverlay = null;
}
return false;
}
}
class Ship extends Sprite {
Vector2 _movementVector;
double _rotationTarget;
Ship(Texture img) : super(img) {
_movementVector = new Vector2.zero();
rotation = _rotationTarget = 270.0;
// Create sprite
size = new Size(_shipRadius * 2.0, _shipRadius * 2.0);
position = new Point(_gameSizeWidth/2.0, _gameSizeHeight/2.0);
}
void thrust(double x, double y) {
_rotationTarget = convertRadians2Degrees(Math.atan2(y, x));
Vector2 directionVector = new Vector2(x, y).normalize();
_movementVector.addScaled(directionVector, 1.0);
}
void move() {
position = new Point(position.x + _movementVector[0], position.y + _movementVector[1]);
_movementVector.scale(0.9);
rotation = dampenRotation(rotation, _rotationTarget, 0.1);
}
}
class Laser extends Sprite {
int _frameCount = 0;
Point _movementVector;
double radius = 10.0;
Laser(Texture img, Ship ship) : super(img) {
size = new Size(20.0, 20.0);
position = ship.position;
rotation = ship.rotation + 90.0;
transferMode = TransferMode.plus;
double rotRadians = convertDegrees2Radians(rotation);
_movementVector = pointMult(new Point(Math.sin(rotRadians), -Math.cos(rotRadians)), 10.0);
_movementVector = new Point(_movementVector.x + ship._movementVector[0], _movementVector.y + ship._movementVector[1]);
}
void move() {
position = pointAdd(position, _movementVector);
_frameCount++;
}
}
// Background starfield
class StarField extends Node {
Texture _img;
int _numStars;
List<Point> _starPositions;
List<double> _starScales;
List<double> _opacity;
StarField(this._img, this._numStars) {
_starPositions = [];
_starScales = [];
_opacity = [];
for (int i = 0; i < _numStars; i++) {
_starPositions.add(new Point(_rand.nextDouble() * _gameSizeWidth, _rand.nextDouble() * _gameSizeHeight));
_starScales.add(_rand.nextDouble());
_opacity.add(_rand.nextDouble() * 0.5 + 0.5);
}
}
void paint(RenderCanvas canvas) {
// Setup paint object for opacity and transfer mode
Paint paint = new Paint();
paint.setTransferMode(TransferMode.plus);
double baseScaleX = 32.0 / _img.size.width;
double baseScaleY = 32.0 / _img.size.height;
// Draw each star
for (int i = 0; i < _numStars; i++) {
Point pos = _starPositions[i];
double scale = _starScales[i];
paint.color = new Color.fromARGB((255.0*_opacity[i]).toInt(), 255, 255, 255);
canvas.save();
canvas.translate(pos.x, pos.y);
canvas.scale(baseScaleX * scale, baseScaleY * scale);
canvas.drawImageRect(_img.image, _img.frame, _img.spriteSourceSize, paint);
canvas.restore();
}
}
void move(double dx, double dy) {
for (int i = 0; i < _numStars; i++) {
double xPos = _starPositions[i].x;
double yPos = _starPositions[i].y;
double scale = _starScales[i];
xPos += dx * scale;
yPos += dy * scale;
if (xPos >= _gameSizeWidth) xPos -= _gameSizeWidth;
if (xPos < 0) xPos += _gameSizeWidth;
if (yPos >= _gameSizeHeight) yPos -= _gameSizeHeight;
if (yPos < 0) yPos += _gameSizeHeight;
_starPositions[i] = new Point(xPos, yPos);
}
}
}
class Nebula extends Node {
Nebula.withImage(Image img) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
Sprite sprt = new Sprite.fromImage(img);
sprt.pivot = Point.origin;
sprt.position = new Point(i * _gameSizeWidth - _gameSizeWidth, j * _gameSizeHeight - _gameSizeHeight);
addChild(sprt);
}
}
}
}
// Convenience methods
Point pointAdd(Point a, Point b) {
return new Point(a.x+ b.x, a.y + b.y);
}
Point pointMult(Point a, double multiplier) {
return new Point(a.x * multiplier, a.y * multiplier);
}
double dampenRotation(double src, double dst, double dampening) {
double delta = dst - src;
while (delta > 180.0) delta -= 360;
while (delta < -180) delta += 360;
delta *= dampening;
return src + delta;
}
double pointQuickDist(Point a, Point b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
if (dx < 0.0) dx = -dx;
if (dy < 0.0) dy = -dy;
if (dx > dy) {
return dx + dy/2.0;
}
else {
return dy + dx/2.0;
}
}

View File

@ -1,37 +0,0 @@
part of sprites;
typedef void ImageMapCallback(ImageMap preloader);
class ImageMap {
Map<String, Image> _images;
int _totalNumImages = 0;
int _numLoadedImages = 0;
ImageMapCallback _callback;
ImageMap(List<String> urls, ImageMapCallback this._callback) {
_images = new Map();
_totalNumImages = urls.length;
urls.forEach(_addURL);
}
void _addURL(String url) {
image_cache.load(url, (Image image) {
// Store reference to image
_images[url] = image;
// Check if all images are loaded
_numLoadedImages++;
if (_numLoadedImages==_totalNumImages) {
// Everything loaded, make callback
_callback(this);
}
});
}
Image getImage(String url) => _images[url];
Image operator [](String url) => _images[url];
}

View File

@ -1,530 +0,0 @@
part of sprites;
double convertDegrees2Radians(double degrees) => degrees * Math.PI/180.8;
double convertRadians2Degrees(double radians) => radians * 180.0/Math.PI;
/// A base class for all objects that can be added to the sprite node tree and rendered to screen using [SpriteBox] and
/// [SpriteWidget].
///
/// The [Node] class itself doesn't render any content, but provides the basic functions of any type of node, such as
/// handling transformations and user input. To render the node tree, a root node must be added to a [SpriteBox] or a
/// [SpriteWidget]. Commonly used sub-classes of [Node] are [Sprite], [NodeWithSize], and many more upcoming subclasses.
///
/// Nodes form a hierarchical tree. Each node can have a number of children, and the transformation (positioning,
/// rotation, and scaling) of a node also affects its children.
class Node {
// Member variables
SpriteBox _spriteBox;
Node _parent;
Point _position = Point.origin;
double _rotation = 0.0;
Matrix4 _transformMatrix = new Matrix4.identity();
Matrix4 _transformMatrixNodeToBox;
Matrix4 _transformMatrixBoxToNode;
double _scaleX = 1.0;
double _scaleY = 1.0;
/// The visibility of this node and its children.
bool visible = true;
double _zPosition = 0.0;
int _addedOrder;
int _childrenLastAddedOrder = 0;
bool _childrenNeedSorting = false;
/// Decides if the node and its children is currently paused.
///
/// A paused node will not receive any input events, update calls, or run any animations.
///
/// myNodeTree.paused = true;
bool paused = false;
bool _userInteractionEnabled = false;
/// If set to true the node will receive multiple pointers, otherwise it will only receive events the first pointer.
///
/// This property is only meaningful if [userInteractionEnabled] is set to true. Default value is false.
///
/// class MyCustomNode extends Node {
/// handleMultiplePointers = true;
/// }
bool handleMultiplePointers = false;
int _handlingPointer;
List<Node>_children = [];
// Constructors
/// Creates a new [Node] without any transformation.
///
/// var myNode = new Node();
Node() {
}
// Property setters and getters
/// The [SpriteBox] this node is added to, or null if it's not currently added to a [SpriteBox].
///
/// For most applications it's not necessary to access the [SpriteBox] directly.
///
/// // Get the transformMode of the sprite box
/// var transformMode = myNode.spriteBox.transformMode;
SpriteBox get spriteBox => _spriteBox;
/// The parent of this node, or null if it doesn't have a parent.
///
/// // Hide the parent
/// myNode.parent.visible = false;
Node get parent => _parent;
/// The rotation of this node in degrees.
///
/// myNode.rotation = 45.0;
double get rotation => _rotation;
void set rotation(double rotation) {
assert(rotation != null);
_rotation = rotation;
_invalidateTransformMatrix();
}
/// The position of this node relative to its parent.
///
/// myNode.position = new Point(42.0, 42.0);
Point get position => _position;
void set position(Point position) {
assert(position != null);
_position = position;
_invalidateTransformMatrix();
}
/// The draw order of this node compared to its parent and its siblings.
///
/// By default nodes are drawn in the order that they have been added to a parent. To override this behavior the
/// [zPosition] property can be used. A higher value of this property will force the node to be drawn in front of
/// siblings that have a lower value. If a negative value is used the node will be drawn behind its parent.
///
/// nodeInFront.zPosition = 1.0;
/// nodeBehind.zPosition = -1.0;
double get zPosition => _zPosition;
void set zPosition(double zPosition) {
assert(zPosition != null);
_zPosition = zPosition;
if (_parent != null) {
_parent._childrenNeedSorting = true;
}
}
/// The scale of this node relative its parent.
///
/// The [scale] property is only valid if [scaleX] and [scaleY] are equal values.
///
/// myNode.scale = 5.0;
double get scale {
assert(_scaleX == _scaleY);
return _scaleX;
}
void set scale(double scale) {
assert(scale != null);
_scaleX = _scaleY = scale;
_invalidateTransformMatrix();
}
/// The horizontal scale of this node relative its parent.
///
/// myNode.scaleX = 5.0;
double get scaleX => _scaleX;
void set scaleX(double scaleX) {
assert(scaleX != null);
_scaleX = scaleX;
_invalidateTransformMatrix();
}
/// The vertical scale of this node relative its parent.
///
/// myNode.scaleY = 5.0;
double get scaleY => _scaleY;
void set scaleY(double scaleY) {
assert(scaleY != null);
_scaleY = scaleY;
_invalidateTransformMatrix();
}
/// A list of the children of this node.
///
/// This list should only be modified by using the [addChild] and [removeChild] methods.
///
/// // Iterate over a nodes children
/// for (Node child in myNode.children) {
/// // Do something with the child
/// }
List<Node> get children {
_sortChildren();
return _children;
}
// Adding and removing children
/// Adds a child to this node.
///
/// The same node cannot be added to multiple nodes.
///
/// addChild(new Sprite(myImage));
void addChild(Node child) {
assert(child != null);
assert(child._parent == null);
_childrenNeedSorting = true;
_children.add(child);
child._parent = this;
child._spriteBox = this._spriteBox;
_childrenLastAddedOrder += 1;
child._addedOrder = _childrenLastAddedOrder;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
/// Removes a child from this node.
///
/// removeChild(myChildNode);
void removeChild(Node child) {
assert(child != null);
if (_children.remove(child)) {
child._parent = null;
child._spriteBox = null;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
}
/// Removes this node from its parent node.
///
/// removeFromParent();
void removeFromParent() {
assert(_parent != null);
_parent.removeChild(this);
}
/// Removes all children of this node.
///
/// removeAllChildren();
void removeAllChildren() {
for (Node child in _children) {
child._parent = null;
child._spriteBox = null;
}
_children = [];
_childrenNeedSorting = false;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
void _sortChildren() {
// Sort children primarily by zPosition, secondarily by added order
if (_childrenNeedSorting) {
_children.sort((Node a, Node b) {
if (a._zPosition == b._zPosition) {
return a._addedOrder - b._addedOrder;
}
else if (a._zPosition > b._zPosition) {
return 1;
}
else {
return -1;
}
});
_childrenNeedSorting = false;
}
}
// Calculating the transformation matrix
/// The transformMatrix describes the transformation from the node's parent.
///
/// You cannot set the transformMatrix directly, instead use the position, rotation and scale properties.
///
/// Matrix4 matrix = myNode.transformMatrix;
Matrix4 get transformMatrix {
if (_transformMatrix != null) {
return _transformMatrix;
}
double cx, sx, cy, sy;
if (_rotation == 0.0) {
cx = 1.0;
sx = 0.0;
cy = 1.0;
sy = 0.0;
}
else {
double radiansX = convertDegrees2Radians(_rotation);
double radiansY = convertDegrees2Radians(_rotation);
cx = Math.cos(radiansX);
sx = Math.sin(radiansX);
cy = Math.cos(radiansY);
sy = Math.sin(radiansY);
}
// Create transformation matrix for scale, position and rotation
_transformMatrix = new Matrix4(cy * _scaleX, sy * _scaleX, 0.0, 0.0,
-sx * _scaleY, cx * _scaleY, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
_position.x, _position.y, 0.0, 1.0);
return _transformMatrix;
}
void _invalidateTransformMatrix() {
_transformMatrix = null;
_invalidateToBoxTransformMatrix();
}
void _invalidateToBoxTransformMatrix () {
_transformMatrixNodeToBox = null;
_transformMatrixBoxToNode = null;
for (Node child in children) {
child._invalidateToBoxTransformMatrix();
}
}
// Transforms to other nodes
Matrix4 _nodeToBoxMatrix() {
assert(_spriteBox != null);
if (_transformMatrixNodeToBox != null) {
return _transformMatrixNodeToBox;
}
if (_parent == null) {
// Base case, we are at the top
assert(this == _spriteBox.rootNode);
_transformMatrixNodeToBox = new Matrix4.copy(_spriteBox.transformMatrix).multiply(transformMatrix);
}
else {
_transformMatrixNodeToBox = new Matrix4.copy(_parent._nodeToBoxMatrix()).multiply(transformMatrix);
}
return _transformMatrixNodeToBox;
}
Matrix4 _boxToNodeMatrix() {
assert(_spriteBox != null);
if (_transformMatrixBoxToNode != null) {
return _transformMatrixBoxToNode;
}
_transformMatrixBoxToNode = new Matrix4.copy(_nodeToBoxMatrix());
_transformMatrixBoxToNode.invert();
return _transformMatrixBoxToNode;
}
/// Converts a point from the coordinate system of the [SpriteBox] to the local coordinate system of the node.
///
/// This method is particularly useful when handling pointer events and need the pointers position in a local
/// coordinate space.
///
/// Point localPoint = myNode.convertPointToNodeSpace(pointInBoxCoordinates);
Point convertPointToNodeSpace(Point boxPoint) {
assert(boxPoint != null);
assert(_spriteBox != null);
Vector4 v =_boxToNodeMatrix().transform(new Vector4(boxPoint.x, boxPoint.y, 0.0, 1.0));
return new Point(v[0], v[1]);
}
/// Converts a point from the local coordinate system of the node to the coordinate system of the [SpriteBox].
///
/// Point pointInBoxCoordinates = myNode.convertPointToBoxSpace(localPoint);
Point convertPointToBoxSpace(Point nodePoint) {
assert(nodePoint != null);
assert(_spriteBox != null);
Vector4 v =_nodeToBoxMatrix().transform(new Vector4(nodePoint.x, nodePoint.y, 0.0, 1.0));
return new Point(v[0], v[1]);
}
/// Converts a [point] from another [node]s coordinate system into the local coordinate system of this node.
///
/// Point pointInNodeASpace = nodeA.convertPointFromNode(pointInNodeBSpace, nodeB);
Point convertPointFromNode(Point point, Node node) {
assert(node != null);
assert(point != null);
assert(_spriteBox != null);
assert(_spriteBox == node._spriteBox);
Point boxPoint = node.convertPointToBoxSpace(point);
Point localPoint = convertPointToNodeSpace(boxPoint);
return localPoint;
}
// Hit test
/// Returns true if the [point] is inside the node, the [point] is in the local coordinate system of the node.
///
/// myNode.isPointInside(localPoint);
///
/// [NodeWithSize] provides a basic bounding box check for this method, if you require a more detailed check this
/// method can be overridden.
///
/// bool isPointInside (Point nodePoint) {
/// double minX = -size.width * pivot.x;
/// double minY = -size.height * pivot.y;
/// double maxX = minX + size.width;
/// double maxY = minY + size.height;
/// return (nodePoint.x >= minX && nodePoint.x < maxX &&
/// nodePoint.y >= minY && nodePoint.y < maxY);
/// }
bool isPointInside(Point point) {
assert(point != null);
return false;
}
// Rendering
void _visit(RenderCanvas canvas) {
assert(canvas != null);
if (!visible) return;
_prePaint(canvas);
_visitChildren(canvas);
_postPaint(canvas);
}
void _prePaint(RenderCanvas canvas) {
canvas.save();
// Get the transformation matrix and apply transform
canvas.concat(transformMatrix.storage);
}
/// Paints this node to the canvas.
///
/// Subclasses, such as [Sprite], override this method to do the actual painting of the node. To do custom
/// drawing override this method and make calls to the [canvas] object. All drawing is done in the node's local
/// coordinate system, relative to the node's position. If you want to make the drawing relative to the node's
/// bounding box's origin, override [NodeWithSize] and call the applyTransformForPivot method before making calls for
/// drawing.
///
/// void paint(RenderCanvas canvas) {
/// canvas.save();
/// applyTransformForPivot(canvas);
///
/// // Do painting here
///
/// canvas.restore();
/// }
void paint(RenderCanvas canvas) {
}
void _visitChildren(RenderCanvas canvas) {
// Sort children if needed
_sortChildren();
int i = 0;
// Visit children behind this node
while (i < _children.length) {
Node child = _children[i];
if (child.zPosition >= 0.0) break;
child._visit(canvas);
i++;
}
// Paint this node
paint(canvas);
// Visit children in front of this node
while (i < _children.length) {
Node child = _children[i];
child._visit(canvas);
i++;
}
}
void _postPaint(RenderCanvas canvas) {
canvas.restore();
}
// Receiving update calls
/// Called before a frame is drawn.
///
/// Override this method to do any updates to the node or node tree before it's drawn to screen.
///
/// // Make the node rotate at a fixed speed
/// void update(double dt) {
/// rotation = rotation * 10.0 * dt;
/// }
void update(double dt) {
}
/// Called whenever the [SpriteBox] is modified or resized, or if the device is rotated.
///
/// Override this method to do any updates that may be necessary to correctly display the node or node tree with the
/// new layout of the [SpriteBox].
///
/// void spriteBoxPerformedLayout() {
/// // Move some stuff around here
/// }
void spriteBoxPerformedLayout() {
}
// Handling user interaction
/// The node will receive user interactions, such as pointer (touch or mouse) events.
///
/// class MyCustomNode extends NodeWithSize {
/// userInteractionEnabled = true;
/// }
bool get userInteractionEnabled => _userInteractionEnabled;
void set userInteractionEnabled(bool userInteractionEnabled) {
_userInteractionEnabled = userInteractionEnabled;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
/// Handles an event, such as a pointer (touch or mouse) event.
///
/// Override this method to handle events. The node will only receive events if the [userInteractionEnabled] property
/// is set to true and the [isPointInside] method returns true for the position of the pointer down event (default
/// behavior provided by [NodeWithSize]). Unless [handleMultiplePointers] is set to true, the node will only receive
/// events for the first pointer that is down.
///
/// Return true if the node has consumed the event, if an event is consumed it will not be passed on to nodes behind
/// the current node.
///
/// // MyTouchySprite gets transparent when we touch it
/// class MyTouchySprite extends Sprite {
///
/// MyTouchySprite(Image img) : super (img) {
/// userInteractionEnabled = true;
/// }
///
/// bool handleEvent(SpriteBoxEvent event) {
/// if (event.type == 'pointerdown) {
/// opacity = 0.5;
/// }
/// else if (event.type == 'pointerup') {
/// opacity = 1.0;
/// }
/// return true;
/// }
/// }
bool handleEvent(SpriteBoxEvent event) {
return false;
}
}

View File

@ -1,60 +0,0 @@
part of sprites;
/// The super class of any [Node] that has a size.
///
/// NodeWithSize adds the ability for a node to have a size and a pivot point.
abstract class NodeWithSize extends Node {
/// Changing the size will affect the size of the rendering of the node.
///
/// myNode.size = new Size(1024.0, 1024.0);
Size size;
/// The normalized point which the node is transformed around.
///
/// // Position myNode from is middle top
/// myNode.pivot = new Point(0.5, 0.0);
Point pivot;
/// Creates a new NodeWithSize.
///
/// The default [size] is zero and the default [pivot] point is the origin. Subclasses may change the default values.
///
/// var myNodeWithSize = new NodeWithSize(new Size(1024.0, 1024.0));
NodeWithSize([Size this.size, Point this.pivot]) {
if (size == null) size = Size.zero;
if (pivot == null) pivot = Point.origin;
}
/// Call this method in your [paint] method if you want the origin of your drawing to be the top left corner of the
/// node's bounding box.
///
/// If you use this method you will need to save and restore your canvas at the beginning and
/// end of your [paint] method.
///
/// void paint(RenderCanvas canvas) {
/// canvas.save();
/// applyTransformForPivot(canvas);
///
/// // Do painting here
///
/// canvas.restore();
/// }
void applyTransformForPivot(RenderCanvas canvas) {
if (pivot.x != 0 || pivot.y != 0) {
double pivotInPointsX = size.width * pivot.x;
double pivotInPointsY = size.height * pivot.y;
canvas.translate(-pivotInPointsX, -pivotInPointsY);
}
}
bool isPointInside (Point nodePoint) {
double minX = -size.width * pivot.x;
double minY = -size.height * pivot.y;
double maxX = minX + size.width;
double maxY = minY + size.height;
return (nodePoint.x >= minX && nodePoint.x < maxX &&
nodePoint.y >= minY && nodePoint.y < maxY);
}
}

View File

@ -1,129 +0,0 @@
part of sprites;
/// A Sprite is a [Node] that renders a bitmap image to the screen.
class Sprite extends NodeWithSize {
/// The texture that the sprite will render to screen.
///
/// If the texture is null, the sprite will be rendered as a red square
/// marking the bounds of the sprite.
///
/// mySprite.texture = myTexture;
Texture texture;
/// If true, constrains the proportions of the image by scaling it down, if its proportions doesn't match the [size].
///
/// mySprite.constrainProportions = true;
bool constrainProportions = false;
double _opacity = 1.0;
/// The color to draw on top of the sprite, null if no color overlay is used.
///
/// // Color the sprite red
/// mySprite.colorOverlay = new Color(0x77ff0000);
Color colorOverlay;
/// The transfer mode used when drawing the sprite to screen.
///
/// // Add the colors of the sprite with the colors of the background
/// mySprite.transferMode = TransferMode.plusMode;
TransferMode transferMode;
/// Creates a new sprite from the provided [texture].
///
/// var mySprite = new Sprite(myTexture)
Sprite([this.texture]) {
if (texture != null) {
size = texture.size;
pivot = texture.pivot;
} else {
pivot = new Point(0.5, 0.5);
}
}
/// Creates a new sprite from the provided [image].
///
/// var mySprite = new Sprite.fromImage(myImage);
Sprite.fromImage(Image image) {
assert(image != null);
texture = new Texture(image);
size = texture.size;
pivot = new Point(0.5, 0.5);
}
/// The opacity of the sprite in the range 0.0 to 1.0.
///
/// mySprite.opacity = 0.5;
double get opacity => _opacity;
void set opacity(double opacity) {
assert(opacity != null);
assert(opacity >= 0.0 && opacity <= 1.0);
_opacity = opacity;
}
void paint(RenderCanvas canvas) {
canvas.save();
// Account for pivot point
applyTransformForPivot(canvas);
if (texture != null) {
double w = texture.size.width;
double h = texture.size.height;
if (w <= 0 || h <= 0) return;
double scaleX = size.width / w;
double scaleY = size.height / h;
if (constrainProportions) {
// Constrain proportions, using the smallest scale and by centering the image
if (scaleX < scaleY) {
canvas.translate(0.0, (size.height - scaleX * h) / 2.0);
scaleY = scaleX;
} else {
canvas.translate((size.width - scaleY * w) / 2.0, 0.0);
scaleX = scaleY;
}
}
canvas.scale(scaleX, scaleY);
// Setup paint object for opacity and transfer mode
Paint paint = new Paint();
paint.color = new Color.fromARGB((255.0*_opacity).toInt(), 255, 255, 255);
if (colorOverlay != null) {
paint.setColorFilter(new ColorFilter.mode(colorOverlay, TransferMode.srcATop));
}
if (transferMode != null) {
paint.setTransferMode(transferMode);
}
// Do actual drawing of the sprite
if (texture.rotated) {
// Calculate the rotated frame and spriteSourceSize
Size originalFrameSize = texture.frame.size;
Rect rotatedFrame = new Rect.fromPointAndSize(texture.frame.upperLeft, new Size(originalFrameSize.height, originalFrameSize.width));
Point rotatedSpriteSourcePoint = new Point(
-texture.spriteSourceSize.top - (texture.spriteSourceSize.bottom - texture.spriteSourceSize.top),
texture.spriteSourceSize.left);
Rect rotatedSpriteSourceSize = new Rect.fromPointAndSize(rotatedSpriteSourcePoint, new Size(originalFrameSize.height, originalFrameSize.width));
// Draw the rotated sprite
canvas.rotate(-Math.PI/2.0);
canvas.drawImageRect(texture.image, rotatedFrame, rotatedSpriteSourceSize, paint);
} else {
// Draw the sprite
canvas.drawImageRect(texture.image, texture.frame, texture.spriteSourceSize, paint);
}
} else {
// Paint a red square for missing texture
canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, size.width, size.height),
new Paint()..color = const Color.fromARGB(255, 255, 0, 0));
}
canvas.restore();
}
}

View File

@ -1,381 +0,0 @@
part of sprites;
/// Options for setting up a [SpriteBox].
///
/// * [nativePoints], use the same points as the parent [Widget].
/// * [letterbox], use the size of the root node for the coordinate system, constrain the aspect ratio and trim off
/// areas that end up outside the screen.
/// * [stretch], use the size of the root node for the coordinate system, scale it to fit the size of the box.
/// * [scaleToFit], similar to the letterbox option, but instead of trimming areas the sprite system will be scaled
/// down to fit the box.
/// * [fixedWidth], uses the width of the root node to set the size of the coordinate system, this option will change
/// the height of the root node to fit the box.
/// * [fixedHeight], uses the height of the root node to set the size of the coordinate system, this option will change
/// the width of the root node to fit the box.
enum SpriteBoxTransformMode {
nativePoints,
letterbox,
stretch,
scaleToFit,
fixedWidth,
fixedHeight,
}
class SpriteBox extends RenderBox {
// Member variables
// Root node for drawing
NodeWithSize _rootNode;
// Tracking of frame rate and updates
double _lastTimeStamp;
int _numFrames = 0;
double _frameRate = 0.0;
// Transformation mode
SpriteBoxTransformMode _transformMode;
/// The transform mode used by the [SpriteBox].
SpriteBoxTransformMode get transformMode => _transformMode;
// Cached transformation matrix
Matrix4 _transformMatrix;
List<Node> _eventTargets;
// Setup
/// Creates a new SpriteBox with a node as its content, by default uses letterboxing.
///
/// The [rootNode] provides the content of the node tree, typically it's a custom subclass of [NodeWithSize]. The
/// [mode] provides different ways to scale the content to best fit it to the screen. In most cases it's preferred to
/// use a [SpriteWidget] that automatically wraps the SpriteBox.
///
/// var spriteBox = new SpriteBox(myNode, SpriteBoxTransformMode.fixedHeight);
SpriteBox(NodeWithSize rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.letterbox]) {
assert(rootNode != null);
assert(rootNode._spriteBox == null);
// Setup root node
_rootNode = rootNode;
// Assign SpriteBox reference to all the nodes
_addSpriteBoxReference(_rootNode);
// Setup transform mode
_transformMode = mode;
_scheduleTick();
}
void _addSpriteBoxReference(Node node) {
node._spriteBox = this;
for (Node child in node._children) {
_addSpriteBoxReference(child);
}
}
// Properties
/// The root node of the node tree that is rendered by this box.
///
/// var rootNode = mySpriteBox.rootNode;
NodeWithSize get rootNode => _rootNode;
void performLayout() {
size = constraints.constrain(Size.infinite);
_invalidateTransformMatrix();
_callSpriteBoxPerformedLayout(_rootNode);
}
// Event handling
void _addEventTargets(Node node, List<Node> eventTargets) {
List children = node.children;
int i = 0;
// Add childrens that are behind this node
while (i < children.length) {
Node child = children[i];
if (child.zPosition >= 0.0) break;
_addEventTargets(child, eventTargets);
i++;
}
// Add this node
if (node.userInteractionEnabled) {
eventTargets.add(node);
}
// Add children in front of this node
while (i < children.length) {
Node child = children[i];
_addEventTargets(child, eventTargets);
i++;
}
}
void handleEvent(Event event, _SpriteBoxHitTestEntry entry) {
if (event is PointerEvent) {
if (event.type == 'pointerdown') {
// Build list of event targets
if (_eventTargets == null) {
_eventTargets = [];
_addEventTargets(_rootNode, _eventTargets);
}
// Find the once that are hit by the pointer
List<Node> nodeTargets = [];
for (int i = _eventTargets.length - 1; i >= 0; i--) {
Node node = _eventTargets[i];
// Check if the node is ready to handle a pointer
if (node.handleMultiplePointers || node._handlingPointer == null) {
// Do the hit test
Point posInNodeSpace = node.convertPointToNodeSpace(entry.localPosition);
if (node.isPointInside(posInNodeSpace)) {
nodeTargets.add(node);
node._handlingPointer = event.pointer;
}
}
}
entry.nodeTargets = nodeTargets;
}
// Pass the event down to nodes that were hit by the pointerdown
List<Node> targets = entry.nodeTargets;
for (Node node in targets) {
// Check if this event should be dispatched
if (node.handleMultiplePointers || event.pointer == node._handlingPointer) {
// Dispatch event
bool consumedEvent = node.handleEvent(new SpriteBoxEvent(new Point(event.x, event.y), event.type, event.pointer));
if (consumedEvent == null || consumedEvent) break;
}
}
// De-register pointer for nodes that doesn't handle multiple pointers
for (Node node in targets) {
if (event.type == 'pointerup' || event.type == 'pointercancel') {
node._handlingPointer = null;
}
}
}
}
bool hitTest(HitTestResult result, { Point position }) {
result.add(new _SpriteBoxHitTestEntry(this, position));
return true;
}
// Rendering
/// The transformation matrix used to transform the root node to the space of the box.
///
/// It's uncommon to need access to this property.
///
/// var matrix = mySpriteBox.transformMatrix;
Matrix4 get transformMatrix {
// Get cached matrix if available
if (_transformMatrix != null) {
return _transformMatrix;
}
_transformMatrix = new Matrix4.identity();
// Calculate matrix
double scaleX = 1.0;
double scaleY = 1.0;
double offsetX = 0.0;
double offsetY = 0.0;
double systemWidth = rootNode.size.width;
double systemHeight = rootNode.size.height;
switch(_transformMode) {
case SpriteBoxTransformMode.stretch:
scaleX = size.width/systemWidth;
scaleY = size.height/systemHeight;
break;
case SpriteBoxTransformMode.letterbox:
scaleX = size.width/systemWidth;
scaleY = size.height/systemHeight;
if (scaleX > scaleY) {
scaleY = scaleX;
offsetY = (size.height - scaleY * systemHeight)/2.0;
} else {
scaleX = scaleY;
offsetX = (size.width - scaleX * systemWidth)/2.0;
}
break;
case SpriteBoxTransformMode.scaleToFit:
scaleX = size.width/systemWidth;
scaleY = size.height/systemHeight;
if (scaleX < scaleY) {
scaleY = scaleX;
offsetY = (size.height - scaleY * systemHeight)/2.0;
} else {
scaleX = scaleY;
offsetX = (size.width - scaleX * systemWidth)/2.0;
}
break;
case SpriteBoxTransformMode.fixedWidth:
scaleX = size.width/systemWidth;
scaleY = scaleX;
systemHeight = size.height/scaleX;
rootNode.size = new Size(systemWidth, systemHeight);
break;
case SpriteBoxTransformMode.fixedHeight:
scaleY = size.height/systemHeight;
scaleX = scaleY;
systemWidth = size.width/scaleY;
rootNode.size = new Size(systemWidth, systemHeight);
break;
case SpriteBoxTransformMode.nativePoints:
break;
default:
assert(false);
break;
}
_transformMatrix.translate(offsetX, offsetY);
_transformMatrix.scale(scaleX, scaleY);
return _transformMatrix;
}
void _invalidateTransformMatrix() {
_transformMatrix = null;
_rootNode._invalidateToBoxTransformMatrix();
}
void paint(RenderCanvas canvas) {
canvas.save();
// Move to correct coordinate space before drawing
canvas.concat(transformMatrix.storage);
// Draw the sprite tree
_rootNode._visit(canvas);
canvas.restore();
}
// Updates
int _animationId = 0;
void _scheduleTick() {
_animationId = scheduler.requestAnimationFrame(_tick);
}
void _tick(double timeStamp) {
// Calculate the time between frames in seconds
if (_lastTimeStamp == null) _lastTimeStamp = timeStamp;
double delta = (timeStamp - _lastTimeStamp) / 1000;
_lastTimeStamp = timeStamp;
// Count the number of frames we've been running
_numFrames += 1;
_frameRate = 1.0/delta;
// Print frame rate
if (_numFrames % 60 == 0) print("delta: $delta fps: $_frameRate");
_callUpdate(_rootNode, delta);
_scheduleTick();
}
void _callUpdate(Node node, double dt) {
node.update(dt);
for (Node child in node.children) {
if (!child.paused) {
_callUpdate(child, dt);
}
}
}
void _callSpriteBoxPerformedLayout(Node node) {
node.spriteBoxPerformedLayout();
for (Node child in node.children) {
_callSpriteBoxPerformedLayout(child);
}
}
// Hit tests
/// Finds all nodes at a position defined in the box's coordinates.
///
/// Use this method with caution. It searches the complete node tree to locate the nodes, which can be slow if the
/// node tree is large.
///
/// List nodes = mySpriteBox.findNodesAtPosition(new Point(50.0, 50.0));
List<Node> findNodesAtPosition(Point position) {
assert(position != null);
List<Node> nodes = [];
// Traverse the render tree and find objects at the position
_addNodesAtPosition(_rootNode, position, nodes);
return nodes;
}
_addNodesAtPosition(Node node, Point position, List<Node> list) {
// Visit children first
for (Node child in node.children) {
_addNodesAtPosition(child, position, list);
}
// Do the hit test
Point posInNodeSpace = node.convertPointToNodeSpace(position);
if (node.isPointInside(posInNodeSpace)) {
list.add(node);
}
}
}
class _SpriteBoxHitTestEntry extends BoxHitTestEntry {
List<Node> nodeTargets;
_SpriteBoxHitTestEntry(RenderBox target, Point localPosition) : super(target, localPosition);
}
/// An event that is passed down the node tree when pointer events occur. The SpriteBoxEvent is typically handled in
/// the handleEvent method of [Node].
class SpriteBoxEvent {
/// The position of the event in box coordinates.
///
/// You can use the convertPointToNodeSpace of [Node] to convert the position to local coordinates.
///
/// bool handleEvent(SpriteBoxEvent event) {
/// Point localPosition = convertPointToNodeSpace(event.boxPosition);
/// if (event.type == 'pointerdown') {
/// // Do something!
/// }
/// }
final Point boxPosition;
/// The type of event, there are currently four valid types, 'pointerdown', 'pointermoved', 'pointerup', and
/// 'pointercancel'.
///
/// if (event.type == 'pointerdown') {
/// // Do something!
/// }
final String type;
/// The id of the pointer. Each pointer on the screen will have a unique pointer id.
///
/// if (event.pointer == firstPointerId) {
/// // Do something
/// }
final int pointer;
/// Creates a new SpriteBoxEvent, typically this is done internally inside the SpriteBox.
///
/// var event = new SpriteBoxEvent(new Point(50.0, 50.0), 'pointerdown', 0);
SpriteBoxEvent(this.boxPosition, this.type, this.pointer);
}

View File

@ -1,38 +0,0 @@
part of sprites;
/// A widget that uses a [SpriteBox] to render a sprite node tree to the screen.
class SpriteWidget extends OneChildRenderObjectWrapper {
/// The rootNode of the sprite node tree.
///
/// var node = mySpriteWidget.rootNode;
final NodeWithSize rootNode;
/// The transform mode used to fit the sprite node tree to the size of the widget.
final SpriteBoxTransformMode transformMode;
/// Creates a new sprite widget with [rootNode] as its content.
///
/// The widget will setup the coordinate space for the sprite node tree using the size of the [rootNode] in
/// combination with the supplied [transformMode]. By default the letterbox transform mode is used. See
/// [SpriteBoxTransformMode] for more details on the different modes.
///
/// The most common way to setup the sprite node graph is to subclass [NodeWithSize] and pass it to the sprite widget.
/// In the custom subclass it's possible to build the node graph, do animations and handle user events.
///
/// var mySpriteTree = new MyCustomNodeWithSize();
/// var mySpriteWidget = new SpriteWidget(mySpriteTree, SpriteBoxTransformMode.fixedHeight);
SpriteWidget(this.rootNode, [this.transformMode = SpriteBoxTransformMode.letterbox]);
SpriteBox get root => super.root;
SpriteBox createNode() => new SpriteBox(rootNode, transformMode);
void syncRenderObject(SpriteWidget old) {
super.syncRenderObject(old);
// SpriteBox doesn't allow mutation of these properties
assert(rootNode == root.rootNode);
assert(transformMode == root._transformMode);
}
}

View File

@ -1,23 +0,0 @@
library sprites;
import 'dart:math' as Math;
import 'dart:sky';
import 'dart:typed_data';
import 'dart:convert';
import 'package:sky/base/scheduler.dart' as scheduler;
import 'package:sky/mojo/net/image_cache.dart' as image_cache;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/widgets/widget.dart';
import 'package:vector_math/vector_math.dart';
import 'package:sky/framework/net/fetch.dart';
part 'sprite_box.dart';
part 'sprite_widget.dart';
part 'node.dart';
part 'node_with_size.dart';
part 'sprite.dart';
part 'image_map.dart';
part 'texture.dart';
part 'spritesheet.dart';

View File

@ -1,74 +0,0 @@
part of sprites;
/// A sprite sheet packs a number of smaller images into a single large image.
///
/// The placement of the smaller images are defined by a json file. The larger image and json file is typically created
/// by a tool such as TexturePacker. The [SpriteSheet] class will take a reference to a larger image and a json string.
/// From the image and the string the [SpriteSheet] creates a number of [Texture] objects. The names of the frames in
/// the sprite sheet definition are used to reference the different textures.
class SpriteSheet {
Image _image;
Map<String, Texture> _textures = new Map();
/// Creates a new sprite sheet from an [_image] and a sprite sheet [jsonDefinition].
///
/// var mySpriteSheet = new SpriteSheet(myImage, jsonString);
SpriteSheet(this._image, String jsonDefinition) {
assert(_image != null);
assert(jsonDefinition != null);
JsonDecoder decoder = new JsonDecoder();
Map file = decoder.convert(jsonDefinition);
assert(file != null);
List frames = file["frames"];
for (Map frameInfo in frames) {
String fileName = frameInfo["filename"];
Rect frame = _readJsonRect(frameInfo["frame"]);
bool rotated = frameInfo["rotated"];
bool trimmed = frameInfo["trimmed"];
Rect spriteSourceSize = _readJsonRect(frameInfo["spriteSourceSize"]);
Size sourceSize = _readJsonSize(frameInfo["sourceSize"]);
Point pivot = _readJsonPoint(frameInfo["pivot"]);
var texture = new Texture._fromSpriteFrame(_image, fileName, sourceSize, rotated, trimmed, frame,
spriteSourceSize, pivot);
_textures[fileName] = texture;
}
}
Rect _readJsonRect(Map data) {
num x = data["x"];
num y = data["y"];
num w = data["w"];
num h = data["h"];
return new Rect.fromLTRB(x.toDouble(), y.toDouble(), (x + w).toDouble(), (y + h).toDouble());
}
Size _readJsonSize(Map data) {
num w = data["w"];
num h = data["h"];
return new Size(w.toDouble(), h.toDouble());
}
Point _readJsonPoint(Map data) {
num x = data["x"];
num y = data["y"];
return new Point(x.toDouble(), y.toDouble());
}
/// The image used by the sprite sheet.
///
/// var spriteSheetImage = mySpriteSheet.image;
Image get image => _image;
/// Returns a texture by its name.
///
/// var myTexture = mySpriteSheet["example.png"];
Texture operator [](String fileName) => _textures[fileName];
}

View File

@ -1,73 +0,0 @@
part of sprites;
/// A texture represents a rectangular area of an image and is typically used to draw a sprite to the screen.
///
/// Normally you get a reference to a texture from a [SpriteSheet], but you can also create one from an [Image].
class Texture {
/// The image that this texture is a part of.
///
/// var textureImage = myTexture.image;
final Image image;
/// The logical size of the texture, before being trimmed by the texture packer.
///
/// var textureSize = myTexture.size;
final Size size;
/// The name of the image acts as a tag when acquiring a reference to it.
///
/// myTexture.name = "new_texture_name";
String name;
/// The texture was rotated 90 degrees when being packed into a sprite sheet.
///
/// if (myTexture.rotated) drawRotated();
final bool rotated;
/// The texture was trimmed when being packed into a sprite sheet.
///
/// bool trimmed = myTexture.trimmed
final bool trimmed;
/// The frame of the trimmed texture inside the image.
///
/// Rect frame = myTexture.frame;
final Rect frame;
/// The offset and size of the trimmed texture inside the image.
///
/// Position represents the offset from the logical [size], the size of the rect represents the size of the trimmed
/// texture.
///
/// Rect spriteSourceSize = myTexture.spriteSourceSize;
final Rect spriteSourceSize;
/// The default pivot point for this texture. When creating a [Sprite] from the texture, this is the pivot point that
/// will be used.
///
/// myTexture.pivot = new Point(0.5, 0.5);
Point pivot;
/// Creates a new texture from an [Image] object.
///
/// var myTexture = new Texture(myImage);
Texture(Image image) :
size = new Size(image.width.toDouble(), image.height.toDouble()),
image = image,
trimmed = false,
rotated = false,
frame = new Rect.fromLTRB(0.0, 0.0, image.width.toDouble(), image.height.toDouble()),
spriteSourceSize = new Rect.fromLTRB(0.0, 0.0, image.width.toDouble(), image.height.toDouble()),
pivot = new Point(0.5, 0.5);
Texture._fromSpriteFrame(this.image, this.name, this.size, this.rotated, this.trimmed, this.frame,
this.spriteSourceSize, this.pivot) {
}
// Texture textureFromRect(Rect rect, [String name = null]) {
// assert(rect != null);
// Rect frame = new Rect.fromLTRB();
// return new Texture._fromSpriteFrame(image, name, rect.size, false, false, );
// }
}

View File

@ -1,58 +0,0 @@
import 'dart:sky';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/raised_button.dart';
import 'package:sky/widgets/widget.dart';
import 'package:sky/framework/net/fetch.dart';
import 'lib/game_demo.dart';
import 'lib/sprites.dart';
void main() {
// Load images
new ImageMap([
"res/nebula.png",
"res/sprites.png",
],
allImagesLoaded);
}
void allImagesLoaded(ImageMap loader) {
_loader = loader;
fetchBody("res/sprites.json").then((Response response) {
String json = response.bodyAsString();
_spriteSheet = new SpriteSheet(_loader["res/sprites.png"], json);
allResourcesLoaded();
});
}
void allResourcesLoaded() {
runApp(new GameDemoApp());
}
class GameDemoApp extends App {
Widget build() {
return new Stack([
new SpriteWidget(new GameDemoWorld(_loader, _spriteSheet)),
// new StackPositionedChild(
// new Flex([
// new FlexExpandingChild(
// new RaisedButton(child:new Text("Hello")),
// key: 1
// ),
// new FlexExpandingChild(
// new RaisedButton(child:new Text("Foo!")),
// key: 2
// )
// ]),
// right:0.0,
// top: 20.0
// )
]);
}
}
ImageMap _loader;
SpriteSheet _spriteSheet;

View File

@ -1,3 +0,0 @@
name: game
dependencies:
sky: '>=0.0.10 <1.0.0'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 859 KiB

View File

@ -1,165 +0,0 @@
{"frames": [
{
"filename": "arrow.png",
"frame": {"x":2,"y":2,"w":446,"h":283},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":30,"y":49,"w":446,"h":283},
"sourceSize": {"w":512,"h":512},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_0.nrm.png",
"frame": {"x":2,"y":287,"w":200,"h":188},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":200,"h":188},
"sourceSize": {"w":200,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_0.png",
"frame": {"x":204,"y":287,"w":200,"h":188},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":200,"h":188},
"sourceSize": {"w":200,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_1.nrm.png",
"frame": {"x":545,"y":275,"w":204,"h":166},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":204,"h":166},
"sourceSize": {"w":204,"h":166},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_1.png",
"frame": {"x":589,"y":2,"w":204,"h":166},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":204,"h":166},
"sourceSize": {"w":204,"h":166},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_2.nrm.png",
"frame": {"x":795,"y":2,"w":194,"h":165},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":194,"h":165},
"sourceSize": {"w":194,"h":165},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_2.png",
"frame": {"x":795,"y":169,"w":194,"h":165},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":194,"h":165},
"sourceSize": {"w":194,"h":167},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_0.nrm.png",
"frame": {"x":646,"y":170,"w":102,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":102,"h":84},
"sourceSize": {"w":102,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_0.png",
"frame": {"x":862,"y":336,"w":102,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":102,"h":84},
"sourceSize": {"w":102,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_1.nrm.png",
"frame": {"x":450,"y":171,"w":96,"h":102},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":102},
"sourceSize": {"w":96,"h":102},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_1.png",
"frame": {"x":548,"y":171,"w":96,"h":102},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":102},
"sourceSize": {"w":96,"h":106},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_2.nrm.png",
"frame": {"x":751,"y":336,"w":109,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":109,"h":84},
"sourceSize": {"w":109,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_2.png",
"frame": {"x":751,"y":422,"w":109,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":109,"h":84},
"sourceSize": {"w":109,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "laser.png",
"frame": {"x":751,"y":170,"w":37,"h":76},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":37,"h":76},
"sourceSize": {"w":37,"h":76},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "ship.nrm.png",
"frame": {"x":406,"y":287,"w":137,"h":167},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":137,"h":167},
"sourceSize": {"w":137,"h":167},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "ship.png",
"frame": {"x":450,"y":2,"w":137,"h":167},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":25,"y":10,"w":137,"h":167},
"sourceSize": {"w":188,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "star.png",
"frame": {"x":862,"y":422,"w":62,"h":68},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":5,"w":62,"h":68},
"sourceSize": {"w":82,"h":78},
"pivot": {"x":0.5,"y":0.5}
}],
"meta": {
"app": "http://www.codeandweb.com/texturepacker",
"version": "1.0",
"image": "sprites.png",
"format": "RGBA8888",
"size": {"w":991,"h":508},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:b79d98a34caa23746c4e2af6dd5b8506:bfdb7027c351003110a2082bbb53a657:1eabdf11f75e3a4fe3147baf7b5be24b$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 KiB

View File

@ -1,11 +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.
import 'package:sky/framework/fn.dart';
class HelloWorldApp extends App {
UINode build() {
return new Text('Hello, world!');
}
}

View File

@ -1,7 +0,0 @@
<script>
import 'hello_world.dart';
void main() {
new HelloWorldApp();
}
</script>

View File

@ -1,3 +0,0 @@
name: hello_world
dependencies:
sky: any

View File

@ -1,51 +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.
import 'dart:sky' as sky;
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/box.dart';
class RenderSolidColorBox extends RenderDecoratedBox {
final Size desiredSize;
final Color backgroundColor;
RenderSolidColorBox(Color backgroundColor, { this.desiredSize: Size.infinite })
: backgroundColor = backgroundColor,
super(decoration: new BoxDecoration(backgroundColor: backgroundColor));
double getMinIntrinsicWidth(BoxConstraints constraints) {
return constraints.constrainHeight(
this.desiredSize == Size.infinite ? 0.0 : desiredSize.width
);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
return constraints.constrainWidth(
this.desiredSize == Size.infinite ? 0.0 : desiredSize.width
);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
return constraints.constrainHeight(
this.desiredSize == Size.infinite ? 0.0 : desiredSize.height
);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return constraints.constrainHeight(
this.desiredSize == Size.infinite ? 0.0 : desiredSize.height
);
}
void performLayout() {
size = constraints.constrain(desiredSize);
}
void handleEvent(sky.Event event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown')
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
else if (event.type == 'pointerup')
decoration = new BoxDecoration(backgroundColor: backgroundColor);
}
}

View File

@ -1,373 +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.
import 'dart:sky' as sky;
import 'dart:math';
import 'package:sky/rendering/flex.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/painting/text_style.dart';
// Classic minesweeper-inspired game. The mouse controls are standard except
// for left + right combo which is not implemented. For touch, the duration of
// the pointer determines probing versus flagging.
//
// There are only 3 classes to understand. Game, which is contains all the
// logic and two UI classes: CoveredMineNode and ExposedMineNode, none of them
// holding state.
class Game {
static const int rows = 9;
static const int cols = 9;
static const int totalMineCount = 11;
static const int coveredCell = 0;
static const int explodedCell = 1;
static const int clearedCell = 2;
static const int flaggedCell = 3;
static const int shownCell = 4;
static final List<TextStyle> textStyles = new List<TextStyle>();
final App app;
bool alive;
bool hasWon;
int detectedCount;
int randomSeed;
// |cells| keeps track of the positions of the mines.
List<List<bool>> cells;
// |uiState| keeps track of the visible player progess.
List<List<int>> uiState;
Game(this.app) {
randomSeed = 22;
// Colors for each mine count:
// 0 - none, 1 - blue, 2-green, 3-red, 4-black, 5-dark red .. etc.
textStyles.add(
new TextStyle(color: const Color(0xFF555555), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFF0094FF), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFF13A023), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFFDA1414), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFF1E2347), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFF7F0037), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFFE93BE9), fontWeight: bold));
initialize();
}
void initialize() {
alive = true;
hasWon = false;
detectedCount = 0;
// Build the arrays.
cells = new List<List<bool>>();
uiState = new List<List<int>>();
for (int iy = 0; iy != rows; iy++) {
cells.add(new List<bool>());
uiState.add(new List<int>());
for (int ix = 0; ix != cols; ix++) {
cells[iy].add(false);
uiState[iy].add(coveredCell);
}
}
// Place the mines.
Random random = new Random(++randomSeed);
for (int mc = 0; mc != totalMineCount; mc++) {
int rx = random.nextInt(rows);
int ry = random.nextInt(cols);
if (cells[ry][rx]) {
// Mine already there. Try again.
--mc;
} else {
cells[ry][rx] = true;
}
}
}
Widget buildBoard() {
bool hasCoveredCell = false;
List<Flex> flexRows = new List<Flex>();
for (int iy = 0; iy != 9; iy++) {
List<Component> row = new List<Component>();
for (int ix = 0; ix != 9; ix++) {
int state = uiState[iy][ix];
int count = mineCount(ix, iy);
if (!alive) {
if (state != explodedCell)
state = cells[iy][ix] ? shownCell : state;
}
if (state == coveredCell) {
row.add(new CoveredMineNode(
this,
flagged: false,
posX: ix, posY: iy));
// Mutating |hasCoveredCell| here is hacky, but convenient, same
// goes for mutating |hasWon| below.
hasCoveredCell = true;
} else if (state == flaggedCell) {
row.add(new CoveredMineNode(
this,
flagged: true,
posX: ix, posY: iy));
} else {
row.add(new ExposedMineNode(
state: state,
count: count));
}
}
flexRows.add(
new Flex(
row,
direction: FlexDirection.horizontal,
justifyContent: FlexJustifyContent.center,
key: 'flex_row($iy)'
));
}
if (!hasCoveredCell) {
// all cells uncovered. Are all mines flagged?
if ((detectedCount == totalMineCount) && alive) {
hasWon = true;
}
}
return new Container(
key: 'minefield',
padding: new EdgeDims.all(10.0),
margin: new EdgeDims.all(10.0),
decoration: new BoxDecoration(backgroundColor: const Color(0xFF6B6B6B)),
child: new Flex(
flexRows,
direction: FlexDirection.vertical,
key: 'flxv'));
}
Widget buildToolBar() {
String banner = hasWon ?
'Awesome!!' : alive ?
'Mine Digger [$detectedCount-$totalMineCount]': 'Kaboom! [press here]';
return new ToolBar(
// FIXME: Strange to have the toolbar be tapable.
center: new Listener(
onPointerDown: handleBannerPointerDown,
child: new Text(banner, style: Theme.of(this.app).text.title)
)
);
}
Widget buildUI() {
// FIXME: We need to build the board before we build the toolbar because
// we compute the win state during build step.
Widget board = buildBoard();
return new Scaffold(
toolbar: buildToolBar(),
body: new Container(
child: new Center(child: board),
decoration: new BoxDecoration(backgroundColor: colors.Grey[50])
)
);
}
void handleBannerPointerDown(sky.PointerEvent event) {
initialize();
app.setState((){});
}
// User action. The user uncovers the cell which can cause losing the game.
void probe(int x, int y) {
if (!alive)
return;
if (uiState[y][x] == flaggedCell)
return;
// Allowed to probe.
if (cells[y][x]) {
// Probed on a mine --> dead!!
uiState[y][x] = explodedCell;
alive = false;
} else {
// No mine, uncover nearby if possible.
cull(x, y);
}
app.setState((){});
}
// User action. The user is sure a mine is at this location.
void flag(int x, int y) {
if (uiState[y][x] == flaggedCell) {
uiState[y][x] = coveredCell;
--detectedCount;
} else {
uiState[y][x] = flaggedCell;
++detectedCount;
}
app.setState((){});
}
// Recursively uncovers cells whose totalMineCount is zero.
void cull(int x, int y) {
if ((x < 0) || (x > rows - 1))
return;
if ((y < 0) || (y > cols - 1))
return;
if (uiState[y][x] == clearedCell)
return;
uiState[y][x] = clearedCell;
if (mineCount(x, y) > 0)
return;
cull(x - 1, y);
cull(x + 1, y);
cull(x, y - 1);
cull(x, y + 1 );
cull(x - 1, y - 1);
cull(x + 1, y + 1);
cull(x + 1, y - 1);
cull(x - 1, y + 1);
}
int mineCount(int x, int y) {
int count = 0;
int my = cols - 1;
int mx = rows - 1;
count += x > 0 ? bombs(x - 1, y) : 0;
count += x < mx ? bombs(x + 1, y) : 0;
count += y > 0 ? bombs(x, y - 1) : 0;
count += y < my ? bombs(x, y + 1 ) : 0;
count += (x > 0) && (y > 0) ? bombs(x - 1, y - 1) : 0;
count += (x < mx) && (y < my) ? bombs(x + 1, y + 1) : 0;
count += (x < mx) && (y > 0) ? bombs(x + 1, y - 1) : 0;
count += (x > 0) && (y < my) ? bombs(x - 1, y + 1) : 0;
return count;
}
int bombs(int x, int y) {
return cells[y][x] ? 1 : 0;
}
}
Widget makeCell(Widget widget) {
return new Container(
padding: new EdgeDims.all(1.0),
height: 27.0, width: 27.0,
decoration: new BoxDecoration(backgroundColor: const Color(0xFFC0C0C0)),
margin: new EdgeDims.all(2.0),
child: widget);
}
Widget makeInnerCell(Widget widget) {
return new Container(
padding: new EdgeDims.all(1.0),
margin: new EdgeDims.all(3.0),
height: 17.0, width: 17.0,
child: widget);
}
class CoveredMineNode extends Component {
final Game game;
final bool flagged;
final int posX;
final int posY;
Stopwatch stopwatch;
CoveredMineNode(this.game, {this.flagged, this.posX, this.posY});
void _handlePointerDown(sky.PointerEvent event) {
if (event.buttons == 1) {
game.probe(posX, posY);
} else if (event.buttons == 2) {
game.flag(posX, posY);
} else {
// Touch event.
stopwatch = new Stopwatch()..start();
}
}
void _handlePointerUp(sky.PointerEvent event) {
if (stopwatch == null)
return;
// Pointer down was a touch event.
var ms = stopwatch.elapsedMilliseconds;
if (stopwatch.elapsedMilliseconds < 250) {
game.probe(posX, posY);
} else {
// Long press flags.
game.flag(posX, posY);
}
stopwatch = null;
}
Widget build() {
Widget text = flagged ?
makeInnerCell(new StyledText(elements : [Game.textStyles[5], '\u2691'])) :
null;
Container inner = new Container(
margin: new EdgeDims.all(2.0),
height: 17.0, width: 17.0,
decoration: new BoxDecoration(backgroundColor: const Color(0xFFD9D9D9)),
child: text);
return makeCell(new Listener(
child: inner,
onPointerDown: _handlePointerDown,
onPointerUp: _handlePointerUp));
}
}
class ExposedMineNode extends Component {
final int state;
final int count;
ExposedMineNode({this.state, this.count});
Widget build() {
StyledText text;
if (state == Game.clearedCell) {
// Uncovered cell with nearby mine count.
if (count != 0)
text = new StyledText(elements : [Game.textStyles[count], '$count']);
} else {
// Exploded mine or shown mine for 'game over'.
int color = state == Game.explodedCell ? 3 : 0;
text = new StyledText(elements : [Game.textStyles[color], '\u2600']);
}
return makeCell(makeInnerCell(text));
}
}
class MineDiggerApp extends App {
Game game;
MineDiggerApp() {
game = new Game(this);
}
Widget build() {
return game.buildUI();
}
}
void main() {
runApp(new MineDiggerApp());
}

View File

@ -1,65 +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.
import 'dart:sky' as sky;
void drawText(sky.Canvas canvas, String lh) {
sky.Paint paint = new sky.Paint();
// offset down
canvas.translate(0.0, 100.0);
// set up the text
sky.Document document = new sky.Document();
sky.Text arabic = document.createText("مرحبا");
sky.Text english = document.createText(" Hello");
sky.Element block = document.createElement('div');
block.style['display'] = 'paragraph';
block.style['font-family'] = 'monospace';
block.style['font-size'] = '50px';
block.style['line-height'] = lh;
block.style['color'] = '#0000A0';
block.appendChild(arabic);
block.appendChild(english);
sky.LayoutRoot layoutRoot = new sky.LayoutRoot();
layoutRoot.rootElement = block;
layoutRoot.maxWidth = sky.view.width - 20.0; // you need to set a width for this to paint
layoutRoot.layout();
// draw a line at the text's baseline
sky.Path path = new sky.Path();
path.moveTo(0.0, 0.0);
path.lineTo(block.maxContentWidth, 0.0);
path.moveTo(0.0, block.alphabeticBaseline);
path.lineTo(block.maxContentWidth, block.alphabeticBaseline);
path.moveTo(0.0, block.height);
path.lineTo(block.maxContentWidth, block.height);
paint.color = const sky.Color(0xFFFF9000);
paint.setStyle(sky.PaintingStyle.stroke);
paint.strokeWidth = 3.0;
canvas.drawPath(path, paint);
// paint the text
layoutRoot.paint(canvas);
}
void main() {
// prepare the rendering
sky.PictureRecorder recorder = new sky.PictureRecorder();
sky.Canvas canvas = new sky.Canvas(recorder, sky.view.width, sky.view.height);
// background
sky.Paint paint = new sky.Paint();
paint.color = const sky.Color(0xFFFFFFFF);
paint.setStyle(sky.PaintingStyle.fill);
canvas.drawRect(new sky.Rect.fromLTRB(0.0, 0.0, sky.view.width, sky.view.height), paint);
canvas.translate(10.0, 0.0);
drawText(canvas, '1.0');
drawText(canvas, 'lh');
// put it on the screen
sky.view.picture = recorder.endRecording();
sky.view.scheduleFrame();
}

View File

@ -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.
import "dart:math";
import 'dart:sky';
Picture draw(int a, int r, int g, int b) {
double width = view.width;
double height = view.height;
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, width, height);
double radius = min(width, height) * 0.45;
Paint paint = new Paint()..color = new Color.fromARGB(a, r, g, b);
canvas.drawCircle(width / 2, height / 2, radius, paint);
return recorder.endRecording();
}
bool handleEvent(Event event) {
if (event.type == "pointerdown") {
view.picture = draw(255, 0, 0, 255);
view.scheduleFrame();
return true;
}
if (event.type == "pointerup") {
view.picture = draw(255, 0, 255, 0);
view.scheduleFrame();
return true;
}
if (event.type == "back") {
print("Pressed back button.");
return true;
}
return false;
}
void main() {
print("Hello, world");
view.picture = draw(255, 0, 255, 0);
view.scheduleFrame();
view.setEventCallback(handleEvent);
}

View File

@ -1,58 +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.
import "dart:math";
import 'dart:sky';
import 'package:sky/framework/shell.dart' as shell;
import 'package:mojom/intents/intents.mojom.dart';
Picture draw(int a, int r, int g, int b) {
double width = view.width;
double height = view.height;
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, width, height);
double radius = min(width, height) * 0.45;
Paint paint = new Paint()..color = new Color.fromARGB(a, r, g, b);
canvas.drawRect(new Rect.fromSize(new Size(width, height)), paint);
return recorder.endRecording();
}
bool handleEvent(Event event) {
if (event.type == "pointerdown") {
view.picture = draw(255, 0, 0, 255);
view.scheduleFrame();
return true;
}
if (event.type == "pointerup") {
view.picture = draw(255, 255, 255, 0);
view.scheduleFrame();
ActivityManagerProxy activityManager = new ActivityManagerProxy.unbound();
Intent intent = new Intent()
..action = 'android.intent.action.VIEW'
..url = 'sky://localhost:9888/sky/examples/raw/hello_world.dart';
shell.requestService(null, activityManager);
activityManager.ptr.startActivity(intent);
return true;
}
if (event.type == "back") {
print("Pressed back button.");
return true;
}
return false;
}
void main() {
print("Hello, world");
view.picture = draw(255, 255, 255, 0);
view.scheduleFrame();
view.setEventCallback(handleEvent);
}

View File

@ -1,92 +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.
import 'dart:sky' as sky;
import 'dart:math' as math;
import 'dart:typed_data';
void beginFrame(double timeStamp) {
sky.PictureRecorder recorder = new sky.PictureRecorder();
Canvas canvas = new Canvas(recorder, sky.view.width, 200.0);
sky.Paint paint = new sky.Paint();
sky.Point mid = new sky.Point(sky.view.width / 2.0, sky.view.height / 2.0);
double radius = math.min(mid.x, mid.y);
canvas.drawPaint(new sky.Paint()..color = const sky.Color(0xFFFFFFFF));
canvas.save();
canvas.translate(-mid.x/2.0, sky.view.height*2.0);
canvas.clipRect(
new sky.Rect.fromLTRB(0.0, -sky.view.height, sky.view.width, radius));
canvas.translate(mid.x, mid.y);
paint.color = const sky.Color.fromARGB(128, 255, 0, 255);
canvas.rotate(math.PI/4.0);
sky.Gradient yellowBlue = new sky.Gradient.linear(
[new sky.Point(-radius, -radius), new sky.Point(0.0, 0.0)],
[const sky.Color(0xFFFFFF00), const sky.Color(0xFF0000FF)]);
canvas.drawRect(new sky.Rect.fromLTRB(-radius, -radius, radius, radius),
new sky.Paint()..setShader(yellowBlue));
// Scale x and y by 0.5.
var scaleMatrix = new Float32List.fromList([
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]);
canvas.concat(scaleMatrix);
paint.color = const sky.Color.fromARGB(128, 0, 255, 0);
canvas.drawCircle(0.0, 0.0, radius, paint);
canvas.restore();
canvas.translate(0.0, 50.0);
var builder = new sky.LayerDrawLooperBuilder()
..addLayerOnTop(
new sky.DrawLooperLayerInfo()
..setOffset(const sky.Point(150.0, 0.0))
..setColorMode(sky.TransferMode.src)
..setPaintBits(sky.PaintBits.all),
(sky.Paint layerPaint) {
layerPaint.color = const sky.Color.fromARGB(128, 255, 255, 0);
layerPaint.setColorFilter(new sky.ColorFilter.mode(
const sky.Color.fromARGB(128, 0, 0, 255), sky.TransferMode.srcIn));
layerPaint.setMaskFilter(new sky.MaskFilter.blur(
sky.BlurStyle.normal, 3.0, highQuality: true));
})
..addLayerOnTop(
new sky.DrawLooperLayerInfo()
..setOffset(const sky.Point(75.0, 75.0))
..setColorMode(sky.TransferMode.src)
..setPaintBits(sky.PaintBits.shader),
(sky.Paint layerPaint) {
sky.Gradient redYellow = new sky.Gradient.radial(
new sky.Point(0.0, 0.0), radius/3.0,
[const sky.Color(0xFFFFFF00), const sky.Color(0xFFFF0000)],
null, sky.TileMode.mirror);
layerPaint.setShader(redYellow);
// Since we're don't set sky.PaintBits.maskFilter, this has no effect.
layerPaint.setMaskFilter(new sky.MaskFilter.blur(
sky.BlurStyle.normal, 50.0, highQuality: true));
})
..addLayerOnTop(
new sky.DrawLooperLayerInfo()..setOffset(const sky.Point(225.0, 75.0)),
(sky.Paint layerPaint) {
// Since this layer uses a DST color mode, this has no effect.
layerPaint.color = const sky.Color.fromARGB(128, 255, 0, 0);
});
paint.setDrawLooper(builder.build());
canvas.drawCircle(0.0, 0.0, radius, paint);
sky.view.picture = recorder.endRecording();
}
void main() {
sky.view.setBeginFrameCallback(beginFrame);
sky.view.scheduleFrame();
}

View File

@ -1,3 +0,0 @@
name: raw
dependencies:
sky: any

View File

@ -1,40 +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.
import 'dart:sky';
void beginFrame(double timeStamp) {
var size = 100.0;
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, view.width, view.height);
canvas.translate(size + 10.0, size + 10.0);
Paint paint = new Paint();
paint.color = const Color.fromARGB(255, 0, 255, 0);
var builder = new LayerDrawLooperBuilder()
// Shadow layer.
..addLayerOnTop(
new DrawLooperLayerInfo()
..setPaintBits(PaintBits.all)
..setOffset(const Point(5.0, 5.0))
..setColorMode(TransferMode.src),
(Paint layerPaint) {
layerPaint.color = const Color.fromARGB(128, 55, 55, 55);
layerPaint.setMaskFilter(
new MaskFilter.blur(BlurStyle.normal, 5.0, highQuality: true));
})
// Main layer.
..addLayerOnTop(new DrawLooperLayerInfo(), (Paint) {});
paint.setDrawLooper(builder.build());
canvas.drawPaint(
new Paint()..color = const Color.fromARGB(255, 255, 255, 255));
canvas.drawRect(new Rect.fromLTRB(-size, -size, size, size), paint);
view.picture = recorder.endRecording();
}
void main() {
view.setBeginFrameCallback(beginFrame);
view.scheduleFrame();
}

View File

@ -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.
import "dart:math" as math;
import 'dart:sky';
double timeBase = null;
LayoutRoot layoutRoot = new LayoutRoot();
void beginFrame(double timeStamp) {
if (timeBase == null)
timeBase = timeStamp;
double delta = timeStamp - timeBase;
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, view.width, view.height);
canvas.translate(view.width / 2.0, view.height / 2.0);
canvas.rotate(math.PI * delta / 1800);
canvas.drawRect(new Rect.fromLTRB(-100.0, -100.0, 100.0, 100.0),
new Paint()..color = const Color.fromARGB(255, 0, 255, 0));
double sin = math.sin(delta / 200);
layoutRoot.maxWidth = 150.0 + (50 * sin);
layoutRoot.layout();
canvas.translate(layoutRoot.maxWidth / -2.0, (layoutRoot.maxWidth / 2.0) - 125);
layoutRoot.paint(canvas);
view.picture = recorder.endRecording();
view.scheduleFrame();
}
void main() {
var document = new Document();
var arabic = document.createText("هذا هو قليلا طويلة من النص الذي يجب التفاف .");
var more = document.createText(" و أكثر قليلا لجعله أطول. ");
var block = document.createElement('p');
block.style['display'] = 'paragraph';
block.style['direction'] = 'rtl';
block.style['unicode-bidi'] = 'plaintext';
block.appendChild(arabic);
block.appendChild(more);
layoutRoot.rootElement = block;
view.setBeginFrameCallback(beginFrame);
view.scheduleFrame();
}

View File

@ -1,73 +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.
import 'dart:math' as math;
import 'dart:sky';
import 'package:sky/mojo/net/image_cache.dart' as image_cache;
double timeBase = null;
Image image = null;
String url1 = "https://www.dartlang.org/logos/dart-logo.png";
String url2 = "http://i2.kym-cdn.com/photos/images/facebook/000/581/296/c09.jpg";
void beginFrame(double timeStamp) {
if (timeBase == null) timeBase = timeStamp;
double delta = timeStamp - timeBase;
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, view.width, view.height);
canvas.translate(view.width / 2.0, view.height / 2.0);
canvas.rotate(math.PI * delta / 1800);
canvas.scale(0.2, 0.2);
Paint paint = new Paint()..color = const Color.fromARGB(255, 0, 255, 0);
// Draw image
if (image != null)
canvas.drawImage(image, -image.width / 2.0, -image.height / 2.0, paint);
// Draw cut out of image
canvas.rotate(math.PI * delta / 1800);
if (image != null) {
var w = image.width.toDouble();
var h = image.width.toDouble();
canvas.drawImageRect(image,
new Rect.fromLTRB(w * 0.25, h * 0.25, w * 0.75, h * 0.75),
new Rect.fromLTRB(-w / 4.0, -h / 4.0, w / 4.0, h / 4.0),
paint);
}
view.picture = recorder.endRecording();
view.scheduleFrame();
}
void handleImageLoad(result) {
if (result != image) {
print("${result.width}x${result.width} image loaded!");
image = result;
view.scheduleFrame();
} else {
print("Existing image was loaded again");
}
}
bool handleEvent(Event event) {
if (event.type == "pointerdown") {
return true;
}
if (event.type == "pointerup") {
image_cache.load(url2, handleImageLoad);
return true;
}
return false;
}
void main() {
image_cache.load(url1, handleImageLoad);
image_cache.load(url1, handleImageLoad);
view.setEventCallback(handleEvent);
view.setBeginFrameCallback(beginFrame);
}

View File

@ -1,29 +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.
import 'dart:sky';
import 'dart:math' as math;
double timeBase = null;
void beginFrame(double timeStamp) {
tracing.begin('beginFrame');
if (timeBase == null)
timeBase = timeStamp;
double delta = timeStamp - timeBase;
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, view.width, view.height);
canvas.translate(view.width / 2.0, view.height / 2.0);
canvas.rotate(math.PI * delta / 1800);
canvas.drawRect(new Rect.fromLTRB(-100.0, -100.0, 100.0, 100.0),
new Paint()..color = const Color.fromARGB(255, 0, 255, 0));
view.picture = recorder.endRecording();
view.scheduleFrame();
tracing.end('beginFrame');
}
void main() {
view.setBeginFrameCallback(beginFrame);
view.scheduleFrame();
}

View File

@ -1,70 +0,0 @@
#!mojo mojo:sky_viewer
<sky>
<import src="/packages/sky/framework/debug/shake-to-reload.sky" />
<style>
dot {
position: absolute;
height: 10px;
width: 10px;
background-color: #00FF00;
border-radius: 5px;
opacity: .75;
}
log {
display: paragraph;
margin-top: 50px;
}
</style>
<log>Touch the screen!</log>
<script>
import "dart:sky";
// Material design colors. :p
List<String> colors = [
"#009688",
"#FFC107",
"#9C27B0",
"#03A9F4",
"#673AB7",
"#CDDC39",
];
Element whichDot(event) {
return document.querySelector('dot[id="${event.pointer}"]');
}
void moreDots(event) {
Element dot = document.createElement('dot');
dot.setAttribute('id', "${event.pointer}");
dot.style['background-color'] = colors[event.pointer.remainder(colors.length)];
document.querySelector('sky').appendChild(dot);
runToTheCenter(event);
}
void goAway(event) {
whichDot(event).remove();
}
void stopDots(event) {
for (Element e in document.querySelectorAll('dot'))
e.remove();
}
void runToTheCenter(event) {
double radius = (5 + (95 * event.pressure));
Element dot = whichDot(event);
dot.style["transform"] = "translate(${event.x-radius}px,${event.y-radius}px)";
dot.style["width"] = "${2 * radius}px";
dot.style["height"] = "${2 * radius}px";
dot.style["border-radius"] = "${radius}px";
}
void main() {
document.addEventListener("pointerdown", moreDots);
document.addEventListener("pointermove", runToTheCenter);
document.addEventListener("pointerup", goAway);
document.addEventListener("pointercancel", stopDots);
}
</script>
</sky>

View File

@ -1,78 +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.
import 'dart:sky' as sky;
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/block.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/sky_binding.dart';
RenderBox getBox(double lh) {
RenderParagraph paragraph = new RenderParagraph(
new InlineStyle(
new TextStyle(),
[
new InlineText('test'),
new InlineStyle(
new TextStyle(
color: const Color(0xFF0000A0),
fontFamily: 'serif',
fontSize: 50.0,
height: lh
),
[new InlineText('مرحبا Hello')]
)
]
)
);
return new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 200.0),
child: new RenderDecoratedBox(
decoration: new BoxDecoration(
backgroundColor: const Color(0xFFFFFFFF)
),
child: new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderCustomPaint(
child: paragraph,
callback: (canvas, size) {
double baseline = paragraph.getDistanceToBaseline(TextBaseline.alphabetic);
double w = paragraph.getMaxIntrinsicWidth(new BoxConstraints.loose(size));
double h = paragraph.getMaxIntrinsicHeight(new BoxConstraints.loose(size));
Path path = new Path();
path.moveTo(0.0, 0.0);
path.lineTo(w, 0.0);
path.moveTo(0.0, baseline);
path.lineTo(w, baseline);
path.moveTo(0.0, h);
path.lineTo(w, h);
Paint paint = new Paint();
paint.color = const Color(0xFFFF9000);
paint.setStyle(sky.PaintingStyle.stroke);
paint.strokeWidth = 3.0;
canvas.drawPath(path, paint);
}
)
)
)
)
);
}
void main() {
RenderBox root = new RenderBlock(children: [
new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 50.0)
),
getBox(1.0),
getBox(null),
]);
var b = new SkyBinding(root: root);
// b.onFrame = b.debugDumpRenderTree;
}

View File

@ -1,77 +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.
import 'dart:math' as math;
import 'dart:sky' as sky;
import 'package:sky/rendering/block.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/sky_binding.dart';
void main() {
var root = new RenderBlock(children: [
new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
child: new RenderDecoratedBox(
decoration: new BoxDecoration(
backgroundColor: new sky.Color(0xFFFFFF00)
)
)
)
),
new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
child: new RenderDecoratedBox(
decoration: new BoxDecoration(
border: new Border(
top: new BorderSide(color: new sky.Color(0xFFF00000), width: 5.0),
right: new BorderSide(color: new sky.Color(0xFFFF9000), width: 10.0),
bottom: new BorderSide(color: new sky.Color(0xFFFFF000), width: 15.0),
left: new BorderSide(color: new sky.Color(0xFF00FF00), width: 20.0)
),
backgroundColor: new sky.Color(0xFFDDDDDD)
)
)
)
),
new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
child: new RenderDecoratedBox(
decoration: new BoxDecoration(
backgroundColor: new sky.Color(0xFFFFFF00)
)
)
)
),
new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
child: new RenderDecoratedBox(
decoration: new BoxDecoration(
backgroundColor: new sky.Color(0xFFFFFF00)
)
)
)
),
new RenderPadding(
padding: new EdgeDims.all(10.0),
child: new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tightFor(height: 100.0),
child: new RenderDecoratedBox(
decoration: new BoxDecoration(
backgroundColor: new sky.Color(0xFFFFFF00)
)
)
)
),
]);
new SkyBinding(root: root);
}

View File

@ -1,101 +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.
import 'dart:sky';
import 'dart:math' as math;
import 'package:sky/mojo/net/image_cache.dart' as image_cache;
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/block.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/sky_binding.dart';
import '../lib/solid_color_box.dart';
class Touch {
final double x;
final double y;
const Touch(this.x, this.y);
}
class RenderImageGrow extends RenderImage {
final Size _startingSize;
RenderImageGrow(String src, Size size) : _startingSize = size, super(src, size);
double _growth = 0.0;
double get growth => _growth;
void set growth(double value) {
_growth = value;
double newWidth = _startingSize.width == null ? null : _startingSize.width + growth;
double newHeight = _startingSize.height == null ? null : _startingSize.height + growth;
requestedSize = new Size(newWidth, newHeight);
}
}
RenderImageGrow image;
Map<int, Touch> touches = new Map();
void handleEvent(event) {
if (event is PointerEvent) {
if (event.type == 'pointermove')
image.growth = math.max(0.0, image.growth + event.x - touches[event.pointer].x);
touches[event.pointer] = new Touch(event.x, event.y);
}
}
void main() {
void addFlexChildSolidColor(RenderFlex parent, Color backgroundColor, { int flex: 0 }) {
RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
parent.add(child);
child.parentData.flex = flex;
}
var row = new RenderFlex(direction: FlexDirection.horizontal);
// Left cell
addFlexChildSolidColor(row, const Color(0xFF00D2B8), flex: 1);
// Resizeable image
image = new RenderImageGrow("https://www.dartlang.org/logos/dart-logo.png",
new Size(100.0, null));
var padding = new RenderPadding(padding: const EdgeDims.all(10.0), child: image);
row.add(padding);
RenderFlex column = new RenderFlex(direction: FlexDirection.vertical);
// Top cell
addFlexChildSolidColor(column, const Color(0xFF55DDCA), flex: 1);
// The internet is a beautiful place. https://baconipsum.com/
String meatyString = """Bacon ipsum dolor amet ham fatback tri-tip, prosciutto
porchetta bacon kevin meatball meatloaf pig beef ribs chicken. Brisket ribeye
andouille leberkas capicola meatloaf. Chicken pig ball tip pork picanha bresaola
alcatra. Pork pork belly alcatra, flank chuck drumstick biltong doner jowl.
Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
var text = new InlineStyle(
new TextStyle(color: const Color(0xFF009900)),
[new InlineText(meatyString)]);
padding = new RenderPadding(
padding: const EdgeDims.all(10.0),
child: new RenderParagraph(text));
column.add(padding);
// Bottom cell
addFlexChildSolidColor(column, const Color(0xFF0081C6), flex: 2);
row.add(column);
column.parentData.flex = 8;
RenderDecoratedBox root = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF)),
child: row
);
new SkyBinding(root: root);
view.setEventCallback(handleEvent);
}

View File

@ -1,46 +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.
import 'dart:sky';
import 'dart:math' as math;
import 'package:sky/rendering/block.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/sky_binding.dart';
import '../lib/solid_color_box.dart';
// Attempts to draw
// http://www.w3.org/TR/2015/WD-css-flexbox-1-20150514/images/flex-pack.svg
void main() {
var table = new RenderFlex(direction: FlexDirection.vertical);
void addRow(FlexJustifyContent justify) {
RenderParagraph paragraph = new RenderParagraph(new InlineText("${justify}"));
table.add(new RenderPadding(child: paragraph, padding: new EdgeDims.only(top: 20.0)));
var row = new RenderFlex(direction: FlexDirection.horizontal);
row.add(new RenderSolidColorBox(const Color(0xFFFFCCCC), desiredSize: new Size(80.0, 60.0)));
row.add(new RenderSolidColorBox(const Color(0xFFCCFFCC), desiredSize: new Size(64.0, 60.0)));
row.add(new RenderSolidColorBox(const Color(0xFFCCCCFF), desiredSize: new Size(160.0, 60.0)));
row.justifyContent = justify;
table.add(row);
row.parentData.flex = 1;
}
addRow(FlexJustifyContent.flexStart);
addRow(FlexJustifyContent.flexEnd);
addRow(FlexJustifyContent.center);
addRow(FlexJustifyContent.spaceBetween);
addRow(FlexJustifyContent.spaceAround);
RenderDecoratedBox root = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF)),
child: new RenderPadding(child: table, padding: new EdgeDims.symmetric(vertical: 50.0))
);
new SkyBinding(root: root);
}

View File

@ -1,46 +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.
import 'dart:sky';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/sky_binding.dart';
import '../lib/solid_color_box.dart';
void main() {
RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.vertical);
RenderObject root = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const Color(0xFF606060)),
child: flexRoot
);
RenderObject child = new RenderSolidColorBox(const Color(0xFFFFFF00));
flexRoot.add(child);
child.parentData.flex = 2;
// The internet is a beautiful place. https://baconipsum.com/
String meatyString = """Bacon ipsum dolor amet ham fatback tri-tip, prosciutto
porchetta bacon kevin meatball meatloaf pig beef ribs chicken. Brisket ribeye
andouille leberkas capicola meatloaf. Chicken pig ball tip pork picanha bresaola
alcatra. Pork pork belly alcatra, flank chuck drumstick biltong doner jowl.
Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
var text = new InlineStyle(
new TextStyle(color: const Color(0xFF009900)),
[new InlineText(meatyString)]);
child = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF)),
child: new RenderParagraph(text)
);
flexRoot.add(child);
child.parentData.flex = 1;
new SkyBinding(root: root);
}

View File

@ -1,540 +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.
import 'dart:math' as math;
import 'dart:sky' as sky;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/sky_binding.dart';
const double kTwoPi = 2 * math.PI;
class SectorConstraints extends Constraints {
const SectorConstraints({
this.minDeltaRadius: 0.0,
this.maxDeltaRadius: double.INFINITY,
this.minDeltaTheta: 0.0,
this.maxDeltaTheta: kTwoPi
});
const SectorConstraints.tight({ double deltaRadius: 0.0, double deltaTheta: 0.0 })
: minDeltaRadius = deltaRadius,
maxDeltaRadius = deltaRadius,
minDeltaTheta = deltaTheta,
maxDeltaTheta = deltaTheta;
final double minDeltaRadius;
final double maxDeltaRadius;
final double minDeltaTheta;
final double maxDeltaTheta;
double constrainDeltaRadius(double deltaRadius) {
return clamp(min: minDeltaRadius, max: maxDeltaRadius, value: deltaRadius);
}
double constrainDeltaTheta(double deltaTheta) {
return clamp(min: minDeltaTheta, max: maxDeltaTheta, value: deltaTheta);
}
bool get isTight => minDeltaTheta >= maxDeltaTheta && minDeltaTheta >= maxDeltaTheta;
}
class SectorDimensions {
const SectorDimensions({ this.deltaRadius: 0.0, this.deltaTheta: 0.0 });
factory SectorDimensions.withConstraints(
SectorConstraints constraints,
{ double deltaRadius: 0.0, double deltaTheta: 0.0 }
) {
return new SectorDimensions(
deltaRadius: constraints.constrainDeltaRadius(deltaRadius),
deltaTheta: constraints.constrainDeltaTheta(deltaTheta)
);
}
final double deltaRadius;
final double deltaTheta;
}
class SectorParentData extends ParentData {
double radius = 0.0;
double theta = 0.0;
}
abstract class RenderSector extends RenderObject {
void setupParentData(RenderObject child) {
if (child.parentData is! SectorParentData)
child.parentData = new SectorParentData();
}
SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
return new SectorDimensions.withConstraints(constraints);
}
SectorConstraints get constraints => super.constraints;
bool debugDoesMeetConstraints() {
assert(constraints != null);
assert(deltaRadius != null);
assert(deltaRadius < double.INFINITY);
assert(deltaTheta != null);
assert(deltaTheta < double.INFINITY);
return constraints.minDeltaRadius <= deltaRadius &&
deltaRadius <= math.max(constraints.minDeltaRadius, constraints.maxDeltaRadius) &&
constraints.minDeltaTheta <= deltaTheta &&
deltaTheta <= math.max(constraints.minDeltaTheta, constraints.maxDeltaTheta);
}
void performResize() {
// default behaviour for subclasses that have sizedByParent = true
deltaRadius = constraints.constrainDeltaRadius(0.0);
deltaTheta = constraints.constrainDeltaTheta(0.0);
}
void performLayout() {
// descendants have to either override performLayout() to set both
// the dimensions and lay out children, or, set sizedByParent to
// true so that performResize()'s logic above does its thing.
assert(sizedByParent);
}
bool hitTest(HitTestResult result, { double radius, double theta }) {
assert(parentData is SectorParentData);
if (radius < parentData.radius || radius >= parentData.radius + deltaRadius ||
theta < parentData.theta || theta >= parentData.theta + deltaTheta)
return false;
hitTestChildren(result, radius: radius, theta: theta);
result.add(new HitTestEntry(this));
return true;
}
void hitTestChildren(HitTestResult result, { double radius, double theta }) { }
double deltaRadius;
double deltaTheta;
}
abstract class RenderDecoratedSector extends RenderSector {
RenderDecoratedSector(BoxDecoration decoration) : _decoration = decoration;
BoxDecoration _decoration;
BoxDecoration get decoration => _decoration;
void set decoration (BoxDecoration value) {
if (value == _decoration)
return;
_decoration = value;
markNeedsPaint();
}
// origin must be set to the center of the circle
void paint(RenderCanvas canvas) {
assert(deltaRadius != null);
assert(deltaTheta != null);
assert(parentData is SectorParentData);
if (_decoration == null)
return;
if (_decoration.backgroundColor != null) {
Paint paint = new Paint()..color = _decoration.backgroundColor;
Path path = new Path();
double outerRadius = (parentData.radius + deltaRadius);
Rect outerBounds = new Rect.fromLTRB(-outerRadius, -outerRadius, outerRadius, outerRadius);
path.arcTo(outerBounds, parentData.theta, deltaTheta, true);
double innerRadius = parentData.radius;
Rect innerBounds = new Rect.fromLTRB(-innerRadius, -innerRadius, innerRadius, innerRadius);
path.arcTo(innerBounds, parentData.theta + deltaTheta, -deltaTheta, false);
path.close();
canvas.drawPath(path, paint);
}
}
}
class SectorChildListParentData extends SectorParentData with ContainerParentDataMixin<RenderSector> { }
class RenderSectorWithChildren extends RenderDecoratedSector with ContainerRenderObjectMixin<RenderSector, SectorChildListParentData> {
RenderSectorWithChildren(BoxDecoration decoration) : super(decoration);
void hitTestChildren(HitTestResult result, { double radius, double theta }) {
RenderSector child = lastChild;
while (child != null) {
assert(child.parentData is SectorChildListParentData);
if (child.hitTest(result, radius: radius, theta: theta))
return;
child = child.parentData.previousSibling;
}
}
}
class RenderSectorRing extends RenderSectorWithChildren {
// lays out RenderSector children in a ring
RenderSectorRing({
BoxDecoration decoration,
double deltaRadius: double.INFINITY,
double padding: 0.0
}) : super(decoration), _padding = padding, _desiredDeltaRadius = deltaRadius;
double _desiredDeltaRadius;
double get desiredDeltaRadius => _desiredDeltaRadius;
void set desiredDeltaRadius(double value) {
assert(value != null);
if (_desiredDeltaRadius != value) {
_desiredDeltaRadius = value;
markNeedsLayout();
}
}
double _padding;
double get padding => _padding;
void set padding(double value) {
// TODO(ianh): avoid code duplication
assert(value != null);
if (_padding != value) {
_padding = value;
markNeedsLayout();
}
}
void setupParentData(RenderObject child) {
// TODO(ianh): avoid code duplication
if (child.parentData is! SectorChildListParentData)
child.parentData = new SectorChildListParentData();
}
SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
double outerDeltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
double innerDeltaRadius = outerDeltaRadius - padding * 2.0;
double childRadius = radius + padding;
double paddingTheta = math.atan(padding / (radius + outerDeltaRadius));
double innerTheta = paddingTheta; // increments with each child
double remainingDeltaTheta = constraints.maxDeltaTheta - (innerTheta + paddingTheta);
RenderSector child = firstChild;
while (child != null) {
SectorConstraints innerConstraints = new SectorConstraints(
maxDeltaRadius: innerDeltaRadius,
maxDeltaTheta: remainingDeltaTheta
);
SectorDimensions childDimensions = child.getIntrinsicDimensions(innerConstraints, childRadius);
innerTheta += childDimensions.deltaTheta;
remainingDeltaTheta -= childDimensions.deltaTheta;
assert(child.parentData is SectorChildListParentData);
child = child.parentData.nextSibling;
if (child != null) {
innerTheta += paddingTheta;
remainingDeltaTheta -= paddingTheta;
}
}
return new SectorDimensions.withConstraints(constraints,
deltaRadius: outerDeltaRadius,
deltaTheta: innerTheta);
}
void performLayout() {
assert(this.parentData is SectorParentData);
deltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
assert(deltaRadius < double.INFINITY);
double innerDeltaRadius = deltaRadius - padding * 2.0;
double childRadius = this.parentData.radius + padding;
double paddingTheta = math.atan(padding / (this.parentData.radius + deltaRadius));
double innerTheta = paddingTheta; // increments with each child
double remainingDeltaTheta = constraints.maxDeltaTheta - (innerTheta + paddingTheta);
RenderSector child = firstChild;
while (child != null) {
SectorConstraints innerConstraints = new SectorConstraints(
maxDeltaRadius: innerDeltaRadius,
maxDeltaTheta: remainingDeltaTheta
);
assert(child.parentData is SectorParentData);
child.parentData.theta = innerTheta;
child.parentData.radius = childRadius;
child.layout(innerConstraints, parentUsesSize: true);
innerTheta += child.deltaTheta;
remainingDeltaTheta -= child.deltaTheta;
assert(child.parentData is SectorChildListParentData);
child = child.parentData.nextSibling;
if (child != null) {
innerTheta += paddingTheta;
remainingDeltaTheta -= paddingTheta;
}
}
deltaTheta = innerTheta;
}
// paint origin is 0,0 of our circle
// each sector then knows how to paint itself at its location
void paint(RenderCanvas canvas) {
// TODO(ianh): avoid code duplication
super.paint(canvas);
RenderSector child = firstChild;
while (child != null) {
assert(child.parentData is SectorChildListParentData);
canvas.paintChild(child, Point.origin);
child = child.parentData.nextSibling;
}
}
}
class RenderSectorSlice extends RenderSectorWithChildren {
// lays out RenderSector children in a stack
RenderSectorSlice({
BoxDecoration decoration,
double deltaTheta: kTwoPi,
double padding: 0.0
}) : super(decoration), _padding = padding, _desiredDeltaTheta = deltaTheta;
double _desiredDeltaTheta;
double get desiredDeltaTheta => _desiredDeltaTheta;
void set desiredDeltaTheta(double value) {
assert(value != null);
if (_desiredDeltaTheta != value) {
_desiredDeltaTheta = value;
markNeedsLayout();
}
}
double _padding;
double get padding => _padding;
void set padding(double value) {
// TODO(ianh): avoid code duplication
assert(value != null);
if (_padding != value) {
_padding = value;
markNeedsLayout();
}
}
void setupParentData(RenderObject child) {
// TODO(ianh): avoid code duplication
if (child.parentData is! SectorChildListParentData)
child.parentData = new SectorChildListParentData();
}
SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
assert(this.parentData is SectorParentData);
double paddingTheta = math.atan(padding / this.parentData.radius);
double outerDeltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
double innerDeltaTheta = outerDeltaTheta - paddingTheta * 2.0;
double childRadius = this.parentData.radius + padding;
double remainingDeltaRadius = constraints.maxDeltaRadius - (padding * 2.0);
RenderSector child = firstChild;
while (child != null) {
SectorConstraints innerConstraints = new SectorConstraints(
maxDeltaRadius: remainingDeltaRadius,
maxDeltaTheta: innerDeltaTheta
);
SectorDimensions childDimensions = child.getIntrinsicDimensions(innerConstraints, childRadius);
childRadius += childDimensions.deltaRadius;
remainingDeltaRadius -= childDimensions.deltaRadius;
assert(child.parentData is SectorChildListParentData);
child = child.parentData.nextSibling;
childRadius += padding;
remainingDeltaRadius -= padding;
}
return new SectorDimensions.withConstraints(constraints,
deltaRadius: childRadius - this.parentData.radius,
deltaTheta: outerDeltaTheta);
}
void performLayout() {
assert(this.parentData is SectorParentData);
deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
assert(deltaTheta <= kTwoPi);
double paddingTheta = math.atan(padding / this.parentData.radius);
double innerTheta = this.parentData.theta + paddingTheta;
double innerDeltaTheta = deltaTheta - paddingTheta * 2.0;
double childRadius = this.parentData.radius + padding;
double remainingDeltaRadius = constraints.maxDeltaRadius - (padding * 2.0);
RenderSector child = firstChild;
while (child != null) {
SectorConstraints innerConstraints = new SectorConstraints(
maxDeltaRadius: remainingDeltaRadius,
maxDeltaTheta: innerDeltaTheta
);
child.parentData.theta = innerTheta;
child.parentData.radius = childRadius;
child.layout(innerConstraints, parentUsesSize: true);
childRadius += child.deltaRadius;
remainingDeltaRadius -= child.deltaRadius;
assert(child.parentData is SectorChildListParentData);
child = child.parentData.nextSibling;
childRadius += padding;
remainingDeltaRadius -= padding;
}
deltaRadius = childRadius - this.parentData.radius;
}
// paint origin is 0,0 of our circle
// each sector then knows how to paint itself at its location
void paint(RenderCanvas canvas) {
// TODO(ianh): avoid code duplication
super.paint(canvas);
RenderSector child = firstChild;
while (child != null) {
assert(child.parentData is SectorChildListParentData);
canvas.paintChild(child, Point.origin);
child = child.parentData.nextSibling;
}
}
}
class RenderBoxToRenderSectorAdapter extends RenderBox {
RenderBoxToRenderSectorAdapter({ double innerRadius: 0.0, RenderSector child }) :
_innerRadius = innerRadius {
_child = child;
adoptChild(_child);
}
double _innerRadius;
double get innerRadius => _innerRadius;
void set innerRadius(double value) {
_innerRadius = value;
markNeedsLayout();
}
RenderSector _child;
RenderSector get child => _child;
void set child(RenderSector value) {
if (_child != null)
dropChild(_child);
_child = value;
adoptChild(_child);
markNeedsLayout();
}
void setupParentData(RenderObject child) {
if (child.parentData is! SectorParentData)
child.parentData = new SectorParentData();
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (child == null)
return super.getMinIntrinsicWidth(constraints);
return getIntrinsicDimensions(constraints).width;
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child == null)
return super.getMaxIntrinsicWidth(constraints);
return getIntrinsicDimensions(constraints).width;
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child == null)
return super.getMinIntrinsicHeight(constraints);
return getIntrinsicDimensions(constraints).height;
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child == null)
return super.getMaxIntrinsicHeight(constraints);
return getIntrinsicDimensions(constraints).height;
}
Size getIntrinsicDimensions(BoxConstraints constraints) {
assert(child is RenderSector);
assert(child.parentData is SectorParentData);
assert(!constraints.isInfinite);
double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxHeight) / 2.0 - innerRadius;
SectorDimensions childDimensions = child.getIntrinsicDimensions(new SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), innerRadius);
double dimension = (innerRadius + childDimensions.deltaRadius) * 2.0;
return constraints.constrain(new Size(dimension, dimension));
}
void performLayout() {
if (child == null) {
size = constraints.constrain(Size.zero);
} else {
assert(child is RenderSector);
assert(!constraints.isInfinite);
double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxHeight) / 2.0 - innerRadius;
assert(child.parentData is SectorParentData);
child.parentData.radius = innerRadius;
child.parentData.theta = 0.0;
child.layout(new SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), parentUsesSize: true);
double dimension = (innerRadius + child.deltaRadius) * 2.0;
size = constraints.constrain(new Size(dimension, dimension));
}
}
// paint origin is 0,0 of our circle
void paint(RenderCanvas canvas) {
super.paint(canvas);
if (child != null) {
Rect bounds = new Rect.fromSize(size);
canvas.paintChild(child, bounds.center);
}
}
bool hitTest(HitTestResult result, { Point position }) {
double x = position.x;
double y = position.y;
if (child == null)
return false;
// translate to our origin
x -= size.width/2.0;
y -= size.height/2.0;
// convert to radius/theta
double radius = math.sqrt(x*x+y*y);
double theta = (math.atan2(x, -y) - math.PI/2.0) % kTwoPi;
if (radius < innerRadius)
return false;
if (radius >= innerRadius + child.deltaRadius)
return false;
if (theta > child.deltaTheta)
return false;
child.hitTest(result, radius: radius, theta: theta);
result.add(new BoxHitTestEntry(this, position));
return true;
}
}
class RenderSolidColor extends RenderDecoratedSector {
RenderSolidColor(Color backgroundColor, {
this.desiredDeltaRadius: double.INFINITY,
this.desiredDeltaTheta: kTwoPi
}) : this.backgroundColor = backgroundColor,
super(new BoxDecoration(backgroundColor: backgroundColor));
double desiredDeltaRadius;
double desiredDeltaTheta;
final Color backgroundColor;
SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
return new SectorDimensions.withConstraints(constraints, deltaTheta: desiredDeltaTheta);
}
void performLayout() {
deltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
}
void handleEvent(sky.Event event, HitTestEntry entry) {
if (event.type == 'pointerdown')
decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
else if (event.type == 'pointerup')
decoration = new BoxDecoration(backgroundColor: backgroundColor);
}
}
RenderBox buildSectorExample() {
RenderSectorRing rootCircle = new RenderSectorRing(padding: 20.0);
rootCircle.add(new RenderSolidColor(const Color(0xFF00FFFF), desiredDeltaTheta: kTwoPi * 0.15));
rootCircle.add(new RenderSolidColor(const Color(0xFF0000FF), desiredDeltaTheta: kTwoPi * 0.4));
RenderSectorSlice stack = new RenderSectorSlice(padding: 2.0);
stack.add(new RenderSolidColor(const Color(0xFFFFFF00), desiredDeltaRadius: 20.0));
stack.add(new RenderSolidColor(const Color(0xFFFF9000), desiredDeltaRadius: 20.0));
stack.add(new RenderSolidColor(const Color(0xFF00FF00)));
rootCircle.add(stack);
return new RenderBoxToRenderSectorAdapter(innerRadius: 50.0, child: rootCircle);
}
void main() {
new SkyBinding(root: buildSectorExample());
}

View File

@ -1,30 +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.
import 'dart:sky';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/theme/colors.dart';
import 'package:sky/theme/shadows.dart';
void main() {
var coloredBox = new RenderDecoratedBox(
decoration: new BoxDecoration(
gradient: new RadialGradient(
center: Point.origin, radius: 500.0,
colors: [Yellow[500], Blue[500]]),
boxShadow: shadows[3])
);
var paddedBox = new RenderPadding(
padding: const EdgeDims.all(50.0),
child: coloredBox);
new SkyBinding(root: new RenderDecoratedBox(
decoration: const BoxDecoration(
backgroundColor: const Color(0xFFFFFFFF)
),
child: paddedBox
));
}

View File

@ -1,50 +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.
import 'dart:sky' as sky;
import 'dart:math' as math;
import 'package:sky/base/scheduler.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:vector_math/vector_math.dart';
import '../lib/solid_color_box.dart';
double timeBase;
RenderTransform transformBox;
void main() {
RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.vertical);
void addFlexChildSolidColor(RenderFlex parent, sky.Color backgroundColor, { int flex: 0 }) {
RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
parent.add(child);
child.parentData.flex = flex;
}
addFlexChildSolidColor(flexRoot, const sky.Color(0xFFFF00FF), flex: 1);
addFlexChildSolidColor(flexRoot, const sky.Color(0xFFFFFF00), flex: 2);
addFlexChildSolidColor(flexRoot, const sky.Color(0xFF00FFFF), flex: 1);
transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity());
RenderPadding root = new RenderPadding(padding: new EdgeDims.all(20.0), child: transformBox);
new SkyBinding(root: root);
addPersistentFrameCallback(rotate);
}
void rotate(double timeStamp) {
if (timeBase == null)
timeBase = timeStamp;
double delta = (timeStamp - timeBase) / 1000; // radians
transformBox.setIdentity();
transformBox.translate(transformBox.size.width / 2.0, transformBox.size.height / 2.0);
transformBox.rotateZ(delta);
transformBox.translate(-transformBox.size.width / 2.0, -transformBox.size.height / 2.0);
}

View File

@ -1,91 +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.
import 'dart:math';
import 'dart:sky';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/rendering/stack.dart';
import 'package:sky/theme/colors.dart';
// Material design colors. :p
List<Color> colors = [
Teal[500],
Amber[500],
Purple[500],
LightBlue[500],
DeepPurple[500],
Lime[500],
];
class Dot {
final Paint _paint;
double x = 0.0;
double y = 0.0;
double radius = 0.0;
Dot({ Color color }) : _paint = new Paint()..color = color;
void update(PointerEvent event) {
x = event.x;
y = event.y;
radius = 5 + (95 * event.pressure);
}
void paint(RenderCanvas canvas) {
canvas.drawCircle(x, y, radius, _paint);
}
}
class RenderTouchDemo extends RenderBox {
Map<int, Dot> dots = new Map();
RenderTouchDemo();
void handleEvent(Event event, BoxHitTestEntry entry) {
switch (event.type) {
case 'pointerdown':
Color color = colors[event.pointer.remainder(colors.length)];
dots[event.pointer] = new Dot(color: color)..update(event);
break;
case 'pointerup':
dots.remove(event.pointer);
break;
case 'pointercancel':
dots = new Map();
break;
case 'pointermove':
dots[event.pointer].update(event);
break;
}
markNeedsPaint();
}
void performLayout() {
size = constraints.constrain(Size.infinite);
}
void paint(RenderCanvas canvas) {
Paint white = new Paint()..color = const Color(0xFFFFFFFF);
canvas.drawRect(new Rect.fromSize(size), white);
for (Dot dot in dots.values)
dot.paint(canvas);
}
}
void main() {
var paragraph = new RenderParagraph(new InlineText("Touch me!"));
var stack = new RenderStack(children: [
new RenderTouchDemo(),
paragraph,
]);
// Prevent the RenderParagraph from filling the whole screen so
// that it doesn't eat events.
paragraph.parentData..top = 40.0
..left = 20.0;
new SkyBinding(root: stack);
}

View File

@ -1,29 +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.
import 'dart:sky' as sky;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:vector_math/vector_math.dart';
void main() {
RenderDecoratedBox green = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const sky.Color(0xFF00FF00))
);
RenderConstrainedBox box = new RenderConstrainedBox(
additionalConstraints: new BoxConstraints.tight(const Size(200.0, 200.0)),
child: green
);
Matrix4 transform = new Matrix4.identity();
RenderTransform spin = new RenderTransform(
transform: transform, child: box);
spin.rotateZ(1.0);
RenderFlex flex = new RenderFlex();
flex.add(spin);
new SkyBinding(root: flex);
}

View File

@ -1,31 +0,0 @@
This sample app is our main test harness right now.
Follow these steps to make sure everything works, comparing the
results to earlier builds:
1. Load the app
2. Scroll down and up.
3. Fling down.
4. Fling up. Verify that it bounces at the top.
5. Tap on rows. Make sure they get ink splashes.
6. Open the drawer.
7. Slide the drawer in and out.
8. Check that you can change the radio buttons.
9. Check for ink splashes on each row but not in the header.
10. Check that you can't scroll the list with the drawer out.
11. Close the drawer.
12. Open the menu.
13. Check the checkbox.
14. Open the menu. Verify the checkbox is checked.
15. Tap another menu item.
16. Hit search.
17. Type a query like "XXI".
18. Dismiss the keyboard.
19. Scroll the list. Verify that you can't overscroll.
20. Tap the search bar. Verify the keyboard comes back.
21. Switch to the voice keyboard. Verify that that keyboard works.
22. Hit the back button.
23. Verify that the floating action button gets ink splashes.
These steps carefully avoid known bugs. See:
https://github.com/domokit/mojo/labels/stock%20demo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,632 +0,0 @@
[
[
"WSFSL",
"WSFS Financial Corporation",
"26.3499",
"n/a",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/wsfsl"
],
[
"WSTC",
"West Corporation",
"34.78",
"$2.93B",
"2013",
"Miscellaneous",
"Business Services",
"http://www.nasdaq.com/symbol/wstc"
],
[
"WSTG",
"Wayside Technology Group, Inc.",
"17.08",
"$83.72M",
"n/a",
"Technology",
"Retail: Computer Software & Peripheral Equipment",
"http://www.nasdaq.com/symbol/wstg"
],
[
"WSTL",
"Westell Technologies, Inc.",
"1.54",
"$92.7M",
"1995",
"Public Utilities",
"Telecommunications Equipment",
"http://www.nasdaq.com/symbol/wstl"
],
[
"WTBA",
"West Bancorporation",
"17.99",
"$288.18M",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/wtba"
],
[
"WTFC",
"Wintrust Financial Corporation",
"47.69",
"$2.23B",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/wtfc"
],
[
"WTFCW",
"Wintrust Financial Corporation",
"25.25",
"n/a",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/wtfcw"
],
[
"WVFC",
"WVS Financial Corp.",
"11.5",
"$23.58M",
"n/a",
"Finance",
"Banks",
"http://www.nasdaq.com/symbol/wvfc"
],
[
"WVVI",
"Willamette Valley Vineyards, Inc.",
"5.9499",
"$28.93M",
"n/a",
"Consumer Non-Durables",
"Beverages (Production/Distribution)",
"http://www.nasdaq.com/symbol/wvvi"
],
[
"WWD",
"Woodward, Inc.",
"48.75",
"$3.17B",
"n/a",
"Energy",
"Industrial Machinery/Components",
"http://www.nasdaq.com/symbol/wwd"
],
[
"WWWW",
"Web.com Group, Inc.",
"18.01",
"$946.04M",
"n/a",
"Technology",
"Computer Software: Prepackaged Software",
"http://www.nasdaq.com/symbol/wwww"
],
[
"WYNN",
"Wynn Resorts, Limited",
"158.47",
"$16.06B",
"2002",
"Consumer Services",
"Hotels/Resorts",
"http://www.nasdaq.com/symbol/wynn"
],
[
"XBKS",
"Xenith Bankshares, Inc.",
"6.4001",
"$82.71M",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/xbks"
],
[
"XCRA",
"Xcerra Corporation",
"8.68",
"$472.42M",
"n/a",
"Capital Goods",
"Electrical Products",
"http://www.nasdaq.com/symbol/xcra"
],
[
"XENE",
"Xenon Pharmaceuticals Inc.",
"19.38",
"$274.83M",
"2014",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/xene"
],
[
"XENT",
"Intersect ENT, Inc.",
"22.7",
"$530.65M",
"2014",
"Health Care",
"Medical/Dental Instruments",
"http://www.nasdaq.com/symbol/xent"
],
[
"XGTI",
"XG Technology, Inc",
"0.49",
"$12.26M",
"2013",
"Consumer Durables",
"Telecommunications Equipment",
"http://www.nasdaq.com/symbol/xgti"
],
[
"XGTIW",
"XG Technology, Inc",
"0.26",
"n/a",
"2013",
"Consumer Durables",
"Telecommunications Equipment",
"http://www.nasdaq.com/symbol/xgtiw"
],
[
"XIV",
"VelocityShares Daily Inverse VIX Short Term ETN",
"31.285",
"$485.35M",
"n/a",
"Finance",
"Investment Bankers/Brokers/Service",
"http://www.nasdaq.com/symbol/xiv"
],
[
"XLNX",
"Xilinx, Inc.",
"41.675",
"$10.9B",
"1990",
"Technology",
"Semiconductors",
"http://www.nasdaq.com/symbol/xlnx"
],
[
"XLRN",
"Acceleron Pharma Inc.",
"39.98",
"$1.29B",
"2013",
"Health Care",
"Biotechnology: Biological Products (No Diagnostic Substances)",
"http://www.nasdaq.com/symbol/xlrn"
],
[
"XNCR",
"Xencor, Inc.",
"15.06",
"$473.52M",
"2013",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/xncr"
],
[
"XNET",
"Xunlei Limited",
"7.25",
"$471.36M",
"2014",
"Technology",
"Computer Software: Prepackaged Software",
"http://www.nasdaq.com/symbol/xnet"
],
[
"XNPT",
"XenoPort, Inc.",
"7.19",
"$447.49M",
"2005",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/xnpt"
],
[
"XOMA",
"XOMA Corporation",
"4.05",
"$469.36M",
"1986",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/xoma"
],
[
"XONE",
"The ExOne Company",
"16.32",
"$235.71M",
"2013",
"Capital Goods",
"Industrial Machinery/Components",
"http://www.nasdaq.com/symbol/xone"
],
[
"XOOM",
"Xoom Corporation",
"16.43",
"$631.69M",
"2013",
"Finance",
"Investment Bankers/Brokers/Service",
"http://www.nasdaq.com/symbol/xoom"
],
[
"XPLR",
"Xplore Technologies Corp",
"6.82",
"$57.83M",
"n/a",
"Technology",
"Computer Manufacturing",
"http://www.nasdaq.com/symbol/xplr"
],
[
"XRAY",
"DENTSPLY International Inc.",
"52.53",
"$7.43B",
"1987",
"Health Care",
"Medical/Dental Instruments",
"http://www.nasdaq.com/symbol/xray"
],
[
"XTLB",
"XTL Biopharmaceuticals Ltd.",
"2.21",
"$25.73M",
"n/a",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/xtlb"
],
[
"XXIA",
"Ixia",
"10.45",
"$819.24M",
"2000",
"Capital Goods",
"Electrical Products",
"http://www.nasdaq.com/symbol/xxia"
],
[
"YDIV",
"First Trust NASDAQ Technology Dividend Index Fund",
"19.3412",
"$12.57M",
"n/a",
"n/a",
"n/a",
"http://www.nasdaq.com/symbol/ydiv"
],
[
"YDLE",
"Yodlee, Inc.",
"13.01",
"$380.3M",
"2014",
"Technology",
"Computer Software: Prepackaged Software",
"http://www.nasdaq.com/symbol/ydle"
],
[
"YHOO",
"Yahoo! Inc.",
"44.11",
"$41.79B",
"1996",
"Technology",
"EDP Services",
"http://www.nasdaq.com/symbol/yhoo"
],
[
"YNDX",
"Yandex N.V.",
"17.01",
"$5.41B",
"2011",
"Technology",
"Computer Software: Programming, Data Processing",
"http://www.nasdaq.com/symbol/yndx"
],
[
"YOD",
"You On Demand Holdings, Inc.",
"2.25",
"$53.4M",
"n/a",
"Consumer Services",
"Television Services",
"http://www.nasdaq.com/symbol/yod"
],
[
"YORW",
"The York Water Company",
"23.07",
"$295.51M",
"n/a",
"Public Utilities",
"Water Supply",
"http://www.nasdaq.com/symbol/yorw"
],
[
"YPRO",
"AdvisorShares YieldPro ETF",
"23.94",
"$68.23M",
"n/a",
"n/a",
"n/a",
"http://www.nasdaq.com/symbol/ypro"
],
[
"YRCW",
"YRC Worldwide, Inc.",
"19.96",
"$623.91M",
"n/a",
"Transportation",
"Trucking Freight/Courier Services",
"http://www.nasdaq.com/symbol/yrcw"
],
[
"YY",
"YY Inc.",
"61.82",
"$3.5B",
"2012",
"Technology",
"EDP Services",
"http://www.nasdaq.com/symbol/yy"
],
[
"Z",
"Zillow Group, Inc.",
"125.42",
"$5.12B",
"2011",
"Miscellaneous",
"Business Services",
"http://www.nasdaq.com/symbol/z"
],
[
"ZAGG",
"ZAGG Inc",
"6.51",
"$197.48M",
"n/a",
"Consumer Services",
"Other Specialty Stores",
"http://www.nasdaq.com/symbol/zagg"
],
[
"ZAZA",
"ZaZa Energy Corporation",
"2.11",
"$27.28M",
"n/a",
"Energy",
"Oil & Gas Production",
"http://www.nasdaq.com/symbol/zaza"
],
[
"ZBRA",
"Zebra Technologies Corporation",
"91",
"$4.63B",
"1991",
"Technology",
"Industrial Machinery/Components",
"http://www.nasdaq.com/symbol/zbra"
],
[
"ZEUS",
"Olympic Steel, Inc.",
"16.35",
"$179.56M",
"1994",
"Basic Industries",
"Metal Fabrications",
"http://www.nasdaq.com/symbol/zeus"
],
[
"ZFGN",
"Zafgen, Inc.",
"40.64",
"$1.08B",
"2014",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/zfgn"
],
[
"ZGNX",
"Zogenix, Inc.",
"1.55",
"$237.21M",
"2010",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/zgnx"
],
[
"ZHNE",
"Zhone Technologies, Inc.",
"1.54",
"$50.05M",
"n/a",
"Public Utilities",
"Telecommunications Equipment",
"http://www.nasdaq.com/symbol/zhne"
],
[
"ZINC",
"Horsehead Holding Corp.",
"13.49",
"$763.52M",
"2007",
"Capital Goods",
"Metal Fabrications",
"http://www.nasdaq.com/symbol/zinc"
],
[
"ZION",
"Zions Bancorporation",
"26.33",
"$5.34B",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/zion"
],
[
"ZIONW",
"Zions Bancorporation",
"3.4",
"n/a",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/zionw"
],
[
"ZIONZ",
"Zions Bancorporation",
"2.45",
"n/a",
"n/a",
"Finance",
"Major Banks",
"http://www.nasdaq.com/symbol/zionz"
],
[
"ZIOP",
"ZIOPHARM Oncology Inc",
"9.56",
"$1.11B",
"n/a",
"Health Care",
"Medical Specialities",
"http://www.nasdaq.com/symbol/ziop"
],
[
"ZIV",
"VelocityShares Daily Inverse VIX Medium Term ETN",
"41.1",
"$37.81M",
"n/a",
"Finance",
"Investment Bankers/Brokers/Service",
"http://www.nasdaq.com/symbol/ziv"
],
[
"ZIXI",
"Zix Corporation",
"3.81",
"$216.48M",
"n/a",
"Technology",
"EDP Services",
"http://www.nasdaq.com/symbol/zixi"
],
[
"ZLTQ",
"ZELTIQ Aesthetics, Inc.",
"34.23",
"$1.3B",
"2011",
"Health Care",
"Biotechnology: Electromedical & Electrotherapeutic Apparatus",
"http://www.nasdaq.com/symbol/zltq"
],
[
"ZN",
"Zion Oil & Gas Inc",
"1.85",
"$65.29M",
"n/a",
"Energy",
"Oil & Gas Production",
"http://www.nasdaq.com/symbol/zn"
],
[
"ZNGA",
"Zynga Inc.",
"2.32",
"$2.09B",
"2011",
"Technology",
"EDP Services",
"http://www.nasdaq.com/symbol/znga"
],
[
"ZNWAA",
"Zion Oil & Gas Inc",
"n/a",
"n/a",
"n/a",
"Energy",
"Oil & Gas Production",
"http://www.nasdaq.com/symbol/znwaa"
],
[
"ZSAN",
"Zosano Pharma Corporation",
"11.09",
"$131.04M",
"2015",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/zsan"
],
[
"ZSPH",
"ZS Pharma, Inc.",
"50.51",
"$1.05B",
"2014",
"Health Care",
"Major Pharmaceuticals",
"http://www.nasdaq.com/symbol/zsph"
],
[
"ZU",
"zulily, inc.",
"14.4",
"$1.8B",
"2013",
"Consumer Services",
"Catalog/Specialty Distribution",
"http://www.nasdaq.com/symbol/zu"
],
[
"ZUMZ",
"Zumiez Inc.",
"38.77",
"$1.13B",
"2005",
"Consumer Services",
"Clothing/Shoe/Accessory Stores",
"http://www.nasdaq.com/symbol/zumz"
]
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,225 +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.
import 'package:sky/framework/components/tool_bar.dart';
import 'package:sky/framework/components/drawer.dart';
import 'package:sky/framework/components/drawer_header.dart';
import 'package:sky/framework/components/floating_action_button.dart';
import 'package:sky/framework/components/icon.dart';
import 'package:sky/framework/components/icon_button.dart';
import 'package:sky/framework/components/input.dart';
import 'package:sky/framework/components/menu_divider.dart';
import 'package:sky/framework/components/menu_item.dart';
import 'package:sky/framework/components/modal_overlay.dart';
import 'package:sky/framework/components/popup_menu.dart';
import 'package:sky/framework/components/radio.dart';
import 'package:sky/framework/components/scaffold.dart';
import 'package:sky/framework/fn.dart';
import 'package:sky/framework/theme/typography.dart' as typography;
import 'package:sky/framework/theme/colors.dart';
import 'stock_data.dart';
import 'stock_list.dart';
import 'stock_menu.dart';
import 'dart:async';
import 'package:sky/framework/layout.dart';
const bool debug = false; // set to true to dump the DOM for debugging purposes
enum StockMode { Optimistic, Pessimistic }
class StocksApp extends App {
static final Style _toolBarStyle = new Style('''
background-color: ${Purple[500]};''');
static final Style _searchBarStyle = new Style('''
background-color: ${Grey[50]};''');
static final Style _titleStyle = new Style('''
${typography.white.title};''');
List<Stock> _stocks = [];
StocksApp() : super() {
if (debug)
new Timer(new Duration(seconds: 1), dumpState);
new StockDataFetcher((StockData data) {
setState(() {
data.appendTo(_stocks);
});
});
_drawerController = new DrawerController(_handleDrawerStatusChanged);
}
bool _isSearching = false;
String _searchQuery;
void _handleSearchBegin(_) {
setState(() {
_isSearching = true;
});
}
void _handleSearchEnd(_) {
setState(() {
_isSearching = false;
_searchQuery = null;
});
}
void _handleSearchQueryChanged(String query) {
setState(() {
_searchQuery = query;
});
}
DrawerController _drawerController;
bool _drawerShowing = false;
void _handleDrawerStatusChanged(bool showing) {
setState(() {
_drawerShowing = showing;
});
}
PopupMenuController _menuController;
void _handleMenuShow(_) {
setState(() {
_menuController = new PopupMenuController();
_menuController.open();
});
}
void _handleMenuHide(_) {
setState(() {
_menuController.close().then((_) {
setState(() {
_menuController = null;
});
});
});
}
bool _autorefresh = false;
void _handleAutorefreshChanged(bool value) {
setState(() {
_autorefresh = value;
});
}
StockMode _stockMode = StockMode.Optimistic;
void _handleStockModeChange(StockMode value) {
setState(() {
_stockMode = value;
});
}
static FlexBoxParentData _flex1 = new FlexBoxParentData()..flex = 1;
Drawer buildDrawer() {
return new Drawer(
controller: _drawerController,
level: 3,
children: [
new DrawerHeader(children: [new Text('Stocks')]),
new MenuItem(
key: 'Stock list',
icon: 'action/assessment',
children: [new Text('Stock List')]),
new MenuItem(
key: 'Account Balance',
icon: 'action/account_balance',
children: [new Text('Account Balance')]),
new MenuDivider(key: 'div1'),
new MenuItem(
key: 'Optimistic Menu Item',
icon: 'action/thumb_up',
onGestureTap: (event) => _handleStockModeChange(StockMode.Optimistic),
children: [
new ParentDataNode(new Text('Optimistic'), _flex1),
new Radio(key: 'optimistic-radio', value: StockMode.Optimistic, groupValue: _stockMode, onChanged: _handleStockModeChange)
]),
new MenuItem(
key: 'Pessimistic Menu Item',
icon: 'action/thumb_down',
onGestureTap: (event) => _handleStockModeChange(StockMode.Pessimistic),
children: [
new ParentDataNode(new Text('Pessimistic'), _flex1),
new Radio(key: 'pessimistic-radio', value: StockMode.Pessimistic, groupValue: _stockMode, onChanged: _handleStockModeChange)
]),
new MenuDivider(key: 'div2'),
new MenuItem(
key: 'Settings',
icon: 'action/settings',
children: [new Text('Settings')]),
new MenuItem(
key: 'Help & Feedback',
icon: 'action/help',
children: [new Text('Help & Feedback')])
]
);
}
UINode buildToolBar() {
return new StyleNode(
new ToolBar(
left: new IconButton(
icon: 'navigation/menu_white',
onGestureTap: _drawerController.toggle),
center: new Container(
style: _titleStyle,
children: [new Text('Stocks')]),
right: [
new IconButton(
icon: 'action/search_white',
onGestureTap: _handleSearchBegin),
new IconButton(
icon: 'navigation/more_vert_white',
onGestureTap: _handleMenuShow)
]),
_toolBarStyle);
}
// TODO(abarth): Should we factor this into a SearchBar in the framework?
UINode buildSearchBar() {
return new StyleNode(
new ToolBar(
left: new IconButton(
icon: 'navigation/arrow_back_grey600',
onGestureTap: _handleSearchEnd),
center: new Input(
focused: true,
placeholder: 'Search stocks',
onChanged: _handleSearchQueryChanged)),
_searchBarStyle);
}
void addMenuToOverlays(List<UINode> overlays) {
if (_menuController == null)
return;
overlays.add(new ModalOverlay(
children: [new StockMenu(
controller: _menuController,
autorefresh: _autorefresh,
onAutorefreshChanged: _handleAutorefreshChanged
)],
onDismiss: _handleMenuHide));
}
UINode build() {
List<UINode> overlays = [];
addMenuToOverlays(overlays);
return new Scaffold(
header: _isSearching ? buildSearchBar() : buildToolBar(),
content: new Stocklist(stocks: _stocks, query: _searchQuery),
fab: new FloatingActionButton(
content: new Icon(type: 'content/add_white', size: 24), level: 3),
drawer: _drawerShowing ? buildDrawer() : null,
overlays: overlays
);
}
}

View File

@ -1,93 +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.
import 'dart:math';
import 'package:sky/framework/fn.dart';
import 'package:sky/framework/layout.dart';
class StockArrow extends Component {
static final Style _style = new Style('''
width: 40px;
height: 40px;
align-items: center;
justify-content: center;
border-radius: 40px;
margin-right: 16px;
border: 1px solid transparent;'''
);
static final Style _upStyle = new Style('''
width: 0;
height: 0;
border-left: 9px solid transparent;
border-right: 9px solid transparent;
margin-bottom: 3px;
border-bottom: 9px solid white;'''
);
static final Style _downStyle = new Style('''
width: 0;
height: 0;
border-left: 9px solid transparent;
border-right: 9px solid transparent;
margin-top: 3px;
border-top: 9px solid white'''
);
double percentChange;
StockArrow({ Object key, this.percentChange }) : super(key: key);
// TODO(abarth): These should use sky/framework/theme/colors.dart.
final List<String> _kRedColors = [
'#E57373',
'#EF5350',
'#F44336',
'#E53935',
'#D32F2F',
'#C62828',
'#B71C1C',
];
// TODO(abarth): These should use sky/framework/theme/colors.dart.
final List<String> _kGreenColors = [
'#81C784',
'#66BB6A',
'#4CAF50',
'#43A047',
'#388E3C',
'#2E7D32',
'#1B5E20',
];
int _colorIndexForPercentChange(double percentChange) {
// Currently the max is 10%.
double maxPercent = 10.0;
return max(0, ((percentChange.abs() / maxPercent) * _kGreenColors.length).floor());
}
String _colorForPercentChange(double percentChange) {
if (percentChange > 0)
return _kGreenColors[_colorIndexForPercentChange(percentChange)];
return _kRedColors[_colorIndexForPercentChange(percentChange)];
}
UINode build() {
String border = _colorForPercentChange(percentChange).toString();
bool up = percentChange > 0;
String type = up ? 'bottom' : 'top';
return new FlexContainer(
inlineStyle: 'border-color: $border',
direction: FlexDirection.Row,
style: _style,
children: [
new Container(
inlineStyle: 'border-$type-color: $border',
style: up ? _upStyle : _downStyle
)
]
);
}
}

View File

@ -1,72 +0,0 @@
// Copyright 2014 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:convert';
import 'dart:math';
import 'package:sky/framework/net/fetch.dart';
// Snapshot from http://www.nasdaq.com/screening/company-list.aspx
// Fetched 2/23/2014.
// "Symbol","Name","LastSale","MarketCap","IPOyear","Sector","industry","Summary Quote",
// Data in stock_data.json
final Random _rng = new Random();
class Stock {
String symbol;
String name;
double lastSale;
String marketCap;
double percentChange;
Stock(this.symbol, this.name, this.lastSale, this.marketCap, this.percentChange);
Stock.fromFields(List<String> fields) {
// FIXME: This class should only have static data, not lastSale, etc.
// "Symbol","Name","LastSale","MarketCap","IPOyear","Sector","industry","Summary Quote",
lastSale = 0.0;
try{
lastSale = double.parse(fields[2]);
} catch(_) {}
symbol = fields[0];
name = fields[1];
marketCap = fields[4];
percentChange = (_rng.nextDouble() * 20) - 10;
}
}
class StockData {
List<List<String>> _data;
StockData(this._data);
void appendTo(List<Stock> stocks) {
for (List<String> fields in _data)
stocks.add(new Stock.fromFields(fields));
}
}
typedef void StockDataCallback(StockData data);
const _kChunkCount = 30;
class StockDataFetcher {
int _currentChunk = 0;
final StockDataCallback callback;
StockDataFetcher(this.callback) {
_fetchNextChunk();
}
void _fetchNextChunk() {
fetchBody('data/stock_data_${_currentChunk++}.json').then((Response response) {
String json = response.bodyAsString();
JsonDecoder decoder = new JsonDecoder();
callback(new StockData(decoder.convert(json)));
if (_currentChunk < _kChunkCount)
_fetchNextChunk();
});
}
}

View File

@ -1,32 +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.
import 'package:sky/framework/components/fixed_height_scrollable.dart';
import 'package:sky/framework/fn.dart';
import 'stock_data.dart';
import 'stock_row.dart';
class Stocklist extends FixedHeightScrollable {
String query;
List<Stock> stocks;
Stocklist({
Object key,
this.stocks,
this.query
}) : super(key: key);
List<UINode> buildItems(int start, int count) {
var filteredStocks = stocks.where((stock) {
return query == null ||
stock.symbol.contains(new RegExp(query, caseSensitive: false));
});
itemCount = filteredStocks.length;
return filteredStocks
.skip(start)
.take(count)
.map((stock) => new StockRow(stock: stock))
.toList(growable: false);
}
}

View File

@ -1,44 +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.
import 'package:sky/framework/fn.dart';
import 'package:sky/framework/layout.dart';
import 'package:sky/framework/components/popup_menu.dart';
import 'package:sky/framework/components/checkbox.dart';
import 'package:sky/framework/theme/view_configuration.dart';
class StockMenu extends Component {
static final Style _style = new Style('''
position: absolute;
right: 8px;
top: ${8 + kStatusBarHeight}px;''');
PopupMenuController controller;
StockMenu({Object key, this.controller, this.autorefresh: false, this.onAutorefreshChanged}) : super(key: key);
final bool autorefresh;
final ValueChanged onAutorefreshChanged;
static FlexBoxParentData _flex1 = new FlexBoxParentData()..flex = 1;
UINode build() {
var checkbox = new Checkbox(
checked: this.autorefresh,
onChanged: this.onAutorefreshChanged
);
return new StyleNode(
new PopupMenu(
controller: controller,
items: [
[new Text('Add stock')],
[new Text('Remove stock')],
[new ParentDataNode(new Text('Autorefresh'), _flex1), checkbox],
],
level: 4),
_style
);
}
}

View File

@ -1,72 +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.
import 'package:sky/framework/components/ink_well.dart';
import 'package:sky/framework/fn.dart';
import 'package:sky/framework/layout.dart';
import 'package:sky/framework/theme/typography.dart' as typography;
import 'stock_arrow.dart';
import 'stock_data.dart';
class StockRow extends Component {
static final Style _style = new Style('''
align-items: center;
border-bottom: 1px solid #F4F4F4;
padding-top: 16px;
padding-left: 16px;
padding-right: 16px;
padding-bottom: 20px;'''
);
static final FlexBoxParentData _tickerFlex = new FlexBoxParentData()..flex = 1;
static final Style _lastSaleStyle = new Style('''
text-align: right;
padding-right: 16px;'''
);
static final Style _changeStyle = new Style('''
${typography.black.caption};
text-align: right;'''
);
Stock stock;
StockRow({Stock stock}) : super(key: stock.symbol) {
this.stock = stock;
}
UINode build() {
String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}";
String changeInPrice = "${stock.percentChange.toStringAsFixed(2)}%";
if (stock.percentChange > 0)
changeInPrice = "+" + changeInPrice;
List<UINode> children = [
new StockArrow(
percentChange: stock.percentChange
),
new ParentDataNode(
new Container(
key: 'Ticker',
children: [new Text(stock.symbol)]
),
_tickerFlex
),
new Container(
key: 'LastSale',
style: _lastSaleStyle,
children: [new Text(lastSale)]
),
new Container(
key: 'Change',
style: _changeStyle,
children: [new Text(changeInPrice)]
)
];
return new StyleNode(new InkWell(children: children), _style);
}
}

View File

@ -1,15 +0,0 @@
#!mojo mojo:sky_viewer
<!--
// 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.
-->
<sky>
<script>
// TODO(abarth): Should this be package:stocks/stocks_app.dart?
import 'lib/stock_app.dart';
void main() {
new StocksApp();
}
</script>
</sky>

View File

@ -1,7 +0,0 @@
name: stocks
author: Chromium Authors <sky-dev@googlegroups.com>
description: A demo application using Sky that shows stock data
homepage: https://github.com/domokit/sky_sdk/tree/master/examples/stocks
version: 0.0.1
dependencies:
sky: '>=0.0.1 <1.0.0'

View File

@ -1,4 +0,0 @@
This is a copy of the stocks app... with everything removed.
The goal is to eventually replace the stocks app with this one, by
adding it back bit by bit as we port it to RenderNode.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More