OldBlueWater/BlueWater/Assets/Doozy/Runtime/UIManager/Containers/UIPopup.cs

852 lines
36 KiB
C#

// 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 System.Collections.Generic;
using System.Linq;
using Doozy.Runtime.Common.Attributes;
using Doozy.Runtime.Common.Extensions;
using Doozy.Runtime.Common.Utils;
using Doozy.Runtime.Global;
using Doozy.Runtime.Signals;
using Doozy.Runtime.UIManager.Components;
using Doozy.Runtime.UIManager.Containers.Internal;
using Doozy.Runtime.UIManager.Input;
using Doozy.Runtime.UIManager.ScriptableObjects;
using Doozy.Runtime.UIManager.Triggers;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
// ReSharper disable PartialTypeWithSinglePart
// ReSharper disable MemberCanBePrivate.Global
namespace Doozy.Runtime.UIManager.Containers
{
/// <summary>
/// Specialized container that behaves like a popup (modal window),
/// with parenting and positioning options.
/// </summary>
[RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(Canvas))]
[RequireComponent(typeof(GraphicRaycaster))]
[AddComponentMenu("Doozy/UI/Containers/UIPopup")]
[DisallowMultipleComponent]
public partial class UIPopup : UIContainerComponent<UIPopup>
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("GameObject/Doozy/UI/Containers/UIPopup", false, 8)]
private static void CreateComponent(UnityEditor.MenuCommand menuCommand)
{
GameObjectUtils.AddToScene<UIPopup>("UIPopup", false, true);
}
#endif
/// <summary> Describes where a popup can be instantiated under </summary>
public enum Parenting
{
/// <summary> The parent of the popup will be the PopupCanvas </summary>
PopupsCanvas = 0,
/// <summary> The parent of the popup will be the RectTransform of the GameObject that has the given UITagId </summary>
UITag = 1
}
/// <summary> Maximum sorting order value for popups (it's 1 level lower than popups) </summary>
public const int k_MaxSortingOrder = 32766;
/// <summary> Default popup name </summary>
public const string k_DefaultPopupName = "None";
/// <summary> Default category used by the UITagId to identify the default Popup Canvas </summary>
public const string k_DefaultPopupCanvasUITagCategory = "UIPopup";
/// <summary> Default name used by the UITagId to identify the default Popup Canvas </summary>
public const string k_DefaultPopupCanvasUITagName = "Canvas";
/// <summary> Default name for the popups queue. </summary>
public const string k_DefaultQueueName = "Default";
/// <summary> Get all the visible popups (returns all popups that are either in the isVisible or isShowing state) </summary>
public static IEnumerable<UIPopup> visiblePopups =>
database.Where(item => item.isVisible || item.isShowing);
/// <summary> Internal static reference to the default canvas used to display popups </summary>
[ClearOnReload]
private static Canvas s_popupsCanvas;
/// <summary>
/// Static reference to the default canvas used to display popups (popups get parented to this canvas).
/// <para/> You can override the default canvas by referencing another canvas (at runtime) to be used as the default canvas.
/// </summary>
public static Canvas popupsCanvas
{
get
{
if (s_popupsCanvas != null) return s_popupsCanvas;
//look for UITag
UITag uiTag = UITag.GetTags(k_DefaultPopupCanvasUITagCategory, k_DefaultPopupCanvasUITagName).FirstOrDefault();
if (uiTag != null)
{
s_popupsCanvas = uiTag.GetComponent<Canvas>();
if (s_popupsCanvas != null)
return s_popupsCanvas;
}
//create Popup Canvas
s_popupsCanvas = new GameObject("Popups Canvas").AddComponent<Canvas>();
s_popupsCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
s_popupsCanvas.overrideSorting = true;
s_popupsCanvas.sortingOrder = k_MaxSortingOrder;
//add the default tag
uiTag = s_popupsCanvas.gameObject.AddComponent<UITag>();
uiTag.Id.Category = k_DefaultPopupCanvasUITagCategory;
uiTag.Id.Name = k_DefaultPopupCanvasUITagName;
return s_popupsCanvas;
}
set => s_popupsCanvas = value;
}
#region Popup Queue
[ClearOnReload]
private static Dictionary<string, List<UIPopup>> s_queues;
/// <summary> Popup queues </summary>
public static Dictionary<string, List<UIPopup>> queues => s_queues ?? (s_queues = new Dictionary<string, List<UIPopup>>());
/// <summary> Get the queue with the given name </summary>
/// <param name="queueName"> Queue name </param>
/// <returns> The queue with the given name </returns>
public static List<UIPopup> GetQueue(string queueName = k_DefaultQueueName)
{
if (string.IsNullOrEmpty(queueName)) return null;
return queues.TryGetValue(queueName, out List<UIPopup> queue) ? queue.RemoveNulls() : null;
}
/// <summary> Get the first popup in the queue with the given name </summary>
/// <param name="queueName"> Queue name </param>
/// <returns> The first popup in the queue with the given name </returns>
public static UIPopup GetFirstPopupInQueue(string queueName = k_DefaultQueueName) =>
GetQueue(queueName)?.FirstOrDefault();
/// <summary> Show the first popup in the queue with the given name </summary>
/// <param name="queueName"> Queue name </param>
/// <returns>
/// The first popup in the queue with the given name.
/// <para/> Returns null if the queue is empty.
/// </returns>
public static UIPopup ShowNextPopupInQueue(string queueName = k_DefaultQueueName)
{
List<UIPopup> queue = GetQueue(queueName);
if (queue == null) return null;
if (queue.Count == 0)
{
queues.Remove(queueName);
return null;
}
UIPopup popup = queue.FirstOrDefault();
if (popup == null) return null;
popup.OnHiddenCallback.Event.AddListener(() =>
{
RemovePopupFromQueue(popup);
ShowNextPopupInQueue(queueName);
});
popup.Show();
return popup;
}
/// <summary>
/// Add a popup to the queue with the given name.
/// If the queue doesn't exist, it will be created and the popup will be shown.
/// </summary>
/// <param name="popup"> Popup to add to the queue </param>
/// <param name="queueName"> Queue name </param>
public static void AddPopupToQueue(UIPopup popup, string queueName = k_DefaultQueueName)
{
if (popup == null) return;
List<UIPopup> queue = GetQueue(queueName);
//check if the queue already exists and if it's empty
bool showPopup = queue == null || queue.Count == 0;
//create queue if it doesn't exist
if (queue == null)
{
queue = new List<UIPopup>();
queues.Add(queueName, queue);
}
//don't add the popup if it's already in the queue
if (!showPopup && queue.Contains(popup))
return;
//add the popup to the queue
queue.Add(popup);
//instantly hide the popup if it's not hidden
if (!popup.isHidden) popup.InstantHide(false);
//show the popup if it's the first one in the queue
if (showPopup) ShowNextPopupInQueue(queueName);
}
/// <summary>
/// Remove the popup from the queue with the given name.
/// If the popup is currently showing, it will be hidden and removed from the queue.
/// </summary>
/// <param name="popup"> Popup to remove from the queue </param>
/// <param name="queueName"> Queue name </param>
public static void RemovePopupFromQueue(UIPopup popup, string queueName = k_DefaultQueueName)
{
if (popup == null) return;
List<UIPopup> queue = GetQueue(queueName);
queue?.Remove(popup);
if (popup.isVisible || popup.isShowing)
popup.Hide();
}
/// <summary>
/// Clear the queue with the given name by hiding all the popups in the queue and removing them from the queue.
/// </summary>
/// <param name="queueName"> Queue name </param>
public static void ClearQueue(string queueName = k_DefaultQueueName)
{
List<UIPopup> queue = GetQueue(queueName);
if (queue == null) return;
foreach (UIPopup popup in queue)
popup.Hide();
queue.Clear();
queues.Remove(queueName);
}
#endregion
/// <summary> Set where a popup should be instantiated under </summary>
public Parenting ParentMode = Parenting.PopupsCanvas;
/// <summary>
/// Id used to identify the designated parent where the popup should be parented under,
/// after is has been instantiated
/// </summary>
public UITagId ParentTag;
/// <summary>
/// Enable override sorting and set the sorting order to the maximum value,
/// for the Canvas component attached to this popup
/// </summary>
public bool OverrideSorting = true;
/// <summary> Block the 'Back' button when the popup is visible </summary>
public bool BlockBackButton = true;
/// <summary>
/// Reselect the previously selected GameObject when the popup is hidden.
/// <para/> This is useful when the popup is hidden from a button that was selected before the popup was shown.
/// <para/> EventSystem.current is used to determine the currently selected GameObject.
/// </summary>
public bool RestoreSelectedAfterHide = true;
/// <summary>
/// Hide (close) the popup when the user clicks on any of the UIButton references.
/// <para/> At runtime, a 'hide popup' event will be added to all the referenced UIButtons (if any).
/// </summary>
public bool HideOnAnyButton = true;
/// <summary> Set the next 'Back' button event to hide (close) this UIPopup </summary>
public bool HideOnBackButton;
/// <summary> Set the next click (on the Container) to hide (close) this UIPopup </summary>
public bool HideOnClickContainer = true;
/// <summary> Set the next click (on the Overlay) to hide (close) this UIPopup </summary>
public bool HideOnClickOverlay = true;
/// <summary> Reference to the popup's Overlay RectTransform </summary>
public RectTransform Overlay;
/// <summary> TRUE if the popup has an Overlay RectTransform reference </summary>
public bool hasOverlay => Overlay != null;
/// <summary> Reference to the popup's Container RectTransform </summary>
public RectTransform Container;
/// <summary> TRUE if the popup has a Content RectTransform reference </summary>
public bool hasContainer => Container != null;
/// <summary> List of all the labels this UIPopup has </summary>
public List<TextMeshProUGUI> Labels = new List<TextMeshProUGUI>();
/// <summary> TRUE if the popup has at least one TextMeshProUGUI label reference </summary>
public bool hasLabels => Labels.RemoveNulls().Count > 0;
/// <summary> List of all the images this UIPopup has </summary>
public List<Image> Images = new List<Image>();
/// <summary> TRUE if the popup has at least one Image reference </summary>
public bool hasImages => Images.RemoveNulls().Count > 0;
/// <summary> List of all the buttons this UIPopup has </summary>
public List<UIButton> Buttons = new List<UIButton>();
/// <summary> TRUE if the popup has at least one UIButton reference </summary>
public bool hasButtons => Buttons.RemoveNulls().Count > 0;
/// <summary>
/// Reference to the RectTransform of the popup's parent.
/// This value is updated after SetParent() is called.
/// </summary>
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public RectTransform parentRectTransform { get; internal set; }
/// <summary> 'Back' button signal receiver used to trigger the hiding of this UIPopup if HideOnBackButton is TRUE </summary>
public SignalReceiver backButtonReceiver { get; set; }
/// <summary> Internal flag used to keep track if this popup disabled the 'Back' button, used to restore the previous state </summary>
private bool unblockBackButton { get; set; }
/// <summary> Internal flag used to keep track if this popup added a PointerClickTrigger to the Overlay RectTransform </summary>
private bool addedHideOnClickOverlay { get; set; }
/// <summary> Internal flag used to keep track if this popup added a PointerClickTrigger to the Container RectTransform </summary>
private bool addedHideOnClickContainer { get; set; }
/// <summary>
/// Internal flag used to keep track if the hide event was added to the buttons.
/// This is needed to avoid adding the event multiple times to the same button.
/// </summary>
private bool addedHideEventToButtons { get; set; }
/// <summary> Internal reference to the previously selected GameObject. </summary>
private GameObject previouslySelectedGameObject { get; set; }
/// <summary> Internal coroutine used to update the popup's sorting order. </summary>
private Coroutine sortingCoroutine { get; set; }
/// <summary> Validate the popup's settings </summary>
public virtual void Validate()
{
Labels.RemoveNulls();
Images.RemoveNulls();
Buttons.RemoveNulls();
}
protected override void Awake()
{
base.Awake();
//initialize the 'Back' button signal receiver
backButtonReceiver = new SignalReceiver().SetOnSignalCallback(signal =>
{
if (!HideOnBackButton) return;
if (isHidden || isHiding) return;
Hide();
});
}
protected override void OnEnable()
{
base.OnEnable();
//connect to the 'Back' button secondary signal stream
//(this stream ignores the disabled state for the 'Back' button)
BackButton.streamIgnoreDisabled.ConnectReceiver(backButtonReceiver);
}
protected override void OnDisable()
{
base.OnDisable();
//disconnect from the 'Back' button secondary signal stream
//(this stream ignores the disabled state for the 'Back' button)
BackButton.streamIgnoreDisabled.DisconnectReceiver(backButtonReceiver);
StopSortingCoroutine();
}
protected override void OnDestroy()
{
base.OnDestroy();
//sanity check to make sure the 'Back' button is enabled back again
EnableBackButton();
}
public override void Show()
{
SavePreviouslySelectedGameObject();
DisableBackButton();
AddOnClickToOverlay();
AddOnClickToContainer();
StartSortingCoroutine();
base.Show();
}
public override void InstantShow()
{
SavePreviouslySelectedGameObject();
DisableBackButton();
AddOnClickToOverlay();
AddOnClickToContainer();
StartSortingCoroutine();
base.InstantShow();
}
public override void Hide()
{
StopSortingCoroutine();
EnableBackButton();
base.Hide();
}
public override void InstantHide()
{
StopSortingCoroutine();
EnableBackButton();
base.InstantHide();
}
#region Public Methods
/// <summary>
/// Get a parent reference for the popup according to the popup's current ParentMode setting.
/// <para/> This is not the same as the popup's transform.parent, which is the parent of the popup's GameObject.
/// </summary>
public RectTransform GetParent()
{
RectTransform parent;
switch (ParentMode)
{
case Parenting.PopupsCanvas:
parent = popupsCanvas.GetComponent<RectTransform>();
break;
case Parenting.UITag:
if (ParentTag == null)
{
Debug.Log
(
"[Popup] Parenting mode set to 'UITag' but no UITag is set." +
"Used the PopupsCanvas as parent instead."
);
parent = popupsCanvas.GetComponent<RectTransform>();
break;
}
var uiTag = UITag.GetFirstTag(ParentTag.Category, ParentTag.Name);
if (uiTag == null)
{
Debug.Log
(
"[Popup] Parenting mode set to 'UITag' but the UITag is not found." +
"Used the PopupsCanvas as parent instead."
);
parent = popupsCanvas.GetComponent<RectTransform>();
break;
}
parent = uiTag.GetComponent<RectTransform>();
if (parent == null)
{
Debug.Log
(
"[Popup] Parenting mode set to 'UITag' but the UITag has no RectTransform component." +
"Used the PopupsCanvas as parent instead."
);
parent = popupsCanvas.GetComponent<RectTransform>();
}
break;
default:
throw new ArgumentOutOfRangeException();
}
return parent;
}
#endregion
#region Private Methods
private void StartSortingCoroutine()
{
StopSortingCoroutine();
sortingCoroutine = StartCoroutine
(
Coroutiner.DelayExecution
(
() =>
{
if (this == null) return;
this.ApplyOverrideSorting();
},
3 //number of frames to wait
)
);
}
private void StopSortingCoroutine()
{
if (sortingCoroutine == null) return;
StopCoroutine(sortingCoroutine);
sortingCoroutine = null;
}
/// <summary> Disable the 'Back' button if it is enabled and the popup is visible </summary>
private void DisableBackButton()
{
//sanity check to make sure the 'Back' button was not already disabled by this UIPopup
if (unblockBackButton) return;
//check that block 'Back' button option is enabled
if (!BlockBackButton) return;
BackButton.Disable();
unblockBackButton = true;
}
private void EnableBackButton()
{
//sanity check to make sure the 'Back' button was not already enabled by this UIPopup
if (!unblockBackButton) return;
//check that block 'Back' button option is enabled
if (!BlockBackButton) return;
BackButton.Enable();
unblockBackButton = false;
}
/// <summary>
/// Add on pointer click trigger on the Overlay RectTransform to hide (close) this UIPopup.
/// If the Overlay RectTransform is not assigned, nothing will happen.
/// Calling this method multiple time will not add multiple triggers (nor events) to the Overlay RectTransform.
/// </summary>
private void AddOnClickToOverlay()
{
if (!hasOverlay) return;
if (!HideOnClickOverlay) return;
if (addedHideOnClickOverlay) return;
PointerClickTrigger clickTrigger = Overlay.GetComponent<PointerClickTrigger>() ?? Overlay.gameObject.AddComponent<PointerClickTrigger>();
clickTrigger.OnTrigger.AddListener(evt => Hide());
addedHideOnClickOverlay = true;
}
/// <summary>
/// Add on pointer click trigger on the Container RectTransform to hide (close) this UIPopup.
/// If the Container RectTransform is not assigned, nothing will happen.
/// Calling this method multiple time will not add multiple triggers (nor events) to the Container RectTransform.
/// </summary>
private void AddOnClickToContainer()
{
if (!hasContainer) return;
if (!HideOnClickContainer) return;
if (addedHideOnClickContainer) return;
PointerClickTrigger clickTrigger = Container.GetComponent<PointerClickTrigger>() ?? Container.gameObject.AddComponent<PointerClickTrigger>();
clickTrigger.OnTrigger.AddListener(evt => Hide());
addedHideOnClickContainer = true;
}
/// <summary> Set all the referenced buttons to hide the tooltip is HideOnAnyButton is enabled </summary>
private void ApplyHideOnAnyButton()
{
if (addedHideEventToButtons) return;
if (!hasButtons) return;
if (!HideOnAnyButton) return;
foreach (UIButton button in Buttons)
{
button.onClickBehaviour.Event.AddListener(Hide);
button.onSubmitBehaviour.Event.AddListener(Hide);
}
addedHideEventToButtons = true; //only add the event once
}
/// <summary>
/// Save the currently selected GameObject in the EventSystem.current.
/// </summary>
private void SavePreviouslySelectedGameObject()
{
if (EventSystem.current == null) return;
previouslySelectedGameObject = EventSystem.current.currentSelectedGameObject;
}
/// <summary>
/// Restore the previously selected GameObject when the popup is hidden.
/// </summary>
private void RestorePreviouslySelectedGameObject()
{
if (!RestoreSelectedAfterHide) return;
if (EventSystem.current == null) return;
if (previouslySelectedGameObject == null) return;
EventSystem.current.SetSelectedGameObject(previouslySelectedGameObject);
}
#endregion
#region Static Methods
/// <summary>
/// Instantiate a new popup from the prefab that is registered in the database.
/// If a prefab with the given popup name is not found, null will be returned.
/// </summary>
/// <param name="popupName"> The name of the popup prefab in the database. </param>
/// <returns> The popup instance. Null if the prefab is not found. </returns>
public static UIPopup Get(string popupName)
{
if (string.IsNullOrEmpty(popupName)) return null;
GameObject prefab = UIPopupDatabase.instance.GetPrefab(popupName);
if (prefab == null)
{
Debug.LogWarning($"UIPopup.Get({popupName}) - prefab not found in the database");
return null;
}
UIPopup popup =
Instantiate(prefab)
.GetComponent<UIPopup>()
.Reset();
popup.Validate();
popup.ApplyHideOnAnyButton();
popup.SetParent(popup.GetParent());
popup.InstantHide(false);
//destroy the popup when it is hidden
popup.OnHiddenCallback.Event.AddListener(() =>
{
//sanity check to make sure the popup is not already destroyed
if (popup == null) return;
popup.RestorePreviouslySelectedGameObject();
Destroy(popup.gameObject);
popup = null;
});
return popup;
}
#endregion
}
public static class UIPopupExtensions
{
/// <summary> Reset the popup to its initial state </summary>
/// <param name="popup"> Target popup </param>
/// <returns> The popup instance </returns>
public static T Reset<T>(this T popup) where T : UIPopup
{
popup.parentRectTransform = null;
return popup;
}
/// <summary> Reparent the popup to a new parent </summary>
/// <param name="popup"> Target popup </param>
/// <param name="parent"> The new parent </param>
/// <returns> The popup instance </returns>
public static T SetParent<T>(this T popup, RectTransform parent) where T : UIPopup
{
popup.parentRectTransform = parent;
if (parent == null) return popup;
popup.rectTransform.SetParent(parent, true);
popup.rectTransform.CenterPivot().ExpandToParentSize(true);
return popup;
}
/// <summary> Update the override sorting order setting </summary>
/// <param name="popup"> Target popup </param>
/// <param name="overrideSortingOrder"> New override sorting order value </param>
/// <param name="apply"> TRUE to apply the new value, FALSE to only update the setting </param>
/// <returns> The popup instance </returns>
public static T SetOverrideSorting<T>(this T popup, bool overrideSortingOrder, bool apply = false) where T : UIPopup
{
popup.OverrideSorting = overrideSortingOrder;
if (apply) popup.ApplyOverrideSorting();
return popup;
}
/// <summary> Apply the override sorting order setting (if enabled) </summary>
/// <param name="popup"> Target popup </param>
/// <returns> The popup instance </returns>
public static T ApplyOverrideSorting<T>(this T popup) where T : UIPopup
{
if (!popup.OverrideSorting)
return popup;
popup.canvas.overrideSorting = true;
popup.canvas.sortingOrder = UIPopup.k_MaxSortingOrder;
if (!popup.canvas.gameObject.activeInHierarchy)
Debug.Log($"Cannot apply override sorting order to popup {popup.name} because it is not active in the scene");
if (!popup.canvas.enabled)
Debug.Log($"Cannot apply override sorting order to popup {popup.name} because its canvas is not enabled");
return popup;
}
/// <summary>
/// Set the text values for all the text mesh pro labels this popup has references to.
/// <para/> Each string value will be set to the TextMeshProUI label with the same index in the Labels list.
/// </summary>
/// <param name="popup"> Target popup </param>
/// <param name="texts"> Text values to set </param>
/// <returns> The popup instance </returns>
public static T SetTexts<T>(this T popup, params string[] texts) where T : UIPopup
{
int textsCount = texts.Length;
if (textsCount == 0) return popup;
if (popup.Labels == null)
{
Debug.LogWarning($"Cannot set texts for popup {popup.name} because it has no labels references");
return popup;
}
popup.Labels = popup.Labels.RemoveNulls();
if (popup.Labels.Count == 0)
{
Debug.LogWarning($"Cannot set texts for popup {popup.name} because it has no labels references");
return popup;
}
for (int i = 0; i < popup.Labels.Count; i++)
{
TextMeshProUGUI label = popup.Labels[i];
if (label == null) continue;
label.SetText(i < textsCount ? texts[i] : string.Empty);
label.ForceMeshUpdate();
}
return popup;
}
/// <summary>
/// Set the sprite references for all the Images this popup has references to.
/// <para/> Each Sprite will be referenced to the Image with the same index in the Images list.
/// </summary>
/// <param name="popup"> Target popup </param>
/// <param name="sprites"> Sprite references to set </param>
/// <returns> The popup instance </returns>
public static T SetSprites<T>(this T popup, params Sprite[] sprites) where T : UIPopup
{
int spritesCount = sprites.Length;
if (spritesCount == 0) return popup;
if (popup.Images == null)
{
Debug.LogWarning($"Cannot set sprites for popup {popup.name} because it has no image references");
return popup;
}
popup.Images = popup.Images.RemoveNulls();
if (popup.Images.Count == 0)
{
Debug.LogWarning($"Cannot set sprites for popup {popup.name} because it has no image references");
return popup;
}
for (int i = 0; i < popup.Images.Count; i++)
{
Image image = popup.Images[i];
if (image == null) continue;
image.sprite = i < spritesCount ? sprites[i] : null;
}
return popup;
}
/// <summary>
/// Set the UnityEvents to invoke for all the UIButtons this popup has references to
/// <para/> Each UnityEvent will be assigned to the UIButton with the same index in the Buttons list.
/// <para/> The UnityEvent will be invoked when the UIButton's either on click or submit behaviour is invoked.
/// </summary>
/// <param name="popup"> Target popup </param>
/// <param name="events"> UnityEvents to invoke </param>
/// <returns> The popup instance </returns>
public static T SetEvents<T>(this T popup, params UnityEvent[] events) where T : UIPopup
{
int eventsCount = events.Length;
if (eventsCount == 0) return popup;
bool hasGraphicRaycaster = popup.GetComponentInChildren<GraphicRaycaster>();
if (popup.Buttons == null)
{
Debug.LogWarning($"Cannot set events for popup {popup.name} because it has no button references");
return popup;
}
popup.Buttons = popup.Buttons.RemoveNulls();
if (popup.Buttons.Count == 0)
{
Debug.LogWarning($"Cannot set events for popup {popup.name} because it has no button references");
return popup;
}
for (int i = 0; i < popup.Buttons.Count; i++)
{
UIButton button = popup.Buttons[i]; //get the button
if (button == null) continue; //if the button is null, continue
if (!hasGraphicRaycaster) //if the popup doesn't have a graphic raycaster, check if the button has one
if (!button.GetComponent<GraphicRaycaster>()) //if the button doesn't have a graphic raycaster
button.gameObject.AddComponent<GraphicRaycaster>(); //add a graphic raycaster to the button
if (eventsCount <= i) continue; //if the event count is less than the index, continue
UnityEvent evt = events[i]; //get the event
if (evt == null) continue; //if the event is null, continue
button.onClickBehaviour.Event.AddListener(evt.Invoke); //add the event to the button on click behaviour
button.onSubmitBehaviour.Event.AddListener(evt.Invoke); //add the event to the button on submit behaviour
}
return popup;
}
/// <summary>
/// Set the UnityActions to invoke for all the UIButtons this popup has references to.
/// <para/> Each UnityAction will be assigned to the UIButton with the same index in the Buttons list.
/// <para/> The UnityAction will be invoked when the UIButton's either on click or submit behaviour is invoked.
/// </summary>
/// <param name="popup"> Target popup </param>
/// <param name="actions"> UnityActions to invoke </param>
/// <returns> The popup instance </returns>
public static T SetEvents<T>(this T popup, params UnityAction[] actions) where T : UIPopup
{
int actionsCount = actions.Length;
if (actionsCount == 0) return popup;
bool hasGraphicRaycaster = popup.GetComponentInChildren<GraphicRaycaster>();
if (popup.Buttons == null)
{
Debug.LogWarning($"Cannot set events for popup {popup.name} because it has no button references");
return popup;
}
popup.Buttons = popup.Buttons.RemoveNulls();
if (popup.Buttons.Count == 0)
{
Debug.LogWarning($"Cannot set events for popup {popup.name} because it has no button references");
return popup;
}
for (int i = 0; i < popup.Buttons.Count; i++)
{
UIButton button = popup.Buttons[i]; //get the button
if (button == null) continue; //if the button is null, continue
if (!hasGraphicRaycaster) //if the popup doesn't have a graphic raycaster, check if the button has one
if (!button.GetComponent<GraphicRaycaster>()) //if the button doesn't have a graphic raycaster
button.gameObject.AddComponent<GraphicRaycaster>(); //add a graphic raycaster to the button
if (actionsCount <= i) continue; //if the event count is less than the index, continue
UnityAction action = actions[i]; //get the action
if (action == null) continue; //if the action is null, continue
button.onClickBehaviour.Event.AddListener(action.Invoke); //add the action to the button on click behaviour
button.onSubmitBehaviour.Event.AddListener(action.Invoke); //add the action to the button on submit behaviour
}
return popup;
}
#region Popup Queue
/// <summary> Add a popup to the popup queue and show it (if the queue is not already showing a popup). </summary>
/// <param name="popup"> Target popup </param>
/// <param name="queueName"> Name of the popup queue to add the popup to </param>
/// <returns> The popup instance </returns>
public static T ShowFromQueue<T>(this T popup, string queueName = UIPopup.k_DefaultQueueName) where T : UIPopup
{
if (string.IsNullOrEmpty(queueName))
{
Debug.LogError($"Cannot show popup {popup.name} from queue because the queue name is null or empty");
return popup;
}
UIPopup.AddPopupToQueue(popup);
return popup;
}
#endregion
}
}