Skip to content

Commit

Permalink
working on dragging
Browse files Browse the repository at this point in the history
  • Loading branch information
foulston committed Apr 14, 2017
1 parent 17fc87d commit 4fd2de7
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 81 deletions.
Binary file modified Assets/ReorderableList/Example/Example.prefab
Binary file not shown.
203 changes: 122 additions & 81 deletions Assets/ReorderableList/List/Editor/ReorderableList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public enum ElementDisplayType {
private bool dragging;
private bool dragMoved;
private float dragPosition;
private List<DragElement> dragList;
private DragElement[] dragList;
private ListSelection beforeDragSelection;

private int dragDropControlID = -1;
Expand Down Expand Up @@ -134,7 +134,7 @@ public ReorderableList(SerializedProperty list, bool canAdd, bool canRemove, boo
slideEasing = 0.15f;
expandable = true;
showDefaultBackground = true;
captureFocus = false;
captureFocus = true;
multipleSelection = true;
elementLabel = new GUIContent();

Expand Down Expand Up @@ -235,7 +235,12 @@ public void DoList(Rect rect, GUIContent label) {

if (list.arraySize > 0) {

UpdateElementRects(elementBackgroundRect, evt);
//update element rects if not dragging. Dragging caches draw rects so no need to update

if (!dragging) {

UpdateElementRects(elementBackgroundRect, evt);
}

if (elementRects.Length > 0) {

Expand Down Expand Up @@ -542,7 +547,7 @@ private void UpdateElementRects(Rect rect, Event evt) {

//resize array if elements changed

int i, len = dragging ? dragList.Count : list.arraySize;
int i, len = list.arraySize;

if (len != elementRects.Length) {

Expand All @@ -558,9 +563,7 @@ private void UpdateElementRects(Rect rect, Event evt) {

for (i = 0; i < len; i++) {

//if dragging, use the element in the temporary drag list as this list will re-order as the user drags an item

SerializedProperty element = dragging ? dragList[i].element : list.GetArrayElementAtIndex(i);
SerializedProperty element = list.GetArrayElementAtIndex(i);

//update the elementRects value for this object. Grab the last elementRect for startPosition

Expand All @@ -571,7 +574,7 @@ private void UpdateElementRects(Rect rect, Event evt) {
}
}

private void DrawElements(Rect rect, Event evt) {
private void DrawElements(Rect rect, Event evt) {

//draw list background

Expand All @@ -580,53 +583,68 @@ private void DrawElements(Rect rect, Event evt) {
Style.boxBackground.Draw(rect, false, false, false, false);
}

//only draw dragging elements when repainting
//if not dragging, draw elements as usual

if (dragging && evt.type != EventType.Repaint) {
if (!dragging) {

return;
int i, len = list.arraySize;

for (i = 0; i < len; i++) {

bool selected = selection.Contains(i);

DrawElement(list.GetArrayElementAtIndex(i), GetElementDrawRect(i, elementRects[i]), selected, selected && GUIUtility.keyboardControl == controlID);
}
}
else if (evt.type == EventType.Repaint) {

//draw elements
//draw dragging elements only when repainting

int i = dragging ? dragList.Count : list.arraySize;
int i, s, len = dragList.Length;
int sLen = selection.Length;

while (--i > -1) {

//if dragging, use the element in the temporary drag list as this list will re-order as the user drags an item
for (i = 0; i < len; i++) {

SerializedProperty element = dragging ? dragList[i].element : list.GetArrayElementAtIndex(i);
DragElement element = dragList[i];

//draw the element if its not in the selection

//don't draw the any dragging elements here
if (!element.selected) {

bool isSelected = selection.Contains(i);
float middle = element.rect.y + element.rect.height / 2;
float top = element.rect.yMin;

if (dragging && isSelected) {
for (s = 0; s < sLen; s++) {

continue;
}

bool selected = !dragging ? isSelected : false;
DragElement selected = dragList[s];

DrawElement(element, GetElementDrawRect(i, elementRects[i]), selected, selected && GUIUtility.keyboardControl == controlID);
}
if (selected.rect.Overlaps(element.rect)) {

GUI.Box(element.rect, GUIContent.none);
}
}

//draw dragging element last, above other items
DrawElement(element.property, GetElementDrawRect(i, element.rect), false, false && GUIUtility.keyboardControl == controlID);
}
else {

if (dragging) {
//update the element rect if selected. Selected elements appear first in the dragList, so other elements later in iteration will have rects to compare

//because elementRects are static rects representing indexed positions, make a copy here and move it based on the drag position
element.rect.x = 30;
element.rect.y = dragPosition - element.dragOffset;
dragList[i] = element;
}
}

int n = selection.Length;
//draw the selected elements last

while (--n > -1) {
len = sLen;

int index = selection[n];
for (i = 0; i < len; i++) {

Rect dragRect = elementRects[index];
dragRect.y = dragPosition - dragList[index].dragOffset;
DragElement element = dragList[i];

DrawElement(dragList[index].element, dragRect, true, true);
DrawElement(element.property, element.rect, true, true);
}
}
}
Expand Down Expand Up @@ -1085,15 +1103,6 @@ private void HandlePostSelection(Rect rect, Event evt) {
list.MoveArrayElement(dragList[selectionIndex].startIndex, selectionIndex);
}

//restore state

for (int i = 0; i < dragList.Count; i++) {

dragList[i].RestoreState(list.GetArrayElementAtIndex(i));
}

dragList.Clear();

//apply changes

list.serializedObject.ApplyModifiedProperties();
Expand All @@ -1108,8 +1117,6 @@ private void HandlePostSelection(Rect rect, Event evt) {
}
else {

dragList.Clear();

//if we didn't drag, then select the original pressed object

selection.SelectWhenNoAction(pressIndex, evt);
Expand All @@ -1131,21 +1138,26 @@ private void HandlePostSelection(Rect rect, Event evt) {

if (GUIUtility.keyboardControl == controlID) {

if (evt.keyCode == KeyCode.DownArrow) {
if (evt.keyCode == KeyCode.DownArrow && !dragging) {

selection.Select(Mathf.Min(selection.Last + 1, list.arraySize - 1));
evt.Use();
}
else if (evt.keyCode == KeyCode.UpArrow) {
else if (evt.keyCode == KeyCode.UpArrow && !dragging) {

selection.Select(Mathf.Max(selection.Last - 1, 0));
evt.Use();
}
else if (evt.keyCode == KeyCode.Escape && GUIUtility.hotControl == controlID) {

GUIUtility.hotControl = 0;
dragging = false;
selection = beforeDragSelection;

if (dragging) {

dragging = false;
selection = beforeDragSelection;
}

evt.Use();
}
}
Expand Down Expand Up @@ -1192,50 +1204,77 @@ private void DoSelection(int index, Event evt) {
evt.Use();
}

private List<DragElement> GetDragList(float dragPosition) {
private DragElement[] GetDragList(float dragPosition) {

int i, len = list.arraySize;

dragList = dragList ?? new List<DragElement>();
dragList.Clear();
if (dragList == null) {

for (int i = 0; i < list.arraySize; i++) {
dragList = new DragElement[len];
}
else if (dragList.Length != len) {

System.Array.Resize(ref dragList, len);
}

for (i = 0; i < len; i++) {

SerializedProperty element = list.GetArrayElementAtIndex(i);
SerializedProperty property = list.GetArrayElementAtIndex(i);
Rect elementRect = elementRects[i];

DragElement dragElement = new DragElement() {
element = element,
property = property,
dragOffset = dragPosition - elementRect.y,
height = elementRect.height,
rect = elementRect,
selected = selection.Contains(i),
startIndex = i
};

dragElement.RecordState();

dragList.Add(dragElement);
dragList[i] = dragElement;
}

//finally, sort the dragList by selection, selected objects appear first in the list
//selection order is preserved as well

System.Array.Sort(dragList, (a, b) => {
if (b.selected) {
return a.selected ? a.startIndex.CompareTo(b.startIndex) : 1;
}
else if (a.selected) {
return b.selected ? b.startIndex.CompareTo(a.startIndex) : -1;
}
else {
return a.startIndex.CompareTo(b.startIndex);
}
});

return dragList;
}

private void UpdateDragPosition(Vector2 position, Rect bounds, List<DragElement> dragList) {

//TODO When dragging at very high speeds this breaks down. Need to fix
private void UpdateDragPosition(Vector2 position, Rect bounds, DragElement[] dragList) {

//find new drag position

float oldPosition = dragPosition;
float minOffset = dragList[selection.Min].dragOffset;
float maxOffset = dragList[selection.Max].height - dragList[selection.Max].dragOffset;
int startIndex = 0;
int endIndex = selection.Length - 1;

float minOffset = dragList[startIndex].dragOffset;
float maxOffset = dragList[endIndex].rect.height - dragList[endIndex].dragOffset;

dragPosition = Mathf.Clamp(position.y, bounds.yMin + minOffset, bounds.yMax - maxOffset);

/*
//check if changed
if (dragList != null && dragPosition != oldPosition) {
//get the interation direction with start and end points
int i, len = dragList.Count;
int i, len = dragList.Length;
int dir = (int)Mathf.Sign(dragPosition - oldPosition);
int start = dir == 1 ? 0 : len - 1;
Expand All @@ -1252,10 +1291,14 @@ private void UpdateDragPosition(Vector2 position, Rect bounds, List<DragElement>
selection.Sort();
Debug.Log("UPDATE");
for (s = selectionStart; s != selectionEnd; s -= dir) {
int selectionIndex = selection[s];
Debug.Log(selectionIndex);
//find the min and max positions of this selected item, we need to know where this item moved from and move to
//to compare with dragList elements
Expand All @@ -1271,16 +1314,20 @@ private void UpdateDragPosition(Vector2 position, Rect bounds, List<DragElement>
//don't consider already selected items
if (!selection.Contains(i)) {
if (!selection.Contains(i)) {
//swap the selected item if it's within the dragList item
Rect elementRect = elementRects[i];
//Debug.Log("Checking element " + i + " " + elementRect);
float middle = elementRect.y + elementRect.height / 2;
if (minPos < middle && maxPos > middle) {
Debug.Log(i + " is inside");
//move items in dragList
DragElement element = dragList[i];
Expand All @@ -1303,6 +1350,7 @@ private void UpdateDragPosition(Vector2 position, Rect bounds, List<DragElement>
selection.Sort();
}
*/
}

private int GetSelectionIndex(Vector2 position) {
Expand Down Expand Up @@ -1445,13 +1493,15 @@ static Style() {
// -- DRAG ELEMENT --
//

class DragElement {
struct DragElement {

public SerializedProperty element;
public SerializedProperty property;
public int startIndex;
public float dragOffset;
public float height;
public bool selected;
public Rect rect;

/*
private bool isExpanded;
private Dictionary<int, bool> states;
Expand Down Expand Up @@ -1493,6 +1543,7 @@ private void Iterate(SerializedProperty element, System.Action<SerializedPropert
}
}
}
*/
}

//
Expand Down Expand Up @@ -1598,16 +1649,6 @@ public int Length {
get { return indexes.Count; }
}

public int Min {

get { return indexes.Min(); }
}

public int Max {

get { return indexes.Max(); }
}

public int this[int index] {

get { return indexes[index]; }
Expand Down

0 comments on commit 4fd2de7

Please sign in to comment.