// 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.Collections;
using System.Collections.Generic;
using System.Linq;
using Doozy.Runtime.Common.Attributes;
using Doozy.Runtime.Common.Utils;
using Doozy.Runtime.Signals;
using UnityEngine;
using UnityEngine.EventSystems;
// ReSharper disable MemberCanBePrivate.Global
namespace Doozy.Runtime.UIManager.Components
{
///
/// Button component based on UISelectable with category/name id identifier.
///
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("Doozy/UI/Components/UI Button")]
[SelectionBase]
public partial class UIButton : UISelectable, IPointerClickHandler, ISubmitHandler
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("GameObject/Doozy/UI/Components/UIButton", false, 8)]
private static void CreateComponent(UnityEditor.MenuCommand menuCommand)
{
GameObjectUtils.AddToScene("UIButton", false, true);
}
#endif
/// UIButtons database
public static HashSet database { get; private set; } = new HashSet();
[ExecuteOnReload]
private static void OnReload()
{
database ??= new HashSet();
}
[ClearOnReload]
private static SignalStream s_stream;
/// UIButton signal stream
public static SignalStream stream => s_stream ??= SignalsService.GetStream(k_StreamCategory, nameof(UIButton));
/// All buttons that are active and enabled
public static IEnumerable availableButtons => database.Where(item => item.isActiveAndEnabled);
/// TRUE is this selectable is selected by EventSystem.current, FALSE otherwise
public bool isSelected => EventSystem.current.currentSelectedGameObject == gameObject;
/// Type of selectable
public override SelectableType selectableType => SelectableType.Button;
/// UIButton identifier
public UIButtonId Id;
protected UIButton()
{
Id = new UIButtonId();
}
protected override void Awake()
{
database.Add(this);
base.Awake();
}
protected override void OnEnable()
{
if (!Application.isPlaying) return;
StopCooldown();
database.Remove(null);
base.OnEnable();
}
protected override void OnDisable()
{
StopCooldown();
database.Remove(null);
base.OnDisable();
}
protected override void OnDestroy()
{
database.Remove(null);
database.Remove(this);
base.OnDestroy();
}
/// Called when on pointer click event is sent by the IPointerClickHandler
/// Pointer event data
public virtual void OnPointerClick(PointerEventData eventData)
{
if (inCooldown) return;
if (eventData.button != PointerEventData.InputButton.Left)
return;
Click();
}
/// Called when on submit event is sent by the ISubmitHandler
/// Event data
public void OnSubmit(BaseEventData eventData)
{
if (inCooldown) return;
if (!IsActive() || !IsInteractable())
return;
DoStateTransition(SelectionState.Pressed, false);
Click();
if (!inputSettings.submitTriggersPointerClick) return;
behaviours.GetBehaviour(UIBehaviour.Name.PointerClick)?.Execute();
behaviours.GetBehaviour(UIBehaviour.Name.PointerLeftClick)?.Execute();
}
private IEnumerator RefreshSelectionState()
{
const float selectionDelay = 0.1f;
float elapsedTime = 0f;
while (elapsedTime < selectionDelay)
{
elapsedTime += Time.unscaledDeltaTime;
yield return null;
}
DoStateTransition(currentSelectionState, false);
}
/// Click the button and play the pressed state animations
public void ClickWithAnimation() =>
OnSubmit(null);
/// Click the button (no animation)
public void Click() =>
Click(false);
///
/// Click the button (no animation)
///
/// Ignore active and interactable states
public void Click(bool forced)
{
if (inCooldown) return;
if (!forced && (!IsActive() || !IsInteractable()))
return;
if (isActiveAndEnabled)
{
StartCoroutine(RefreshSelectionState());
}
UISystemProfilerApi.AddMarker($"{nameof(UIButton)}.{nameof(Click)}", this);
stream.SendSignal(new UIButtonSignalData(Id.Category, Id.Name, ButtonTrigger.Click, playerIndex, this));
if (isActiveAndEnabled)
{
StartCooldown();
}
}
#region Static Methods
/// Get all the registered buttons with the given category and name
/// UIButton category
/// UIButton name (from the given category)
public static IEnumerable GetButtons(string category, string name) =>
database.Where(button => button.Id.Category.Equals(category)).Where(button => button.Id.Name.Equals(name));
/// Get all the registered buttons with the given category
/// UIButton category
public static IEnumerable GetAllButtonsInCategory(string category) =>
database.Where(button => button.Id.Category.Equals(category));
/// Get all the buttons that are active and enabled (all the visible/available buttons)
public static IEnumerable GetAvailableButtons() =>
database.Where(button => button.isActiveAndEnabled);
/// Get the selected button (if a button is not selected, this method returns null)
public static UIButton GetSelectedButton() =>
database.FirstOrDefault(button => button.isSelected);
/// Select the button with the given category and name (if it is active and enabled)
/// UIButton category
/// UIButton name (from the given category)
public static bool SelectButton(string category, string name)
{
UIButton button = availableButtons.FirstOrDefault(b => b.Id.Category.Equals(category) & b.Id.Name.Equals(name));
if (button == null) return false;
button.Select();
return true;
}
#endregion
}
}