您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
304 行
11 KiB
304 行
11 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.ui;
|
|
|
|
namespace Unity.UIWidgets.painting {
|
|
public class ShapeDecoration : Decoration, IEquatable<ShapeDecoration> {
|
|
public ShapeDecoration(
|
|
Color color = null,
|
|
DecorationImage image = null,
|
|
Gradient gradient = null,
|
|
List<BoxShadow> shadows = null,
|
|
ShapeBorder shape = null
|
|
) {
|
|
D.assert(!(color != null && gradient != null));
|
|
D.assert(shape != null);
|
|
|
|
this.color = color;
|
|
this.image = image;
|
|
this.gradient = gradient;
|
|
this.shadows = shadows;
|
|
this.shape = shape;
|
|
}
|
|
|
|
public readonly Color color;
|
|
public readonly DecorationImage image;
|
|
public readonly Gradient gradient;
|
|
public readonly List<BoxShadow> shadows;
|
|
public readonly ShapeBorder shape;
|
|
|
|
public static ShapeDecoration fromBoxDecoration(BoxDecoration source) {
|
|
ShapeBorder shape = null;
|
|
|
|
switch (source.shape) {
|
|
case BoxShape.circle:
|
|
if (source.border != null) {
|
|
D.assert(source.border.isUniform);
|
|
shape = new CircleBorder(side: source.border.top);
|
|
}
|
|
else {
|
|
shape = new CircleBorder();
|
|
}
|
|
|
|
break;
|
|
case BoxShape.rectangle:
|
|
if (source.borderRadius != null) {
|
|
D.assert(source.border == null || source.border.isUniform);
|
|
shape = new RoundedRectangleBorder(
|
|
side: source.border?.top ?? BorderSide.none,
|
|
borderRadius: source.borderRadius
|
|
);
|
|
}
|
|
else {
|
|
shape = source.border ?? new Border();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return new ShapeDecoration(
|
|
color: source.color,
|
|
image: source.image,
|
|
gradient: source.gradient,
|
|
shadows: source.boxShadow,
|
|
shape: shape
|
|
);
|
|
}
|
|
|
|
public override Path getClipPath(Rect rect, TextDirection textDirection) {
|
|
return shape.getOuterPath(rect);
|
|
}
|
|
|
|
public override EdgeInsetsGeometry padding {
|
|
get { return shape.dimensions; }
|
|
}
|
|
|
|
public override bool isComplex {
|
|
get { return shadows != null; }
|
|
}
|
|
|
|
public override Decoration lerpFrom(Decoration a, float t) {
|
|
if (a is BoxDecoration decoration) {
|
|
return lerp(fromBoxDecoration(decoration), this, t);
|
|
}
|
|
else if (a == null || a is ShapeDecoration) {
|
|
return lerp(a, this, t);
|
|
}
|
|
|
|
return base.lerpFrom(a, t);
|
|
}
|
|
|
|
public override Decoration lerpTo(Decoration b, float t) {
|
|
if (b is BoxDecoration decoration) {
|
|
return lerp(this, fromBoxDecoration(decoration), t);
|
|
}
|
|
else if (b == null || b is ShapeDecoration) {
|
|
return lerp(this, b, t);
|
|
}
|
|
|
|
return base.lerpTo(b, t);
|
|
}
|
|
|
|
public static ShapeDecoration lerp(ShapeDecoration a, ShapeDecoration b, float t) {
|
|
if (a == null && b == null) {
|
|
return null;
|
|
}
|
|
|
|
if (a != null && b != null) {
|
|
if (t == 0.0) {
|
|
return a;
|
|
}
|
|
|
|
if (t == 1.0) {
|
|
return b;
|
|
}
|
|
}
|
|
|
|
return new ShapeDecoration(
|
|
color: Color.lerp(a?.color, b?.color, t),
|
|
gradient: Gradient.lerp(a?.gradient, b?.gradient, t),
|
|
image: t < 0.5 ? a.image : b.image,
|
|
shadows: BoxShadow.lerpList(a?.shadows, b?.shadows, t),
|
|
shape: ShapeBorder.lerp(a?.shape, b?.shape, t)
|
|
);
|
|
}
|
|
|
|
public bool Equals(ShapeDecoration other) {
|
|
if (ReferenceEquals(null, other)) {
|
|
return false;
|
|
}
|
|
|
|
if (ReferenceEquals(this, other)) {
|
|
return true;
|
|
}
|
|
|
|
return Equals(color, other.color) && Equals(image, other.image) &&
|
|
Equals(gradient, other.gradient) && Equals(shadows, other.shadows) &&
|
|
Equals(shape, other.shape);
|
|
}
|
|
|
|
public override bool Equals(object obj) {
|
|
if (ReferenceEquals(null, obj)) {
|
|
return false;
|
|
}
|
|
|
|
if (ReferenceEquals(this, obj)) {
|
|
return true;
|
|
}
|
|
|
|
if (obj.GetType() != GetType()) {
|
|
return false;
|
|
}
|
|
|
|
return Equals((ShapeDecoration) obj);
|
|
}
|
|
|
|
public override int GetHashCode() {
|
|
unchecked {
|
|
var hashCode = (color != null ? color.GetHashCode() : 0);
|
|
hashCode = (hashCode * 397) ^ (image != null ? image.GetHashCode() : 0);
|
|
hashCode = (hashCode * 397) ^ (gradient != null ? gradient.GetHashCode() : 0);
|
|
hashCode = (hashCode * 397) ^ (shadows != null ? shadows.GetHashCode() : 0);
|
|
hashCode = (hashCode * 397) ^ (shape != null ? shape.GetHashCode() : 0);
|
|
return hashCode;
|
|
}
|
|
}
|
|
|
|
public static bool operator ==(ShapeDecoration left, ShapeDecoration right) {
|
|
return Equals(left, right);
|
|
}
|
|
|
|
public static bool operator !=(ShapeDecoration left, ShapeDecoration right) {
|
|
return !Equals(left, right);
|
|
}
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.whitespace;
|
|
properties.add(new ColorProperty("color", color,
|
|
defaultValue: foundation_.kNullDefaultValue));
|
|
properties.add(new DiagnosticsProperty<Gradient>("gradient", gradient,
|
|
defaultValue: foundation_.kNullDefaultValue));
|
|
properties.add(new DiagnosticsProperty<DecorationImage>("image", image,
|
|
defaultValue: foundation_.kNullDefaultValue));
|
|
properties.add(new EnumerableProperty<BoxShadow>("shadows", shadows,
|
|
defaultValue: foundation_.kNullDefaultValue, style: DiagnosticsTreeStyle.whitespace));
|
|
properties.add(new DiagnosticsProperty<ShapeBorder>("shape", shape));
|
|
}
|
|
|
|
public override bool hitTest(Size size, Offset position, TextDirection textDirection) {
|
|
return shape.getOuterPath(Offset.zero & size, textDirection: textDirection).contains(position);
|
|
}
|
|
|
|
public override BoxPainter createBoxPainter(VoidCallback onChanged = null) {
|
|
D.assert(onChanged != null || image == null);
|
|
return new _ShapeDecorationPainter(this, onChanged);
|
|
}
|
|
}
|
|
|
|
class _ShapeDecorationPainter : BoxPainter {
|
|
public _ShapeDecorationPainter(ShapeDecoration decoration, VoidCallback onChanged)
|
|
: base(onChanged) {
|
|
D.assert(decoration != null);
|
|
_decoration = decoration;
|
|
}
|
|
|
|
readonly ShapeDecoration _decoration;
|
|
|
|
Rect _lastRect;
|
|
Path _outerPath;
|
|
Path _innerPath;
|
|
Paint _interiorPaint;
|
|
int? _shadowCount;
|
|
Path[] _shadowPaths;
|
|
Paint[] _shadowPaints;
|
|
|
|
void _precache(Rect rect) {
|
|
D.assert(rect != null);
|
|
if (rect == _lastRect) {
|
|
return;
|
|
}
|
|
|
|
if (_interiorPaint == null && (_decoration.color != null || _decoration.gradient != null)) {
|
|
_interiorPaint = new Paint();
|
|
if (_decoration.color != null) {
|
|
_interiorPaint.color = _decoration.color;
|
|
}
|
|
}
|
|
|
|
if (_decoration.gradient != null) {
|
|
// this._interiorPaint.shader = this._decoration.gradient.createShader(rect);
|
|
}
|
|
|
|
if (_decoration.shadows != null) {
|
|
if (_shadowCount == null) {
|
|
_shadowCount = _decoration.shadows.Count;
|
|
_shadowPaths = new Path[_shadowCount.Value];
|
|
_shadowPaints = new Paint[_shadowCount.Value];
|
|
for (int index = 0; index < _shadowCount.Value; index += 1) {
|
|
_shadowPaints[index] = _decoration.shadows[index].toPaint();
|
|
}
|
|
}
|
|
|
|
for (int index = 0; index < _shadowCount; index += 1) {
|
|
BoxShadow shadow = _decoration.shadows[index];
|
|
_shadowPaths[index] = _decoration.shape.getOuterPath(
|
|
rect.shift(shadow.offset).inflate(shadow.spreadRadius));
|
|
}
|
|
}
|
|
|
|
if (_interiorPaint != null || _shadowCount != null) {
|
|
_outerPath = _decoration.shape.getOuterPath(rect);
|
|
}
|
|
|
|
if (_decoration.image != null) {
|
|
_innerPath = _decoration.shape.getInnerPath(rect);
|
|
}
|
|
|
|
_lastRect = rect;
|
|
}
|
|
|
|
void _paintShadows(Canvas canvas) {
|
|
if (_shadowCount != null) {
|
|
for (int index = 0; index < _shadowCount.Value; index += 1) {
|
|
canvas.drawPath(_shadowPaths[index], _shadowPaints[index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _paintInterior(Canvas canvas) {
|
|
if (_interiorPaint != null) {
|
|
canvas.drawPath(_outerPath, _interiorPaint);
|
|
}
|
|
}
|
|
|
|
DecorationImagePainter _imagePainter;
|
|
|
|
void _paintImage(Canvas canvas, ImageConfiguration configuration) {
|
|
if (_decoration.image == null) {
|
|
return;
|
|
}
|
|
|
|
_imagePainter = _imagePainter ?? _decoration.image.createPainter(onChanged);
|
|
_imagePainter.paint(canvas, _lastRect, _innerPath, configuration);
|
|
}
|
|
|
|
public override void Dispose() {
|
|
_imagePainter?.Dispose();
|
|
base.Dispose();
|
|
}
|
|
|
|
public override void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
|
|
D.assert(configuration != null);
|
|
D.assert(configuration.size != null);
|
|
Rect rect = offset & configuration.size;
|
|
TextDirection textDirection = configuration.textDirection;
|
|
_precache(rect);
|
|
_paintShadows(canvas);
|
|
_paintInterior(canvas);
|
|
_paintImage(canvas, configuration);
|
|
_decoration.shape.paint(canvas, rect, textDirection: textDirection);
|
|
}
|
|
}
|
|
}
|