com.unity.uiextensions/Runtime/Scripts/Controls/Sliders/RadialSlider.cs

258 lines
8.0 KiB
C#
Raw Normal View History

/// Credit mgear, SimonDarksideJ
/// Sourced from - https://forum.unity3d.com/threads/radial-slider-circle-slider.326392/#post-3143582
2020-07-09 03:38:28 +08:00
/// Updated to include lerping features and programmatic access to angle/value
using System;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(Image))]
Release 2.3.0 (#429) * Package upver for Development * Added OnHighlightChanged and OnPressChanged events Added getters and setters for Highlighted and Pressed * Patch fix for UILineRenderer * Update package preview release * Resolves issue where the lower range value would become stuck when moved to the max value position Resolves: https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/381/cant-move-range-slider-if-low-is-moved-to * Updated Infinite scroll to work with content of different sizes * Clean-up and reset pivots on scene start * Patches from PR * Clean up range slider unused variables * Updated Dropdown list to NOT resize text Rect on draw * Upgraded RangeSlider to work in both Horizontal and Verticle setups, just like regular slider. Also fixed a minor issue with offset when dragging on the bar. # Conflicts: # Runtime/Scripts/Controls/RangeSlider.cs * Taking in fix from https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/132 * Applying PR manually, because Bitbucket https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/128 * Merged in fix manually because... Bitbucket https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/130 * Remove old BitBucket Pipeline for GitHub * Fixes issue #398 where the Next / Previous buttons filed to work if the ScrollSnap was previously scrolling. Also renamed the Extension Methods scripts and added a new function. Resolves: #398 * Resolves #397 Moved OnValidate checks which redraw the component to the RectTransformDimensionsCHanged event * Updated UIParticleSystem access to Particles array to ensure it is more stable. Updated some #if statements to be better future proofed Resolves #360 * Fixed the UIConnector to safely handle when no parent canvas can be found. Resolves #392 * Fixed issue which allowed an item marked as NOT transferable to actually be transferred between lists Resolves #382 * Updated #if filter inclusion to 2019_1_OR_Newer resolves: - https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/411 * Updated UIVertical scroller to be 2022 compliant Resolves: - https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/410 * Updated Curly UI to wait until end of the frame to recalculate positions Also updated Editor script to work in 2022 Resolves: - https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/409 * Updated Depth Texture sampler in UI Particles Shaders Resolves: - https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/401 * Remove meta duplicates for HSVColour Picker * Add newly generated HSV picker meta files * Hard reset of Colour picker guids * Updated Points to always be an array of 1 when set to nothing. Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/295 * Updated Cooldown button to work with Keyboard input Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/171 * Added error handling around setting Unity UI Components for Vertical/Horizontal scrolling Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/296 * Protecting Remove too * Added SetArc method to UICircle as requested Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/280 * Marked ScrollPositionController as Obsolete, users should use the newer Scroller component instead, will be removed in a future release. Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/305 * Updated ScrollPositionControllerEditor as obsolete too * Removed unneeded size calculation which caused some issues with mixed height/width children. Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/380 * Resolved issue whereby the last row in a flow layout group would not size correctly. Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/357 * Updated all components using "LayoutGroup" to override their OnDisable feature to incorporate this fix: https://gist.github.com/randomize/73ca6d3b6aa7210073692eb5cabd537e Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/178 * Checking in new MinMaxSlider TODO - Finish Editor creator * Added Editor Menu Option to create a Min/Max slider Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/270 * Marked TileSizeFitter as obsolete as Unity has made this unworkable Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/214 * Updated Editor create options to add the correct Event System Input module for the Input system used, now or old. Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/378 * Updated Editor menu layout * Updated initialisation logic to not cause an endless loop in the TabNavigationHelper Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/208 * Added new FIFO based UI Line Render when dynamic line rendering is needed (basic, no Beziers) Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/324 * Clean-up of ScrollSnapBase * Updated "Action" use to "UnityAction" to avoid Unity issues Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/253 * Updated UIVerticalScroller for standards and added UIHorizontalScroller Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/205 * Updated ReorderableList/ReorderableListElement to prevent creating a "Fake" droppable when the item is not transferable Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/164 * Updated panel drawing for ComboBox controls and added DropdownOffset Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/393 * Base update for pointers to new version / package home * Cleanup and ensuring the UIParticleSystem is disposed on Destroy correctly. Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/412 * Refresh FancyScrollView with latest fixes * Remove broken examples link * Break Module * Update Examples module to new home * Updating GitHub artifacts and automation * Updated build issue with ReorderableListElement * Revised the Curly UI fix as it was preventing the graphic from being updated in the scene view. Thanks to @solidsign for the update. * Removed legacy Examples link, moving to separate repository * Added new submodule for extracted examples * Fix class spellings and update MultiTouchScrollRect * Updated NonDrawingGraphic to require a CanvasRender, else it causes an error on run (and doesn't work) - Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/420 * Add updated test flow for builds * Fix github issue templates * Add the Version upgrade pipeline * Added ResetSelectableHighlight component * Resolves issue in 2022 with the missing Text component Fixes: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/424 * The BIG Unity 2022 Text reorganisation * Remove editor validation and add error checking for the ColorLabel component * Add 2019 to the testing validation * Switch android builds to windows * Several lifetime feature updates for the ComboBox controls: - Resolves startup issue that prevented the control being used (Unity changed the start order in some instances), this was causing null reference issues with comboboxes - Added the ability to set a specific item on start and not just the first - Added the ability to disable the dropdown to make a read-only dropdown Resolves: - https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/426 - https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/425 * Resolved issues with DisplayAbove and using a 0 ItemsToDisplay * Update pipelines for release * Final checks for merge! --------- Co-authored-by: Robert Rioja <rrioja@immersivedisplayinc.com> Co-authored-by: Simon Jackson <darkside@xna-uk.net> Co-authored-by: Ben MacKinnon <bilmackinnon@googlemail.com> Co-authored-by: Simon Jackson <sjackson@ethar.com> Co-authored-by: action <action@users.noreply.github.com>
2023-02-07 22:35:43 +08:00
[AddComponentMenu("UI/Extensions/Sliders/Radial Slider")]
public class RadialSlider : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
private bool isPointerDown, isPointerReleased, lerpInProgress;
private Vector2 m_localPos, m_screenPos;
private float m_targetAngle, m_lerpTargetAngle, m_startAngle, m_currentLerpTime, m_lerpTime;
private Camera m_eventCamera;
private Image m_image;
[SerializeField]
[Tooltip("Radial Gradient Start Color")]
private Color m_startColor = Color.green;
[SerializeField]
[Tooltip("Radial Gradient End Color")]
private Color m_endColor = Color.red;
[Tooltip("Move slider absolute or use Lerping?\nDragging only supported with absolute")]
[SerializeField]
private bool m_lerpToTarget;
[Tooltip("Curve to apply to the Lerp\nMust be set to enable Lerp")]
[SerializeField]
private AnimationCurve m_lerpCurve;
[Tooltip("Event fired when value of control changes, outputs an INT angle value")]
[SerializeField]
private RadialSliderValueChangedEvent _onValueChanged = new RadialSliderValueChangedEvent();
[Tooltip("Event fired when value of control changes, outputs a TEXT angle value")]
[SerializeField]
private RadialSliderTextValueChangedEvent _onTextValueChanged = new RadialSliderTextValueChangedEvent();
public float Angle
{
get { return RadialImage.fillAmount * 360f; }
set
{
if (LerpToTarget)
{
StartLerp(value / 360f);
}
else
{
UpdateRadialImage(value / 360f);
}
}
}
public float Value
{
get { return RadialImage.fillAmount; }
set
{
if (LerpToTarget)
{
StartLerp(value);
}
else
{
UpdateRadialImage(value);
}
}
}
public Color EndColor
{
get { return m_endColor; }
set { m_endColor = value; }
}
public Color StartColor
{
get { return m_startColor; }
set { m_startColor = value; }
}
public bool LerpToTarget
{
get { return m_lerpToTarget; }
set { m_lerpToTarget = value; }
}
public AnimationCurve LerpCurve
{
get { return m_lerpCurve; }
set { m_lerpCurve = value; m_lerpTime = LerpCurve[LerpCurve.length - 1].time; }
}
public bool LerpInProgress
{
get { return lerpInProgress; }
}
[Serializable]
public class RadialSliderValueChangedEvent : UnityEvent<int> { }
[Serializable]
public class RadialSliderTextValueChangedEvent : UnityEvent<string> { }
public Image RadialImage
{
get
{
if (m_image == null)
{
m_image = GetComponent<Image>();
m_image.type = Image.Type.Filled;
m_image.fillMethod = Image.FillMethod.Radial360;
m_image.fillAmount = 0;
}
return m_image;
}
}
public RadialSliderValueChangedEvent onValueChanged
{
get { return _onValueChanged; }
set { _onValueChanged = value; }
}
public RadialSliderTextValueChangedEvent onTextValueChanged
{
get { return _onTextValueChanged; }
set { _onTextValueChanged = value; }
}
private void Awake()
{
if (LerpCurve != null && LerpCurve.length > 0)
{
m_lerpTime = LerpCurve[LerpCurve.length - 1].time;
}
else
{
m_lerpTime = 1;
}
}
private void Update()
{
if (isPointerDown)
{
m_targetAngle = GetAngleFromMousePoint();
if (!lerpInProgress)
{
if (!LerpToTarget)
{
UpdateRadialImage(m_targetAngle);
NotifyValueChanged();
}
else
{
if (isPointerReleased) StartLerp(m_targetAngle);
isPointerReleased = false;
}
}
}
if (lerpInProgress && Value != m_lerpTargetAngle)
{
m_currentLerpTime += Time.deltaTime;
float perc = m_currentLerpTime / m_lerpTime;
if (LerpCurve != null && LerpCurve.length > 0)
{
UpdateRadialImage(Mathf.Lerp(m_startAngle, m_lerpTargetAngle, LerpCurve.Evaluate(perc)));
}
else
{
UpdateRadialImage(Mathf.Lerp(m_startAngle, m_lerpTargetAngle, perc));
}
}
if (m_currentLerpTime >= m_lerpTime || Value == m_lerpTargetAngle)
{
lerpInProgress = false;
UpdateRadialImage(m_lerpTargetAngle);
NotifyValueChanged();
}
}
private void StartLerp(float targetAngle)
{
if (!lerpInProgress)
{
m_startAngle = Value;
m_lerpTargetAngle = targetAngle;
m_currentLerpTime = 0f;
lerpInProgress = true;
}
}
private float GetAngleFromMousePoint()
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, m_screenPos, m_eventCamera, out m_localPos);
// radial pos of the mouse position.
return (Mathf.Atan2(-m_localPos.y, m_localPos.x) * 180f / Mathf.PI + 180f) / 360f;
}
private void UpdateRadialImage(float targetAngle)
{
RadialImage.fillAmount = targetAngle;
RadialImage.color = Color.Lerp(m_startColor, m_endColor, targetAngle);
}
private void NotifyValueChanged()
{
_onValueChanged.Invoke((int)(m_targetAngle * 360f));
_onTextValueChanged.Invoke(((int)(m_targetAngle * 360f)).ToString());
}
//#if UNITY_EDITOR
// private void OnValidate()
// {
// if (LerpToTarget && LerpCurve.length < 2)
// {
// LerpToTarget = false;
// Debug.LogError("You need to define a Lerp Curve to enable 'Lerp To Target'");
// }
// }
//#endif
#region Interfaces
// Called when the pointer enters our GUI component.
// Start tracking the mouse
public void OnPointerEnter(PointerEventData eventData)
{
m_screenPos = eventData.position;
m_eventCamera = eventData.enterEventCamera;
}
public void OnPointerDown(PointerEventData eventData)
{
m_screenPos = eventData.position;
m_eventCamera = eventData.enterEventCamera;
isPointerDown = true;
}
public void OnPointerUp(PointerEventData eventData)
{
m_screenPos = Vector2.zero;
isPointerDown = false;
isPointerReleased = true;
}
public void OnDrag(PointerEventData eventData)
{
m_screenPos = eventData.position;
}
#endregion
}
}