2023-08-02 06:08:03 +00:00
// 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 ;
using System.Collections.Generic ;
using System.Linq ;
using Doozy.Runtime.Common.Extensions ;
using Doozy.Runtime.Common.Utils ;
using Doozy.Runtime.Global ;
using Doozy.Runtime.Mody ;
using Doozy.Runtime.Reactor ;
using Doozy.Runtime.Reactor.Internal ;
using Doozy.Runtime.Reactor.Reactions ;
using Doozy.Runtime.UIManager.Events ;
using Doozy.Runtime.UIManager.Input ;
using Doozy.Runtime.UIManager.ScriptableObjects ;
using UnityEngine ;
using UnityEngine.Events ;
using UnityEngine.EventSystems ;
using UnityEngine.UI ;
// ReSharper disable MemberCanBeProtected.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Local
// ReSharper disable VirtualMemberNeverOverridden.Global
// ReSharper disable UnusedMember.Global
namespace Doozy.Runtime.UIManager.Containers
{
/// <summary>
/// Basic container with show and hide capabilities.
/// All other containers use this as their base.
/// </summary>
[RequireComponent(typeof(Canvas))]
// [RequireComponent(typeof(GraphicRaycaster))]
[RequireComponent(typeof(RectTransform))]
2023-12-05 06:20:20 +00:00
[AddComponentMenu("Doozy/UI/Containers/UIContainer")]
2023-08-02 06:08:03 +00:00
[SelectionBase]
public class UIContainer : MonoBehaviour , ICanvasElement , IUseMultiplayerInfo
{
#if UNITY_EDITOR
2023-12-05 06:20:20 +00:00
[UnityEditor.MenuItem("GameObject/Doozy/UI/Containers/UIContainer", false, 8)]
2023-08-02 06:08:03 +00:00
private static void CreateComponent ( UnityEditor . MenuCommand menuCommand )
{
GameObjectUtils . AddToScene < UIContainer > ( "UIContainer" , false , true ) ;
}
#endif
/// <summary> Stream category name </summary>
public const string k_StreamCategory = nameof ( UIContainer ) ;
/// <summary> Default animation duration </summary>
public const float k_DefaultAnimationDuration = 0.3f ;
#region MultiplayerInfo
[SerializeField] private MultiplayerInfo MultiplayerInfo ;
/// <summary> Reference to the MultiPlayerInfo component </summary>
public MultiplayerInfo multiplayerInfo = > MultiplayerInfo ;
/// <summary> Check if a MultiplayerInfo has been referenced </summary>
public bool hasMultiplayerInfo = > multiplayerInfo ! = null ;
/// <summary> Player index for this component </summary>
public int playerIndex = > multiplayerMode & hasMultiplayerInfo ? multiplayerInfo . playerIndex : inputSettings . defaultPlayerIndex ;
/// <summary> Set the a reference to a MultiplayerInfo </summary>
/// <param name="reference"> MultiplayerInfo reference </param>
public void SetMultiplayerInfo ( MultiplayerInfo reference ) = >
MultiplayerInfo = reference ;
#endregion
/// <summary> Reference to the UIManager Input Settings </summary>
public static UIManagerInputSettings inputSettings = > UIManagerInputSettings . instance ;
/// <summary> Check if Multiplayer Mode is enabled </summary>
public static bool multiplayerMode = > inputSettings . multiplayerMode ;
private Canvas m_Canvas ;
/// <summary> Reference to the Canvas component attached to this GameObject </summary>
public Canvas canvas = > m_Canvas ? m_Canvas : m_Canvas = GetComponent < Canvas > ( ) ;
private CanvasGroup m_CanvasGroup ;
/// <summary> Reference to the CanvasGroup component attached to this GameObject </summary>
public CanvasGroup canvasGroup = > m_CanvasGroup ? m_CanvasGroup : m_CanvasGroup = GetComponent < CanvasGroup > ( ) ;
private GraphicRaycaster m_GraphicRaycaster ;
/// <summary> Reference to the GraphicRaycaster component attached to this GameObject </summary>
public GraphicRaycaster graphicRaycaster = > m_GraphicRaycaster ? m_GraphicRaycaster : m_GraphicRaycaster = GetComponent < GraphicRaycaster > ( ) ;
private RectTransform m_RectTransform ;
/// <summary> Reference to the RectTransform component attached to this GameObject </summary>
public RectTransform rectTransform = > m_RectTransform ? m_RectTransform : m_RectTransform = GetComponent < RectTransform > ( ) ;
/// <summary> Flag used to determine if a Canvas component is attached to this GameObject </summary>
public bool hasCanvas { get ; private set ; }
/// <summary> Flag used to determine if a CanvasGroup component is attached to this GameObject </summary>
public bool hasGraphicRaycaster { get ; private set ; }
/// <summary> Flag used to determine if a CanvasGroup component is attached to this GameObject </summary>
public bool hasCanvasGroup { get ; private set ; }
/// <summary> Behaviour on Start </summary>
public ContainerBehaviour OnStartBehaviour = ContainerBehaviour . Disabled ;
#region Visibility
private int m_LastFrameVisibilityStateChanged ;
/// <summary> Current visibility state </summary>
protected VisibilityState VisibilityState = VisibilityState . Visible ;
/// <summary> Current visibility state </summary>
public VisibilityState visibilityState
{
get = > VisibilityState ;
private set = > SetVisibility ( value , true ) ;
}
/// <summary> Visibility state is Visible </summary>
public bool isVisible = > visibilityState = = VisibilityState . Visible ;
/// <summary> Visibility state is Hidden </summary>
public bool isHidden = > visibilityState = = VisibilityState . Hidden ;
/// <summary> Visibility state is IsShowing - Show animation is running </summary>
public bool isShowing = > visibilityState = = VisibilityState . IsShowing ;
/// <summary> Visibility state is IsHiding - Hide animation is running </summary>
public bool isHiding = > visibilityState = = VisibilityState . IsHiding ;
/// <summary> Visibility state is either IsShowing or IsHiding - either Show or Hide animation is running </summary>
public bool inTransition = > isShowing | | isHiding ;
/// <summary> Show animation started - executed when visibility state changed to IsShowing </summary>
public ModyEvent OnShowCallback ;
/// <summary> Returns TRUE if the OnShowCallback event is not null and has at least one listener </summary>
public bool hasOnShowCallbacks = > OnShowCallback ! = null & & OnShowCallback . hasCallbacks ;
/// <summary> Visible - Show animation finished - executed when visibility state changed to Visible </summary>
public ModyEvent OnVisibleCallback ;
/// <summary> Returns TRUE if the OnVisibleCallback event is not null and has at least one listener </summary>
public bool hasOnVisibleCallbacks = > OnVisibleCallback ! = null & & OnVisibleCallback . hasCallbacks ;
/// <summary> Hide animation started - executed when visibility state changed to IsHiding </summary>
public ModyEvent OnHideCallback ;
/// <summary> Returns TRUE if the OnHideCallback event is not null and has at least one listener </summary>
public bool hasOnHideCallbacks = > OnHideCallback ! = null & & OnHideCallback . hasCallbacks ;
/// <summary> Hidden - Hide animation finished - callback invoked when visibility state changed to Hidden </summary>
public ModyEvent OnHiddenCallback ;
/// <summary> Returns TRUE if the OnHiddenCallback event is not null and has at least one listener </summary>
public bool hasOnHiddenCallbacks = > OnHiddenCallback ! = null & & OnHiddenCallback . hasCallbacks ;
/// <summary> Visibility changed - callback invoked when visibility state changed </summary>
public VisibilityStateEvent OnVisibilityChangedCallback ;
/// <summary> Returns TRUE if the OnVisibilityChangedCallback event is not null and has at least one listener </summary>
public bool hasOnVisibilityChangedCallbacks = > OnVisibilityChangedCallback ! = null & & OnVisibilityChangedCallback . GetPersistentEventCount ( ) > 0 ;
/// <summary> Returns TRUE if any of the available callbacks has at least one listener </summary>
public bool hasCallbacks = > hasOnShowCallbacks | hasOnVisibleCallbacks | hasOnHideCallbacks | hasOnHiddenCallbacks | hasOnVisibilityChangedCallbacks ;
[SerializeField] private List < Progressor > ShowProgressors ;
/// <summary> Progressors triggered on Show. Plays forward. </summary>
public List < Progressor > showProgressors = > ShowProgressors ? ? ( ShowProgressors = new List < Progressor > ( ) ) ;
[SerializeField] private List < Progressor > HideProgressors ;
/// <summary> Progressors triggered on Hide. Plays forward. </summary>
public List < Progressor > hideProgressors = > HideProgressors ? ? ( HideProgressors = new List < Progressor > ( ) ) ;
[SerializeField] private List < Progressor > ShowHideProgressors ;
/// <summary> Progressors triggered on both Show and Hide. Plays forward on Show and in reverse on Hide. </summary>
public List < Progressor > showHideProgressors = > ShowHideProgressors ? ? ( ShowHideProgressors = new List < Progressor > ( ) ) ;
/// <summary> Action invoked every time before the container needs to change its state </summary>
public UnityAction < ShowHideExecute > showHideExecute { get ; set ; }
/// <summary> Flag to keep track if the first show/hide command has been issued </summary>
public bool executedFirstCommand { get ; protected set ; }
/// <summary> Keeps track of the previously executed show/hide command </summary>
public ShowHideExecute previouslyExecutedCommand { get ; protected set ; }
#endregion
/// <summary> AnchoredPosition3D to snap to on Awake </summary>
public Vector3 CustomStartPosition ;
/// <summary> If TRUE, the rectTransform.anchoredPosition3D will 'snap' to the CustomStartPosition on Awake </summary>
public bool UseCustomStartPosition ;
/// <summary> If TRUE, after this container gets shown, it will get automatically hidden after the AutoHideAfterShowDelay time interval has passed </summary>
public bool AutoHideAfterShow ;
/// <summary> If AutoHideAfterShow is TRUE, this is the time interval after which this container will get automatically hidden </summary>
public float AutoHideAfterShowDelay ;
/// <summary> If TRUE, when this container gets hidden, the GameObject this container component is attached to, will be disabled </summary>
public bool DisableGameObjectWhenHidden ;
/// <summary> If TRUE, when this container gets hidden, the Canvas component found on the same GameObject this container component is attached to, will be disabled </summary>
public bool DisableCanvasWhenHidden = true ;
/// <summary> If TRUE, when this container gets hidden, the GraphicRaycaster component found on the same GameObject this container component is attached to, will be disabled </summary>
public bool DisableGraphicRaycasterWhenHidden = true ;
/// <summary> Controls the Block Raycasts property of the target CanvasGroup component </summary>
public bool HandleCanvasGroupBlockRaycasts = true ;
/// <summary> If TRUE, when this container is shown, any GameObject that is selected by the EventSystem.current will get deselected </summary>
public bool ClearSelectedOnShow ;
/// <summary> If TRUE, when this container is hidden, any GameObject that is selected by the EventSystem.current will get deselected </summary>
public bool ClearSelectedOnHide ;
/// <summary> If TRUE, after this container has been shown, the referenced selectable GameObject will get automatically selected by EventSystem.current </summary>
public bool AutoSelectAfterShow ;
/// <summary> Reference to the GameObject that should be selected after this container has been shown. Works only if AutoSelectAfterShow is TRUE </summary>
public GameObject AutoSelectTarget ;
/// <summary> Check if there are any referenced Show reactions </summary>
public bool hasShowReactions = > showReactions ! = null & & showReactions . Count > 0 ;
/// <summary> Check if there are any referenced Hide reactions </summary>
public bool hasHideReactions = > hideReactions ! = null & & hideReactions . Count > 0 ;
/// <summary> Check if any Show animation is active (running) </summary>
public bool anyShowAnimationIsActive = > showReactions . Any ( show = > show . isActive ) ;
/// <summary> Check if any Hide animation is active (running) </summary>
public bool anyHideAnimationIsActive = > hideReactions . Any ( hide = > hide . isActive ) ;
/// <summary> Check if any Show or Hide animation is active (running) </summary>
public bool anyAnimationIsActive = > anyShowAnimationIsActive | anyHideAnimationIsActive ;
/// <summary> Check if there are any referenced Show progressors </summary>
public bool hasShowProgressors = > showProgressors . Count > 0 ;
/// <summary> Check if there are any referenced Hide progressors </summary>
public bool hasHideProgressors = > hideProgressors . Count > 0 ;
/// <summary> Check if there are any referenced ShowHide progressors </summary>
public bool hasShowHideProgressors = > showHideProgressors . Count > 0 ;
/// <summary> Check if there are any referenced progressors </summary>
public bool hasProgressors = > hasShowProgressors | | hasHideProgressors | | hasShowHideProgressors ;
/// <summary> Check if any referenced Show progressor is active (running) </summary>
public bool anyShowProgressorIsActive = > showProgressors . Where ( p = > p ! = null ) . Any ( p = > p . reaction . isActive ) ;
/// <summary> Check if any referenced Hide progressor is active (running) </summary>
public bool anyHideProgressorIsActive = > hideProgressors . Where ( p = > p ! = null ) . Any ( p = > p . reaction . isActive ) ;
/// <summary> Check if any referenced ShowHide progressor is active (running) </summary>
public bool anyShowHideProgressorIsActive = > showHideProgressors . Where ( p = > p ! = null ) . Any ( p = > p . reaction . isActive ) ;
/// <summary> Check if any referenced progressor is active (running) </summary>
public bool anyProgressorIsActive = > anyShowProgressorIsActive | anyHideProgressorIsActive | anyShowHideProgressorIsActive ;
private HashSet < Reaction > m_ShowReactions ;
/// <summary>
/// Collection of reactions triggered by Show.
/// <para/> This collection is dynamically generated at runtime.
/// It is populated by all the animators controlled by this UIContainer.
/// The animators automatically add/remove their reactions to/from this collection.
/// </summary>
internal HashSet < Reaction > showReactions = > m_ShowReactions ? ? = new HashSet < Reaction > ( ) ;
/// <summary>
/// Get the maximum duration for the Show animations Max(startDelay) + Max(duration).
/// <para> At start this value can be calculated only after 2 frames have passed (the time it takes for the reactions to register) </para>
/// <para> For reactions that use random intervals for startDelay and/or duration, the maximum interval values are taken into account </para>
/// </summary>
public float totalDurationForShow = > CalculateTotalShowDuration ( ) ;
private HashSet < Reaction > m_HideReactions ;
/// <summary>
/// Collection of reactions triggered by Hide.
/// <para/> This collection is dynamically generated at runtime.
/// It is populated by all the animators controlled by this UIContainer.
/// The animators automatically add/remove their reactions to/from this collection.
/// </summary>
internal HashSet < Reaction > hideReactions = > m_HideReactions ? ? = new HashSet < Reaction > ( ) ;
/// <summary>
/// Get the maximum duration for the Hide animations Max(startDelay) + Max(duration).
/// <para> At start this value can be calculated only after 2 frames have passed (the time it takes for the reactions to register) </para>
/// <para> For reactions that use random intervals for startDelay and/or duration, the maximum interval values are taken into account </para>
/// </summary>
public float totalDurationForHide = > CalculateTotalHideDuration ( ) ;
/// <summary> Coroutine used when auto hide is enabled to hide the container after the specified delay </summary>
private Coroutine m_AutoHideCoroutine ;
/// <summary> Coroutine that is running when the container is showing </summary>
private Coroutine m_CoroutineIsShowing ;
/// <summary> Coroutine that is running when the container is hiding </summary>
private Coroutine m_CoroutineIsHiding ;
/// <summary> Coroutine used to disable the GameObject with a delay after the is hidden is completed </summary>
private Coroutine m_DisableGameObjectWithDelayCoroutine ;
/// <summary> Coroutine used to call Show with a 2 frame delay </summary>
private Coroutine m_DelayedShowCoroutine ;
/// <summary> Coroutine used to call Hide with a 2 frame delay </summary>
private Coroutine m_DelayedHideCoroutine ;
#if ENABLE_INPUT_SYSTEM
/// <summary>
/// Reference to a MultiplayerEventSystem component that will be used to handle the input events if multiplayer mode is enabled.
/// It only works with the new Input System.
/// For this to work, the MultiplayerEventSystem component should me placed on the same GameObject as the MultiplayerInfo component.
/// </summary>
protected UnityEngine . InputSystem . UI . MultiplayerEventSystem MultiplayerEventSystem ;
#endif
public UIContainer ( )
{
UseCustomStartPosition = true ;
OnShowCallback = new ModyEvent ( nameof ( OnShowCallback ) ) ;
OnVisibleCallback = new ModyEvent ( nameof ( OnVisibleCallback ) ) ;
OnHideCallback = new ModyEvent ( nameof ( OnHideCallback ) ) ;
OnHiddenCallback = new ModyEvent ( nameof ( OnHiddenCallback ) ) ;
OnVisibilityChangedCallback = new VisibilityStateEvent ( ) ;
}
#if UNITY_EDITOR
protected virtual void OnValidate ( )
{
if ( ! UnityEditor . PrefabUtility . IsPartOfPrefabAsset ( this ) & & ! Application . isPlaying )
CanvasUpdateRegistry . RegisterCanvasElementForLayoutRebuild ( this ) ;
}
#endif // if UNITY_EDITOR
#region ICanvasElement
public virtual void Rebuild ( CanvasUpdate executing ) { }
public virtual void LayoutComplete ( ) { }
public virtual void GraphicUpdateComplete ( ) { }
public bool IsDestroyed ( ) = > this = = null ;
#endregion
protected virtual void Awake ( )
{
if ( ! Application . isPlaying ) return ;
BackButton . Initialize ( ) ;
// m_Canvas = GetComponent<Canvas>();
// m_GraphicRaycaster = GetComponent<GraphicRaycaster>();
hasCanvas = GetComponent < Canvas > ( ) ! = null ;
hasGraphicRaycaster = GetComponent < GraphicRaycaster > ( ) ! = null ;
hasCanvasGroup = GetComponent < CanvasGroup > ( ) ! = null ;
showReactions . Remove ( null ) ;
hideReactions . Remove ( null ) ;
executedFirstCommand = false ;
if ( UseCustomStartPosition )
{
SetCustomStartPosition ( CustomStartPosition ) ;
}
}
protected virtual void OnEnable ( )
{
if ( ! Application . isPlaying ) return ;
BackButton . Initialize ( ) ;
hasCanvas = GetComponent < Canvas > ( ) ! = null ;
hasGraphicRaycaster = GetComponent < GraphicRaycaster > ( ) ! = null ;
hasCanvasGroup = GetComponent < CanvasGroup > ( ) ! = null ;
showReactions . Remove ( null ) ;
hideReactions . Remove ( null ) ;
}
protected virtual void Start ( )
{
if ( ! Application . isPlaying ) return ;
RunBehaviour ( OnStartBehaviour ) ;
}
protected virtual void OnDisable ( )
{
if ( ! Application . isPlaying ) return ;
StopIsShowingCoroutine ( ) ;
StopIsHidingCoroutine ( ) ;
showReactions . Remove ( null ) ;
foreach ( Reaction reaction in showReactions )
reaction . Stop ( ) ;
hideReactions . Remove ( null ) ;
foreach ( Reaction reaction in hideReactions )
reaction . Stop ( ) ;
StopAllCoroutines ( ) ;
}
protected virtual void OnDestroy ( ) { }
/// <summary>
/// Set the custom start position for the UIContainer.
/// </summary>
/// <param name="startPosition"> The new start position </param>
/// <param name="jumpToPosition"> If true, the UIContainer will be immediately moved to the new position </param>
public virtual void SetCustomStartPosition ( Vector3 startPosition , bool jumpToPosition = true )
{
CustomStartPosition = startPosition ;
showReactions . Remove ( null ) ;
foreach ( Reaction reaction in showReactions )
if ( reaction is UIMoveReaction moveReaction )
moveReaction . startPosition = startPosition ;
hideReactions . Remove ( null ) ;
foreach ( Reaction reaction in hideReactions )
if ( reaction is UIMoveReaction moveReaction )
moveReaction . startPosition = startPosition ;
if ( jumpToPosition )
rectTransform . anchoredPosition3D = startPosition ;
}
/// <summary>
/// Set the given GameObject as the selected object in the EventSystem or MultiplayerEventSystem, depending on the current input system and if multiplayer mode is enabled.
/// </summary>
/// <param name="selectable"> The GameObject to select </param>
protected virtual void SetSelected ( GameObject selectable )
{
#if ENABLE_INPUT_SYSTEM // if the new input system is enabled
if
(
multiplayerMode & & // multiplayer mode is enabled
(
MultiplayerEventSystem ! = null | | // multiplayer event system is already set
(
hasMultiplayerInfo & & // this UIContainer has multiplayer info
multiplayerInfo . gameObject . TryGetComponent ( out MultiplayerEventSystem ) // multiplayer event system is found
)
)
)
{
MultiplayerEventSystem . SetSelectedGameObject ( selectable ) ; // set selected game object in the multiplayer event system
}
else
{
EventSystem . current . SetSelectedGameObject ( selectable ) ; // set selected game object in the default event system
}
#elif ENABLE_LEGACY_INPUT_MANAGER // if the old input system is enabled
EventSystem . current . SetSelectedGameObject ( selectable ) ; // set selected game object in the default event system
#endif
}
private void ExecutedCommand ( ShowHideExecute command )
{
showHideExecute ? . Invoke ( command ) ;
executedFirstCommand = true ;
if ( ! hasProgressors )
{
previouslyExecutedCommand = command ;
return ;
}
showProgressors . RemoveNulls ( ) ;
hideProgressors . RemoveNulls ( ) ;
showHideProgressors . RemoveNulls ( ) ;
// ReSharper disable Unity.NoNullPropagation
switch ( command )
{
case ShowHideExecute . Show :
hideProgressors . ForEach ( p = > p . Stop ( ) ) ;
showProgressors . ForEach ( p = >
{
p . SetProgressAtZero ( ) ;
p . Play ( PlayDirection . Forward ) ;
} ) ;
showHideProgressors . ForEach ( p = >
{
p . SetProgressAtZero ( ) ;
p . Play ( PlayDirection . Forward ) ;
} ) ;
break ;
case ShowHideExecute . Hide :
showProgressors . ForEach ( p = > p . Stop ( ) ) ;
hideProgressors . ForEach ( p = >
{
p . SetProgressAtZero ( ) ;
p . Play ( PlayDirection . Forward ) ;
} ) ;
showHideProgressors . ForEach ( p = >
{
p . SetProgressAtOne ( ) ;
p . Play ( PlayDirection . Reverse ) ;
} ) ;
break ;
case ShowHideExecute . InstantShow :
hideProgressors . ForEach ( p = > p . Stop ( ) ) ;
showProgressors . ForEach ( p = > p . SetProgressAtOne ( ) ) ;
showHideProgressors . ForEach ( p = > p . SetProgressAtOne ( ) ) ;
break ;
case ShowHideExecute . InstantHide :
showProgressors . ForEach ( p = > p . Stop ( ) ) ;
hideProgressors . ForEach ( p = > p . SetProgressAtOne ( ) ) ;
showHideProgressors . ForEach ( p = > p . SetProgressAtZero ( ) ) ;
break ;
case ShowHideExecute . ReverseShow :
hideProgressors . ForEach ( p = > p . Stop ( ) ) ;
if ( previouslyExecutedCommand = = ShowHideExecute . ReverseShow )
{
showProgressors . ForEach ( p = >
{
if ( p . reaction . isActive )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Forward ) ;
}
} ) ;
showHideProgressors . ForEach ( p = >
{
if ( p . reaction . isActive & & p . reaction . direction = = PlayDirection . Reverse )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Forward ) ;
}
} ) ;
break ;
}
2023-12-05 06:20:20 +00:00
2023-08-02 06:08:03 +00:00
showProgressors . ForEach ( p = >
{
if ( p . reaction . isActive )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Reverse ) ;
}
} ) ;
showHideProgressors . ForEach ( p = >
{
if ( p . reaction . isActive & & p . reaction . direction = = PlayDirection . Forward )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Reverse ) ;
}
} ) ;
break ;
case ShowHideExecute . ReverseHide :
showProgressors . ForEach ( p = > p . Stop ( ) ) ;
2023-12-05 06:20:20 +00:00
if ( previouslyExecutedCommand = = ShowHideExecute . ReverseHide )
2023-08-02 06:08:03 +00:00
{
hideProgressors . ForEach ( p = >
{
if ( p . reaction . isActive )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Forward ) ;
}
} ) ;
showHideProgressors . ForEach ( p = >
{
if ( p . reaction . isActive & & p . reaction . direction = = PlayDirection . Forward )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Reverse ) ;
}
} ) ;
break ;
}
2023-12-05 06:20:20 +00:00
2023-08-02 06:08:03 +00:00
hideProgressors . ForEach ( p = >
{
if ( p . reaction . isActive )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Reverse ) ;
}
} ) ;
showHideProgressors . ForEach ( p = >
{
if ( p . reaction . isActive & & p . reaction . direction = = PlayDirection . Reverse )
{
p . Reverse ( ) ;
}
else
{
p . Play ( PlayDirection . Forward ) ;
}
} ) ;
break ;
default :
throw new ArgumentOutOfRangeException ( nameof ( command ) , command , null ) ;
}
previouslyExecutedCommand = command ;
// ReSharper restore Unity.NoNullPropagation
}
#region Instant Show / Hide / Toggle
/// <summary>
/// Show in the current frame without animations.
/// <para/> Triggers visibility states IsShowing and then Visible.
/// </summary>
public virtual void InstantShow ( ) = >
InstantShow ( true ) ;
/// <summary>
/// Show in the current frame without animations.
/// <para/> Triggers visibility states IsShowing and then Visible.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void InstantShow ( bool triggerCallbacks )
{
StopDelayedShowCoroutine ( ) ;
StopDelayedHideCoroutine ( ) ;
if ( isVisible ) return ;
StopIsShowingCoroutine ( ) ;
StopIsHidingCoroutine ( ) ;
if ( hasCanvas )
canvas . enabled = true ; //enable the canvas
if ( hasGraphicRaycaster & DisableGraphicRaycasterWhenHidden )
graphicRaycaster . enabled = true ; //enable the graphic raycaster
if ( hasCanvasGroup & HandleCanvasGroupBlockRaycasts )
canvasGroup . blocksRaycasts = true ; //enable blocks raycasts
gameObject . SetActive ( true ) ; //set the active state to true (in case it has been disabled when hidden)
ExecutedCommand ( ShowHideExecute . InstantShow ) ;
if ( ClearSelectedOnShow )
{
SetSelected ( null ) ; //clear any selected object
}
if ( AutoSelectAfterShow & & AutoSelectTarget ! = null ) //check that the auto select option is enabled and that a GameObject has been referenced
{
SetSelected ( AutoSelectTarget ) ; //select the referenced target
}
SetVisibility ( VisibilityState . IsShowing , triggerCallbacks ) ;
SetVisibility ( VisibilityState . Visible , triggerCallbacks ) ;
}
/// <summary>
/// Hide in the current frame without animations.
/// <para/> Triggers visibility states IsHiding and then Hidden.
/// </summary>
public virtual void InstantHide ( ) = >
InstantHide ( true ) ;
/// <summary>
/// Hide in the current frame without animations.
/// <para/> Triggers visibility states IsHiding and then Hidden.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void InstantHide ( bool triggerCallbacks )
{
StopDelayedShowCoroutine ( ) ;
StopDelayedHideCoroutine ( ) ;
if ( isHidden ) return ;
StopIsShowingCoroutine ( ) ;
StopIsHidingCoroutine ( ) ;
ExecutedCommand ( ShowHideExecute . InstantHide ) ;
if ( ClearSelectedOnHide )
{
SetSelected ( null ) ; //clear any selected object
}
SetVisibility ( VisibilityState . IsHiding , triggerCallbacks ) ;
SetVisibility ( VisibilityState . Hidden , triggerCallbacks ) ;
}
2023-12-05 06:20:20 +00:00
/// <summary>
/// Show or hide in the current frame without animations.
/// </summary>
/// <param name="show"> Should trigger show or hide </param>
public virtual void InstantShowHide ( bool show ) = >
InstantShowHide ( show , true ) ;
/// <summary>
/// Show or hide in the current frame without animations.
/// </summary>
/// <param name="show"> Should trigger show or hide </param>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void InstantShowHide ( bool show , bool triggerCallbacks )
{
if ( show )
{
InstantShow ( triggerCallbacks ) ;
return ;
}
2023-08-02 06:08:03 +00:00
2023-12-05 06:20:20 +00:00
InstantHide ( triggerCallbacks ) ;
}
2023-08-02 06:08:03 +00:00
/// <summary>
/// Toggles the visibility state.
/// If Visible or IsShowing calls InstantHide.
/// If Hidden or IsHiding calls InstantShow.
/// </summary>
public virtual void InstantToggle ( ) = >
InstantToggle ( true ) ;
/// <summary>
/// Toggles the visibility state.
/// If Visible or IsShowing calls InstantHide.
/// If Hidden or IsHiding calls InstantShow.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void InstantToggle ( bool triggerCallbacks )
{
switch ( visibilityState )
{
case VisibilityState . Visible :
case VisibilityState . IsShowing :
InstantHide ( ) ;
break ;
case VisibilityState . Hidden :
case VisibilityState . IsHiding :
InstantShow ( ) ;
break ;
default :
throw new ArgumentOutOfRangeException ( ) ;
}
}
#endregion
#region Animated Show / Hide / Toggle
/// <summary>
/// Show with animations.
/// <para/> Triggers visibility states IsShowing when Show starts and then Visible when Show finished.
/// </summary>
public virtual void Show ( ) = >
Show ( true ) ;
/// <summary>
/// Show with animations.
/// <para/> Triggers visibility states IsShowing when Show starts and then Visible when Show finished.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void Show ( bool triggerCallbacks )
{
StopDelayedShowCoroutine ( ) ;
StopDelayedHideCoroutine ( ) ;
if ( isShowing | | isVisible ) return ;
gameObject . SetActive ( true ) ; //set the active state to true (in case it has been disabled when hidden)
if ( m_LastFrameVisibilityStateChanged = = Time . frameCount )
{
StartDelayedShowCoroutine ( triggerCallbacks ) ;
return ;
}
if ( ClearSelectedOnShow )
{
SetSelected ( null ) ; //clear any selected object
}
if ( hasCanvas )
canvas . enabled = true ; //enable the canvas
if ( hasGraphicRaycaster & DisableGraphicRaycasterWhenHidden )
graphicRaycaster . enabled = true ; //enable the graphic raycaster
if ( hasCanvasGroup & HandleCanvasGroupBlockRaycasts )
canvasGroup . blocksRaycasts = true ; //enable blocks raycasts
2023-12-05 06:20:20 +00:00
2023-08-02 06:08:03 +00:00
if ( isHiding )
{
StopIsHidingCoroutine ( ) ;
ExecutedCommand ( ShowHideExecute . ReverseHide ) ;
m_CoroutineIsShowing = StartCoroutine ( IsShowing ( triggerCallbacks ) ) ;
return ;
}
ExecutedCommand ( ShowHideExecute . Show ) ;
m_CoroutineIsShowing = StartCoroutine ( IsShowing ( triggerCallbacks ) ) ;
}
private void StartDelayedShowCoroutine ( bool triggerCallbacks )
{
StopDelayedShowCoroutine ( ) ;
m_DelayedShowCoroutine =
StartCoroutine
(
Coroutiner . DelayExecution
(
( ) = >
{
Show ( triggerCallbacks ) ;
} ,
2 //2 frames delay
)
) ;
}
private void StopDelayedShowCoroutine ( )
{
if ( m_DelayedShowCoroutine = = null ) return ;
StopCoroutine ( m_DelayedShowCoroutine ) ;
m_DelayedShowCoroutine = null ;
}
private void StopIsShowingCoroutine ( )
{
if ( m_CoroutineIsShowing = = null ) return ;
StopCoroutine ( m_CoroutineIsShowing ) ;
m_CoroutineIsShowing = null ;
}
/// <summary>
/// Internal functionality used by the Show process.
/// <para/> Triggered by Show
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
private IEnumerator IsShowing ( bool triggerCallbacks )
{
StopIsHidingCoroutine ( ) ;
SetVisibility ( VisibilityState . IsShowing , triggerCallbacks ) ;
yield return new WaitForEndOfFrame ( ) ;
while ( anyAnimationIsActive )
yield return null ;
if ( hasProgressors )
while ( anyProgressorIsActive )
yield return null ;
if ( AutoSelectAfterShow & & AutoSelectTarget ! = null ) //check that the auto select option is enabled and that a GameObject has been referenced
{
SetSelected ( AutoSelectTarget ) ; //select the referenced target
}
SetVisibility ( VisibilityState . Visible , triggerCallbacks ) ;
m_CoroutineIsShowing = null ;
}
/// <summary>
/// Hide with animations.
/// <para/> Triggers visibility states IsHiding when Hide starts and then Hidden when Hide finished.
/// </summary>
public virtual void Hide ( ) = >
Hide ( true ) ;
/// <summary>
/// Hide with animations.
/// <para/> Triggers visibility states IsHiding when Hide starts and then Hidden when Hide finished.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void Hide ( bool triggerCallbacks )
{
if ( ! isActiveAndEnabled ) return ;
StopDelayedShowCoroutine ( ) ;
StopDelayedHideCoroutine ( ) ;
if ( isHiding | | isHidden ) return ;
if ( m_LastFrameVisibilityStateChanged = = Time . frameCount )
{
StartDelayedHideCoroutine ( triggerCallbacks ) ;
return ;
}
if ( ClearSelectedOnHide )
{
SetSelected ( null ) ; //clear any selected object
}
if ( isShowing )
{
StopIsShowingCoroutine ( ) ;
ExecutedCommand ( ShowHideExecute . ReverseShow ) ;
m_CoroutineIsHiding = StartCoroutine ( IsHiding ( triggerCallbacks ) ) ;
return ;
}
ExecutedCommand ( ShowHideExecute . Hide ) ;
m_CoroutineIsHiding = StartCoroutine ( IsHiding ( triggerCallbacks ) ) ;
}
private void StartDelayedHideCoroutine ( bool triggerCallbacks )
{
StopDelayedHideCoroutine ( ) ;
m_DelayedHideCoroutine =
StartCoroutine
(
Coroutiner . DelayExecution
(
( ) = >
{
m_DelayedHideCoroutine = null ;
Hide ( triggerCallbacks ) ;
} ,
2 //2 frames delay
)
) ;
}
private void StopDelayedHideCoroutine ( )
{
if ( m_DelayedHideCoroutine = = null ) return ;
StopCoroutine ( m_DelayedHideCoroutine ) ;
m_DelayedHideCoroutine = null ;
}
private void StopIsHidingCoroutine ( )
{
StopDisableGameObject ( ) ;
if ( m_CoroutineIsHiding = = null ) return ;
StopCoroutine ( m_CoroutineIsHiding ) ;
m_CoroutineIsHiding = null ;
}
/// <summary>
/// Internal functionality used by the Hide process.
/// <para/> Triggered by Hide
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
private IEnumerator IsHiding ( bool triggerCallbacks )
{
StopDisableGameObject ( ) ;
StopIsShowingCoroutine ( ) ;
SetVisibility ( VisibilityState . IsHiding , triggerCallbacks ) ;
yield return new WaitForEndOfFrame ( ) ;
while ( anyAnimationIsActive )
yield return null ;
if ( hasProgressors )
while ( anyProgressorIsActive )
yield return null ;
SetVisibility ( VisibilityState . Hidden , triggerCallbacks ) ;
m_CoroutineIsHiding = null ;
}
2023-12-05 06:20:20 +00:00
/// <summary>
/// Show or Hide with animations.
/// </summary>
/// <param name="show"> Show or Hide </param>
public virtual void ShowHide ( bool show ) = >
ShowHide ( show , true ) ;
/// <summary>
/// Show or Hide with animations.
/// </summary>
/// <param name="show"> Show or Hide </param>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void ShowHide ( bool show , bool triggerCallbacks )
{
if ( show )
{
Show ( triggerCallbacks ) ;
return ;
}
Hide ( triggerCallbacks ) ;
}
2023-08-02 06:08:03 +00:00
/// <summary>
/// Toggle the visibility state.
/// If Visible or IsShowing calls Hide.
/// If Hidden or IsHiding calls Show.
/// </summary>
public virtual void Toggle ( ) = >
Toggle ( true ) ;
/// <summary>
/// Toggle the visibility state.
/// If Visible or IsShowing calls Hide.
/// If Hidden or IsHiding calls Show.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
public virtual void Toggle ( bool triggerCallbacks )
{
switch ( visibilityState )
{
case VisibilityState . Visible :
case VisibilityState . IsShowing :
Hide ( triggerCallbacks ) ;
break ;
case VisibilityState . Hidden :
case VisibilityState . IsHiding :
Show ( triggerCallbacks ) ;
break ;
default :
throw new ArgumentOutOfRangeException ( ) ;
}
}
#endregion
/// <summary> Set the container visibility </summary>
/// <param name="state"> New visibility state </param>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
internal void SetVisibility ( VisibilityState state , bool triggerCallbacks )
{
m_LastFrameVisibilityStateChanged = Time . frameCount ;
VisibilityState = state ;
if ( triggerCallbacks ) OnVisibilityChangedCallback ? . Invoke ( VisibilityState ) ;
switch ( state )
{
case VisibilityState . Visible :
ExecuteOnVisible ( triggerCallbacks ) ;
break ;
case VisibilityState . Hidden :
ExecuteOnHidden ( triggerCallbacks ) ;
break ;
case VisibilityState . IsShowing :
ExecuteOnShow ( triggerCallbacks ) ;
break ;
case VisibilityState . IsHiding :
ExecuteOnHide ( triggerCallbacks ) ;
break ;
default :
throw new ArgumentOutOfRangeException ( nameof ( state ) , state , null ) ;
}
}
/// <summary>
/// Execute internal operations when the Show animation
/// is in the process (transition) of becoming visible.
/// <para/> Triggered at the start of the Show animation.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
private void ExecuteOnShow ( bool triggerCallbacks )
{
if ( triggerCallbacks )
{
OnShowCallback . Execute ( ) ;
}
}
/// <summary>
/// Execute internal operations when the Hide animation
/// is in the process (transition) of becoming hidden.
/// <para/> Triggered at the start of the Hide animation.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
private void ExecuteOnHide ( bool triggerCallbacks )
{
if ( triggerCallbacks )
{
OnHideCallback . Execute ( ) ;
}
if ( hasGraphicRaycaster & DisableGraphicRaycasterWhenHidden )
graphicRaycaster . enabled = false ; //disable graphic raycaster when hidden
if ( hasCanvasGroup & HandleCanvasGroupBlockRaycasts )
canvasGroup . blocksRaycasts = false ; //disable blocks raycasts when hidden
StopAutoHide ( ) ;
}
/// <summary>
/// Execute internal operations when the Show animation
/// finished and the container Is Visible.
/// <para/> Triggered at the end of the Show animation.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
private void ExecuteOnVisible ( bool triggerCallbacks )
{
if ( triggerCallbacks )
{
OnVisibleCallback . Execute ( ) ;
}
StartAutoHide ( ) ;
}
/// <summary>
/// Execute internal operations when the Hide animation
/// finished and the container Is Hidden.
/// <para/> Triggered at the end of the Hide animation.
/// </summary>
/// <param name="triggerCallbacks"> Should callbacks be triggered or not </param>
private void ExecuteOnHidden ( bool triggerCallbacks )
{
if ( triggerCallbacks )
{
OnHiddenCallback . Execute ( ) ;
}
if ( hasCanvas & DisableCanvasWhenHidden )
canvas . enabled = false ; //disable canvas when hidden
if ( hasGraphicRaycaster & DisableGraphicRaycasterWhenHidden )
graphicRaycaster . enabled = false ; //disable graphic raycaster when hidden
if ( hasCanvasGroup & HandleCanvasGroupBlockRaycasts )
canvasGroup . blocksRaycasts = false ; //disable blocks raycasts when hidden
StartDisableGameObject ( ) ;
}
private void StartDisableGameObject ( )
{
StopDisableGameObject ( ) ;
m_DisableGameObjectWithDelayCoroutine = StartCoroutine ( DisableGameObjectWithDelay ( ) ) ;
}
private void StopDisableGameObject ( )
{
if ( m_DisableGameObjectWithDelayCoroutine = = null )
return ;
StopCoroutine ( m_DisableGameObjectWithDelayCoroutine ) ;
m_DisableGameObjectWithDelayCoroutine = null ;
}
private IEnumerator DisableGameObjectWithDelay ( )
{
//we need to wait for 3 frames to make sure all the connected animators have had enough time to initialize (it takes 2 frames for a position animator to get its start position from a layout group (THANKS UNITY!!!) FML)
yield return null ; //wait 1 frame (1 for the money)
yield return null ; //wait 1 frame (2 for the show)
yield return null ; //wait 1 frame (3 to get ready)
// ...and 4 to f@#king go!
gameObject . SetActive ( ! DisableGameObjectWhenHidden ) ; //set the active state to false, if the option is enabled
}
private void StartAutoHide ( )
{
StopAutoHide ( ) ;
if ( ! AutoHideAfterShow ) return ;
m_AutoHideCoroutine = StartCoroutine ( AutoHideEnumerator ( ) ) ;
}
private void StopAutoHide ( )
{
if ( m_AutoHideCoroutine = = null ) return ;
StopCoroutine ( m_AutoHideCoroutine ) ;
m_AutoHideCoroutine = null ;
}
private IEnumerator AutoHideEnumerator ( )
{
yield return new WaitForSecondsRealtime ( AutoHideAfterShowDelay ) ;
Hide ( ) ;
m_AutoHideCoroutine = null ;
}
protected virtual void RunBehaviour ( ContainerBehaviour behaviour )
{
switch ( behaviour )
{
case ContainerBehaviour . Disabled :
//ignored
return ;
case ContainerBehaviour . InstantHide :
VisibilityState = VisibilityState . Visible ;
InstantHide ( ) ;
return ;
case ContainerBehaviour . InstantShow :
VisibilityState = VisibilityState . Hidden ;
InstantShow ( ) ;
return ;
case ContainerBehaviour . Hide :
VisibilityState = VisibilityState . Visible ;
Hide ( ) ;
return ;
case ContainerBehaviour . Show :
InstantHide ( false ) ;
StartCoroutine ( Coroutiner . DelayExecution ( Show , 2 ) ) ;
return ;
default :
throw new ArgumentOutOfRangeException ( nameof ( behaviour ) , behaviour , null ) ;
}
}
private float CalculateTotalShowDuration ( )
{
float duration = CalculateTotalDurationForReactions ( showReactions ) ;
float maxDelay = 0 ;
float maxDuration = 0 ;
showProgressors . RemoveNulls ( ) ;
foreach ( FloatReaction r in showProgressors . Select ( p = > p . reaction ) )
{
maxDelay = Mathf . Max ( maxDelay , r . settings . useRandomStartDelay ? r . settings . randomStartDelay . max : r . settings . startDelay ) ;
maxDuration = Mathf . Max ( maxDuration , r . settings . useRandomDuration ? r . settings . randomDuration . max : r . settings . duration ) ;
}
showHideProgressors . RemoveNulls ( ) ;
foreach ( FloatReaction r in showHideProgressors . Select ( p = > p . reaction ) )
{
maxDelay = Mathf . Max ( maxDelay , r . settings . useRandomStartDelay ? r . settings . randomStartDelay . max : r . settings . startDelay ) ;
maxDuration = Mathf . Max ( maxDuration , r . settings . useRandomDuration ? r . settings . randomDuration . max : r . settings . duration ) ;
}
return Mathf . Max ( duration , maxDelay + maxDuration ) ;
}
private float CalculateTotalHideDuration ( )
{
float duration = CalculateTotalDurationForReactions ( hideReactions ) ;
float maxDelay = 0 ;
float maxDuration = 0 ;
hideProgressors . RemoveNulls ( ) ;
foreach ( FloatReaction r in hideProgressors . Select ( p = > p . reaction ) )
{
maxDelay = Mathf . Max ( maxDelay , r . settings . useRandomStartDelay ? r . settings . randomStartDelay . max : r . settings . startDelay ) ;
maxDuration = Mathf . Max ( maxDuration , r . settings . useRandomDuration ? r . settings . randomDuration . max : r . settings . duration ) ;
}
showHideProgressors . RemoveNulls ( ) ;
foreach ( FloatReaction r in showHideProgressors . Select ( p = > p . reaction ) )
{
//don't calculate start delay as this progressor plays in reverse on hide
// maxDelay = Mathf.Max(maxDelay, r.settings.useRandomStartDelay ? r.settings.randomStartDelay.max : r.settings.startDelay);
maxDuration = Mathf . Max ( maxDuration , r . settings . useRandomDuration ? r . settings . randomDuration . max : r . settings . duration ) ;
}
return Mathf . Max ( duration , maxDelay + maxDuration ) ;
}
private static float CalculateTotalDurationForReactions ( IEnumerable < Reaction > reactions , params Reaction [ ] others )
{
if ( reactions = = null ) return 0f ;
float maxDelay = 0 ;
float maxDuration = 0 ;
foreach ( Reaction r in reactions )
{
if ( r = = null ) continue ;
maxDelay = Mathf . Max ( maxDelay , r . settings . useRandomStartDelay ? r . settings . randomStartDelay . max : r . settings . startDelay ) ;
maxDuration = Mathf . Max ( maxDuration , r . settings . useRandomDuration ? r . settings . randomDuration . max : r . settings . duration ) ;
}
if ( others = = null )
return maxDelay + maxDuration ;
foreach ( Reaction r in others )
{
if ( r = = null ) continue ;
maxDelay = Mathf . Max ( maxDelay , r . settings . useRandomStartDelay ? r . settings . randomStartDelay . max : r . settings . startDelay ) ;
maxDuration = Mathf . Max ( maxDuration , r . settings . useRandomDuration ? r . settings . randomDuration . max : r . settings . duration ) ;
}
return maxDelay + maxDuration ;
}
}
}