Skip to content

Commit

Permalink
UI Utilities + Improved Delayed Calls
Browse files Browse the repository at this point in the history
Delayed calls can now be cancelled and the gameobject containing the monobehaviour handling these calls has been unified

Added a utility for dragging a UI element

Added a utility for showing a UI element on hover of another UI element given a delay and option drag
  • Loading branch information
R-C137 committed Aug 5, 2024
1 parent 946e3a9 commit bd3b439
Show file tree
Hide file tree
Showing 10 changed files with 611 additions and 4 deletions.
7 changes: 7 additions & 0 deletions Assets/C's Utils/Runtime/CsSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
* - Updated execution order (C137)
*
* [31/07/2024] - Added support for the context menu (C137)
* [05/08/2024] - Added support for a C's Utils Gameobject (C137)
*
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEngine;
using ILogger = CsUtils.Systems.Logging.ILogger;

namespace CsUtils
Expand All @@ -60,6 +62,11 @@ public struct ContextMenuData
/// </summary>
public ILogger logger;

/// <summary>
/// Reference to the gameobject used to hold required monobehaviour for static classes
/// </summary>
public static GameObject csUtilsGameobject;

/// <summary>
/// The prefab to use for the modal window
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
*
* Changes:
* [10/01/2024] - Initial implementation (C137)
* [05/08/2024] - Unified monobehaviour creation (C137)
* - Delayed calls can now be cancelled (C137)
*/

using System;
Expand Down Expand Up @@ -58,7 +60,7 @@ public static partial class StaticUtils
static CallDelay delayHandler;

/// <summary>
/// All of the delayed calls to be made
/// All the delayed calls to be made
/// </summary>
internal static Dictionary<Action, ExecutionDelay> delayedCalls = new();

Expand All @@ -73,16 +75,19 @@ public static partial class StaticUtils
/// <param name="delay">How long in seconds should the delay be</param>
/// <param name="callback">The function to call</param>
/// <param name="executionOrder">At which execution order should the function be called</param>
public static void DelayedCall(float delay, Action callback, ExecutionOrder executionOrder = ExecutionOrder.Update)
public static Action DelayedCall(float delay, Action callback, ExecutionOrder executionOrder = ExecutionOrder.Update)
{
if (delayHandler == null)
{
delayHandler = new GameObject("CsUtils~").AddComponent<CallDelay>();
delayHandler = (CsSettings.csUtilsGameobject ??= new GameObject("CsUtils~")).AddComponent<CallDelay>();
UnityEngine.Object.DontDestroyOnLoad(delayHandler);
}

delayedCalls.Add(SingularizeAction(callback), new ExecutionDelay(delay, executionOrder));
Action singleAction = SingularizeAction(callback);
delayedCalls.Add(singleAction, new ExecutionDelay(delay, executionOrder));

return singleAction;

Action SingularizeAction(Action action)
{
return () =>
Expand All @@ -92,6 +97,16 @@ Action SingularizeAction(Action action)
};
}
}

/// <summary>
/// Cancels a delayed call
/// </summary>
/// <param name="call">The call to cancel</param>
/// <returns>Whether the call could be cancelled</returns>
public static bool CancelDelayedCall(Action call)
{
return delayedCalls.Remove(call);
}
}

public class CallDelay : MonoBehaviour
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* StaticUtils.Drag.cs - C's Utils
*
* QoL class to handle dragging UI on the screen. Can also be used to create a cursor
*
*
* Creation Date: 05/08/2024
* Authors: C137
* Original: C137
*
* Edited By: C137
*
* Changes:
* [05/08/2024] - Initial implementation (C137)
*/
using System;
using System.Collections.Generic;
using UnityEngine;

