// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Threading.Tasks; using TMPro; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.UI { /// /// Displays progress bar and (optionally) percentage text. /// [ExecuteAlways] [AddComponentMenu("Scripts/MRTK/SDK/ProgressIndicatorLoadingBar")] public class ProgressIndicatorLoadingBar : MonoBehaviour, IProgressIndicator { const float SmoothProgressSpeed = 0.25f; /// public Transform MainTransform { get { return transform; } } /// public ProgressIndicatorState State { get { return state; } } /// public float Progress { set { targetProgress = value; } } /// public string Message { set { messageText.text = value; } } // The animated progress bar object [SerializeField] private Transform progressBar = null; // The message text used by the 'Visible' message style [SerializeField] private TextMeshPro messageText = null; // The progress text used by all non-'None' progress styles [SerializeField] private TextMeshPro progressText = null; [Tooltip("Format to use when converting progress number to string.")] [SerializeField] private string progressStringFormat = "{0:P0}"; [Tooltip("Whether to display the percentage as text in addition to the loading bar.")] [SerializeField] private bool displayPercentage = true; private float smoothProgress = 0f; private float lastSmoothProgress = -1; private ProgressIndicatorState state = ProgressIndicatorState.Closed; private Vector3 barScale = Vector3.one; /// /// Target for smooth progress, 0-1. Serialized to test in editor. /// [SerializeField] [Range(0f, 1f)] private float targetProgress = 0f; /// public async Task OpenAsync() { if (state != ProgressIndicatorState.Closed) { throw new System.Exception("Can't open in state " + state); } smoothProgress = 0; lastSmoothProgress = 0; progressText.text = string.Format(progressStringFormat, smoothProgress); gameObject.SetActive(true); state = ProgressIndicatorState.Opening; await Task.Yield(); state = ProgressIndicatorState.Open; } /// public async Task CloseAsync() { if (state != ProgressIndicatorState.Open) { throw new System.Exception("Can't close in state " + state); } state = ProgressIndicatorState.Closing; await Task.Yield(); state = ProgressIndicatorState.Closed; gameObject.SetActive(false); } /// public void CloseImmediate() { if (state != ProgressIndicatorState.Open) { throw new System.Exception("Can't close in state " + state); } state = ProgressIndicatorState.Closed; gameObject.SetActive(false); } /// public async Task AwaitTransitionAsync() { while (isActiveAndEnabled) { switch (state) { case ProgressIndicatorState.Open: case ProgressIndicatorState.Closed: return; default: break; } await Task.Yield(); } } private void Update() { if (state != ProgressIndicatorState.Open) { return; } smoothProgress = Mathf.Lerp(smoothProgress, targetProgress, SmoothProgressSpeed); if (smoothProgress > 0.99f) { smoothProgress = 1f; } barScale.x = Mathf.Clamp(smoothProgress, 0.01f, 1f); progressBar.localScale = barScale; progressText.gameObject.SetActive(displayPercentage); if (lastSmoothProgress != smoothProgress) { progressText.text = string.Format(progressStringFormat, smoothProgress); lastSmoothProgress = smoothProgress; } #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(this); #endif } } }