// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System;
using UnityEditor;
// ReSharper disable DelegateSubtraction
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMethodReturnValue.Global
namespace Doozy.Editor.Common.Utils
{
/// Executes a delayed call in the Editor
public class DelayedCall
{
/// Triggered when the delayed call starts
public Action onStart { get; set; }
/// Triggered every frame until the delayed call finishes
public Action onUpdate { get; set; }
/// Triggered when the delayed call finishes
public Action onFinish { get; set; }
/// Triggered when the delayed call is canceled
public Action onCancel { get; set; }
/// Delay in seconds
public float delay { get; private set; }
/// Checks if the delayed call is running
public bool isRunning { get; private set; }
/// EditorApplication.timeSinceStartup when the delayed call started
private double startupTime { get; set; }
///
/// Creates a delayed call. You need to set a delay and a callback (onFinish) before starting it.
/// eg. DelayedCall dc = new DelayedCall().SetDelay(1f).SetOnFinish(() => Debug.Log("Delayed call finished")).Start();
///
public DelayedCall()
{
}
///
/// Creates a delayed call that will execute after the specified delay.
/// This delayed call will automatically start.
///
/// Delay in seconds
/// Callback to execute when the delayed call finishes (onFinish)
public DelayedCall(float delay, Action callback)
{
this.delay = delay;
onFinish = callback;
Start();
}
private void Update()
{
onUpdate?.Invoke();
if (EditorApplication.timeSinceStartup - startupTime < delay) return;
if (EditorApplication.update != null) EditorApplication.update -= Update;
onFinish?.Invoke();
}
/// Starts the delayed call
/// Self (for method chaining)
public DelayedCall Start()
{
startupTime = EditorApplication.timeSinceStartup;
onStart?.Invoke();
isRunning = true;
if (EditorApplication.update != null) EditorApplication.update -= Update;
EditorApplication.update += Update;
return this;
}
/// Stops the delayed call from running
/// Self (for method chaining)
public DelayedCall Stop()
{
isRunning = false;
if (EditorApplication.update != null) EditorApplication.update -= Update;
return this;
}
/// Cancels the delayed call and triggers the onCancel callback
public void Cancel()
{
Stop();
onCancel?.Invoke();
}
/// Sets the delay in seconds
/// Delay in seconds
/// Self (for method chaining)
public DelayedCall SetDelay(float value)
{
delay = value;
return this;
}
/// Adds a callback that will be triggered when the delayed call starts
/// Callback to add
/// Self (for method chaining)
public DelayedCall OnStart(Action callback)
{
onStart += callback;
return this;
}
/// Adds a callback that will be triggered every frame until the delayed call finishes
/// Callback to add
/// Self (for method chaining)
public DelayedCall OnUpdate(Action callback)
{
onUpdate += callback;
return this;
}
/// Adds a callback that will be triggered when the delayed call finishes
/// Callback to add
/// Self (for method chaining)
public DelayedCall OnFinish(Action callback)
{
onFinish += callback;
return this;
}
/// Adds a callback that will be triggered when the delayed call is canceled
/// Callback to add
/// Self (for method chaining)
public DelayedCall OnCancel(Action callback)
{
onCancel += callback;
return this;
}
/// Removes all callbacks that will be triggered when the delayed call starts
/// Self (for method chaining)
public DelayedCall ClearOnStart()
{
onStart = null;
return this;
}
/// Removes all callbacks that will be triggered every frame until the delayed call finishes
/// Self (for method chaining)
public DelayedCall ClearOnUpdate()
{
onUpdate = null;
return this;
}
/// Removes all callbacks that will be triggered when the delayed call finishes
/// Self (for method chaining)
public DelayedCall ClearOnFinish()
{
onFinish = null;
return this;
}
/// Removes all callbacks that will be triggered when the delayed call is canceled
/// Self (for method chaining)
public DelayedCall ClearOnCancel()
{
onCancel = null;
return this;
}
/// Removes all callbacks that will be triggered when the delayed call starts, every frame until the delayed call finishes, when the delayed call finishes and when the delayed call is canceled
/// Self (for method chaining)
public DelayedCall ClearAllCallbacks()
{
ClearOnStart();
ClearOnUpdate();
ClearOnFinish();
ClearOnCancel();
return this;
}
public static DelayedCall Run(float delay, Action callback) =>
new DelayedCall(delay, callback);
}
}