您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
408 行
15 KiB
408 行
15 KiB
using System.Runtime.CompilerServices;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.ui;
|
|
using UnityEngine;
|
|
using Canvas = Unity.UIWidgets.ui.Canvas;
|
|
using Rect = Unity.UIWidgets.ui.Rect;
|
|
|
|
namespace Unity.UIWidgets.material {
|
|
public abstract class InputBorder : ShapeBorder {
|
|
public InputBorder(
|
|
BorderSide borderSide = null
|
|
) {
|
|
this.borderSide = borderSide ?? BorderSide.none;
|
|
}
|
|
|
|
public static readonly InputBorder none = new _NoInputBorder();
|
|
|
|
public readonly BorderSide borderSide;
|
|
|
|
public abstract InputBorder copyWith(BorderSide borderSide = null);
|
|
|
|
public virtual bool isOutline { get; }
|
|
|
|
public abstract void paint(Canvas canvas, Rect rect,
|
|
float gapStart,
|
|
float gapExtent = 0.0f,
|
|
float gapPercentage = 0.0f
|
|
);
|
|
|
|
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection) {
|
|
paint(canvas, rect, 0.0f);
|
|
}
|
|
}
|
|
|
|
class _NoInputBorder : InputBorder {
|
|
public _NoInputBorder() : base(borderSide: BorderSide.none) {
|
|
}
|
|
|
|
public override InputBorder copyWith(BorderSide borderSide) {
|
|
return new _NoInputBorder();
|
|
}
|
|
|
|
public override bool isOutline {
|
|
get { return false; }
|
|
}
|
|
|
|
public override EdgeInsetsGeometry dimensions {
|
|
get { return EdgeInsets.zero; }
|
|
}
|
|
|
|
public override ShapeBorder scale(float t) {
|
|
return new _NoInputBorder();
|
|
}
|
|
|
|
public override Path getInnerPath(Rect rect, TextDirection? textDirection) {
|
|
Path path = new Path();
|
|
path.addRect(rect);
|
|
return path;
|
|
}
|
|
|
|
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection) {
|
|
throw new System.NotImplementedException();
|
|
}
|
|
|
|
public override Path getOuterPath(Rect rect, TextDirection? textDirection) {
|
|
Path path = new Path();
|
|
path.addRect(rect);
|
|
return path;
|
|
}
|
|
|
|
public override void paint(Canvas canvas, Rect rect,
|
|
float gapStart,
|
|
float gapExtent = 0.0f,
|
|
float gapPercentage = 0.0f
|
|
) {
|
|
}
|
|
}
|
|
|
|
public class UnderlineInputBorder : InputBorder {
|
|
public UnderlineInputBorder(
|
|
BorderSide borderSide = null,
|
|
BorderRadius borderRadius = null
|
|
) : base(borderSide: borderSide ?? new BorderSide()) {
|
|
this.borderRadius = borderRadius ?? BorderRadius.only(
|
|
topLeft: Radius.circular(4.0f),
|
|
topRight: Radius.circular(4.0f)
|
|
);
|
|
}
|
|
|
|
public readonly BorderRadius borderRadius;
|
|
|
|
public override bool isOutline {
|
|
get { return false; }
|
|
}
|
|
|
|
public UnderlineInputBorder copyWith(BorderSide borderSide = null, BorderRadius borderRadius = null) {
|
|
return new UnderlineInputBorder(
|
|
borderSide: borderSide ?? this.borderSide,
|
|
borderRadius: borderRadius ?? this.borderRadius
|
|
);
|
|
}
|
|
|
|
public override InputBorder copyWith(BorderSide borderSide = null) {
|
|
return new UnderlineInputBorder(
|
|
borderSide: borderSide ?? this.borderSide
|
|
);
|
|
}
|
|
|
|
public override EdgeInsetsGeometry dimensions {
|
|
get { return EdgeInsets.only(bottom: borderSide.width); }
|
|
}
|
|
|
|
public override ShapeBorder scale(float t) {
|
|
return new UnderlineInputBorder(borderSide: borderSide.scale(t));
|
|
}
|
|
|
|
public override Path getInnerPath(Rect rect, TextDirection? textDirection) {
|
|
Path path = new Path();
|
|
path.addRect(Rect.fromLTWH(rect.left, rect.top, rect.width,
|
|
Mathf.Max(0.0f, rect.height - borderSide.width)));
|
|
return path;
|
|
}
|
|
|
|
public override Path getOuterPath(Rect rect, TextDirection? textDirection) {
|
|
Path path = new Path();
|
|
path.addRRect(borderRadius.toRRect(rect));
|
|
return path;
|
|
}
|
|
|
|
public override ShapeBorder lerpFrom(ShapeBorder a, float t) {
|
|
if (a is UnderlineInputBorder) {
|
|
return new UnderlineInputBorder(
|
|
borderSide: BorderSide.lerp((a as UnderlineInputBorder).borderSide, borderSide, t),
|
|
borderRadius: BorderRadius.lerp((a as UnderlineInputBorder).borderRadius, borderRadius, t)
|
|
);
|
|
}
|
|
|
|
return base.lerpFrom(a, t);
|
|
}
|
|
|
|
public override ShapeBorder lerpTo(ShapeBorder b, float t) {
|
|
if (b is UnderlineInputBorder) {
|
|
return new UnderlineInputBorder(
|
|
borderSide: BorderSide.lerp(borderSide, (b as UnderlineInputBorder).borderSide, t),
|
|
borderRadius: BorderRadius.lerp(borderRadius, (b as UnderlineInputBorder).borderRadius, t)
|
|
);
|
|
}
|
|
|
|
return base.lerpTo(b, t);
|
|
}
|
|
|
|
public override void paint(Canvas canvas, Rect rect,
|
|
float gapStart,
|
|
float gapExtent = 0.0f,
|
|
float gapPercentage = 0.0f
|
|
) {
|
|
if (borderRadius.bottomLeft != Radius.zero || borderRadius.bottomRight != Radius.zero) {
|
|
canvas.clipPath(getOuterPath(rect, null));
|
|
}
|
|
|
|
canvas.drawLine(rect.bottomLeft, rect.bottomRight, borderSide.toPaint());
|
|
}
|
|
|
|
public static bool operator ==(UnderlineInputBorder left, UnderlineInputBorder right) {
|
|
return left.Equals(right);
|
|
}
|
|
|
|
public static bool operator !=(UnderlineInputBorder left, UnderlineInputBorder right) {
|
|
return !left.Equals(right);
|
|
}
|
|
|
|
public bool Equals(UnderlineInputBorder other) {
|
|
return borderSide == other.borderSide;
|
|
}
|
|
|
|
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((UnderlineInputBorder) obj);
|
|
}
|
|
|
|
public override int GetHashCode() {
|
|
return borderSide.GetHashCode();
|
|
}
|
|
}
|
|
|
|
public class OutlineInputBorder : InputBorder {
|
|
public OutlineInputBorder(
|
|
BorderSide borderSide = null,
|
|
BorderRadius borderRadius = null,
|
|
float gapPadding = 4.0f
|
|
) : base(borderSide: borderSide ?? new BorderSide()) {
|
|
D.assert(gapPadding >= 0.0f);
|
|
this.gapPadding = gapPadding;
|
|
this.borderRadius = borderRadius ?? BorderRadius.all(Radius.circular(4.0f));
|
|
}
|
|
|
|
static bool _cornersAreCircular(BorderRadius borderRadius) {
|
|
return borderRadius.topLeft.x == borderRadius.topLeft.y
|
|
&& borderRadius.bottomLeft.x == borderRadius.bottomLeft.y
|
|
&& borderRadius.topRight.x == borderRadius.topRight.y
|
|
&& borderRadius.bottomRight.x == borderRadius.bottomRight.y;
|
|
}
|
|
|
|
public readonly float gapPadding;
|
|
|
|
public readonly BorderRadius borderRadius;
|
|
|
|
public override bool isOutline {
|
|
get { return true; }
|
|
}
|
|
|
|
public OutlineInputBorder copyWith(
|
|
BorderSide borderSide,
|
|
BorderRadius borderRadius,
|
|
float? gapPadding
|
|
) {
|
|
return new OutlineInputBorder(
|
|
borderSide: borderSide ?? this.borderSide,
|
|
borderRadius: borderRadius ?? this.borderRadius,
|
|
gapPadding: gapPadding ?? this.gapPadding
|
|
);
|
|
}
|
|
|
|
public override InputBorder copyWith(BorderSide borderSide) {
|
|
return new OutlineInputBorder(
|
|
borderSide: borderSide ?? this.borderSide,
|
|
borderRadius: borderRadius,
|
|
gapPadding: gapPadding
|
|
);
|
|
}
|
|
|
|
public override EdgeInsetsGeometry dimensions {
|
|
get { return EdgeInsets.all(borderSide.width); }
|
|
}
|
|
|
|
public override ShapeBorder scale(float t) {
|
|
return new OutlineInputBorder(
|
|
borderSide: borderSide.scale(t),
|
|
borderRadius: (BorderRadius)(borderRadius * t),
|
|
gapPadding: gapPadding * t
|
|
);
|
|
}
|
|
|
|
public override ShapeBorder lerpFrom(ShapeBorder a, float t) {
|
|
if (a is OutlineInputBorder) {
|
|
OutlineInputBorder outline = a as OutlineInputBorder;
|
|
return new OutlineInputBorder(
|
|
borderRadius: BorderRadius.lerp(outline.borderRadius, borderRadius, t),
|
|
borderSide: BorderSide.lerp(outline.borderSide, borderSide, t),
|
|
gapPadding: outline.gapPadding
|
|
);
|
|
}
|
|
|
|
return base.lerpFrom(a, t);
|
|
}
|
|
|
|
public override ShapeBorder lerpTo(ShapeBorder b, float t) {
|
|
if (b is OutlineInputBorder) {
|
|
OutlineInputBorder outline = b as OutlineInputBorder;
|
|
return new OutlineInputBorder(
|
|
borderRadius: BorderRadius.lerp(borderRadius, outline.borderRadius, t),
|
|
borderSide: BorderSide.lerp(borderSide, outline.borderSide, t),
|
|
gapPadding: outline.gapPadding
|
|
);
|
|
}
|
|
|
|
return base.lerpTo(b, t);
|
|
}
|
|
|
|
public override Path getInnerPath(Rect rect, TextDirection? textDirection) {
|
|
Path path = new Path();
|
|
path.addRRect(borderRadius.toRRect(rect).deflate(borderSide.width));
|
|
return path;
|
|
}
|
|
|
|
public override Path getOuterPath(Rect rect, TextDirection? textDirection) {
|
|
Path path = new Path();
|
|
path.addRRect(borderRadius.toRRect(rect));
|
|
return path;
|
|
}
|
|
|
|
Path _gapBorderPath(Canvas canvas, RRect center, float start, float extent) {
|
|
RRect scaledRRect = center.scaleRadii();
|
|
Rect tlCorner = Rect.fromLTWH(
|
|
scaledRRect.left,
|
|
scaledRRect.top,
|
|
scaledRRect.tlRadiusX * 2.0f,
|
|
scaledRRect.tlRadiusY * 2.0f
|
|
);
|
|
Rect trCorner = Rect.fromLTWH(
|
|
scaledRRect.right - scaledRRect.trRadiusX * 2.0f,
|
|
scaledRRect.top,
|
|
scaledRRect.trRadiusX * 2.0f,
|
|
scaledRRect.trRadiusY * 2.0f
|
|
);
|
|
Rect brCorner = Rect.fromLTWH(
|
|
scaledRRect.right - scaledRRect.brRadiusX * 2.0f,
|
|
scaledRRect.bottom - scaledRRect.brRadiusY * 2.0f,
|
|
scaledRRect.brRadiusX * 2.0f,
|
|
scaledRRect.brRadiusY * 2.0f
|
|
);
|
|
Rect blCorner = Rect.fromLTWH(
|
|
scaledRRect.left,
|
|
scaledRRect.bottom - scaledRRect.brRadiusY * 2.0f,
|
|
scaledRRect.blRadiusX * 2.0f,
|
|
scaledRRect.blRadiusY * 2.0f
|
|
);
|
|
|
|
const float cornerArcSweep = Mathf.PI / 2.0f;
|
|
float tlCornerArcSweep = start < scaledRRect.tlRadiusX
|
|
? Mathf.Asin((start / scaledRRect.tlRadiusX).clamp(-1.0f, 1.0f))
|
|
: Mathf.PI / 2.0f;
|
|
|
|
Path path = new Path();
|
|
path.addArc(tlCorner, Mathf.PI, tlCornerArcSweep);
|
|
path.moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top);
|
|
|
|
if (start > scaledRRect.tlRadiusX) {
|
|
path.lineTo(scaledRRect.left + start, scaledRRect.top);
|
|
}
|
|
|
|
const float trCornerArcStart = (3 * Mathf.PI) / 2.0f;
|
|
const float trCornerArcSweep = cornerArcSweep;
|
|
if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) {
|
|
path.relativeMoveTo(extent, 0.0f);
|
|
path.lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top);
|
|
path.addArc(trCorner, trCornerArcStart, trCornerArcSweep);
|
|
}
|
|
else if (start + extent < scaledRRect.width) {
|
|
float dx = scaledRRect.width - (start + extent);
|
|
float sweep = Mathf.Acos(dx / scaledRRect.trRadiusX);
|
|
path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep);
|
|
}
|
|
|
|
path.moveTo(scaledRRect.right, scaledRRect.top + scaledRRect.trRadiusY);
|
|
path.lineTo(scaledRRect.right, scaledRRect.bottom - scaledRRect.brRadiusY);
|
|
path.addArc(brCorner, 0.0f, cornerArcSweep);
|
|
path.lineTo(scaledRRect.left + scaledRRect.blRadiusX, scaledRRect.bottom);
|
|
path.addArc(blCorner, Mathf.PI / 2.0f, cornerArcSweep);
|
|
path.lineTo(scaledRRect.left, scaledRRect.top + scaledRRect.trRadiusY);
|
|
return path;
|
|
}
|
|
|
|
public override void paint(Canvas canvas, Rect rect,
|
|
float gapStart,
|
|
float gapExtent = 0.0f,
|
|
float gapPercentage = 0.0f
|
|
) {
|
|
D.assert(gapPercentage >= 0.0f && gapPercentage <= 1.0f);
|
|
D.assert(_cornersAreCircular(borderRadius));
|
|
|
|
Paint paint = borderSide.toPaint();
|
|
RRect outer = borderRadius.toRRect(rect);
|
|
RRect center = outer.deflate(borderSide.width / 2.0f);
|
|
if (gapExtent <= 0.0f || gapPercentage == 0.0f) {
|
|
canvas.drawRRect(center, paint);
|
|
}
|
|
else {
|
|
float extent = MathUtils.lerpNullableFloat(0.0f, gapExtent + gapPadding * 2.0f, gapPercentage);
|
|
Path path = _gapBorderPath(canvas, center, Mathf.Max(0.0f,gapStart - gapPadding), extent);
|
|
canvas.drawPath(path, paint);
|
|
}
|
|
}
|
|
|
|
public static bool operator ==(OutlineInputBorder left, OutlineInputBorder right) {
|
|
return left.Equals(right);
|
|
}
|
|
|
|
public static bool operator !=(OutlineInputBorder left, OutlineInputBorder right) {
|
|
return !left.Equals(right);
|
|
}
|
|
|
|
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((OutlineInputBorder) obj);
|
|
}
|
|
|
|
public bool Equals(OutlineInputBorder other) {
|
|
return other.borderSide == borderSide
|
|
&& other.borderRadius == borderRadius
|
|
&& other.gapPadding == gapPadding;
|
|
}
|
|
|
|
public override int GetHashCode() {
|
|
var hashCode = borderSide.GetHashCode();
|
|
hashCode = (hashCode * 397) ^ borderRadius.GetHashCode();
|
|
hashCode = (hashCode * 397) ^ gapPadding.GetHashCode();
|
|
return hashCode;
|
|
}
|
|
}
|
|
}
|