105 lines
3.2 KiB
C#
105 lines
3.2 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
using UnityEngine.Events;
|
||
|
|
using frame8.Logic.Misc.Other.Extensions;
|
||
|
|
using frame8.Logic.Misc.Visual.UI;
|
||
|
|
using frame8.Logic.Misc.Visual.UI.MonoBehaviours;
|
||
|
|
using Com.ForbiddenByte.OSA.Core;
|
||
|
|
|
||
|
|
namespace Com.ForbiddenByte.OSA.Util
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Important note: if used with ScrollbarFixer8 (which is true in the most cases,
|
||
|
|
/// make sure <see cref="ScrollbarFixer8.minSize"/> is not too small
|
||
|
|
/// </summary>
|
||
|
|
public class DiscreteScrollbar : MonoBehaviour
|
||
|
|
{
|
||
|
|
public RectTransform slotPrefab;
|
||
|
|
public RectTransform slotsParent;
|
||
|
|
public UnityIntEvent OnSlotSelected;
|
||
|
|
public Func<int> getItemsCountFunc;
|
||
|
|
|
||
|
|
Scrollbar _Scrollbar;
|
||
|
|
RectTransform[] slots = new RectTransform[0];
|
||
|
|
RectTransform _ScrollbarPanelRT;
|
||
|
|
IScrollRectProxy _ScrollRectProxy;
|
||
|
|
int _OneIfVert_ZeroIfHor;
|
||
|
|
|
||
|
|
const int MAX_COUNT = 100;
|
||
|
|
bool _UpdatePending;
|
||
|
|
|
||
|
|
|
||
|
|
void Awake()
|
||
|
|
{
|
||
|
|
// Get in parent, but ignore self
|
||
|
|
_ScrollRectProxy = transform.parent.GetComponentInParent<IScrollRectProxy>();
|
||
|
|
if (_ScrollRectProxy == null)
|
||
|
|
throw new OSAException(GetType().Name + ": No IScrollRectProxy component found in parent");
|
||
|
|
|
||
|
|
_Scrollbar = GetComponent<Scrollbar>();
|
||
|
|
_ScrollbarPanelRT = _Scrollbar.transform as RectTransform;
|
||
|
|
_OneIfVert_ZeroIfHor = _ScrollRectProxy.IsHorizontal ? 0 : 1;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void OnEnable() { _UpdatePending = false; }
|
||
|
|
|
||
|
|
public void OnScrollbarSizeChanged()
|
||
|
|
{
|
||
|
|
StartCoroutine(UpdateSize());
|
||
|
|
}
|
||
|
|
|
||
|
|
IEnumerator UpdateSize()
|
||
|
|
{
|
||
|
|
while (_UpdatePending) // wait for prev request to complete
|
||
|
|
yield return null;
|
||
|
|
|
||
|
|
_UpdatePending = true;
|
||
|
|
yield return null;
|
||
|
|
|
||
|
|
if (getItemsCountFunc == null)
|
||
|
|
throw new OSAException(GetType().Name + "getItemsCountFunc==null. Please specify a count provider");
|
||
|
|
|
||
|
|
_UpdatePending = true;
|
||
|
|
int count = getItemsCountFunc();
|
||
|
|
if (count > MAX_COUNT)
|
||
|
|
throw new OSAException(GetType().Name + ": count is " + count + ". Bigger than MAX_COUNT=" + MAX_COUNT + ". Are you sure you want to use a discrete scrollbar?");
|
||
|
|
|
||
|
|
Rebuild(count);
|
||
|
|
_UpdatePending = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Rebuild(int numSlots)
|
||
|
|
{
|
||
|
|
slotPrefab.gameObject.SetActive(true);
|
||
|
|
|
||
|
|
// Clear prev
|
||
|
|
if (slots != null)
|
||
|
|
foreach (var slot in slots)
|
||
|
|
Destroy(slot.gameObject);
|
||
|
|
|
||
|
|
// Add new
|
||
|
|
slots = new RectTransform[numSlots];
|
||
|
|
float sizesCumu = 0;
|
||
|
|
float slotSize = _ScrollbarPanelRT.rect.size[_OneIfVert_ZeroIfHor] / numSlots; // not using the handle's size because of rounding errors with higher <numSlots>
|
||
|
|
RectTransform.Edge edgeToInsetFrom = _OneIfVert_ZeroIfHor == 1 ? RectTransform.Edge.Top : RectTransform.Edge.Left;
|
||
|
|
for (int i = 0; i < numSlots; i++)
|
||
|
|
{
|
||
|
|
var slot = (Instantiate(slotPrefab.gameObject) as GameObject).GetComponent<RectTransform>();
|
||
|
|
slots[i] = slot;
|
||
|
|
slot.SetParent(slotsParent, false);
|
||
|
|
slot.SetInsetAndSizeFromParentEdgeWithCurrentAnchors(edgeToInsetFrom, sizesCumu, slotSize);
|
||
|
|
sizesCumu += slotSize;
|
||
|
|
int copyOfI = i;
|
||
|
|
slot.GetComponentInChildren<Button>().onClick.AddListener(() => { if (OnSlotSelected != null) OnSlotSelected.Invoke(copyOfI); });
|
||
|
|
}
|
||
|
|
slotPrefab.gameObject.SetActive(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
[Serializable]
|
||
|
|
public class UnityIntEvent : UnityEvent<int> { }
|
||
|
|
}
|
||
|
|
}
|