fzhangtj
6 年前
当前提交
cd624f79
共有 74 个文件被更改,包括 4840 次插入 和 23 次删除
-
2Assets/UIWidgets/foundation/basic_types.cs
-
65Assets/UIWidgets/foundation/change_notifier.cs
-
11Assets/UIWidgets/gestures/recognizer.cs
-
6Assets/UIWidgets/painting/image_provider.cs
-
25Assets/UIWidgets/painting/image_stream.cs
-
36Assets/UIWidgets/rendering/viewport_offset.cs
-
18Assets/UIWidgets/scheduler/binding.cs
-
62Assets/UIWidgets/ui/geometry.cs
-
27Assets/UIWidgets/ui/painting/painting.cs
-
14Assets/UIWidgets/ui/window.cs
-
144Assets/UIWidgets/widgets/framework.cs
-
2ProjectSettings/ProjectSettings.asset
-
7Assets/UIWidgets/gestures/drag.cs
-
3Assets/UIWidgets/gestures/drag.cs.meta
-
298Assets/UIWidgets/scheduler/ticker.cs
-
3Assets/UIWidgets/scheduler/ticker.cs.meta
-
57Assets/UIWidgets/widgets/basic.cs
-
3Assets/UIWidgets/widgets/basic.cs.meta
-
52Assets/UIWidgets/widgets/binding.cs
-
3Assets/UIWidgets/widgets/binding.cs.meta
-
178Assets/UIWidgets/widgets/image.cs
-
3Assets/UIWidgets/widgets/image.cs.meta
-
70Assets/UIWidgets/widgets/notification_listener.cs
-
3Assets/UIWidgets/widgets/notification_listener.cs.meta
-
361Assets/UIWidgets/widgets/scroll_activity.cs
-
3Assets/UIWidgets/widgets/scroll_activity.cs.meta
-
18Assets/UIWidgets/widgets/scroll_context.cs
-
3Assets/UIWidgets/widgets/scroll_context.cs.meta
-
75Assets/UIWidgets/widgets/scroll_matrics.cs
-
3Assets/UIWidgets/widgets/scroll_matrics.cs.meta
-
139Assets/UIWidgets/widgets/scroll_notification.cs
-
3Assets/UIWidgets/widgets/scroll_notification.cs.meta
-
53Assets/UIWidgets/widgets/scroll_notification.mixin.gen.cs
-
11Assets/UIWidgets/widgets/scroll_notification.mixin.gen.cs.meta
-
32Assets/UIWidgets/widgets/scroll_notification.mixin.njk
-
3Assets/UIWidgets/widgets/scroll_notification.mixin.njk.meta
-
352Assets/UIWidgets/widgets/scroll_physics.cs
-
3Assets/UIWidgets/widgets/scroll_physics.cs.meta
-
7Assets/UIWidgets/widgets/scroll_position.cs
-
3Assets/UIWidgets/widgets/scroll_position.cs.meta
-
169Assets/UIWidgets/widgets/scroll_simulation.cs
-
3Assets/UIWidgets/widgets/scroll_simulation.cs.meta
-
318Assets/UIWidgets/animation/curves.cs
-
3Assets/UIWidgets/animation/animation.cs.meta
-
3Assets/UIWidgets/animation/animation_controller.cs.meta
-
3Assets/UIWidgets/animation/animations.cs.meta
-
11Assets/UIWidgets/animation/curves.cs.meta
-
2Assets/UIWidgets/animation/listener_helpers.cs
-
3Assets/UIWidgets/animation/listener_helpers.cs.meta
-
11Assets/UIWidgets/animation/listener_helpers.mixin.gen.cs.meta
-
3Assets/UIWidgets/animation/listener_helpers.mixin.njk.meta
-
3Assets/UIWidgets/animation/tween.cs.meta
-
60Assets/UIWidgets/animation/animation.cs
-
417Assets/UIWidgets/animation/animation_controller.cs
-
591Assets/UIWidgets/animation/animations.cs
-
245Assets/UIWidgets/animation/listener_helpers.mixin.gen.cs
-
141Assets/UIWidgets/animation/listener_helpers.mixin.njk
-
216Assets/UIWidgets/animation/tween.cs
-
44Assets/UIWidgets/physics/clamped_simulation.cs
-
3Assets/UIWidgets/physics/clamped_simulation.cs.meta
-
96Assets/UIWidgets/physics/friction_simulation.cs
-
3Assets/UIWidgets/physics/friction_simulation.cs.meta
-
36Assets/UIWidgets/physics/gravity_simulation.cs
-
3Assets/UIWidgets/physics/gravity_simulation.cs.meta
-
15Assets/UIWidgets/physics/simulation.cs
-
11Assets/UIWidgets/physics/simulation.cs.meta
-
238Assets/UIWidgets/physics/spring_simulation.cs
-
3Assets/UIWidgets/physics/spring_simulation.cs.meta
-
28Assets/UIWidgets/physics/tolerance.cs
-
3Assets/UIWidgets/physics/tolerance.cs.meta
-
14Assets/UIWidgets/physics/utils.cs
-
3Assets/UIWidgets/physics/utils.cs.meta
|
|||
namespace UIWidgets.gestures { |
|||
public interface Drag { |
|||
void update(DragUpdateDetails details); |
|||
void end(DragEndDetails details); |
|||
void cancel(); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2f59e34cb2654a9c9b2ce3b7df07ab22 |
|||
timeCreated: 1536665218 |
|
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.Text; |
|||
using RSG; |
|||
using RSG.Promises; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.scheduler { |
|||
public delegate void TickerCallback(TimeSpan elapsed); |
|||
|
|||
public interface TickerProvider { |
|||
Ticker createTicker(TickerCallback onTick); |
|||
} |
|||
|
|||
public class Ticker { |
|||
public Ticker(SchedulerBinding binding, TickerCallback onTick, string debugLabel = null) { |
|||
D.assert(() => { |
|||
this._debugCreationStack = new StackTrace(); |
|||
return true; |
|||
}); |
|||
|
|||
this._binding = binding; |
|||
this._onTick = onTick; |
|||
this.debugLabel = debugLabel; |
|||
} |
|||
|
|||
readonly SchedulerBinding _binding; |
|||
|
|||
TickerFutureImpl _future; |
|||
|
|||
public bool muted { |
|||
get { return this._muted; } |
|||
set { |
|||
if (value == this._muted) { |
|||
return; |
|||
} |
|||
|
|||
this._muted = value; |
|||
if (value) { |
|||
this.unscheduleTick(); |
|||
} else if (this.shouldScheduleTick) { |
|||
this.scheduleTick(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool _muted = false; |
|||
|
|||
public bool isTicking { |
|||
get { |
|||
if (this._future == null) { |
|||
return false; |
|||
} |
|||
|
|||
if (this.muted) { |
|||
return false; |
|||
} |
|||
|
|||
if (this._binding.framesEnabled) { |
|||
return true; |
|||
} |
|||
|
|||
if (this._binding.schedulerPhase != SchedulerPhase.idle) { |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public bool isActive { |
|||
get { return this._future != null; } |
|||
} |
|||
|
|||
TimeSpan? _startTime; |
|||
|
|||
public TickerFuture start() { |
|||
D.assert(() => { |
|||
if (this.isActive) { |
|||
throw new UIWidgetsError( |
|||
"A ticker that is already active cannot be started again without first stopping it.\n" + |
|||
"The affected ticker was: " + this.toString(debugIncludeStack: true)); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
|
|||
D.assert(this._startTime == null); |
|||
this._future = new TickerFutureImpl(); |
|||
if (this.shouldScheduleTick) { |
|||
this.scheduleTick(); |
|||
} |
|||
|
|||
if (this._binding.schedulerPhase > SchedulerPhase.idle && |
|||
this._binding.schedulerPhase < SchedulerPhase.postFrameCallbacks) { |
|||
this._startTime = this._binding.currentFrameTimeStamp; |
|||
} |
|||
|
|||
return this._future; |
|||
} |
|||
|
|||
public void stop(bool canceled = false) { |
|||
if (!this.isActive) { |
|||
return; |
|||
} |
|||
|
|||
var localFuture = this._future; |
|||
this._future = null; |
|||
this._startTime = null; |
|||
D.assert(!this.isActive); |
|||
|
|||
this.unscheduleTick(); |
|||
if (canceled) { |
|||
localFuture._cancel(this); |
|||
} else { |
|||
localFuture._complete(); |
|||
} |
|||
} |
|||
|
|||
readonly TickerCallback _onTick; |
|||
|
|||
int? _animationId; |
|||
|
|||
protected bool scheduled { |
|||
get { return this._animationId != null; } |
|||
} |
|||
|
|||
protected bool shouldScheduleTick { |
|||
get { return !this.muted && this.isActive && !this.scheduled; } |
|||
} |
|||
|
|||
void _tick(TimeSpan timeStamp) { |
|||
D.assert(this.isTicking); |
|||
D.assert(this.scheduled); |
|||
this._animationId = null; |
|||
|
|||
this._startTime = this._startTime ?? timeStamp; |
|||
|
|||
this._onTick(timeStamp - this._startTime.Value); |
|||
|
|||
if (this.shouldScheduleTick) { |
|||
this.scheduleTick(rescheduling: true); |
|||
} |
|||
} |
|||
|
|||
protected void scheduleTick(bool rescheduling = false) { |
|||
D.assert(!this.scheduled); |
|||
D.assert(this.shouldScheduleTick); |
|||
this._animationId = this._binding.scheduleFrameCallback(this._tick, rescheduling: rescheduling); |
|||
} |
|||
|
|||
protected void unscheduleTick() { |
|||
if (this.scheduled) { |
|||
this._binding.cancelFrameCallbackWithId(this._animationId.Value); |
|||
this._animationId = null; |
|||
} |
|||
|
|||
D.assert(!this.shouldScheduleTick); |
|||
} |
|||
|
|||
public void absorbTicker(Ticker originalTicker) { |
|||
D.assert(!this.isActive); |
|||
D.assert(this._future == null); |
|||
D.assert(this._startTime == null); |
|||
D.assert(this._animationId == null); |
|||
D.assert((originalTicker._future == null) == (originalTicker._startTime == null), |
|||
"Cannot absorb Ticker after it has been disposed."); |
|||
if (originalTicker._future != null) { |
|||
this._future = originalTicker._future; |
|||
this._startTime = originalTicker._startTime; |
|||
if (this.shouldScheduleTick) { |
|||
this.scheduleTick(); |
|||
} |
|||
|
|||
originalTicker._future = null; |
|||
originalTicker.unscheduleTick(); |
|||
} |
|||
|
|||
originalTicker.dispose(); |
|||
} |
|||
|
|||
public virtual void dispose() { |
|||
if (this._future != null) { |
|||
var localFuture = this._future; |
|||
this._future = null; |
|||
D.assert(!this.isActive); |
|||
this.unscheduleTick(); |
|||
localFuture._cancel(this); |
|||
} |
|||
|
|||
D.assert(() => { |
|||
this._startTime = default(TimeSpan); |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
public readonly String debugLabel; |
|||
|
|||
StackTrace _debugCreationStack; |
|||
|
|||
public override string ToString() { |
|||
return this.toString(debugIncludeStack: false); |
|||
} |
|||
|
|||
public string toString(bool debugIncludeStack = false) { |
|||
var buffer = new StringBuilder(); |
|||
buffer.Append(this.GetType() + "("); |
|||
D.assert(() => { |
|||
buffer.Append(this.debugLabel ?? ""); |
|||
return true; |
|||
}); |
|||
buffer.Append(')'); |
|||
D.assert(() => { |
|||
if (debugIncludeStack) { |
|||
buffer.AppendLine(); |
|||
buffer.AppendLine("The stack trace when the " + this.GetType() + " was actually created was:"); |
|||
UIWidgetsError.defaultStackFilter(this._debugCreationStack.ToString().TrimEnd().Split('\n')) |
|||
.Each(line => buffer.AppendLine(line)); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
return buffer.ToString(); |
|||
} |
|||
} |
|||
|
|||
public interface TickerFuture : IPromise { |
|||
void whenCompleteOrCancel(VoidCallback callback); |
|||
|
|||
IPromise orCancel { get; } |
|||
} |
|||
|
|||
public class TickerFutureImpl : Promise, TickerFuture { |
|||
public static TickerFuture complete() { |
|||
var result = new TickerFutureImpl(); |
|||
result._complete(); |
|||
return result; |
|||
} |
|||
|
|||
Promise _secondaryCompleter; |
|||
bool? _completed; |
|||
|
|||
internal void _complete() { |
|||
D.assert(this._completed == null); |
|||
this._completed = true; |
|||
this.Resolve(); |
|||
if (this._secondaryCompleter != null) { |
|||
this._secondaryCompleter.Resolve(); |
|||
} |
|||
} |
|||
|
|||
internal void _cancel(Ticker ticker) { |
|||
D.assert(this._completed == null); |
|||
this._completed = false; |
|||
if (this._secondaryCompleter != null) { |
|||
this._secondaryCompleter.Reject(new TickerCanceled(ticker)); |
|||
} |
|||
} |
|||
|
|||
public void whenCompleteOrCancel(VoidCallback callback) { |
|||
this.orCancel.Then(() => callback(), ex => callback()); |
|||
} |
|||
|
|||
public IPromise orCancel { |
|||
get { |
|||
if (this._secondaryCompleter == null) { |
|||
this._secondaryCompleter = new Promise(); |
|||
if (this._completed != null) { |
|||
if (this._completed.Value) { |
|||
this._secondaryCompleter.Resolve(); |
|||
} else { |
|||
this._secondaryCompleter.Reject(new TickerCanceled()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return this._secondaryCompleter; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class TickerCanceled : Exception { |
|||
public TickerCanceled(Ticker ticker = null) { |
|||
this.ticker = ticker; |
|||
} |
|||
|
|||
public readonly Ticker ticker; |
|||
|
|||
public override string ToString() { |
|||
if (this.ticker != null) { |
|||
return "This ticker was canceled: " + this.ticker; |
|||
} |
|||
|
|||
return "The ticker was canceled before the \"orCancel\" property was first used."; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3fb425debd2a441cadf8ad4a4fed3aa1 |
|||
timeCreated: 1536717302 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.rendering; |
|||
using UIWidgets.ui; |
|||
using UnityEngine.Assertions; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class RawImage : LeafRenderObjectWidget { |
|||
public RawImage(string key, ui.Image image, double width, double height, double scale, Color color, |
|||
BlendMode colorBlendMode, BoxFit fit, Rect centerSlice, Alignment alignment = null, |
|||
ImageRepeat repeat = ImageRepeat.noRepeat) : base(key) { |
|||
this.image = image; |
|||
this.width = width; |
|||
this.height = height; |
|||
this.scale = scale; |
|||
this.color = color; |
|||
this.blendMode = colorBlendMode; |
|||
this.centerSlice = centerSlice; |
|||
this.fit = fit; |
|||
this.alignment = alignment == null ? Alignment.center : alignment; |
|||
this.repeat = repeat; |
|||
} |
|||
|
|||
public override Element createElement() { |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new RenderImage( |
|||
this.image, |
|||
this.width, |
|||
this.height, |
|||
this.color, |
|||
this.blendMode, |
|||
this.fit, |
|||
this.repeat, |
|||
this.centerSlice, |
|||
this.alignment |
|||
); |
|||
} |
|||
|
|||
public ui.Image image; |
|||
public double width; |
|||
public double height; |
|||
public double scale; |
|||
public Color color; |
|||
public BlendMode blendMode; |
|||
public BoxFit fit; |
|||
public Alignment alignment; |
|||
public ImageRepeat repeat; |
|||
public Rect centerSlice; |
|||
} |
|||
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 69241aaa538e4e2baa651ffa39d6f355 |
|||
timeCreated: 1536564821 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.rendering; |
|||
using UIWidgets.ui; |
|||
using UnityEngine.Assertions; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
abstract class WidgetsBinding : RendererBinding { |
|||
protected WidgetsBinding(Window window) : base(window) { |
|||
this.buildOwner.onBuildScheduled = this._handleBuildScheduled; |
|||
window.onLocaleChanged += this.handleLocaleChanged; |
|||
window.onAccessibilityFeaturesChanged += handleAccessibilityFeaturesChanged; |
|||
} |
|||
|
|||
public BuildOwner buildOwner { |
|||
get { return this._buildOwner; } |
|||
} |
|||
|
|||
readonly BuildOwner _buildOwner; |
|||
|
|||
public Element renderViewElement { |
|||
get { return this._renderViewElement; } |
|||
} |
|||
|
|||
Element _renderViewElement; |
|||
|
|||
void _handleBuildScheduled() { |
|||
ensureVisualUpdate(); |
|||
} |
|||
|
|||
void handleLocaleChanged() { |
|||
// todo
|
|||
// dispatchLocaleChanged(window.locale);
|
|||
} |
|||
|
|||
void handleAccessibilityFeaturesChanged() { |
|||
// for (WidgetsBindingObserver observer in _observers) {
|
|||
// observer.didChangeAccessibilityFeatures();
|
|||
// }
|
|||
} |
|||
|
|||
public void drawFrame() { |
|||
if (renderViewElement != null) { |
|||
buildOwner.buildScope(renderViewElement); |
|||
} |
|||
base.drawFrame(); |
|||
buildOwner.finalizeTree(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 39d3379616cb4c64afdedd889e3ac2a2 |
|||
timeCreated: 1536213633 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.rendering; |
|||
using UIWidgets.ui; |
|||
using UnityEngine; |
|||
using UnityEngine.Assertions; |
|||
using Color = UIWidgets.ui.Color; |
|||
using Rect = UnityEngine.Rect; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
internal class Util { |
|||
public static ImageConfiguration createLocalImageConfiguration(BuildContext context, Size size) { |
|||
return new ImageConfiguration( |
|||
size: size |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class Image<T> : StatefulWidget { |
|||
public IImageProvider<System.Object> image; |
|||
public double width; |
|||
public double height; |
|||
public Color color; |
|||
public BoxFit fit; |
|||
public Alignment alignment; |
|||
public BlendMode colorBlendMode; |
|||
public ImageRepeat repeat; |
|||
public ui.Rect centerSlice; |
|||
|
|||
public bool gaplessPlayback; |
|||
|
|||
public Image( |
|||
string key, |
|||
ImageProvider<System.Object> image, |
|||
double width, |
|||
double height, |
|||
Color color, |
|||
BlendMode colorBlendMode, |
|||
BoxFit fit, |
|||
ui.Rect centerSlice, |
|||
Alignment alignment, |
|||
ImageRepeat repeat = ImageRepeat.noRepeat, |
|||
bool gaplessPlayback = false |
|||
) : base(key) { |
|||
this.image = image; |
|||
this.width = width; |
|||
this.height = height; |
|||
this.color = color; |
|||
this.colorBlendMode = colorBlendMode; |
|||
this.fit = fit; |
|||
this.alignment = alignment == null ? Alignment.center : alignment; |
|||
this.repeat = repeat; |
|||
this.centerSlice = centerSlice; |
|||
this.gaplessPlayback = gaplessPlayback; |
|||
} |
|||
|
|||
// Network Image
|
|||
public Image( |
|||
string src, |
|||
string key, |
|||
double width, |
|||
double height, |
|||
Color color, |
|||
BlendMode colorBlendMode, |
|||
BoxFit fit, |
|||
Alignment alignment, |
|||
ui.Rect centerSlice, |
|||
Dictionary<String, String> headers, |
|||
ImageRepeat repeat = ImageRepeat.noRepeat, |
|||
bool gaplessPlayback = false, |
|||
double scale = 1.0 |
|||
) : base(key) { |
|||
this.image = new NetworkImage(src, headers, scale); |
|||
this.width = width; |
|||
this.height = height; |
|||
this.color = color; |
|||
this.colorBlendMode = colorBlendMode; |
|||
this.fit = fit; |
|||
this.alignment = alignment; |
|||
this.centerSlice = centerSlice; |
|||
this.repeat = repeat; |
|||
this.gaplessPlayback = gaplessPlayback; |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new _ImageState<T>(); |
|||
} |
|||
} |
|||
|
|||
public class _ImageState<T> : State { |
|||
ImageStream _imageStream; |
|||
ImageInfo _imageInfo; |
|||
bool _isListeningToStream = false; |
|||
|
|||
public override void didChangeDependencies() { |
|||
_resolveImage(); |
|||
// if (TickerMode.of(context))
|
|||
// _listenToStream();
|
|||
// else
|
|||
// _stopListeningToStream();
|
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
if (((Image<T>) widget).image != ((Image<T>) oldWidget).image) |
|||
_resolveImage(); |
|||
} |
|||
|
|||
public override void reassemble() { |
|||
_resolveImage(); // in case the image cache was flushed
|
|||
} |
|||
|
|||
void _resolveImage() { |
|||
var imageWidget = (Image<T>) widget; |
|||
ImageStream newStream = |
|||
imageWidget.image.resolve(Util.createLocalImageConfiguration( |
|||
context, |
|||
size: new Size(imageWidget.width, imageWidget.height) |
|||
)); |
|||
_updateSourceStream(newStream); |
|||
} |
|||
|
|||
void _handleImageChanged(ImageInfo imageInfo, bool synchronousCall) { |
|||
setState(() => { _imageInfo = imageInfo; }); |
|||
} |
|||
|
|||
void _updateSourceStream(ImageStream newStream) { |
|||
if ((_imageStream == null ? null : _imageStream.key) == (newStream == null ? null : newStream.key)) |
|||
return; |
|||
|
|||
if (_isListeningToStream && _imageStream != null) |
|||
_imageStream.removeListener(_handleImageChanged); |
|||
|
|||
if (!((Image<T>) widget).gaplessPlayback) { |
|||
setState(() => { _imageInfo = null; }); |
|||
|
|||
_imageStream = newStream; |
|||
if (_isListeningToStream && _imageStream != null) |
|||
_imageStream.addListener(_handleImageChanged); |
|||
} |
|||
} |
|||
|
|||
void _listenToStream() { |
|||
if (_isListeningToStream) |
|||
return; |
|||
_imageStream.addListener(_handleImageChanged); |
|||
_isListeningToStream = true; |
|||
} |
|||
|
|||
void _stopListeningToStream() { |
|||
if (!_isListeningToStream) |
|||
return; |
|||
_imageStream.removeListener(_handleImageChanged); |
|||
_isListeningToStream = false; |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
var imageWidget = (Image<T>) widget; |
|||
RawImage image = new RawImage( |
|||
"", // todo
|
|||
_imageInfo == null ? null : _imageInfo.image, |
|||
imageWidget.width, |
|||
imageWidget.height, |
|||
_imageInfo == null ? 1.0 : _imageInfo.scale, |
|||
imageWidget.color, |
|||
imageWidget.colorBlendMode, |
|||
imageWidget.fit, |
|||
imageWidget.centerSlice, |
|||
imageWidget.alignment, |
|||
imageWidget.repeat |
|||
); |
|||
|
|||
return image; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: d1d313d74f6044198caad151f52721b8 |
|||
timeCreated: 1536219326 |
|
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public delegate bool NotificationListenerCallback<T>(T notification) where T : Notification; |
|||
|
|||
public abstract class Notification { |
|||
protected virtual bool visitAncestor(Element element) { |
|||
if (element is StatelessElement) { |
|||
StatelessWidget widget = (StatelessWidget) element.widget; |
|||
var listener = widget as _NotificationListener; |
|||
if (listener != null) { |
|||
if (listener._dispatch(this, element)) { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
public void dispatch(BuildContext target) { |
|||
D.assert(target != null); |
|||
target.visitAncestorElements(this.visitAncestor); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
var description = new List<string>(); |
|||
this.debugFillDescription(description); |
|||
return string.Format("{0}({1})", this.GetType(), string.Join(", ", description.ToArray())); |
|||
} |
|||
|
|||
protected virtual void debugFillDescription(List<string> description) { |
|||
} |
|||
} |
|||
|
|||
interface _NotificationListener { |
|||
bool _dispatch(Notification notification, Element element); |
|||
} |
|||
|
|||
public class NotificationListener<T> : StatelessWidget, _NotificationListener where T : Notification { |
|||
public NotificationListener( |
|||
string key = null, |
|||
Widget child = null, |
|||
NotificationListenerCallback<T> onNotification = null) : base(key) { |
|||
this.child = child; |
|||
this.onNotification = onNotification; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly NotificationListenerCallback<T> onNotification; |
|||
|
|||
bool _NotificationListener._dispatch(Notification notification, Element element) { |
|||
if (this.onNotification != null && notification is T) { |
|||
bool result = this.onNotification((T) notification); |
|||
return result; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return this.child; |
|||
} |
|||
} |
|||
|
|||
public class LayoutChangedNotification : Notification { |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 647bb259966f4e4e8196f7c9c4ef56dc |
|||
timeCreated: 1536582324 |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.gestures; |
|||
using UIWidgets.painting; |
|||
using UIWidgets.physics; |
|||
using UIWidgets.scheduler; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public interface ScrollActivityDelegate { |
|||
AxisDirection axisDirection { get; } |
|||
|
|||
double setPixels(double pixels); |
|||
|
|||
void applyUserOffset(double delta); |
|||
|
|||
void goIdle(); |
|||
|
|||
void goBallistic(double velocity); |
|||
} |
|||
|
|||
public abstract class ScrollActivity { |
|||
public ScrollActivity(ScrollActivityDelegate @delegate) { |
|||
this._delegate = @delegate; |
|||
} |
|||
|
|||
public ScrollActivityDelegate @delegate { |
|||
get { return this._delegate; } |
|||
} |
|||
|
|||
ScrollActivityDelegate _delegate; |
|||
|
|||
public void updateDelegate(ScrollActivityDelegate value) { |
|||
D.assert(this._delegate != value); |
|||
this._delegate = value; |
|||
} |
|||
|
|||
public virtual void resetActivity() { |
|||
} |
|||
|
|||
public virtual void dispatchScrollStartNotification(ScrollMetrics metrics, BuildContext context) { |
|||
new ScrollStartNotification(metrics: metrics, context: context).dispatch(context); |
|||
} |
|||
|
|||
public virtual void dispatchScrollUpdateNotification(ScrollMetrics metrics, BuildContext context, |
|||
double scrollDelta) { |
|||
new ScrollUpdateNotification(metrics: metrics, context: context, scrollDelta: scrollDelta) |
|||
.dispatch(context); |
|||
} |
|||
|
|||
public virtual void dispatchOverscrollNotification(ScrollMetrics metrics, BuildContext context, |
|||
double overscroll) { |
|||
new OverscrollNotification(metrics: metrics, context: context, overscroll: overscroll).dispatch(context); |
|||
} |
|||
|
|||
public virtual void dispatchScrollEndNotification(ScrollMetrics metrics, BuildContext context) { |
|||
new ScrollEndNotification(metrics: metrics, context: context).dispatch(context); |
|||
} |
|||
|
|||
public virtual void applyNewDimensions() { |
|||
} |
|||
|
|||
public abstract bool shouldIgnorePointer { get; } |
|||
|
|||
public abstract bool isScrolling { get; } |
|||
|
|||
public abstract double velocity { get; } |
|||
|
|||
public virtual void dispose() { |
|||
this._delegate = null; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return Diagnostics.describeIdentity(this); |
|||
} |
|||
} |
|||
|
|||
public class IdleScrollActivity : ScrollActivity { |
|||
public IdleScrollActivity(ScrollActivityDelegate @delegate) : base(@delegate) { |
|||
} |
|||
|
|||
public override void applyNewDimensions() { |
|||
this.@delegate.goBallistic(0.0); |
|||
} |
|||
|
|||
public override bool shouldIgnorePointer { |
|||
get { return false; } |
|||
} |
|||
|
|||
public override bool isScrolling { |
|||
get { return false; } |
|||
} |
|||
|
|||
public override double velocity { |
|||
get { return 0.0; } |
|||
} |
|||
} |
|||
|
|||
public interface ScrollHoldController { |
|||
void cancel(); |
|||
} |
|||
|
|||
public class HoldScrollActivity : ScrollActivity, ScrollHoldController { |
|||
public HoldScrollActivity( |
|||
ScrollActivityDelegate @delegate = null, |
|||
VoidCallback onHoldCanceled = null |
|||
) : base(@delegate) { |
|||
this.onHoldCanceled = onHoldCanceled; |
|||
} |
|||
|
|||
public readonly VoidCallback onHoldCanceled; |
|||
|
|||
public override bool shouldIgnorePointer { |
|||
get { return false; } |
|||
} |
|||
|
|||
public override bool isScrolling { |
|||
get { return false; } |
|||
} |
|||
|
|||
public override double velocity { |
|||
get { return 0.0; } |
|||
} |
|||
|
|||
public void cancel() { |
|||
this.@delegate.goBallistic(0.0); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
if (this.onHoldCanceled != null) |
|||
this.onHoldCanceled(); |
|||
base.dispose(); |
|||
} |
|||
} |
|||
|
|||
public class ScrollDragController : Drag { |
|||
public ScrollDragController( |
|||
ScrollActivityDelegate @delegate = null, |
|||
DragStartDetails details = null, |
|||
VoidCallback onDragCanceled = null, |
|||
double? carriedVelocity = null, |
|||
double? motionStartDistanceThreshold = null |
|||
) { |
|||
D.assert(@delegate != null); |
|||
D.assert(details != null); |
|||
D.assert( |
|||
motionStartDistanceThreshold == null || motionStartDistanceThreshold > 0.0, |
|||
"motionStartDistanceThreshold must be a positive number or null" |
|||
); |
|||
|
|||
this._delegate = @delegate; |
|||
this._lastDetails = details; |
|||
this._retainMomentum = carriedVelocity != null && carriedVelocity != 0.0; |
|||
this._lastNonStationaryTimestamp = details.sourceTimeStamp; |
|||
this._offsetSinceLastStop = motionStartDistanceThreshold == null ? (double?) null : 0.0; |
|||
|
|||
this.onDragCanceled = onDragCanceled; |
|||
this.carriedVelocity = carriedVelocity; |
|||
this.motionStartDistanceThreshold = motionStartDistanceThreshold; |
|||
} |
|||
|
|||
public ScrollActivityDelegate @delegate { |
|||
get { return this._delegate; } |
|||
} |
|||
|
|||
ScrollActivityDelegate _delegate; |
|||
|
|||
public readonly VoidCallback onDragCanceled; |
|||
|
|||
public readonly double? carriedVelocity; |
|||
|
|||
public readonly double? motionStartDistanceThreshold; |
|||
|
|||
DateTime _lastNonStationaryTimestamp; |
|||
|
|||
bool _retainMomentum; |
|||
|
|||
double? _offsetSinceLastStop; |
|||
|
|||
public static readonly TimeSpan momentumRetainStationaryDurationThreshold = new TimeSpan(0, 0, 0, 0, 20); |
|||
|
|||
public static readonly TimeSpan motionStoppedDurationThreshold = new TimeSpan(0, 0, 0, 0, 50); |
|||
|
|||
const double _bigThresholdBreakDistance = 24.0; |
|||
|
|||
bool _reversed { |
|||
get { return AxisUtils.axisDirectionIsReversed(this.@delegate.axisDirection); } |
|||
} |
|||
|
|||
public void updateDelegate(ScrollActivityDelegate value) { |
|||
D.assert(this._delegate != value); |
|||
this._delegate = value; |
|||
} |
|||
|
|||
void _maybeLoseMomentum(double offset, DateTime? timestamp) { |
|||
if (this._retainMomentum && |
|||
offset == 0.0 && |
|||
(timestamp == null || |
|||
timestamp - this._lastNonStationaryTimestamp > momentumRetainStationaryDurationThreshold)) { |
|||
this._retainMomentum = false; |
|||
} |
|||
} |
|||
|
|||
double _adjustForScrollStartThreshold(double offset, DateTime? timestamp) { |
|||
if (timestamp == null) { |
|||
return offset; |
|||
} |
|||
|
|||
if (offset == 0.0) { |
|||
if (this.motionStartDistanceThreshold != null && |
|||
this._offsetSinceLastStop == null && |
|||
timestamp - this._lastNonStationaryTimestamp > motionStoppedDurationThreshold) { |
|||
this._offsetSinceLastStop = 0.0; |
|||
} |
|||
|
|||
return 0.0; |
|||
} else { |
|||
if (this._offsetSinceLastStop == null) { |
|||
return offset; |
|||
} else { |
|||
this._offsetSinceLastStop += offset; |
|||
if (this._offsetSinceLastStop.Value.abs() > this.motionStartDistanceThreshold) { |
|||
this._offsetSinceLastStop = null; |
|||
if (offset.abs() > _bigThresholdBreakDistance) { |
|||
return offset; |
|||
} else { |
|||
return Math.Min( |
|||
this.motionStartDistanceThreshold.Value / 3.0, |
|||
offset.abs() |
|||
) * offset.sign(); |
|||
} |
|||
} else { |
|||
return 0.0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void update(DragUpdateDetails details) { |
|||
D.assert(details.primaryDelta != null); |
|||
this._lastDetails = details; |
|||
double offset = details.primaryDelta.Value; |
|||
if (offset != 0.0) { |
|||
this._lastNonStationaryTimestamp = details.sourceTimeStamp; |
|||
} |
|||
|
|||
this._maybeLoseMomentum(offset, details.sourceTimeStamp); |
|||
offset = this._adjustForScrollStartThreshold(offset, details.sourceTimeStamp); |
|||
if (offset == 0.0) { |
|||
return; |
|||
} |
|||
|
|||
if (this._reversed) { |
|||
offset = -offset; |
|||
} |
|||
|
|||
this.@delegate.applyUserOffset(offset); |
|||
} |
|||
|
|||
public void end(DragEndDetails details) { |
|||
D.assert(details.primaryVelocity != null); |
|||
double velocity = -details.primaryVelocity.Value; |
|||
if (this._reversed) { |
|||
velocity = -velocity; |
|||
} |
|||
|
|||
this._lastDetails = details; |
|||
|
|||
if (this._retainMomentum && velocity.sign() == this.carriedVelocity.Value.sign()) { |
|||
velocity += this.carriedVelocity.Value; |
|||
} |
|||
|
|||
this.@delegate.goBallistic(velocity); |
|||
} |
|||
|
|||
public void cancel() { |
|||
this.@delegate.goBallistic(0.0); |
|||
} |
|||
|
|||
public virtual void dispose() { |
|||
this._lastDetails = null; |
|||
if (this.onDragCanceled != null) { |
|||
this.onDragCanceled(); |
|||
} |
|||
} |
|||
|
|||
public object lastDetails { |
|||
get { return this._lastDetails; } |
|||
} |
|||
|
|||
object _lastDetails; |
|||
|
|||
public override string ToString() { |
|||
return Diagnostics.describeIdentity(this); |
|||
} |
|||
} |
|||
|
|||
public class DragScrollActivity : ScrollActivity { |
|||
public DragScrollActivity( |
|||
ScrollActivityDelegate @delegate, |
|||
ScrollDragController controller |
|||
) : base(@delegate) { |
|||
this._controller = controller; |
|||
} |
|||
|
|||
ScrollDragController _controller; |
|||
|
|||
public override void dispatchScrollStartNotification(ScrollMetrics metrics, BuildContext context) { |
|||
object lastDetails = this._controller.lastDetails; |
|||
D.assert(lastDetails is DragStartDetails); |
|||
new ScrollStartNotification(metrics: metrics, context: context, dragDetails: (DragStartDetails) lastDetails) |
|||
.dispatch(context); |
|||
} |
|||
|
|||
public override void dispatchScrollUpdateNotification(ScrollMetrics metrics, BuildContext context, |
|||
double scrollDelta) { |
|||
object lastDetails = this._controller.lastDetails; |
|||
D.assert(lastDetails is DragUpdateDetails); |
|||
new ScrollUpdateNotification(metrics: metrics, context: context, scrollDelta: scrollDelta, |
|||
dragDetails: (DragUpdateDetails) lastDetails).dispatch(context); |
|||
} |
|||
|
|||
public override void dispatchOverscrollNotification(ScrollMetrics metrics, BuildContext context, |
|||
double overscroll) { |
|||
object lastDetails = this._controller.lastDetails; |
|||
D.assert(lastDetails is DragUpdateDetails); |
|||
new OverscrollNotification(metrics: metrics, context: context, overscroll: overscroll, |
|||
dragDetails: (DragUpdateDetails) lastDetails).dispatch(context); |
|||
} |
|||
|
|||
public override void dispatchScrollEndNotification(ScrollMetrics metrics, BuildContext context) { |
|||
object lastDetails = this._controller.lastDetails; |
|||
new ScrollEndNotification( |
|||
metrics: metrics, |
|||
context: context, |
|||
dragDetails: lastDetails is DragEndDetails ? (DragEndDetails) lastDetails : null |
|||
).dispatch(context); |
|||
} |
|||
|
|||
public override bool shouldIgnorePointer { |
|||
get { return true; } |
|||
} |
|||
|
|||
public override bool isScrolling { |
|||
get { return true; } |
|||
} |
|||
|
|||
public override double velocity { |
|||
get { return 0.0; } |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._controller = null; |
|||
base.dispose(); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1})", Diagnostics.describeIdentity(this), this._controller); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6f4554d0588f42cfbef25f404ead887a |
|||
timeCreated: 1536667809 |
|
|||
using UIWidgets.painting; |
|||
using UIWidgets.scheduler; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public interface ScrollContext { |
|||
BuildContext notificationContext { get; } |
|||
|
|||
BuildContext storageContext { get; } |
|||
|
|||
TickerProvider vsync { get; } |
|||
|
|||
AxisDirection axisDirection { get; } |
|||
|
|||
void setIgnorePointer(bool value); |
|||
|
|||
void setCanDrag(bool value); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ffa0043fe4ac45479630806085f547a9 |
|||
timeCreated: 1536670059 |
|
|||
using System; |
|||
using UIWidgets.painting; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public interface ScrollMetrics { |
|||
double minScrollExtent { get; } |
|||
|
|||
double maxScrollExtent { get; } |
|||
|
|||
double pixels { get; } |
|||
|
|||
double viewportDimension { get; } |
|||
|
|||
AxisDirection axisDirection { get; } |
|||
} |
|||
|
|||
public static class ScrollMetricsUtils { |
|||
public static Axis axis(this ScrollMetrics it) { |
|||
return AxisUtils.axisDirectionToAxis(it.axisDirection); |
|||
} |
|||
|
|||
public static bool outOfRange(this ScrollMetrics it) { |
|||
return it.pixels < it.minScrollExtent || it.pixels > it.maxScrollExtent; |
|||
} |
|||
|
|||
public static bool atEdge(this ScrollMetrics it) { |
|||
return it.pixels == it.minScrollExtent || it.pixels == it.maxScrollExtent; |
|||
} |
|||
|
|||
public static double extentBefore(this ScrollMetrics it) { |
|||
return Math.Max(it.pixels - it.minScrollExtent, 0.0); |
|||
} |
|||
|
|||
public static double extentInside(this ScrollMetrics it) { |
|||
return Math.Min(it.pixels, it.maxScrollExtent) - |
|||
Math.Max(it.pixels, it.minScrollExtent) + |
|||
Math.Min(it.viewportDimension, it.maxScrollExtent - it.minScrollExtent); |
|||
} |
|||
|
|||
public static double extentAfter(this ScrollMetrics it) { |
|||
return Math.Max(it.maxScrollExtent - it.pixels, 0.0); |
|||
} |
|||
} |
|||
|
|||
public class FixedScrollMetrics : ScrollMetrics { |
|||
public FixedScrollMetrics( |
|||
double minScrollExtent = 0.0, |
|||
double maxScrollExtent = 0.0, |
|||
double pixels = 0.0, |
|||
double viewportDimension = 0.0, |
|||
AxisDirection axisDirection = AxisDirection.down |
|||
) { |
|||
this.minScrollExtent = minScrollExtent; |
|||
this.maxScrollExtent = maxScrollExtent; |
|||
this.pixels = pixels; |
|||
this.viewportDimension = viewportDimension; |
|||
this.axisDirection = axisDirection; |
|||
} |
|||
|
|||
public double minScrollExtent { get; private set; } |
|||
|
|||
public double maxScrollExtent { get; private set; } |
|||
|
|||
public double pixels { get; private set; } |
|||
|
|||
public double viewportDimension { get; private set; } |
|||
|
|||
public AxisDirection axisDirection { get; private set; } |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1:F1})..[{2:F1}]..{3:F1})", |
|||
this.GetType(), this.extentBefore(), this.extentInside(), this.extentAfter()); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 25e09958cead4597adacd8c3dbf7b12f |
|||
timeCreated: 1536561228 |
|
|||
using System.Collections.Generic; |
|||
using UIWidgets.gestures; |
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public abstract class ScrollNotification : ViewportNotificationMixinLayoutChangedNotification { |
|||
protected ScrollNotification( |
|||
ScrollMetrics metrics = null, |
|||
BuildContext context = null |
|||
) { |
|||
this.metrics = metrics; |
|||
this.context = context; |
|||
} |
|||
|
|||
public readonly ScrollMetrics metrics; |
|||
|
|||
public readonly BuildContext context; |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(this.metrics.ToString()); |
|||
} |
|||
|
|||
public static bool defaultScrollNotificationPredicate(ScrollNotification notification) { |
|||
return notification.depth == 0; |
|||
} |
|||
} |
|||
|
|||
public class ScrollStartNotification : ScrollNotification { |
|||
public ScrollStartNotification( |
|||
ScrollMetrics metrics = null, |
|||
BuildContext context = null, |
|||
DragStartDetails dragDetails = null |
|||
) : base(metrics: metrics, context: context) { |
|||
this.dragDetails = dragDetails; |
|||
} |
|||
|
|||
public readonly DragStartDetails dragDetails; |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
if (this.dragDetails != null) |
|||
description.Add(this.dragDetails.ToString()); |
|||
} |
|||
} |
|||
|
|||
public class ScrollUpdateNotification : ScrollNotification { |
|||
public ScrollUpdateNotification( |
|||
ScrollMetrics metrics = null, |
|||
BuildContext context = null, |
|||
DragUpdateDetails dragDetails = null, |
|||
double scrollDelta = 0 |
|||
) : base(metrics: metrics, context: context) { |
|||
this.dragDetails = dragDetails; |
|||
this.scrollDelta = scrollDelta; |
|||
} |
|||
|
|||
public readonly DragUpdateDetails dragDetails; |
|||
|
|||
public readonly double scrollDelta; |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(string.Format("scrollDelta: {0}", this.scrollDelta)); |
|||
if (this.dragDetails != null) { |
|||
description.Add(this.dragDetails.ToString()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class OverscrollNotification : ScrollNotification { |
|||
public OverscrollNotification( |
|||
ScrollMetrics metrics = null, |
|||
BuildContext context = null, |
|||
DragUpdateDetails dragDetails = null, |
|||
double overscroll = 0, |
|||
double velocity = 0 |
|||
) : base(metrics: metrics, context: context) { |
|||
this.dragDetails = dragDetails; |
|||
this.overscroll = overscroll; |
|||
this.velocity = velocity; |
|||
} |
|||
|
|||
public readonly DragUpdateDetails dragDetails; |
|||
|
|||
public readonly double overscroll; |
|||
|
|||
public readonly double velocity; |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(string.Format("overscroll: {0:F1}", this.overscroll)); |
|||
description.Add(string.Format("velocity: {0:F1}", this.velocity)); |
|||
if (this.dragDetails != null) { |
|||
description.Add(this.dragDetails.ToString()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class ScrollEndNotification : ScrollNotification { |
|||
public ScrollEndNotification( |
|||
ScrollMetrics metrics = null, |
|||
BuildContext context = null, |
|||
DragEndDetails dragDetails = null, |
|||
double overscroll = 0, |
|||
double velocity = 0 |
|||
) : base(metrics: metrics, context: context) { |
|||
this.dragDetails = dragDetails; |
|||
} |
|||
|
|||
public readonly DragEndDetails dragDetails; |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
if (this.dragDetails != null) { |
|||
description.Add(this.dragDetails.ToString()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class UserScrollNotification : ScrollNotification { |
|||
public UserScrollNotification( |
|||
ScrollMetrics metrics = null, |
|||
BuildContext context = null, |
|||
ScrollDirection direction = ScrollDirection.idle |
|||
) : base(metrics: metrics, context: context) { |
|||
this.direction = direction; |
|||
} |
|||
|
|||
public readonly ScrollDirection direction; |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(string.Format("direction: {0}", this.direction)); |
|||
} |
|||
} |
|||
|
|||
public delegate bool ScrollNotificationPredicate(ScrollNotification notification); |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 76d5830e8d5948e8a312ac1699cbfcb1 |
|||
timeCreated: 1536583483 |
|
|||
using System.Collections.Generic; |
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
|
|||
|
|||
public abstract class ViewportNotificationMixinNotification : Notification { |
|||
public int depth { |
|||
get { return _depth; } |
|||
} |
|||
|
|||
int _depth = 0; |
|||
|
|||
protected override bool visitAncestor(Element element) { |
|||
if (element is RenderObjectElement && element.renderObject is RenderAbstractViewport) { |
|||
this._depth += 1; |
|||
} |
|||
|
|||
return base.visitAncestor(element); |
|||
} |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(string.Format("depth: {0} ({1})", |
|||
this._depth, this._depth == 0 ? "local" : "remote")); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
public abstract class ViewportNotificationMixinLayoutChangedNotification : LayoutChangedNotification { |
|||
public int depth { |
|||
get { return _depth; } |
|||
} |
|||
|
|||
int _depth = 0; |
|||
|
|||
protected override bool visitAncestor(Element element) { |
|||
if (element is RenderObjectElement && element.renderObject is RenderAbstractViewport) { |
|||
this._depth += 1; |
|||
} |
|||
|
|||
return base.visitAncestor(element); |
|||
} |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(string.Format("depth: {0} ({1})", |
|||
this._depth, this._depth == 0 ? "local" : "remote")); |
|||
} |
|||
} |
|||
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 76fcf9dfb96bf49579e29af4f80c2d52 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
{% macro ViewportNotificationMixin(with) %} |
|||
public abstract class ViewportNotificationMixin{{with}} : {{with}} { |
|||
public int depth { |
|||
get { return _depth; } |
|||
} |
|||
|
|||
int _depth = 0; |
|||
|
|||
protected override bool visitAncestor(Element element) { |
|||
if (element is RenderObjectElement && element.renderObject is RenderAbstractViewport) { |
|||
this._depth += 1; |
|||
} |
|||
|
|||
return base.visitAncestor(element); |
|||
} |
|||
|
|||
protected override void debugFillDescription(List<string> description) { |
|||
base.debugFillDescription(description); |
|||
description.Add(string.Format("depth: {0} ({1})", |
|||
this._depth, this._depth == 0 ? "local" : "remote")); |
|||
} |
|||
} |
|||
{% endmacro %} |
|||
|
|||
{{ ViewportNotificationMixin('Notification') }} |
|||
|
|||
{{ ViewportNotificationMixin('LayoutChangedNotification') }} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 50050e438a664e30957959a7a1da310c |
|||
timeCreated: 1536583983 |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.gestures; |
|||
using UIWidgets.physics; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class ScrollPhysics { |
|||
public ScrollPhysics(ScrollPhysics parent) { |
|||
this.parent = parent; |
|||
} |
|||
|
|||
public readonly ScrollPhysics parent; |
|||
|
|||
protected ScrollPhysics buildParent(ScrollPhysics ancestor) { |
|||
if (this.parent == null) { |
|||
return ancestor; |
|||
} |
|||
|
|||
return this.parent.applyTo(ancestor) ?? ancestor; |
|||
} |
|||
|
|||
public virtual ScrollPhysics applyTo(ScrollPhysics ancestor) { |
|||
return new ScrollPhysics(parent: this.buildParent(ancestor)); |
|||
} |
|||
|
|||
public virtual double applyPhysicsToUserOffset(ScrollMetrics position, double offset) { |
|||
if (this.parent == null) { |
|||
return offset; |
|||
} |
|||
|
|||
return this.parent.applyPhysicsToUserOffset(position, offset); |
|||
} |
|||
|
|||
public virtual bool shouldAcceptUserOffset(ScrollMetrics position) { |
|||
if (this.parent == null) { |
|||
return position.pixels != 0.0 || position.minScrollExtent != position.maxScrollExtent; |
|||
} |
|||
|
|||
return this.parent.shouldAcceptUserOffset(position); |
|||
} |
|||
|
|||
public virtual double applyBoundaryConditions(ScrollMetrics position, double value) { |
|||
if (this.parent == null) { |
|||
return 0.0; |
|||
} |
|||
|
|||
return this.parent.applyBoundaryConditions(position, value); |
|||
} |
|||
|
|||
public virtual Simulation createBallisticSimulation(ScrollMetrics position, double velocity) { |
|||
if (parent == null) { |
|||
return null; |
|||
} |
|||
|
|||
return this.parent.createBallisticSimulation(position, velocity); |
|||
} |
|||
|
|||
static readonly SpringDescription _kDefaultSpring = SpringDescription.withDampingRatio( |
|||
mass: 0.5, |
|||
stiffness: 100.0, |
|||
ratio: 1.1 |
|||
); |
|||
|
|||
public virtual SpringDescription spring { |
|||
get { |
|||
if (this.parent == null) { |
|||
return ScrollPhysics._kDefaultSpring; |
|||
} |
|||
|
|||
return this.parent.spring ?? _kDefaultSpring; |
|||
} |
|||
} |
|||
|
|||
// todo: Handle the case of the device pixel ratio changing. use 1 as devicePixelRatio for now.
|
|||
static readonly Tolerance _kDefaultTolerance = new Tolerance( |
|||
velocity: 1.0 / (0.050 * 1), |
|||
distance: 1.0 / 1 |
|||
); |
|||
|
|||
public virtual Tolerance tolerance { |
|||
get { |
|||
if (this.parent == null) { |
|||
return _kDefaultTolerance; |
|||
} |
|||
|
|||
return this.parent.tolerance ?? _kDefaultTolerance; |
|||
} |
|||
} |
|||
|
|||
public virtual double minFlingDistance { |
|||
get { |
|||
if (this.parent == null) { |
|||
return Constants.kTouchSlop; |
|||
} |
|||
|
|||
return this.parent.minFlingDistance; |
|||
} |
|||
} |
|||
|
|||
public virtual double carriedMomentum(double existingVelocity) { |
|||
if (this.parent == null) { |
|||
return 0.0; |
|||
} |
|||
|
|||
return this.parent.carriedMomentum(existingVelocity); |
|||
} |
|||
|
|||
public virtual double minFlingVelocity { |
|||
get { |
|||
if (this.parent == null) { |
|||
return Constants.kMinFlingVelocity; |
|||
} |
|||
|
|||
return this.parent.minFlingVelocity; |
|||
} |
|||
} |
|||
|
|||
public virtual double maxFlingVelocity { |
|||
get { |
|||
if (this.parent == null) { |
|||
return Constants.kMaxFlingVelocity; |
|||
} |
|||
|
|||
return this.parent.maxFlingVelocity; |
|||
} |
|||
} |
|||
|
|||
public virtual double dragStartDistanceMotionThreshold { |
|||
get { |
|||
if (this.parent == null) { |
|||
return 0.0; |
|||
} |
|||
|
|||
return this.parent.dragStartDistanceMotionThreshold; |
|||
} |
|||
} |
|||
|
|||
public virtual bool allowImplicitScrolling { |
|||
get { return true; } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
if (this.parent == null) { |
|||
return string.Format("{0}", this.GetType()); |
|||
} |
|||
|
|||
return string.Format("{0} -> {1}", this.GetType(), this.parent); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class BouncingScrollPhysics : ScrollPhysics { |
|||
public BouncingScrollPhysics(ScrollPhysics parent = null) : base(parent: parent) { |
|||
} |
|||
|
|||
public override ScrollPhysics applyTo(ScrollPhysics ancestor) { |
|||
return new BouncingScrollPhysics(parent: this.buildParent(ancestor)); |
|||
} |
|||
|
|||
public double frictionFactor(double overscrollFraction) { |
|||
return 0.52 * Math.Pow(1 - overscrollFraction, 2); |
|||
} |
|||
|
|||
public override double applyPhysicsToUserOffset(ScrollMetrics position, double offset) { |
|||
D.assert(position.minScrollExtent <= position.maxScrollExtent); |
|||
|
|||
if (!position.outOfRange()) { |
|||
return offset; |
|||
} |
|||
|
|||
double overscrollPastStart = Math.Max(position.minScrollExtent - position.pixels, 0.0); |
|||
double overscrollPastEnd = Math.Max(position.pixels - position.maxScrollExtent, 0.0); |
|||
double overscrollPast = Math.Max(overscrollPastStart, overscrollPastEnd); |
|||
bool easing = (overscrollPastStart > 0.0 && offset < 0.0) || (overscrollPastEnd > 0.0 && offset > 0.0); |
|||
|
|||
double friction = easing |
|||
? this.frictionFactor((overscrollPast - offset.abs()) / position.viewportDimension) |
|||
: this.frictionFactor(overscrollPast / position.viewportDimension); |
|||
double direction = offset.sign(); |
|||
|
|||
return direction * _applyFriction(overscrollPast, offset.abs(), friction); |
|||
} |
|||
|
|||
static double _applyFriction(double extentOutside, double absDelta, double gamma) { |
|||
D.assert(absDelta > 0); |
|||
double total = 0.0; |
|||
if (extentOutside > 0) { |
|||
double deltaToLimit = extentOutside / gamma; |
|||
if (absDelta < deltaToLimit) { |
|||
return absDelta * gamma; |
|||
} |
|||
|
|||
total += extentOutside; |
|||
absDelta -= deltaToLimit; |
|||
} |
|||
|
|||
return total + absDelta; |
|||
} |
|||
|
|||
public override double applyBoundaryConditions(ScrollMetrics position, double value) { |
|||
return 0.0; |
|||
} |
|||
|
|||
public override Simulation createBallisticSimulation(ScrollMetrics position, double velocity) { |
|||
Tolerance tolerance = this.tolerance; |
|||
if (velocity.abs() >= tolerance.velocity || position.outOfRange()) { |
|||
return new BouncingScrollSimulation( |
|||
spring: spring, |
|||
position: position.pixels, |
|||
velocity: velocity * 0.91, |
|||
leadingExtent: position.minScrollExtent, |
|||
trailingExtent: position.maxScrollExtent, |
|||
tolerance: tolerance |
|||
); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public override double minFlingVelocity { |
|||
get { return Constants.kMinFlingVelocity * 2.0; } |
|||
} |
|||
|
|||
public override double carriedMomentum(double existingVelocity) { |
|||
return existingVelocity.sign() * Math.Min(0.000816 * Math.Pow(existingVelocity.abs(), 1.967), 40000.0); |
|||
} |
|||
|
|||
public override double dragStartDistanceMotionThreshold { |
|||
get { return 3.5; } |
|||
} |
|||
} |
|||
|
|||
|
|||
public class ClampingScrollPhysics : ScrollPhysics { |
|||
public ClampingScrollPhysics(ScrollPhysics parent = null) : base(parent: parent) { |
|||
} |
|||
|
|||
public override ScrollPhysics applyTo(ScrollPhysics ancestor) { |
|||
return new ClampingScrollPhysics(parent: this.buildParent(ancestor)); |
|||
} |
|||
|
|||
public override double applyBoundaryConditions(ScrollMetrics position, double value) { |
|||
D.assert(() => { |
|||
if (value == position.pixels) { |
|||
throw new UIWidgetsError( |
|||
string.Format( |
|||
"{0}.applyBoundaryConditions() was called redundantly.\n" + |
|||
"The proposed new position, {1}, is exactly equal to the current position of the " + |
|||
"given {2}, {3}.\n" + |
|||
"The applyBoundaryConditions method should only be called when the value is " + |
|||
"going to actually change the pixels, otherwise it is redundant.\n" + |
|||
"The physics object in question was:\n" + |
|||
" {4}\n" + |
|||
"The position object in question was:\n" + |
|||
" {5}\n", |
|||
this.GetType(), value, position.GetType(), position.pixels, this, position)); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
if (value < position.pixels && position.pixels <= position.minScrollExtent) { |
|||
return value - position.pixels; |
|||
} |
|||
|
|||
if (position.maxScrollExtent <= position.pixels && position.pixels < value) { |
|||
return value - position.pixels; |
|||
} |
|||
|
|||
if (value < position.minScrollExtent && position.minScrollExtent < position.pixels) { |
|||
return value - position.minScrollExtent; |
|||
} |
|||
|
|||
if (position.pixels < position.maxScrollExtent && position.maxScrollExtent < value) { |
|||
return value - position.maxScrollExtent; |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
public override Simulation createBallisticSimulation(ScrollMetrics position, double velocity) { |
|||
Tolerance tolerance = this.tolerance; |
|||
if (position.outOfRange()) { |
|||
double? end = null; |
|||
if (position.pixels > position.maxScrollExtent) { |
|||
end = position.maxScrollExtent; |
|||
} |
|||
|
|||
if (position.pixels < position.minScrollExtent) { |
|||
end = position.minScrollExtent; |
|||
} |
|||
|
|||
D.assert(end != null); |
|||
return new ScrollSpringSimulation( |
|||
this.spring, |
|||
position.pixels, |
|||
position.maxScrollExtent, |
|||
Math.Min(0.0, velocity), |
|||
tolerance: tolerance |
|||
); |
|||
} |
|||
|
|||
if (velocity.abs() < tolerance.velocity) { |
|||
return null; |
|||
} |
|||
|
|||
if (velocity > 0.0 && position.pixels >= position.maxScrollExtent) { |
|||
return null; |
|||
} |
|||
|
|||
if (velocity < 0.0 && position.pixels <= position.minScrollExtent) { |
|||
return null; |
|||
} |
|||
|
|||
return new ClampingScrollSimulation( |
|||
position: position.pixels, |
|||
velocity: velocity, |
|||
tolerance: tolerance |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class AlwaysScrollableScrollPhysics : ScrollPhysics { |
|||
public AlwaysScrollableScrollPhysics(ScrollPhysics parent = null) : base(parent: parent) { |
|||
} |
|||
|
|||
public override ScrollPhysics applyTo(ScrollPhysics ancestor) { |
|||
return new AlwaysScrollableScrollPhysics(parent: this.buildParent(ancestor)); |
|||
} |
|||
|
|||
public override bool shouldAcceptUserOffset(ScrollMetrics position) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
public class NeverScrollableScrollPhysics : ScrollPhysics { |
|||
public NeverScrollableScrollPhysics(ScrollPhysics parent = null) : base(parent: parent) { |
|||
} |
|||
|
|||
public override ScrollPhysics applyTo(ScrollPhysics ancestor) { |
|||
return new NeverScrollableScrollPhysics(parent: this.buildParent(ancestor)); |
|||
} |
|||
|
|||
public override bool shouldAcceptUserOffset(ScrollMetrics position) { |
|||
return false; |
|||
} |
|||
|
|||
public override bool allowImplicitScrolling { |
|||
get { return false; } |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f58c175eda22408f95d902db1c4eec03 |
|||
timeCreated: 1536563659 |
|
|||
using UIWidgets.rendering; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
// public abstract class ScrollPosition : ViewportOffset, ScrollMetrics {
|
|||
//
|
|||
// }
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: d1ce64af14b4434b8850b299aae20240 |
|||
timeCreated: 1536563588 |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.physics; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.widgets { |
|||
public class BouncingScrollSimulation : Simulation { |
|||
public BouncingScrollSimulation( |
|||
double position, |
|||
double velocity, |
|||
double leadingExtent, |
|||
double trailingExtent, |
|||
SpringDescription spring, |
|||
Tolerance tolerance = null |
|||
) : base(tolerance: tolerance) { |
|||
D.assert(leadingExtent <= trailingExtent); |
|||
D.assert(spring != null); |
|||
|
|||
this.leadingExtent = leadingExtent; |
|||
this.trailingExtent = trailingExtent; |
|||
this.spring = spring; |
|||
|
|||
if (position < leadingExtent) { |
|||
this._springSimulation = this._underscrollSimulation(position, velocity); |
|||
this._springTime = double.NegativeInfinity; |
|||
} else if (position > trailingExtent) { |
|||
this._springSimulation = this._overscrollSimulation(position, velocity); |
|||
this._springTime = double.NegativeInfinity; |
|||
} else { |
|||
this._frictionSimulation = new FrictionSimulation(0.135, position, velocity); |
|||
double finalX = this._frictionSimulation.finalX; |
|||
if (velocity > 0.0 && finalX > trailingExtent) { |
|||
this._springTime = this._frictionSimulation.timeAtX(trailingExtent); |
|||
this._springSimulation = this._overscrollSimulation( |
|||
trailingExtent, |
|||
Math.Min(this._frictionSimulation.dx(this._springTime), maxSpringTransferVelocity) |
|||
); |
|||
D.assert(this._springTime.isFinite()); |
|||
} else if (velocity < 0.0 && finalX < leadingExtent) { |
|||
this._springTime = this._frictionSimulation.timeAtX(leadingExtent); |
|||
this._springSimulation = this._underscrollSimulation( |
|||
leadingExtent, |
|||
Math.Min(this._frictionSimulation.dx(this._springTime), maxSpringTransferVelocity) |
|||
); |
|||
D.assert(this._springTime.isFinite()); |
|||
} else { |
|||
this._springTime = double.PositiveInfinity; |
|||
} |
|||
} |
|||
} |
|||
|
|||
const double maxSpringTransferVelocity = 5000.0; |
|||
|
|||
public readonly double leadingExtent; |
|||
|
|||
public readonly double trailingExtent; |
|||
|
|||
public readonly SpringDescription spring; |
|||
|
|||
readonly FrictionSimulation _frictionSimulation; |
|||
readonly Simulation _springSimulation; |
|||
readonly double _springTime; |
|||
double _timeOffset = 0.0; |
|||
|
|||
Simulation _underscrollSimulation(double x, double dx) { |
|||
return new ScrollSpringSimulation(this.spring, x, this.leadingExtent, dx); |
|||
} |
|||
|
|||
Simulation _overscrollSimulation(double x, double dx) { |
|||
return new ScrollSpringSimulation(this.spring, x, this.trailingExtent, dx); |
|||
} |
|||
|
|||
Simulation _simulation(double time) { |
|||
Simulation simulation; |
|||
if (time > this._springTime) { |
|||
this._timeOffset = this._springTime.isFinite() ? this._springTime : 0.0; |
|||
simulation = this._springSimulation; |
|||
} else { |
|||
this._timeOffset = 0.0; |
|||
simulation = this._frictionSimulation; |
|||
} |
|||
|
|||
simulation.tolerance = this.tolerance; |
|||
return simulation; |
|||
} |
|||
|
|||
public override double x(double time) { |
|||
return this._simulation(time).x(time - this._timeOffset); |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
return this._simulation(time).dx(time - this._timeOffset); |
|||
} |
|||
|
|||
public override bool isDone(double time) { |
|||
return this._simulation(time).isDone(time - this._timeOffset); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}(leadingExtent: {1}, trailingExtent: {2})", |
|||
this.GetType(), this.leadingExtent, this.trailingExtent); |
|||
} |
|||
} |
|||
|
|||
public class ClampingScrollSimulation : Simulation { |
|||
public ClampingScrollSimulation( |
|||
double position, |
|||
double velocity, |
|||
double friction = 0.015, |
|||
Tolerance tolerance = null |
|||
) : base(tolerance: tolerance) { |
|||
D.assert(_flingVelocityPenetration(0.0) == _initialVelocityPenetration); |
|||
this.position = position; |
|||
this.velocity = velocity; |
|||
this.friction = friction; |
|||
|
|||
this._duration = this._flingDuration(velocity); |
|||
this._distance = (velocity * this._duration / _initialVelocityPenetration).abs(); |
|||
} |
|||
|
|||
public readonly double position; |
|||
|
|||
public readonly double velocity; |
|||
|
|||
public readonly double friction; |
|||
|
|||
readonly double _duration; |
|||
|
|||
readonly double _distance; |
|||
|
|||
static readonly double _kDecelerationRate = Math.Log(0.78) / Math.Log(0.9); |
|||
|
|||
static double _decelerationForFriction(double friction) { |
|||
return friction * 61774.04968; |
|||
} |
|||
|
|||
double _flingDuration(double velocity) { |
|||
double scaledFriction = this.friction * _decelerationForFriction(0.84); |
|||
|
|||
double deceleration = Math.Log(0.35 * velocity.abs() / scaledFriction); |
|||
|
|||
return Math.Exp(deceleration / (_kDecelerationRate - 1.0)); |
|||
} |
|||
|
|||
const double _initialVelocityPenetration = 3.065; |
|||
|
|||
static double _flingDistancePenetration(double t) { |
|||
return (1.2 * t * t * t) - (3.27 * t * t) + (_initialVelocityPenetration * t); |
|||
} |
|||
|
|||
static double _flingVelocityPenetration(double t) { |
|||
return (3.6 * t * t) - (6.54 * t) + _initialVelocityPenetration; |
|||
} |
|||
|
|||
public override double x(double time) { |
|||
double t = (time / this._duration).clamp(0.0, 1.0); |
|||
return this.position + this._distance * _flingDistancePenetration(t) * this.velocity.sign(); |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
double t = (time / this._duration).clamp(0.0, 1.0); |
|||
return this._distance * _flingVelocityPenetration(t) * this.velocity.sign() / this._duration; |
|||
} |
|||
|
|||
public override bool isDone(double time) { |
|||
return time >= this._duration; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c2459448f9d744ec8e3240a0e1a88754 |
|||
timeCreated: 1536573658 |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.animation { |
|||
public abstract class Curve { |
|||
public abstract double transform(double t); |
|||
|
|||
public Curve flipped { |
|||
get { return new FlippedCurve(this); } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return this.GetType().ToString(); |
|||
} |
|||
} |
|||
|
|||
class _Linear : Curve { |
|||
public override double transform(double t) { |
|||
return t; |
|||
} |
|||
} |
|||
|
|||
public class SawTooth : Curve { |
|||
public SawTooth(int count) { |
|||
this.count = count; |
|||
} |
|||
|
|||
public readonly int count; |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
if (t == 1.0) { |
|||
return 1.0; |
|||
} |
|||
|
|||
t *= this.count; |
|||
return t - (int) t; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1})", this.GetType(), this.count); |
|||
} |
|||
} |
|||
|
|||
public class Interval : Curve { |
|||
public Interval(double begin, double end, Curve curve = null) { |
|||
this.begin = begin; |
|||
this.end = end; |
|||
this.curve = curve ?? Curves.linear; |
|||
} |
|||
|
|||
public readonly double begin; |
|||
|
|||
public readonly double end; |
|||
|
|||
public readonly Curve curve; |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
D.assert(this.begin >= 0.0); |
|||
D.assert(this.begin <= 1.0); |
|||
D.assert(this.end >= 0.0); |
|||
D.assert(this.end <= 1.0); |
|||
D.assert(this.end >= this.begin); |
|||
if (t == 0.0 || t == 1.0) { |
|||
return t; |
|||
} |
|||
|
|||
t = ((t - this.begin) / (this.end - this.begin)).clamp(0.0, 1.0); |
|||
if (t == 0.0 || t == 1.0) { |
|||
return t; |
|||
} |
|||
|
|||
return this.curve.transform(t); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
if (!(this.curve is _Linear)) { |
|||
return string.Format("{0}({1}\u22EF{2}\u27A9{3}", this.GetType(), this.begin, this.end, this.curve); |
|||
} |
|||
|
|||
return string.Format("{0}({1}\u22EF{2})", this.GetType(), this.begin, this.end); |
|||
} |
|||
} |
|||
|
|||
public class Threshold : Curve { |
|||
public Threshold(double threshold) { |
|||
this.threshold = threshold; |
|||
} |
|||
|
|||
public readonly double threshold; |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
D.assert(this.threshold >= 0.0); |
|||
D.assert(this.threshold <= 1.0); |
|||
if (t == 0.0 || t == 1.0) { |
|||
return t; |
|||
} |
|||
|
|||
return t < this.threshold ? 0.0 : 1.0; |
|||
} |
|||
} |
|||
|
|||
public class Cubic : Curve { |
|||
public Cubic(double a, double b, double c, double d) { |
|||
this.a = a; |
|||
this.b = b; |
|||
this.c = c; |
|||
this.d = d; |
|||
} |
|||
|
|||
public readonly double a; |
|||
|
|||
public readonly double b; |
|||
|
|||
public readonly double c; |
|||
|
|||
public readonly double d; |
|||
|
|||
const double _cubicErrorBound = 0.001; |
|||
|
|||
double _evaluateCubic(double a, double b, double m) { |
|||
return 3 * a * (1 - m) * (1 - m) * m + |
|||
3 * b * (1 - m) * m * m + |
|||
m * m * m; |
|||
} |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
double start = 0.0; |
|||
double end = 1.0; |
|||
while (true) { |
|||
double midpoint = (start + end) / 2; |
|||
double estimate = this._evaluateCubic(this.a, this.c, midpoint); |
|||
if ((t - estimate).abs() < _cubicErrorBound) { |
|||
return this._evaluateCubic(this.b, this.d, midpoint); |
|||
} |
|||
|
|||
if (estimate < t) { |
|||
start = midpoint; |
|||
} else { |
|||
end = midpoint; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1:F2}, {2:F2}, {3:F2}, {4:F2})", this.GetType(), this.a, this.b, this.c, this.d); |
|||
} |
|||
} |
|||
|
|||
public class FlippedCurve : Curve { |
|||
public FlippedCurve(Curve curve) { |
|||
D.assert(curve != null); |
|||
this.curve = curve; |
|||
} |
|||
|
|||
public readonly Curve curve; |
|||
|
|||
public override double transform(double t) { |
|||
return 1.0 - this.curve.transform(1.0 - t); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1})", this.GetType(), this.curve); |
|||
} |
|||
} |
|||
|
|||
class _DecelerateCurve : Curve { |
|||
internal _DecelerateCurve() { |
|||
} |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
t = 1.0 - t; |
|||
return 1.0 - t * t; |
|||
} |
|||
} |
|||
|
|||
class _BounceInCurve : Curve { |
|||
internal _BounceInCurve() { |
|||
} |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
return 1.0 - Curves._bounce(1.0 - t); |
|||
} |
|||
} |
|||
|
|||
class _BounceOutCurve : Curve { |
|||
internal _BounceOutCurve() { |
|||
} |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
return Curves._bounce(t); |
|||
} |
|||
} |
|||
|
|||
class _BounceInOutCurve : Curve { |
|||
internal _BounceInOutCurve() { |
|||
} |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
if (t < 0.5) { |
|||
return (1.0 - Curves._bounce(1.0 - t)) * 0.5; |
|||
} else { |
|||
return Curves._bounce(t * 2.0 - 1.0) * 0.5 + 0.5; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class ElasticInCurve : Curve { |
|||
public ElasticInCurve(double period = 0.4) { |
|||
this.period = period; |
|||
} |
|||
|
|||
public readonly double period; |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
double s = this.period / 4.0; |
|||
t = t - 1.0; |
|||
return -Math.Pow(2.0, 10.0 * t) * Math.Sin((t - s) * (Math.PI * 2.0) / this.period); |
|||
} |
|||
|
|||
public override String ToString() { |
|||
return string.Format("{0}({1})", this.GetType(), this.period); |
|||
} |
|||
} |
|||
|
|||
public class ElasticOutCurve : Curve { |
|||
public ElasticOutCurve(double period = 0.4) { |
|||
this.period = period; |
|||
} |
|||
|
|||
public readonly double period; |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
double s = this.period / 4.0; |
|||
return Math.Pow(2.0, -10.0 * t) * Math.Sin((t - s) * (Math.PI * 2.0) / this.period) + 1.0; |
|||
} |
|||
|
|||
public override String ToString() { |
|||
return string.Format("{0}({1})", this.GetType(), this.period); |
|||
} |
|||
} |
|||
|
|||
public class ElasticInOutCurve : Curve { |
|||
public ElasticInOutCurve(double period = 0.4) { |
|||
this.period = period; |
|||
} |
|||
|
|||
public readonly double period; |
|||
|
|||
public override double transform(double t) { |
|||
D.assert(t >= 0.0 && t <= 1.0); |
|||
double s = this.period / 4.0; |
|||
t = 2.0 * t - 1.0; |
|||
if (t < 0.0) { |
|||
return -0.5 * Math.Pow(2.0, 10.0 * t) * Math.Sin((t - s) * (Math.PI * 2.0) / this.period); |
|||
} else { |
|||
return Math.Pow(2.0, -10.0 * t) * Math.Sin((t - s) * (Math.PI * 2.0) / this.period) * 0.5 + 1.0; |
|||
} |
|||
} |
|||
|
|||
public override String ToString() { |
|||
return string.Format("{0}({1})", this.GetType(), this.period); |
|||
} |
|||
} |
|||
|
|||
public static class Curves { |
|||
public static readonly Curve linear = new _Linear(); |
|||
|
|||
public static readonly Curve decelerate = new _DecelerateCurve(); |
|||
|
|||
public static readonly Curve ease = new Cubic(0.25, 0.1, 0.25, 1.0); |
|||
|
|||
public static readonly Curve easeIn = new Cubic(0.42, 0.0, 1.0, 1.0); |
|||
|
|||
public static readonly Curve easeOut = new Cubic(0.0, 0.0, 0.58, 1.0); |
|||
|
|||
public static readonly Curve easeInOut = new Cubic(0.42, 0.0, 0.58, 1.0); |
|||
|
|||
public static readonly Curve fastOutSlowIn = new Cubic(0.4, 0.0, 0.2, 1.0); |
|||
|
|||
public static readonly Curve bounceIn = new _BounceInCurve(); |
|||
|
|||
public static readonly Curve bounceOut = new _BounceOutCurve(); |
|||
|
|||
public static readonly Curve bounceInOut = new _BounceInOutCurve(); |
|||
|
|||
public static readonly Curve elasticIn = new ElasticInCurve(); |
|||
|
|||
public static readonly Curve elasticOut = new ElasticOutCurve(); |
|||
|
|||
public static readonly Curve elasticInOut = new ElasticInOutCurve(); |
|||
|
|||
internal static double _bounce(double t) { |
|||
if (t < 1.0 / 2.75) { |
|||
return 7.5625 * t * t; |
|||
} else if (t < 2 / 2.75) { |
|||
t -= 1.5 / 2.75; |
|||
return 7.5625 * t * t + 0.75; |
|||
} else if (t < 2.5 / 2.75) { |
|||
t -= 2.25 / 2.75; |
|||
return 7.5625 * t * t + 0.9375; |
|||
} |
|||
|
|||
t -= 2.625 / 2.75; |
|||
return 7.5625 * t * t + 0.984375; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: dacb0a58278b41d585c256badb6f6a5c |
|||
timeCreated: 1536727284 |
|
|||
fileFormatVersion: 2 |
|||
guid: f1417c6a32c94895b551503b8ea7a464 |
|||
timeCreated: 1536734209 |
|
|||
fileFormatVersion: 2 |
|||
guid: 6a1fb4f1aff742c98f8e4e27a03e45f2 |
|||
timeCreated: 1536728596 |
|
|||
fileFormatVersion: 2 |
|||
guid: 020ec64cb65c14f6493309339667afee |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
namespace UIWidgets.animation { |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 904fcf341bef44a191cf4674c42334a8 |
|||
timeCreated: 1536731860 |
|
|||
fileFormatVersion: 2 |
|||
guid: fc158b938e74644e0ba73d8e95247892 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 3bad423f035f41e0a5dbb75dc244a06b |
|||
timeCreated: 1536731953 |
|
|||
fileFormatVersion: 2 |
|||
guid: ca9370be0eef47e2aa0fcc3a9d4b4c46 |
|||
timeCreated: 1536728064 |
|
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.animation { |
|||
public enum AnimationStatus { |
|||
dismissed, |
|||
forward, |
|||
reverse, |
|||
completed, |
|||
} |
|||
|
|||
public delegate void AnimationStatusListener(AnimationStatus status); |
|||
|
|||
public abstract class Animation<T> : ValueListenable<T> { |
|||
public abstract void addListener(VoidCallback listener); |
|||
|
|||
public abstract void removeListener(VoidCallback listener); |
|||
|
|||
public abstract void addStatusListener(AnimationStatusListener listener); |
|||
|
|||
public abstract void removeStatusListener(AnimationStatusListener listener); |
|||
|
|||
public abstract AnimationStatus status { get; } |
|||
|
|||
public abstract T value { get; } |
|||
|
|||
public bool isDismissed { |
|||
get { return this.status == AnimationStatus.dismissed; } |
|||
} |
|||
|
|||
public bool isCompleted { |
|||
get { return this.status == AnimationStatus.completed; } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1})", Diagnostics.describeIdentity(this), this.toStringDetails()); |
|||
} |
|||
|
|||
public virtual string toStringDetails() { |
|||
string icon = null; |
|||
switch (this.status) { |
|||
case AnimationStatus.forward: |
|||
icon = "\u25B6"; // >
|
|||
break; |
|||
case AnimationStatus.reverse: |
|||
icon = "\u25C0"; // <
|
|||
break; |
|||
case AnimationStatus.completed: |
|||
icon = "\u23ED"; // >>|
|
|||
break; |
|||
case AnimationStatus.dismissed: |
|||
icon = "\u23EE"; // |<<
|
|||
break; |
|||
} |
|||
|
|||
D.assert(icon != null); |
|||
return icon; |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.physics; |
|||
using UIWidgets.scheduler; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.animation { |
|||
enum _AnimationDirection { |
|||
forward, |
|||
reverse, |
|||
} |
|||
|
|||
public class AnimationController : |
|||
AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<double> { |
|||
public AnimationController( |
|||
double? value = null, |
|||
TimeSpan? duration = null, |
|||
string debugLabel = null, |
|||
double lowerBound = 0.0, |
|||
double upperBound = 1.0, |
|||
TickerProvider vsync = null |
|||
) { |
|||
D.assert(upperBound >= lowerBound); |
|||
D.assert(vsync != null); |
|||
this._direction = _AnimationDirection.forward; |
|||
|
|||
this.duration = duration; |
|||
this.debugLabel = debugLabel; |
|||
this.lowerBound = lowerBound; |
|||
this.upperBound = upperBound; |
|||
|
|||
this._ticker = vsync.createTicker(this._tick); |
|||
this._internalSetValue(value ?? lowerBound); |
|||
} |
|||
|
|||
private AnimationController( |
|||
double value = 0.0, |
|||
TimeSpan? duration = null, |
|||
string debugLabel = null, |
|||
TickerProvider vsync = null |
|||
) { |
|||
D.assert(vsync != null); |
|||
this.lowerBound = double.NegativeInfinity; |
|||
this.upperBound = double.PositiveInfinity; |
|||
this._direction = _AnimationDirection.forward; |
|||
|
|||
this.duration = duration; |
|||
this.debugLabel = debugLabel; |
|||
|
|||
this._ticker = vsync.createTicker(this._tick); |
|||
this._internalSetValue(value); |
|||
} |
|||
|
|||
public static AnimationController unbounded( |
|||
double value = 0.0, |
|||
TimeSpan? duration = null, |
|||
string debugLabel = null, |
|||
TickerProvider vsync = null |
|||
) { |
|||
return new AnimationController(value, duration, debugLabel, vsync); |
|||
} |
|||
|
|||
public readonly double lowerBound; |
|||
|
|||
public readonly double upperBound; |
|||
|
|||
public readonly string debugLabel; |
|||
|
|||
public Animation<double> view { |
|||
get { return this; } |
|||
} |
|||
|
|||
public TimeSpan? duration; |
|||
|
|||
Ticker _ticker; |
|||
|
|||
public void resync(TickerProvider vsync) { |
|||
Ticker oldTicker = this._ticker; |
|||
this._ticker = vsync.createTicker(_tick); |
|||
this._ticker.absorbTicker(oldTicker); |
|||
} |
|||
|
|||
Simulation _simulation; |
|||
|
|||
public override double value { |
|||
get { return this._value; } |
|||
} |
|||
|
|||
double _value; |
|||
|
|||
public void setValue(double newValue) { |
|||
this.stop(); |
|||
this._internalSetValue(newValue); |
|||
this.notifyListeners(); |
|||
this._checkStatusChanged(); |
|||
} |
|||
|
|||
|
|||
public void reset() { |
|||
this.setValue(this.lowerBound); |
|||
} |
|||
|
|||
public double velocity { |
|||
get { |
|||
if (!this.isAnimating) { |
|||
return 0.0; |
|||
} |
|||
|
|||
return this._simulation.dx((double) this.lastElapsedDuration.Value.Ticks / TimeSpan.TicksPerSecond); |
|||
} |
|||
} |
|||
|
|||
void _internalSetValue(double newValue) { |
|||
this._value = newValue.clamp(this.lowerBound, this.upperBound); |
|||
if (this._value == this.lowerBound) { |
|||
this._status = AnimationStatus.dismissed; |
|||
} else if (this._value == this.upperBound) { |
|||
this._status = AnimationStatus.completed; |
|||
} else { |
|||
this._status = (this._direction == _AnimationDirection.forward) |
|||
? AnimationStatus.forward |
|||
: AnimationStatus.reverse; |
|||
} |
|||
} |
|||
|
|||
TimeSpan? lastElapsedDuration { |
|||
get { return this._lastElapsedDuration; } |
|||
} |
|||
|
|||
TimeSpan? _lastElapsedDuration; |
|||
|
|||
public bool isAnimating { |
|||
get { return this._ticker != null && this._ticker.isActive; } |
|||
} |
|||
|
|||
_AnimationDirection _direction; |
|||
|
|||
public override AnimationStatus status { |
|||
get { return this._status; } |
|||
} |
|||
|
|||
AnimationStatus _status; |
|||
|
|||
public TickerFuture forward(double? from = null) { |
|||
D.assert(() => { |
|||
if (this.duration == null) { |
|||
throw new UIWidgetsError( |
|||
"AnimationController.forward() called with no default Duration.\n" + |
|||
"The \"duration\" property should be set, either in the constructor or later, before " + |
|||
"calling the forward() function." |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
this._direction = _AnimationDirection.forward; |
|||
if (from != null) { |
|||
this.setValue(from.Value); |
|||
} |
|||
|
|||
return this._animateToInternal(this.upperBound); |
|||
} |
|||
|
|||
public TickerFuture reverse(double? from = null) { |
|||
D.assert(() => { |
|||
if (this.duration == null) { |
|||
throw new UIWidgetsError( |
|||
"AnimationController.reverse() called with no default Duration.\n" + |
|||
"The \"duration\" property should be set, either in the constructor or later, before " + |
|||
"calling the reverse() function." |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
this._direction = _AnimationDirection.reverse; |
|||
if (from != null) { |
|||
this.setValue(from.Value); |
|||
} |
|||
|
|||
return this._animateToInternal(this.lowerBound); |
|||
} |
|||
|
|||
public TickerFuture animateTo(double target, TimeSpan? duration = null, Curve curve = null) { |
|||
curve = curve ?? Curves.linear; |
|||
|
|||
this._direction = _AnimationDirection.forward; |
|||
return this._animateToInternal(target, duration: duration, curve: curve); |
|||
} |
|||
|
|||
TickerFuture _animateToInternal(double target, TimeSpan? duration = null, Curve curve = null) { |
|||
curve = curve ?? Curves.linear; |
|||
|
|||
TimeSpan? simulationDuration = duration; |
|||
if (simulationDuration == null) { |
|||
D.assert(() => { |
|||
if (this.duration == null) { |
|||
throw new UIWidgetsError( |
|||
"AnimationController.animateTo() called with no explicit Duration and no default Duration.\n" + |
|||
"Either the \"duration\" argument to the animateTo() method should be provided, or the " + |
|||
"\"duration\" property should be set, either in the constructor or later, before " + |
|||
"calling the animateTo() function." |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
double range = this.upperBound - this.lowerBound; |
|||
double remainingFraction = range.isFinite() ? (target - this._value).abs() / range : 1.0; |
|||
simulationDuration = TimeSpan.FromTicks((long) (this.duration.Value.Ticks * remainingFraction)); |
|||
} else if (target == this.value) { |
|||
simulationDuration = TimeSpan.Zero; |
|||
} |
|||
|
|||
this.stop(); |
|||
|
|||
if (simulationDuration == TimeSpan.Zero) { |
|||
if (this._value != target) { |
|||
this._value = target.clamp(this.lowerBound, this.upperBound); |
|||
this.notifyListeners(); |
|||
} |
|||
|
|||
this._status = (this._direction == _AnimationDirection.forward) |
|||
? AnimationStatus.completed |
|||
: AnimationStatus.dismissed; |
|||
this._checkStatusChanged(); |
|||
return TickerFutureImpl.complete(); |
|||
} |
|||
|
|||
D.assert(simulationDuration > TimeSpan.Zero); |
|||
D.assert(!this.isAnimating); |
|||
return this._startSimulation( |
|||
new _InterpolationSimulation(this._value, target, simulationDuration.Value, curve)); |
|||
} |
|||
|
|||
public TickerFuture repeat(double? min = null, double? max = null, TimeSpan? period = null) { |
|||
min = min ?? this.lowerBound; |
|||
max = max ?? this.upperBound; |
|||
period = period ?? this.duration; |
|||
D.assert(() => { |
|||
if (period == null) { |
|||
throw new UIWidgetsError( |
|||
"AnimationController.repeat() called without an explicit period and with no default Duration.\n" + |
|||
"Either the \"period\" argument to the repeat() method should be provided, or the " + |
|||
"\"duration\" property should be set, either in the constructor or later, before " + |
|||
"calling the repeat() function." |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
return this.animateWith(new _RepeatingSimulation(min.Value, max.Value, period.Value)); |
|||
} |
|||
|
|||
public TickerFuture fling(double velocity = 1.0) { |
|||
this._direction = velocity < 0.0 ? _AnimationDirection.reverse : _AnimationDirection.forward; |
|||
double target = velocity < 0.0 |
|||
? this.lowerBound - _kFlingTolerance.distance |
|||
: this.upperBound + _kFlingTolerance.distance; |
|||
Simulation simulation = new SpringSimulation(_kFlingSpringDescription, this.value, target, velocity); |
|||
simulation.tolerance = _kFlingTolerance; |
|||
return this.animateWith(simulation); |
|||
} |
|||
|
|||
|
|||
public TickerFuture animateWith(Simulation simulation) { |
|||
this.stop(); |
|||
return this._startSimulation(simulation); |
|||
} |
|||
|
|||
TickerFuture _startSimulation(Simulation simulation) { |
|||
D.assert(simulation != null); |
|||
D.assert(!this.isAnimating); |
|||
this._simulation = simulation; |
|||
this._lastElapsedDuration = TimeSpan.Zero; |
|||
this._value = simulation.x(0.0).clamp(this.lowerBound, this.upperBound); |
|||
var result = this._ticker.start(); |
|||
this._status = (this._direction == _AnimationDirection.forward) |
|||
? AnimationStatus.forward |
|||
: AnimationStatus.reverse; |
|||
this._checkStatusChanged(); |
|||
return result; |
|||
} |
|||
|
|||
public void stop(bool canceled = true) { |
|||
this._simulation = null; |
|||
this._lastElapsedDuration = null; |
|||
this._ticker.stop(canceled: canceled); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
D.assert(() => { |
|||
if (this._ticker == null) { |
|||
throw new UIWidgetsError( |
|||
"AnimationController.dispose() called more than once.\n" + |
|||
"A given " + this.GetType() + " cannot be disposed more than once.\n" + |
|||
"The following " + this.GetType() + " object was disposed multiple times:\n" + |
|||
" " + this); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
this._ticker.dispose(); |
|||
this._ticker = null; |
|||
base.dispose(); |
|||
} |
|||
|
|||
AnimationStatus _lastReportedStatus = AnimationStatus.dismissed; |
|||
|
|||
void _checkStatusChanged() { |
|||
AnimationStatus newStatus = this.status; |
|||
if (this._lastReportedStatus != newStatus) { |
|||
this._lastReportedStatus = newStatus; |
|||
this.notifyStatusListeners(newStatus); |
|||
} |
|||
} |
|||
|
|||
void _tick(TimeSpan elapsed) { |
|||
this._lastElapsedDuration = elapsed; |
|||
double elapsedInSeconds = (double) elapsed.Ticks / TimeSpan.TicksPerSecond; |
|||
D.assert(elapsedInSeconds >= 0.0); |
|||
this._value = this._simulation.x(elapsedInSeconds).clamp(this.lowerBound, this.upperBound); |
|||
if (this._simulation.isDone(elapsedInSeconds)) { |
|||
this._status = (this._direction == _AnimationDirection.forward) |
|||
? AnimationStatus.completed |
|||
: AnimationStatus.dismissed; |
|||
this.stop(canceled: false); |
|||
} |
|||
|
|||
this.notifyListeners(); |
|||
this._checkStatusChanged(); |
|||
} |
|||
|
|||
public override string toStringDetails() { |
|||
string paused = this.isAnimating ? "" : "; paused"; |
|||
string ticker = this._ticker == null ? "; DISPOSED" : (this._ticker.muted ? "; silenced" : ""); |
|||
string label = this.debugLabel == null ? "" : "; for " + this.debugLabel; |
|||
string more = string.Format("{0} {1:F3}", base.toStringDetails(), this.value); |
|||
return more + paused + ticker + label; |
|||
} |
|||
|
|||
static readonly SpringDescription _kFlingSpringDescription = SpringDescription.withDampingRatio( |
|||
mass: 1.0, |
|||
stiffness: 500.0, |
|||
ratio: 1.0 |
|||
); |
|||
|
|||
static readonly Tolerance _kFlingTolerance = new Tolerance( |
|||
velocity: double.PositiveInfinity, |
|||
distance: 0.01 |
|||
); |
|||
} |
|||
|
|||
|
|||
class _InterpolationSimulation : Simulation { |
|||
internal _InterpolationSimulation(double _begin, double _end, TimeSpan duration, Curve _curve) { |
|||
this._begin = _begin; |
|||
this._end = _end; |
|||
this._curve = _curve; |
|||
|
|||
D.assert(duration.Ticks > 0); |
|||
this._durationInSeconds = (double) duration.Ticks / TimeSpan.TicksPerSecond; |
|||
} |
|||
|
|||
readonly double _durationInSeconds; |
|||
readonly double _begin; |
|||
readonly double _end; |
|||
readonly Curve _curve; |
|||
|
|||
public override double x(double timeInSeconds) { |
|||
double t = (timeInSeconds / this._durationInSeconds).clamp(0.0, 1.0); |
|||
if (t == 0.0) { |
|||
return this._begin; |
|||
} else if (t == 1.0) { |
|||
return this._end; |
|||
} else { |
|||
return this._begin + (this._end - this._begin) * this._curve.transform(t); |
|||
} |
|||
} |
|||
|
|||
public override double dx(double timeInSeconds) { |
|||
double epsilon = this.tolerance.time; |
|||
return (this.x(timeInSeconds + epsilon) - this.x(timeInSeconds - epsilon)) / (2 * epsilon); |
|||
} |
|||
|
|||
public override bool isDone(double timeInSeconds) { |
|||
return timeInSeconds > this._durationInSeconds; |
|||
} |
|||
} |
|||
|
|||
class _RepeatingSimulation : Simulation { |
|||
internal _RepeatingSimulation(double min, double max, TimeSpan period) { |
|||
this.min = min; |
|||
this.max = max; |
|||
this._periodInSeconds = (double) period.Ticks / TimeSpan.TicksPerSecond; |
|||
D.assert(this._periodInSeconds > 0.0); |
|||
} |
|||
|
|||
readonly double min; |
|||
readonly double max; |
|||
readonly double _periodInSeconds; |
|||
|
|||
public override double x(double timeInSeconds) { |
|||
D.assert(timeInSeconds >= 0.0); |
|||
double t = (timeInSeconds / this._periodInSeconds) % 1.0; |
|||
return MathUtils.lerpDouble(this.min, this.max, t); |
|||
} |
|||
|
|||
public override double dx(double timeInSeconds) { |
|||
return (this.max - this.min) / this._periodInSeconds; |
|||
} |
|||
|
|||
public override bool isDone(double timeInSeconds) { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.animation { |
|||
class _AlwaysCompleteAnimation : Animation<double> { |
|||
internal _AlwaysCompleteAnimation() { |
|||
} |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
} |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { return AnimationStatus.completed; } |
|||
} |
|||
|
|||
|
|||
public override double value { |
|||
get { return 1.0; } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "kAlwaysCompleteAnimation"; |
|||
} |
|||
} |
|||
|
|||
class _AlwaysDismissedAnimation : Animation<double> { |
|||
internal _AlwaysDismissedAnimation() { |
|||
} |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
} |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { return AnimationStatus.dismissed; } |
|||
} |
|||
|
|||
|
|||
public override double value { |
|||
get { return 0.0; } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "kAlwaysDismissedAnimation"; |
|||
} |
|||
} |
|||
|
|||
public class AlwaysStoppedAnimation<T> : Animation<T> { |
|||
public AlwaysStoppedAnimation(T value) { |
|||
this._value = value; |
|||
} |
|||
|
|||
public override T value { |
|||
get { return this._value; } |
|||
} |
|||
|
|||
readonly T _value; |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
} |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { return AnimationStatus.forward; } |
|||
} |
|||
|
|||
public override string toStringDetails() { |
|||
return string.Format("{0} {1}; paused", base.toStringDetails(), this.value); |
|||
} |
|||
} |
|||
|
|||
public abstract class AnimationWithParentMixin<TParent, T> : Animation<T> { |
|||
public abstract Animation<TParent> parent { get; } |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
this.parent.addListener(listener); |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
this.parent.removeListener(listener); |
|||
} |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
this.parent.addStatusListener(listener); |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
this.parent.removeStatusListener(listener); |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { return this.parent.status; } |
|||
} |
|||
} |
|||
|
|||
public class ProxyAnimation : |
|||
AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<double> { |
|||
public ProxyAnimation(Animation<double> animation = null) { |
|||
this._parent = animation; |
|||
if (this._parent == null) { |
|||
this._status = AnimationStatus.dismissed; |
|||
this._value = 0.0; |
|||
} |
|||
} |
|||
|
|||
AnimationStatus _status; |
|||
|
|||
double _value; |
|||
|
|||
public Animation<double> parent { |
|||
get { return this._parent; } |
|||
set { |
|||
if (value == this._parent) { |
|||
return; |
|||
} |
|||
|
|||
if (this._parent != null) { |
|||
this._status = this._parent.status; |
|||
this._value = this._parent.value; |
|||
if (this.isListening) { |
|||
this.didStopListening(); |
|||
} |
|||
} |
|||
|
|||
this._parent = value; |
|||
if (this._parent != null) { |
|||
if (this.isListening) { |
|||
this.didStartListening(); |
|||
} |
|||
|
|||
if (this._value != this._parent.value) { |
|||
this.notifyListeners(); |
|||
} |
|||
|
|||
if (this._status != this._parent.status) { |
|||
this.notifyStatusListeners(this._parent.status); |
|||
} |
|||
|
|||
this._status = AnimationStatus.dismissed; |
|||
this._value = 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
Animation<double> _parent; |
|||
|
|||
protected override void didStartListening() { |
|||
if (this._parent != null) { |
|||
this._parent.addListener(this.notifyListeners); |
|||
this._parent.addStatusListener(this.notifyStatusListeners); |
|||
} |
|||
} |
|||
|
|||
protected override void didStopListening() { |
|||
if (this._parent != null) { |
|||
this._parent.removeListener(this.notifyListeners); |
|||
this._parent.removeStatusListener(this.notifyStatusListeners); |
|||
} |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { return this._parent != null ? this._parent.status : this._status; } |
|||
} |
|||
|
|||
public override double value { |
|||
get { return this._parent != null ? this._parent.value : this._value; } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
if (this.parent == null) { |
|||
return string.Format("{0}(null; {1} {2:F3}", this.GetType(), this.toStringDetails(), this.value); |
|||
} |
|||
|
|||
return string.Format("{0}\u27A9{1}", this.parent, this.GetType()); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class ReverseAnimation : AnimationLocalStatusListenersMixinAnimationLazyListenerMixinAnimation<double> { |
|||
public ReverseAnimation(Animation<double> parent) { |
|||
D.assert(parent != null); |
|||
this._parent = parent; |
|||
} |
|||
|
|||
public Animation<double> parent { |
|||
get { return this._parent; } |
|||
} |
|||
|
|||
readonly Animation<double> _parent; |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
this.didRegisterListener(); |
|||
this.parent.addListener(listener); |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
this.parent.removeListener(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
protected override void didStartListening() { |
|||
this.parent.addStatusListener(this._statusChangeHandler); |
|||
} |
|||
|
|||
protected override void didStopListening() { |
|||
this.parent.removeStatusListener(this._statusChangeHandler); |
|||
} |
|||
|
|||
void _statusChangeHandler(AnimationStatus status) { |
|||
this.notifyStatusListeners(this._reverseStatus(status)); |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { return this._reverseStatus(this.parent.status); } |
|||
} |
|||
|
|||
public override double value { |
|||
get { return 1.0 - this.parent.value; } |
|||
} |
|||
|
|||
AnimationStatus _reverseStatus(AnimationStatus status) { |
|||
switch (status) { |
|||
case AnimationStatus.forward: return AnimationStatus.reverse; |
|||
case AnimationStatus.reverse: return AnimationStatus.forward; |
|||
case AnimationStatus.completed: return AnimationStatus.dismissed; |
|||
case AnimationStatus.dismissed: return AnimationStatus.completed; |
|||
} |
|||
|
|||
D.assert(false); |
|||
return default(AnimationStatus); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return this.parent + "\u27AA" + this.GetType(); |
|||
} |
|||
} |
|||
|
|||
public class CurvedAnimation : AnimationWithParentMixin<double, double> { |
|||
public CurvedAnimation( |
|||
Animation<double> parent = null, |
|||
Curve curve = null, |
|||
Curve reverseCurve = null |
|||
) { |
|||
D.assert(parent != null); |
|||
D.assert(curve != null); |
|||
this._parent = parent; |
|||
this.curve = curve; |
|||
this.reverseCurve = reverseCurve; |
|||
|
|||
this._updateCurveDirection(parent.status); |
|||
parent.addStatusListener(this._updateCurveDirection); |
|||
} |
|||
|
|||
public override Animation<double> parent { |
|||
get { return this._parent; } |
|||
} |
|||
|
|||
readonly Animation<double> _parent; |
|||
|
|||
public Curve curve; |
|||
|
|||
public Curve reverseCurve; |
|||
|
|||
AnimationStatus? _curveDirection; |
|||
|
|||
void _updateCurveDirection(AnimationStatus status) { |
|||
switch (status) { |
|||
case AnimationStatus.dismissed: |
|||
case AnimationStatus.completed: |
|||
this._curveDirection = null; |
|||
break; |
|||
case AnimationStatus.forward: |
|||
this._curveDirection = this._curveDirection ?? AnimationStatus.forward; |
|||
break; |
|||
case AnimationStatus.reverse: |
|||
this._curveDirection = this._curveDirection ?? AnimationStatus.reverse; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
bool _useForwardCurve { |
|||
get { |
|||
return this.reverseCurve == null || |
|||
(this._curveDirection ?? this.parent.status) != AnimationStatus.reverse; |
|||
} |
|||
} |
|||
|
|||
public override double value { |
|||
get { |
|||
Curve activeCurve = this._useForwardCurve ? this.curve : this.reverseCurve; |
|||
|
|||
double t = this.parent.value; |
|||
if (activeCurve == null) { |
|||
return t; |
|||
} |
|||
|
|||
if (t == 0.0 || t == 1.0) { |
|||
D.assert(() => { |
|||
double transformedValue = activeCurve.transform(t); |
|||
double roundedTransformedValue = transformedValue.round(); |
|||
if (roundedTransformedValue != t) { |
|||
throw new UIWidgetsError( |
|||
string.Format( |
|||
"Invalid curve endpoint at {0}.\n" + |
|||
"Curves must map 0.0 to near zero and 1.0 to near one but " + |
|||
"{1} mapped {0} to {2}, which " + |
|||
"is near {3}.", |
|||
t, activeCurve.GetType(), transformedValue, roundedTransformedValue) |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
return t; |
|||
} |
|||
|
|||
return activeCurve.transform(t); |
|||
} |
|||
} |
|||
|
|||
public override string ToString() { |
|||
if (this.reverseCurve == null) { |
|||
return this.parent + "\u27A9" + this.curve; |
|||
} |
|||
|
|||
if (this._useForwardCurve) { |
|||
return this.parent + "\u27A9" + this.curve + "\u2092\u2099/" + this.reverseCurve; |
|||
} |
|||
|
|||
return this.parent + "\u27A9" + this.curve + "/" + this.reverseCurve + "\u2092\u2099"; |
|||
} |
|||
} |
|||
|
|||
enum _TrainHoppingMode { |
|||
minimize, |
|||
maximize |
|||
} |
|||
|
|||
public class TrainHoppingAnimation : |
|||
AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<double> { |
|||
public TrainHoppingAnimation( |
|||
Animation<double> _currentTrain = null, |
|||
Animation<double> _nextTrain = null, |
|||
VoidCallback onSwitchedTrain = null) { |
|||
D.assert(_currentTrain != null); |
|||
this._currentTrain = _currentTrain; |
|||
this._nextTrain = _nextTrain; |
|||
this.onSwitchedTrain = onSwitchedTrain; |
|||
|
|||
if (this._nextTrain != null) { |
|||
if (this._currentTrain.value > this._nextTrain.value) { |
|||
this._mode = _TrainHoppingMode.maximize; |
|||
} else { |
|||
this._mode = _TrainHoppingMode.minimize; |
|||
if (this._currentTrain.value == this._nextTrain.value) { |
|||
this._currentTrain = this._nextTrain; |
|||
this._nextTrain = null; |
|||
} |
|||
} |
|||
} |
|||
|
|||
this._currentTrain.addStatusListener(this._statusChangeHandler); |
|||
this._currentTrain.addListener(this._valueChangeHandler); |
|||
if (this._nextTrain != null) { |
|||
this._nextTrain.addListener(this._valueChangeHandler); |
|||
} |
|||
} |
|||
|
|||
public Animation<double> currentTrain { |
|||
get { return this._currentTrain; } |
|||
} |
|||
|
|||
Animation<double> _currentTrain; |
|||
Animation<double> _nextTrain; |
|||
_TrainHoppingMode _mode; |
|||
|
|||
public VoidCallback onSwitchedTrain; |
|||
|
|||
AnimationStatus? _lastStatus; |
|||
|
|||
void _statusChangeHandler(AnimationStatus status) { |
|||
D.assert(this._currentTrain != null); |
|||
|
|||
if (status != this._lastStatus) { |
|||
this.notifyListeners(); |
|||
this._lastStatus = status; |
|||
} |
|||
|
|||
D.assert(this._lastStatus != null); |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { return this._currentTrain.status; } |
|||
} |
|||
|
|||
double? _lastValue; |
|||
|
|||
void _valueChangeHandler() { |
|||
D.assert(this._currentTrain != null); |
|||
|
|||
bool hop = false; |
|||
if (this._nextTrain != null) { |
|||
switch (this._mode) { |
|||
case _TrainHoppingMode.minimize: |
|||
hop = this._nextTrain.value <= this._currentTrain.value; |
|||
break; |
|||
case _TrainHoppingMode.maximize: |
|||
hop = this._nextTrain.value >= this._currentTrain.value; |
|||
break; |
|||
} |
|||
|
|||
if (hop) { |
|||
this._currentTrain.removeStatusListener(this._statusChangeHandler); |
|||
this._currentTrain.removeListener(this._valueChangeHandler); |
|||
this._currentTrain = this._nextTrain; |
|||
this._nextTrain = null; |
|||
this._currentTrain.addStatusListener(this._statusChangeHandler); |
|||
this._statusChangeHandler(this._currentTrain.status); |
|||
} |
|||
} |
|||
|
|||
double newValue = this.value; |
|||
if (newValue != this._lastValue) { |
|||
this.notifyListeners(); |
|||
this._lastValue = newValue; |
|||
} |
|||
|
|||
D.assert(this._lastValue != null); |
|||
|
|||
if (hop && this.onSwitchedTrain != null) { |
|||
this.onSwitchedTrain(); |
|||
} |
|||
} |
|||
|
|||
public override double value { |
|||
get { return this._currentTrain.value; } |
|||
} |
|||
|
|||
public override void dispose() { |
|||
D.assert(this._currentTrain != null); |
|||
|
|||
this._currentTrain.removeStatusListener(this._statusChangeHandler); |
|||
this._currentTrain.removeListener(this._valueChangeHandler); |
|||
this._currentTrain = null; |
|||
|
|||
if (this._nextTrain != null) { |
|||
this._nextTrain.removeListener(this._valueChangeHandler); |
|||
this._nextTrain = null; |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
if (this._nextTrain != null) { |
|||
return string.Format("{0}\u27A9{1}(next: {2})", this.currentTrain, this.GetType(), this._nextTrain); |
|||
} |
|||
|
|||
return string.Format("{0}\u27A9{1}(no next)", this.currentTrain, this.GetType()); |
|||
} |
|||
} |
|||
|
|||
public abstract class CompoundAnimation<T> : |
|||
AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> { |
|||
public CompoundAnimation( |
|||
Animation<T> first = null, |
|||
Animation<T> next = null |
|||
) { |
|||
D.assert(first != null); |
|||
D.assert(next != null); |
|||
this.first = first; |
|||
this.next = next; |
|||
} |
|||
|
|||
public readonly Animation<T> first; |
|||
|
|||
public readonly Animation<T> next; |
|||
|
|||
protected override void didStartListening() { |
|||
this.first.addListener(this._maybeNotifyListeners); |
|||
this.first.addStatusListener(this._maybeNotifyStatusListeners); |
|||
this.next.addListener(this._maybeNotifyListeners); |
|||
this.next.addStatusListener(this._maybeNotifyStatusListeners); |
|||
} |
|||
|
|||
protected override void didStopListening() { |
|||
this.first.removeListener(this._maybeNotifyListeners); |
|||
this.first.removeStatusListener(this._maybeNotifyStatusListeners); |
|||
this.next.removeListener(this._maybeNotifyListeners); |
|||
this.next.removeStatusListener(this._maybeNotifyStatusListeners); |
|||
} |
|||
|
|||
public override AnimationStatus status { |
|||
get { |
|||
if (this.next.status == AnimationStatus.forward || this.next.status == AnimationStatus.reverse) |
|||
return this.next.status; |
|||
return this.first.status; |
|||
} |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1}, {2})", this.GetType(), this.first, this.next); |
|||
} |
|||
|
|||
AnimationStatus _lastStatus; |
|||
|
|||
void _maybeNotifyStatusListeners(AnimationStatus _) { |
|||
if (this.status != this._lastStatus) { |
|||
this._lastStatus = this.status; |
|||
this.notifyStatusListeners(this.status); |
|||
} |
|||
} |
|||
|
|||
T _lastValue; |
|||
|
|||
void _maybeNotifyListeners() { |
|||
if (object.Equals(this.value, this._lastValue)) { |
|||
this._lastValue = this.value; |
|||
this.notifyListeners(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class AnimationMean : CompoundAnimation<double> { |
|||
public AnimationMean( |
|||
Animation<double> left = null, |
|||
Animation<double> right = null |
|||
) : base(first: left, next: right) { |
|||
} |
|||
|
|||
public override double value { |
|||
get { return (this.first.value + this.next.value) / 2.0; } |
|||
} |
|||
} |
|||
|
|||
public class AnimationMax : CompoundAnimation<double> { |
|||
public AnimationMax( |
|||
Animation<double> left = null, |
|||
Animation<double> right = null |
|||
) : base(first: left, next: right) { |
|||
} |
|||
|
|||
public override double value { |
|||
get { return Math.Max(this.first.value, this.next.value); } |
|||
} |
|||
} |
|||
|
|||
public class AnimationMin : CompoundAnimation<double> { |
|||
public AnimationMin( |
|||
Animation<double> left = null, |
|||
Animation<double> right = null |
|||
) : base(first: left, next: right) { |
|||
} |
|||
|
|||
public override double value { |
|||
get { return Math.Min(this.first.value, this.next.value); } |
|||
} |
|||
} |
|||
|
|||
public static class Animations { |
|||
public static readonly Animation<double> kAlwaysCompleteAnimation = new _AlwaysCompleteAnimation(); |
|||
|
|||
public static readonly Animation<double> kAlwaysDismissedAnimation = new _AlwaysDismissedAnimation(); |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.animation { |
|||
|
|||
|
|||
public abstract class AnimationLazyListenerMixinAnimation<T> : Animation<T> { |
|||
int _listenerCounter = 0; |
|||
|
|||
protected void didRegisterListener() { |
|||
D.assert(this._listenerCounter >= 0); |
|||
if (this._listenerCounter == 0) { |
|||
this.didStartListening(); |
|||
} |
|||
|
|||
this._listenerCounter += 1; |
|||
} |
|||
|
|||
protected void didUnregisterListener() { |
|||
D.assert(this._listenerCounter >= 1); |
|||
this._listenerCounter -= 1; |
|||
if (this._listenerCounter == 0) { |
|||
this.didStopListening(); |
|||
} |
|||
} |
|||
|
|||
protected abstract void didStartListening(); |
|||
|
|||
protected abstract void didStopListening(); |
|||
|
|||
public bool isListening { |
|||
get { return this._listenerCounter > 0; } |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
public abstract class AnimationEagerListenerMixinAnimation<T> : Animation<T> { |
|||
protected void didRegisterListener() { |
|||
} |
|||
|
|||
protected void didUnregisterListener() { |
|||
} |
|||
|
|||
public virtual void dispose() { |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
public abstract class AnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLazyListenerMixinAnimation<T> { |
|||
readonly ObserverList<VoidCallback> _listeners = new ObserverList<VoidCallback>(); |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
this.didRegisterListener(); |
|||
this._listeners.Add(listener); |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
this._listeners.Remove(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
public void notifyListeners() { |
|||
var localListeners = new List<VoidCallback>(this._listeners); |
|||
foreach (VoidCallback listener in localListeners) { |
|||
try { |
|||
if (this._listeners.Contains(listener)) { |
|||
listener(); |
|||
} |
|||
} |
|||
catch (Exception exception) { |
|||
UIWidgetsError.reportError(new UIWidgetsErrorDetails( |
|||
exception: exception, |
|||
library: "animation library", |
|||
context: "while notifying listeners for " + this.GetType(), |
|||
informationCollector: information => { |
|||
information.AppendLine("The " + this.GetType() + " notifying listeners was:"); |
|||
information.Append(" " + this); |
|||
} |
|||
)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
public abstract class AnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> : AnimationEagerListenerMixinAnimation<T> { |
|||
readonly ObserverList<VoidCallback> _listeners = new ObserverList<VoidCallback>(); |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
this.didRegisterListener(); |
|||
this._listeners.Add(listener); |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
this._listeners.Remove(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
public void notifyListeners() { |
|||
var localListeners = new List<VoidCallback>(this._listeners); |
|||
foreach (VoidCallback listener in localListeners) { |
|||
try { |
|||
if (this._listeners.Contains(listener)) { |
|||
listener(); |
|||
} |
|||
} |
|||
catch (Exception exception) { |
|||
UIWidgetsError.reportError(new UIWidgetsErrorDetails( |
|||
exception: exception, |
|||
library: "animation library", |
|||
context: "while notifying listeners for " + this.GetType(), |
|||
informationCollector: information => { |
|||
information.AppendLine("The " + this.GetType() + " notifying listeners was:"); |
|||
information.Append(" " + this); |
|||
} |
|||
)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
public abstract class AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T> { |
|||
readonly ObserverList<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>(); |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
this.didRegisterListener(); |
|||
this._statusListeners.Add(listener); |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
this._statusListeners.Remove(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
public void notifyStatusListeners(AnimationStatus status) { |
|||
var localListeners = new List<AnimationStatusListener>(this._statusListeners); |
|||
foreach (AnimationStatusListener listener in localListeners) { |
|||
try { |
|||
if (this._statusListeners.Contains(listener)) { |
|||
listener(status); |
|||
} |
|||
} |
|||
catch (Exception exception) { |
|||
UIWidgetsError.reportError(new UIWidgetsErrorDetails( |
|||
exception: exception, |
|||
library: "animation library", |
|||
context: "while notifying status listeners for " + this.GetType(), |
|||
informationCollector: information => { |
|||
information.AppendLine("The " + this.GetType() + " notifying status listeners was:"); |
|||
information.Append(" " + this); |
|||
} |
|||
)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
public abstract class AnimationLocalStatusListenersMixinAnimationLazyListenerMixinAnimation<T> : AnimationLazyListenerMixinAnimation<T> { |
|||
readonly ObserverList<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>(); |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
this.didRegisterListener(); |
|||
this._statusListeners.Add(listener); |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
this._statusListeners.Remove(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
public void notifyStatusListeners(AnimationStatus status) { |
|||
var localListeners = new List<AnimationStatusListener>(this._statusListeners); |
|||
foreach (AnimationStatusListener listener in localListeners) { |
|||
try { |
|||
if (this._statusListeners.Contains(listener)) { |
|||
listener(status); |
|||
} |
|||
} |
|||
catch (Exception exception) { |
|||
UIWidgetsError.reportError(new UIWidgetsErrorDetails( |
|||
exception: exception, |
|||
library: "animation library", |
|||
context: "while notifying status listeners for " + this.GetType(), |
|||
informationCollector: information => { |
|||
information.AppendLine("The " + this.GetType() + " notifying status listeners was:"); |
|||
information.Append(" " + this); |
|||
} |
|||
)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
public abstract class AnimationLocalStatusListenersMixinAnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> : AnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T> { |
|||
readonly ObserverList<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>(); |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
this.didRegisterListener(); |
|||
this._statusListeners.Add(listener); |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
this._statusListeners.Remove(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
public void notifyStatusListeners(AnimationStatus status) { |
|||
var localListeners = new List<AnimationStatusListener>(this._statusListeners); |
|||
foreach (AnimationStatusListener listener in localListeners) { |
|||
try { |
|||
if (this._statusListeners.Contains(listener)) { |
|||
listener(status); |
|||
} |
|||
} |
|||
catch (Exception exception) { |
|||
UIWidgetsError.reportError(new UIWidgetsErrorDetails( |
|||
exception: exception, |
|||
library: "animation library", |
|||
context: "while notifying status listeners for " + this.GetType(), |
|||
informationCollector: information => { |
|||
information.AppendLine("The " + this.GetType() + " notifying status listeners was:"); |
|||
information.Append(" " + this); |
|||
} |
|||
)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.animation { |
|||
{% macro AnimationLazyListenerMixin(with) %} |
|||
public abstract class AnimationLazyListenerMixin{{with | safe}} : {{with | safe}} { |
|||
int _listenerCounter = 0; |
|||
|
|||
protected void didRegisterListener() { |
|||
D.assert(this._listenerCounter >= 0); |
|||
if (this._listenerCounter == 0) { |
|||
this.didStartListening(); |
|||
} |
|||
|
|||
this._listenerCounter += 1; |
|||
} |
|||
|
|||
protected void didUnregisterListener() { |
|||
D.assert(this._listenerCounter >= 1); |
|||
this._listenerCounter -= 1; |
|||
if (this._listenerCounter == 0) { |
|||
this.didStopListening(); |
|||
} |
|||
} |
|||
|
|||
protected abstract void didStartListening(); |
|||
|
|||
protected abstract void didStopListening(); |
|||
|
|||
public bool isListening { |
|||
get { return this._listenerCounter > 0; } |
|||
} |
|||
} |
|||
{% endmacro %} |
|||
|
|||
{{ AnimationLazyListenerMixin('Animation<T>') }} |
|||
|
|||
{% macro AnimationEagerListenerMixin(with) %} |
|||
public abstract class AnimationEagerListenerMixin{{with | safe}} : {{with | safe}} { |
|||
protected void didRegisterListener() { |
|||
} |
|||
|
|||
protected void didUnregisterListener() { |
|||
} |
|||
|
|||
public virtual void dispose() { |
|||
} |
|||
} |
|||
{% endmacro %} |
|||
|
|||
{{ AnimationEagerListenerMixin('Animation<T>') }} |
|||
|
|||
{% macro AnimationLocalListenersMixin(with) %} |
|||
public abstract class AnimationLocalListenersMixin{{with | safe}} : {{with | safe}} { |
|||
readonly ObserverList<VoidCallback> _listeners = new ObserverList<VoidCallback>(); |
|||
|
|||
public override void addListener(VoidCallback listener) { |
|||
this.didRegisterListener(); |
|||
this._listeners.Add(listener); |
|||
} |
|||
|
|||
public override void removeListener(VoidCallback listener) { |
|||
this._listeners.Remove(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
public void notifyListeners() { |
|||
var localListeners = new List<VoidCallback>(this._listeners); |
|||
foreach (VoidCallback listener in localListeners) { |
|||
try { |
|||
if (this._listeners.Contains(listener)) { |
|||
listener(); |
|||
} |
|||
} |
|||
catch (Exception exception) { |
|||
UIWidgetsError.reportError(new UIWidgetsErrorDetails( |
|||
exception: exception, |
|||
library: "animation library", |
|||
context: "while notifying listeners for " + this.GetType(), |
|||
informationCollector: information => { |
|||
information.AppendLine("The " + this.GetType() + " notifying listeners was:"); |
|||
information.Append(" " + this); |
|||
} |
|||
)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
{% endmacro %} |
|||
|
|||
{{ AnimationLocalListenersMixin('AnimationLazyListenerMixinAnimation<T>') }} |
|||
|
|||
{{ AnimationLocalListenersMixin('AnimationEagerListenerMixinAnimation<T>') }} |
|||
|
|||
{% macro AnimationLocalStatusListenersMixin(with) %} |
|||
public abstract class AnimationLocalStatusListenersMixin{{with | safe}} : {{with | safe}} { |
|||
readonly ObserverList<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>(); |
|||
|
|||
public override void addStatusListener(AnimationStatusListener listener) { |
|||
this.didRegisterListener(); |
|||
this._statusListeners.Add(listener); |
|||
} |
|||
|
|||
public override void removeStatusListener(AnimationStatusListener listener) { |
|||
this._statusListeners.Remove(listener); |
|||
this.didUnregisterListener(); |
|||
} |
|||
|
|||
public void notifyStatusListeners(AnimationStatus status) { |
|||
var localListeners = new List<AnimationStatusListener>(this._statusListeners); |
|||
foreach (AnimationStatusListener listener in localListeners) { |
|||
try { |
|||
if (this._statusListeners.Contains(listener)) { |
|||
listener(status); |
|||
} |
|||
} |
|||
catch (Exception exception) { |
|||
UIWidgetsError.reportError(new UIWidgetsErrorDetails( |
|||
exception: exception, |
|||
library: "animation library", |
|||
context: "while notifying status listeners for " + this.GetType(), |
|||
informationCollector: information => { |
|||
information.AppendLine("The " + this.GetType() + " notifying status listeners was:"); |
|||
information.Append(" " + this); |
|||
} |
|||
)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
{% endmacro %} |
|||
|
|||
{{ AnimationLocalStatusListenersMixin('AnimationLocalListenersMixinAnimationLazyListenerMixinAnimation<T>') }} |
|||
|
|||
{{ AnimationLocalStatusListenersMixin('AnimationLazyListenerMixinAnimation<T>') }} |
|||
|
|||
{{ AnimationLocalStatusListenersMixin('AnimationLocalListenersMixinAnimationEagerListenerMixinAnimation<T>') }} |
|||
|
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.animation { |
|||
public abstract class Animatable<T> { |
|||
public abstract T evaluate(Animation<double> animation); |
|||
|
|||
public Animation<T> animate(Animation<double> parent) { |
|||
return new _AnimatedEvaluation<T>(parent, this); |
|||
} |
|||
|
|||
public Animatable<T> chain(Animatable<double> parent) { |
|||
return new _ChainedEvaluation<T>(parent, this); |
|||
} |
|||
} |
|||
|
|||
class _AnimatedEvaluation<T> : AnimationWithParentMixin<double, T> { |
|||
internal _AnimatedEvaluation(Animation<double> _parent, Animatable<T> _evaluatable) { |
|||
this._parent = parent; |
|||
this._evaluatable = _evaluatable; |
|||
} |
|||
|
|||
public override Animation<double> parent { |
|||
get { return this._parent; } |
|||
} |
|||
|
|||
readonly Animation<double> _parent; |
|||
|
|||
readonly Animatable<T> _evaluatable; |
|||
|
|||
public override T value { |
|||
get { return this._evaluatable.evaluate(this.parent); } |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}\u27A9{1}\u27A9{2}", this.parent, this._evaluatable, this.value); |
|||
} |
|||
|
|||
public override string toStringDetails() { |
|||
return base.toStringDetails() + " " + this._evaluatable; |
|||
} |
|||
} |
|||
|
|||
|
|||
class _ChainedEvaluation<T> : Animatable<T> { |
|||
internal _ChainedEvaluation(Animatable<double> _parent, Animatable<T> _evaluatable) { |
|||
this._parent = _parent; |
|||
this._evaluatable = _evaluatable; |
|||
} |
|||
|
|||
readonly Animatable<double> _parent; |
|||
|
|||
readonly Animatable<T> _evaluatable; |
|||
|
|||
public override T evaluate(Animation<double> animation) { |
|||
double value = this._parent.evaluate(animation); |
|||
return this._evaluatable.evaluate(new AlwaysStoppedAnimation<double>(value)); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}\u27A9{1}", this._parent, this._evaluatable); |
|||
} |
|||
} |
|||
|
|||
public abstract class Tween<T> : Animatable<T>, IEquatable<Tween<T>> { |
|||
protected Tween(T begin, T end) { |
|||
D.assert(begin != null); |
|||
D.assert(end != null); |
|||
|
|||
this.begin = begin; |
|||
this.end = end; |
|||
} |
|||
|
|||
public readonly T begin; |
|||
|
|||
public readonly T end; |
|||
|
|||
public abstract T lerp(double t); |
|||
|
|||
public override T evaluate(Animation<double> animation) { |
|||
double t = animation.value; |
|||
if (t == 0.0) { |
|||
return this.begin; |
|||
} |
|||
|
|||
if (t == 1.0) { |
|||
return this.end; |
|||
} |
|||
|
|||
return this.lerp(t); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}({1} \u2192 {2})", this.GetType(), this.begin, this.end); |
|||
} |
|||
|
|||
public bool Equals(Tween<T> other) { |
|||
if (object.ReferenceEquals(null, other)) return false; |
|||
if (object.ReferenceEquals(this, other)) return true; |
|||
return EqualityComparer<T>.Default.Equals(this.begin, other.begin) && |
|||
EqualityComparer<T>.Default.Equals(this.end, other.end); |
|||
} |
|||
|
|||
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((Tween<T>) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
unchecked { |
|||
return (EqualityComparer<T>.Default.GetHashCode(this.begin) * 397) ^ |
|||
EqualityComparer<T>.Default.GetHashCode(this.end); |
|||
} |
|||
} |
|||
|
|||
public static bool operator ==(Tween<T> left, Tween<T> right) { |
|||
return object.Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(Tween<T> left, Tween<T> right) { |
|||
return !object.Equals(left, right); |
|||
} |
|||
} |
|||
|
|||
public class ReverseTween<T> : Tween<T> { |
|||
public ReverseTween(Tween<T> parent) : base(begin: parent.end, end: parent.begin) { |
|||
} |
|||
|
|||
public readonly Tween<T> parent; |
|||
|
|||
public override T lerp(double t) { |
|||
return this.parent.lerp(1.0 - t); |
|||
} |
|||
} |
|||
|
|||
public class ColorTween : Tween<Color> { |
|||
public ColorTween(Color begin = null, Color end = null) : base(begin: begin, end: end) { |
|||
} |
|||
|
|||
public override Color lerp(double t) { |
|||
return Color.lerp(this.begin, this.end, t); |
|||
} |
|||
} |
|||
|
|||
public class SizeTween : Tween<Size> { |
|||
public SizeTween(Size begin = null, Size end = null) : base(begin: begin, end: end) { |
|||
} |
|||
|
|||
public override Size lerp(double t) { |
|||
return Size.lerp(this.begin, this.end, t); |
|||
} |
|||
} |
|||
|
|||
public class RectTween : Tween<Rect> { |
|||
public RectTween(Rect begin = null, Rect end = null) : base(begin: begin, end: end) { |
|||
} |
|||
|
|||
public override Rect lerp(double t) { |
|||
return Rect.lerp(this.begin, this.end, t); |
|||
} |
|||
} |
|||
|
|||
public class IntTween : Tween<int> { |
|||
public IntTween(int begin, int end) : base(begin: begin, end: end) { |
|||
} |
|||
|
|||
public override int lerp(double t) { |
|||
return (this.begin + (this.end - this.begin) * t).round(); |
|||
} |
|||
} |
|||
|
|||
public class DoubleTween : Tween<double> { |
|||
public DoubleTween(int begin, int end) : base(begin: begin, end: end) { |
|||
} |
|||
|
|||
public override double lerp(double t) { |
|||
return this.begin + (this.end - this.begin) * t; |
|||
} |
|||
} |
|||
|
|||
public class StepTween : Tween<int> { |
|||
public StepTween(int begin, int end) : base(begin: begin, end: end) { |
|||
} |
|||
|
|||
public override int lerp(double t) { |
|||
return (this.begin + (this.end - this.begin) * t).floor(); |
|||
} |
|||
} |
|||
|
|||
public class CurveTween : Animatable<double> { |
|||
public CurveTween(Curve curve = null) { |
|||
D.assert(curve != null); |
|||
this.curve = curve; |
|||
} |
|||
|
|||
public readonly Curve curve; |
|||
|
|||
public override double evaluate(Animation<double> animation) { |
|||
double t = animation.value; |
|||
if (t == 0.0 || t == 1.0) { |
|||
D.assert(this.curve.transform(t).round() == t); |
|||
return t; |
|||
} |
|||
|
|||
return this.curve.transform(t); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}(curve: {1})", this.GetType(), this.curve); |
|||
} |
|||
} |
|||
} |
|
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.physics { |
|||
public class ClampedSimulation : Simulation { |
|||
public ClampedSimulation(Simulation simulation, |
|||
double xMin = double.NegativeInfinity, |
|||
double xMax = double.PositiveInfinity, |
|||
double dxMin = double.NegativeInfinity, |
|||
double dxMax = double.PositiveInfinity |
|||
) { |
|||
D.assert(simulation != null); |
|||
D.assert(xMax >= xMin); |
|||
D.assert(dxMax >= dxMin); |
|||
|
|||
this.simulation = simulation; |
|||
this.xMin = xMin; |
|||
this.dxMin = dxMin; |
|||
this.dxMax = dxMax; |
|||
} |
|||
|
|||
public readonly Simulation simulation; |
|||
|
|||
public readonly double xMin; |
|||
|
|||
public readonly double xMax; |
|||
|
|||
public readonly double dxMin; |
|||
|
|||
public readonly double dxMax; |
|||
|
|||
public override double x(double time) { |
|||
return this.simulation.x(time).clamp(this.xMin, this.xMax); |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
return this.simulation.dx(time).clamp(this.dxMin, this.dxMax); |
|||
} |
|||
|
|||
public override bool isDone(double time) { |
|||
return this.simulation.isDone(time); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e1b026c0820446e69cc5ec78354b9418 |
|||
timeCreated: 1536564505 |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.physics { |
|||
public class FrictionSimulation : Simulation { |
|||
public FrictionSimulation( |
|||
double drag, double position, double velocity, |
|||
Tolerance tolerance = null |
|||
) : base(tolerance: tolerance) { |
|||
this._drag = drag; |
|||
this._dragLog = Math.Log(drag); |
|||
this._x = position; |
|||
this._v = velocity; |
|||
} |
|||
|
|||
public static FrictionSimulation through(double startPosition, double endPosition, double startVelocity, |
|||
double endVelocity) { |
|||
D.assert(startVelocity == 0.0 || endVelocity == 0.0 || startVelocity.sign() == endVelocity.sign()); |
|||
D.assert(startVelocity.abs() >= endVelocity.abs()); |
|||
D.assert((endPosition - startPosition).sign() == startVelocity.sign()); |
|||
|
|||
return new FrictionSimulation( |
|||
FrictionSimulation._dragFor(startPosition, endPosition, startVelocity, endVelocity), |
|||
startPosition, |
|||
startVelocity, |
|||
tolerance: new Tolerance(velocity: endVelocity.abs()) |
|||
); |
|||
} |
|||
|
|||
readonly double _drag; |
|||
readonly double _dragLog; |
|||
readonly double _x; |
|||
readonly double _v; |
|||
|
|||
static double _dragFor(double startPosition, double endPosition, double startVelocity, double endVelocity) { |
|||
return Math.Pow(Math.E, (startVelocity - endVelocity) / (startPosition - endPosition)); |
|||
} |
|||
|
|||
public override double x(double time) { |
|||
return this._x + this._v * Math.Pow(this._drag, time) / this._dragLog - this._v / this._dragLog; |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
return this._v * Math.Pow(this._drag, time); |
|||
} |
|||
|
|||
public double finalX { |
|||
get { return this._x - this._v / this._dragLog; } |
|||
} |
|||
|
|||
public double timeAtX(double x) { |
|||
if (x == this._x) { |
|||
return 0.0; |
|||
} |
|||
|
|||
if (this._v == 0.0 || (this._v > 0 ? (x < this._x || x > this.finalX) : (x > this._x || x < this.finalX))) { |
|||
return double.PositiveInfinity; |
|||
} |
|||
|
|||
return Math.Log(this._dragLog * (x - this._x) / this._v + 1.0) / this._dragLog; |
|||
} |
|||
|
|||
public override bool isDone(double time) { |
|||
return this.dx(time).abs() < this.tolerance.velocity; |
|||
} |
|||
} |
|||
|
|||
public class BoundedFrictionSimulation : FrictionSimulation { |
|||
BoundedFrictionSimulation( |
|||
double drag, |
|||
double position, |
|||
double velocity, |
|||
double _minX, |
|||
double _maxX |
|||
) : base(drag, position, velocity) { |
|||
D.assert(position.clamp(_minX, _maxX) == position); |
|||
this._minX = _minX; |
|||
this._maxX = _maxX; |
|||
} |
|||
|
|||
readonly double _minX; |
|||
|
|||
readonly double _maxX; |
|||
|
|||
public override double x(double time) { |
|||
return base.x(time).clamp(this._minX, this._maxX); |
|||
} |
|||
|
|||
public override bool isDone(double time) { |
|||
return base.isDone(time) || |
|||
(this.x(time) - this._minX).abs() < this.tolerance.distance || |
|||
(this.x(time) - this._maxX).abs() < this.tolerance.distance; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 1d5938e637654fddb90f71c0d24bb3c2 |
|||
timeCreated: 1536564777 |
|
|||
using UIWidgets.foundation; |
|||
using UIWidgets.ui; |
|||
|
|||
namespace UIWidgets.physics { |
|||
public class GravitySimulation : Simulation { |
|||
public GravitySimulation( |
|||
double acceleration, |
|||
double distance, |
|||
double endDistance, |
|||
double velocity |
|||
) { |
|||
D.assert(endDistance >= 0); |
|||
this._a = acceleration; |
|||
this._x = distance; |
|||
this._v = velocity; |
|||
this._end = endDistance; |
|||
} |
|||
|
|||
readonly double _x; |
|||
readonly double _v; |
|||
readonly double _a; |
|||
readonly double _end; |
|||
|
|||
public override double x(double time) { |
|||
return this._x + this._v * time + 0.5 * this._a * time * time; |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
return this._v + time * this._a; |
|||
} |
|||
|
|||
public override bool isDone(double time) { |
|||
return this.x(time).abs() >= this._end; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f56308b79b45489b9cac8421a70c6795 |
|||
timeCreated: 1536566201 |
|
|||
namespace UIWidgets.physics { |
|||
public abstract class Simulation { |
|||
protected Simulation(Tolerance tolerance = null) { |
|||
this.tolerance = tolerance ?? Tolerance.defaultTolerance; |
|||
} |
|||
|
|||
public abstract double x(double time); |
|||
|
|||
public abstract double dx(double time); |
|||
|
|||
public abstract bool isDone(double time); |
|||
|
|||
public Tolerance tolerance; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2856e502c3bc04fd6b143e53f228f788 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using UIWidgets.foundation; |
|||
|
|||
namespace UIWidgets.physics { |
|||
public class SpringDescription { |
|||
public SpringDescription( |
|||
double mass, |
|||
double stiffness, |
|||
double damping |
|||
) { |
|||
this.mass = mass; |
|||
this.stiffness = stiffness; |
|||
this.damping = damping; |
|||
} |
|||
|
|||
public static SpringDescription withDampingRatio( |
|||
double mass, |
|||
double stiffness, |
|||
double ratio = 1.0 |
|||
) { |
|||
var damping = ratio * 2.0 * Math.Sqrt(mass * stiffness); |
|||
return new SpringDescription(mass, stiffness, damping); |
|||
} |
|||
|
|||
public readonly double mass; |
|||
|
|||
public readonly double stiffness; |
|||
|
|||
public readonly double damping; |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}(mass {1:F1}, stiffness: {2:F1}, damping: {3:F1})", |
|||
this.GetType(), this.mass, this.stiffness, this.damping); |
|||
} |
|||
} |
|||
|
|||
public enum SpringType { |
|||
criticallyDamped, |
|||
underDamped, |
|||
overDamped, |
|||
} |
|||
|
|||
public class SpringSimulation : Simulation { |
|||
public SpringSimulation( |
|||
SpringDescription spring, |
|||
double start, |
|||
double end, |
|||
double velocity, |
|||
Tolerance tolerance = null |
|||
) : base(tolerance: tolerance) { |
|||
this._endPosition = end; |
|||
this._solution = _SpringSolution.create(spring, start - end, velocity); |
|||
} |
|||
|
|||
protected readonly double _endPosition; |
|||
readonly _SpringSolution _solution; |
|||
|
|||
public SpringType type { |
|||
get { return this._solution.type; } |
|||
} |
|||
|
|||
public override double x(double time) { |
|||
return this._endPosition + this._solution.x(time); |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
return this._solution.dx(time); |
|||
} |
|||
|
|||
public override bool isDone(double time) { |
|||
return PhysicsUtils.nearZero(this._solution.x(time), this.tolerance.distance) && |
|||
PhysicsUtils.nearZero(this._solution.dx(time), this.tolerance.velocity); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return string.Format("{0}(end: {1}, {2}", this.GetType(), this._endPosition, this.type); |
|||
} |
|||
} |
|||
|
|||
public class ScrollSpringSimulation : SpringSimulation { |
|||
public ScrollSpringSimulation( |
|||
SpringDescription spring, |
|||
double start, |
|||
double end, |
|||
double velocity, |
|||
Tolerance tolerance = null |
|||
) : base(spring, start, end, velocity, tolerance: tolerance) { |
|||
} |
|||
|
|||
public double x(double time) { |
|||
return this.isDone(time) ? this._endPosition : base.x(time); |
|||
} |
|||
} |
|||
|
|||
abstract class _SpringSolution { |
|||
public static _SpringSolution create( |
|||
SpringDescription spring, |
|||
double initialPosition, |
|||
double initialVelocity |
|||
) { |
|||
D.assert(spring != null); |
|||
double cmk = spring.damping * spring.damping - 4 * spring.mass * spring.stiffness; |
|||
|
|||
if (cmk == 0.0) { |
|||
return _CriticalSolution.create(spring, initialPosition, initialVelocity); |
|||
} |
|||
|
|||
if (cmk > 0.0) { |
|||
return _OverdampedSolution.create(spring, initialPosition, initialVelocity); |
|||
} |
|||
|
|||
return _UnderdampedSolution.create(spring, initialPosition, initialVelocity); |
|||
} |
|||
|
|||
public abstract double x(double time); |
|||
public abstract double dx(double time); |
|||
public abstract SpringType type { get; } |
|||
} |
|||
|
|||
class _CriticalSolution : _SpringSolution { |
|||
internal static _CriticalSolution create( |
|||
SpringDescription spring, |
|||
double distance, |
|||
double velocity |
|||
) { |
|||
double r = -spring.damping / (2.0 * spring.mass); |
|||
double c1 = distance; |
|||
double c2 = velocity / (r * distance); |
|||
return new _CriticalSolution(r, c1, c2); |
|||
} |
|||
|
|||
private _CriticalSolution( |
|||
double r, double c1, double c2 |
|||
) { |
|||
this._r = r; |
|||
this._c1 = c1; |
|||
this._c2 = c2; |
|||
} |
|||
|
|||
readonly double _r, _c1, _c2; |
|||
|
|||
public override double x(double time) { |
|||
return (this._c1 + this._c2 * time) * Math.Pow(Math.E, this._r * time); |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
double power = Math.Pow(Math.E, this._r * time); |
|||
return this._r * (this._c1 + this._c2 * time) * power + this._c2 * power; |
|||
} |
|||
|
|||
public override SpringType type { |
|||
get { return SpringType.criticallyDamped; } |
|||
} |
|||
} |
|||
|
|||
class _OverdampedSolution : _SpringSolution { |
|||
internal static _OverdampedSolution create( |
|||
SpringDescription spring, |
|||
double distance, |
|||
double velocity |
|||
) { |
|||
double cmk = spring.damping * spring.damping - 4 * spring.mass * spring.stiffness; |
|||
double r1 = (-spring.damping - Math.Sqrt(cmk)) / (2.0 * spring.mass); |
|||
double r2 = (-spring.damping + Math.Sqrt(cmk)) / (2.0 * spring.mass); |
|||
double c2 = (velocity - r1 * distance) / (r2 - r1); |
|||
double c1 = distance - c2; |
|||
return new _OverdampedSolution(r1, r2, c1, c2); |
|||
} |
|||
|
|||
private _OverdampedSolution( |
|||
double r1, double r2, double c1, double c2 |
|||
) { |
|||
this._r1 = r1; |
|||
this._r2 = r2; |
|||
this._c1 = c1; |
|||
this._c2 = c2; |
|||
} |
|||
|
|||
readonly double _r1, _r2, _c1, _c2; |
|||
|
|||
public override double x(double time) { |
|||
return this._c1 * Math.Pow(Math.E, this._r1 * time) + |
|||
this._c2 * Math.Pow(Math.E, this._r2 * time); |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
return this._c1 * this._r1 * Math.Pow(Math.E, this._r1 * time) + |
|||
this._c2 * this._r2 * Math.Pow(Math.E, this._r2 * time); |
|||
} |
|||
|
|||
public override SpringType type { |
|||
get { return SpringType.overDamped; } |
|||
} |
|||
} |
|||
|
|||
class _UnderdampedSolution : _SpringSolution { |
|||
internal static _UnderdampedSolution create( |
|||
SpringDescription spring, |
|||
double distance, |
|||
double velocity |
|||
) { |
|||
double w = Math.Sqrt(4.0 * spring.mass * spring.stiffness - |
|||
spring.damping * spring.damping) / (2.0 * spring.mass); |
|||
double r = -(spring.damping / 2.0 * spring.mass); |
|||
double c1 = distance; |
|||
double c2 = (velocity - r * distance) / w; |
|||
return new _UnderdampedSolution(w, r, c1, c2); |
|||
} |
|||
|
|||
private _UnderdampedSolution( |
|||
double w, double r, double c1, double c2 |
|||
) { |
|||
this._w = w; |
|||
this._r = r; |
|||
this._c1 = c1; |
|||
this._c2 = c2; |
|||
} |
|||
|
|||
readonly double _w, _r, _c1, _c2; |
|||
|
|||
public override double x(double time) { |
|||
return Math.Pow(Math.E, this._r * time) * |
|||
(this._c1 * Math.Cos(this._w * time) + this._c2 * Math.Sin(this._w * time)); |
|||
} |
|||
|
|||
public override double dx(double time) { |
|||
double power = Math.Pow(Math.E, this._r * time); |
|||
double cosine = Math.Cos(this._w * time); |
|||
double sine = Math.Sin(this._w * time); |
|||
return power * (this._c2 * this._w * cosine - this._c1 * this._w * sine) + |
|||
this._r * power * (this._c2 * sine + this._c1 * cosine); |
|||
} |
|||
|
|||
public override SpringType type { |
|||
get { return SpringType.underDamped; } |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 8ed83c6d32a548d08ba79900e173dd53 |
|||
timeCreated: 1536566442 |
|
|||
namespace UIWidgets.physics { |
|||
public class Tolerance { |
|||
public Tolerance( |
|||
double distance = _epsilonDefault, |
|||
double time = _epsilonDefault, |
|||
double velocity = _epsilonDefault |
|||
) { |
|||
this.distance = distance; |
|||
this.time = time; |
|||
this.velocity = velocity; |
|||
} |
|||
|
|||
const double _epsilonDefault = 1e-3; |
|||
|
|||
public static readonly Tolerance defaultTolerance = new Tolerance(); |
|||
|
|||
public readonly double distance; |
|||
|
|||
public readonly double time; |
|||
|
|||
public readonly double velocity; |
|||
|
|||
public override string ToString() { |
|||
return string.Format("Tolerance(distance: ±{0}, time: ±{1}, velocity: ±{2})", |
|||
this.distance, this.time, this.velocity); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 24153b761064430a8482c0388fd41746 |
|||
timeCreated: 1536564124 |
|
|||
using UIWidgets.foundation; |
|||
|
|||
namespace UIWidgets.physics { |
|||
public class PhysicsUtils { |
|||
public static bool nearEqual(double a, double b, double epsilon) { |
|||
D.assert(epsilon >= 0.0); |
|||
return (a > (b - epsilon)) && (a < (b + epsilon)) || a == b; |
|||
} |
|||
|
|||
public static bool nearZero(double a, double epsilon) { |
|||
return nearEqual(a, 0.0, epsilon); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e65d36fdcaac4e92a77c930023bfd62f |
|||
timeCreated: 1536570487 |
撰写
预览
正在加载...
取消
保存
Reference in new issue