ProjektMWS/Projekt MWS/Library/PackageCache/com.unity.collab-proxy@1.3.9/Editor/Components/AlertBox.cs
2021-06-28 19:31:12 +02:00

215 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
[UsedImplicitly]
internal class AlertBox : VisualElement
{
/// <summary>
/// Describes the severity of the alert. Used to set the icon.
/// </summary>
public enum AlertLevel
{
Info,
Warning,
Alert
}
public const string UssClassName = "alert-box";
public const string IconUssClassName = UssClassName + "__icon";
public const string TextUssClassName = UssClassName + "__text";
public const string ButtonUssClassName = UssClassName + "__button";
static readonly string k_LayoutPath = $"{CollaborateWindow.LayoutPath}/{nameof(AlertBox)}.uxml";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(AlertBox)}.uss";
readonly Button m_Button;
readonly VisualElement m_Icon;
readonly TextElement m_Text;
// Uss classes to set which icon is displayed.
const string k_UssIconInfo = "icon-info";
const string k_UssIconWarning = "icon-warning";
const string k_UssIconAlert = "icon-alert";
/// <summary>
/// Queue of alerts to be displayed.
/// </summary>
readonly SortedSet<AlertEntry> m_AlertEntryList;
/// <summary>
/// Initialize the box and hide it.
/// </summary>
public AlertBox()
{
// Get the layout
AddToClassList(UssClassName);
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_LayoutPath).CloneTree(this);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
// Initialise fields
m_Icon = this.Q<VisualElement>(className: IconUssClassName);
m_Text = this.Q<TextElement>(className: TextUssClassName);
m_Button = this.Q<Button>(className: ButtonUssClassName);
m_AlertEntryList = new SortedSet<AlertEntry>();
// No alerts to display, so this hides the box.
UpdateAlertBox();
}
/// <summary>
/// Queue an alert to be displayed. Displayed immediately if there is currently none. If there is an existing
/// alert with the same name, it will be replaced with the latest one.
/// </summary>
/// <param name="id">Unique ID for the queued alert.</param>
/// <param name="level">Level of important of the alert.</param>
/// <param name="message">Message to be displayed.</param>
/// <param name="button">Info to populate optional button.</param>
public void QueueAlert([NotNull] string id, AlertLevel level, [NotNull] string message, (string text, Action action)? button = null)
{
// Search for existing alert.
var oldActive = m_AlertEntryList.Count == 0 ? (AlertEntry?)null : m_AlertEntryList.Max;
// Create new alert entry.
var entry = new AlertEntry(id, level, message, button == null
? (AlertEntry.AlertButton?)null
: new AlertEntry.AlertButton { Text = button.Value.text, Action = button.Value.action });
m_AlertEntryList.Add(entry);
UpdateAlertBox(oldActive?.Button?.Action);
}
/// <summary>
/// Remove existing alert. If current active one, switch to next one, or hide if none queued.
/// </summary>
/// <param name="id">Unique ID for the alert.</param>
public void DequeueAlert([NotNull] string id)
{
var oldAlert = m_AlertEntryList.Max;
m_AlertEntryList.RemoveWhere(e => e.Id == id);
UpdateAlertBox(oldAlert.Button?.Action);
}
/// <summary>
/// Display alert at the front of the queue, or hide if there are none.
/// </summary>
void UpdateAlertBox(Action previousButtonAction = null)
{
// Remove old event if it exists.
if (previousButtonAction != null)
{
m_Button.clickable.clicked -= previousButtonAction;
}
if (m_AlertEntryList.Count == 0)
{
m_Button.text = string.Empty;
m_Button.AddToClassList(UiConstants.ussHidden);
AddToClassList(UiConstants.ussHidden);
}
else
{
var activeAlert = m_AlertEntryList.Max;
m_Text.text = activeAlert.Message;
// Update state of optional button
if (activeAlert.Button?.Action != null)
{
m_Button.clickable.clicked += activeAlert.Button.Value.Action;
m_Button.text = activeAlert.Button.Value.Text;
m_Button.RemoveFromClassList(UiConstants.ussHidden);
}
else
{
m_Button.text = string.Empty;
m_Button.AddToClassList(UiConstants.ussHidden);
}
SetAlertLevel(activeAlert.Level);
RemoveFromClassList(UiConstants.ussHidden);
}
}
/// <summary>
/// Set the icon to the given severity level.
/// </summary>
/// <param name="level">Level of severity to make the icon.</param>
void SetAlertLevel(AlertLevel level)
{
// Remove old level
m_Icon.RemoveFromClassList(k_UssIconInfo);
m_Icon.RemoveFromClassList(k_UssIconWarning);
m_Icon.RemoveFromClassList(k_UssIconAlert);
// Set new one
switch (level)
{
case AlertLevel.Info:
m_Icon.AddToClassList(k_UssIconInfo);
break;
case AlertLevel.Warning:
m_Icon.AddToClassList(k_UssIconWarning);
break;
case AlertLevel.Alert:
m_Icon.AddToClassList(k_UssIconAlert);
break;
default:
throw new ArgumentOutOfRangeException(nameof(level), level, null);
}
}
struct AlertEntry : IComparable<AlertEntry>
{
public readonly string Id;
public readonly AlertLevel Level;
public readonly string Message;
public AlertButton? Button;
public AlertEntry(string id, AlertLevel level, string message, AlertButton? button)
{
Id = id;
Level = level;
Message = message;
Button = button;
}
public struct AlertButton
{
public string Text;
public Action Action;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is AlertEntry other && Id == other.Id;
}
public int CompareTo(AlertEntry other)
{
var value = Level.CompareTo(other.Level);
// If same level, compare by id.
return value != 0
? value
: string.Compare(Id, other.Id, StringComparison.Ordinal);
}
}
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<AlertBox> { }
}
}