From a88c7a9c1bf39e0513458e24ca3d844d69976153 Mon Sep 17 00:00:00 2001 From: "Simon (darkside) Jackson" Date: Thu, 29 Oct 2015 16:07:17 +0000 Subject: [PATCH] Initial Checkin of new Re-Orderable List. Still ToDo: 1: complete testing scenarios 2: Update Editor script to add new auto-create option --HG-- branch : develop_5.2 --- Scripts/ReorderableList.meta | 9 + Scripts/ReorderableList/ReorderableList.cs | 123 +++--- .../ReorderableList/ReorderableListContent.cs | 93 +++-- .../ReorderableList/ReorderableListDebug.cs | 46 +-- .../ReorderableList/ReorderableListElement.cs | 375 +++++++++--------- 5 files changed, 335 insertions(+), 311 deletions(-) create mode 100644 Scripts/ReorderableList.meta diff --git a/Scripts/ReorderableList.meta b/Scripts/ReorderableList.meta new file mode 100644 index 0000000..30e2761 --- /dev/null +++ b/Scripts/ReorderableList.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 281614f4c0e3b7a4d9056bd377134172 +folderAsset: yes +timeCreated: 1446117980 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ReorderableList/ReorderableList.cs b/Scripts/ReorderableList/ReorderableList.cs index 7261c1c..898357f 100644 --- a/Scripts/ReorderableList/ReorderableList.cs +++ b/Scripts/ReorderableList/ReorderableList.cs @@ -1,74 +1,79 @@ -using System; -using UnityEngine; +/// Credit Ziboo +/// Sourced from - http://forum.unity3d.com/threads/free-reorderable-list.364600/ + +using System; using UnityEngine.Events; -using UnityEngine.UI; -public class ReorderableList : MonoBehaviour +namespace UnityEngine.UI.Extensions { - public LayoutGroup ContentLayout; - - public bool IsDraggable = true; - public RectTransform DraggableArea; - public bool CloneDraggedObject = false; - - public bool IsDropable = true; - - - public ReorderableListHandler OnElementDropped = new ReorderableListHandler(); - - private RectTransform _content; - private ReorderableListContent _listContent; - - public RectTransform Content + [AddComponentMenu("UI/Extensions/Re-orderable list")] + public class ReorderableList : MonoBehaviour { - get + public LayoutGroup ContentLayout; + + public bool IsDraggable = true; + public RectTransform DraggableArea; + public bool CloneDraggedObject = false; + + public bool IsDropable = true; + + + public ReorderableListHandler OnElementDropped = new ReorderableListHandler(); + + private RectTransform _content; + private ReorderableListContent _listContent; + + public RectTransform Content { - if (_content == null) + get { - _content = ContentLayout.GetComponent(); + if (_content == null) + { + _content = ContentLayout.GetComponent(); + } + return _content; } - return _content; } - } - private void Awake() - { - if (ContentLayout == null) + private void Awake() { - Debug.LogError("You need to have a LayoutGroup content set for the list", gameObject); - return; + if (ContentLayout == null) + { + Debug.LogError("You need to have a LayoutGroup content set for the list", gameObject); + return; + } + if (DraggableArea == null) + { + Debug.LogError("You need to set a draggable area for the list", gameObject); + return; + } + _listContent = ContentLayout.gameObject.AddComponent(); + _listContent.Init(this); } - if (DraggableArea == null) + + #region Nested type: ReorderableListEventStruct + + [Serializable] + public struct ReorderableListEventStruct { - Debug.LogError("You need to set a draggable area for the list", gameObject); - return; + public GameObject DropedObject; + public int FromIndex; + public ReorderableList FromList; + public bool IsAClone; + public GameObject SourceObject; + public int ToIndex; + public ReorderableList ToList; } - _listContent = ContentLayout.gameObject.AddComponent(); - _listContent.Init(this); + + #endregion + + #region Nested type: ReorderableListHandler + + [Serializable] + public class ReorderableListHandler : UnityEvent + { + } + + #endregion } - - #region Nested type: ReorderableListEventStruct - - [Serializable] - public struct ReorderableListEventStruct - { - public GameObject DropedObject; - public int FromIndex; - public ReorderableList FromList; - public bool IsAClone; - public GameObject SourceObject; - public int ToIndex; - public ReorderableList ToList; - } - - #endregion - - #region Nested type: ReorderableListHandler - - [Serializable] - public class ReorderableListHandler : UnityEvent - { - } - - #endregion } \ No newline at end of file diff --git a/Scripts/ReorderableList/ReorderableListContent.cs b/Scripts/ReorderableList/ReorderableListContent.cs index a9df741..9d5b47c 100644 --- a/Scripts/ReorderableList/ReorderableListContent.cs +++ b/Scripts/ReorderableList/ReorderableListContent.cs @@ -1,57 +1,62 @@ -using System.Collections; +/// Credit Ziboo +/// Sourced from - http://forum.unity3d.com/threads/free-reorderable-list.364600/ + +using System.Collections; using System.Collections.Generic; -using UnityEngine; -public class ReorderableListContent : MonoBehaviour +namespace UnityEngine.UI.Extensions { - private List _cachedChildren; - private List _cachedListElement; - private ReorderableListElement _ele; - private ReorderableList _extList; - private RectTransform _rect; - - public void OnTransformChildrenChanged() + public class ReorderableListContent : MonoBehaviour { - StartCoroutine(RefreshChildren()); - } + private List _cachedChildren; + private List _cachedListElement; + private ReorderableListElement _ele; + private ReorderableList _extList; + private RectTransform _rect; - public void Init(ReorderableList extList) - { - _extList = extList; - _rect = GetComponent(); - _cachedChildren = new List(); - _cachedListElement = new List(); - - StartCoroutine(RefreshChildren()); - } - - private IEnumerator RefreshChildren() - { - //Handle new chilren - for (int i = 0; i < _rect.childCount; i++) + public void OnTransformChildrenChanged() { - if (_cachedChildren.Contains(_rect.GetChild(i))) - continue; - - //Get or Create ReorderableListElement - _ele = _rect.GetChild(i).gameObject.GetComponent() ?? - _rect.GetChild(i).gameObject.AddComponent(); - _ele.Init(_extList); - - _cachedChildren.Add(_rect.GetChild(i)); - _cachedListElement.Add(_ele); + StartCoroutine(RefreshChildren()); } - //HACK a little hack, if I don't wait one frame I don't have the right deleted children - yield return 0; - - //Remove deleted child - for (int i = _cachedChildren.Count - 1; i >= 0; i--) + public void Init(ReorderableList extList) { - if (_cachedChildren[i] == null) + _extList = extList; + _rect = GetComponent(); + _cachedChildren = new List(); + _cachedListElement = new List(); + + StartCoroutine(RefreshChildren()); + } + + private IEnumerator RefreshChildren() + { + //Handle new chilren + for (int i = 0; i < _rect.childCount; i++) { - _cachedChildren.RemoveAt(i); - _cachedListElement.RemoveAt(i); + if (_cachedChildren.Contains(_rect.GetChild(i))) + continue; + + //Get or Create ReorderableListElement + _ele = _rect.GetChild(i).gameObject.GetComponent() ?? + _rect.GetChild(i).gameObject.AddComponent(); + _ele.Init(_extList); + + _cachedChildren.Add(_rect.GetChild(i)); + _cachedListElement.Add(_ele); + } + + //HACK a little hack, if I don't wait one frame I don't have the right deleted children + yield return 0; + + //Remove deleted child + for (int i = _cachedChildren.Count - 1; i >= 0; i--) + { + if (_cachedChildren[i] == null) + { + _cachedChildren.RemoveAt(i); + _cachedListElement.RemoveAt(i); + } } } } diff --git a/Scripts/ReorderableList/ReorderableListDebug.cs b/Scripts/ReorderableList/ReorderableListDebug.cs index c6fa31f..e02ed76 100644 --- a/Scripts/ReorderableList/ReorderableListDebug.cs +++ b/Scripts/ReorderableList/ReorderableListDebug.cs @@ -1,29 +1,29 @@ -using System; -using UnityEngine; -using System.Collections; -using UnityEngine.UI; +/// Credit Ziboo +/// Sourced from - http://forum.unity3d.com/threads/free-reorderable-list.364600/ -public class ReorderableListDebug : MonoBehaviour +namespace UnityEngine.UI.Extensions { - - public Text DebugLabel; - - void Awake() + public class ReorderableListDebug : MonoBehaviour { - foreach (var list in FindObjectsOfType()) + public Text DebugLabel; + + void Awake() { - list.OnElementDropped.AddListener(ElementDropped); + foreach (var list in FindObjectsOfType()) + { + list.OnElementDropped.AddListener(ElementDropped); + } + } + + private void ElementDropped(ReorderableList.ReorderableListEventStruct droppedStruct) + { + DebugLabel.text = ""; + DebugLabel.text += "Dropped Object: " + droppedStruct.DropedObject.name + "\n"; + DebugLabel.text += "Is Clone ?: " + droppedStruct.IsAClone + "\n"; + if (droppedStruct.IsAClone) + DebugLabel.text += "Source Object: " + droppedStruct.SourceObject.name + "\n"; + DebugLabel.text += string.Format("From {0} at Index {1} \n", droppedStruct.FromList.name, droppedStruct.FromIndex); + DebugLabel.text += string.Format("To {0} at Index {1} \n", droppedStruct.ToList.name, droppedStruct.ToIndex); } } - - private void ElementDropped(ReorderableList.ReorderableListEventStruct droppedStruct) - { - DebugLabel.text = ""; - DebugLabel.text += "Dropped Object: " + droppedStruct.DropedObject.name + "\n"; - DebugLabel.text += "Is Clone ?: " + droppedStruct.IsAClone + "\n"; - if (droppedStruct.IsAClone) - DebugLabel.text += "Source Object: " + droppedStruct.SourceObject.name + "\n"; - DebugLabel.text += string.Format("From {0} at Index {1} \n", droppedStruct.FromList.name,droppedStruct.FromIndex); - DebugLabel.text += string.Format("To {0} at Index {1} \n", droppedStruct.ToList.name,droppedStruct.ToIndex); - } -} +} \ No newline at end of file diff --git a/Scripts/ReorderableList/ReorderableListElement.cs b/Scripts/ReorderableList/ReorderableListElement.cs index 8e6b691..bc6411e 100644 --- a/Scripts/ReorderableList/ReorderableListElement.cs +++ b/Scripts/ReorderableList/ReorderableListElement.cs @@ -1,209 +1,214 @@ -using System.Collections.Generic; -using UnityEngine; +/// Credit Ziboo +/// Sourced from - http://forum.unity3d.com/threads/free-reorderable-list.364600/ + +using System.Collections.Generic; using UnityEngine.EventSystems; -using UnityEngine.UI; -[RequireComponent(typeof (RectTransform))] -public class ReorderableListElement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler +namespace UnityEngine.UI.Extensions { - private readonly List _raycastResults = new List(); - private ReorderableList _currentReorderableListRaycasted; - private RectTransform _draggingObject; - private LayoutElement _draggingObjectLE; - private Vector2 _draggingObjectOriginalSize; - private RectTransform _fakeElement; - private LayoutElement _fakeElementLE; - private int _fromIndex; - private bool _isDragging; - private RectTransform _rect; - private ReorderableList _reorderableList; - #region IBeginDragHandler Members - - public void OnBeginDrag(PointerEventData eventData) + [RequireComponent(typeof(RectTransform))] + public class ReorderableListElement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler { - if (_reorderableList == null) - return; + private readonly List _raycastResults = new List(); + private ReorderableList _currentReorderableListRaycasted; + private RectTransform _draggingObject; + private LayoutElement _draggingObjectLE; + private Vector2 _draggingObjectOriginalSize; + private RectTransform _fakeElement; + private LayoutElement _fakeElementLE; + private int _fromIndex; + private bool _isDragging; + private RectTransform _rect; + private ReorderableList _reorderableList; - //Can't drag, return... - if (!_reorderableList.IsDraggable) - { - _draggingObject = null; - return; - } + #region IBeginDragHandler Members - //If CloneDraggedObject just set draggingObject to this gameobject - if (_reorderableList.CloneDraggedObject == false) + public void OnBeginDrag(PointerEventData eventData) { - _draggingObject = _rect; - _fromIndex = _rect.GetSiblingIndex(); - } + if (_reorderableList == null) + return; + + //Can't drag, return... + if (!_reorderableList.IsDraggable) + { + _draggingObject = null; + return; + } + + //If CloneDraggedObject just set draggingObject to this gameobject + if (_reorderableList.CloneDraggedObject == false) + { + _draggingObject = _rect; + _fromIndex = _rect.GetSiblingIndex(); + } //Else Duplicate - else - { - GameObject clone = Instantiate(gameObject); - _draggingObject = clone.GetComponent(); - } - - //Put _dragging object into the draggin area - _draggingObjectOriginalSize = gameObject.GetComponent().rect.size; - _draggingObjectLE = _draggingObject.GetComponent(); - _draggingObject.SetParent(_reorderableList.DraggableArea, false); - _draggingObject.SetAsLastSibling(); - - //Create a fake element for previewing placement - _fakeElement = new GameObject("Fake").AddComponent(); - _fakeElementLE = _fakeElement.gameObject.AddComponent(); - - - RefreshSizes(); - - - _isDragging = true; - } - - #endregion - - #region IDragHandler Members - - public void OnDrag(PointerEventData eventData) - { - if (!_isDragging) - return; - - //Set dragging object on cursor - _draggingObject.position = eventData.position; - - - //Check everything under the cursor to find a ReorderableList - EventSystem.current.RaycastAll(eventData, _raycastResults); - for (int i = 0; i < _raycastResults.Count; i++) - { - _currentReorderableListRaycasted = _raycastResults[i].gameObject.GetComponent(); - if (_currentReorderableListRaycasted != null) - { - break; - } - } - - //If nothing found or the list is not dropable, put the fake element outsite - if (_currentReorderableListRaycasted == null || _currentReorderableListRaycasted.IsDropable == false) - { - RefreshSizes(); - _fakeElement.transform.SetParent(_reorderableList.DraggableArea, false); - - } - //Else find the best position on the list and put fake element on the right index - else - { - if (_fakeElement.parent != _currentReorderableListRaycasted) - _fakeElement.SetParent(_currentReorderableListRaycasted.Content, false); - - float minDistance = float.PositiveInfinity; - int targetIndex = 0; - float dist = 0; - for (int j = 0; j < _currentReorderableListRaycasted.Content.childCount; j++) - { - var c = _currentReorderableListRaycasted.Content.GetChild(j).GetComponent(); - - if (_currentReorderableListRaycasted.ContentLayout is VerticalLayoutGroup) - dist = Mathf.Abs(c.position.y - eventData.position.y); - else if (_currentReorderableListRaycasted.ContentLayout is HorizontalLayoutGroup) - dist = Mathf.Abs(c.position.x - eventData.position.x); - else if (_currentReorderableListRaycasted.ContentLayout is GridLayoutGroup) - dist = (Mathf.Abs(c.position.x - eventData.position.x) + Mathf.Abs(c.position.y - eventData.position.y)); - - if (dist < minDistance) - { - minDistance = dist; - targetIndex = j; - } - } - - RefreshSizes(); - _fakeElement.SetSiblingIndex(targetIndex); - _fakeElement.gameObject.SetActive(true); - - } - } - - #endregion - - #region IEndDragHandler Members - - public void OnEndDrag(PointerEventData eventData) - { - _isDragging = false; - - if (_draggingObject != null) - { - //If we have a, ReorderableList that is dropable - //Put the dragged object into the content and at the right index - if (_currentReorderableListRaycasted != null && _currentReorderableListRaycasted.IsDropable) - { - RefreshSizes(); - _draggingObject.SetParent(_currentReorderableListRaycasted.Content, false); - _draggingObject.SetSiblingIndex(_fakeElement.GetSiblingIndex()); - - - //Send OnelementDropped Event - _reorderableList.OnElementDropped.Invoke(new ReorderableList.ReorderableListEventStruct - { - DropedObject = _draggingObject.gameObject, - IsAClone = _reorderableList.CloneDraggedObject, - SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject, - FromList = _reorderableList, - FromIndex = _fromIndex, - ToList = _currentReorderableListRaycasted, - ToIndex = _fakeElement.GetSiblingIndex() - 1 - }); - } - //We don't have an ReorderableList else { - //If it's a clone, delete it - if (_reorderableList.CloneDraggedObject) + GameObject clone = Instantiate(gameObject); + _draggingObject = clone.GetComponent(); + } + + //Put _dragging object into the draggin area + _draggingObjectOriginalSize = gameObject.GetComponent().rect.size; + _draggingObjectLE = _draggingObject.GetComponent(); + _draggingObject.SetParent(_reorderableList.DraggableArea, false); + _draggingObject.SetAsLastSibling(); + + //Create a fake element for previewing placement + _fakeElement = new GameObject("Fake").AddComponent(); + _fakeElementLE = _fakeElement.gameObject.AddComponent(); + + + RefreshSizes(); + + + _isDragging = true; + } + + #endregion + + #region IDragHandler Members + + public void OnDrag(PointerEventData eventData) + { + if (!_isDragging) + return; + + //Set dragging object on cursor + _draggingObject.position = eventData.position; + + + //Check everything under the cursor to find a ReorderableList + EventSystem.current.RaycastAll(eventData, _raycastResults); + for (int i = 0; i < _raycastResults.Count; i++) + { + _currentReorderableListRaycasted = _raycastResults[i].gameObject.GetComponent(); + if (_currentReorderableListRaycasted != null) { - Destroy(_draggingObject.gameObject); + break; } - //Else replace the draggedObject to his first place - else + } + + //If nothing found or the list is not dropable, put the fake element outsite + if (_currentReorderableListRaycasted == null || _currentReorderableListRaycasted.IsDropable == false) + { + RefreshSizes(); + _fakeElement.transform.SetParent(_reorderableList.DraggableArea, false); + + } + //Else find the best position on the list and put fake element on the right index + else + { + if (_fakeElement.parent != _currentReorderableListRaycasted) + _fakeElement.SetParent(_currentReorderableListRaycasted.Content, false); + + float minDistance = float.PositiveInfinity; + int targetIndex = 0; + float dist = 0; + for (int j = 0; j < _currentReorderableListRaycasted.Content.childCount; j++) + { + var c = _currentReorderableListRaycasted.Content.GetChild(j).GetComponent(); + + if (_currentReorderableListRaycasted.ContentLayout is VerticalLayoutGroup) + dist = Mathf.Abs(c.position.y - eventData.position.y); + else if (_currentReorderableListRaycasted.ContentLayout is HorizontalLayoutGroup) + dist = Mathf.Abs(c.position.x - eventData.position.x); + else if (_currentReorderableListRaycasted.ContentLayout is GridLayoutGroup) + dist = (Mathf.Abs(c.position.x - eventData.position.x) + Mathf.Abs(c.position.y - eventData.position.y)); + + if (dist < minDistance) + { + minDistance = dist; + targetIndex = j; + } + } + + RefreshSizes(); + _fakeElement.SetSiblingIndex(targetIndex); + _fakeElement.gameObject.SetActive(true); + + } + } + + #endregion + + #region IEndDragHandler Members + + public void OnEndDrag(PointerEventData eventData) + { + _isDragging = false; + + if (_draggingObject != null) + { + //If we have a, ReorderableList that is dropable + //Put the dragged object into the content and at the right index + if (_currentReorderableListRaycasted != null && _currentReorderableListRaycasted.IsDropable) { RefreshSizes(); - _draggingObject.SetParent(_reorderableList.Content, false); - _draggingObject.SetSiblingIndex(_fromIndex); + _draggingObject.SetParent(_currentReorderableListRaycasted.Content, false); + _draggingObject.SetSiblingIndex(_fakeElement.GetSiblingIndex()); + + + //Send OnelementDropped Event + _reorderableList.OnElementDropped.Invoke(new ReorderableList.ReorderableListEventStruct + { + DropedObject = _draggingObject.gameObject, + IsAClone = _reorderableList.CloneDraggedObject, + SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject, + FromList = _reorderableList, + FromIndex = _fromIndex, + ToList = _currentReorderableListRaycasted, + ToIndex = _fakeElement.GetSiblingIndex() - 1 + }); + } + //We don't have an ReorderableList + else + { + //If it's a clone, delete it + if (_reorderableList.CloneDraggedObject) + { + Destroy(_draggingObject.gameObject); + } + //Else replace the draggedObject to his first place + else + { + RefreshSizes(); + _draggingObject.SetParent(_reorderableList.Content, false); + _draggingObject.SetSiblingIndex(_fromIndex); + } } } + + //Delete fake element + if (_fakeElement != null) + Destroy(_fakeElement.gameObject); } - //Delete fake element - if (_fakeElement != null) - Destroy(_fakeElement.gameObject); - } + #endregion - #endregion - - private void RefreshSizes() - { - Vector2 size = _draggingObjectOriginalSize; - - if (_currentReorderableListRaycasted != null && _currentReorderableListRaycasted.IsDropable) + private void RefreshSizes() { - var firstChild = _currentReorderableListRaycasted.Content.GetChild(0); - if (firstChild != null) - { - size = firstChild.GetComponent().rect.size; - } - } - - _draggingObject.sizeDelta = size; - _fakeElementLE.preferredHeight = _draggingObjectLE.preferredHeight = size.y; - _fakeElementLE.preferredWidth = _draggingObjectLE.preferredWidth = size.x; - } + Vector2 size = _draggingObjectOriginalSize; - public void Init(ReorderableList reorderableList) - { - _reorderableList = reorderableList; - _rect = GetComponent(); + if (_currentReorderableListRaycasted != null && _currentReorderableListRaycasted.IsDropable) + { + var firstChild = _currentReorderableListRaycasted.Content.GetChild(0); + if (firstChild != null) + { + size = firstChild.GetComponent().rect.size; + } + } + + _draggingObject.sizeDelta = size; + _fakeElementLE.preferredHeight = _draggingObjectLE.preferredHeight = size.y; + _fakeElementLE.preferredWidth = _draggingObjectLE.preferredWidth = size.x; + } + + public void Init(ReorderableList reorderableList) + { + _reorderableList = reorderableList; + _rect = GetComponent(); + } } } \ No newline at end of file