namespace CsUtils
{
public struct DragData
{
/// <summary>
/// The canvas used to display the dragged UI element
/// </summary>
public Canvas parentCanvas;

/// <summary>
/// The offset by which to drag the UI element
/// </summary>
public Vector2 offset;

/// <summary>
/// The id of the touch which this drag is assigned
/// </summary>
public int? touchID;
}

public static partial class StaticUtils
{
private static DragHandler dragHandler;

/// <summary>
/// Moves a UI element to the mouse position everything, giving a drag effect
/// </summary>
/// <param name="transform">The transform to be moved</param>
/// <param name="parentCanvas">The canvas in which the transform is found. Will search for one if unspecified</param>
/// <param name="offset">The offset by which to move the transform to the mouse position</param>
/// <param name="touchID">The touch id to drag the UI element with. Set null to use the mouse position</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static bool Drag(Transform transform, Canvas parentCanvas = null, Vector2? offset = null, int? touchID = null)
{
offset ??= Vector2.zero;

parentCanvas ??= SearchForCanvas();

if(parentCanvas == null)
throw new ArgumentException("The given transform is not child of a canvas", nameof(transform));

if(dragHandler == null)
{
dragHandler = (CsSettings.csUtilsGameobject ??= new GameObject("CsUtils~")).AddComponent<DragHandler>();
UnityEngine.Object.DontDestroyOnLoad(dragHandler);
}

return dragHandler.itemsToDrag.TryAdd(transform, new DragData { parentCanvas = parentCanvas, offset = offset.Value, touchID = touchID});

Canvas SearchForCanvas()
{
Transform parent = transform.parent;

while (parent is not null)
{
if(parent.TryGetComponent(out Canvas canvas))
return canvas;

parent = parent.parent;
}
return null;
}
}

/// <summary>
/// Checks whether a UI element is currently being dragged
/// </summary>
/// <param name="transform">The UI element to check</param>
/// <returns></returns>
public static bool IsDragging(Transform transform)
{
if(dragHandler == null)
return false;

return dragHandler.itemsToDrag.ContainsKey(transform);
}

/// <summary>
/// Stops dragging a UI element
/// </summary>
/// <param name="transform">The UI element to stop dragging</param>
public static void StopDrag(Transform transform)
{
if(dragHandler != null)
dragHandler.itemsToDrag.Remove(transform);
}
}

public class DragHandler : MonoBehaviour
{
public Dictionary<Transform, DragData> itemsToDrag = new ();

public void Update()
{
DoDrag();
}

void DoDrag()
{
foreach (var kvp in itemsToDrag)
{
DragData drag = kvp.Value;

Vector2 mousePos = drag.touchID == null ? Input.mousePosition : Input.GetTouch(drag.touchID.Value).position;
StaticUtils.MoveUIToMouse(kvp.Key, drag.parentCanvas, mousePos, drag.offset);
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 108 additions & 0 deletions Assets/C's Utils/Runtime/UI/HoverShower.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using UnityEngine;
using UnityEngine.EventSystems;

namespace CsUtils
{
public class HoverShower : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
/// <summary>
/// The object to show on hover
/// </summary>
public Transform show;

/// <summary>
/// The previous show object, used for automatically finding the canvas
/// </summary>
private Transform oldShow;

/// <summary>
/// The parent canvas of the object to show
/// </summary>
public Canvas showParentCanvas;

/// <summary>
/// How long should the hover be before the object is shown
/// </summary>
public float delay;

/// <summary>
/// Whether the shown transform should be dragged
/// </summary>
public bool doDragging;

/// <summary>
/// The offset to drag/show the transform by
/// </summary>
public Vector2 offset;

/// <summary>
/// The delayed called use to show the object
/// </summary>
public Action delayedCall;

/// <summary>
/// Shows the hover object and starts dragging it
/// </summary>
public void Show()
{
show.gameObject.SetActive(true);

if(doDragging)
StaticUtils.Drag(show);
}

public void Hide()
{
if(doDragging)
StaticUtils.StopDrag(transform);

show.gameObject.SetActive(false);
}

public void OnPointerEnter(PointerEventData eventData)
{
if(delay == 0)
Show();
else
delayedCall = StaticUtils.DelayedCall(delay, Show);
}



public void OnPointerExit(PointerEventData eventData)
{
if(delayedCall != null)
StaticUtils.CancelDelayedCall(delayedCall);

Hide();
}

private void OnValidate()
{
if(show == null || oldShow == show)
{
oldShow = show;
return;
}

showParentCanvas = showParentCanvas == null ? SearchForCanvas() : showParentCanvas;

oldShow = show;

Canvas SearchForCanvas()
{
Transform parent = show.parent;

while (parent is not null)
{
if(parent.TryGetComponent(out Canvas canvas))
return canvas;

parent = parent.parent;
}
return null;
}
}
}
}
2 changes: 2 additions & 0 deletions Assets/C's Utils/Runtime/UI/HoverShower.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions Assets/C's Utils/Testing/DragTester.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using CsUtils;
using UnityEngine;
using UnityEngine.UI;

public class DragTester : MonoBehaviour
{
public Image drag;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{

}

// Update is called once per frame
void Update()
{
// if(InputQuery.GetKeyDown(KeyCode.K))
// DragHelper.Drag(drag.transform);
//
// if(Input.GetKeyDown(KeyCode.L))
// DragHelper.StopDrag(drag.transform);
//
}
}
2 changes: 2 additions & 0 deletions Assets/C's Utils/Testing/DragTester.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Assets/C's Utils/Testing/InputTester.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

using System;
using CsUtils;
using UnityEngine;
Expand Down
Loading

0 comments on commit bd3b439

Please sign in to comment.