Skip to content

Instantly share code, notes, and snippets.

@AgainPsychoX
Last active June 6, 2019 12:53
Show Gist options
  • Save AgainPsychoX/e7402ed1c3e525d0b2b0a504cbc86a41 to your computer and use it in GitHub Desktop.
Save AgainPsychoX/e7402ed1c3e525d0b2b0a504cbc86a41 to your computer and use it in GitHub Desktop.
`PaintStyle` for `Paint` of `sky_engine`
import 'dart:ui';
/// A description of the style to use when drawing on a [Canvas].
///
/// Most APIs on [Canvas] take a [Paint] object to describe the style
/// to use for that operation. [PaintStyle] allows to be const
/// constructed and later in runtime forged into the [Paint] object.
class PaintStyle {
/// Whether to apply anti-aliasing to lines and images drawn on the
/// canvas.
///
/// Defaults to true.
final bool isAntiAlias;
// Must be kept in sync with the default in paint.cc.
static const int _kColorDefault = 0xFF000000;
/// The color to use when stroking or filling a shape.
///
/// Defaults to opaque black.
///
/// See also:
///
/// * [style], which controls whether to stroke or fill (or both).
/// * [colorFilter], which overrides [color].
/// * [shader], which overrides [color] with more elaborate effects.
///
/// This color is not used when compositing. To colorize a layer, use
/// [colorFilter].
final Color color;
// Must be kept in sync with the default in paint.cc.
static final int _kBlendModeDefault = BlendMode.srcOver.index;
/// A blend mode to apply when a shape is drawn or a layer is composited.
///
/// The source colors are from the shape being drawn (e.g. from
/// [Canvas.drawPath]) or layer being composited (the graphics that were drawn
/// between the [Canvas.saveLayer] and [Canvas.restore] calls), after applying
/// the [colorFilter], if any.
///
/// The destination colors are from the background onto which the shape or
/// layer is being composited.
///
/// Defaults to [BlendMode.srcOver].
///
/// See also:
///
/// * [Canvas.saveLayer], which uses its [Paint]'s [blendMode] to composite
/// the layer when [restore] is called.
/// * [BlendMode], which discusses the user of [saveLayer] with [blendMode].
final BlendMode blendMode;
/// Whether to paint inside shapes, the edges of shapes, or both.
///
/// Defaults to [PaintingStyle.fill].
final PaintingStyle style;
/// How wide to make edges drawn when [style] is set to
/// [PaintingStyle.stroke]. The width is given in logical pixels measured in
/// the direction orthogonal to the direction of the path.
///
/// Defaults to 0.0, which correspond to a hairline width.
final double strokeWidth;
/// The kind of finish to place on the end of lines drawn when
/// [style] is set to [PaintingStyle.stroke].
///
/// Defaults to [StrokeCap.butt], i.e. no caps.
final StrokeCap strokeCap;
/// The kind of finish to place on the joins between segments.
///
/// This applies to paths drawn when [style] is set to [PaintingStyle.stroke],
/// It does not apply to points drawn as lines with [Canvas.drawPoints].
///
/// Defaults to [StrokeJoin.miter], i.e. sharp corners.
///
/// Some examples of joins:
///
/// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}
///
/// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_join.mp4}
///
/// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/bevel_join.mp4}
///
/// The centers of the line segments are colored in the diagrams above to
/// highlight the joins, but in normal usage the join is the same color as the
/// line.
///
/// See also:
///
/// * [strokeMiterLimit] to control when miters are replaced by bevels when
/// this is set to [StrokeJoin.miter].
/// * [strokeCap] to control what is drawn at the ends of the stroke.
/// * [StrokeJoin] for the definitive list of stroke joins.
final StrokeJoin strokeJoin;
// Must be kept in sync with the default in paint.cc.
static const double _kStrokeMiterLimitDefault = 4.0;
/// The limit for miters to be drawn on segments when the join is set to
/// [StrokeJoin.miter] and the [style] is set to [PaintingStyle.stroke]. If
/// this limit is exceeded, then a [StrokeJoin.bevel] join will be drawn
/// instead. This may cause some 'popping' of the corners of a path if the
/// angle between line segments is animated, as seen in the diagrams below.
///
/// This limit is expressed as a limit on the length of the miter.
///
/// Defaults to 4.0. Using zero as a limit will cause a [StrokeJoin.bevel]
/// join to be used all the time.
///
/// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_0_join.mp4}
///
/// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4}
///
/// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_6_join.mp4}
///
/// The centers of the line segments are colored in the diagrams above to
/// highlight the joins, but in normal usage the join is the same color as the
/// line.
///
/// See also:
///
/// * [strokeJoin] to control the kind of finish to place on the joins
/// between segments.
/// * [strokeCap] to control what is drawn at the ends of the stroke.
final double strokeMiterLimit;
/// A mask filter (for example, a blur) to apply to a shape after it has been
/// drawn but before it has been composited into the image.
///
/// See [MaskFilter] for details.
final MaskFilter maskFilter;
/// Controls the performance vs quality trade-off to use when applying
/// filters, such as [maskFilter], or when drawing images, as with
/// [Canvas.drawImageRect] or [Canvas.drawImageNine].
///
/// Defaults to [FilterQuality.none].
// TODO(ianh): verify that the image drawing methods actually respect this
final FilterQuality filterQuality;
/// The shader to use when stroking or filling a shape.
///
/// When this is null, the [color] is used instead.
///
/// See also:
///
/// * [Gradient], a shader that paints a color gradient.
/// * [ImageShader], a shader that tiles an [Image].
/// * [colorFilter], which overrides [shader].
/// * [color], which is used if [shader] and [colorFilter] are null.
final Shader shader;
/// A color filter to apply when a shape is drawn or when a layer is
/// composited.
///
/// See [ColorFilter] for details.
///
/// When a shape is being drawn, [colorFilter] overrides [color] and [shader].
final ColorFilter colorFilter;
/// Whether the colors of the image are inverted when drawn.
///
/// Inverting the colors of an image applies a new color filter that will
/// be composed with any user provided color filters. This is primarily
/// used for implementing smart invert on iOS.
final bool invertColors;
const PaintStyle({
this.isAntiAlias = true,
this.color = const Color(_kColorDefault),
this.blendMode = BlendMode.srcOver,
this.style = PaintingStyle.fill,
this.strokeWidth = 0.0,
this.strokeCap = StrokeCap.butt,
this.strokeJoin = StrokeJoin.miter,
this.strokeMiterLimit = 4.0,
this.maskFilter, // null
this.filterQuality = FilterQuality.none,
this.shader, // null
this.colorFilter, // null
this.invertColors = false,
});
@override
String toString() {
final StringBuffer result = StringBuffer();
String semicolon = '';
result.write('Paint(');
if (style == PaintingStyle.stroke) {
result.write('$style');
if (strokeWidth != 0.0)
result.write(' ${strokeWidth.toStringAsFixed(1)}');
else
result.write(' hairline');
if (strokeCap != StrokeCap.butt)
result.write(' $strokeCap');
if (strokeJoin == StrokeJoin.miter) {
if (strokeMiterLimit != _kStrokeMiterLimitDefault)
result.write(' $strokeJoin up to ${strokeMiterLimit.toStringAsFixed(1)}');
} else {
result.write(' $strokeJoin');
}
semicolon = '; ';
}
if (isAntiAlias != true) {
result.write('${semicolon}antialias off');
semicolon = '; ';
}
if (color != const Color(_kColorDefault)) {
if (color != null)
result.write('$semicolon$color');
else
result.write('${semicolon}no color');
semicolon = '; ';
}
if (blendMode.index != _kBlendModeDefault) {
result.write('$semicolon$blendMode');
semicolon = '; ';
}
if (colorFilter != null) {
result.write('${semicolon}colorFilter: $colorFilter');
semicolon = '; ';
}
if (maskFilter != null) {
result.write('${semicolon}maskFilter: $maskFilter');
semicolon = '; ';
}
if (filterQuality != FilterQuality.none) {
result.write('${semicolon}filterQuality: $filterQuality');
semicolon = '; ';
}
if (shader != null) {
result.write('${semicolon}shader: $shader');
semicolon = '; ';
}
if (invertColors)
result.write('${semicolon}invert: $invertColors');
result.write(')');
return result.toString();
}
Paint toPaint() {
Paint paint = Paint();
if (this.isAntiAlias != true)
paint.isAntiAlias = this.isAntiAlias;
if (this.color != const Color(_kColorDefault))
paint.color = this.color;
if (this.blendMode != BlendMode.srcOver)
paint.blendMode = this.blendMode;
if (this.style != PaintingStyle.fill)
paint.style = this.style;
if (this.strokeWidth != 0.0)
paint.strokeWidth = this.strokeWidth;
if (this.strokeCap != StrokeCap.butt)
paint.strokeCap = this.strokeCap;
if (this.strokeJoin != StrokeJoin.miter)
paint.strokeJoin = this.strokeJoin;
if (this.strokeMiterLimit != 4.0)
paint.strokeMiterLimit = this.strokeMiterLimit;
if (this.maskFilter != null)
paint.maskFilter = this.maskFilter;
if (this.filterQuality != FilterQuality.none)
paint.filterQuality = this.filterQuality;
if (this.shader != null)
paint.shader = this.shader;
if (this.colorFilter != null)
paint.colorFilter = this.colorFilter;
if (this.invertColors != false)
paint.invertColors = this.invertColors;
return paint;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment