Add dartdoc for the painting code
This commit is contained in:
parent
bbb29f229f
commit
e525943d81
@ -10,22 +10,40 @@ import 'package:sky/base/image_resource.dart';
|
|||||||
import 'package:sky/base/lerp.dart';
|
import 'package:sky/base/lerp.dart';
|
||||||
import 'package:sky/painting/shadows.dart';
|
import 'package:sky/painting/shadows.dart';
|
||||||
|
|
||||||
|
/// An immutable set of offsets in each of the four cardinal directions
|
||||||
|
///
|
||||||
|
/// Typically used for an offset from each of the four sides of a box. For
|
||||||
|
/// example, the padding inside a box can be represented using this class.
|
||||||
class EdgeDims {
|
class EdgeDims {
|
||||||
// used for e.g. padding
|
// TODO(abarth): Remove this constructor or rename it to EdgeDims.fromTRBL.
|
||||||
|
/// Constructs an EdgeDims from offsets from the top, right, bottom and left
|
||||||
const EdgeDims(this.top, this.right, this.bottom, this.left);
|
const EdgeDims(this.top, this.right, this.bottom, this.left);
|
||||||
|
|
||||||
|
/// Constructs an EdgeDims where all the offsets are value
|
||||||
const EdgeDims.all(double value)
|
const EdgeDims.all(double value)
|
||||||
: top = value, right = value, bottom = value, left = value;
|
: top = value, right = value, bottom = value, left = value;
|
||||||
|
|
||||||
|
/// Constructs an EdgeDims with only the given values non-zero
|
||||||
const EdgeDims.only({ this.top: 0.0,
|
const EdgeDims.only({ this.top: 0.0,
|
||||||
this.right: 0.0,
|
this.right: 0.0,
|
||||||
this.bottom: 0.0,
|
this.bottom: 0.0,
|
||||||
this.left: 0.0 });
|
this.left: 0.0 });
|
||||||
|
|
||||||
|
/// Constructs an EdgeDims with symmetrical vertical and horizontal offsets
|
||||||
const EdgeDims.symmetric({ double vertical: 0.0,
|
const EdgeDims.symmetric({ double vertical: 0.0,
|
||||||
double horizontal: 0.0 })
|
double horizontal: 0.0 })
|
||||||
: top = vertical, left = horizontal, bottom = vertical, right = horizontal;
|
: top = vertical, left = horizontal, bottom = vertical, right = horizontal;
|
||||||
|
|
||||||
|
/// The offset from the top
|
||||||
final double top;
|
final double top;
|
||||||
|
|
||||||
|
/// The offset from the right
|
||||||
final double right;
|
final double right;
|
||||||
|
|
||||||
|
/// The offset from the bottom
|
||||||
final double bottom;
|
final double bottom;
|
||||||
|
|
||||||
|
/// The offset from the left
|
||||||
final double left;
|
final double left;
|
||||||
|
|
||||||
bool operator ==(other) {
|
bool operator ==(other) {
|
||||||
@ -52,6 +70,7 @@ class EdgeDims {
|
|||||||
left - other.left);
|
left - other.left);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An EdgeDims with zero offsets in each direction
|
||||||
static const EdgeDims zero = const EdgeDims(0.0, 0.0, 0.0, 0.0);
|
static const EdgeDims zero = const EdgeDims(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
@ -65,14 +84,20 @@ class EdgeDims {
|
|||||||
String toString() => "EdgeDims($top, $right, $bottom, $left)";
|
String toString() => "EdgeDims($top, $right, $bottom, $left)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A side of a border of a box
|
||||||
class BorderSide {
|
class BorderSide {
|
||||||
const BorderSide({
|
const BorderSide({
|
||||||
this.color: const Color(0xFF000000),
|
this.color: const Color(0xFF000000),
|
||||||
this.width: 1.0
|
this.width: 1.0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// The color of this side of the border
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
|
/// The width of this side of the border
|
||||||
final double width;
|
final double width;
|
||||||
|
|
||||||
|
/// A black border side of zero width
|
||||||
static const none = const BorderSide(width: 0.0);
|
static const none = const BorderSide(width: 0.0);
|
||||||
|
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
@ -84,6 +109,7 @@ class BorderSide {
|
|||||||
String toString() => 'BorderSide($color, $width)';
|
String toString() => 'BorderSide($color, $width)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A border of a box, comprised of four sides
|
||||||
class Border {
|
class Border {
|
||||||
const Border({
|
const Border({
|
||||||
this.top: BorderSide.none,
|
this.top: BorderSide.none,
|
||||||
@ -92,6 +118,7 @@ class Border {
|
|||||||
this.left: BorderSide.none
|
this.left: BorderSide.none
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// A uniform border with all sides the same color and width
|
||||||
factory Border.all({
|
factory Border.all({
|
||||||
Color color: const Color(0xFF000000),
|
Color color: const Color(0xFF000000),
|
||||||
double width: 1.0
|
double width: 1.0
|
||||||
@ -100,11 +127,19 @@ class Border {
|
|||||||
return new Border(top: side, right: side, bottom: side, left: side);
|
return new Border(top: side, right: side, bottom: side, left: side);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The top side of this border
|
||||||
final BorderSide top;
|
final BorderSide top;
|
||||||
|
|
||||||
|
/// The right side of this border
|
||||||
final BorderSide right;
|
final BorderSide right;
|
||||||
|
|
||||||
|
/// The bottom side of this border
|
||||||
final BorderSide bottom;
|
final BorderSide bottom;
|
||||||
|
|
||||||
|
/// The left side of this border
|
||||||
final BorderSide left;
|
final BorderSide left;
|
||||||
|
|
||||||
|
/// The widths of the sides of this border represented as an EdgeDims
|
||||||
EdgeDims get dimensions {
|
EdgeDims get dimensions {
|
||||||
return new EdgeDims(top.width, right.width, bottom.width, left.width);
|
return new EdgeDims(top.width, right.width, bottom.width, left.width);
|
||||||
}
|
}
|
||||||
@ -120,6 +155,10 @@ class Border {
|
|||||||
String toString() => 'Border($top, $right, $bottom, $left)';
|
String toString() => 'Border($top, $right, $bottom, $left)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A shadow cast by a box
|
||||||
|
///
|
||||||
|
/// Note: BoxShadow can cast non-rectangular shadows if the box is
|
||||||
|
/// non-rectangular (e.g., has a border radius or a circular shape).
|
||||||
class BoxShadow {
|
class BoxShadow {
|
||||||
const BoxShadow({
|
const BoxShadow({
|
||||||
this.color,
|
this.color,
|
||||||
@ -127,10 +166,16 @@ class BoxShadow {
|
|||||||
this.blur
|
this.blur
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// The color of the shadow
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
|
/// The displacement of the shadow from the box
|
||||||
final Offset offset;
|
final Offset offset;
|
||||||
|
|
||||||
|
/// The standard deviation of the Gaussian to convolve with the box's shape
|
||||||
final double blur;
|
final double blur;
|
||||||
|
|
||||||
|
/// Returns a new box shadow with its offset and blur scaled by the given factor
|
||||||
BoxShadow scale(double factor) {
|
BoxShadow scale(double factor) {
|
||||||
return new BoxShadow(
|
return new BoxShadow(
|
||||||
color: color,
|
color: color,
|
||||||
@ -139,97 +184,172 @@ class BoxShadow {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Linearly interpolate between two box shadows
|
||||||
|
///
|
||||||
|
/// If either box shadow is null, this function linearly interpolates from a
|
||||||
|
/// a box shadow that matches the other box shadow in color but has a zero
|
||||||
|
/// offset and a zero blur.
|
||||||
|
static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) {
|
||||||
|
if (a == null && b == null)
|
||||||
|
return null;
|
||||||
|
if (a == null)
|
||||||
|
return b.scale(t);
|
||||||
|
if (b == null)
|
||||||
|
return a.scale(1.0 - t);
|
||||||
|
return new BoxShadow(
|
||||||
|
color: lerpColor(a.color, b.color, t),
|
||||||
|
offset: lerpOffset(a.offset, b.offset, t),
|
||||||
|
blur: lerpNum(a.blur, b.blur, t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Linearly interpolate between two lists of box shadows
|
||||||
|
///
|
||||||
|
/// If the lists differ in length, excess items are lerped with null.
|
||||||
|
static List<BoxShadow> lerpList(List<BoxShadow> a, List<BoxShadow> b, double t) {
|
||||||
|
if (a == null && b == null)
|
||||||
|
return null;
|
||||||
|
if (a == null)
|
||||||
|
a = new List<BoxShadow>();
|
||||||
|
if (b == null)
|
||||||
|
b = new List<BoxShadow>();
|
||||||
|
List<BoxShadow> result = new List<BoxShadow>();
|
||||||
|
int commonLength = math.min(a.length, b.length);
|
||||||
|
for (int i = 0; i < commonLength; ++i)
|
||||||
|
result.add(BoxShadow.lerp(a[i], b[i], t));
|
||||||
|
for (int i = commonLength; i < a.length; ++i)
|
||||||
|
result.add(a[i].scale(1.0 - t));
|
||||||
|
for (int i = commonLength; i < b.length; ++i)
|
||||||
|
result.add(b[i].scale(t));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
String toString() => 'BoxShadow($color, $offset, $blur)';
|
String toString() => 'BoxShadow($color, $offset, $blur)';
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxShadow lerpBoxShadow(BoxShadow a, BoxShadow b, double t) {
|
/// A 2D gradient
|
||||||
if (a == null && b == null)
|
|
||||||
return null;
|
|
||||||
if (a == null)
|
|
||||||
return b.scale(t);
|
|
||||||
if (b == null)
|
|
||||||
return a.scale(1.0 - t);
|
|
||||||
return new BoxShadow(
|
|
||||||
color: lerpColor(a.color, b.color, t),
|
|
||||||
offset: lerpOffset(a.offset, b.offset, t),
|
|
||||||
blur: lerpNum(a.blur, b.blur, t)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BoxShadow> lerpListBoxShadow(List<BoxShadow> a, List<BoxShadow> b, double t) {
|
|
||||||
if (a == null && b == null)
|
|
||||||
return null;
|
|
||||||
if (a == null)
|
|
||||||
a = new List<BoxShadow>();
|
|
||||||
if (b == null)
|
|
||||||
b = new List<BoxShadow>();
|
|
||||||
List<BoxShadow> result = new List<BoxShadow>();
|
|
||||||
int commonLength = math.min(a.length, b.length);
|
|
||||||
for (int i = 0; i < commonLength; ++i)
|
|
||||||
result.add(lerpBoxShadow(a[i], b[i], t));
|
|
||||||
for (int i = commonLength; i < a.length; ++i)
|
|
||||||
result.add(a[i].scale(1.0 - t));
|
|
||||||
for (int i = commonLength; i < b.length; ++i)
|
|
||||||
result.add(b[i].scale(t));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Gradient {
|
abstract class Gradient {
|
||||||
sky.Shader createShader();
|
sky.Shader createShader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A 2D linear gradient
|
||||||
class LinearGradient extends Gradient {
|
class LinearGradient extends Gradient {
|
||||||
LinearGradient({
|
LinearGradient({
|
||||||
this.endPoints,
|
this.begin,
|
||||||
|
this.end,
|
||||||
this.colors,
|
this.colors,
|
||||||
this.colorStops,
|
this.stops,
|
||||||
this.tileMode: sky.TileMode.clamp
|
this.tileMode: sky.TileMode.clamp
|
||||||
});
|
}) {
|
||||||
|
assert(colors.length == stops.length);
|
||||||
|
}
|
||||||
|
|
||||||
final List<Point> endPoints;
|
/// The point at which stop 0.0 of the gradient is placed
|
||||||
|
final Point begin;
|
||||||
|
|
||||||
|
/// The point at which stop 1.0 of the gradient is placed
|
||||||
|
final Point end;
|
||||||
|
|
||||||
|
/// The colors the gradient should obtain at each of the stops
|
||||||
|
///
|
||||||
|
/// Note: This list must have the same length as [stops].
|
||||||
final List<Color> colors;
|
final List<Color> colors;
|
||||||
final List<double> colorStops;
|
|
||||||
|
/// A list of values from 0.0 to 1.0 that denote fractions of the vector from start to end
|
||||||
|
///
|
||||||
|
/// Note: This list must have the same length as [colors].
|
||||||
|
final List<double> stops;
|
||||||
|
|
||||||
|
/// How this gradient should tile the plane
|
||||||
final sky.TileMode tileMode;
|
final sky.TileMode tileMode;
|
||||||
|
|
||||||
sky.Shader createShader() {
|
sky.Shader createShader() {
|
||||||
return new sky.Gradient.linear(this.endPoints, this.colors,
|
return new sky.Gradient.linear([begin, end], this.colors,
|
||||||
this.colorStops, this.tileMode);
|
this.stops, this.tileMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LinearGradient($endPoints, $colors, $colorStops, $tileMode)';
|
return 'LinearGradient($begin, $end, $colors, $stops, $tileMode)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A 2D radial gradient
|
||||||
class RadialGradient extends Gradient {
|
class RadialGradient extends Gradient {
|
||||||
RadialGradient({
|
RadialGradient({
|
||||||
this.center,
|
this.center,
|
||||||
this.radius,
|
this.radius,
|
||||||
this.colors,
|
this.colors,
|
||||||
this.colorStops,
|
this.stops,
|
||||||
this.tileMode: sky.TileMode.clamp
|
this.tileMode: sky.TileMode.clamp
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// The center of the gradient
|
||||||
final Point center;
|
final Point center;
|
||||||
|
|
||||||
|
/// The radius at which stop 1.0 is placed
|
||||||
final double radius;
|
final double radius;
|
||||||
|
|
||||||
|
/// The colors the gradient should obtain at each of the stops
|
||||||
|
///
|
||||||
|
/// Note: This list must have the same length as [stops].
|
||||||
final List<Color> colors;
|
final List<Color> colors;
|
||||||
final List<double> colorStops;
|
|
||||||
|
/// A list of values from 0.0 to 1.0 that denote concentric rings
|
||||||
|
///
|
||||||
|
/// The rings are centered at [center] and have a radius equal to the value of
|
||||||
|
/// the stop times [radius].
|
||||||
|
///
|
||||||
|
/// Note: This list must have the same length as [colors].
|
||||||
|
final List<double> stops;
|
||||||
|
|
||||||
|
/// How this gradient should tile the plane
|
||||||
final sky.TileMode tileMode;
|
final sky.TileMode tileMode;
|
||||||
|
|
||||||
sky.Shader createShader() {
|
sky.Shader createShader() {
|
||||||
return new sky.Gradient.radial(this.center, this.radius, this.colors,
|
return new sky.Gradient.radial(center, radius, colors, stops, tileMode);
|
||||||
this.colorStops, this.tileMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'RadialGradient($center, $radius, $colors, $colorStops, $tileMode)';
|
return 'RadialGradient($center, $radius, $colors, $stops, $tileMode)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ImageFit { fill, contain, cover, none, scaleDown }
|
/// How an image should be inscribed into a box
|
||||||
|
enum ImageFit {
|
||||||
|
/// Fill the box by distorting the image's aspect ratio
|
||||||
|
fill,
|
||||||
|
|
||||||
enum ImageRepeat { repeat, repeatX, repeatY, noRepeat }
|
/// As large as possible while still containing the image entirely within the box
|
||||||
|
contain,
|
||||||
|
|
||||||
|
/// As small as possible while still covering the entire box
|
||||||
|
cover,
|
||||||
|
|
||||||
|
/// Center the image within the box and discard any portions of the image that
|
||||||
|
/// lie outside the box
|
||||||
|
none,
|
||||||
|
|
||||||
|
/// Center the image within the box and, if necessary, scale the image down to
|
||||||
|
/// ensure that the image fits within the box
|
||||||
|
scaleDown
|
||||||
|
}
|
||||||
|
|
||||||
|
/// How to paint any portions of a box not covered by an image
|
||||||
|
enum ImageRepeat {
|
||||||
|
/// Repeat the image in both the x and y directions until the box is filled
|
||||||
|
repeat,
|
||||||
|
|
||||||
|
/// Repeat the image in the x direction until the box is filled horizontally
|
||||||
|
repeatX,
|
||||||
|
|
||||||
|
/// Repeat the image in the y direction until the box is filled vertically
|
||||||
|
repeatY,
|
||||||
|
|
||||||
|
/// Leave uncovered poritions of the box transparent
|
||||||
|
noRepeat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Paint an image into the given rectangle in the canvas
|
||||||
void paintImage({
|
void paintImage({
|
||||||
sky.Canvas canvas,
|
sky.Canvas canvas,
|
||||||
Rect rect,
|
Rect rect,
|
||||||
@ -289,9 +409,15 @@ void paintImage({
|
|||||||
|
|
||||||
typedef void BackgroundImageChangeListener();
|
typedef void BackgroundImageChangeListener();
|
||||||
|
|
||||||
|
/// A background image for a box
|
||||||
class BackgroundImage {
|
class BackgroundImage {
|
||||||
|
/// How the background image should be inscribed into the box
|
||||||
final ImageFit fit;
|
final ImageFit fit;
|
||||||
|
|
||||||
|
/// How to paint any portions of the box not covered by the background image
|
||||||
final ImageRepeat repeat;
|
final ImageRepeat repeat;
|
||||||
|
|
||||||
|
/// A color filter to apply to the background image before painting it
|
||||||
final sky.ColorFilter colorFilter;
|
final sky.ColorFilter colorFilter;
|
||||||
|
|
||||||
BackgroundImage({
|
BackgroundImage({
|
||||||
@ -302,6 +428,7 @@ class BackgroundImage {
|
|||||||
}) : _imageResource = image;
|
}) : _imageResource = image;
|
||||||
|
|
||||||
sky.Image _image;
|
sky.Image _image;
|
||||||
|
/// The image to be painted into the background
|
||||||
sky.Image get image => _image;
|
sky.Image get image => _image;
|
||||||
|
|
||||||
ImageResource _imageResource;
|
ImageResource _imageResource;
|
||||||
@ -309,6 +436,7 @@ class BackgroundImage {
|
|||||||
final List<BackgroundImageChangeListener> _listeners =
|
final List<BackgroundImageChangeListener> _listeners =
|
||||||
new List<BackgroundImageChangeListener>();
|
new List<BackgroundImageChangeListener>();
|
||||||
|
|
||||||
|
/// Call listener when the background images changes (e.g., arrives from the network)
|
||||||
void addChangeListener(BackgroundImageChangeListener listener) {
|
void addChangeListener(BackgroundImageChangeListener listener) {
|
||||||
// We add the listener to the _imageResource first so that the first change
|
// We add the listener to the _imageResource first so that the first change
|
||||||
// listener doesn't get callback synchronously if the image resource is
|
// listener doesn't get callback synchronously if the image resource is
|
||||||
@ -318,6 +446,7 @@ class BackgroundImage {
|
|||||||
_listeners.add(listener);
|
_listeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// No longer call listener when the background image changes
|
||||||
void removeChangeListener(BackgroundImageChangeListener listener) {
|
void removeChangeListener(BackgroundImageChangeListener listener) {
|
||||||
_listeners.remove(listener);
|
_listeners.remove(listener);
|
||||||
// We need to remove ourselves as listeners from the _imageResource so that
|
// We need to remove ourselves as listeners from the _imageResource so that
|
||||||
@ -340,9 +469,17 @@ class BackgroundImage {
|
|||||||
String toString() => 'BackgroundImage($fit, $repeat)';
|
String toString() => 'BackgroundImage($fit, $repeat)';
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Shape { rectangle, circle }
|
// TODO(abarth): Rename to BoxShape?
|
||||||
|
/// A 2D geometrical shape
|
||||||
|
enum Shape {
|
||||||
|
/// An axis-aligned, 2D rectangle
|
||||||
|
rectangle,
|
||||||
|
|
||||||
// This must be immutable, because we won't notice when it changes
|
/// A 2D locus of points equidistant from a single point
|
||||||
|
circle
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An immutable description of how to paint a box
|
||||||
class BoxDecoration {
|
class BoxDecoration {
|
||||||
const BoxDecoration({
|
const BoxDecoration({
|
||||||
this.backgroundColor, // null = don't draw background color
|
this.backgroundColor, // null = don't draw background color
|
||||||
@ -354,14 +491,33 @@ class BoxDecoration {
|
|||||||
this.shape: Shape.rectangle
|
this.shape: Shape.rectangle
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// The color to fill in the background of the box
|
||||||
|
///
|
||||||
|
/// The color is filled into the shape of the box (e.g., either a rectangle,
|
||||||
|
/// potentially with a border radius, or a circle).
|
||||||
final Color backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
|
/// An image to paint above the background color
|
||||||
final BackgroundImage backgroundImage;
|
final BackgroundImage backgroundImage;
|
||||||
final double borderRadius;
|
|
||||||
|
/// A border to draw above the background
|
||||||
final Border border;
|
final Border border;
|
||||||
|
|
||||||
|
/// If non-null, the corners of this box are rounded by this radius
|
||||||
|
///
|
||||||
|
/// Applies only to boxes with rectangular shapes.
|
||||||
|
final double borderRadius;
|
||||||
|
|
||||||
|
/// A list of shadows cast by this box behind the background
|
||||||
final List<BoxShadow> boxShadow;
|
final List<BoxShadow> boxShadow;
|
||||||
|
|
||||||
|
/// A graident to use when filling the background
|
||||||
final Gradient gradient;
|
final Gradient gradient;
|
||||||
|
|
||||||
|
/// The shape to fill the background color into and to cast as a shadow
|
||||||
final Shape shape;
|
final Shape shape;
|
||||||
|
|
||||||
|
/// Returns a new box decoration that is scalled by the given factor
|
||||||
BoxDecoration scale(double factor) {
|
BoxDecoration scale(double factor) {
|
||||||
// TODO(abarth): Scale ALL the things.
|
// TODO(abarth): Scale ALL the things.
|
||||||
return new BoxDecoration(
|
return new BoxDecoration(
|
||||||
@ -369,12 +525,34 @@ class BoxDecoration {
|
|||||||
backgroundImage: backgroundImage,
|
backgroundImage: backgroundImage,
|
||||||
border: border,
|
border: border,
|
||||||
borderRadius: lerpNum(null, borderRadius, factor),
|
borderRadius: lerpNum(null, borderRadius, factor),
|
||||||
boxShadow: lerpListBoxShadow(null, boxShadow, factor),
|
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
|
||||||
gradient: gradient,
|
gradient: gradient,
|
||||||
shape: shape
|
shape: shape
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Linearly interpolate between two box decorations
|
||||||
|
///
|
||||||
|
/// Interpolates each parameter of the box decoration separately.
|
||||||
|
static BoxDecoration lerp(BoxDecoration a, BoxDecoration b, double t) {
|
||||||
|
if (a == null && b == null)
|
||||||
|
return null;
|
||||||
|
if (a == null)
|
||||||
|
return b.scale(t);
|
||||||
|
if (b == null)
|
||||||
|
return a.scale(1.0 - t);
|
||||||
|
// TODO(abarth): lerp ALL the fields.
|
||||||
|
return new BoxDecoration(
|
||||||
|
backgroundColor: lerpColor(a.backgroundColor, b.backgroundColor, t),
|
||||||
|
backgroundImage: b.backgroundImage,
|
||||||
|
border: b.border,
|
||||||
|
borderRadius: lerpNum(a.borderRadius, b.borderRadius, t),
|
||||||
|
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
||||||
|
gradient: b.gradient,
|
||||||
|
shape: b.shape
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
String toString([String prefix = '']) {
|
String toString([String prefix = '']) {
|
||||||
List<String> result = [];
|
List<String> result = [];
|
||||||
if (backgroundColor != null)
|
if (backgroundColor != null)
|
||||||
@ -397,31 +575,14 @@ class BoxDecoration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxDecoration lerpBoxDecoration(BoxDecoration a, BoxDecoration b, double t) {
|
/// An object that paints a [BoxDecoration] into a canvas
|
||||||
if (a == null && b == null)
|
|
||||||
return null;
|
|
||||||
if (a == null)
|
|
||||||
return b.scale(t);
|
|
||||||
if (b == null)
|
|
||||||
return a.scale(1.0 - t);
|
|
||||||
// TODO(abarth): lerp ALL the fields.
|
|
||||||
return new BoxDecoration(
|
|
||||||
backgroundColor: lerpColor(a.backgroundColor, b.backgroundColor, t),
|
|
||||||
backgroundImage: b.backgroundImage,
|
|
||||||
border: b.border,
|
|
||||||
borderRadius: lerpNum(a.borderRadius, b.borderRadius, t),
|
|
||||||
boxShadow: lerpListBoxShadow(a.boxShadow, b.boxShadow, t),
|
|
||||||
gradient: b.gradient,
|
|
||||||
shape: b.shape
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class BoxPainter {
|
class BoxPainter {
|
||||||
BoxPainter(BoxDecoration decoration) : _decoration = decoration {
|
BoxPainter(BoxDecoration decoration) : _decoration = decoration {
|
||||||
assert(decoration != null);
|
assert(decoration != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxDecoration _decoration;
|
BoxDecoration _decoration;
|
||||||
|
/// The box decoration to paint
|
||||||
BoxDecoration get decoration => _decoration;
|
BoxDecoration get decoration => _decoration;
|
||||||
void set decoration (BoxDecoration value) {
|
void set decoration (BoxDecoration value) {
|
||||||
assert(value != null);
|
assert(value != null);
|
||||||
@ -611,6 +772,7 @@ class BoxPainter {
|
|||||||
canvas.drawCircle(center, radius, paint);
|
canvas.drawCircle(center, radius, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Paint the box decoration into the given location on the given canvas
|
||||||
void paint(sky.Canvas canvas, Rect rect) {
|
void paint(sky.Canvas canvas, Rect rect) {
|
||||||
_paintBackgroundColor(canvas, rect);
|
_paintBackgroundColor(canvas, rect);
|
||||||
_paintBackgroundImage(canvas, rect);
|
_paintBackgroundImage(canvas, rect);
|
||||||
|
@ -20,6 +20,9 @@ int _roundOpacity(double opacity) {
|
|||||||
return (255 * opacity).round();
|
return (255 * opacity).round();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A material design radial ink reaction
|
||||||
|
///
|
||||||
|
/// See [https://www.google.com/design/spec/animation/responsive-interaction.html#responsive-interaction-radial-action]
|
||||||
class RadialReaction {
|
class RadialReaction {
|
||||||
RadialReaction({
|
RadialReaction({
|
||||||
this.center,
|
this.center,
|
||||||
@ -41,7 +44,10 @@ class RadialReaction {
|
|||||||
..duration =_kHideDuration;
|
..duration =_kHideDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The center of the circle in which the reaction occurs
|
||||||
final Point center;
|
final Point center;
|
||||||
|
|
||||||
|
/// The radius of the circle in which the reaction occurs
|
||||||
final double radius;
|
final double radius;
|
||||||
|
|
||||||
AnimationPerformance _showPerformance;
|
AnimationPerformance _showPerformance;
|
||||||
@ -54,15 +60,22 @@ class RadialReaction {
|
|||||||
AnimationPerformance _hidePerformance;
|
AnimationPerformance _hidePerformance;
|
||||||
AnimatedValue<double> _fade;
|
AnimatedValue<double> _fade;
|
||||||
|
|
||||||
void show() {
|
/// Show the reaction
|
||||||
_showComplete = _showPerformance.forward();
|
///
|
||||||
|
/// Returns a future that resolves when the reaction is completely revealed.
|
||||||
|
Future show() {
|
||||||
|
return _showComplete = _showPerformance.forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hide the reaction
|
||||||
|
///
|
||||||
|
/// Returns a future that resolves when the reaction is completely hidden.
|
||||||
Future hide() async {
|
Future hide() async {
|
||||||
await _showComplete;
|
await _showComplete;
|
||||||
await _hidePerformance.forward();
|
await _hidePerformance.forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call listener whenever the visual appearance of the reaction changes
|
||||||
void addListener(Function listener) {
|
void addListener(Function listener) {
|
||||||
_showPerformance.addListener(listener);
|
_showPerformance.addListener(listener);
|
||||||
_hidePerformance.addListener(listener);
|
_hidePerformance.addListener(listener);
|
||||||
@ -71,6 +84,7 @@ class RadialReaction {
|
|||||||
final Paint _outerPaint = new Paint();
|
final Paint _outerPaint = new Paint();
|
||||||
final Paint _innerPaint = new Paint();
|
final Paint _innerPaint = new Paint();
|
||||||
|
|
||||||
|
/// Paint the reaction onto the given canvas at the given offset
|
||||||
void paint(sky.Canvas canvas, Offset offset) {
|
void paint(sky.Canvas canvas, Offset offset) {
|
||||||
_outerPaint.color = _kOuterColor.withAlpha(_roundOpacity(_outerOpacity.value * _fade.value));
|
_outerPaint.color = _kOuterColor.withAlpha(_roundOpacity(_outerOpacity.value * _fade.value));
|
||||||
canvas.drawCircle(center + offset, radius, _outerPaint);
|
canvas.drawCircle(center + offset, radius, _outerPaint);
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
import 'dart:sky' as sky;
|
import 'dart:sky' as sky;
|
||||||
|
|
||||||
/// Helper class to build a Paint DrawLooper that adds shadows to the Paint's
|
/// A helper class to build a [sky.DrawLooper] for drawing shadows
|
||||||
/// operation.
|
|
||||||
class ShadowDrawLooperBuilder {
|
class ShadowDrawLooperBuilder {
|
||||||
var builder_ = new sky.LayerDrawLooperBuilder();
|
var builder_ = new sky.LayerDrawLooperBuilder();
|
||||||
|
|
||||||
|
/// Add a shadow with the given parameters
|
||||||
void addShadow(sky.Offset offset, sky.Color color, double blur) {
|
void addShadow(sky.Offset offset, sky.Color color, double blur) {
|
||||||
builder_.addLayerOnTop(
|
builder_.addLayerOnTop(
|
||||||
new sky.DrawLooperLayerInfo()
|
new sky.DrawLooperLayerInfo()
|
||||||
@ -20,6 +20,7 @@ class ShadowDrawLooperBuilder {
|
|||||||
..setMaskFilter(new sky.MaskFilter.blur(sky.BlurStyle.normal, blur)));
|
..setMaskFilter(new sky.MaskFilter.blur(sky.BlurStyle.normal, blur)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the draw looper built for the added shadows
|
||||||
sky.DrawLooper build() {
|
sky.DrawLooper build() {
|
||||||
builder_.addLayerOnTop(new sky.DrawLooperLayerInfo(), new sky.Paint());
|
builder_.addLayerOnTop(new sky.DrawLooperLayerInfo(), new sky.Paint());
|
||||||
return builder_.build();
|
return builder_.build();
|
||||||
|
@ -8,8 +8,9 @@ import 'package:sky/painting/text_style.dart';
|
|||||||
|
|
||||||
export 'package:sky/painting/text_style.dart';
|
export 'package:sky/painting/text_style.dart';
|
||||||
|
|
||||||
// This must be immutable, because we won't notice when it changes
|
/// An immutable span of text
|
||||||
abstract class TextSpan {
|
abstract class TextSpan {
|
||||||
|
// This class must be immutable, because we won't notice when it changes
|
||||||
sky.Node _toDOM(sky.Document owner);
|
sky.Node _toDOM(sky.Document owner);
|
||||||
String toString([String prefix = '']);
|
String toString([String prefix = '']);
|
||||||
|
|
||||||
@ -17,11 +18,13 @@ abstract class TextSpan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An immutable span of unstyled text
|
||||||
class PlainTextSpan extends TextSpan {
|
class PlainTextSpan extends TextSpan {
|
||||||
PlainTextSpan(this.text) {
|
PlainTextSpan(this.text) {
|
||||||
assert(text != null);
|
assert(text != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The text contained in the span
|
||||||
final String text;
|
final String text;
|
||||||
|
|
||||||
sky.Node _toDOM(sky.Document owner) {
|
sky.Node _toDOM(sky.Document owner) {
|
||||||
@ -34,13 +37,17 @@ class PlainTextSpan extends TextSpan {
|
|||||||
String toString([String prefix = '']) => '${prefix}${runtimeType}: "${text}"';
|
String toString([String prefix = '']) => '${prefix}${runtimeType}: "${text}"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An immutable text span that applies a style to a list of children
|
||||||
class StyledTextSpan extends TextSpan {
|
class StyledTextSpan extends TextSpan {
|
||||||
StyledTextSpan(this.style, this.children) {
|
StyledTextSpan(this.style, this.children) {
|
||||||
assert(style != null);
|
assert(style != null);
|
||||||
assert(children != null);
|
assert(children != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The style to apply to the children
|
||||||
final TextStyle style;
|
final TextStyle style;
|
||||||
|
|
||||||
|
/// The children to which the style is applied
|
||||||
final List<TextSpan> children;
|
final List<TextSpan> children;
|
||||||
|
|
||||||
sky.Node _toDOM(sky.Document owner) {
|
sky.Node _toDOM(sky.Document owner) {
|
||||||
@ -90,6 +97,7 @@ class StyledTextSpan extends TextSpan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An object that paints a [TextSpan] into a canvas
|
||||||
class TextPainter {
|
class TextPainter {
|
||||||
TextPainter(TextSpan text) {
|
TextPainter(TextSpan text) {
|
||||||
_layoutRoot.rootElement = _document.createElement('p');
|
_layoutRoot.rootElement = _document.createElement('p');
|
||||||
@ -102,6 +110,7 @@ class TextPainter {
|
|||||||
bool _needsLayout = true;
|
bool _needsLayout = true;
|
||||||
|
|
||||||
TextSpan _text;
|
TextSpan _text;
|
||||||
|
/// The (potentially styled) text to paint
|
||||||
TextSpan get text => _text;
|
TextSpan get text => _text;
|
||||||
void set text(TextSpan value) {
|
void set text(TextSpan value) {
|
||||||
if (_text == value)
|
if (_text == value)
|
||||||
@ -113,6 +122,7 @@ class TextPainter {
|
|||||||
_needsLayout = true;
|
_needsLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The minimum width at which to layout the text
|
||||||
double get minWidth => _layoutRoot.minWidth;
|
double get minWidth => _layoutRoot.minWidth;
|
||||||
void set minWidth(value) {
|
void set minWidth(value) {
|
||||||
if (_layoutRoot.minWidth == value)
|
if (_layoutRoot.minWidth == value)
|
||||||
@ -121,6 +131,7 @@ class TextPainter {
|
|||||||
_needsLayout = true;
|
_needsLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The maximum width at which to layout the text
|
||||||
double get maxWidth => _layoutRoot.maxWidth;
|
double get maxWidth => _layoutRoot.maxWidth;
|
||||||
void set maxWidth(value) {
|
void set maxWidth(value) {
|
||||||
if (_layoutRoot.maxWidth == value)
|
if (_layoutRoot.maxWidth == value)
|
||||||
@ -129,6 +140,7 @@ class TextPainter {
|
|||||||
_needsLayout = true;
|
_needsLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The minimum height at which to layout the text
|
||||||
double get minHeight => _layoutRoot.minHeight;
|
double get minHeight => _layoutRoot.minHeight;
|
||||||
void set minHeight(value) {
|
void set minHeight(value) {
|
||||||
if (_layoutRoot.minHeight == value)
|
if (_layoutRoot.minHeight == value)
|
||||||
@ -137,6 +149,7 @@ class TextPainter {
|
|||||||
_needsLayout = true;
|
_needsLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The maximum height at which to layout the text
|
||||||
double get maxHeight => _layoutRoot.maxHeight;
|
double get maxHeight => _layoutRoot.maxHeight;
|
||||||
void set maxHeight(value) {
|
void set maxHeight(value) {
|
||||||
if (_layoutRoot.maxHeight == value)
|
if (_layoutRoot.maxHeight == value)
|
||||||
@ -144,21 +157,25 @@ class TextPainter {
|
|||||||
_layoutRoot.maxHeight = value;
|
_layoutRoot.maxHeight = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The width at which decreasing the width of the text would prevent it from painting itself completely within its bounds
|
||||||
double get minContentWidth {
|
double get minContentWidth {
|
||||||
assert(!_needsLayout);
|
assert(!_needsLayout);
|
||||||
return _layoutRoot.rootElement.minContentWidth;
|
return _layoutRoot.rootElement.minContentWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The width at which increasing the width of the text no longer decreases the height
|
||||||
double get maxContentWidth {
|
double get maxContentWidth {
|
||||||
assert(!_needsLayout);
|
assert(!_needsLayout);
|
||||||
return _layoutRoot.rootElement.maxContentWidth;
|
return _layoutRoot.rootElement.maxContentWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The height required to paint the text completely within its bounds
|
||||||
double get height {
|
double get height {
|
||||||
assert(!_needsLayout);
|
assert(!_needsLayout);
|
||||||
return _layoutRoot.rootElement.height;
|
return _layoutRoot.rootElement.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The distance from the top of the text to the first baseline of the given type
|
||||||
double computeDistanceToActualBaseline(TextBaseline baseline) {
|
double computeDistanceToActualBaseline(TextBaseline baseline) {
|
||||||
assert(!_needsLayout);
|
assert(!_needsLayout);
|
||||||
sky.Element root = _layoutRoot.rootElement;
|
sky.Element root = _layoutRoot.rootElement;
|
||||||
@ -168,6 +185,7 @@ class TextPainter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the visual position of the glyphs for painting the text
|
||||||
void layout() {
|
void layout() {
|
||||||
if (!_needsLayout)
|
if (!_needsLayout)
|
||||||
return;
|
return;
|
||||||
@ -175,6 +193,7 @@ class TextPainter {
|
|||||||
_needsLayout = false;
|
_needsLayout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Paint the text onto the given canvas at the given offset
|
||||||
void paint(sky.Canvas canvas, sky.Offset offset) {
|
void paint(sky.Canvas canvas, sky.Offset offset) {
|
||||||
assert(!_needsLayout && "Please call layout() before paint() to position the text before painting it." is String);
|
assert(!_needsLayout && "Please call layout() before paint() to position the text before painting it." is String);
|
||||||
// TODO(ianh): Make LayoutRoot support a paint offset so we don't
|
// TODO(ianh): Make LayoutRoot support a paint offset so we don't
|
||||||
|
@ -4,23 +4,118 @@
|
|||||||
|
|
||||||
import 'dart:sky';
|
import 'dart:sky';
|
||||||
|
|
||||||
enum FontWeight { w100, w200, w300, w400, w500, w600, w700, w800, w900 }
|
/// The thickness of the glyphs used to draw the text
|
||||||
|
enum FontWeight {
|
||||||
|
/// Thin, the least thick
|
||||||
|
w100,
|
||||||
|
|
||||||
|
/// Extra-light
|
||||||
|
w200,
|
||||||
|
|
||||||
|
/// Light
|
||||||
|
w300,
|
||||||
|
|
||||||
|
/// Normal / regular / plain
|
||||||
|
w400,
|
||||||
|
|
||||||
|
/// Medium
|
||||||
|
w500,
|
||||||
|
|
||||||
|
/// Semi-bold
|
||||||
|
w600,
|
||||||
|
|
||||||
|
/// Bold
|
||||||
|
w700,
|
||||||
|
|
||||||
|
/// Extra-bold
|
||||||
|
w800,
|
||||||
|
|
||||||
|
/// Black, the most thick
|
||||||
|
w900
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A normal font weight
|
||||||
const normal = FontWeight.w400;
|
const normal = FontWeight.w400;
|
||||||
|
|
||||||
|
/// A bold font weight
|
||||||
const bold = FontWeight.w700;
|
const bold = FontWeight.w700;
|
||||||
|
|
||||||
enum FontStyle { normal, italic, oblique }
|
/// Whether to slant the glyphs in the font
|
||||||
|
enum FontStyle {
|
||||||
|
/// Use the upright glyphs
|
||||||
|
normal,
|
||||||
|
|
||||||
enum TextAlign { left, right, center }
|
/// Use glyphs designed for slanting
|
||||||
|
italic,
|
||||||
|
|
||||||
enum TextBaseline { alphabetic, ideographic }
|
/// Use the upright glyphs but slant them during painting
|
||||||
|
oblique // TODO(abarth): Remove. We don't really support this value.
|
||||||
|
}
|
||||||
|
|
||||||
enum TextDecoration { none, underline, overline, lineThrough }
|
/// Whether to align text horizontally
|
||||||
|
enum TextAlign {
|
||||||
|
/// Align the text on the left edge of the container
|
||||||
|
left,
|
||||||
|
|
||||||
|
/// Align the text on the right edge of the container
|
||||||
|
right,
|
||||||
|
|
||||||
|
/// Align the text in the center of the container
|
||||||
|
center
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A horizontal line used for aligning text
|
||||||
|
enum TextBaseline {
|
||||||
|
// The horizontal line used to align the bottom of glyphs for alphabetic characters
|
||||||
|
alphabetic,
|
||||||
|
|
||||||
|
// The horizontal line used to align ideographic characters
|
||||||
|
ideographic
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A linear decoration to draw near the text
|
||||||
|
enum TextDecoration {
|
||||||
|
/// Do not draw a decoration
|
||||||
|
none,
|
||||||
|
|
||||||
|
/// Draw a line underneath each line of text
|
||||||
|
underline,
|
||||||
|
|
||||||
|
/// Draw a line above each line of text
|
||||||
|
overline,
|
||||||
|
|
||||||
|
/// Draw a line through each line of text
|
||||||
|
lineThrough
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a line underneath each line of text
|
||||||
const underline = const <TextDecoration>[TextDecoration.underline];
|
const underline = const <TextDecoration>[TextDecoration.underline];
|
||||||
|
|
||||||
|
/// Draw a line above each line of text
|
||||||
const overline = const <TextDecoration>[TextDecoration.overline];
|
const overline = const <TextDecoration>[TextDecoration.overline];
|
||||||
|
|
||||||
|
/// Draw a line through each line of text
|
||||||
const lineThrough = const <TextDecoration>[TextDecoration.lineThrough];
|
const lineThrough = const <TextDecoration>[TextDecoration.lineThrough];
|
||||||
|
|
||||||
enum TextDecorationStyle { solid, double, dotted, dashed, wavy }
|
/// The style in which to draw a text decoration
|
||||||
|
enum TextDecorationStyle {
|
||||||
|
/// Draw a solid line
|
||||||
|
solid,
|
||||||
|
|
||||||
|
/// Draw two lines
|
||||||
|
double,
|
||||||
|
|
||||||
|
/// Draw a dotted line
|
||||||
|
dotted,
|
||||||
|
|
||||||
|
/// Draw a dashed line
|
||||||
|
dashed,
|
||||||
|
|
||||||
|
/// Draw a sinusoidal line
|
||||||
|
wavy
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An immutable style in which paint text
|
||||||
class TextStyle {
|
class TextStyle {
|
||||||
const TextStyle({
|
const TextStyle({
|
||||||
this.color,
|
this.color,
|
||||||
@ -36,18 +131,42 @@ class TextStyle {
|
|||||||
this.decorationStyle
|
this.decorationStyle
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// The color to use when painting the text
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
|
/// The name of the font to use when painting the text
|
||||||
final String fontFamily;
|
final String fontFamily;
|
||||||
final double fontSize; // in pixels
|
|
||||||
|
/// The size of gyphs (in logical pixels) to use when painting the text
|
||||||
|
final double fontSize;
|
||||||
|
|
||||||
|
/// The font weight to use when painting the text
|
||||||
final FontWeight fontWeight;
|
final FontWeight fontWeight;
|
||||||
|
|
||||||
|
/// The font style to use when painting the text
|
||||||
final FontStyle fontStyle;
|
final FontStyle fontStyle;
|
||||||
|
|
||||||
|
/// How the text should be aligned (applies only to the outermost
|
||||||
|
/// StyledTextSpan, which establishes the container for the text)
|
||||||
final TextAlign textAlign;
|
final TextAlign textAlign;
|
||||||
|
|
||||||
|
/// The baseline to use for aligning the text
|
||||||
final TextBaseline textBaseline;
|
final TextBaseline textBaseline;
|
||||||
final double height; // multiple of fontSize
|
|
||||||
|
/// The distance between the text baselines, as a multiple of the font size
|
||||||
|
final double height;
|
||||||
|
|
||||||
|
/// A list of decorations to paint near the text
|
||||||
final List<TextDecoration> decoration; // TODO(ianh): Switch this to a Set<> once Dart supports constant Sets
|
final List<TextDecoration> decoration; // TODO(ianh): Switch this to a Set<> once Dart supports constant Sets
|
||||||
|
|
||||||
|
/// The color in which to paint the text decorations
|
||||||
final Color decorationColor;
|
final Color decorationColor;
|
||||||
|
|
||||||
|
/// The style in which to paint the text decorations
|
||||||
final TextDecorationStyle decorationStyle;
|
final TextDecorationStyle decorationStyle;
|
||||||
|
|
||||||
|
/// Returns a new text style that matches this text style but with the given
|
||||||
|
/// values replaced
|
||||||
TextStyle copyWith({
|
TextStyle copyWith({
|
||||||
Color color,
|
Color color,
|
||||||
String fontFamily,
|
String fontFamily,
|
||||||
@ -76,6 +195,8 @@ class TextStyle {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new text style that matches this text style but with some values
|
||||||
|
/// replaced by the non-null parameters of the given text style
|
||||||
TextStyle merge(TextStyle other) {
|
TextStyle merge(TextStyle other) {
|
||||||
return copyWith(
|
return copyWith(
|
||||||
color: other.color,
|
color: other.color,
|
||||||
@ -124,6 +245,10 @@ class TextStyle {
|
|||||||
return toCSS[decorationStyle];
|
return toCSS[decorationStyle];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Program this text style into the engine
|
||||||
|
///
|
||||||
|
/// Note: This function will likely be removed when we refactor the interface
|
||||||
|
/// between the framework and the engine
|
||||||
void applyToCSSStyle(CSSStyleDeclaration cssStyle) {
|
void applyToCSSStyle(CSSStyleDeclaration cssStyle) {
|
||||||
if (color != null) {
|
if (color != null) {
|
||||||
cssStyle['color'] = _colorToCSSString(color);
|
cssStyle['color'] = _colorToCSSString(color);
|
||||||
@ -163,6 +288,10 @@ class TextStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Program the container aspects of this text style into the engine
|
||||||
|
///
|
||||||
|
/// Note: This function will likely be removed when we refactor the interface
|
||||||
|
/// between the framework and the engine
|
||||||
void applyToContainerCSSStyle(CSSStyleDeclaration cssStyle) {
|
void applyToContainerCSSStyle(CSSStyleDeclaration cssStyle) {
|
||||||
if (textAlign != null) {
|
if (textAlign != null) {
|
||||||
cssStyle['text-align'] = const {
|
cssStyle['text-align'] = const {
|
||||||
|
@ -131,7 +131,8 @@ import 'package:sky/widgets.dart';
|
|||||||
final BoxDecoration _decoration = new BoxDecoration(
|
final BoxDecoration _decoration = new BoxDecoration(
|
||||||
borderRadius: 5.0,
|
borderRadius: 5.0,
|
||||||
gradient: new LinearGradient(
|
gradient: new LinearGradient(
|
||||||
endPoints: [ Point.origin, const Point(0.0, 36.0) ],
|
start: Point.origin,
|
||||||
|
end: const Point(0.0, 36.0),
|
||||||
colors: [ const Color(0xFFEEEEEE), const Color(0xFFCCCCCC) ]
|
colors: [ const Color(0xFFEEEEEE), const Color(0xFFCCCCCC) ]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -25,7 +25,7 @@ class AnimatedBoxDecorationValue extends AnimatedValue<BoxDecoration> {
|
|||||||
AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve: linear })
|
AnimatedBoxDecorationValue(BoxDecoration begin, { BoxDecoration end, Curve curve: linear })
|
||||||
: super(begin, end: end, curve: curve);
|
: super(begin, end: end, curve: curve);
|
||||||
|
|
||||||
BoxDecoration lerp(double t) => lerpBoxDecoration(begin, end, t);
|
BoxDecoration lerp(double t) => BoxDecoration.lerp(begin, end, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AnimatedEdgeDimsValue extends AnimatedValue<EdgeDims> {
|
class AnimatedEdgeDimsValue extends AnimatedValue<EdgeDims> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user