// 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 } }