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

254 lines
7.9 KiB
C#
Raw Normal View History

2017-07-26 01:54:00 +08:00
/// Credit David Gileadi
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/11
using System;
using System.Collections;
2017-07-26 01:54:00 +08:00
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
// Stepper control
[RequireComponent(typeof(RectTransform))]
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/Stepper")]
2017-07-26 01:54:00 +08:00
public class Stepper : UIBehaviour
{
private Selectable[] _sides;
2017-07-26 01:54:00 +08:00
[SerializeField]
[Tooltip("The current step value of the control")]
2017-07-26 01:54:00 +08:00
private int _value = 0;
[SerializeField]
[Tooltip("The minimum step value allowed by the control. When reached it will disable the '-' button")]
2017-07-26 01:54:00 +08:00
private int _minimum = 0;
[SerializeField]
[Tooltip("The maximum step value allowed by the control. When reached it will disable the '+' button")]
2017-07-26 01:54:00 +08:00
private int _maximum = 100;
[SerializeField]
[Tooltip("The step increment used to increment / decrement the step value")]
2017-07-26 01:54:00 +08:00
private int _step = 1;
[SerializeField]
[Tooltip("Does the step value loop around from end to end")]
2017-07-26 01:54:00 +08:00
private bool _wrap = false;
[SerializeField]
[Tooltip("A GameObject with an Image to use as a separator between segments. Size of the RectTransform will determine the size of the separator used.\nNote, make sure to disable the separator GO so that it does not affect the scene")]
2017-07-26 01:54:00 +08:00
private Graphic _separator;
private float _separatorWidth = 0;
2017-07-26 01:54:00 +08:00
private float separatorWidth
{
get
{
if (_separatorWidth == 0 && separator)
{
_separatorWidth = separator.rectTransform.rect.width;
var image = separator.GetComponent<Image>();
if (image)
_separatorWidth /= image.pixelsPerUnit;
}
return _separatorWidth;
}
}
// Event delegates triggered on click.
[SerializeField]
private StepperValueChangedEvent _onValueChanged = new StepperValueChangedEvent();
[Serializable]
public class StepperValueChangedEvent : UnityEvent<int> { }
public Selectable[] sides
{
get
{
if (_sides == null || _sides.Length == 0)
{
_sides = GetSides();
}
return _sides;
}
}
public int value { get { return _value; } set { _value = value; } }
public int minimum { get { return _minimum; } set { _minimum = value; } }
public int maximum { get { return _maximum; } set { _maximum = value; } }
public int step { get { return _step; } set { _step = value; } }
public bool wrap { get { return _wrap; } set { _wrap = value; } }
public Graphic separator { get { return _separator; } set { _separator = value; _separatorWidth = 0; LayoutSides(sides); } }
2017-07-26 01:54:00 +08:00
public StepperValueChangedEvent onValueChanged
{
get { return _onValueChanged; }
set { _onValueChanged = value; }
}
protected Stepper()
{ }
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
RecreateSprites(sides);
2017-07-26 01:54:00 +08:00
if (separator)
LayoutSides();
if (!wrap)
{
DisableAtExtremes(sides);
}
}
#endif
protected override void Start()
{
if (isActiveAndEnabled)
StartCoroutine(DelayedInit());
}
protected override void OnEnable()
{
StartCoroutine(DelayedInit());
}
IEnumerator DelayedInit()
{
yield return null;
RecreateSprites(sides);
}
private Selectable[] GetSides()
2017-07-26 01:54:00 +08:00
{
var buttons = GetComponentsInChildren<Selectable>();
2017-07-26 01:54:00 +08:00
if (buttons.Length != 2)
{
throw new InvalidOperationException("A stepper must have two Button children");
}
if (!wrap)
{
DisableAtExtremes(buttons);
}
LayoutSides(buttons);
return buttons;
}
public void StepUp()
{
Step(step);
}
public void StepDown()
{
Step(-step);
}
private void Step(int amount)
{
value += amount;
if (wrap)
{
if (value > maximum) value = minimum;
if (value < minimum) value = maximum;
}
else
{
value = Math.Max(minimum, value);
value = Math.Min(maximum, value);
DisableAtExtremes(sides);
}
_onValueChanged.Invoke(value);
}
private void DisableAtExtremes(Selectable[] sides)
2017-07-26 01:54:00 +08:00
{
sides[0].interactable = wrap || value > minimum;
sides[1].interactable = wrap || value < maximum;
}
private void RecreateSprites(Selectable[] sides)
2017-07-26 01:54:00 +08:00
{
for (int i = 0; i < 2; i++)
{
if (sides[i].image == null)
continue;
var sprite = CutSprite(sides[i].image.sprite, i == 0);
var side = sides[i].GetComponent<StepperSide>();
if (side)
{
side.cutSprite = sprite;
}
sides[i].image.overrideSprite = sprite;
}
}
2017-07-26 01:54:00 +08:00
static internal Sprite CutSprite(Sprite sprite, bool leftmost)
{
if (sprite.border.x == 0 || sprite.border.z == 0)
return sprite;
2017-07-26 01:54:00 +08:00
var rect = sprite.rect;
var border = sprite.border;
2017-07-26 01:54:00 +08:00
if (leftmost)
{
rect.xMax = border.z;
border.z = 0;
2017-07-26 01:54:00 +08:00
}
else
{
rect.xMin = border.x;
border.x = 0;
}
return Sprite.Create(sprite.texture, rect, sprite.pivot, sprite.pixelsPerUnit, 0, SpriteMeshType.FullRect, border);
2017-07-26 01:54:00 +08:00
}
public void LayoutSides(Selectable[] sides = null)
2017-07-26 01:54:00 +08:00
{
sides = sides ?? this.sides;
RecreateSprites(sides);
RectTransform transform = this.transform as RectTransform;
float width = (transform.rect.width / 2) - separatorWidth;
for (int i = 0; i < 2; i++)
{
float insetX = i == 0 ? 0 : width + separatorWidth;
var rectTransform = sides[i].GetComponent<RectTransform>();
rectTransform.anchorMin = Vector2.zero;
rectTransform.anchorMax = Vector2.zero;
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, insetX, width);
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, transform.rect.height);
// TODO: maybe adjust text position
}
if (separator)
{
var sepTransform = gameObject.transform.Find("Separator");
Graphic sep = (sepTransform != null) ? sepTransform.GetComponent<Graphic>() : (GameObject.Instantiate(separator.gameObject) as GameObject).GetComponent<Graphic>();
sep.gameObject.name = "Separator";
sep.gameObject.SetActive(true);
sep.rectTransform.SetParent(this.transform, false);
sep.rectTransform.anchorMin = Vector2.zero;
sep.rectTransform.anchorMax = Vector2.zero;
sep.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, width, separatorWidth);
sep.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, transform.rect.height);
}
}
}
}