fzhangtj
6 年前
当前提交
d060a225
共有 58 个文件被更改,包括 5914 次插入 和 77 次删除
-
55Assets/UIWidgets/Tests/CanvasAndLayers.cs
-
8Assets/UIWidgets/painting/alignment.cs
-
6Assets/UIWidgets/painting/alignment.cs.meta
-
46Assets/UIWidgets/painting/basic_types.cs
-
29Assets/UIWidgets/painting/binding.cs
-
17Assets/UIWidgets/painting/box_border.cs
-
128Assets/UIWidgets/painting/decoration_image.cs
-
13Assets/UIWidgets/rendering/box.cs
-
98Assets/UIWidgets/rendering/object.mixin.gen.cs
-
7Assets/UIWidgets/rendering/object.mixin.njk
-
514Assets/UIWidgets/rendering/sliver.cs
-
738Assets/UIWidgets/rendering/viewpoint.cs
-
61Assets/UIWidgets/rendering/viewport_offset.cs
-
47Assets/UIWidgets/ui/geometry.cs
-
11Assets/UIWidgets/ui/painting/canvas.cs
-
41Assets/UIWidgets/ui/painting/canvas_impl.cs
-
7Assets/UIWidgets/ui/painting/draw_cmd.cs
-
42Assets/UIWidgets/ui/painting/painting.cs
-
84Assets/UIWidgets/painting/box_fit.cs
-
3Assets/UIWidgets/painting/box_fit.cs.meta
-
138Assets/UIWidgets/painting/image_cache.cs
-
3Assets/UIWidgets/painting/image_cache.cs.meta
-
109Assets/UIWidgets/painting/image_provider.cs
-
3Assets/UIWidgets/painting/image_provider.cs.meta
-
111Assets/UIWidgets/painting/image_stream.cs
-
3Assets/UIWidgets/painting/image_stream.cs.meta
-
8Assets/UIWidgets/promise.meta
-
199Assets/UIWidgets/rendering/image.cs
-
3Assets/UIWidgets/rendering/image.cs.meta
-
170Assets/UIWidgets/rendering/sliver_fixed_extent_list.cs
-
3Assets/UIWidgets/rendering/sliver_fixed_extent_list.cs.meta
-
194Assets/UIWidgets/rendering/sliver_list.cs
-
3Assets/UIWidgets/rendering/sliver_list.cs.meta
-
299Assets/UIWidgets/rendering/sliver_multi_box_adaptor.cs
-
3Assets/UIWidgets/rendering/sliver_multi_box_adaptor.cs.meta
-
232Assets/UIWidgets/rendering/sliver_padding.cs
-
3Assets/UIWidgets/rendering/sliver_padding.cs.meta
-
20Assets/UIWidgets/ui/painting/image.cs
-
3Assets/UIWidgets/ui/painting/image.cs.meta
-
2Assets/UIWidgets/gestures/arena.cs
-
3Assets/UIWidgets/promise/EnumerableExt.cs.meta
-
1001Assets/UIWidgets/promise/Promise.cs
-
3Assets/UIWidgets/promise/Promise.cs.meta
-
19Assets/UIWidgets/promise/PromiseException.cs
-
3Assets/UIWidgets/promise/PromiseException.cs.meta
-
3Assets/UIWidgets/promise/PromiseHelpers.cs.meta
-
3Assets/UIWidgets/promise/PromiseStateException.cs.meta
-
3Assets/UIWidgets/promise/PromiseTimer.cs.meta
-
1001Assets/UIWidgets/promise/Promise_NonGeneric.cs
-
3Assets/UIWidgets/promise/Promise_NonGeneric.cs.meta
-
3Assets/UIWidgets/promise/Tuple.cs.meta
-
33Assets/UIWidgets/promise/EnumerableExt.cs
-
70Assets/UIWidgets/promise/PromiseHelpers.cs
-
22Assets/UIWidgets/promise/PromiseStateException.cs
-
220Assets/UIWidgets/promise/PromiseTimer.cs
-
137Assets/UIWidgets/promise/Tuple.cs
|
|||
fileFormatVersion: 2 |
|||
guid: d34b191577d24c30b0fd2a99022b8a88 |
|||
timeCreated: 1535002958 |
|||
fileFormatVersion: 2 |
|||
guid: 52b90656e86c4a39af38d0518a67f68b |
|||
timeCreated: 1534820611 |
|
|||
using UIWidgets.ui; |
|||
|
|||
public abstract class PaintingBinding { |
|||
public class PaintingBinding { |
|||
|
|||
public PaintingBinding(Window window) { |
|||
this._window = window; |
|||
} |
|||
private static PaintingBinding _instance; |
|||
public readonly Window _window; |
|||
|
|||
public static PaintingBinding instance { |
|||
get { return _instance; } |
|||
} |
|||
|
|||
private ImageCache _imageCache; |
|||
|
|||
public ImageCache imageCache { |
|||
get { return _imageCache; } |
|||
} |
|||
|
|||
public ImageCache createImageCache() { |
|||
return new ImageCache(); |
|||
} |
|||
|
|||
public void initInstances() { |
|||
_instance = this; |
|||
_imageCache = createImageCache(); |
|||
} |
|||
} |
|||
} |
|
|||
|
|||
using System; |
|||
using UIWidgets.ui; |
|||
using System.Collections.Generic; |
|||
/// How to paint any portions of a box not covered by an image.
|
|||
public 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 portions of the box transparent.
|
|||
noRepeat, |
|||
} |
|||
|
|||
|
|||
public DecorationImage() { |
|||
} |
|||
} |
|||
|
|||
public static class DecorationImageUtil { |
|||
public static void paintImage(Canvas canvas, Rect rect, ui.Image image, BoxFit fit, Rect centerSlice, |
|||
Alignment alignment = null, |
|||
ImageRepeat repeat = ImageRepeat.noRepeat) { |
|||
if (rect.isEmpty) |
|||
return; |
|||
alignment = alignment ?? Alignment.center; |
|||
Size outputSize = rect.size; |
|||
Size inputSize = new Size(image.width, image.height); |
|||
Offset sliceBorder = null; |
|||
if (centerSlice != null) { |
|||
sliceBorder = new Offset( |
|||
centerSlice.left + inputSize.width - centerSlice.right, |
|||
centerSlice.top + inputSize.height - centerSlice.bottom |
|||
); |
|||
outputSize -= sliceBorder; |
|||
inputSize -= sliceBorder; |
|||
} |
|||
|
|||
fit = centerSlice == null ? BoxFit.scaleDown : BoxFit.fill; |
|||
FittedSizes fittedSizes = FittedSizes.applyBoxFit(fit, inputSize, outputSize); |
|||
Size sourceSize = fittedSizes.source; |
|||
Size destinationSize = fittedSizes.destination; |
|||
if (centerSlice != null) { |
|||
outputSize += sliceBorder; |
|||
destinationSize += sliceBorder; |
|||
} |
|||
|
|||
if (repeat != ImageRepeat.noRepeat && destinationSize == outputSize) { |
|||
repeat = ImageRepeat.noRepeat; |
|||
} |
|||
|
|||
Paint paint = new Paint(); // ..isAntiAlias = false;
|
|||
// if (colorFilter != null)
|
|||
// paint.colorFilter = colorFilter;
|
|||
if (sourceSize != destinationSize) { |
|||
// Use the "low" quality setting to scale the image, which corresponds to
|
|||
// bilinear interpolation, rather than the default "none" which corresponds
|
|||
// to nearest-neighbor.
|
|||
// paint.filterQuality = FilterQuality.low;
|
|||
} |
|||
|
|||
double halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0; |
|||
double halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0; |
|||
double dx = halfWidthDelta + alignment.x * halfWidthDelta; |
|||
double dy = halfHeightDelta + alignment.y * halfHeightDelta; |
|||
Offset destinationPosition = rect.topLeft.translate(dx, dy); |
|||
Rect destinationRect = destinationPosition & destinationSize; |
|||
bool needSave = repeat != ImageRepeat.noRepeat; |
|||
if (needSave) |
|||
canvas.save(); |
|||
if (repeat != ImageRepeat.noRepeat) |
|||
canvas.clipRect(rect); |
|||
if (centerSlice == null) { |
|||
Rect sourceRect = alignment.inscribe( |
|||
fittedSizes.source, Offset.zero & inputSize |
|||
); |
|||
foreach (Rect tileRect in _generateImageTileRects(rect, destinationRect, repeat)) { |
|||
canvas.drawImageRect(sourceRect, tileRect, paint, image); |
|||
} |
|||
} |
|||
else { |
|||
// todo
|
|||
foreach (Rect tileRect in _generateImageTileRects(rect, destinationRect, repeat)) { |
|||
// canvas.drawImageNine(image, centerSlice, tileRect, paint);
|
|||
} |
|||
} |
|||
|
|||
if (needSave) |
|||
canvas.restore(); |
|||
} |
|||
|
|||
public static List<Rect> _generateImageTileRects(Rect outputRect, Rect fundamentalRect, |
|||
ImageRepeat repeat) { |
|||
List<Rect> tileRects = new List<Rect>(); |
|||
if (repeat == ImageRepeat.noRepeat) { |
|||
tileRects.Add(fundamentalRect); |
|||
return tileRects; |
|||
} |
|||
|
|||
int startX = 0; |
|||
int startY = 0; |
|||
int stopX = 0; |
|||
int stopY = 0; |
|||
double strideX = fundamentalRect.width; |
|||
double strideY = fundamentalRect.height; |
|||
|
|||
if (repeat == ImageRepeat.repeat || repeat == ImageRepeat.repeatX) { |
|||
startX = (int) Math.Floor((outputRect.left - fundamentalRect.left) / strideX); |
|||
stopX = (int) Math.Ceiling((outputRect.right - fundamentalRect.right) / strideX); |
|||
} |
|||
|
|||
if (repeat == ImageRepeat.repeat || repeat == ImageRepeat.repeatY) { |
|||
startY = (int) Math.Floor((outputRect.top - fundamentalRect.top) / strideY); |
|||
stopY = (int) Math.Ceiling((outputRect.bottom - fundamentalRect.bottom) / strideY); |
|||
} |
|||
|
|||
for (int i = startX; i <= stopX; ++i) { |
|||
for (int j = startY; j <= stopY; ++j) |
|||
tileRects.Add(fundamentalRect.shift(new Offset(i * strideX, j * strideY))); |
|||
} |
|||
|
|||
return tileRects; |
|||
} |
|||
} |
|||
} |
|
|||
namespace UIWidgets.rendering { |
|||
using System; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
using Rect = UIWidgets.ui.Rect; |
|||
|
|||
namespace UIWidgets.rendering { |
|||
public enum GrowthDirection { |
|||
forward, |
|||
reverse, |
|||
} |
|||
|
|||
public static class GrowthDirectionUtils { |
|||
public static AxisDirection applyGrowthDirectionToAxisDirection( |
|||
AxisDirection axisDirection, GrowthDirection growthDirection) { |
|||
switch (growthDirection) { |
|||
case GrowthDirection.forward: |
|||
return axisDirection; |
|||
case GrowthDirection.reverse: |
|||
return AxisUtils.flipAxisDirection(axisDirection); |
|||
} |
|||
|
|||
throw new Exception("unknown growthDirection"); |
|||
} |
|||
|
|||
public static ScrollDirection applyGrowthDirectionToScrollDirection( |
|||
ScrollDirection scrollDirection, GrowthDirection growthDirection) { |
|||
switch (growthDirection) { |
|||
case GrowthDirection.forward: |
|||
return scrollDirection; |
|||
case GrowthDirection.reverse: |
|||
return ScrollDirectionUtils.flipScrollDirection(scrollDirection); |
|||
} |
|||
public class SliverPhysicalParentData : ContainerParentDataMixinParentData<RenderSliver> { |
|||
throw new Exception("unknown growthDirection"); |
|||
} |
|||
public class SliverPhysicalContainerParentData : SliverPhysicalParentData { |
|||
public class SliverConstraints : Constraints, IEquatable<SliverConstraints> { |
|||
public SliverConstraints( |
|||
AxisDirection axisDirection, |
|||
GrowthDirection growthDirection, |
|||
ScrollDirection userScrollDirection, |
|||
double scrollOffset, |
|||
double overlap, |
|||
double remainingPaintExtent, |
|||
double crossAxisExtent, |
|||
AxisDirection crossAxisDirection, |
|||
double viewportMainAxisExtent, |
|||
double remainingCacheExtent, |
|||
double cacheOrigin |
|||
) { |
|||
this.axisDirection = axisDirection; |
|||
this.growthDirection = growthDirection; |
|||
this.userScrollDirection = userScrollDirection; |
|||
this.scrollOffset = scrollOffset; |
|||
this.overlap = overlap; |
|||
this.remainingPaintExtent = remainingPaintExtent; |
|||
this.crossAxisExtent = crossAxisExtent; |
|||
this.crossAxisDirection = crossAxisDirection; |
|||
this.viewportMainAxisExtent = viewportMainAxisExtent; |
|||
this.remainingCacheExtent = remainingCacheExtent; |
|||
this.cacheOrigin = cacheOrigin; |
|||
} |
|||
|
|||
public SliverConstraints copyWith( |
|||
AxisDirection? axisDirection = null, |
|||
GrowthDirection? growthDirection = null, |
|||
ScrollDirection? userScrollDirection = null, |
|||
double? scrollOffset = null, |
|||
double? overlap = null, |
|||
double? remainingPaintExtent = null, |
|||
double? crossAxisExtent = null, |
|||
AxisDirection? crossAxisDirection = null, |
|||
double? viewportMainAxisExtent = null, |
|||
double? remainingCacheExtent = null, |
|||
double? cacheOrigin = null |
|||
) { |
|||
return new SliverConstraints( |
|||
axisDirection: axisDirection ?? this.axisDirection, |
|||
growthDirection: growthDirection ?? this.growthDirection, |
|||
userScrollDirection: userScrollDirection ?? this.userScrollDirection, |
|||
scrollOffset: scrollOffset ?? this.scrollOffset, |
|||
overlap: overlap ?? this.overlap, |
|||
remainingPaintExtent: remainingPaintExtent ?? this.remainingPaintExtent, |
|||
crossAxisExtent: crossAxisExtent ?? this.crossAxisExtent, |
|||
crossAxisDirection: crossAxisDirection ?? this.crossAxisDirection, |
|||
viewportMainAxisExtent: viewportMainAxisExtent ?? this.viewportMainAxisExtent, |
|||
remainingCacheExtent: remainingCacheExtent ?? this.remainingCacheExtent, |
|||
cacheOrigin: cacheOrigin ?? this.cacheOrigin |
|||
); |
|||
} |
|||
|
|||
public readonly AxisDirection axisDirection; |
|||
|
|||
public readonly GrowthDirection growthDirection; |
|||
|
|||
public readonly ScrollDirection userScrollDirection; |
|||
|
|||
public readonly double scrollOffset; |
|||
|
|||
public readonly double overlap; |
|||
|
|||
public readonly double remainingPaintExtent; |
|||
|
|||
public readonly double crossAxisExtent; |
|||
|
|||
public readonly AxisDirection crossAxisDirection; |
|||
|
|||
public readonly double viewportMainAxisExtent; |
|||
|
|||
public readonly double cacheOrigin; |
|||
|
|||
public readonly double remainingCacheExtent; |
|||
|
|||
public Axis axis { |
|||
get { return AxisUtils.axisDirectionToAxis(this.axisDirection); } |
|||
} |
|||
|
|||
public GrowthDirection normalizedGrowthDirection { |
|||
get { |
|||
switch (this.axisDirection) { |
|||
case AxisDirection.down: |
|||
case AxisDirection.right: |
|||
return this.growthDirection; |
|||
case AxisDirection.up: |
|||
case AxisDirection.left: |
|||
switch (this.growthDirection) { |
|||
case GrowthDirection.forward: |
|||
return GrowthDirection.reverse; |
|||
case GrowthDirection.reverse: |
|||
return GrowthDirection.forward; |
|||
} |
|||
|
|||
throw new Exception("unknown growthDirection"); |
|||
} |
|||
|
|||
throw new Exception("unknown axisDirection"); |
|||
} |
|||
} |
|||
|
|||
public override bool isTight { |
|||
get { return false; } |
|||
} |
|||
|
|||
public override bool isNormalized { |
|||
get { |
|||
return this.scrollOffset >= 0.0 |
|||
&& this.crossAxisExtent >= 0.0 |
|||
&& AxisUtils.axisDirectionToAxis(this.axisDirection) != |
|||
AxisUtils.axisDirectionToAxis(this.crossAxisDirection) |
|||
&& this.viewportMainAxisExtent >= 0.0 |
|||
&& this.remainingPaintExtent >= 0.0; |
|||
} |
|||
} |
|||
|
|||
public BoxConstraints asBoxConstraints( |
|||
double minExtent = 0.0, |
|||
double maxExtent = double.PositiveInfinity, |
|||
double? crossAxisExtent = null |
|||
) { |
|||
crossAxisExtent = crossAxisExtent ?? this.crossAxisExtent; |
|||
switch (this.axis) { |
|||
case Axis.horizontal: |
|||
return new BoxConstraints( |
|||
minHeight: crossAxisExtent.Value, |
|||
maxHeight: crossAxisExtent.Value, |
|||
minWidth: minExtent, |
|||
maxWidth: maxExtent |
|||
); |
|||
case Axis.vertical: |
|||
return new BoxConstraints( |
|||
minWidth: crossAxisExtent.Value, |
|||
maxWidth: crossAxisExtent.Value, |
|||
minHeight: minExtent, |
|||
maxHeight: maxExtent |
|||
); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public bool Equals(SliverConstraints other) { |
|||
if (object.ReferenceEquals(null, other)) return false; |
|||
if (object.ReferenceEquals(this, other)) return true; |
|||
return this.axisDirection == other.axisDirection |
|||
&& this.growthDirection == other.growthDirection |
|||
&& this.userScrollDirection == other.userScrollDirection |
|||
&& this.scrollOffset.Equals(other.scrollOffset) |
|||
&& this.overlap.Equals(other.overlap) |
|||
&& this.remainingPaintExtent.Equals(other.remainingPaintExtent) |
|||
&& this.crossAxisExtent.Equals(other.crossAxisExtent) |
|||
&& this.crossAxisDirection == other.crossAxisDirection |
|||
&& this.viewportMainAxisExtent.Equals(other.viewportMainAxisExtent) |
|||
&& this.cacheOrigin.Equals(other.cacheOrigin) |
|||
&& this.remainingCacheExtent.Equals(other.remainingCacheExtent); |
|||
} |
|||
|
|||
public override bool Equals(object obj) { |
|||
if (object.ReferenceEquals(null, obj)) return false; |
|||
if (object.ReferenceEquals(this, obj)) return true; |
|||
if (obj.GetType() != this.GetType()) return false; |
|||
return this.Equals((SliverConstraints) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
unchecked { |
|||
var hashCode = (int) this.axisDirection; |
|||
hashCode = (hashCode * 397) ^ (int) this.growthDirection; |
|||
hashCode = (hashCode * 397) ^ (int) this.userScrollDirection; |
|||
hashCode = (hashCode * 397) ^ this.scrollOffset.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.overlap.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.remainingPaintExtent.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.crossAxisExtent.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ (int) this.crossAxisDirection; |
|||
hashCode = (hashCode * 397) ^ this.viewportMainAxisExtent.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.cacheOrigin.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.remainingCacheExtent.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
public static bool operator ==(SliverConstraints left, SliverConstraints right) { |
|||
return Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(SliverConstraints left, SliverConstraints right) { |
|||
return !Equals(left, right); |
|||
} |
|||
|
|||
|
|||
public class SliverGeometry { |
|||
public SliverGeometry( |
|||
double scrollExtent = 0.0, |
|||
double paintExtent = 0.0, |
|||
double paintOrigin = 0.0, |
|||
double? layoutExtent = null, |
|||
double maxPaintExtent = 0.0, |
|||
double maxScrollObstructionExtent = 0.0, |
|||
double? hitTestExtent = null, |
|||
bool? visible = null, |
|||
bool hasVisualOverflow = false, |
|||
double scrollOffsetCorrection = 0.0, |
|||
double? cacheExtent = null |
|||
) { |
|||
this.scrollExtent = scrollExtent; |
|||
this.paintExtent = paintExtent; |
|||
this.paintOrigin = paintOrigin; |
|||
this.layoutExtent = layoutExtent ?? paintExtent; |
|||
this.maxPaintExtent = maxPaintExtent; |
|||
this.maxScrollObstructionExtent = maxScrollObstructionExtent; |
|||
this.hitTestExtent = hitTestExtent ?? paintExtent; |
|||
this.visible = visible ?? paintExtent > 0.0; |
|||
this.hasVisualOverflow = hasVisualOverflow; |
|||
this.scrollOffsetCorrection = scrollOffsetCorrection; |
|||
this.cacheExtent = cacheExtent ?? layoutExtent ?? paintExtent; |
|||
} |
|||
|
|||
public static readonly SliverGeometry zero = new SliverGeometry(); |
|||
|
|||
public readonly double scrollExtent; |
|||
public readonly double paintOrigin; |
|||
public readonly double paintExtent; |
|||
public readonly double layoutExtent; |
|||
public readonly double maxPaintExtent; |
|||
public readonly double maxScrollObstructionExtent; |
|||
public readonly double hitTestExtent; |
|||
public readonly bool visible; |
|||
public readonly bool hasVisualOverflow; |
|||
public readonly double scrollOffsetCorrection; |
|||
public readonly double cacheExtent; |
|||
} |
|||
|
|||
public class SliverPhysicalParentData : ParentData { |
|||
public Offset paintOffset = Offset.zero; |
|||
|
|||
public void applyPaintTransform(ref Matrix4x4 transform) { |
|||
transform = Matrix4x4.Translate(this.paintOffset.toVector()) * transform; |
|||
} |
|||
} |
|||
|
|||
public class SliverPhysicalContainerParentData : ContainerParentDataMixinSliverPhysicalParentData<RenderSliver> { |
|||
} |
|||
|
|||
public class SliverLogicalParentData : ParentData { |
|||
public double layoutOffset = 0.0; |
|||
} |
|||
|
|||
public class SliverLogicalContainerParentData : ContainerParentDataMixinSliverLogicalParentData<RenderSliver> { |
|||
} |
|||
|
|||
|
|||
public new SliverConstraints constraints { |
|||
get { return (SliverConstraints) base.constraints; } |
|||
} |
|||
|
|||
public SliverGeometry geometry { |
|||
get { return this._geometry; } |
|||
set { this._geometry = value; } |
|||
} |
|||
|
|||
public SliverGeometry _geometry; |
|||
|
|||
public override Rect paintBounds { |
|||
get { |
|||
switch (this.constraints.axis) { |
|||
case Axis.horizontal: |
|||
return Rect.fromLTWH( |
|||
0.0, 0.0, |
|||
this.geometry.paintExtent, |
|||
this.constraints.crossAxisExtent |
|||
); |
|||
case Axis.vertical: |
|||
return Rect.fromLTWH( |
|||
0.0, 0.0, |
|||
this.constraints.crossAxisExtent, |
|||
this.geometry.paintExtent |
|||
); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public override void performResize() { |
|||
} |
|||
|
|||
public double centerOffsetAdjustment { |
|||
get { return 0.0; } |
|||
} |
|||
|
|||
public double calculatePaintOffset(SliverConstraints constraints, double from, double to) { |
|||
double a = constraints.scrollOffset; |
|||
double b = constraints.scrollOffset + constraints.remainingPaintExtent; |
|||
return (to.clamp(a, b) - from.clamp(a, b)).clamp(0.0, constraints.remainingPaintExtent); |
|||
} |
|||
|
|||
public double calculateCacheOffset(SliverConstraints constraints, double from, double to) { |
|||
double a = constraints.scrollOffset + constraints.cacheOrigin; |
|||
double b = constraints.scrollOffset + constraints.remainingCacheExtent; |
|||
return (to.clamp(a, b) - from.clamp(a, b)).clamp(0.0, constraints.remainingCacheExtent); |
|||
} |
|||
|
|||
public virtual double childMainAxisPosition(RenderObject child) { |
|||
return 0.0; |
|||
} |
|||
|
|||
public virtual double childCrossAxisPosition(RenderObject child) { |
|||
return 0.0; |
|||
} |
|||
|
|||
public virtual double childScrollOffset(RenderObject child) { |
|||
return 0.0; |
|||
} |
|||
|
|||
public override void applyPaintTransform(RenderObject child, ref Matrix4x4 transform) { |
|||
} |
|||
|
|||
public Size getAbsoluteSizeRelativeToOrigin() { |
|||
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection( |
|||
this.constraints.axisDirection, this.constraints.growthDirection)) { |
|||
case AxisDirection.up: |
|||
return new Size(this.constraints.crossAxisExtent, -this.geometry.paintExtent); |
|||
case AxisDirection.right: |
|||
return new Size(this.geometry.paintExtent, this.constraints.crossAxisExtent); |
|||
case AxisDirection.down: |
|||
return new Size(this.constraints.crossAxisExtent, this.geometry.paintExtent); |
|||
case AxisDirection.left: |
|||
return new Size(-this.geometry.paintExtent, this.constraints.crossAxisExtent); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public static class RenderSliverHelpers { |
|||
public static bool _getRightWayUp(SliverConstraints constraints) { |
|||
bool rightWayUp = true; |
|||
switch (constraints.axisDirection) { |
|||
case AxisDirection.up: |
|||
case AxisDirection.left: |
|||
rightWayUp = false; |
|||
break; |
|||
case AxisDirection.down: |
|||
case AxisDirection.right: |
|||
rightWayUp = true; |
|||
break; |
|||
} |
|||
|
|||
switch (constraints.growthDirection) { |
|||
case GrowthDirection.forward: |
|||
break; |
|||
case GrowthDirection.reverse: |
|||
rightWayUp = !rightWayUp; |
|||
break; |
|||
} |
|||
|
|||
return rightWayUp; |
|||
} |
|||
|
|||
public static void applyPaintTransformForBoxChild(this RenderSliver it, RenderBox child, |
|||
ref Matrix4x4 transform) { |
|||
bool rightWayUp = RenderSliverHelpers._getRightWayUp(it.constraints); |
|||
double delta = it.childMainAxisPosition(child); |
|||
double crossAxisDelta = it.childCrossAxisPosition(child); |
|||
switch (it.constraints.axis) { |
|||
case Axis.horizontal: |
|||
if (!rightWayUp) { |
|||
delta = it.geometry.paintExtent - child.size.width - delta; |
|||
} |
|||
|
|||
transform = Matrix4x4.Translate(new Vector2((float) delta, (float) crossAxisDelta)) * transform; |
|||
break; |
|||
case Axis.vertical: |
|||
if (!rightWayUp) { |
|||
delta = it.geometry.paintExtent - child.size.height - delta; |
|||
} |
|||
|
|||
transform = Matrix4x4.Translate(new Vector2((float) crossAxisDelta, (float) delta)) * transform; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public abstract class RenderSliverSingleBoxAdapter : RenderObjectWithChildMixinRenderSliver<RenderBox> { |
|||
public RenderSliverSingleBoxAdapter( |
|||
RenderBox child = null |
|||
) { |
|||
this.child = child; |
|||
} |
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is SliverPhysicalParentData)) { |
|||
child.parentData = new SliverPhysicalParentData(); |
|||
} |
|||
} |
|||
|
|||
public void setChildParentData(RenderObject child, SliverConstraints constraints, SliverGeometry geometry) { |
|||
var childParentData = (SliverPhysicalParentData) child.parentData; |
|||
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(constraints.axisDirection, |
|||
constraints.growthDirection)) { |
|||
case AxisDirection.up: |
|||
childParentData.paintOffset = new Offset(0.0, |
|||
-(geometry.scrollExtent - (geometry.paintExtent + constraints.scrollOffset))); |
|||
break; |
|||
case AxisDirection.right: |
|||
childParentData.paintOffset = new Offset(-constraints.scrollOffset, 0.0); |
|||
break; |
|||
case AxisDirection.down: |
|||
childParentData.paintOffset = new Offset(0.0, -constraints.scrollOffset); |
|||
break; |
|||
case AxisDirection.left: |
|||
childParentData.paintOffset = |
|||
new Offset(-(geometry.scrollExtent - (geometry.paintExtent + constraints.scrollOffset)), 0.0); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public override double childMainAxisPosition(RenderObject child) { |
|||
return -this.constraints.scrollOffset; |
|||
} |
|||
|
|||
public override void applyPaintTransform(RenderObject child, ref Matrix4x4 transform) { |
|||
var childParentData = (SliverPhysicalParentData) child.parentData; |
|||
childParentData.applyPaintTransform(ref transform); |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
if (this.child != null && this.geometry.visible) { |
|||
var childParentData = (SliverPhysicalParentData) this.child.parentData; |
|||
context.paintChild(this.child, offset + childParentData.paintOffset); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class RenderSliverToBoxAdapter : RenderSliverSingleBoxAdapter { |
|||
public RenderSliverToBoxAdapter( |
|||
RenderBox child = null |
|||
) : base(child) { |
|||
} |
|||
|
|||
public override void performLayout() { |
|||
if (this.child == null) { |
|||
this.geometry = SliverGeometry.zero; |
|||
return; |
|||
} |
|||
|
|||
this.child.layout(this.constraints.asBoxConstraints(), parentUsesSize: true); |
|||
|
|||
double childExtent = 0.0; |
|||
switch (this.constraints.axis) { |
|||
case Axis.horizontal: |
|||
childExtent = this.child.size.width; |
|||
break; |
|||
case Axis.vertical: |
|||
childExtent = this.child.size.height; |
|||
break; |
|||
} |
|||
|
|||
double paintedChildSize = this.calculatePaintOffset(this.constraints, from: 0.0, to: childExtent); |
|||
double cacheExtent = this.calculateCacheOffset(this.constraints, from: 0.0, to: childExtent); |
|||
|
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: childExtent, |
|||
paintExtent: paintedChildSize, |
|||
cacheExtent: cacheExtent, |
|||
maxPaintExtent: childExtent, |
|||
hitTestExtent: paintedChildSize, |
|||
hasVisualOverflow: childExtent > this.constraints.remainingPaintExtent |
|||
|| this.constraints.scrollOffset > 0.0 |
|||
); |
|||
|
|||
this.setChildParentData(this.child, this.constraints, this.geometry); |
|||
} |
|||
} |
|||
} |
|
|||
using UIWidgets.ui; |
|||
using System; |
|||
|
|||
namespace UIWidgets.painting { |
|||
public enum BoxFit { |
|||
fill, |
|||
contain, |
|||
cover, |
|||
fitWidth, |
|||
fitHeight, |
|||
none, |
|||
scaleDown, |
|||
} |
|||
|
|||
public class FittedSizes { |
|||
public FittedSizes(Size source, Size destination) { |
|||
this.source = source; |
|||
this.destination = destination; |
|||
} |
|||
|
|||
public Size source; |
|||
public Size destination; |
|||
|
|||
public static FittedSizes applyBoxFit(BoxFit fit, Size inputSize, Size outputSize) { |
|||
if (inputSize.height <= 0.0 || inputSize.width <= 0.0 || outputSize.height <= 0.0 || |
|||
outputSize.width <= 0.0) |
|||
return new FittedSizes(Size.zero, Size.zero); |
|||
Size sourceSize = null; |
|||
Size destinationSize = null; |
|||
switch (fit) { |
|||
case BoxFit.fill: |
|||
sourceSize = inputSize; |
|||
destinationSize = outputSize; |
|||
break; |
|||
case BoxFit.contain: |
|||
sourceSize = inputSize; |
|||
if (outputSize.width / outputSize.height > sourceSize.width / sourceSize.height) |
|||
destinationSize = new Size(sourceSize.width * outputSize.height / sourceSize.height, |
|||
outputSize.height); |
|||
else |
|||
destinationSize = new Size(outputSize.width, |
|||
sourceSize.height * outputSize.width / sourceSize.width); |
|||
break; |
|||
case BoxFit.cover: |
|||
if (outputSize.width / outputSize.height > inputSize.width / inputSize.height) { |
|||
sourceSize = new Size(inputSize.width, inputSize.width * outputSize.height / outputSize.width); |
|||
} |
|||
else { |
|||
sourceSize = new Size(inputSize.height * outputSize.width / outputSize.height, |
|||
inputSize.height); |
|||
} |
|||
|
|||
destinationSize = outputSize; |
|||
break; |
|||
case BoxFit.fitWidth: |
|||
sourceSize = new Size(inputSize.width, inputSize.width * outputSize.height / outputSize.width); |
|||
destinationSize = new Size(outputSize.width, |
|||
sourceSize.height * outputSize.width / sourceSize.width); |
|||
break; |
|||
case BoxFit.fitHeight: |
|||
sourceSize = new Size(inputSize.height * outputSize.width / outputSize.height, inputSize.height); |
|||
destinationSize = new Size(sourceSize.width * outputSize.height / sourceSize.height, |
|||
outputSize.height); |
|||
break; |
|||
case BoxFit.none: |
|||
sourceSize = new Size(Math.Min(inputSize.width, outputSize.width), |
|||
Math.Min(inputSize.height, outputSize.height)); |
|||
destinationSize = sourceSize; |
|||
break; |
|||
case BoxFit.scaleDown: |
|||
sourceSize = inputSize; |
|||
destinationSize = inputSize; |
|||
double aspectRatio = inputSize.width / inputSize.height; |
|||
if (destinationSize.height > outputSize.height) |
|||
destinationSize = new Size(outputSize.height * aspectRatio, outputSize.height); |
|||
if (destinationSize.width > outputSize.width) |
|||
destinationSize = new Size(outputSize.width, outputSize.width / aspectRatio); |
|||
break; |
|||
} |
|||
|
|||
return new FittedSizes(sourceSize, destinationSize); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 4d75ec15a75b4a7baca1968978b1eec9 |
|||
timeCreated: 1534820694 |
|
|||
using System.Collections.Generic; |
|||
using Object = System.Object; |
|||
|
|||
namespace UIWidgets.painting { |
|||
public class ImageCache { |
|||
private const int _kDefaultSize = 1000; |
|||
private const int _kDefaultSizeBytes = 20 << 20; // 20 MiB
|
|||
|
|||
public Dictionary<Object, ImageStreamCompleter> _pendingImages = |
|||
new Dictionary<Object, ImageStreamCompleter>(); |
|||
|
|||
public Dictionary<Object, _CachedImage> _cache = new Dictionary<Object, _CachedImage>(); |
|||
public LinkedList<Object> _lruKeys = new LinkedList<Object>(); |
|||
|
|||
private int _maximumSize = _kDefaultSize; |
|||
|
|||
public int maximumSize { |
|||
get { return _maximumSize; } |
|||
set { |
|||
if (value == maximumSize) { |
|||
return; |
|||
} |
|||
|
|||
_maximumSize = value; |
|||
if (maximumSize == 0) { |
|||
_cache.Clear(); |
|||
_lruKeys.Clear(); |
|||
_currentSizeBytes = 0; |
|||
} |
|||
else { |
|||
_checkCacheSize(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public int currentSize { |
|||
get { return _cache.Count; } |
|||
} |
|||
|
|||
private int _maximumSizeBytes = _kDefaultSizeBytes; |
|||
|
|||
public int maximumSizeBytes { |
|||
get { return _maximumSizeBytes; } |
|||
set { |
|||
if (value == _maximumSizeBytes) { |
|||
return; |
|||
} |
|||
|
|||
_maximumSizeBytes = value; |
|||
if (_maximumSizeBytes == 0) { |
|||
_cache.Clear(); |
|||
_lruKeys.Clear(); |
|||
_currentSizeBytes = 0; |
|||
} |
|||
else { |
|||
_checkCacheSize(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private int _currentSizeBytes; |
|||
|
|||
public int currentSizeBytes { |
|||
get { return _currentSizeBytes; } |
|||
} |
|||
|
|||
public void clear() { |
|||
_cache.Clear(); |
|||
_lruKeys.Clear(); |
|||
_currentSizeBytes = 0; |
|||
} |
|||
|
|||
public delegate ImageStreamCompleter Loader(); |
|||
|
|||
public ImageStreamCompleter putIfAbsent(Object key, Loader loader) { |
|||
ImageStreamCompleter result; |
|||
if (_pendingImages.TryGetValue(key, out result)) { |
|||
return result; |
|||
} |
|||
|
|||
_CachedImage image; |
|||
if (_cache.TryGetValue(key, out image)) { |
|||
// put to the MRU position
|
|||
_lruKeys.Remove(key); |
|||
_lruKeys.AddLast(key); |
|||
} |
|||
|
|||
if (image != null) { |
|||
return image.completer; |
|||
} |
|||
|
|||
result = loader(); |
|||
|
|||
if (maximumSize > 0 && maximumSizeBytes > 0) { |
|||
_pendingImages[key] = result; |
|||
result.addListener((info, syncCall) => { |
|||
// int imageSize = info.image == null ? 0 : info.image.height * info.image.width * 4;
|
|||
// now we use length or raw bytes array as image size
|
|||
int imageSize = info.image == null ? 0 : info.image.rawData.Length; |
|||
_CachedImage cachedImage = new _CachedImage(result, imageSize); |
|||
if (maximumSizeBytes > 0 && imageSize > maximumSizeBytes) { |
|||
_maximumSize = imageSize + 1000; |
|||
} |
|||
|
|||
_currentSizeBytes += imageSize; |
|||
_pendingImages.Remove(key); |
|||
_cache[key] = cachedImage; |
|||
_lruKeys.AddLast(key); |
|||
this._checkCacheSize(); |
|||
}, null); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void _checkCacheSize() { |
|||
while (_currentSizeBytes > _maximumSizeBytes || _cache.Count > _maximumSize) { |
|||
Object key = _lruKeys.First.Value; // get the LRU item
|
|||
_CachedImage image = _cache[key]; |
|||
bool removed = _cache.Remove(key); |
|||
if (image != null && removed) { |
|||
_currentSizeBytes -= image.sizeBytes; |
|||
_lruKeys.Remove(key); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class _CachedImage { |
|||
public _CachedImage(ImageStreamCompleter completer, int sizeBytes) { |
|||
this.completer = completer; |
|||
this.sizeBytes = sizeBytes; |
|||
} |
|||
|
|||
public ImageStreamCompleter completer; |
|||
public int sizeBytes; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 80732e4248ce48ec92e1463ddc59451d |
|||
timeCreated: 1534833891 |
|
|||
using System.Collections.Generic; |
|||
using RSG; |
|||
using System.Net; |
|||
using System; |
|||
using System.IO; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.painting { |
|||
public abstract class ImageProvider<T> { |
|||
public ImageStream resolve(ImageConfiguration configuration) { |
|||
ImageStream stream = new ImageStream(); |
|||
T obtainedKey; |
|||
obtainedKey = obtainKey(configuration); |
|||
stream.setCompleter(PaintingBinding.instance.imageCache.putIfAbsent(obtainedKey, () => load(obtainedKey))); |
|||
return stream; |
|||
} |
|||
|
|||
public abstract ImageStreamCompleter load(T key); |
|||
|
|||
public abstract T obtainKey(ImageConfiguration configuration); |
|||
} |
|||
|
|||
public class NetworkImage : ImageProvider<NetworkImage> { |
|||
public NetworkImage(string url, Dictionary<string, string> headers, double scale = 1.0) { |
|||
this.url = url; |
|||
this.headers = headers; |
|||
this.scale = scale; |
|||
} |
|||
|
|||
/// The URL from which the image will be fetched.
|
|||
string url; |
|||
|
|||
/// The scale to place in the [ImageInfo] object of the image.
|
|||
double scale; |
|||
|
|||
/// The HTTP headers that will be used with [HttpClient.get] to fetch image from network.
|
|||
Dictionary<string, string> headers; |
|||
|
|||
public override NetworkImage obtainKey(ImageConfiguration configuration) { |
|||
return this; |
|||
} |
|||
|
|||
public override ImageStreamCompleter load(NetworkImage key) { |
|||
return new OneFrameImageStreamCompleter(_loadAsync(key)); |
|||
} |
|||
|
|||
public static IPromise<ImageInfo> _loadAsync(NetworkImage key) { |
|||
var promise = new Promise<ImageInfo>(); // Create promise.
|
|||
using (var client = new WebClient()) { |
|||
client.DownloadDataCompleted += // Monitor event for download completed.
|
|||
(s, ev) => { |
|||
if (ev.Error != null) { |
|||
promise.Reject(ev.Error); // Error during download, reject the promise.
|
|||
} |
|||
else { |
|||
var bytes = ev.Result; |
|||
var imageInfo = new ImageInfo(new ui.Image( |
|||
bytes |
|||
)); |
|||
promise.Resolve(imageInfo); // Downloaded completed successfully, resolve the promise.
|
|||
} |
|||
}; |
|||
|
|||
client.DownloadDataAsync(new Uri(key.url)); // Initiate async op.
|
|||
} |
|||
|
|||
return promise; // Return the promise so the caller can await resolution (or error).
|
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "NetworkImage with Url: " + this.url; |
|||
} |
|||
|
|||
public bool Equals(NetworkImage other) { |
|||
return this.url.Equals(other.url) && this.scale.Equals(other.scale); |
|||
} |
|||
|
|||
public override bool Equals(object obj) { |
|||
if (object.ReferenceEquals(null, obj)) return false; |
|||
if (object.ReferenceEquals(this, obj)) return true; |
|||
return obj is NetworkImage && this.Equals((NetworkImage) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
unchecked { |
|||
var hashCode = this.url.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.scale.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class ImageConfiguration { |
|||
public ImageConfiguration(Size size = null) { |
|||
this.size = size; |
|||
} |
|||
|
|||
public static readonly ImageConfiguration empty = new ImageConfiguration(); |
|||
|
|||
public ImageConfiguration copyWith(Size size = null) { |
|||
return new ImageConfiguration( |
|||
size: size ?? this.size |
|||
); |
|||
} |
|||
|
|||
public readonly Size size; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 858587f8fb5d435e8a07a0ff46e5bc95 |
|||
timeCreated: 1534820746 |
|
|||
using RSG; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
|
|||
namespace UIWidgets.painting { |
|||
public delegate void ImageListener(ImageInfo image, bool synchronousCall); |
|||
|
|||
public delegate void ImageErrorListerner(System.Object exception, string stackTrack); |
|||
|
|||
public class ImageInfo { |
|||
public ImageInfo(Image image, double scale = 1.0) { |
|||
this.image = image; |
|||
this.scale = scale; |
|||
} |
|||
|
|||
public Image image; |
|||
public double scale; |
|||
} |
|||
|
|||
public class ImageStream { |
|||
public ImageStream() { |
|||
} |
|||
|
|||
private ImageStreamCompleter _completer; |
|||
private List<_ImageListenerPair> _listeners; |
|||
|
|||
public ImageStreamCompleter completer { |
|||
get { return _completer; } |
|||
} |
|||
|
|||
public void setCompleter(ImageStreamCompleter value) { |
|||
_completer = value; |
|||
if (_listeners != null) { |
|||
List<_ImageListenerPair> initialListeners = _listeners; |
|||
_listeners = null; |
|||
foreach (_ImageListenerPair listenerPair in initialListeners) { |
|||
_completer.addListener( |
|||
listenerPair.listener, |
|||
listenerPair.errorListener |
|||
); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public abstract class ImageStreamCompleter { |
|||
public List<_ImageListenerPair> _listeners = new List<_ImageListenerPair>(); |
|||
public ImageInfo _currentImgae; |
|||
|
|||
public void addListener(ImageListener listener, ImageErrorListerner onError) { |
|||
this._listeners.Add(new _ImageListenerPair(listener, onError)); |
|||
if (_currentImgae != null) { |
|||
try { |
|||
listener(_currentImgae, true); |
|||
this.removeListener(listener); |
|||
} |
|||
catch (Exception e) { |
|||
Console.WriteLine("{0} Exception caught.", e); |
|||
} |
|||
} |
|||
|
|||
// todo call onError
|
|||
} |
|||
|
|||
public void removeListener(ImageListener listener) { |
|||
var pairToRemove = this._listeners.Single(lp => lp.listener == listener); |
|||
this._listeners.Remove(pairToRemove); |
|||
} |
|||
|
|||
public void setImage(ImageInfo image) { |
|||
_currentImgae = image; |
|||
if (_listeners.Count == 0) { |
|||
return; |
|||
} |
|||
|
|||
foreach (var lp in _listeners.ToList()) { |
|||
// todo refine
|
|||
var listener = lp.listener; |
|||
try { |
|||
listener(image, false); |
|||
this.removeListener(listener); |
|||
} |
|||
catch (Exception e) { |
|||
Console.WriteLine("{0} Exception caught.", e); |
|||
} |
|||
|
|||
// todo call onError
|
|||
} |
|||
} |
|||
} |
|||
|
|||
public class OneFrameImageStreamCompleter : ImageStreamCompleter { |
|||
public OneFrameImageStreamCompleter(IPromise<ImageInfo> image) { |
|||
image.Then(result => { setImage(result); }).Catch(err => { Debug.Log(err); }); |
|||
} |
|||
} |
|||
|
|||
public class _ImageListenerPair { |
|||
public _ImageListenerPair(ImageListener listener, ImageErrorListerner errorListener) { |
|||
this.listener = listener; |
|||
this.errorListener = errorListener; |
|||
} |
|||
|
|||
public ImageListener listener; |
|||
public ImageErrorListerner errorListener; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 462d84cff25d484895d1a81e7ebd2a24 |
|||
timeCreated: 1534820764 |
|
|||
fileFormatVersion: 2 |
|||
guid: e2adb93c961cc4d4e8d94fce276c0b57 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UIWidgets.ui; |
|||
using UIWidgets.painting; |
|||
using UnityEngine.Rendering; |
|||
using BlendMode = UIWidgets.ui.BlendMode; |
|||
|
|||
namespace UIWidgets.rendering { |
|||
class RenderImage : RenderBox { |
|||
public RenderImage(ui.Image image, |
|||
double width, |
|||
double height, |
|||
Color color, |
|||
ui.BlendMode colorBlendMode, |
|||
BoxFit fit, |
|||
ImageRepeat repeat, |
|||
Rect centerSlice, |
|||
Alignment alignment = null, |
|||
double scale = 1.0 |
|||
) { |
|||
this._image = image; |
|||
this._width = width; |
|||
this._height = height; |
|||
this._scale = scale; |
|||
this._color = color; |
|||
this._colorBlendMode = colorBlendMode; |
|||
this._fit = fit; |
|||
this._repeat = repeat; |
|||
this._centerSlice = centerSlice; |
|||
this._alignment = alignment ?? Alignment.center; |
|||
} |
|||
|
|||
Alignment _resolvedAlignment; |
|||
|
|||
void _resolve() { |
|||
if (_resolvedAlignment != null) |
|||
return; |
|||
_resolvedAlignment = alignment; |
|||
} |
|||
|
|||
void _markNeedsResolution() { |
|||
_resolvedAlignment = null; |
|||
markNeedsPaint(); |
|||
} |
|||
|
|||
private ui.Image _image; |
|||
|
|||
public ui.Image image { |
|||
get { return this._image; } |
|||
set { |
|||
if (value == _image) |
|||
return; |
|||
_image = value; |
|||
markNeedsPaint(); |
|||
if (_width == 0.0 || _height == 0.0) |
|||
markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
private double _width; |
|||
|
|||
public double width { |
|||
get { return _width; } |
|||
set { |
|||
if (value == _width) |
|||
return; |
|||
_width = value; |
|||
markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
private double _height; |
|||
|
|||
public double height { |
|||
get { return _height; } |
|||
set { |
|||
if (value == _height) |
|||
return; |
|||
_height = value; |
|||
markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
private double _scale; |
|||
|
|||
public double scale { |
|||
get { return _scale; } |
|||
set { |
|||
if (value == _scale) |
|||
return; |
|||
_scale = value; |
|||
markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
private Color _color; |
|||
|
|||
public Color color { |
|||
get { return _color; } |
|||
set { |
|||
if (value == _color) |
|||
return; |
|||
_color = value; |
|||
markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
private ui.BlendMode _colorBlendMode; |
|||
|
|||
public ui.BlendMode colorBlendMode { |
|||
get { return _colorBlendMode; } |
|||
set { |
|||
if (value == _colorBlendMode) |
|||
return; |
|||
_colorBlendMode = value; |
|||
markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
private BoxFit _fit; |
|||
|
|||
public BoxFit fit { |
|||
get { return _fit; } |
|||
set { |
|||
if (value == _fit) |
|||
return; |
|||
_fit = value; |
|||
markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
private Alignment _alignment; |
|||
|
|||
public Alignment alignment { |
|||
get { return _alignment; } |
|||
set { |
|||
if (value == _alignment) |
|||
return; |
|||
_alignment = value; |
|||
_markNeedsResolution(); |
|||
} |
|||
} |
|||
|
|||
private ImageRepeat _repeat; |
|||
|
|||
public ImageRepeat repeat { |
|||
get { return _repeat; } |
|||
set { |
|||
if (value == _repeat) |
|||
return; |
|||
_repeat = value; |
|||
markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
private Rect _centerSlice; |
|||
|
|||
public Rect centerSlice { |
|||
get { return _centerSlice; } |
|||
set { |
|||
if (value == _centerSlice) |
|||
return; |
|||
_centerSlice = value; |
|||
markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
Size _sizeForConstraints(BoxConstraints constraints) { |
|||
// Folds the given |width| and |height| into |constraints| so they can all
|
|||
// be treated uniformly.
|
|||
constraints = BoxConstraints.tightFor( |
|||
_width, |
|||
_height |
|||
); |
|||
constraints = constraints.enforce(constraints); |
|||
|
|||
if (_image == null) |
|||
return constraints.smallest; |
|||
|
|||
return constraints.constrainSizeAndAttemptToPreserveAspectRatio(new Size( |
|||
_image.width / _scale, |
|||
_image.height / _scale |
|||
)); |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
if (_image == null) |
|||
return; |
|||
_resolve(); |
|||
DecorationImageUtil.paintImage( |
|||
context.canvas, |
|||
offset & size, |
|||
_image, |
|||
_fit, |
|||
_centerSlice, |
|||
_resolvedAlignment, |
|||
_repeat |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: d0413272d07e4c958f45f9c7597fe2b7 |
|||
timeCreated: 1534820838 |
|
|||
using System; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.rendering { |
|||
public abstract class RenderSliverFixedExtentBoxAdaptor : RenderSliverMultiBoxAdaptor { |
|||
RenderSliverFixedExtentBoxAdaptor( |
|||
RenderSliverBoxChildManager childManager = null |
|||
) : base(childManager: childManager) { |
|||
} |
|||
|
|||
public abstract double itemExtent { get; } |
|||
|
|||
public double indexToLayoutOffset(double itemExtent, int index) { |
|||
return itemExtent * index; |
|||
} |
|||
|
|||
public int getMinChildIndexForScrollOffset(double scrollOffset, double itemExtent) { |
|||
return itemExtent > 0.0 ? Math.Max(0, (int) (scrollOffset / itemExtent)) : 0; |
|||
} |
|||
|
|||
public int getMaxChildIndexForScrollOffset(double scrollOffset, double itemExtent) { |
|||
return itemExtent > 0.0 ? Math.Max(0, (int) Math.Ceiling(scrollOffset / itemExtent) - 1) : 0; |
|||
} |
|||
|
|||
public double estimateMaxScrollOffset(SliverConstraints constraints, |
|||
int firstIndex = 0, |
|||
int lastIndex = 0, |
|||
double leadingScrollOffset = 0.0, |
|||
double trailingScrollOffset = 0.0 |
|||
) { |
|||
return this.childManager.estimateMaxScrollOffset( |
|||
constraints, |
|||
firstIndex: firstIndex, |
|||
lastIndex: lastIndex, |
|||
leadingScrollOffset: leadingScrollOffset, |
|||
trailingScrollOffset: trailingScrollOffset |
|||
); |
|||
} |
|||
|
|||
public double computeMaxScrollOffset(SliverConstraints constraints, double itemExtent) { |
|||
return this.childManager.childCount * itemExtent; |
|||
} |
|||
|
|||
|
|||
public override void performLayout() { |
|||
this.childManager.didStartLayout(); |
|||
this.childManager.setDidUnderflow(false); |
|||
|
|||
double itemExtent = this.itemExtent; |
|||
|
|||
double scrollOffset = this.constraints.scrollOffset + this.constraints.cacheOrigin; |
|||
double remainingExtent = this.constraints.remainingCacheExtent; |
|||
double targetEndScrollOffset = scrollOffset + remainingExtent; |
|||
|
|||
BoxConstraints childConstraints = this.constraints.asBoxConstraints( |
|||
minExtent: itemExtent, |
|||
maxExtent: itemExtent |
|||
); |
|||
|
|||
int firstIndex = this.getMinChildIndexForScrollOffset(scrollOffset, itemExtent); |
|||
int? targetLastIndex = !double.IsInfinity(targetEndScrollOffset) |
|||
? this.getMaxChildIndexForScrollOffset(targetEndScrollOffset, itemExtent) |
|||
: (int?) null; |
|||
|
|||
if (this.firstChild != null) { |
|||
int oldFirstIndex = this.indexOf(this.firstChild); |
|||
int oldLastIndex = this.indexOf(this.lastChild); |
|||
int leadingGarbage = (firstIndex - oldFirstIndex).clamp(0, this.childCount); |
|||
int trailingGarbage = |
|||
targetLastIndex == null ? 0 : (oldLastIndex - targetLastIndex.Value).clamp(0, this.childCount); |
|||
this.collectGarbage(leadingGarbage, trailingGarbage); |
|||
} else { |
|||
this.collectGarbage(0, 0); |
|||
} |
|||
|
|||
if (this.firstChild == null) { |
|||
if (!this.addInitialChild(index: firstIndex, |
|||
layoutOffset: this.indexToLayoutOffset(itemExtent, firstIndex))) { |
|||
double max = this.computeMaxScrollOffset(this.constraints, itemExtent); |
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: max, |
|||
maxPaintExtent: max |
|||
); |
|||
this.childManager.didFinishLayout(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
RenderBox trailingChildWithLayout = null; |
|||
|
|||
for (int index = this.indexOf(this.firstChild) - 1; index >= firstIndex; --index) { |
|||
RenderBox child = this.insertAndLayoutLeadingChild(childConstraints); |
|||
if (child == null) { |
|||
this.geometry = new SliverGeometry(scrollOffsetCorrection: index * itemExtent); |
|||
return; |
|||
} |
|||
|
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
childParentData.layoutOffset = this.indexToLayoutOffset(itemExtent, index); |
|||
trailingChildWithLayout = trailingChildWithLayout ?? child; |
|||
} |
|||
|
|||
if (trailingChildWithLayout == null) { |
|||
this.firstChild.layout(childConstraints); |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) this.firstChild.parentData; |
|||
childParentData.layoutOffset = this.indexToLayoutOffset(itemExtent, firstIndex); |
|||
trailingChildWithLayout = this.firstChild; |
|||
} |
|||
|
|||
while (targetLastIndex == null || this.indexOf(trailingChildWithLayout) < targetLastIndex) { |
|||
RenderBox child = this.childAfter(trailingChildWithLayout); |
|||
if (child == null) { |
|||
child = this.insertAndLayoutChild(childConstraints, after: trailingChildWithLayout); |
|||
if (child == null) { |
|||
break; |
|||
} |
|||
} else { |
|||
child.layout(childConstraints); |
|||
} |
|||
|
|||
trailingChildWithLayout = child; |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
childParentData.layoutOffset = this.indexToLayoutOffset(itemExtent, childParentData.index); |
|||
} |
|||
|
|||
int lastIndex = this.indexOf(this.lastChild); |
|||
double leadingScrollOffset = this.indexToLayoutOffset(itemExtent, firstIndex); |
|||
double trailingScrollOffset = this.indexToLayoutOffset(itemExtent, lastIndex + 1); |
|||
|
|||
double estimatedMaxScrollOffset = this.estimateMaxScrollOffset( |
|||
this.constraints, |
|||
firstIndex: firstIndex, |
|||
lastIndex: lastIndex, |
|||
leadingScrollOffset: leadingScrollOffset, |
|||
trailingScrollOffset: trailingScrollOffset |
|||
); |
|||
|
|||
double paintExtent = this.calculatePaintOffset( |
|||
this.constraints, |
|||
from: leadingScrollOffset, |
|||
to: trailingScrollOffset |
|||
); |
|||
|
|||
double cacheExtent = this.calculateCacheOffset( |
|||
this.constraints, |
|||
from: leadingScrollOffset, |
|||
to: trailingScrollOffset |
|||
); |
|||
|
|||
double targetEndScrollOffsetForPaint = |
|||
this.constraints.scrollOffset + this.constraints.remainingPaintExtent; |
|||
int? targetLastIndexForPaint = !double.IsInfinity(targetEndScrollOffsetForPaint) |
|||
? this.getMaxChildIndexForScrollOffset(targetEndScrollOffsetForPaint, itemExtent) |
|||
: (int?) null; |
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: estimatedMaxScrollOffset, |
|||
paintExtent: paintExtent, |
|||
cacheExtent: cacheExtent, |
|||
maxPaintExtent: estimatedMaxScrollOffset, |
|||
hasVisualOverflow: (targetLastIndexForPaint != null && lastIndex >= targetLastIndexForPaint) |
|||
|| this.constraints.scrollOffset > 0.0 |
|||
); |
|||
if (estimatedMaxScrollOffset == trailingScrollOffset) { |
|||
this.childManager.setDidUnderflow(true); |
|||
} |
|||
|
|||
this.childManager.didFinishLayout(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e602742e1e9c408989efd79055a9e552 |
|||
timeCreated: 1535524936 |
|
|||
using System; |
|||
|
|||
namespace UIWidgets.rendering { |
|||
public class RenderSliverList : RenderSliverMultiBoxAdaptor { |
|||
RenderSliverList( |
|||
RenderSliverBoxChildManager childManager = null |
|||
) : base(childManager: childManager) { |
|||
} |
|||
|
|||
public override void performLayout() { |
|||
this.childManager.didStartLayout(); |
|||
this.childManager.setDidUnderflow(false); |
|||
|
|||
double scrollOffset = this.constraints.scrollOffset + this.constraints.cacheOrigin; |
|||
double remainingExtent = this.constraints.remainingCacheExtent; |
|||
double targetEndScrollOffset = scrollOffset + remainingExtent; |
|||
BoxConstraints childConstraints = this.constraints.asBoxConstraints(); |
|||
int leadingGarbage = 0; |
|||
int trailingGarbage = 0; |
|||
bool reachedEnd = false; |
|||
|
|||
if (this.firstChild == null) { |
|||
if (!this.addInitialChild()) { |
|||
this.geometry = SliverGeometry.zero; |
|||
this.childManager.didFinishLayout(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
RenderBox leadingChildWithLayout = null, trailingChildWithLayout = null; |
|||
|
|||
RenderBox earliestUsefulChild = this.firstChild; |
|||
for (double earliestScrollOffset = this.childScrollOffset(earliestUsefulChild); |
|||
earliestScrollOffset > scrollOffset; |
|||
earliestScrollOffset = this.childScrollOffset(earliestUsefulChild)) { |
|||
earliestUsefulChild = this.insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true); |
|||
|
|||
if (earliestUsefulChild == null) { |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) this.firstChild.parentData; |
|||
childParentData.layoutOffset = 0.0; |
|||
|
|||
if (scrollOffset == 0.0) { |
|||
earliestUsefulChild = this.firstChild; |
|||
leadingChildWithLayout = earliestUsefulChild; |
|||
trailingChildWithLayout = trailingChildWithLayout ?? earliestUsefulChild; |
|||
break; |
|||
} else { |
|||
this.geometry = new SliverGeometry( |
|||
scrollOffsetCorrection: -scrollOffset |
|||
); |
|||
return; |
|||
} |
|||
} else { |
|||
double firstChildScrollOffset = earliestScrollOffset - this.paintExtentOf(this.firstChild); |
|||
if (firstChildScrollOffset < 0.0) { |
|||
double correction = 0.0; |
|||
while (earliestUsefulChild != null) { |
|||
correction += this.paintExtentOf(firstChild); |
|||
earliestUsefulChild = |
|||
this.insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true); |
|||
} |
|||
|
|||
this.geometry = new SliverGeometry( |
|||
scrollOffsetCorrection: correction - earliestScrollOffset |
|||
); |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) this.firstChild.parentData; |
|||
childParentData.layoutOffset = 0.0; |
|||
return; |
|||
} else { |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) earliestUsefulChild.parentData; |
|||
childParentData.layoutOffset = firstChildScrollOffset; |
|||
leadingChildWithLayout = earliestUsefulChild; |
|||
trailingChildWithLayout = trailingChildWithLayout ?? earliestUsefulChild; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (leadingChildWithLayout == null) { |
|||
earliestUsefulChild.layout(childConstraints, parentUsesSize: true); |
|||
leadingChildWithLayout = earliestUsefulChild; |
|||
trailingChildWithLayout = earliestUsefulChild; |
|||
} |
|||
|
|||
bool inLayoutRange = true; |
|||
RenderBox child = earliestUsefulChild; |
|||
int index = this.indexOf(child); |
|||
double endScrollOffset = this.childScrollOffset(child) + this.paintExtentOf(child); |
|||
|
|||
Func<bool> advance = () => { |
|||
if (child == trailingChildWithLayout) { |
|||
inLayoutRange = false; |
|||
} |
|||
|
|||
child = this.childAfter(child); |
|||
if (child == null) { |
|||
inLayoutRange = false; |
|||
} |
|||
|
|||
index += 1; |
|||
if (!inLayoutRange) { |
|||
if (child == null || this.indexOf(child) != index) { |
|||
child = insertAndLayoutChild(childConstraints, |
|||
after: trailingChildWithLayout, |
|||
parentUsesSize: true |
|||
); |
|||
if (child == null) { |
|||
return false; |
|||
} |
|||
} else { |
|||
child.layout(childConstraints, parentUsesSize: true); |
|||
} |
|||
|
|||
trailingChildWithLayout = child; |
|||
} |
|||
|
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
childParentData.layoutOffset = endScrollOffset; |
|||
endScrollOffset = this.childScrollOffset(child) + this.paintExtentOf(child); |
|||
return true; |
|||
}; |
|||
|
|||
while (endScrollOffset < scrollOffset) { |
|||
leadingGarbage += 1; |
|||
if (!advance()) { |
|||
this.collectGarbage(leadingGarbage - 1, 0); |
|||
double extent = this.childScrollOffset(this.lastChild) + this.paintExtentOf(this.lastChild); |
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: extent, |
|||
paintExtent: 0.0, |
|||
maxPaintExtent: extent |
|||
); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
while (endScrollOffset < targetEndScrollOffset) { |
|||
if (!advance()) { |
|||
reachedEnd = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (child != null) { |
|||
child = this.childAfter(child); |
|||
while (child != null) { |
|||
trailingGarbage += 1; |
|||
child = this.childAfter(child); |
|||
} |
|||
} |
|||
|
|||
this.collectGarbage(leadingGarbage, trailingGarbage); |
|||
|
|||
double estimatedMaxScrollOffset; |
|||
if (reachedEnd) { |
|||
estimatedMaxScrollOffset = endScrollOffset; |
|||
} else { |
|||
estimatedMaxScrollOffset = this.childManager.estimateMaxScrollOffset( |
|||
this.constraints, |
|||
firstIndex: this.indexOf(this.firstChild), |
|||
lastIndex: this.indexOf(this.lastChild), |
|||
leadingScrollOffset: this.childScrollOffset(this.firstChild), |
|||
trailingScrollOffset: endScrollOffset |
|||
); |
|||
} |
|||
|
|||
double paintExtent = this.calculatePaintOffset( |
|||
this.constraints, |
|||
from: this.childScrollOffset(this.firstChild), |
|||
to: endScrollOffset |
|||
); |
|||
double cacheExtent = this.calculateCacheOffset( |
|||
this.constraints, |
|||
from: this.childScrollOffset(this.firstChild), |
|||
to: endScrollOffset |
|||
); |
|||
double targetEndScrollOffsetForPaint = |
|||
this.constraints.scrollOffset + this.constraints.remainingPaintExtent; |
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: estimatedMaxScrollOffset, |
|||
paintExtent: paintExtent, |
|||
cacheExtent: cacheExtent, |
|||
maxPaintExtent: estimatedMaxScrollOffset, |
|||
hasVisualOverflow: endScrollOffset > targetEndScrollOffsetForPaint || |
|||
this.constraints.scrollOffset > 0.0 |
|||
); |
|||
|
|||
if (estimatedMaxScrollOffset == endScrollOffset) { |
|||
this.childManager.setDidUnderflow(true); |
|||
} |
|||
|
|||
this.childManager.didFinishLayout(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 1db4d92862744fcdb527f4020106fdf8 |
|||
timeCreated: 1535522746 |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.rendering { |
|||
public interface RenderSliverBoxChildManager { |
|||
void createChild(int index, RenderBox after = null); |
|||
|
|||
void removeChild(RenderBox child); |
|||
|
|||
double estimateMaxScrollOffset( |
|||
SliverConstraints constraints, |
|||
int firstIndex = 0, |
|||
int lastIndex = 0, |
|||
double leadingScrollOffset = 0, |
|||
double trailingScrollOffset = 0); |
|||
|
|||
int childCount { get; } |
|||
|
|||
void didAdoptChild(RenderBox child); |
|||
|
|||
void setDidUnderflow(bool value); |
|||
|
|||
void didStartLayout(); |
|||
|
|||
void didFinishLayout(); |
|||
} |
|||
|
|||
public class SliverMultiBoxAdaptorParentData : ContainerParentDataMixinSliverLogicalParentData<RenderBox> { |
|||
public int index; |
|||
|
|||
public bool keepAlive = false; |
|||
|
|||
public bool _keptAlive = false; |
|||
} |
|||
|
|||
public abstract class RenderSliverMultiBoxAdaptor |
|||
: ContainerRenderObjectMixinRenderSliver<RenderBox, SliverMultiBoxAdaptorParentData> { |
|||
public RenderSliverMultiBoxAdaptor( |
|||
RenderSliverBoxChildManager childManager = null |
|||
) { |
|||
this._childManager = childManager; |
|||
} |
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is SliverMultiBoxAdaptorParentData)) { |
|||
child.parentData = new SliverMultiBoxAdaptorParentData(); |
|||
} |
|||
} |
|||
|
|||
public RenderSliverBoxChildManager childManager { |
|||
get { return this._childManager; } |
|||
} |
|||
|
|||
public RenderSliverBoxChildManager _childManager; |
|||
|
|||
public readonly Dictionary<int, RenderBox> _keepAliveBucket = new Dictionary<int, RenderBox>(); |
|||
|
|||
public override void adoptChild(AbstractNode childNode) { |
|||
base.adoptChild(childNode); |
|||
var child = (RenderBox) childNode; |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
if (!childParentData._keptAlive) { |
|||
this.childManager.didAdoptChild(child); |
|||
} |
|||
} |
|||
|
|||
public override void insert(RenderBox child, RenderBox after = null) { |
|||
base.insert(child, after: after); |
|||
} |
|||
|
|||
public override void remove(RenderBox child) { |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
if (!childParentData._keptAlive) { |
|||
base.remove(child); |
|||
return; |
|||
} |
|||
|
|||
this._keepAliveBucket.Remove(childParentData.index); |
|||
this.dropChild(child); |
|||
} |
|||
|
|||
public override void removeAll() { |
|||
base.removeAll(); |
|||
|
|||
foreach (var child in this._keepAliveBucket.Values) { |
|||
this.dropChild(child); |
|||
} |
|||
|
|||
this._keepAliveBucket.Clear(); |
|||
} |
|||
|
|||
void _createOrObtainChild(int index, RenderBox after = null) { |
|||
this.invokeLayoutCallback<SliverConstraints>((SliverConstraints constraints) => { |
|||
if (this._keepAliveBucket.ContainsKey(index)) { |
|||
RenderBox child = this._keepAliveBucket[index]; |
|||
this._keepAliveBucket.Remove(index); |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
this.dropChild(child); |
|||
child.parentData = childParentData; |
|||
this.insert(child, after: after); |
|||
childParentData._keptAlive = false; |
|||
} else { |
|||
this._childManager.createChild(index, after: after); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public void _destroyOrCacheChild(RenderBox child) { |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
if (childParentData.keepAlive) { |
|||
this.remove(child); |
|||
this._keepAliveBucket[childParentData.index] = child; |
|||
child.parentData = childParentData; |
|||
base.adoptChild(child); |
|||
childParentData._keptAlive = true; |
|||
} else { |
|||
this._childManager.removeChild(child); |
|||
} |
|||
} |
|||
|
|||
public override void attach(object owner) { |
|||
base.attach(owner); |
|||
foreach (RenderBox child in this._keepAliveBucket.Values) { |
|||
child.attach(owner); |
|||
} |
|||
} |
|||
|
|||
public override void detach() { |
|||
base.detach(); |
|||
foreach (RenderBox child in this._keepAliveBucket.Values) { |
|||
child.detach(); |
|||
} |
|||
} |
|||
|
|||
public override void redepthChildren() { |
|||
base.redepthChildren(); |
|||
foreach (var child in this._keepAliveBucket.Values) { |
|||
this.redepthChild(child); |
|||
} |
|||
} |
|||
|
|||
public override void visitChildren(RenderObjectVisitor visitor) { |
|||
base.visitChildren(visitor); |
|||
|
|||
foreach (var child in this._keepAliveBucket.Values) { |
|||
visitor(child); |
|||
} |
|||
} |
|||
|
|||
public bool addInitialChild(int index = 0, double layoutOffset = 0.0) { |
|||
this._createOrObtainChild(index, after: null); |
|||
if (this.firstChild != null) { |
|||
var firstChildParentData = (SliverMultiBoxAdaptorParentData) this.firstChild.parentData; |
|||
firstChildParentData.layoutOffset = layoutOffset; |
|||
return true; |
|||
} |
|||
|
|||
this.childManager.setDidUnderflow(true); |
|||
return false; |
|||
} |
|||
|
|||
public RenderBox insertAndLayoutLeadingChild(BoxConstraints childConstraints, bool parentUsesSize = false) { |
|||
int index = this.indexOf(this.firstChild) - 1; |
|||
this._createOrObtainChild(index, after: null); |
|||
if (this.indexOf(this.firstChild) == index) { |
|||
this.firstChild.layout(childConstraints, parentUsesSize: parentUsesSize); |
|||
return this.firstChild; |
|||
} |
|||
|
|||
this.childManager.setDidUnderflow(true); |
|||
return null; |
|||
} |
|||
|
|||
public RenderBox insertAndLayoutChild( |
|||
BoxConstraints childConstraints, |
|||
RenderBox after = null, |
|||
bool parentUsesSize = false |
|||
) { |
|||
int index = this.indexOf(after) + 1; |
|||
this._createOrObtainChild(index, after: after); |
|||
RenderBox child = this.childAfter(after); |
|||
if (child != null && this.indexOf(child) == index) { |
|||
child.layout(childConstraints, parentUsesSize: parentUsesSize); |
|||
return child; |
|||
} |
|||
|
|||
this.childManager.setDidUnderflow(true); |
|||
return null; |
|||
} |
|||
|
|||
public void collectGarbage(int leadingGarbage, int trailingGarbage) { |
|||
this.invokeLayoutCallback<SliverConstraints>((SliverConstraints constraints) => { |
|||
while (leadingGarbage > 0) { |
|||
this._destroyOrCacheChild(this.firstChild); |
|||
leadingGarbage -= 1; |
|||
} |
|||
|
|||
while (trailingGarbage > 0) { |
|||
this._destroyOrCacheChild(this.lastChild); |
|||
trailingGarbage -= 1; |
|||
} |
|||
|
|||
this._keepAliveBucket.Values.Where((RenderBox child) => { |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
return !childParentData.keepAlive; |
|||
}).ToList().ForEach(this._childManager.removeChild); |
|||
}); |
|||
} |
|||
|
|||
public int indexOf(RenderBox child) { |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
return childParentData.index; |
|||
} |
|||
|
|||
public double paintExtentOf(RenderBox child) { |
|||
switch (this.constraints.axis) { |
|||
case Axis.horizontal: |
|||
return child.size.width; |
|||
case Axis.vertical: |
|||
return child.size.height; |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
public override double childMainAxisPosition(RenderObject child) { |
|||
return this.childScrollOffset(child) - this.constraints.scrollOffset; |
|||
} |
|||
|
|||
public override double childScrollOffset(RenderObject child) { |
|||
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData; |
|||
return childParentData.layoutOffset; |
|||
} |
|||
|
|||
public override void applyPaintTransform(RenderObject child, ref Matrix4x4 transform) { |
|||
this.applyPaintTransformForBoxChild((RenderBox) child, ref transform); |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
if (this.firstChild == null) { |
|||
return; |
|||
} |
|||
|
|||
Offset mainAxisUnit = null, crossAxisUnit = null, originOffset = null; |
|||
bool addExtent = false; |
|||
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(this.constraints.axisDirection, |
|||
this.constraints.growthDirection)) { |
|||
case AxisDirection.up: |
|||
mainAxisUnit = new Offset(0.0, -1.0); |
|||
crossAxisUnit = new Offset(1.0, 0.0); |
|||
originOffset = offset + new Offset(0.0, this.geometry.paintExtent); |
|||
addExtent = true; |
|||
break; |
|||
case AxisDirection.right: |
|||
mainAxisUnit = new Offset(1.0, 0.0); |
|||
crossAxisUnit = new Offset(0.0, 1.0); |
|||
originOffset = offset; |
|||
addExtent = false; |
|||
break; |
|||
case AxisDirection.down: |
|||
mainAxisUnit = new Offset(0.0, 1.0); |
|||
crossAxisUnit = new Offset(1.0, 0.0); |
|||
originOffset = offset; |
|||
addExtent = false; |
|||
break; |
|||
case AxisDirection.left: |
|||
mainAxisUnit = new Offset(-1.0, 0.0); |
|||
crossAxisUnit = new Offset(0.0, 1.0); |
|||
originOffset = offset + new Offset(this.geometry.paintExtent, 0.0); |
|||
addExtent = true; |
|||
break; |
|||
} |
|||
|
|||
RenderBox child = this.firstChild; |
|||
while (child != null) { |
|||
double mainAxisDelta = this.childMainAxisPosition(child); |
|||
double crossAxisDelta = this.childCrossAxisPosition(child); |
|||
Offset childOffset = new Offset( |
|||
originOffset.dx + mainAxisUnit.dx * mainAxisDelta + crossAxisUnit.dx * crossAxisDelta, |
|||
originOffset.dy + mainAxisUnit.dy * mainAxisDelta + crossAxisUnit.dy * crossAxisDelta |
|||
); |
|||
if (addExtent) { |
|||
childOffset += mainAxisUnit * this.paintExtentOf(child); |
|||
} |
|||
|
|||
if (mainAxisDelta < this.constraints.remainingPaintExtent && |
|||
mainAxisDelta + this.paintExtentOf(child) > 0) { |
|||
context.paintChild(child, childOffset); |
|||
} |
|||
|
|||
child = this.childAfter(child); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 00853d7738fe40eeb3e7b44db23248be |
|||
timeCreated: 1535502825 |
|
|||
using System; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.rendering { |
|||
public class RenderSliverPadding : RenderObjectWithChildMixinRenderSliver<RenderSliver> { |
|||
RenderSliverPadding( |
|||
EdgeInsets padding, |
|||
RenderSliver child |
|||
) { |
|||
this._padding = padding; |
|||
this.child = child; |
|||
} |
|||
|
|||
public EdgeInsets padding { |
|||
get { return this._padding; } |
|||
set { |
|||
if (this._padding == value) { |
|||
return; |
|||
} |
|||
|
|||
this._padding = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
public EdgeInsets _padding; |
|||
|
|||
public double beforePadding { |
|||
get { |
|||
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection( |
|||
this.constraints.axisDirection, this.constraints.growthDirection)) { |
|||
case AxisDirection.up: |
|||
return this._padding.bottom; |
|||
case AxisDirection.right: |
|||
return this._padding.left; |
|||
case AxisDirection.down: |
|||
return this._padding.top; |
|||
case AxisDirection.left: |
|||
return this._padding.right; |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
} |
|||
|
|||
public double afterPadding { |
|||
get { |
|||
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection( |
|||
this.constraints.axisDirection, this.constraints.growthDirection)) { |
|||
case AxisDirection.up: |
|||
return this._padding.top; |
|||
case AxisDirection.right: |
|||
return this._padding.right; |
|||
case AxisDirection.down: |
|||
return this._padding.bottom; |
|||
case AxisDirection.left: |
|||
return this._padding.left; |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
} |
|||
|
|||
public double mainAxisPadding { |
|||
get { return this._padding.along(this.constraints.axis); } |
|||
} |
|||
|
|||
public double crossAxisPadding { |
|||
get { |
|||
switch (this.constraints.axis) { |
|||
case Axis.horizontal: |
|||
return this._padding.vertical; |
|||
case Axis.vertical: |
|||
return this._padding.horizontal; |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
} |
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is SliverPhysicalParentData)) { |
|||
child.parentData = new SliverPhysicalParentData(); |
|||
} |
|||
} |
|||
|
|||
public override void performLayout() { |
|||
double beforePadding = this.beforePadding; |
|||
double afterPadding = this.afterPadding; |
|||
double mainAxisPadding = this.mainAxisPadding; |
|||
double crossAxisPadding = this.crossAxisPadding; |
|||
if (this.child == null) { |
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: mainAxisPadding, |
|||
paintExtent: Math.Min(mainAxisPadding, this.constraints.remainingPaintExtent), |
|||
maxPaintExtent: mainAxisPadding |
|||
); |
|||
return; |
|||
} |
|||
|
|||
this.child.layout( |
|||
this.constraints.copyWith( |
|||
scrollOffset: Math.Max(0.0, this.constraints.scrollOffset - beforePadding), |
|||
cacheOrigin: Math.Min(0.0, this.constraints.cacheOrigin + beforePadding), |
|||
overlap: 0.0, |
|||
remainingPaintExtent: this.constraints.remainingPaintExtent - |
|||
this.calculatePaintOffset(this.constraints, from: 0.0, to: beforePadding), |
|||
remainingCacheExtent: this.constraints.remainingCacheExtent - |
|||
this.calculateCacheOffset(this.constraints, from: 0.0, to: beforePadding), |
|||
crossAxisExtent: Math.Max(0.0, this.constraints.crossAxisExtent - crossAxisPadding) |
|||
), |
|||
parentUsesSize: true |
|||
); |
|||
|
|||
SliverGeometry childLayoutGeometry = this.child.geometry; |
|||
if (childLayoutGeometry.scrollOffsetCorrection != 0.0) { |
|||
this.geometry = new SliverGeometry( |
|||
scrollOffsetCorrection: childLayoutGeometry.scrollOffsetCorrection |
|||
); |
|||
return; |
|||
} |
|||
|
|||
double beforePaddingPaintExtent = this.calculatePaintOffset( |
|||
this.constraints, |
|||
from: 0.0, |
|||
to: beforePadding |
|||
); |
|||
|
|||
double afterPaddingPaintExtent = this.calculatePaintOffset( |
|||
this.constraints, |
|||
from: beforePadding + childLayoutGeometry.scrollExtent, |
|||
to: mainAxisPadding + childLayoutGeometry.scrollExtent |
|||
); |
|||
|
|||
double mainAxisPaddingPaintExtent = beforePaddingPaintExtent + afterPaddingPaintExtent; |
|||
double beforePaddingCacheExtent = this.calculateCacheOffset( |
|||
this.constraints, |
|||
from: 0.0, |
|||
to: beforePadding |
|||
); |
|||
double afterPaddingCacheExtent = this.calculateCacheOffset( |
|||
this.constraints, |
|||
from: beforePadding + childLayoutGeometry.scrollExtent, |
|||
to: mainAxisPadding + childLayoutGeometry.scrollExtent |
|||
); |
|||
|
|||
double mainAxisPaddingCacheExtent = afterPaddingCacheExtent + beforePaddingCacheExtent; |
|||
double paintExtent = Math.Min( |
|||
beforePaddingPaintExtent + Math.Max(childLayoutGeometry.paintExtent, |
|||
childLayoutGeometry.layoutExtent + afterPaddingPaintExtent), |
|||
this.constraints.remainingPaintExtent |
|||
); |
|||
|
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: mainAxisPadding + childLayoutGeometry.scrollExtent, |
|||
paintExtent: paintExtent, |
|||
layoutExtent: Math.Min(mainAxisPaddingPaintExtent + childLayoutGeometry.layoutExtent, paintExtent), |
|||
cacheExtent: Math.Min(mainAxisPaddingCacheExtent + childLayoutGeometry.cacheExtent, |
|||
this.constraints.remainingCacheExtent), |
|||
maxPaintExtent: mainAxisPadding + childLayoutGeometry.maxPaintExtent, |
|||
hitTestExtent: Math.Max( |
|||
mainAxisPaddingPaintExtent + childLayoutGeometry.paintExtent, |
|||
beforePaddingPaintExtent + childLayoutGeometry.hitTestExtent |
|||
), |
|||
hasVisualOverflow: childLayoutGeometry.hasVisualOverflow |
|||
); |
|||
|
|||
var childParentData = (SliverPhysicalParentData) this.child.parentData; |
|||
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(this.constraints.axisDirection, |
|||
this.constraints.growthDirection)) { |
|||
case AxisDirection.up: |
|||
childParentData.paintOffset = new Offset(this._padding.left, |
|||
this.calculatePaintOffset(this.constraints, |
|||
from: this._padding.bottom + childLayoutGeometry.scrollExtent, |
|||
to: this._padding.bottom + childLayoutGeometry.scrollExtent + this._padding.top)); |
|||
break; |
|||
case AxisDirection.right: |
|||
childParentData.paintOffset = |
|||
new Offset(this.calculatePaintOffset(this.constraints, from: 0.0, to: this._padding.left), |
|||
this._padding.top); |
|||
break; |
|||
case AxisDirection.down: |
|||
childParentData.paintOffset = new Offset(this._padding.left, |
|||
this.calculatePaintOffset(this.constraints, from: 0.0, to: this._padding.top)); |
|||
break; |
|||
case AxisDirection.left: |
|||
childParentData.paintOffset = new Offset( |
|||
this.calculatePaintOffset(this.constraints, |
|||
from: this._padding.right + childLayoutGeometry.scrollExtent, |
|||
to: this._padding.right + childLayoutGeometry.scrollExtent + this._padding.left), |
|||
this._padding.top); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public override double childMainAxisPosition(RenderObject child) { |
|||
return this.calculatePaintOffset(this.constraints, from: 0.0, to: this.beforePadding); |
|||
} |
|||
|
|||
public override double childCrossAxisPosition(RenderObject child) { |
|||
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection( |
|||
this.constraints.axisDirection, this.constraints.growthDirection)) { |
|||
case AxisDirection.up: |
|||
case AxisDirection.down: |
|||
return this._padding.left; |
|||
case AxisDirection.left: |
|||
case AxisDirection.right: |
|||
return this._padding.top; |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
public override double childScrollOffset(RenderObject child) { |
|||
return this.beforePadding; |
|||
} |
|||
|
|||
public override void applyPaintTransform(RenderObject child, ref Matrix4x4 transform) { |
|||
var childParentData = (SliverPhysicalParentData) child.parentData; |
|||
childParentData.applyPaintTransform(ref transform); |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
if (this.child != null && this.child.geometry.visible) { |
|||
var childParentData = (SliverPhysicalParentData) this.child.parentData; |
|||
context.paintChild(this.child, offset + childParentData.paintOffset); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 470336df9a5d4af3a4ccfa5fa759d854 |
|||
timeCreated: 1535523877 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.painting; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgets.ui |
|||
{ |
|||
public class Image |
|||
{ |
|||
public Image(byte[] raw, int height = 100, int width = 100) { |
|||
this.rawData = raw; |
|||
this.height = height; |
|||
this.width = width; |
|||
} |
|||
|
|||
public byte[] rawData; |
|||
public int height; |
|||
public int width; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: bfd6fdb0d13948d6acbc528589ebef33 |
|||
timeCreated: 1534821698 |
|
|||
namespace UIWidgets.gestures { |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: bb9a3c5b387541cb800b11c84121f7f3 |
|||
timeCreated: 1534828260 |
1001
Assets/UIWidgets/promise/Promise.cs
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: ffdd174fa01b47d99dae6b8b38945413 |
|||
timeCreated: 1534828022 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
|
|||
namespace RSG.Exceptions |
|||
{ |
|||
/// <summary>
|
|||
/// Base class for promise exceptions.
|
|||
/// </summary>
|
|||
public class PromiseException : Exception |
|||
{ |
|||
public PromiseException() { } |
|||
|
|||
public PromiseException(string message) : base(message) { } |
|||
|
|||
public PromiseException(string message, Exception inner) : base(message, inner) { } |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ef24fa8abd794ec9ad904f149ade425b |
|||
timeCreated: 1534828173 |
|
|||
fileFormatVersion: 2 |
|||
guid: 07f0b3c08d53427992f828dd9c4f0f15 |
|||
timeCreated: 1534828078 |
|
|||
fileFormatVersion: 2 |
|||
guid: d922956f02bc4ff2a82f9404787380b0 |
|||
timeCreated: 1534828191 |
|
|||
fileFormatVersion: 2 |
|||
guid: e47ddf579a9a45f48fd9203faf93b52f |
|||
timeCreated: 1534828095 |
1001
Assets/UIWidgets/promise/Promise_NonGeneric.cs
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: fad6eb2d15b84c7cb92f115245ac09f8 |
|||
timeCreated: 1534828106 |
|
|||
fileFormatVersion: 2 |
|||
guid: 2e1ff13e974447a080559101999e17d9 |
|||
timeCreated: 1534828127 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace RSG.Promises { |
|||
/// <summary>
|
|||
/// General extensions to LINQ.
|
|||
/// </summary>
|
|||
public static class EnumerableExt { |
|||
public static void Each<T>(this IEnumerable<T> source, Action<T> fn) { |
|||
foreach (var item in source) { |
|||
fn.Invoke(item); |
|||
} |
|||
} |
|||
|
|||
public static void Each<T>(this IEnumerable<T> source, Action<T, int> fn) { |
|||
int index = 0; |
|||
|
|||
foreach (T item in source) { |
|||
fn.Invoke(item, index); |
|||
index++; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Convert a variable length argument list of items to an enumerable.
|
|||
/// </summary>
|
|||
public static IEnumerable<T> FromItems<T>(params T[] items) { |
|||
foreach (var item in items) { |
|||
yield return item; |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
namespace RSG { |
|||
public static class PromiseHelpers { |
|||
/// <summary>
|
|||
/// Returns a promise that resolves with all of the specified promises have resolved.
|
|||
/// Returns a promise of a tuple of the resolved results.
|
|||
/// </summary>
|
|||
public static IPromise<Tuple<T1, T2>> All<T1, T2>(IPromise<T1> p1, IPromise<T2> p2) { |
|||
var val1 = default(T1); |
|||
var val2 = default(T2); |
|||
var numUnresolved = 2; |
|||
var alreadyRejected = false; |
|||
var promise = new Promise<Tuple<T1, T2>>(); |
|||
|
|||
p1 |
|||
.Then(val => { |
|||
val1 = val; |
|||
numUnresolved--; |
|||
if (numUnresolved <= 0) { |
|||
promise.Resolve(Tuple.Create(val1, val2)); |
|||
} |
|||
}) |
|||
.Catch(e => { |
|||
if (!alreadyRejected) { |
|||
promise.Reject(e); |
|||
} |
|||
|
|||
alreadyRejected = true; |
|||
}) |
|||
.Done(); |
|||
|
|||
p2 |
|||
.Then(val => { |
|||
val2 = val; |
|||
numUnresolved--; |
|||
if (numUnresolved <= 0) { |
|||
promise.Resolve(Tuple.Create(val1, val2)); |
|||
} |
|||
}) |
|||
.Catch(e => { |
|||
if (!alreadyRejected) { |
|||
promise.Reject(e); |
|||
} |
|||
|
|||
alreadyRejected = true; |
|||
}) |
|||
.Done(); |
|||
|
|||
return promise; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a promise that resolves with all of the specified promises have resolved.
|
|||
/// Returns a promise of a tuple of the resolved results.
|
|||
/// </summary>
|
|||
public static IPromise<Tuple<T1, T2, T3>> All<T1, T2, T3>(IPromise<T1> p1, IPromise<T2> p2, IPromise<T3> p3) { |
|||
return All(All(p1, p2), p3) |
|||
.Then(vals => Tuple.Create(vals.Item1.Item1, vals.Item1.Item2, vals.Item2)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a promise that resolves with all of the specified promises have resolved.
|
|||
/// Returns a promise of a tuple of the resolved results.
|
|||
/// </summary>
|
|||
public static IPromise<Tuple<T1, T2, T3, T4>> All<T1, T2, T3, T4>(IPromise<T1> p1, IPromise<T2> p2, |
|||
IPromise<T3> p3, IPromise<T4> p4) { |
|||
return All(All(p1, p2), All(p3, p4)) |
|||
.Then(vals => Tuple.Create(vals.Item1.Item1, vals.Item1.Item2, vals.Item2.Item1, vals.Item2.Item2)); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
|
|||
namespace RSG.Exceptions { |
|||
/// <summary>
|
|||
/// Exception thrown when an operation is performed on a promise that is in an invalid
|
|||
/// state for it to handle.
|
|||
/// </summary>
|
|||
public class PromiseStateException : PromiseException { |
|||
public PromiseStateException() { |
|||
} |
|||
|
|||
public PromiseStateException(string message) : base(message) { |
|||
} |
|||
|
|||
public PromiseStateException(string message, Exception inner) |
|||
: base(message, inner) { |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace RSG { |
|||
public class PromiseCancelledException : Exception { |
|||
/// <summary>
|
|||
/// Just create the exception
|
|||
/// </summary>
|
|||
public PromiseCancelledException() { |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create the exception with description
|
|||
/// </summary>
|
|||
/// <param name="message">Exception description</param>
|
|||
public PromiseCancelledException(String message) : base(message) { |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A class that wraps a pending promise with it's predicate and time data
|
|||
/// </summary>
|
|||
internal class PredicateWait { |
|||
/// <summary>
|
|||
/// Predicate for resolving the promise
|
|||
/// </summary>
|
|||
public Func<TimeData, bool> predicate; |
|||
|
|||
/// <summary>
|
|||
/// The time the promise was started
|
|||
/// </summary>
|
|||
public float timeStarted; |
|||
|
|||
/// <summary>
|
|||
/// The pending promise which is an interface for a promise that can be rejected or resolved.
|
|||
/// </summary>
|
|||
public IPendingPromise pendingPromise; |
|||
|
|||
/// <summary>
|
|||
/// The time data specific to this pending promise. Includes elapsed time and delta time.
|
|||
/// </summary>
|
|||
public TimeData timeData; |
|||
|
|||
/// <summary>
|
|||
/// The frame the promise was started
|
|||
/// </summary>
|
|||
public int frameStarted; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Time data specific to a particular pending promise.
|
|||
/// </summary>
|
|||
public struct TimeData { |
|||
/// <summary>
|
|||
/// The amount of time that has elapsed since the pending promise started running
|
|||
/// </summary>
|
|||
public float elapsedTime; |
|||
|
|||
/// <summary>
|
|||
/// The amount of time since the last time the pending promise was updated.
|
|||
/// </summary>
|
|||
public float deltaTime; |
|||
|
|||
/// <summary>
|
|||
/// The amount of times that update has been called since the pending promise started running
|
|||
/// </summary>
|
|||
public int elapsedUpdates; |
|||
} |
|||
|
|||
public interface IPromiseTimer { |
|||
/// <summary>
|
|||
/// Resolve the returned promise once the time has elapsed
|
|||
/// </summary>
|
|||
IPromise WaitFor(float seconds); |
|||
|
|||
/// <summary>
|
|||
/// Resolve the returned promise once the predicate evaluates to true
|
|||
/// </summary>
|
|||
IPromise WaitUntil(Func<TimeData, bool> predicate); |
|||
|
|||
/// <summary>
|
|||
/// Resolve the returned promise once the predicate evaluates to false
|
|||
/// </summary>
|
|||
IPromise WaitWhile(Func<TimeData, bool> predicate); |
|||
|
|||
/// <summary>
|
|||
/// Update all pending promises. Must be called for the promises to progress and resolve at all.
|
|||
/// </summary>
|
|||
void Update(float deltaTime); |
|||
|
|||
/// <summary>
|
|||
/// Cancel a waiting promise and reject it immediately.
|
|||
/// </summary>
|
|||
bool Cancel(IPromise promise); |
|||
} |
|||
|
|||
public class PromiseTimer : IPromiseTimer { |
|||
/// <summary>
|
|||
/// The current running total for time that this PromiseTimer has run for
|
|||
/// </summary>
|
|||
private float curTime; |
|||
|
|||
/// <summary>
|
|||
/// The current running total for the amount of frames the PromiseTimer has run for
|
|||
/// </summary>
|
|||
private int curFrame; |
|||
|
|||
/// <summary>
|
|||
/// Currently pending promises
|
|||
/// </summary>
|
|||
private readonly LinkedList<PredicateWait> waiting = new LinkedList<PredicateWait>(); |
|||
|
|||
/// <summary>
|
|||
/// Resolve the returned promise once the time has elapsed
|
|||
/// </summary>
|
|||
public IPromise WaitFor(float seconds) { |
|||
return WaitUntil(t => t.elapsedTime >= seconds); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resolve the returned promise once the predicate evaluates to false
|
|||
/// </summary>
|
|||
public IPromise WaitWhile(Func<TimeData, bool> predicate) { |
|||
return WaitUntil(t => !predicate(t)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resolve the returned promise once the predicate evalutes to true
|
|||
/// </summary>
|
|||
public IPromise WaitUntil(Func<TimeData, bool> predicate) { |
|||
var promise = new Promise(); |
|||
|
|||
var wait = new PredicateWait() { |
|||
timeStarted = curTime, |
|||
pendingPromise = promise, |
|||
timeData = new TimeData(), |
|||
predicate = predicate, |
|||
frameStarted = curFrame |
|||
}; |
|||
|
|||
waiting.AddLast(wait); |
|||
|
|||
return promise; |
|||
} |
|||
|
|||
public bool Cancel(IPromise promise) { |
|||
var node = FindInWaiting(promise); |
|||
|
|||
if (node == null) { |
|||
return false; |
|||
} |
|||
|
|||
node.Value.pendingPromise.Reject(new PromiseCancelledException("Promise was cancelled by user.")); |
|||
waiting.Remove(node); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
LinkedListNode<PredicateWait> FindInWaiting(IPromise promise) { |
|||
for (var node = waiting.First; node != null; node = node.Next) { |
|||
if (node.Value.pendingPromise.Id.Equals(promise.Id)) { |
|||
return node; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Update all pending promises. Must be called for the promises to progress and resolve at all.
|
|||
/// </summary>
|
|||
public void Update(float deltaTime) { |
|||
curTime += deltaTime; |
|||
curFrame += 1; |
|||
|
|||
var node = waiting.First; |
|||
while (node != null) { |
|||
var wait = node.Value; |
|||
|
|||
var newElapsedTime = curTime - wait.timeStarted; |
|||
wait.timeData.deltaTime = newElapsedTime - wait.timeData.elapsedTime; |
|||
wait.timeData.elapsedTime = newElapsedTime; |
|||
var newElapsedUpdates = curFrame - wait.frameStarted; |
|||
wait.timeData.elapsedUpdates = newElapsedUpdates; |
|||
|
|||
bool result; |
|||
try { |
|||
result = wait.predicate(wait.timeData); |
|||
} |
|||
catch (Exception ex) { |
|||
wait.pendingPromise.Reject(ex); |
|||
|
|||
node = RemoveNode(node); |
|||
continue; |
|||
} |
|||
|
|||
if (result) { |
|||
wait.pendingPromise.Resolve(); |
|||
|
|||
node = RemoveNode(node); |
|||
} |
|||
else { |
|||
node = node.Next; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the provided node and returns the next node in the list.
|
|||
/// </summary>
|
|||
private LinkedListNode<PredicateWait> RemoveNode(LinkedListNode<PredicateWait> node) { |
|||
var currentNode = node; |
|||
node = node.Next; |
|||
|
|||
waiting.Remove(currentNode); |
|||
|
|||
return node; |
|||
} |
|||
} |
|||
} |
|
|||
namespace RSG { |
|||
/// <summary>
|
|||
/// Provides static methods for creating tuple objects.
|
|||
///
|
|||
/// Tuple implementation for .NET 3.5
|
|||
/// </summary>
|
|||
public class Tuple { |
|||
/// <summary>
|
|||
/// Create a new 2-tuple, or pair.
|
|||
/// </summary>
|
|||
/// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
|
|||
/// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
|
|||
/// <param name="item1">The value of the first component of the tuple.</param>
|
|||
/// <param name="item2">The value of the second component of the tuple.</param>
|
|||
/// <returns>A 2-tuple whose value is (item1, item2)</returns>
|
|||
public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) { |
|||
return new Tuple<T1, T2>(item1, item2); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a new 3-tuple, or triple.
|
|||
/// </summary>
|
|||
/// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
|
|||
/// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
|
|||
/// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
|
|||
/// <param name="item1">The value of the first component of the tuple.</param>
|
|||
/// <param name="item2">The value of the second component of the tuple.</param>
|
|||
/// <param name="item3">The value of the third component of the tuple.</param>
|
|||
/// <returns>A 3-tuple whose value is (item1, item2, item3)</returns>
|
|||
public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) { |
|||
return new Tuple<T1, T2, T3>(item1, item2, item3); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a new 4-tuple, or quadruple.
|
|||
/// </summary>
|
|||
/// <typeparam name="T1">The type of the first component of the tuple.</typeparam>
|
|||
/// <typeparam name="T2">The type of the second component of the tuple.</typeparam>
|
|||
/// <typeparam name="T3">The type of the third component of the tuple.</typeparam>
|
|||
/// <typeparam name="T4">The type of the fourth component of the tuple.</typeparam>
|
|||
/// <param name="item1">The value of the first component of the tuple.</param>
|
|||
/// <param name="item2">The value of the second component of the tuple.</param>
|
|||
/// <param name="item3">The value of the third component of the tuple.</param>
|
|||
/// <param name="item4">The value of the fourth component of the tuple.</param>
|
|||
/// <returns>A 3-tuple whose value is (item1, item2, item3, item4)</returns>
|
|||
public static Tuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4) { |
|||
return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Represents a 2-tuple, or pair.
|
|||
/// </summary>
|
|||
/// <typeparam name="T1">The type of the tuple's first component.</typeparam>
|
|||
/// <typeparam name="T2">The type of the tuple's second component.</typeparam>
|
|||
public class Tuple<T1, T2> { |
|||
internal Tuple(T1 item1, T2 item2) { |
|||
Item1 = item1; |
|||
Item2 = item2; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's first component.
|
|||
/// </summary>
|
|||
public T1 Item1 { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's second component.
|
|||
/// </summary>
|
|||
public T2 Item2 { get; private set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Represents a 3-tuple, or triple.
|
|||
/// </summary>
|
|||
/// <typeparam name="T1">The type of the tuple's first component.</typeparam>
|
|||
/// <typeparam name="T2">The type of the tuple's second component.</typeparam>
|
|||
/// <typeparam name="T3">The type of the tuple's third component.</typeparam>
|
|||
public class Tuple<T1, T2, T3> { |
|||
internal Tuple(T1 item1, T2 item2, T3 item3) { |
|||
Item1 = item1; |
|||
Item2 = item2; |
|||
Item3 = item3; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's first component.
|
|||
/// </summary>
|
|||
public T1 Item1 { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's second component.
|
|||
/// </summary>
|
|||
public T2 Item2 { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's third component.
|
|||
/// </summary>
|
|||
public T3 Item3 { get; private set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Represents a 4-tuple, or quadruple.
|
|||
/// </summary>
|
|||
/// <typeparam name="T1">The type of the tuple's first component.</typeparam>
|
|||
/// <typeparam name="T2">The type of the tuple's second component.</typeparam>
|
|||
/// <typeparam name="T3">The type of the tuple's third component.</typeparam>
|
|||
/// <typeparam name="T4">The type of the tuple's fourth component.</typeparam>
|
|||
public class Tuple<T1, T2, T3, T4> { |
|||
internal Tuple(T1 item1, T2 item2, T3 item3, T4 item4) { |
|||
Item1 = item1; |
|||
Item2 = item2; |
|||
Item3 = item3; |
|||
Item4 = item4; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's first component.
|
|||
/// </summary>
|
|||
public T1 Item1 { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's second component.
|
|||
/// </summary>
|
|||
public T2 Item2 { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's third component.
|
|||
/// </summary>
|
|||
public T3 Item3 { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the current tuple's fourth component.
|
|||
/// </summary>
|
|||
public T4 Item4 { get; private set; } |
|||
} |
|||
} |
撰写
预览
正在加载...
取消
保存
Reference in new issue